diff --git a/.gitignore b/.gitignore index dabb51762d32d..bd0b923fbc2b4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.DS_Store *.a *.o *.o.* @@ -29,7 +30,6 @@ /ffmpeg /ffplay /ffprobe -/ffserver /config.asm /config.h /coverage.info diff --git a/.travis.yml b/.travis.yml index 40f01f94c2679..63f2051cb3f1f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,10 @@ addons: compiler: - clang - gcc +matrix: + exclude: + - os: osx + compiler: gcc cache: directories: - ffmpeg-samples diff --git a/Changelog b/Changelog index d6ec4ad1b557a..cc61b80958fb5 100644 --- a/Changelog +++ b/Changelog @@ -1,7 +1,62 @@ Entries are sorted chronologically from oldest to youngest within each release, releases are sorted from youngest to oldest. -version : +version 4.0: +- Bitstream filters for editing metadata in H.264, HEVC and MPEG-2 streams +- Dropped support for OpenJPEG versions 2.0 and below. Using OpenJPEG now + requires 2.1 (or later) and pkg-config. +- VDA dropped (use VideoToolbox instead) +- MagicYUV encoder +- Raw AMR-NB and AMR-WB demuxers +- TiVo ty/ty+ demuxer +- Intel QSV-accelerated MJPEG encoding +- PCE support for extended channel layouts in the AAC encoder +- native aptX and aptX HD encoder and decoder +- Raw aptX and aptX HD muxer and demuxer +- NVIDIA NVDEC-accelerated H.264, HEVC, MJPEG, MPEG-1/2/4, VC1, VP8/9 hwaccel decoding +- Intel QSV-accelerated overlay filter +- mcompand audio filter +- acontrast audio filter +- OpenCL overlay filter +- video mix filter +- video normalize filter +- audio lv2 wrapper filter +- VAAPI MJPEG and VP8 decoding +- AMD AMF H.264 and HEVC encoders +- video fillborders filter +- video setrange filter +- nsp demuxer +- support LibreSSL (via libtls) +- AVX-512/ZMM support added +- Dropped support for building for Windows XP. The minimum supported Windows + version is Windows Vista. +- deconvolve video filter +- entropy video filter +- hilbert audio filter source +- aiir audio filter +- aiff: add support for CD-ROM XA ADPCM +- Removed the ffserver program +- Removed the ffmenc and ffmdec muxer and demuxer +- VideoToolbox HEVC encoder and hwaccel +- VAAPI-accelerated ProcAmp (color balance), denoise and sharpness filters +- Add android_camera indev +- codec2 en/decoding via libcodec2 +- muxer/demuxer for raw codec2 files and .c2 files +- Moved nvidia codec headers into an external repository. + They can be found at http://git.videolan.org/?p=ffmpeg/nv-codec-headers.git +- native SBC encoder and decoder +- drmeter audio filter +- hapqa_extract bitstream filter +- filter_units bitstream filter +- AV1 Support through libaom +- E-AC-3 dependent frames support +- bitstream filter for extracting E-AC-3 core +- Haivision SRT protocol via libsrt +- segafilm muxer +- vfrdet filter + + +version 3.4: - deflicker video filter - doubleweave video filter - lumakey video filter diff --git a/MAINTAINERS b/MAINTAINERS index 9027ed5846e92..b61856243cc10 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -29,9 +29,6 @@ ffplay: ffprobe: ffprobe.c Stefano Sabatini -ffserver: - ffserver.c Reynaldo H. Verdejo Pinochet - Commandline utility code: cmdutils.c, cmdutils.h Michael Niedermayer @@ -42,7 +39,7 @@ QuickTime faststart: Miscellaneous Areas =================== -documentation Stefano Sabatini, Mike Melanson, Timothy Gu, Lou Logan +documentation Stefano Sabatini, Mike Melanson, Timothy Gu, Lou Logan, Gyan Doshi project server Árpád Gereöffy, Michael Niedermayer, Reimar Doeffinger, Alexander Strasser, Nikolay Aleksandrov presets Robert Swain metadata subsystem Aurelien Jacobs @@ -142,6 +139,7 @@ Codecs: aacenc*, aaccoder.c Rostislav Pehlivanov alacenc.c Jaikrishnan Menon alsdec.c Thilo Borgmann, Umair Khan + aptx.c Aurelien Jacobs ass* Aurelien Jacobs asv* Michael Niedermayer atrac3plus* Maxim Poliakovski @@ -158,7 +156,7 @@ Codecs: cpia.c Stephan Hilb crystalhd.c Philip Langdale cscd.c Reimar Doeffinger - cuvid.c Timo Rothenpieler + cuviddec.c Timo Rothenpieler dca* foo86 dirac* Rostislav Pehlivanov dnxhd* Baptiste Coudurier @@ -170,6 +168,7 @@ Codecs: eacmv*, eaidct*, eat* Peter Ross evrc* Paul B Mahol exif.c, exif.h Thilo Borgmann + exr.c Martin Vignali ffv1* Michael Niedermayer ffwavesynth.c Nicolas George fifo.c Jan Sebechlebsky @@ -189,6 +188,7 @@ Codecs: jvdec.c Peter Ross lcl*.c Roberto Togni, Reimar Doeffinger libcelt_dec.c Nicolas George + libcodec2.c Tomas Härdin libdirac* David Conrad libgsm.c Michel Bardiaux libkvazaar.c Arttu Ylä-Outinen @@ -212,7 +212,7 @@ Codecs: msrle.c Mike Melanson msvideo1.c Mike Melanson nuv.c Reimar Doeffinger - nvenc* Timo Rothenpieler + nvdec*, nvenc* Timo Rothenpieler opus* Rostislav Pehlivanov paf.* Paul B Mahol pcx.c Ivo van Poorten @@ -242,10 +242,10 @@ Codecs: tta.c Alex Beregszaszi, Jaikrishnan Menon ttaenc.c Paul B Mahol txd.c Ivo van Poorten + v4l2_* Jorge Ramirez-Ortiz vc2* Rostislav Pehlivanov vcr1.c Michael Niedermayer - vda_h264_dec.c Xidorn Quan - videotoolboxenc.c Rick Kern + videotoolboxenc.c Rick Kern, Aman Gupta vima.c Paul B Mahol vorbisdec.c Denes Balatoni, David Conrad vorbisenc.c Oded Shimon @@ -268,11 +268,11 @@ Hardware acceleration: crystalhd.c Philip Langdale dxva2* Hendrik Leppkes, Laurent Aimar, Steve Lhomme d3d11va* Steve Lhomme - mediacodec* Matthieu Bouron + mediacodec* Matthieu Bouron, Aman Gupta vaapi* Gwenole Beauchesne vaapi_encode* Mark Thompson vdpau* Philip Langdale, Carl Eugen Hoyos - videotoolbox* Rick Kern + videotoolbox* Rick Kern, Aman Gupta libavdevice @@ -282,6 +282,7 @@ libavdevice avfoundation.m Thilo Borgmann + android_camera.c Felix Matouschek decklink* Marton Balint dshow.c Roger Pack (CC rogerdpack@gmail.com) fbdev_enc.c Lukasz Marek @@ -395,8 +396,10 @@ Muxers/Demuxers: brstm.c Paul B Mahol caf* Peter Ross cdxl.c Paul B Mahol + codec2.c Tomas Härdin crc.c Michael Niedermayer dashdec.c Steven Liu + dashenc.c Karthick Jeyapal daud.c Reimar Doeffinger dss.c Oleksij Rempel dtsdec.c foo86 @@ -549,6 +552,7 @@ Ivan Uskov James Darnley Jan Ekström Joakim Plate +Jun Zhao Kieran Kunhya Kirill Gavrilov Martin Storsjö @@ -587,6 +591,7 @@ FFmpeg release signing key FCF9 86EA 15E6 E293 A564 4F10 B432 2F04 D676 58D8 Ganesh Ajjanagadde C96A 848E 97C3 CEA2 AB72 5CE4 45F9 6A2D 3C36 FB1B Gwenole Beauchesne 2E63 B3A6 3E44 37E2 017D 2704 53C7 6266 B153 99C4 Jaikrishnan Menon 61A1 F09F 01C9 2D45 78E1 C862 25DC 8831 AF70 D368 +James Almer 7751 2E8C FD94 A169 57E6 9A7A 1463 01AD 7376 59E0 Jean Delvare 7CA6 9F44 60F1 BDC4 1FD2 C858 A552 6B9B B3CD 4E6A Loren Merritt ABD9 08F4 C920 3F65 D8BE 35D7 1540 DAA7 060F 56DE Lou Logan 7D68 DC73 CBEF EABB 671A B6CF 621C 2E28 82F8 DC3A diff --git a/Makefile b/Makefile index 642651d4ccda5..0cd0a1d6f2d55 100644 --- a/Makefile +++ b/Makefile @@ -45,12 +45,11 @@ FF_DEP_LIBS := $(DEP_LIBS) FF_STATIC_DEP_LIBS := $(STATIC_DEP_LIBS) $(TOOLS): %$(EXESUF): %.o - $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) + $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(EXTRALIBS-$(*F)) $(EXTRALIBS) $(ELIBS) target_dec_%_fuzzer$(EXESUF): target_dec_%_fuzzer.o $(FF_DEP_LIBS) $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $^ $(ELIBS) $(FF_EXTRALIBS) $(LIBFUZZER_PATH) -tools/cws2fws$(EXESUF): ELIBS = $(ZLIB) tools/sofa2wavs$(EXESUF): ELIBS = $(FF_EXTRALIBS) tools/uncoded_frame$(EXESUF): $(FF_DEP_LIBS) tools/uncoded_frame$(EXESUF): ELIBS = $(FF_EXTRALIBS) @@ -128,25 +127,24 @@ install-data: $(DATA_FILES) $(Q)mkdir -p "$(DATADIR)" $(INSTALL) -m 644 $(DATA_FILES) "$(DATADIR)" -uninstall: uninstall-libs uninstall-headers uninstall-data +uninstall: uninstall-data uninstall-headers uninstall-libs uninstall-pkgconfig uninstall-data: $(RM) -r "$(DATADIR)" clean:: $(RM) $(CLEANSUFFIXES) - $(RM) $(CLEANSUFFIXES:%=compat/msvcrt/%) - $(RM) $(CLEANSUFFIXES:%=compat/atomics/pthread/%) - $(RM) $(CLEANSUFFIXES:%=compat/%) + $(RM) $(addprefix compat/,$(CLEANSUFFIXES)) $(addprefix compat/*/,$(CLEANSUFFIXES)) $(RM) -r coverage-html $(RM) -rf coverage.info coverage.info.in lcov -distclean:: - $(RM) $(DISTCLEANSUFFIXES) +distclean:: clean $(RM) .version avversion.h config.asm config.h mapfile \ ffbuild/.config ffbuild/config.* libavutil/avconfig.h \ version.h libavutil/ffversion.h libavcodec/codec_names.h \ - libavcodec/bsf_list.c libavformat/protocol_list.c + libavcodec/bsf_list.c libavformat/protocol_list.c \ + libavcodec/codec_list.c libavcodec/parser_list.c \ + libavformat/muxer_list.c libavformat/demuxer_list.c ifeq ($(SRC_LINK),src) $(RM) src endif @@ -155,6 +153,7 @@ endif config: $(SRC_PATH)/configure $(value FFMPEG_CONFIGURATION) +build: all alltools examples testprogs check: all alltools examples testprogs fate include $(SRC_PATH)/tests/Makefile @@ -170,4 +169,5 @@ $(sort $(OBJDIRS)): # so this saves some time on slow systems. .SUFFIXES: -.PHONY: all all-yes alltools check *clean config install* testprogs uninstall* +.PHONY: all all-yes alltools build check config testprogs +.PHONY: *clean install* uninstall* diff --git a/README.md b/README.md index 7d5a7efe9eaa9..447347c70064a 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,6 @@ such as audio, video, subtitles and related metadata. * [ffplay](https://ffmpeg.org/ffplay.html) is a minimalistic multimedia player. * [ffprobe](https://ffmpeg.org/ffprobe.html) is a simple analysis tool to inspect multimedia content. -* [ffserver](https://ffmpeg.org/ffserver.html) is a multimedia streaming server - for live broadcasts. * Additional small tools such as `aviocat`, `ismindex` and `qt-faststart`. ## Documentation diff --git a/RELEASE b/RELEASE index 48ea63d1809a3..5186d07068cfe 100644 --- a/RELEASE +++ b/RELEASE @@ -1 +1 @@ -3.3.git +4.0 diff --git a/RELEASE_NOTES b/RELEASE_NOTES new file mode 100644 index 0000000000000..7129a9d669a1d --- /dev/null +++ b/RELEASE_NOTES @@ -0,0 +1,15 @@ + + ┌───────────────────────────────────┐ + │ RELEASE NOTES for FFmpeg 4.0 "Wu" │ + └───────────────────────────────────┘ + + The FFmpeg Project proudly presents FFmpeg 4.0 "Wu", about 6 + months after the release of FFmpeg 3.4. + + A complete Changelog is available at the root of the project, and the + complete Git history on https://git.ffmpeg.org/gitweb/ffmpeg.git + + We hope you will like this release as much as we enjoyed working on it, and + as usual, if you have any questions about it, or any FFmpeg related topic, + feel free to join us on the #ffmpeg IRC channel (on irc.freenode.net) or ask + on the mailing-lists. diff --git a/compat/cuda/dynlink_cuda.h b/compat/cuda/dynlink_cuda.h deleted file mode 100644 index 3a13611ce6458..0000000000000 --- a/compat/cuda/dynlink_cuda.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * This copyright notice applies to this header file only: - * - * Copyright (c) 2016 - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the software, and to permit persons to whom the - * software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -#if !defined(AV_COMPAT_DYNLINK_CUDA_H) && !defined(CUDA_VERSION) -#define AV_COMPAT_DYNLINK_CUDA_H - -#include - -#define CUDA_VERSION 7050 - -#if defined(_WIN32) || defined(__CYGWIN__) -#define CUDAAPI __stdcall -#else -#define CUDAAPI -#endif - -#define CU_CTX_SCHED_BLOCKING_SYNC 4 - -typedef int CUdevice; -typedef void* CUarray; -typedef void* CUcontext; -typedef void* CUstream; -#if defined(__x86_64) || defined(AMD64) || defined(_M_AMD64) -typedef unsigned long long CUdeviceptr; -#else -typedef unsigned int CUdeviceptr; -#endif - -typedef enum cudaError_enum { - CUDA_SUCCESS = 0 -} CUresult; - -typedef enum CUmemorytype_enum { - CU_MEMORYTYPE_HOST = 1, - CU_MEMORYTYPE_DEVICE = 2 -} CUmemorytype; - -typedef struct CUDA_MEMCPY2D_st { - size_t srcXInBytes; - size_t srcY; - CUmemorytype srcMemoryType; - const void *srcHost; - CUdeviceptr srcDevice; - CUarray srcArray; - size_t srcPitch; - - size_t dstXInBytes; - size_t dstY; - CUmemorytype dstMemoryType; - void *dstHost; - CUdeviceptr dstDevice; - CUarray dstArray; - size_t dstPitch; - - size_t WidthInBytes; - size_t Height; -} CUDA_MEMCPY2D; - -typedef CUresult CUDAAPI tcuInit(unsigned int Flags); -typedef CUresult CUDAAPI tcuDeviceGetCount(int *count); -typedef CUresult CUDAAPI tcuDeviceGet(CUdevice *device, int ordinal); -typedef CUresult CUDAAPI tcuDeviceGetName(char *name, int len, CUdevice dev); -typedef CUresult CUDAAPI tcuDeviceComputeCapability(int *major, int *minor, CUdevice dev); -typedef CUresult CUDAAPI tcuCtxCreate_v2(CUcontext *pctx, unsigned int flags, CUdevice dev); -typedef CUresult CUDAAPI tcuCtxPushCurrent_v2(CUcontext *pctx); -typedef CUresult CUDAAPI tcuCtxPopCurrent_v2(CUcontext *pctx); -typedef CUresult CUDAAPI tcuCtxDestroy_v2(CUcontext ctx); -typedef CUresult CUDAAPI tcuMemAlloc_v2(CUdeviceptr *dptr, size_t bytesize); -typedef CUresult CUDAAPI tcuMemFree_v2(CUdeviceptr dptr); -typedef CUresult CUDAAPI tcuMemcpy2D_v2(const CUDA_MEMCPY2D *pcopy); -typedef CUresult CUDAAPI tcuGetErrorName(CUresult error, const char** pstr); -typedef CUresult CUDAAPI tcuGetErrorString(CUresult error, const char** pstr); - -#endif diff --git a/compat/cuda/dynlink_cuviddec.h b/compat/cuda/dynlink_cuviddec.h deleted file mode 100644 index 4af78a186baa8..0000000000000 --- a/compat/cuda/dynlink_cuviddec.h +++ /dev/null @@ -1,886 +0,0 @@ -/* - * This copyright notice applies to this header file only: - * - * Copyright (c) 2010-2017 NVIDIA Corporation - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the software, and to permit persons to whom the - * software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -/*****************************************************************************************************/ -//! \file cuviddec.h -//! NVDECODE API provides video decoding interface to NVIDIA GPU devices. -//! \date 2015-2017 -//! This file contains constants, structure definitions and function prototypes used for decoding. -/*****************************************************************************************************/ - -#if !defined(__CUDA_VIDEO_H__) -#define __CUDA_VIDEO_H__ - -#if defined(_WIN64) || defined(__LP64__) || defined(__x86_64) || defined(AMD64) || defined(_M_AMD64) -#if (CUDA_VERSION >= 3020) && (!defined(CUDA_FORCE_API_VERSION) || (CUDA_FORCE_API_VERSION >= 3020)) -#define __CUVID_DEVPTR64 -#endif -#endif - -#if defined(__cplusplus) -extern "C" { -#endif /* __cplusplus */ - -#if defined(__CYGWIN__) -typedef unsigned int tcu_ulong; -#else -typedef unsigned long tcu_ulong; -#endif - -typedef void *CUvideodecoder; -typedef struct _CUcontextlock_st *CUvideoctxlock; - -/*********************************************************************************/ -//! \enum cudaVideoCodec -//! Video codec enums -//! These enums are used in CUVIDDECODECREATEINFO and CUVIDDECODECAPS structures -/*********************************************************************************/ -typedef enum cudaVideoCodec_enum { - cudaVideoCodec_MPEG1=0, /**< MPEG1 */ - cudaVideoCodec_MPEG2, /**< MPEG2 */ - cudaVideoCodec_MPEG4, /**< MPEG4 */ - cudaVideoCodec_VC1, /**< VC1 */ - cudaVideoCodec_H264, /**< H264 */ - cudaVideoCodec_JPEG, /**< JPEG */ - cudaVideoCodec_H264_SVC, /**< H264-SVC */ - cudaVideoCodec_H264_MVC, /**< H264-MVC */ - cudaVideoCodec_HEVC, /**< HEVC */ - cudaVideoCodec_VP8, /**< VP8 */ - cudaVideoCodec_VP9, /**< VP9 */ - cudaVideoCodec_NumCodecs, /**< Max codecs */ - // Uncompressed YUV - cudaVideoCodec_YUV420 = (('I'<<24)|('Y'<<16)|('U'<<8)|('V')), /**< Y,U,V (4:2:0) */ - cudaVideoCodec_YV12 = (('Y'<<24)|('V'<<16)|('1'<<8)|('2')), /**< Y,V,U (4:2:0) */ - cudaVideoCodec_NV12 = (('N'<<24)|('V'<<16)|('1'<<8)|('2')), /**< Y,UV (4:2:0) */ - cudaVideoCodec_YUYV = (('Y'<<24)|('U'<<16)|('Y'<<8)|('V')), /**< YUYV/YUY2 (4:2:2) */ - cudaVideoCodec_UYVY = (('U'<<24)|('Y'<<16)|('V'<<8)|('Y')) /**< UYVY (4:2:2) */ -} cudaVideoCodec; - -/*********************************************************************************/ -//! \enum cudaVideoSurfaceFormat -//! Video surface format enums used for output format of decoded output -//! These enums are used in CUVIDDECODECREATEINFO structure -/*********************************************************************************/ -typedef enum cudaVideoSurfaceFormat_enum { - cudaVideoSurfaceFormat_NV12=0, /**< NV12 format */ - cudaVideoSurfaceFormat_P016=1 /**< 16 bit semiplaner format. Can be used for 10 bit(6LSB bits 0), - 12 bit (4LSB bits 0) */ -} cudaVideoSurfaceFormat; - -/******************************************************************************************************************/ -//! \enum cudaVideoDeinterlaceMode -//! Deinterlacing mode enums -//! These enums are used in CUVIDDECODECREATEINFO structure -//! Use cudaVideoDeinterlaceMode_Weave for progressive content and for content that doesn't need deinterlacing -//! cudaVideoDeinterlaceMode_Adaptive needs more video memory than other DImodes -/******************************************************************************************************************/ -typedef enum cudaVideoDeinterlaceMode_enum { - cudaVideoDeinterlaceMode_Weave=0, /**< Weave both fields (no deinterlacing) */ - cudaVideoDeinterlaceMode_Bob, /**< Drop one field */ - cudaVideoDeinterlaceMode_Adaptive /**< Adaptive deinterlacing */ -} cudaVideoDeinterlaceMode; - -/**************************************************************************************************************/ -//! \enum cudaVideoChromaFormat -//! Chroma format enums -//! These enums are used in CUVIDDECODECREATEINFO and CUVIDDECODECAPS structures -//! JPEG supports Monochrome, YUV 4:2:0, YUV 4:2:2 and YUV 4:4:4 chroma formats. -//! H264, HEVC, VP9, VP8, VC1, MPEG1, MPEG2 and MPEG4 support YUV 4:2:0 chroma format only. -/**************************************************************************************************************/ -typedef enum cudaVideoChromaFormat_enum { - cudaVideoChromaFormat_Monochrome=0, /**< MonoChrome */ - cudaVideoChromaFormat_420, /**< YUV 4:2:0 */ - cudaVideoChromaFormat_422, /**< YUV 4:2:2 */ - cudaVideoChromaFormat_444 /**< YUV 4:4:4 */ -} cudaVideoChromaFormat; - -/*************************************************************************************************************/ -//! \enum cudaVideoCreateFlags -//! Decoder flag enums to select preferred decode path -//! cudaVideoCreate_Default and cudaVideoCreate_PreferCUVID are most optimized, use these whenever possible -/*************************************************************************************************************/ -typedef enum cudaVideoCreateFlags_enum { - cudaVideoCreate_Default = 0x00, /**< Default operation mode: use dedicated video engines */ - cudaVideoCreate_PreferCUDA = 0x01, /**< Use CUDA-based decoder (requires valid vidLock object for multi-threading) */ - cudaVideoCreate_PreferDXVA = 0x02, /**< Go through DXVA internally if possible (requires D3D9 interop) */ - cudaVideoCreate_PreferCUVID = 0x04 /**< Use dedicated video engines directly */ -} cudaVideoCreateFlags; - - -/**************************************************************************************************************/ -//! \struct CUVIDDECODECAPS; -//! This structure is used in cuvidGetDecoderCaps API -/**************************************************************************************************************/ -typedef struct _CUVIDDECODECAPS -{ - cudaVideoCodec eCodecType; /**< IN: cudaVideoCodec_XXX */ - cudaVideoChromaFormat eChromaFormat; /**< IN: cudaVideoChromaFormat_XXX */ - unsigned int nBitDepthMinus8; /**< IN: The Value "BitDepth minus 8" */ - unsigned int reserved1[3]; /**< Reserved for future use - set to zero */ - - unsigned char bIsSupported; /**< OUT: 1 if codec supported, 0 if not supported */ - unsigned char reserved2[3]; /**< Reserved for future use - set to zero */ - unsigned int nMaxWidth; /**< OUT: Max supported coded width in pixels */ - unsigned int nMaxHeight; /**< OUT: Max supported coded height in pixels */ - unsigned int nMaxMBCount; /**< OUT: Max supported macroblock count - CodedWidth*CodedHeight/256 must be <= nMaxMBCount */ - unsigned short nMinWidth; /**< OUT: Min supported coded width in pixels */ - unsigned short nMinHeight; /**< OUT: Min supported coded height in pixels */ - unsigned int reserved3[11]; /**< Reserved for future use - set to zero */ -} CUVIDDECODECAPS; - -/**************************************************************************************************************/ -//! \struct CUVIDDECODECREATEINFO -//! This structure is used in cuvidCreateDecoder API -/**************************************************************************************************************/ -typedef struct _CUVIDDECODECREATEINFO -{ - tcu_ulong ulWidth; /**< IN: Coded sequence width in pixels */ - tcu_ulong ulHeight; /**< IN: Coded sequence height in pixels */ - tcu_ulong ulNumDecodeSurfaces; /**< IN: Maximum number of internal decode surfaces */ - cudaVideoCodec CodecType; /**< IN: cudaVideoCodec_XXX */ - cudaVideoChromaFormat ChromaFormat; /**< IN: cudaVideoChromaFormat_XXX */ - tcu_ulong ulCreationFlags; /**< IN: Decoder creation flags (cudaVideoCreateFlags_XXX) */ - tcu_ulong bitDepthMinus8; /**< IN: The value "BitDepth minus 8" */ - tcu_ulong ulIntraDecodeOnly; /**< IN: Set 1 only if video has all intra frames (default value is 0). This will - optimize video memory for Intra frames only decoding. The support is limited - to specific codecs(H264 rightnow), the flag will be ignored for codecs which - are not supported. However decoding might fail if the flag is enabled in case - of supported codecs for regular bit streams having P and/or B frames. */ - tcu_ulong Reserved1[3]; /**< Reserved for future use - set to zero */ - /** - * IN: area of the frame that should be displayed - */ - struct { - short left; - short top; - short right; - short bottom; - } display_area; - - cudaVideoSurfaceFormat OutputFormat; /**< IN: cudaVideoSurfaceFormat_XXX */ - cudaVideoDeinterlaceMode DeinterlaceMode; /**< IN: cudaVideoDeinterlaceMode_XXX */ - tcu_ulong ulTargetWidth; /**< IN: Post-processed output width (Should be aligned to 2) */ - tcu_ulong ulTargetHeight; /**< IN: Post-processed output height (Should be aligbed to 2) */ - tcu_ulong ulNumOutputSurfaces; /**< IN: Maximum number of output surfaces simultaneously mapped */ - CUvideoctxlock vidLock; /**< IN: If non-NULL, context lock used for synchronizing ownership of - the cuda context. Needed for cudaVideoCreate_PreferCUDA decode */ - /** - * IN: target rectangle in the output frame (for aspect ratio conversion) - * if a null rectangle is specified, {0,0,ulTargetWidth,ulTargetHeight} will be used - */ - struct { - short left; - short top; - short right; - short bottom; - } target_rect; - tcu_ulong Reserved2[5]; /**< Reserved for future use - set to zero */ -} CUVIDDECODECREATEINFO; - -/*********************************************************/ -//! \struct CUVIDH264DPBENTRY -//! H.264 DPB entry -//! This structure is used in CUVIDH264PICPARAMS structure -/*********************************************************/ -typedef struct _CUVIDH264DPBENTRY -{ - int PicIdx; /**< picture index of reference frame */ - int FrameIdx; /**< frame_num(short-term) or LongTermFrameIdx(long-term) */ - int is_long_term; /**< 0=short term reference, 1=long term reference */ - int not_existing; /**< non-existing reference frame (corresponding PicIdx should be set to -1) */ - int used_for_reference; /**< 0=unused, 1=top_field, 2=bottom_field, 3=both_fields */ - int FieldOrderCnt[2]; /**< field order count of top and bottom fields */ -} CUVIDH264DPBENTRY; - -/************************************************************/ -//! \struct CUVIDH264MVCEXT -//! H.264 MVC picture parameters ext -//! This structure is used in CUVIDH264PICPARAMS structure -/************************************************************/ -typedef struct _CUVIDH264MVCEXT -{ - int num_views_minus1; /**< Max number of coded views minus 1 in video : Range - 0 to 1023 */ - int view_id; /**< view identifier */ - unsigned char inter_view_flag; /**< 1 if used for inter-view prediction, 0 if not */ - unsigned char num_inter_view_refs_l0; /**< number of inter-view ref pics in RefPicList0 */ - unsigned char num_inter_view_refs_l1; /**< number of inter-view ref pics in RefPicList1 */ - unsigned char MVCReserved8Bits; /**< Reserved bits */ - int InterViewRefsL0[16]; /**< view id of the i-th view component for inter-view prediction in RefPicList0 */ - int InterViewRefsL1[16]; /**< view id of the i-th view component for inter-view prediction in RefPicList1 */ -} CUVIDH264MVCEXT; - -/*********************************************************/ -//! \struct CUVIDH264SVCEXT -//! H.264 SVC picture parameters ext -//! This structure is used in CUVIDH264PICPARAMS structure -/*********************************************************/ -typedef struct _CUVIDH264SVCEXT -{ - unsigned char profile_idc; - unsigned char level_idc; - unsigned char DQId; - unsigned char DQIdMax; - unsigned char disable_inter_layer_deblocking_filter_idc; - unsigned char ref_layer_chroma_phase_y_plus1; - signed char inter_layer_slice_alpha_c0_offset_div2; - signed char inter_layer_slice_beta_offset_div2; - - unsigned short DPBEntryValidFlag; - unsigned char inter_layer_deblocking_filter_control_present_flag; - unsigned char extended_spatial_scalability_idc; - unsigned char adaptive_tcoeff_level_prediction_flag; - unsigned char slice_header_restriction_flag; - unsigned char chroma_phase_x_plus1_flag; - unsigned char chroma_phase_y_plus1; - - unsigned char tcoeff_level_prediction_flag; - unsigned char constrained_intra_resampling_flag; - unsigned char ref_layer_chroma_phase_x_plus1_flag; - unsigned char store_ref_base_pic_flag; - unsigned char Reserved8BitsA; - unsigned char Reserved8BitsB; - - short scaled_ref_layer_left_offset; - short scaled_ref_layer_top_offset; - short scaled_ref_layer_right_offset; - short scaled_ref_layer_bottom_offset; - unsigned short Reserved16Bits; - struct _CUVIDPICPARAMS *pNextLayer; /**< Points to the picparams for the next layer to be decoded. - Linked list ends at the target layer. */ - int bRefBaseLayer; /**< whether to store ref base pic */ -} CUVIDH264SVCEXT; - -/******************************************************/ -//! \struct CUVIDH264PICPARAMS -//! H.264 picture parameters -//! This structure is used in CUVIDPICPARAMS structure -/******************************************************/ -typedef struct _CUVIDH264PICPARAMS -{ - // SPS - int log2_max_frame_num_minus4; - int pic_order_cnt_type; - int log2_max_pic_order_cnt_lsb_minus4; - int delta_pic_order_always_zero_flag; - int frame_mbs_only_flag; - int direct_8x8_inference_flag; - int num_ref_frames; // NOTE: shall meet level 4.1 restrictions - unsigned char residual_colour_transform_flag; - unsigned char bit_depth_luma_minus8; // Must be 0 (only 8-bit supported) - unsigned char bit_depth_chroma_minus8; // Must be 0 (only 8-bit supported) - unsigned char qpprime_y_zero_transform_bypass_flag; - // PPS - int entropy_coding_mode_flag; - int pic_order_present_flag; - int num_ref_idx_l0_active_minus1; - int num_ref_idx_l1_active_minus1; - int weighted_pred_flag; - int weighted_bipred_idc; - int pic_init_qp_minus26; - int deblocking_filter_control_present_flag; - int redundant_pic_cnt_present_flag; - int transform_8x8_mode_flag; - int MbaffFrameFlag; - int constrained_intra_pred_flag; - int chroma_qp_index_offset; - int second_chroma_qp_index_offset; - int ref_pic_flag; - int frame_num; - int CurrFieldOrderCnt[2]; - // DPB - CUVIDH264DPBENTRY dpb[16]; // List of reference frames within the DPB - // Quantization Matrices (raster-order) - unsigned char WeightScale4x4[6][16]; - unsigned char WeightScale8x8[2][64]; - // FMO/ASO - unsigned char fmo_aso_enable; - unsigned char num_slice_groups_minus1; - unsigned char slice_group_map_type; - signed char pic_init_qs_minus26; - unsigned int slice_group_change_rate_minus1; - union - { - unsigned long long slice_group_map_addr; - const unsigned char *pMb2SliceGroupMap; - } fmo; - unsigned int Reserved[12]; - // SVC/MVC - union - { - CUVIDH264MVCEXT mvcext; - CUVIDH264SVCEXT svcext; - }; -} CUVIDH264PICPARAMS; - - -/********************************************************/ -//! \struct CUVIDMPEG2PICPARAMS -//! MPEG-2 picture parameters -//! This structure is used in CUVIDPICPARAMS structure -/********************************************************/ -typedef struct _CUVIDMPEG2PICPARAMS -{ - int ForwardRefIdx; // Picture index of forward reference (P/B-frames) - int BackwardRefIdx; // Picture index of backward reference (B-frames) - int picture_coding_type; - int full_pel_forward_vector; - int full_pel_backward_vector; - int f_code[2][2]; - int intra_dc_precision; - int frame_pred_frame_dct; - int concealment_motion_vectors; - int q_scale_type; - int intra_vlc_format; - int alternate_scan; - int top_field_first; - // Quantization matrices (raster order) - unsigned char QuantMatrixIntra[64]; - unsigned char QuantMatrixInter[64]; -} CUVIDMPEG2PICPARAMS; - -// MPEG-4 has VOP types instead of Picture types -#define I_VOP 0 -#define P_VOP 1 -#define B_VOP 2 -#define S_VOP 3 - -/*******************************************************/ -//! \struct CUVIDMPEG4PICPARAMS -//! MPEG-4 picture parameters -//! This structure is used in CUVIDPICPARAMS structure -/*******************************************************/ -typedef struct _CUVIDMPEG4PICPARAMS -{ - int ForwardRefIdx; // Picture index of forward reference (P/B-frames) - int BackwardRefIdx; // Picture index of backward reference (B-frames) - // VOL - int video_object_layer_width; - int video_object_layer_height; - int vop_time_increment_bitcount; - int top_field_first; - int resync_marker_disable; - int quant_type; - int quarter_sample; - int short_video_header; - int divx_flags; - // VOP - int vop_coding_type; - int vop_coded; - int vop_rounding_type; - int alternate_vertical_scan_flag; - int interlaced; - int vop_fcode_forward; - int vop_fcode_backward; - int trd[2]; - int trb[2]; - // Quantization matrices (raster order) - unsigned char QuantMatrixIntra[64]; - unsigned char QuantMatrixInter[64]; - int gmc_enabled; -} CUVIDMPEG4PICPARAMS; - -/********************************************************/ -//! \struct CUVIDVC1PICPARAMS -//! VC1 picture parameters -//! This structure is used in CUVIDPICPARAMS structure -/********************************************************/ -typedef struct _CUVIDVC1PICPARAMS -{ - int ForwardRefIdx; /**< Picture index of forward reference (P/B-frames) */ - int BackwardRefIdx; /**< Picture index of backward reference (B-frames) */ - int FrameWidth; /**< Actual frame width */ - int FrameHeight; /**< Actual frame height */ - // PICTURE - int intra_pic_flag; /**< Set to 1 for I,BI frames */ - int ref_pic_flag; /**< Set to 1 for I,P frames */ - int progressive_fcm; /**< Progressive frame */ - // SEQUENCE - int profile; - int postprocflag; - int pulldown; - int interlace; - int tfcntrflag; - int finterpflag; - int psf; - int multires; - int syncmarker; - int rangered; - int maxbframes; - // ENTRYPOINT - int panscan_flag; - int refdist_flag; - int extended_mv; - int dquant; - int vstransform; - int loopfilter; - int fastuvmc; - int overlap; - int quantizer; - int extended_dmv; - int range_mapy_flag; - int range_mapy; - int range_mapuv_flag; - int range_mapuv; - int rangeredfrm; // range reduction state -} CUVIDVC1PICPARAMS; - -/***********************************************************/ -//! \struct CUVIDJPEGPICPARAMS -//! JPEG picture parameters -//! This structure is used in CUVIDPICPARAMS structure -/***********************************************************/ -typedef struct _CUVIDJPEGPICPARAMS -{ - int Reserved; -} CUVIDJPEGPICPARAMS; - - -/*******************************************************/ -//! \struct CUVIDHEVCPICPARAMS -//! HEVC picture parameters -//! This structure is used in CUVIDPICPARAMS structure -/*******************************************************/ -typedef struct _CUVIDHEVCPICPARAMS -{ - // sps - int pic_width_in_luma_samples; - int pic_height_in_luma_samples; - unsigned char log2_min_luma_coding_block_size_minus3; - unsigned char log2_diff_max_min_luma_coding_block_size; - unsigned char log2_min_transform_block_size_minus2; - unsigned char log2_diff_max_min_transform_block_size; - unsigned char pcm_enabled_flag; - unsigned char log2_min_pcm_luma_coding_block_size_minus3; - unsigned char log2_diff_max_min_pcm_luma_coding_block_size; - unsigned char pcm_sample_bit_depth_luma_minus1; - - unsigned char pcm_sample_bit_depth_chroma_minus1; - unsigned char pcm_loop_filter_disabled_flag; - unsigned char strong_intra_smoothing_enabled_flag; - unsigned char max_transform_hierarchy_depth_intra; - unsigned char max_transform_hierarchy_depth_inter; - unsigned char amp_enabled_flag; - unsigned char separate_colour_plane_flag; - unsigned char log2_max_pic_order_cnt_lsb_minus4; - - unsigned char num_short_term_ref_pic_sets; - unsigned char long_term_ref_pics_present_flag; - unsigned char num_long_term_ref_pics_sps; - unsigned char sps_temporal_mvp_enabled_flag; - unsigned char sample_adaptive_offset_enabled_flag; - unsigned char scaling_list_enable_flag; - unsigned char IrapPicFlag; - unsigned char IdrPicFlag; - - unsigned char bit_depth_luma_minus8; - unsigned char bit_depth_chroma_minus8; - unsigned char reserved1[14]; - - // pps - unsigned char dependent_slice_segments_enabled_flag; - unsigned char slice_segment_header_extension_present_flag; - unsigned char sign_data_hiding_enabled_flag; - unsigned char cu_qp_delta_enabled_flag; - unsigned char diff_cu_qp_delta_depth; - signed char init_qp_minus26; - signed char pps_cb_qp_offset; - signed char pps_cr_qp_offset; - - unsigned char constrained_intra_pred_flag; - unsigned char weighted_pred_flag; - unsigned char weighted_bipred_flag; - unsigned char transform_skip_enabled_flag; - unsigned char transquant_bypass_enabled_flag; - unsigned char entropy_coding_sync_enabled_flag; - unsigned char log2_parallel_merge_level_minus2; - unsigned char num_extra_slice_header_bits; - - unsigned char loop_filter_across_tiles_enabled_flag; - unsigned char loop_filter_across_slices_enabled_flag; - unsigned char output_flag_present_flag; - unsigned char num_ref_idx_l0_default_active_minus1; - unsigned char num_ref_idx_l1_default_active_minus1; - unsigned char lists_modification_present_flag; - unsigned char cabac_init_present_flag; - unsigned char pps_slice_chroma_qp_offsets_present_flag; - - unsigned char deblocking_filter_override_enabled_flag; - unsigned char pps_deblocking_filter_disabled_flag; - signed char pps_beta_offset_div2; - signed char pps_tc_offset_div2; - unsigned char tiles_enabled_flag; - unsigned char uniform_spacing_flag; - unsigned char num_tile_columns_minus1; - unsigned char num_tile_rows_minus1; - - unsigned short column_width_minus1[21]; - unsigned short row_height_minus1[21]; - unsigned int reserved3[15]; - - // RefPicSets - int NumBitsForShortTermRPSInSlice; - int NumDeltaPocsOfRefRpsIdx; - int NumPocTotalCurr; - int NumPocStCurrBefore; - int NumPocStCurrAfter; - int NumPocLtCurr; - int CurrPicOrderCntVal; - int RefPicIdx[16]; // [refpic] Indices of valid reference pictures (-1 if unused for reference) - int PicOrderCntVal[16]; // [refpic] - unsigned char IsLongTerm[16]; // [refpic] 0=not a long-term reference, 1=long-term reference - unsigned char RefPicSetStCurrBefore[8]; // [0..NumPocStCurrBefore-1] -> refpic (0..15) - unsigned char RefPicSetStCurrAfter[8]; // [0..NumPocStCurrAfter-1] -> refpic (0..15) - unsigned char RefPicSetLtCurr[8]; // [0..NumPocLtCurr-1] -> refpic (0..15) - unsigned char RefPicSetInterLayer0[8]; - unsigned char RefPicSetInterLayer1[8]; - unsigned int reserved4[12]; - - // scaling lists (diag order) - unsigned char ScalingList4x4[6][16]; // [matrixId][i] - unsigned char ScalingList8x8[6][64]; // [matrixId][i] - unsigned char ScalingList16x16[6][64]; // [matrixId][i] - unsigned char ScalingList32x32[2][64]; // [matrixId][i] - unsigned char ScalingListDCCoeff16x16[6]; // [matrixId] - unsigned char ScalingListDCCoeff32x32[2]; // [matrixId] -} CUVIDHEVCPICPARAMS; - - -/***********************************************************/ -//! \struct CUVIDVP8PICPARAMS -//! VP8 picture parameters -//! This structure is used in CUVIDPICPARAMS structure -/***********************************************************/ -typedef struct _CUVIDVP8PICPARAMS -{ - int width; - int height; - unsigned int first_partition_size; - //Frame Indexes - unsigned char LastRefIdx; - unsigned char GoldenRefIdx; - unsigned char AltRefIdx; - union { - struct { - unsigned char frame_type : 1; /**< 0 = KEYFRAME, 1 = INTERFRAME */ - unsigned char version : 3; - unsigned char show_frame : 1; - unsigned char update_mb_segmentation_data : 1; /**< Must be 0 if segmentation is not enabled */ - unsigned char Reserved2Bits : 2; - }; - unsigned char wFrameTagFlags; - }; - unsigned char Reserved1[4]; - unsigned int Reserved2[3]; -} CUVIDVP8PICPARAMS; - -/***********************************************************/ -//! \struct CUVIDVP9PICPARAMS -//! VP9 picture parameters -//! This structure is used in CUVIDPICPARAMS structure -/***********************************************************/ -typedef struct _CUVIDVP9PICPARAMS -{ - unsigned int width; - unsigned int height; - - //Frame Indices - unsigned char LastRefIdx; - unsigned char GoldenRefIdx; - unsigned char AltRefIdx; - unsigned char colorSpace; - - unsigned short profile : 3; - unsigned short frameContextIdx : 2; - unsigned short frameType : 1; - unsigned short showFrame : 1; - unsigned short errorResilient : 1; - unsigned short frameParallelDecoding : 1; - unsigned short subSamplingX : 1; - unsigned short subSamplingY : 1; - unsigned short intraOnly : 1; - unsigned short allow_high_precision_mv : 1; - unsigned short refreshEntropyProbs : 1; - unsigned short reserved2Bits : 2; - - unsigned short reserved16Bits; - - unsigned char refFrameSignBias[4]; - - unsigned char bitDepthMinus8Luma; - unsigned char bitDepthMinus8Chroma; - unsigned char loopFilterLevel; - unsigned char loopFilterSharpness; - - unsigned char modeRefLfEnabled; - unsigned char log2_tile_columns; - unsigned char log2_tile_rows; - - unsigned char segmentEnabled : 1; - unsigned char segmentMapUpdate : 1; - unsigned char segmentMapTemporalUpdate : 1; - unsigned char segmentFeatureMode : 1; - unsigned char reserved4Bits : 4; - - - unsigned char segmentFeatureEnable[8][4]; - short segmentFeatureData[8][4]; - unsigned char mb_segment_tree_probs[7]; - unsigned char segment_pred_probs[3]; - unsigned char reservedSegment16Bits[2]; - - int qpYAc; - int qpYDc; - int qpChDc; - int qpChAc; - - unsigned int activeRefIdx[3]; - unsigned int resetFrameContext; - unsigned int mcomp_filter_type; - unsigned int mbRefLfDelta[4]; - unsigned int mbModeLfDelta[2]; - unsigned int frameTagSize; - unsigned int offsetToDctParts; - unsigned int reserved128Bits[4]; - -} CUVIDVP9PICPARAMS; - - -/******************************************************************************************/ -//! \struct CUVIDPICPARAMS -//! Picture parameters for decoding -//! This structure is used in cuvidDecodePicture API -//! IN for cuvidDecodePicture -/******************************************************************************************/ -typedef struct _CUVIDPICPARAMS -{ - int PicWidthInMbs; /**< IN: Coded frame size in macroblocks */ - int FrameHeightInMbs; /**< IN: Coded frame height in macroblocks */ - int CurrPicIdx; /**< IN: Output index of the current picture */ - int field_pic_flag; /**< IN: 0=frame picture, 1=field picture */ - int bottom_field_flag; /**< IN: 0=top field, 1=bottom field (ignored if field_pic_flag=0) */ - int second_field; /**< IN: Second field of a complementary field pair */ - // Bitstream data - unsigned int nBitstreamDataLen; /**< IN: Number of bytes in bitstream data buffer */ - const unsigned char *pBitstreamData; /**< IN: Ptr to bitstream data for this picture (slice-layer) */ - unsigned int nNumSlices; /**< IN: Number of slices in this picture */ - const unsigned int *pSliceDataOffsets; /**< IN: nNumSlices entries, contains offset of each slice within - the bitstream data buffer */ - int ref_pic_flag; /**< IN: This picture is a reference picture */ - int intra_pic_flag; /**< IN: This picture is entirely intra coded */ - unsigned int Reserved[30]; /**< Reserved for future use */ - // IN: Codec-specific data - union { - CUVIDMPEG2PICPARAMS mpeg2; /**< Also used for MPEG-1 */ - CUVIDH264PICPARAMS h264; - CUVIDVC1PICPARAMS vc1; - CUVIDMPEG4PICPARAMS mpeg4; - CUVIDJPEGPICPARAMS jpeg; - CUVIDHEVCPICPARAMS hevc; - CUVIDVP8PICPARAMS vp8; - CUVIDVP9PICPARAMS vp9; - unsigned int CodecReserved[1024]; - } CodecSpecific; -} CUVIDPICPARAMS; - - -/******************************************************/ -//! \struct CUVIDPROCPARAMS -//! Picture parameters for postprocessing -//! This structure is used in cuvidMapVideoFrame API -/******************************************************/ -typedef struct _CUVIDPROCPARAMS -{ - int progressive_frame; /**< IN: Input is progressive (deinterlace_mode will be ignored) */ - int second_field; /**< IN: Output the second field (ignored if deinterlace mode is Weave) */ - int top_field_first; /**< IN: Input frame is top field first (1st field is top, 2nd field is bottom) */ - int unpaired_field; /**< IN: Input only contains one field (2nd field is invalid) */ - // The fields below are used for raw YUV input - unsigned int reserved_flags; /**< Reserved for future use (set to zero) */ - unsigned int reserved_zero; /**< Reserved (set to zero) */ - unsigned long long raw_input_dptr; /**< IN: Input CUdeviceptr for raw YUV extensions */ - unsigned int raw_input_pitch; /**< IN: pitch in bytes of raw YUV input (should be aligned appropriately) */ - unsigned int raw_input_format; /**< IN: Input YUV format (cudaVideoCodec_enum) */ - unsigned long long raw_output_dptr; /**< IN: Output CUdeviceptr for raw YUV extensions */ - unsigned int raw_output_pitch; /**< IN: pitch in bytes of raw YUV output (should be aligned appropriately) */ - unsigned int Reserved1; /**< Reserved for future use (set to zero) */ - CUstream output_stream; /**< IN: stream object used by cuvidMapVideoFrame */ - unsigned int Reserved[46]; /**< Reserved for future use (set to zero) */ - void *Reserved2[2]; /**< Reserved for future use (set to zero) */ -} CUVIDPROCPARAMS; - - -/***********************************************************************************************************/ -//! VIDEO_DECODER -//! -//! In order to minimize decode latencies, there should be always at least 2 pictures in the decode -//! queue at any time, in order to make sure that all decode engines are always busy. -//! -//! Overall data flow: -//! - cuvidGetDecoderCaps(...) -//! - cuvidCreateDecoder(...) -//! - For each picture: -//! + cuvidDecodePicture(N) -//! + cuvidMapVideoFrame(N-4) -//! + do some processing in cuda -//! + cuvidUnmapVideoFrame(N-4) -//! + cuvidDecodePicture(N+1) -//! + cuvidMapVideoFrame(N-3) -//! + ... -//! - cuvidDestroyDecoder(...) -//! -//! NOTE: -//! - When the cuda context is created from a D3D device, the D3D device must also be created -//! with the D3DCREATE_MULTITHREADED flag. -//! - There is a limit to how many pictures can be mapped simultaneously (ulNumOutputSurfaces) -//! - cuvidDecodePicture may block the calling thread if there are too many pictures pending -//! in the decode queue -/***********************************************************************************************************/ - - -/**********************************************************************************************************************/ -//! \fn CUresult CUDAAPI cuvidGetDecoderCaps(CUVIDDECODECAPS *pdc) -//! Queries decode capabilities of NVDEC-HW based on CodecType, ChromaFormat and BitDepthMinus8 parameters. -//! 1. Application fills IN parameters CodecType, ChromaFormat and BitDepthMinus8 of CUVIDDECODECAPS structure -//! 2. On calling cuvidGetDecoderCaps, driver fills OUT parameters if the IN parameters are supported -//! If IN parameters passed to the driver are not supported by NVDEC-HW, then all OUT params are set to 0. -//! E.g. on Geforce GTX 960: -//! App fills - eCodecType = cudaVideoCodec_H264; eChromaFormat = cudaVideoChromaFormat_420; nBitDepthMinus8 = 0; -//! Given IN parameters are supported, hence driver fills: bIsSupported = 1; nMinWidth = 48; nMinHeight = 16; -//! nMaxWidth = 4096; nMaxHeight = 4096; nMaxMBCount = 65536; -//! CodedWidth*CodedHeight/256 must be less than or equal to nMaxMBCount -/**********************************************************************************************************************/ -typedef CUresult CUDAAPI tcuvidGetDecoderCaps(CUVIDDECODECAPS *pdc); - -/********************************************************************************************************************/ -//! \fn CUresult CUDAAPI cuvidCreateDecoder(CUvideodecoder *phDecoder, CUVIDDECODECREATEINFO *pdci) -//! Create the decoder object based on pdci. A handle to the created decoder is returned -/********************************************************************************************************************/ -typedef CUresult CUDAAPI tcuvidCreateDecoder(CUvideodecoder *phDecoder, CUVIDDECODECREATEINFO *pdci); -/********************************************************************************************************************/ -//! \fn CUresult CUDAAPI cuvidDestroyDecoder(CUvideodecoder hDecoder) -//! Destroy the decoder object. -/********************************************************************************************************************/ -typedef CUresult CUDAAPI tcuvidDestroyDecoder(CUvideodecoder hDecoder); - -/********************************************************************************************************************/ -//! \fn CUresult CUDAAPI cuvidDecodePicture(CUvideodecoder hDecoder, CUVIDPICPARAMS *pPicParams) -//! Decode a single picture (field or frame) -//! Kicks off HW decoding -/********************************************************************************************************************/ -typedef CUresult CUDAAPI tcuvidDecodePicture(CUvideodecoder hDecoder, CUVIDPICPARAMS *pPicParams); - - -#if !defined(__CUVID_DEVPTR64) || defined(__CUVID_INTERNAL) -/************************************************************************************************************************/ -//! \fn CUresult CUDAAPI cuvidMapVideoFrame(CUvideodecoder hDecoder, int nPicIdx, unsigned int *pDevPtr, -//! unsigned int *pPitch, CUVIDPROCPARAMS *pVPP); -//! Post-process and map video frame corresponding to nPicIdx for use in cuda. Returns cuda device pointer and associated -//! pitch of the video frame -/************************************************************************************************************************/ -typedef CUresult CUDAAPI tcuvidMapVideoFrame(CUvideodecoder hDecoder, int nPicIdx, - unsigned int *pDevPtr, unsigned int *pPitch, - CUVIDPROCPARAMS *pVPP); - -/********************************************************************************************************************/ -//! \fn CUresult CUDAAPI cuvidUnmapVideoFrame(CUvideodecoder hDecoder, unsigned int DevPtr) -//! Unmap a previously mapped video frame -/********************************************************************************************************************/ -typedef CUresult CUDAAPI tcuvidUnmapVideoFrame(CUvideodecoder hDecoder, unsigned int DevPtr); -#endif - -#if defined(_WIN64) || defined(__LP64__) || defined(__x86_64) || defined(AMD64) || defined(_M_AMD64) -/************************************************************************************************************************/ -//! \fn CUresult CUDAAPI cuvidMapVideoFrame64(CUvideodecoder hDecoder, int nPicIdx, unsigned long long *pDevPtr, -//! unsigned int *pPitch, CUVIDPROCPARAMS *pVPP); -//! Post-process and map video frame corresponding to nPicIdx for use in cuda. Returns cuda device pointer and associated -//! pitch of the video frame -/************************************************************************************************************************/ -typedef CUresult CUDAAPI tcuvidMapVideoFrame64(CUvideodecoder hDecoder, int nPicIdx, unsigned long long *pDevPtr, - unsigned int *pPitch, CUVIDPROCPARAMS *pVPP); - -/********************************************************************************************************************/ -//! \fn CUresult CUDAAPI cuvidUnmapVideoFrame64(CUvideodecoder hDecoder, unsigned long long DevPtr); -//! Unmap a previously mapped video frame -/********************************************************************************************************************/ -typedef CUresult CUDAAPI tcuvidUnmapVideoFrame64(CUvideodecoder hDecoder, unsigned long long DevPtr); - -#if defined(__CUVID_DEVPTR64) && !defined(__CUVID_INTERNAL) -#define tcuvidMapVideoFrame tcuvidMapVideoFrame64 -#define tcuvidUnmapVideoFrame tcuvidUnmapVideoFrame64 -#endif -#endif - - - -/********************************************************************************************************************/ -//! -//! Context-locking: to facilitate multi-threaded implementations, the following 4 functions -//! provide a simple mutex-style host synchronization. If a non-NULL context is specified -//! in CUVIDDECODECREATEINFO, the codec library will acquire the mutex associated with the given -//! context before making any cuda calls. -//! A multi-threaded application could create a lock associated with a context handle so that -//! multiple threads can safely share the same cuda context: -//! - use cuCtxPopCurrent immediately after context creation in order to create a 'floating' context -//! that can be passed to cuvidCtxLockCreate. -//! - When using a floating context, all cuda calls should only be made within a cuvidCtxLock/cuvidCtxUnlock section. -//! -//! NOTE: This is a safer alternative to cuCtxPushCurrent and cuCtxPopCurrent, and is not related to video -//! decoder in any way (implemented as a critical section associated with cuCtx{Push|Pop}Current calls). -/********************************************************************************************************************/ - -/********************************************************************************************************************/ -//! \fn CUresult CUDAAPI cuvidCtxLockCreate(CUvideoctxlock *pLock, CUcontext ctx) -//! This API is used to create CtxLock object -/********************************************************************************************************************/ -typedef CUresult CUDAAPI tcuvidCtxLockCreate(CUvideoctxlock *pLock, CUcontext ctx); - -/********************************************************************************************************************/ -//! \fn CUresult CUDAAPI cuvidCtxLockDestroy(CUvideoctxlock lck) -//! This API is used to free CtxLock object -/********************************************************************************************************************/ -typedef CUresult CUDAAPI tcuvidCtxLockDestroy(CUvideoctxlock lck); - -/********************************************************************************************************************/ -//! \fn CUresult CUDAAPI cuvidCtxLock(CUvideoctxlock lck, unsigned int reserved_flags) -//! This API is used to acquire ctxlock -/********************************************************************************************************************/ -typedef CUresult CUDAAPI tcuvidCtxLock(CUvideoctxlock lck, unsigned int reserved_flags); - -/********************************************************************************************************************/ -//! \fn CUresult CUDAAPI cuvidCtxUnlock(CUvideoctxlock lck, unsigned int reserved_flags) -//! This API is used to release ctxlock -/********************************************************************************************************************/ -typedef CUresult CUDAAPI tcuvidCtxUnlock(CUvideoctxlock lck, unsigned int reserved_flags); - -/**********************************************************************************************/ - -#if defined(__cplusplus) -} -#endif /* __cplusplus */ - -#endif // __CUDA_VIDEO_H__ diff --git a/compat/cuda/dynlink_loader.h b/compat/cuda/dynlink_loader.h index 7d2c87449e1e0..9f93465088ed1 100644 --- a/compat/cuda/dynlink_loader.h +++ b/compat/cuda/dynlink_loader.h @@ -1,268 +1,33 @@ /* - * This copyright notice applies to this header file only: + * This file is part of FFmpeg. * - * Copyright (c) 2016 + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the software, and to permit persons to whom the - * software is furnished to do so, subject to the following - * conditions: + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. + * You should have received a copy of the GNU Lesser General 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 AV_COMPAT_CUDA_DYNLINK_LOADER_H #define AV_COMPAT_CUDA_DYNLINK_LOADER_H -#include "compat/cuda/dynlink_cuda.h" -#include "compat/cuda/dynlink_nvcuvid.h" -#include "compat/nvenc/nvEncodeAPI.h" -#include "compat/w32dlfcn.h" - #include "libavutil/log.h" -#include "libavutil/error.h" - -#if defined(_WIN32) -# define LIB_HANDLE HMODULE -#else -# define LIB_HANDLE void* -#endif - -#if defined(_WIN32) || defined(__CYGWIN__) -# define CUDA_LIBNAME "nvcuda.dll" -# define NVCUVID_LIBNAME "nvcuvid.dll" -# if ARCH_X86_64 -# define NVENC_LIBNAME "nvEncodeAPI64.dll" -# else -# define NVENC_LIBNAME "nvEncodeAPI.dll" -# endif -#else -# define CUDA_LIBNAME "libcuda.so.1" -# define NVCUVID_LIBNAME "libnvcuvid.so.1" -# define NVENC_LIBNAME "libnvidia-encode.so.1" -#endif - -#define LOAD_LIBRARY(l, path) \ - do { \ - if (!((l) = dlopen(path, RTLD_LAZY))) { \ - av_log(NULL, AV_LOG_ERROR, "Cannot load %s\n", path); \ - ret = AVERROR_UNKNOWN; \ - goto error; \ - } \ - av_log(NULL, AV_LOG_TRACE, "Loaded lib: %s\n", path); \ - } while (0) - -#define LOAD_SYMBOL(fun, tp, symbol) \ - do { \ - if (!((f->fun) = (tp*)dlsym(f->lib, symbol))) { \ - av_log(NULL, AV_LOG_ERROR, "Cannot load %s\n", symbol); \ - ret = AVERROR_UNKNOWN; \ - goto error; \ - } \ - av_log(NULL, AV_LOG_TRACE, "Loaded sym: %s\n", symbol); \ - } while (0) - -#define LOAD_SYMBOL_OPT(fun, tp, symbol) \ - do { \ - if (!((f->fun) = (tp*)dlsym(f->lib, symbol))) { \ - av_log(NULL, AV_LOG_DEBUG, "Cannot load optional %s\n", symbol); \ - } else { \ - av_log(NULL, AV_LOG_TRACE, "Loaded sym: %s\n", symbol); \ - } \ - } while (0) - -#define GENERIC_LOAD_FUNC_PREAMBLE(T, n, N) \ - T *f; \ - int ret; \ - \ - n##_free_functions(functions); \ - \ - f = *functions = av_mallocz(sizeof(*f)); \ - if (!f) \ - return AVERROR(ENOMEM); \ - \ - LOAD_LIBRARY(f->lib, N); - -#define GENERIC_LOAD_FUNC_FINALE(n) \ - return 0; \ -error: \ - n##_free_functions(functions); \ - return ret; - -#define GENERIC_FREE_FUNC() \ - if (!functions) \ - return; \ - if (*functions && (*functions)->lib) \ - dlclose((*functions)->lib); \ - av_freep(functions); - -#ifdef AV_COMPAT_DYNLINK_CUDA_H -typedef struct CudaFunctions { - tcuInit *cuInit; - tcuDeviceGetCount *cuDeviceGetCount; - tcuDeviceGet *cuDeviceGet; - tcuDeviceGetName *cuDeviceGetName; - tcuDeviceComputeCapability *cuDeviceComputeCapability; - tcuCtxCreate_v2 *cuCtxCreate; - tcuCtxPushCurrent_v2 *cuCtxPushCurrent; - tcuCtxPopCurrent_v2 *cuCtxPopCurrent; - tcuCtxDestroy_v2 *cuCtxDestroy; - tcuMemAlloc_v2 *cuMemAlloc; - tcuMemFree_v2 *cuMemFree; - tcuMemcpy2D_v2 *cuMemcpy2D; - tcuGetErrorName *cuGetErrorName; - tcuGetErrorString *cuGetErrorString; - - LIB_HANDLE lib; -} CudaFunctions; -#else -typedef struct CudaFunctions CudaFunctions; -#endif - -typedef struct CuvidFunctions { - tcuvidGetDecoderCaps *cuvidGetDecoderCaps; - tcuvidCreateDecoder *cuvidCreateDecoder; - tcuvidDestroyDecoder *cuvidDestroyDecoder; - tcuvidDecodePicture *cuvidDecodePicture; - tcuvidMapVideoFrame *cuvidMapVideoFrame; - tcuvidUnmapVideoFrame *cuvidUnmapVideoFrame; - tcuvidCtxLockCreate *cuvidCtxLockCreate; - tcuvidCtxLockDestroy *cuvidCtxLockDestroy; - tcuvidCtxLock *cuvidCtxLock; - tcuvidCtxUnlock *cuvidCtxUnlock; - - tcuvidCreateVideoSource *cuvidCreateVideoSource; - tcuvidCreateVideoSourceW *cuvidCreateVideoSourceW; - tcuvidDestroyVideoSource *cuvidDestroyVideoSource; - tcuvidSetVideoSourceState *cuvidSetVideoSourceState; - tcuvidGetVideoSourceState *cuvidGetVideoSourceState; - tcuvidGetSourceVideoFormat *cuvidGetSourceVideoFormat; - tcuvidGetSourceAudioFormat *cuvidGetSourceAudioFormat; - tcuvidCreateVideoParser *cuvidCreateVideoParser; - tcuvidParseVideoData *cuvidParseVideoData; - tcuvidDestroyVideoParser *cuvidDestroyVideoParser; - - LIB_HANDLE lib; -} CuvidFunctions; - -typedef NVENCSTATUS NVENCAPI tNvEncodeAPICreateInstance(NV_ENCODE_API_FUNCTION_LIST *functionList); -typedef NVENCSTATUS NVENCAPI tNvEncodeAPIGetMaxSupportedVersion(uint32_t* version); - -typedef struct NvencFunctions { - tNvEncodeAPICreateInstance *NvEncodeAPICreateInstance; - tNvEncodeAPIGetMaxSupportedVersion *NvEncodeAPIGetMaxSupportedVersion; - - LIB_HANDLE lib; -} NvencFunctions; - -#ifdef AV_COMPAT_DYNLINK_CUDA_H -static inline void cuda_free_functions(CudaFunctions **functions) -{ - GENERIC_FREE_FUNC(); -} -#endif - -static inline void cuvid_free_functions(CuvidFunctions **functions) -{ - GENERIC_FREE_FUNC(); -} - -static inline void nvenc_free_functions(NvencFunctions **functions) -{ - GENERIC_FREE_FUNC(); -} - -#ifdef AV_COMPAT_DYNLINK_CUDA_H -static inline int cuda_load_functions(CudaFunctions **functions) -{ - GENERIC_LOAD_FUNC_PREAMBLE(CudaFunctions, cuda, CUDA_LIBNAME); - - LOAD_SYMBOL(cuInit, tcuInit, "cuInit"); - LOAD_SYMBOL(cuDeviceGetCount, tcuDeviceGetCount, "cuDeviceGetCount"); - LOAD_SYMBOL(cuDeviceGet, tcuDeviceGet, "cuDeviceGet"); - LOAD_SYMBOL(cuDeviceGetName, tcuDeviceGetName, "cuDeviceGetName"); - LOAD_SYMBOL(cuDeviceComputeCapability, tcuDeviceComputeCapability, "cuDeviceComputeCapability"); - LOAD_SYMBOL(cuCtxCreate, tcuCtxCreate_v2, "cuCtxCreate_v2"); - LOAD_SYMBOL(cuCtxPushCurrent, tcuCtxPushCurrent_v2, "cuCtxPushCurrent_v2"); - LOAD_SYMBOL(cuCtxPopCurrent, tcuCtxPopCurrent_v2, "cuCtxPopCurrent_v2"); - LOAD_SYMBOL(cuCtxDestroy, tcuCtxDestroy_v2, "cuCtxDestroy_v2"); - LOAD_SYMBOL(cuMemAlloc, tcuMemAlloc_v2, "cuMemAlloc_v2"); - LOAD_SYMBOL(cuMemFree, tcuMemFree_v2, "cuMemFree_v2"); - LOAD_SYMBOL(cuMemcpy2D, tcuMemcpy2D_v2, "cuMemcpy2D_v2"); - LOAD_SYMBOL(cuGetErrorName, tcuGetErrorName, "cuGetErrorName"); - LOAD_SYMBOL(cuGetErrorString, tcuGetErrorString, "cuGetErrorString"); - - GENERIC_LOAD_FUNC_FINALE(cuda); -} -#endif - -static inline int cuvid_load_functions(CuvidFunctions **functions) -{ - GENERIC_LOAD_FUNC_PREAMBLE(CuvidFunctions, cuvid, NVCUVID_LIBNAME); - - LOAD_SYMBOL_OPT(cuvidGetDecoderCaps, tcuvidGetDecoderCaps, "cuvidGetDecoderCaps"); - LOAD_SYMBOL(cuvidCreateDecoder, tcuvidCreateDecoder, "cuvidCreateDecoder"); - LOAD_SYMBOL(cuvidDestroyDecoder, tcuvidDestroyDecoder, "cuvidDestroyDecoder"); - LOAD_SYMBOL(cuvidDecodePicture, tcuvidDecodePicture, "cuvidDecodePicture"); -#ifdef __CUVID_DEVPTR64 - LOAD_SYMBOL(cuvidMapVideoFrame, tcuvidMapVideoFrame, "cuvidMapVideoFrame64"); - LOAD_SYMBOL(cuvidUnmapVideoFrame, tcuvidUnmapVideoFrame, "cuvidUnmapVideoFrame64"); -#else - LOAD_SYMBOL(cuvidMapVideoFrame, tcuvidMapVideoFrame, "cuvidMapVideoFrame"); - LOAD_SYMBOL(cuvidUnmapVideoFrame, tcuvidUnmapVideoFrame, "cuvidUnmapVideoFrame"); -#endif - LOAD_SYMBOL(cuvidCtxLockCreate, tcuvidCtxLockCreate, "cuvidCtxLockCreate"); - LOAD_SYMBOL(cuvidCtxLockDestroy, tcuvidCtxLockDestroy, "cuvidCtxLockDestroy"); - LOAD_SYMBOL(cuvidCtxLock, tcuvidCtxLock, "cuvidCtxLock"); - LOAD_SYMBOL(cuvidCtxUnlock, tcuvidCtxUnlock, "cuvidCtxUnlock"); - - LOAD_SYMBOL(cuvidCreateVideoSource, tcuvidCreateVideoSource, "cuvidCreateVideoSource"); - LOAD_SYMBOL(cuvidCreateVideoSourceW, tcuvidCreateVideoSourceW, "cuvidCreateVideoSourceW"); - LOAD_SYMBOL(cuvidDestroyVideoSource, tcuvidDestroyVideoSource, "cuvidDestroyVideoSource"); - LOAD_SYMBOL(cuvidSetVideoSourceState, tcuvidSetVideoSourceState, "cuvidSetVideoSourceState"); - LOAD_SYMBOL(cuvidGetVideoSourceState, tcuvidGetVideoSourceState, "cuvidGetVideoSourceState"); - LOAD_SYMBOL(cuvidGetSourceVideoFormat, tcuvidGetSourceVideoFormat, "cuvidGetSourceVideoFormat"); - LOAD_SYMBOL(cuvidGetSourceAudioFormat, tcuvidGetSourceAudioFormat, "cuvidGetSourceAudioFormat"); - LOAD_SYMBOL(cuvidCreateVideoParser, tcuvidCreateVideoParser, "cuvidCreateVideoParser"); - LOAD_SYMBOL(cuvidParseVideoData, tcuvidParseVideoData, "cuvidParseVideoData"); - LOAD_SYMBOL(cuvidDestroyVideoParser, tcuvidDestroyVideoParser, "cuvidDestroyVideoParser"); - - GENERIC_LOAD_FUNC_FINALE(cuvid); -} - -static inline int nvenc_load_functions(NvencFunctions **functions) -{ - GENERIC_LOAD_FUNC_PREAMBLE(NvencFunctions, nvenc, NVENC_LIBNAME); - - LOAD_SYMBOL(NvEncodeAPICreateInstance, tNvEncodeAPICreateInstance, "NvEncodeAPICreateInstance"); - LOAD_SYMBOL(NvEncodeAPIGetMaxSupportedVersion, tNvEncodeAPIGetMaxSupportedVersion, "NvEncodeAPIGetMaxSupportedVersion"); +#include "compat/w32dlfcn.h" - GENERIC_LOAD_FUNC_FINALE(nvenc); -} +#define FFNV_LOAD_FUNC(path) dlopen((path), RTLD_LAZY) +#define FFNV_SYM_FUNC(lib, sym) dlsym((lib), (sym)) +#define FFNV_FREE_FUNC(lib) dlclose(lib) +#define FFNV_LOG_FUNC(logctx, msg, ...) av_log(logctx, AV_LOG_ERROR, msg, __VA_ARGS__) +#define FFNV_DEBUG_LOG_FUNC(logctx, msg, ...) av_log(logctx, AV_LOG_DEBUG, msg, __VA_ARGS__) -#undef GENERIC_LOAD_FUNC_PREAMBLE -#undef LOAD_LIBRARY -#undef LOAD_SYMBOL -#undef GENERIC_LOAD_FUNC_FINALE -#undef GENERIC_FREE_FUNC -#undef CUDA_LIBNAME -#undef NVCUVID_LIBNAME -#undef NVENC_LIBNAME -#undef LIB_HANDLE +#include #endif - diff --git a/compat/cuda/dynlink_nvcuvid.h b/compat/cuda/dynlink_nvcuvid.h deleted file mode 100644 index 87294248e5a72..0000000000000 --- a/compat/cuda/dynlink_nvcuvid.h +++ /dev/null @@ -1,356 +0,0 @@ -/* - * This copyright notice applies to this header file only: - * - * Copyright (c) 2010-2017 NVIDIA Corporation - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the software, and to permit persons to whom the - * software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -/********************************************************************************************************************/ -//! \file nvcuvid.h -//! NVDECODE API provides video decoding interface to NVIDIA GPU devices. -//! \date 2015-2017 -//! This file contains the interface constants, structure definitions and function prototypes. -/********************************************************************************************************************/ - -#if !defined(__NVCUVID_H__) -#define __NVCUVID_H__ - -#include "compat/cuda/dynlink_cuviddec.h" - -#if defined(__cplusplus) -extern "C" { -#endif /* __cplusplus */ - -/********************************* -** Initialization -*********************************/ -CUresult CUDAAPI cuvidInit(unsigned int Flags); - -/***********************************************/ -//! -//! High-level helper APIs for video sources -//! -/***********************************************/ - -typedef void *CUvideosource; -typedef void *CUvideoparser; -typedef long long CUvideotimestamp; - - -/************************************************************************/ -//! \enum cudaVideoState -//! Video source state enums -//! Used in cuvidSetVideoSourceState and cuvidGetVideoSourceState APIs -/************************************************************************/ -typedef enum { - cudaVideoState_Error = -1, /**< Error state (invalid source) */ - cudaVideoState_Stopped = 0, /**< Source is stopped (or reached end-of-stream) */ - cudaVideoState_Started = 1 /**< Source is running and delivering data */ -} cudaVideoState; - -/************************************************************************/ -//! \enum cudaAudioCodec -//! Audio compression enums -//! Used in CUAUDIOFORMAT structure -/************************************************************************/ -typedef enum { - cudaAudioCodec_MPEG1=0, /**< MPEG-1 Audio */ - cudaAudioCodec_MPEG2, /**< MPEG-2 Audio */ - cudaAudioCodec_MP3, /**< MPEG-1 Layer III Audio */ - cudaAudioCodec_AC3, /**< Dolby Digital (AC3) Audio */ - cudaAudioCodec_LPCM, /**< PCM Audio */ - cudaAudioCodec_AAC, /**< AAC Audio */ -} cudaAudioCodec; - -/************************************************************************************************/ -//! \ingroup STRUCTS -//! \struct CUVIDEOFORMAT -//! Video format -//! Used in cuvidGetSourceVideoFormat API -/************************************************************************************************/ -typedef struct -{ - cudaVideoCodec codec; /**< OUT: Compression format */ - /** - * OUT: frame rate = numerator / denominator (for example: 30000/1001) - */ - struct { - /**< OUT: frame rate numerator (0 = unspecified or variable frame rate) */ - unsigned int numerator; - /**< OUT: frame rate denominator (0 = unspecified or variable frame rate) */ - unsigned int denominator; - } frame_rate; - unsigned char progressive_sequence; /**< OUT: 0=interlaced, 1=progressive */ - unsigned char bit_depth_luma_minus8; /**< OUT: high bit depth luma. E.g, 2 for 10-bitdepth, 4 for 12-bitdepth */ - unsigned char bit_depth_chroma_minus8; /**< OUT: high bit depth chroma. E.g, 2 for 10-bitdepth, 4 for 12-bitdepth */ - unsigned char reserved1; /**< Reserved for future use */ - unsigned int coded_width; /**< OUT: coded frame width in pixels */ - unsigned int coded_height; /**< OUT: coded frame height in pixels */ - /** - * area of the frame that should be displayed - * typical example: - * coded_width = 1920, coded_height = 1088 - * display_area = { 0,0,1920,1080 } - */ - struct { - int left; /**< OUT: left position of display rect */ - int top; /**< OUT: top position of display rect */ - int right; /**< OUT: right position of display rect */ - int bottom; /**< OUT: bottom position of display rect */ - } display_area; - cudaVideoChromaFormat chroma_format; /**< OUT: Chroma format */ - unsigned int bitrate; /**< OUT: video bitrate (bps, 0=unknown) */ - /** - * OUT: Display Aspect Ratio = x:y (4:3, 16:9, etc) - */ - struct { - int x; - int y; - } display_aspect_ratio; - /** - * Video Signal Description - * Refer section E.2.1 (VUI parameters semantics) of H264 spec file - */ - struct { - unsigned char video_format : 3; /**< OUT: 0-Component, 1-PAL, 2-NTSC, 3-SECAM, 4-MAC, 5-Unspecified */ - unsigned char video_full_range_flag : 1; /**< OUT: indicates the black level and luma and chroma range */ - unsigned char reserved_zero_bits : 4; /**< Reserved bits */ - unsigned char color_primaries; /**< OUT: chromaticity coordinates of source primaries */ - unsigned char transfer_characteristics; /**< OUT: opto-electronic transfer characteristic of the source picture */ - unsigned char matrix_coefficients; /**< OUT: used in deriving luma and chroma signals from RGB primaries */ - } video_signal_description; - unsigned int seqhdr_data_length; /**< OUT: Additional bytes following (CUVIDEOFORMATEX) */ -} CUVIDEOFORMAT; - -/****************************************************************/ -//! \ingroup STRUCTS -//! \struct CUVIDEOFORMATEX -//! Video format including raw sequence header information -//! Used in cuvidGetSourceVideoFormat API -/****************************************************************/ -typedef struct -{ - CUVIDEOFORMAT format; /**< OUT: CUVIDEOFORMAT structure */ - unsigned char raw_seqhdr_data[1024]; /**< OUT: Sequence header data */ -} CUVIDEOFORMATEX; - -/****************************************************************/ -//! \ingroup STRUCTS -//! \struct CUAUDIOFORMAT -//! Audio formats -//! Used in cuvidGetSourceAudioFormat API -/****************************************************************/ -typedef struct -{ - cudaAudioCodec codec; /**< OUT: Compression format */ - unsigned int channels; /**< OUT: number of audio channels */ - unsigned int samplespersec; /**< OUT: sampling frequency */ - unsigned int bitrate; /**< OUT: For uncompressed, can also be used to determine bits per sample */ - unsigned int reserved1; /**< Reserved for future use */ - unsigned int reserved2; /**< Reserved for future use */ -} CUAUDIOFORMAT; - - -/***************************************************************/ -//! \enum CUvideopacketflags -//! Data packet flags -//! Used in CUVIDSOURCEDATAPACKET structure -/***************************************************************/ -typedef enum { - CUVID_PKT_ENDOFSTREAM = 0x01, /**< Set when this is the last packet for this stream */ - CUVID_PKT_TIMESTAMP = 0x02, /**< Timestamp is valid */ - CUVID_PKT_DISCONTINUITY = 0x04, /**< Set when a discontinuity has to be signalled */ - CUVID_PKT_ENDOFPICTURE = 0x08, /**< Set when the packet contains exactly one frame */ -} CUvideopacketflags; - -/*****************************************************************************/ -//! \ingroup STRUCTS -//! \struct CUVIDSOURCEDATAPACKET -//! Data Packet -//! Used in cuvidParseVideoData API -//! IN for cuvidParseVideoData -/*****************************************************************************/ -typedef struct _CUVIDSOURCEDATAPACKET -{ - tcu_ulong flags; /**< IN: Combination of CUVID_PKT_XXX flags */ - tcu_ulong payload_size; /**< IN: number of bytes in the payload (may be zero if EOS flag is set) */ - const unsigned char *payload; /**< IN: Pointer to packet payload data (may be NULL if EOS flag is set) */ - CUvideotimestamp timestamp; /**< IN: Presentation time stamp (10MHz clock), only valid if - CUVID_PKT_TIMESTAMP flag is set */ -} CUVIDSOURCEDATAPACKET; - -// Callback for packet delivery -typedef int (CUDAAPI *PFNVIDSOURCECALLBACK)(void *, CUVIDSOURCEDATAPACKET *); - -/**************************************************************************************************************************/ -//! \ingroup STRUCTS -//! \struct CUVIDSOURCEPARAMS -//! Describes parameters needed in cuvidCreateVideoSource API -//! NVDECODE API is intended for HW accelerated video decoding so CUvideosource doesn't have audio demuxer for all supported -//! containers. It's recommended to clients to use their own or third party demuxer if audio support is needed. -/**************************************************************************************************************************/ -typedef struct _CUVIDSOURCEPARAMS -{ - unsigned int ulClockRate; /**< IN: Time stamp units in Hz (0=default=10000000Hz) */ - unsigned int uReserved1[7]; /**< Reserved for future use - set to zero */ - void *pUserData; /**< IN: User private data passed in to the data handlers */ - PFNVIDSOURCECALLBACK pfnVideoDataHandler; /**< IN: Called to deliver video packets */ - PFNVIDSOURCECALLBACK pfnAudioDataHandler; /**< IN: Called to deliver audio packets. */ - void *pvReserved2[8]; /**< Reserved for future use - set to NULL */ -} CUVIDSOURCEPARAMS; - - -/**********************************************/ -//! \ingroup ENUMS -//! \enum CUvideosourceformat_flags -//! CUvideosourceformat_flags -//! Used in cuvidGetSourceVideoFormat API -/**********************************************/ -typedef enum { - CUVID_FMT_EXTFORMATINFO = 0x100 /**< Return extended format structure (CUVIDEOFORMATEX) */ -} CUvideosourceformat_flags; - -#if !defined(__APPLE__) -/**************************************************************************************************************************/ -//! \fn CUresult CUDAAPI cuvidCreateVideoSource(CUvideosource *pObj, const char *pszFileName, CUVIDSOURCEPARAMS *pParams) -//! Create CUvideosource object. CUvideosource spawns demultiplexer thread that provides two callbacks: -//! pfnVideoDataHandler() and pfnAudioDataHandler() -//! NVDECODE API is intended for HW accelerated video decoding so CUvideosource doesn't have audio demuxer for all supported -//! containers. It's recommended to clients to use their own or third party demuxer if audio support is needed. -/**************************************************************************************************************************/ -typedef CUresult CUDAAPI tcuvidCreateVideoSource(CUvideosource *pObj, const char *pszFileName, CUVIDSOURCEPARAMS *pParams); - -/****************************************************************************************************************************/ -//! \fn CUresult CUDAAPI cuvidCreateVideoSourceW(CUvideosource *pObj, const wchar_t *pwszFileName, CUVIDSOURCEPARAMS *pParams) -//! Create video source object and initialize -/****************************************************************************************************************************/ -typedef CUresult CUDAAPI tcuvidCreateVideoSourceW(CUvideosource *pObj, const wchar_t *pwszFileName, CUVIDSOURCEPARAMS *pParams); - -/*********************************************************************/ -//! \fn CUresult CUDAAPI cuvidDestroyVideoSource(CUvideosource obj) -//! Destroy video source -/*********************************************************************/ -typedef CUresult CUDAAPI tcuvidDestroyVideoSource(CUvideosource obj); - -/******************************************************************************************/ -//! \fn CUresult CUDAAPI cuvidSetVideoSourceState(CUvideosource obj, cudaVideoState state) -//! Set video source state -/******************************************************************************************/ -typedef CUresult CUDAAPI tcuvidSetVideoSourceState(CUvideosource obj, cudaVideoState state); - -/******************************************************************************************/ -//! \fn cudaVideoState CUDAAPI cuvidGetVideoSourceState(CUvideosource obj) -//! Get video source state -/******************************************************************************************/ -typedef cudaVideoState CUDAAPI tcuvidGetVideoSourceState(CUvideosource obj); - -/****************************************************************************************************************/ -//! \fn CUresult CUDAAPI cuvidGetSourceVideoFormat(CUvideosource obj, CUVIDEOFORMAT *pvidfmt, unsigned int flags) -//! Gets details of video stream in pvidfmt -/****************************************************************************************************************/ -typedef CUresult CUDAAPI tcuvidGetSourceVideoFormat(CUvideosource obj, CUVIDEOFORMAT *pvidfmt, unsigned int flags); - -/****************************************************************************************************************/ -//! \fn CUresult CUDAAPI cuvidGetSourceAudioFormat(CUvideosource obj, CUAUDIOFORMAT *paudfmt, unsigned int flags) -//! Get audio source format -//! NVDECODE API is intended for HW accelarated video decoding so CUvideosource doesn't have audio demuxer for all suppported -//! containers. It's recommended to clients to use their own or third party demuxer if audio support is needed. -/****************************************************************************************************************/ -typedef CUresult CUDAAPI tcuvidGetSourceAudioFormat(CUvideosource obj, CUAUDIOFORMAT *paudfmt, unsigned int flags); - -#endif -/**********************************************************************************/ -//! \ingroup STRUCTS -//! \struct CUVIDPARSERDISPINFO -//! Used in cuvidParseVideoData API with PFNVIDDISPLAYCALLBACK pfnDisplayPicture -/**********************************************************************************/ -typedef struct _CUVIDPARSERDISPINFO -{ - int picture_index; /**< OUT: Index of the current picture */ - int progressive_frame; /**< OUT: 1 if progressive frame; 0 otherwise */ - int top_field_first; /**< OUT: 1 if top field is displayed first; 0 otherwise */ - int repeat_first_field; /**< OUT: Number of additional fields (1=ivtc, 2=frame doubling, 4=frame tripling, - -1=unpaired field) */ - CUvideotimestamp timestamp; /**< OUT: Presentation time stamp */ -} CUVIDPARSERDISPINFO; - -/***********************************************************************************************************************/ -//! Parser callbacks -//! The parser will call these synchronously from within cuvidParseVideoData(), whenever a picture is ready to -//! be decoded and/or displayed. First argument in functions is "void *pUserData" member of structure CUVIDSOURCEPARAMS -/***********************************************************************************************************************/ -typedef int (CUDAAPI *PFNVIDSEQUENCECALLBACK)(void *, CUVIDEOFORMAT *); -typedef int (CUDAAPI *PFNVIDDECODECALLBACK)(void *, CUVIDPICPARAMS *); -typedef int (CUDAAPI *PFNVIDDISPLAYCALLBACK)(void *, CUVIDPARSERDISPINFO *); - -/**************************************/ -//! \ingroup STRUCTS -//! \struct CUVIDPARSERPARAMS -//! Used in cuvidCreateVideoParser API -/**************************************/ -typedef struct _CUVIDPARSERPARAMS -{ - cudaVideoCodec CodecType; /**< IN: cudaVideoCodec_XXX */ - unsigned int ulMaxNumDecodeSurfaces; /**< IN: Max # of decode surfaces (parser will cycle through these) */ - unsigned int ulClockRate; /**< IN: Timestamp units in Hz (0=default=10000000Hz) */ - unsigned int ulErrorThreshold; /**< IN: % Error threshold (0-100) for calling pfnDecodePicture (100=always - IN: call pfnDecodePicture even if picture bitstream is fully corrupted) */ - unsigned int ulMaxDisplayDelay; /**< IN: Max display queue delay (improves pipelining of decode with display) - 0=no delay (recommended values: 2..4) */ - unsigned int uReserved1[5]; /**< IN: Reserved for future use - set to 0 */ - void *pUserData; /**< IN: User data for callbacks */ - PFNVIDSEQUENCECALLBACK pfnSequenceCallback; /**< IN: Called before decoding frames and/or whenever there is a fmt change */ - PFNVIDDECODECALLBACK pfnDecodePicture; /**< IN: Called when a picture is ready to be decoded (decode order) */ - PFNVIDDISPLAYCALLBACK pfnDisplayPicture; /**< IN: Called whenever a picture is ready to be displayed (display order) */ - void *pvReserved2[7]; /**< Reserved for future use - set to NULL */ - CUVIDEOFORMATEX *pExtVideoInfo; /**< IN: [Optional] sequence header data from system layer */ -} CUVIDPARSERPARAMS; - -/************************************************************************************************/ -//! \fn CUresult CUDAAPI cuvidCreateVideoParser(CUvideoparser *pObj, CUVIDPARSERPARAMS *pParams) -//! Create video parser object and initialize -/************************************************************************************************/ -typedef CUresult CUDAAPI tcuvidCreateVideoParser(CUvideoparser *pObj, CUVIDPARSERPARAMS *pParams); - -/************************************************************************************************/ -//! \fn CUresult CUDAAPI cuvidParseVideoData(CUvideoparser obj, CUVIDSOURCEDATAPACKET *pPacket) -//! Parse the video data from source data packet in pPacket -//! Extracts parameter sets like SPS, PPS, bitstream etc. from pPacket and -//! calls back pfnDecodePicture with CUVIDPICPARAMS data for kicking of HW decoding -/************************************************************************************************/ -typedef CUresult CUDAAPI tcuvidParseVideoData(CUvideoparser obj, CUVIDSOURCEDATAPACKET *pPacket); - -/*******************************************************************/ -//! \fn CUresult CUDAAPI cuvidDestroyVideoParser(CUvideoparser obj) -/*******************************************************************/ -typedef CUresult CUDAAPI tcuvidDestroyVideoParser(CUvideoparser obj); - -/**********************************************************************************************/ - -#if defined(__cplusplus) -} -#endif /* __cplusplus */ - -#endif // __NVCUVID_H__ - - diff --git a/compat/nvenc/nvEncodeAPI.h b/compat/nvenc/nvEncodeAPI.h deleted file mode 100644 index c3a829421282d..0000000000000 --- a/compat/nvenc/nvEncodeAPI.h +++ /dev/null @@ -1,3324 +0,0 @@ -/* - * This copyright notice applies to this header file only: - * - * Copyright (c) 2010-2017 NVIDIA Corporation - * - * Permission is hereby granted, free of charge, to any person - * obtaining a copy of this software and associated documentation - * files (the "Software"), to deal in the Software without - * restriction, including without limitation the rights to use, - * copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the software, and to permit persons to whom the - * software is furnished to do so, subject to the following - * conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR - * OTHER DEALINGS IN THE SOFTWARE. - */ - -/** - * \file nvEncodeAPI.h - * NVIDIA GPUs - beginning with the Kepler generation - contain a hardware-based encoder - * (referred to as NVENC) which provides fully-accelerated hardware-based video encoding. - * NvEncodeAPI provides the interface for NVIDIA video encoder (NVENC). - * \date 2011-2017 - * This file contains the interface constants, structure definitions and function prototypes. - */ - -#ifndef _NV_ENCODEAPI_H_ -#define _NV_ENCODEAPI_H_ - -#include - -#ifdef _WIN32 -#include -#endif - -#ifdef _MSC_VER -#ifndef _STDINT -typedef __int32 int32_t; -typedef unsigned __int32 uint32_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -typedef signed char int8_t; -typedef unsigned char uint8_t; -typedef short int16_t; -typedef unsigned short uint16_t; -#endif -#else -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * \addtogroup ENCODER_STRUCTURE NvEncodeAPI Data structures - * @{ - */ - -#if defined(_WIN32) || defined(__CYGWIN__) -#define NVENCAPI __stdcall -#else -#define NVENCAPI -#endif - -#ifdef _WIN32 -typedef RECT NVENC_RECT; -#else -// ========================================================================================= -#ifndef GUID -/*! - * \struct GUID - * Abstracts the GUID structure for non-windows platforms. - */ -// ========================================================================================= -typedef struct -{ - uint32_t Data1; /**< [in]: Specifies the first 8 hexadecimal digits of the GUID. */ - uint16_t Data2; /**< [in]: Specifies the first group of 4 hexadecimal digits. */ - uint16_t Data3; /**< [in]: Specifies the second group of 4 hexadecimal digits. */ - uint8_t Data4[8]; /**< [in]: Array of 8 bytes. The first 2 bytes contain the third group of 4 hexadecimal digits. - The remaining 6 bytes contain the final 12 hexadecimal digits. */ -} GUID; -#endif // GUID - -/** - * \struct _NVENC_RECT - * Defines a Rectangle. Used in ::NV_ENC_PREPROCESS_FRAME. - */ -typedef struct _NVENC_RECT -{ - uint32_t left; /**< [in]: X coordinate of the upper left corner of rectangular area to be specified. */ - uint32_t top; /**< [in]: Y coordinate of the upper left corner of the rectangular area to be specified. */ - uint32_t right; /**< [in]: X coordinate of the bottom right corner of the rectangular area to be specified. */ - uint32_t bottom; /**< [in]: Y coordinate of the bottom right corner of the rectangular area to be specified. */ -} NVENC_RECT; - -#endif // _WIN32 - -/** @} */ /* End of GUID and NVENC_RECT structure grouping*/ - -typedef void* NV_ENC_INPUT_PTR; /**< NVENCODE API input buffer */ -typedef void* NV_ENC_OUTPUT_PTR; /**< NVENCODE API output buffer*/ -typedef void* NV_ENC_REGISTERED_PTR; /**< A Resource that has been registered with NVENCODE API*/ - -#define NVENCAPI_MAJOR_VERSION 8 -#define NVENCAPI_MINOR_VERSION 0 - -#define NVENCAPI_VERSION (NVENCAPI_MAJOR_VERSION | (NVENCAPI_MINOR_VERSION << 24)) - -/** - * Macro to generate per-structure version for use with API. - */ -#define NVENCAPI_STRUCT_VERSION(ver) ((uint32_t)NVENCAPI_VERSION | ((ver)<<16) | (0x7 << 28)) - - -#define NVENC_INFINITE_GOPLENGTH 0xffffffff - -#define NV_MAX_SEQ_HDR_LEN (512) - -// ========================================================================================= -// Encode Codec GUIDS supported by the NvEncodeAPI interface. -// ========================================================================================= - -// {6BC82762-4E63-4ca4-AA85-1E50F321F6BF} -static const GUID NV_ENC_CODEC_H264_GUID = -{ 0x6bc82762, 0x4e63, 0x4ca4, { 0xaa, 0x85, 0x1e, 0x50, 0xf3, 0x21, 0xf6, 0xbf } }; - -// {790CDC88-4522-4d7b-9425-BDA9975F7603} -static const GUID NV_ENC_CODEC_HEVC_GUID = -{ 0x790cdc88, 0x4522, 0x4d7b, { 0x94, 0x25, 0xbd, 0xa9, 0x97, 0x5f, 0x76, 0x3 } }; - - - -// ========================================================================================= -// * Encode Profile GUIDS supported by the NvEncodeAPI interface. -// ========================================================================================= - -// {BFD6F8E7-233C-4341-8B3E-4818523803F4} -static const GUID NV_ENC_CODEC_PROFILE_AUTOSELECT_GUID = -{ 0xbfd6f8e7, 0x233c, 0x4341, { 0x8b, 0x3e, 0x48, 0x18, 0x52, 0x38, 0x3, 0xf4 } }; - -// {0727BCAA-78C4-4c83-8C2F-EF3DFF267C6A} -static const GUID NV_ENC_H264_PROFILE_BASELINE_GUID = -{ 0x727bcaa, 0x78c4, 0x4c83, { 0x8c, 0x2f, 0xef, 0x3d, 0xff, 0x26, 0x7c, 0x6a } }; - -// {60B5C1D4-67FE-4790-94D5-C4726D7B6E6D} -static const GUID NV_ENC_H264_PROFILE_MAIN_GUID = -{ 0x60b5c1d4, 0x67fe, 0x4790, { 0x94, 0xd5, 0xc4, 0x72, 0x6d, 0x7b, 0x6e, 0x6d } }; - -// {E7CBC309-4F7A-4b89-AF2A-D537C92BE310} -static const GUID NV_ENC_H264_PROFILE_HIGH_GUID = -{ 0xe7cbc309, 0x4f7a, 0x4b89, { 0xaf, 0x2a, 0xd5, 0x37, 0xc9, 0x2b, 0xe3, 0x10 } }; - -// {7AC663CB-A598-4960-B844-339B261A7D52} -static const GUID NV_ENC_H264_PROFILE_HIGH_444_GUID = -{ 0x7ac663cb, 0xa598, 0x4960, { 0xb8, 0x44, 0x33, 0x9b, 0x26, 0x1a, 0x7d, 0x52 } }; - -// {40847BF5-33F7-4601-9084-E8FE3C1DB8B7} -static const GUID NV_ENC_H264_PROFILE_STEREO_GUID = -{ 0x40847bf5, 0x33f7, 0x4601, { 0x90, 0x84, 0xe8, 0xfe, 0x3c, 0x1d, 0xb8, 0xb7 } }; - -// {CE788D20-AAA9-4318-92BB-AC7E858C8D36} -static const GUID NV_ENC_H264_PROFILE_SVC_TEMPORAL_SCALABILTY = -{ 0xce788d20, 0xaaa9, 0x4318, { 0x92, 0xbb, 0xac, 0x7e, 0x85, 0x8c, 0x8d, 0x36 } }; - -// {B405AFAC-F32B-417B-89C4-9ABEED3E5978} -static const GUID NV_ENC_H264_PROFILE_PROGRESSIVE_HIGH_GUID = -{ 0xb405afac, 0xf32b, 0x417b, { 0x89, 0xc4, 0x9a, 0xbe, 0xed, 0x3e, 0x59, 0x78 } }; - -// {AEC1BD87-E85B-48f2-84C3-98BCA6285072} -static const GUID NV_ENC_H264_PROFILE_CONSTRAINED_HIGH_GUID = -{ 0xaec1bd87, 0xe85b, 0x48f2, { 0x84, 0xc3, 0x98, 0xbc, 0xa6, 0x28, 0x50, 0x72 } }; - -// {B514C39A-B55B-40fa-878F-F1253B4DFDEC} -static const GUID NV_ENC_HEVC_PROFILE_MAIN_GUID = -{ 0xb514c39a, 0xb55b, 0x40fa, { 0x87, 0x8f, 0xf1, 0x25, 0x3b, 0x4d, 0xfd, 0xec } }; - -// {fa4d2b6c-3a5b-411a-8018-0a3f5e3c9be5} -static const GUID NV_ENC_HEVC_PROFILE_MAIN10_GUID = -{ 0xfa4d2b6c, 0x3a5b, 0x411a, { 0x80, 0x18, 0x0a, 0x3f, 0x5e, 0x3c, 0x9b, 0xe5 } }; - -// For HEVC Main 444 8 bit and HEVC Main 444 10 bit profiles only -// {51ec32b5-1b4c-453c-9cbd-b616bd621341} -static const GUID NV_ENC_HEVC_PROFILE_FREXT_GUID = -{ 0x51ec32b5, 0x1b4c, 0x453c, { 0x9c, 0xbd, 0xb6, 0x16, 0xbd, 0x62, 0x13, 0x41 } }; - -// ========================================================================================= -// * Preset GUIDS supported by the NvEncodeAPI interface. -// ========================================================================================= -// {B2DFB705-4EBD-4C49-9B5F-24A777D3E587} -static const GUID NV_ENC_PRESET_DEFAULT_GUID = -{ 0xb2dfb705, 0x4ebd, 0x4c49, { 0x9b, 0x5f, 0x24, 0xa7, 0x77, 0xd3, 0xe5, 0x87 } }; - -// {60E4C59F-E846-4484-A56D-CD45BE9FDDF6} -static const GUID NV_ENC_PRESET_HP_GUID = -{ 0x60e4c59f, 0xe846, 0x4484, { 0xa5, 0x6d, 0xcd, 0x45, 0xbe, 0x9f, 0xdd, 0xf6 } }; - -// {34DBA71D-A77B-4B8F-9C3E-B6D5DA24C012} -static const GUID NV_ENC_PRESET_HQ_GUID = -{ 0x34dba71d, 0xa77b, 0x4b8f, { 0x9c, 0x3e, 0xb6, 0xd5, 0xda, 0x24, 0xc0, 0x12 } }; - -// {82E3E450-BDBB-4e40-989C-82A90DF9EF32} -static const GUID NV_ENC_PRESET_BD_GUID = -{ 0x82e3e450, 0xbdbb, 0x4e40, { 0x98, 0x9c, 0x82, 0xa9, 0xd, 0xf9, 0xef, 0x32 } }; - -// {49DF21C5-6DFA-4feb-9787-6ACC9EFFB726} -static const GUID NV_ENC_PRESET_LOW_LATENCY_DEFAULT_GUID = -{ 0x49df21c5, 0x6dfa, 0x4feb, { 0x97, 0x87, 0x6a, 0xcc, 0x9e, 0xff, 0xb7, 0x26 } }; - -// {C5F733B9-EA97-4cf9-BEC2-BF78A74FD105} -static const GUID NV_ENC_PRESET_LOW_LATENCY_HQ_GUID = -{ 0xc5f733b9, 0xea97, 0x4cf9, { 0xbe, 0xc2, 0xbf, 0x78, 0xa7, 0x4f, 0xd1, 0x5 } }; - -// {67082A44-4BAD-48FA-98EA-93056D150A58} -static const GUID NV_ENC_PRESET_LOW_LATENCY_HP_GUID = -{ 0x67082a44, 0x4bad, 0x48fa, { 0x98, 0xea, 0x93, 0x5, 0x6d, 0x15, 0xa, 0x58 } }; - -// {D5BFB716-C604-44e7-9BB8-DEA5510FC3AC} -static const GUID NV_ENC_PRESET_LOSSLESS_DEFAULT_GUID = -{ 0xd5bfb716, 0xc604, 0x44e7, { 0x9b, 0xb8, 0xde, 0xa5, 0x51, 0xf, 0xc3, 0xac } }; - -// {149998E7-2364-411d-82EF-179888093409} -static const GUID NV_ENC_PRESET_LOSSLESS_HP_GUID = -{ 0x149998e7, 0x2364, 0x411d, { 0x82, 0xef, 0x17, 0x98, 0x88, 0x9, 0x34, 0x9 } }; - -/** - * \addtogroup ENCODER_STRUCTURE NvEncodeAPI Data structures - * @{ - */ - -/** - * Input frame encode modes - */ -typedef enum _NV_ENC_PARAMS_FRAME_FIELD_MODE -{ - NV_ENC_PARAMS_FRAME_FIELD_MODE_FRAME = 0x01, /**< Frame mode */ - NV_ENC_PARAMS_FRAME_FIELD_MODE_FIELD = 0x02, /**< Field mode */ - NV_ENC_PARAMS_FRAME_FIELD_MODE_MBAFF = 0x03 /**< MB adaptive frame/field */ -} NV_ENC_PARAMS_FRAME_FIELD_MODE; - -/** - * Rate Control Modes - */ -typedef enum _NV_ENC_PARAMS_RC_MODE -{ - NV_ENC_PARAMS_RC_CONSTQP = 0x0, /**< Constant QP mode */ - NV_ENC_PARAMS_RC_VBR = 0x1, /**< Variable bitrate mode */ - NV_ENC_PARAMS_RC_CBR = 0x2, /**< Constant bitrate mode */ - NV_ENC_PARAMS_RC_CBR_LOWDELAY_HQ = 0x8, /**< low-delay CBR, high quality */ - NV_ENC_PARAMS_RC_CBR_HQ = 0x10, /**< CBR, high quality (slower) */ - NV_ENC_PARAMS_RC_VBR_HQ = 0x20 /**< VBR, high quality (slower) */ -} NV_ENC_PARAMS_RC_MODE; - -#define NV_ENC_PARAMS_RC_VBR_MINQP (NV_ENC_PARAMS_RC_MODE)0x4 /**< Deprecated */ -#define NV_ENC_PARAMS_RC_2_PASS_QUALITY NV_ENC_PARAMS_RC_CBR_LOWDELAY_HQ /**< Deprecated */ -#define NV_ENC_PARAMS_RC_2_PASS_FRAMESIZE_CAP NV_ENC_PARAMS_RC_CBR_HQ /**< Deprecated */ -#define NV_ENC_PARAMS_RC_2_PASS_VBR NV_ENC_PARAMS_RC_VBR_HQ /**< Deprecated */ -#define NV_ENC_PARAMS_RC_CBR2 NV_ENC_PARAMS_RC_CBR /**< Deprecated */ - -/** - * Input picture structure - */ -typedef enum _NV_ENC_PIC_STRUCT -{ - NV_ENC_PIC_STRUCT_FRAME = 0x01, /**< Progressive frame */ - NV_ENC_PIC_STRUCT_FIELD_TOP_BOTTOM = 0x02, /**< Field encoding top field first */ - NV_ENC_PIC_STRUCT_FIELD_BOTTOM_TOP = 0x03 /**< Field encoding bottom field first */ -} NV_ENC_PIC_STRUCT; - -/** - * Input picture type - */ -typedef enum _NV_ENC_PIC_TYPE -{ - NV_ENC_PIC_TYPE_P = 0x0, /**< Forward predicted */ - NV_ENC_PIC_TYPE_B = 0x01, /**< Bi-directionally predicted picture */ - NV_ENC_PIC_TYPE_I = 0x02, /**< Intra predicted picture */ - NV_ENC_PIC_TYPE_IDR = 0x03, /**< IDR picture */ - NV_ENC_PIC_TYPE_BI = 0x04, /**< Bi-directionally predicted with only Intra MBs */ - NV_ENC_PIC_TYPE_SKIPPED = 0x05, /**< Picture is skipped */ - NV_ENC_PIC_TYPE_INTRA_REFRESH = 0x06, /**< First picture in intra refresh cycle */ - NV_ENC_PIC_TYPE_UNKNOWN = 0xFF /**< Picture type unknown */ -} NV_ENC_PIC_TYPE; - -/** - * Motion vector precisions - */ -typedef enum _NV_ENC_MV_PRECISION -{ - NV_ENC_MV_PRECISION_DEFAULT = 0x0, /** (if lookahead is enabled, input frames must remain available to the encoder until encode completion) */ - uint32_t disableIadapt :1; /**< [in]: Set this to 1 to disable adaptive I-frame insertion at scene cuts (only has an effect when lookahead is enabled) */ - uint32_t disableBadapt :1; /**< [in]: Set this to 1 to disable adaptive B-frame decision (only has an effect when lookahead is enabled) */ - uint32_t enableTemporalAQ :1; /**< [in]: Set this to 1 to enable temporal AQ for H.264 */ - uint32_t zeroReorderDelay :1; /**< [in]: Set this to 1 to indicate zero latency operation (no reordering delay, num_reorder_frames=0) */ - uint32_t enableNonRefP :1; /**< [in]: Set this to 1 to enable automatic insertion of non-reference P-frames (no effect if enablePTD=0) */ - uint32_t strictGOPTarget :1; /**< [in]: Set this to 1 to minimize GOP-to-GOP rate fluctuations */ - uint32_t aqStrength :4; /**< [in]: When AQ (Spatial) is enabled (i.e. NV_ENC_RC_PARAMS::enableAQ is set), this field is used to specify AQ strength. AQ strength scale is from 1 (low) - 15 (aggressive). If not set, strength is autoselected by driver. */ - uint32_t reservedBitFields :16; /**< [in]: Reserved bitfields and must be set to 0 */ - NV_ENC_QP minQP; /**< [in]: Specifies the minimum QP used for rate control. Client must set NV_ENC_CONFIG::enableMinQP to 1. */ - NV_ENC_QP maxQP; /**< [in]: Specifies the maximum QP used for rate control. Client must set NV_ENC_CONFIG::enableMaxQP to 1. */ - NV_ENC_QP initialRCQP; /**< [in]: Specifies the initial QP used for rate control. Client must set NV_ENC_CONFIG::enableInitialRCQP to 1. */ - uint32_t temporallayerIdxMask; /**< [in]: Specifies the temporal layers (as a bitmask) whose QPs have changed. Valid max bitmask is [2^NV_ENC_CAPS_NUM_MAX_TEMPORAL_LAYERS - 1] */ - uint8_t temporalLayerQP[8]; /**< [in]: Specifies the temporal layer QPs used for rate control. Temporal layer index is used as as the array index */ - uint8_t targetQuality; /**< [in]: Target CQ (Constant Quality) level for VBR mode (range 0-51 with 0-automatic) */ - uint8_t targetQualityLSB; /**< [in]: Fractional part of target quality (as 8.8 fixed point format) */ - uint16_t lookaheadDepth; /**< [in]: Maximum depth of lookahead with range 0-32 (only used if enableLookahead=1) */ - uint32_t reserved[9]; - } NV_ENC_RC_PARAMS; - -/** macro for constructing the version field of ::_NV_ENC_RC_PARAMS */ -#define NV_ENC_RC_PARAMS_VER NVENCAPI_STRUCT_VERSION(1) - - - -/** - * \struct _NV_ENC_CONFIG_H264_VUI_PARAMETERS - * H264 Video Usability Info parameters - */ -typedef struct _NV_ENC_CONFIG_H264_VUI_PARAMETERS -{ - uint32_t overscanInfoPresentFlag; /**< [in]: if set to 1 , it specifies that the overscanInfo is present */ - uint32_t overscanInfo; /**< [in]: Specifies the overscan info(as defined in Annex E of the ITU-T Specification). */ - uint32_t videoSignalTypePresentFlag; /**< [in]: If set to 1, it specifies that the videoFormat, videoFullRangeFlag and colourDescriptionPresentFlag are present. */ - uint32_t videoFormat; /**< [in]: Specifies the source video format(as defined in Annex E of the ITU-T Specification).*/ - uint32_t videoFullRangeFlag; /**< [in]: Specifies the output range of the luma and chroma samples(as defined in Annex E of the ITU-T Specification). */ - uint32_t colourDescriptionPresentFlag; /**< [in]: If set to 1, it specifies that the colourPrimaries, transferCharacteristics and colourMatrix are present. */ - uint32_t colourPrimaries; /**< [in]: Specifies color primaries for converting to RGB(as defined in Annex E of the ITU-T Specification) */ - uint32_t transferCharacteristics; /**< [in]: Specifies the opto-electronic transfer characteristics to use (as defined in Annex E of the ITU-T Specification) */ - uint32_t colourMatrix; /**< [in]: Specifies the matrix coefficients used in deriving the luma and chroma from the RGB primaries (as defined in Annex E of the ITU-T Specification). */ - uint32_t chromaSampleLocationFlag; /**< [in]: if set to 1 , it specifies that the chromaSampleLocationTop and chromaSampleLocationBot are present.*/ - uint32_t chromaSampleLocationTop; /**< [in]: Specifies the chroma sample location for top field(as defined in Annex E of the ITU-T Specification) */ - uint32_t chromaSampleLocationBot; /**< [in]: Specifies the chroma sample location for bottom field(as defined in Annex E of the ITU-T Specification) */ - uint32_t bitstreamRestrictionFlag; /**< [in]: if set to 1, it specifies the bitstream restriction parameters are present in the bitstream.*/ - uint32_t reserved[15]; -}NV_ENC_CONFIG_H264_VUI_PARAMETERS; - -typedef NV_ENC_CONFIG_H264_VUI_PARAMETERS NV_ENC_CONFIG_HEVC_VUI_PARAMETERS; - -/** - * \struct _NVENC_EXTERNAL_ME_HINT_COUNTS_PER_BLOCKTYPE - * External motion vector hint counts per block type. - * H264 supports multiple hint while HEVC supports one hint for each valid candidate. - */ -typedef struct _NVENC_EXTERNAL_ME_HINT_COUNTS_PER_BLOCKTYPE -{ - uint32_t numCandsPerBlk16x16 : 4; /**< [in]: Supported for H264,HEVC.It Specifies the number of candidates per 16x16 block. */ - uint32_t numCandsPerBlk16x8 : 4; /**< [in]: Supported for H264 only.Specifies the number of candidates per 16x8 block. */ - uint32_t numCandsPerBlk8x16 : 4; /**< [in]: Supported for H264 only.Specifies the number of candidates per 8x16 block. */ - uint32_t numCandsPerBlk8x8 : 4; /**< [in]: Supported for H264,HEVC.Specifies the number of candidates per 8x8 block. */ - uint32_t reserved : 16; /**< [in]: Reserved for padding. */ - uint32_t reserved1[3]; /**< [in]: Reserved for future use. */ -} NVENC_EXTERNAL_ME_HINT_COUNTS_PER_BLOCKTYPE; - - -/** - * \struct _NVENC_EXTERNAL_ME_HINT - * External Motion Vector hint structure. - */ -typedef struct _NVENC_EXTERNAL_ME_HINT -{ - int32_t mvx : 12; /**< [in]: Specifies the x component of integer pixel MV (relative to current MB) S12.0. */ - int32_t mvy : 10; /**< [in]: Specifies the y component of integer pixel MV (relative to current MB) S10.0 .*/ - int32_t refidx : 5; /**< [in]: Specifies the reference index (31=invalid). Current we support only 1 reference frame per direction for external hints, so \p refidx must be 0. */ - int32_t dir : 1; /**< [in]: Specifies the direction of motion estimation . 0=L0 1=L1.*/ - int32_t partType : 2; /**< [in]: Specifies the block partition type.0=16x16 1=16x8 2=8x16 3=8x8 (blocks in partition must be consecutive).*/ - int32_t lastofPart : 1; /**< [in]: Set to 1 for the last MV of (sub) partition */ - int32_t lastOfMB : 1; /**< [in]: Set to 1 for the last MV of macroblock. */ -} NVENC_EXTERNAL_ME_HINT; - - -/** - * \struct _NV_ENC_CONFIG_H264 - * H264 encoder configuration parameters - */ -typedef struct _NV_ENC_CONFIG_H264 -{ - uint32_t enableTemporalSVC :1; /**< [in]: Set to 1 to enable SVC temporal*/ - uint32_t enableStereoMVC :1; /**< [in]: Set to 1 to enable stereo MVC*/ - uint32_t hierarchicalPFrames :1; /**< [in]: Set to 1 to enable hierarchical PFrames */ - uint32_t hierarchicalBFrames :1; /**< [in]: Set to 1 to enable hierarchical BFrames */ - uint32_t outputBufferingPeriodSEI :1; /**< [in]: Set to 1 to write SEI buffering period syntax in the bitstream */ - uint32_t outputPictureTimingSEI :1; /**< [in]: Set to 1 to write SEI picture timing syntax in the bitstream. When set for following rateControlMode : NV_ENC_PARAMS_RC_CBR, NV_ENC_PARAMS_RC_CBR_LOWDELAY_HQ, - NV_ENC_PARAMS_RC_CBR_HQ, filler data is inserted if needed to achieve hrd bitrate */ - uint32_t outputAUD :1; /**< [in]: Set to 1 to write access unit delimiter syntax in bitstream */ - uint32_t disableSPSPPS :1; /**< [in]: Set to 1 to disable writing of Sequence and Picture parameter info in bitstream */ - uint32_t outputFramePackingSEI :1; /**< [in]: Set to 1 to enable writing of frame packing arrangement SEI messages to bitstream */ - uint32_t outputRecoveryPointSEI :1; /**< [in]: Set to 1 to enable writing of recovery point SEI message */ - uint32_t enableIntraRefresh :1; /**< [in]: Set to 1 to enable gradual decoder refresh or intra refresh. If the GOP structure uses B frames this will be ignored */ - uint32_t enableConstrainedEncoding :1; /**< [in]: Set this to 1 to enable constrainedFrame encoding where each slice in the constarined picture is independent of other slices - Check support for constrained encoding using ::NV_ENC_CAPS_SUPPORT_CONSTRAINED_ENCODING caps. */ - uint32_t repeatSPSPPS :1; /**< [in]: Set to 1 to enable writing of Sequence and Picture parameter for every IDR frame */ - uint32_t enableVFR :1; /**< [in]: Set to 1 to enable variable frame rate. */ - uint32_t enableLTR :1; /**< [in]: Set to 1 to enable LTR (Long Term Reference) frame support. LTR can be used in two modes: "LTR Trust" mode and "LTR Per Picture" mode. - LTR Trust mode: In this mode, ltrNumFrames pictures after IDR are automatically marked as LTR. This mode is enabled by setting ltrTrustMode = 1. - Use of LTR Trust mode is strongly discouraged as this mode may be deprecated in future. - LTR Per Picture mode: In this mode, client can control whether the current picture should be marked as LTR. Enable this mode by setting - ltrTrustMode = 0 and ltrMarkFrame = 1 for the picture to be marked as LTR. This is the preferred mode - for using LTR. - Note that LTRs are not supported if encoding session is configured with B-frames */ - uint32_t qpPrimeYZeroTransformBypassFlag :1; /**< [in]: To enable lossless encode set this to 1, set QP to 0 and RC_mode to NV_ENC_PARAMS_RC_CONSTQP and profile to HIGH_444_PREDICTIVE_PROFILE. - Check support for lossless encoding using ::NV_ENC_CAPS_SUPPORT_LOSSLESS_ENCODE caps. */ - uint32_t useConstrainedIntraPred :1; /**< [in]: Set 1 to enable constrained intra prediction. */ - uint32_t reservedBitFields :15; /**< [in]: Reserved bitfields and must be set to 0 */ - uint32_t level; /**< [in]: Specifies the encoding level. Client is recommended to set this to NV_ENC_LEVEL_AUTOSELECT in order to enable the NvEncodeAPI interface to select the correct level. */ - uint32_t idrPeriod; /**< [in]: Specifies the IDR interval. If not set, this is made equal to gopLength in NV_ENC_CONFIG.Low latency application client can set IDR interval to NVENC_INFINITE_GOPLENGTH so that IDR frames are not inserted automatically. */ - uint32_t separateColourPlaneFlag; /**< [in]: Set to 1 to enable 4:4:4 separate colour planes */ - uint32_t disableDeblockingFilterIDC; /**< [in]: Specifies the deblocking filter mode. Permissible value range: [0,2] */ - uint32_t numTemporalLayers; /**< [in]: Specifies max temporal layers to be used for hierarchical coding. Valid value range is [1,::NV_ENC_CAPS_NUM_MAX_TEMPORAL_LAYERS] */ - uint32_t spsId; /**< [in]: Specifies the SPS id of the sequence header */ - uint32_t ppsId; /**< [in]: Specifies the PPS id of the picture header */ - NV_ENC_H264_ADAPTIVE_TRANSFORM_MODE adaptiveTransformMode; /**< [in]: Specifies the AdaptiveTransform Mode. Check support for AdaptiveTransform mode using ::NV_ENC_CAPS_SUPPORT_ADAPTIVE_TRANSFORM caps. */ - NV_ENC_H264_FMO_MODE fmoMode; /**< [in]: Specified the FMO Mode. Check support for FMO using ::NV_ENC_CAPS_SUPPORT_FMO caps. */ - NV_ENC_H264_BDIRECT_MODE bdirectMode; /**< [in]: Specifies the BDirect mode. Check support for BDirect mode using ::NV_ENC_CAPS_SUPPORT_BDIRECT_MODE caps.*/ - NV_ENC_H264_ENTROPY_CODING_MODE entropyCodingMode; /**< [in]: Specifies the entropy coding mode. Check support for CABAC mode using ::NV_ENC_CAPS_SUPPORT_CABAC caps. */ - NV_ENC_STEREO_PACKING_MODE stereoMode; /**< [in]: Specifies the stereo frame packing mode which is to be signalled in frame packing arrangement SEI */ - uint32_t intraRefreshPeriod; /**< [in]: Specifies the interval between successive intra refresh if enableIntrarefresh is set. Requires enableIntraRefresh to be set. - Will be disabled if NV_ENC_CONFIG::gopLength is not set to NVENC_INFINITE_GOPLENGTH. */ - uint32_t intraRefreshCnt; /**< [in]: Specifies the length of intra refresh in number of frames for periodic intra refresh. This value should be smaller than intraRefreshPeriod */ - uint32_t maxNumRefFrames; /**< [in]: Specifies the DPB size used for encoding. Setting it to 0 will let driver use the default dpb size. - The low latency application which wants to invalidate reference frame as an error resilience tool - is recommended to use a large DPB size so that the encoder can keep old reference frames which can be used if recent - frames are invalidated. */ - uint32_t sliceMode; /**< [in]: This parameter in conjunction with sliceModeData specifies the way in which the picture is divided into slices - sliceMode = 0 MB based slices, sliceMode = 1 Byte based slices, sliceMode = 2 MB row based slices, sliceMode = 3, numSlices in Picture - When forceIntraRefreshWithFrameCnt is set it will have priority over sliceMode setting - When sliceMode == 0 and sliceModeData == 0 whole picture will be coded with one slice */ - uint32_t sliceModeData; /**< [in]: Specifies the parameter needed for sliceMode. For: - sliceMode = 0, sliceModeData specifies # of MBs in each slice (except last slice) - sliceMode = 1, sliceModeData specifies maximum # of bytes in each slice (except last slice) - sliceMode = 2, sliceModeData specifies # of MB rows in each slice (except last slice) - sliceMode = 3, sliceModeData specifies number of slices in the picture. Driver will divide picture into slices optimally */ - NV_ENC_CONFIG_H264_VUI_PARAMETERS h264VUIParameters; /**< [in]: Specifies the H264 video usability info pamameters */ - uint32_t ltrNumFrames; /**< [in]: Specifies the number of LTR frames. This parameter has different meaning in two LTR modes. - In "LTR Trust" mode (ltrTrustMode = 1), encoder will mark the first ltrNumFrames base layer reference frames within each IDR interval as LTR. - In "LTR Per Picture" mode (ltrTrustMode = 0 and ltrMarkFrame = 1), ltrNumFrames specifies maximum number of LTR frames in DPB. */ - uint32_t ltrTrustMode; /**< [in]: Specifies the LTR operating mode. See comments near NV_ENC_CONFIG_H264::enableLTR for description of the two modes. - Set to 1 to use "LTR Trust" mode of LTR operation. Clients are discouraged to use "LTR Trust" mode as this mode may - be deprecated in future releases. - Set to 0 when using "LTR Per Picture" mode of LTR operation. */ - uint32_t chromaFormatIDC; /**< [in]: Specifies the chroma format. Should be set to 1 for yuv420 input, 3 for yuv444 input. - Check support for YUV444 encoding using ::NV_ENC_CAPS_SUPPORT_YUV444_ENCODE caps.*/ - uint32_t maxTemporalLayers; /**< [in]: Specifies the max temporal layer used for hierarchical coding. */ - uint32_t reserved1[270]; /**< [in]: Reserved and must be set to 0 */ - void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ -} NV_ENC_CONFIG_H264; - - -/** - * \struct _NV_ENC_CONFIG_HEVC - * HEVC encoder configuration parameters to be set during initialization. - */ -typedef struct _NV_ENC_CONFIG_HEVC -{ - uint32_t level; /**< [in]: Specifies the level of the encoded bitstream.*/ - uint32_t tier; /**< [in]: Specifies the level tier of the encoded bitstream.*/ - NV_ENC_HEVC_CUSIZE minCUSize; /**< [in]: Specifies the minimum size of luma coding unit.*/ - NV_ENC_HEVC_CUSIZE maxCUSize; /**< [in]: Specifies the maximum size of luma coding unit. Currently NVENC SDK only supports maxCUSize equal to NV_ENC_HEVC_CUSIZE_32x32.*/ - uint32_t useConstrainedIntraPred :1; /**< [in]: Set 1 to enable constrained intra prediction. */ - uint32_t disableDeblockAcrossSliceBoundary :1; /**< [in]: Set 1 to disable in loop filtering across slice boundary.*/ - uint32_t outputBufferingPeriodSEI :1; /**< [in]: Set 1 to write SEI buffering period syntax in the bitstream */ - uint32_t outputPictureTimingSEI :1; /**< [in]: Set 1 to write SEI picture timing syntax in the bitstream */ - uint32_t outputAUD :1; /**< [in]: Set 1 to write Access Unit Delimiter syntax. */ - uint32_t enableLTR :1; /**< [in]: Set to 1 to enable LTR (Long Term Reference) frame support. LTR can be used in two modes: "LTR Trust" mode and "LTR Per Picture" mode. - LTR Trust mode: In this mode, ltrNumFrames pictures after IDR are automatically marked as LTR. This mode is enabled by setting ltrTrustMode = 1. - Use of LTR Trust mode is strongly discouraged as this mode may be deprecated in future releases. - LTR Per Picture mode: In this mode, client can control whether the current picture should be marked as LTR. Enable this mode by setting - ltrTrustMode = 0 and ltrMarkFrame = 1 for the picture to be marked as LTR. This is the preferred mode - for using LTR. - Note that LTRs are not supported if encoding session is configured with B-frames */ - uint32_t disableSPSPPS :1; /**< [in]: Set 1 to disable VPS,SPS and PPS signalling in the bitstream. */ - uint32_t repeatSPSPPS :1; /**< [in]: Set 1 to output VPS,SPS and PPS for every IDR frame.*/ - uint32_t enableIntraRefresh :1; /**< [in]: Set 1 to enable gradual decoder refresh or intra refresh. If the GOP structure uses B frames this will be ignored */ - uint32_t chromaFormatIDC :2; /**< [in]: Specifies the chroma format. Should be set to 1 for yuv420 input, 3 for yuv444 input.*/ - uint32_t pixelBitDepthMinus8 :3; /**< [in]: Specifies pixel bit depth minus 8. Should be set to 0 for 8 bit input, 2 for 10 bit input.*/ - uint32_t reserved :18; /**< [in]: Reserved bitfields.*/ - uint32_t idrPeriod; /**< [in]: Specifies the IDR interval. If not set, this is made equal to gopLength in NV_ENC_CONFIG.Low latency application client can set IDR interval to NVENC_INFINITE_GOPLENGTH so that IDR frames are not inserted automatically. */ - uint32_t intraRefreshPeriod; /**< [in]: Specifies the interval between successive intra refresh if enableIntrarefresh is set. Requires enableIntraRefresh to be set. - Will be disabled if NV_ENC_CONFIG::gopLength is not set to NVENC_INFINITE_GOPLENGTH. */ - uint32_t intraRefreshCnt; /**< [in]: Specifies the length of intra refresh in number of frames for periodic intra refresh. This value should be smaller than intraRefreshPeriod */ - uint32_t maxNumRefFramesInDPB; /**< [in]: Specifies the maximum number of references frames in the DPB.*/ - uint32_t ltrNumFrames; /**< [in]: This parameter has different meaning in two LTR modes. - In "LTR Trust" mode (ltrTrustMode = 1), encoder will mark the first ltrNumFrames base layer reference frames within each IDR interval as LTR. - In "LTR Per Picture" mode (ltrTrustMode = 0 and ltrMarkFrame = 1), ltrNumFrames specifies maximum number of LTR frames in DPB. */ - uint32_t vpsId; /**< [in]: Specifies the VPS id of the video parameter set */ - uint32_t spsId; /**< [in]: Specifies the SPS id of the sequence header */ - uint32_t ppsId; /**< [in]: Specifies the PPS id of the picture header */ - uint32_t sliceMode; /**< [in]: This parameter in conjunction with sliceModeData specifies the way in which the picture is divided into slices - sliceMode = 0 CTU based slices, sliceMode = 1 Byte based slices, sliceMode = 2 CTU row based slices, sliceMode = 3, numSlices in Picture - When sliceMode == 0 and sliceModeData == 0 whole picture will be coded with one slice */ - uint32_t sliceModeData; /**< [in]: Specifies the parameter needed for sliceMode. For: - sliceMode = 0, sliceModeData specifies # of CTUs in each slice (except last slice) - sliceMode = 1, sliceModeData specifies maximum # of bytes in each slice (except last slice) - sliceMode = 2, sliceModeData specifies # of CTU rows in each slice (except last slice) - sliceMode = 3, sliceModeData specifies number of slices in the picture. Driver will divide picture into slices optimally */ - uint32_t maxTemporalLayersMinus1; /**< [in]: Specifies the max temporal layer used for hierarchical coding. */ - NV_ENC_CONFIG_HEVC_VUI_PARAMETERS hevcVUIParameters; /**< [in]: Specifies the HEVC video usability info pamameters */ - uint32_t ltrTrustMode; /**< [in]: Specifies the LTR operating mode. See comments near NV_ENC_CONFIG_HEVC::enableLTR for description of the two modes. - Set to 1 to use "LTR Trust" mode of LTR operation. Clients are discouraged to use "LTR Trust" mode as this mode may - be deprecated in future releases. - Set to 0 when using "LTR Per Picture" mode of LTR operation. */ - uint32_t reserved1[217]; /**< [in]: Reserved and must be set to 0.*/ - void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ -} NV_ENC_CONFIG_HEVC; - -/** - * \struct _NV_ENC_CONFIG_H264_MEONLY - * H264 encoder configuration parameters for ME only Mode - * - */ -typedef struct _NV_ENC_CONFIG_H264_MEONLY -{ - uint32_t disablePartition16x16 :1; /**< [in]: Disable MotionEstimation on 16x16 blocks*/ - uint32_t disablePartition8x16 :1; /**< [in]: Disable MotionEstimation on 8x16 blocks*/ - uint32_t disablePartition16x8 :1; /**< [in]: Disable MotionEstimation on 16x8 blocks*/ - uint32_t disablePartition8x8 :1; /**< [in]: Disable MotionEstimation on 8x8 blocks*/ - uint32_t disableIntraSearch :1; /**< [in]: Disable Intra search during MotionEstimation*/ - uint32_t bStereoEnable :1; /**< [in]: Enable Stereo Mode for Motion Estimation where each view is independently executed*/ - uint32_t reserved :26; /**< [in]: Reserved and must be set to 0 */ - uint32_t reserved1 [255]; /**< [in]: Reserved and must be set to 0 */ - void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ -} NV_ENC_CONFIG_H264_MEONLY; - - -/** - * \struct _NV_ENC_CONFIG_HEVC_MEONLY - * HEVC encoder configuration parameters for ME only Mode - * - */ -typedef struct _NV_ENC_CONFIG_HEVC_MEONLY -{ - uint32_t reserved [256]; /**< [in]: Reserved and must be set to 0 */ - void* reserved1[64]; /**< [in]: Reserved and must be set to NULL */ -} NV_ENC_CONFIG_HEVC_MEONLY; - -/** - * \struct _NV_ENC_CODEC_CONFIG - * Codec-specific encoder configuration parameters to be set during initialization. - */ -typedef union _NV_ENC_CODEC_CONFIG -{ - NV_ENC_CONFIG_H264 h264Config; /**< [in]: Specifies the H.264-specific encoder configuration. */ - NV_ENC_CONFIG_HEVC hevcConfig; /**< [in]: Specifies the HEVC-specific encoder configuration. */ - NV_ENC_CONFIG_H264_MEONLY h264MeOnlyConfig; /**< [in]: Specifies the H.264-specific ME only encoder configuration. */ - NV_ENC_CONFIG_HEVC_MEONLY hevcMeOnlyConfig; /**< [in]: Specifies the HEVC-specific ME only encoder configuration. */ - uint32_t reserved[320]; /**< [in]: Reserved and must be set to 0 */ -} NV_ENC_CODEC_CONFIG; - - -/** - * \struct _NV_ENC_CONFIG - * Encoder configuration parameters to be set during initialization. - */ -typedef struct _NV_ENC_CONFIG -{ - uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_CONFIG_VER. */ - GUID profileGUID; /**< [in]: Specifies the codec profile guid. If client specifies \p NV_ENC_CODEC_PROFILE_AUTOSELECT_GUID the NvEncodeAPI interface will select the appropriate codec profile. */ - uint32_t gopLength; /**< [in]: Specifies the number of pictures in one GOP. Low latency application client can set goplength to NVENC_INFINITE_GOPLENGTH so that keyframes are not inserted automatically. */ - int32_t frameIntervalP; /**< [in]: Specifies the GOP pattern as follows: \p frameIntervalP = 0: I, 1: IPP, 2: IBP, 3: IBBP If goplength is set to NVENC_INFINITE_GOPLENGTH \p frameIntervalP should be set to 1. */ - uint32_t monoChromeEncoding; /**< [in]: Set this to 1 to enable monochrome encoding for this session. */ - NV_ENC_PARAMS_FRAME_FIELD_MODE frameFieldMode; /**< [in]: Specifies the frame/field mode. - Check support for field encoding using ::NV_ENC_CAPS_SUPPORT_FIELD_ENCODING caps. - Using a frameFieldMode other than NV_ENC_PARAMS_FRAME_FIELD_MODE_FRAME for RGB input is not supported. */ - NV_ENC_MV_PRECISION mvPrecision; /**< [in]: Specifies the desired motion vector prediction precision. */ - NV_ENC_RC_PARAMS rcParams; /**< [in]: Specifies the rate control parameters for the current encoding session. */ - NV_ENC_CODEC_CONFIG encodeCodecConfig; /**< [in]: Specifies the codec specific config parameters through this union. */ - uint32_t reserved [278]; /**< [in]: Reserved and must be set to 0 */ - void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ -} NV_ENC_CONFIG; - -/** macro for constructing the version field of ::_NV_ENC_CONFIG */ -#define NV_ENC_CONFIG_VER (NVENCAPI_STRUCT_VERSION(6) | ( 1<<31 )) - - -/** - * \struct _NV_ENC_INITIALIZE_PARAMS - * Encode Session Initialization parameters. - */ -typedef struct _NV_ENC_INITIALIZE_PARAMS -{ - uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_INITIALIZE_PARAMS_VER. */ - GUID encodeGUID; /**< [in]: Specifies the Encode GUID for which the encoder is being created. ::NvEncInitializeEncoder() API will fail if this is not set, or set to unsupported value. */ - GUID presetGUID; /**< [in]: Specifies the preset for encoding. If the preset GUID is set then , the preset configuration will be applied before any other parameter. */ - uint32_t encodeWidth; /**< [in]: Specifies the encode width. If not set ::NvEncInitializeEncoder() API will fail. */ - uint32_t encodeHeight; /**< [in]: Specifies the encode height. If not set ::NvEncInitializeEncoder() API will fail. */ - uint32_t darWidth; /**< [in]: Specifies the display aspect ratio Width. */ - uint32_t darHeight; /**< [in]: Specifies the display aspect ratio height. */ - uint32_t frameRateNum; /**< [in]: Specifies the numerator for frame rate used for encoding in frames per second ( Frame rate = frameRateNum / frameRateDen ). */ - uint32_t frameRateDen; /**< [in]: Specifies the denominator for frame rate used for encoding in frames per second ( Frame rate = frameRateNum / frameRateDen ). */ - uint32_t enableEncodeAsync; /**< [in]: Set this to 1 to enable asynchronous mode and is expected to use events to get picture completion notification. */ - uint32_t enablePTD; /**< [in]: Set this to 1 to enable the Picture Type Decision is be taken by the NvEncodeAPI interface. */ - uint32_t reportSliceOffsets :1; /**< [in]: Set this to 1 to enable reporting slice offsets in ::_NV_ENC_LOCK_BITSTREAM. NV_ENC_INITIALIZE_PARAMS::enableEncodeAsync must be set to 0 to use this feature. Client must set this to 0 if NV_ENC_CONFIG_H264::sliceMode is 1 on Kepler GPUs */ - uint32_t enableSubFrameWrite :1; /**< [in]: Set this to 1 to write out available bitstream to memory at subframe intervals */ - uint32_t enableExternalMEHints :1; /**< [in]: Set to 1 to enable external ME hints for the current frame. For NV_ENC_INITIALIZE_PARAMS::enablePTD=1 with B frames, programming L1 hints is optional for B frames since Client doesn't know internal GOP structure. - NV_ENC_PIC_PARAMS::meHintRefPicDist should preferably be set with enablePTD=1. */ - uint32_t enableMEOnlyMode :1; /**< [in]: Set to 1 to enable ME Only Mode .*/ - uint32_t enableWeightedPrediction :1; /**< [in]: Set this to 1 to enable weighted prediction. Not supported if encode session is configured for B-Frames( 'frameIntervalP' in NV_ENC_CONFIG is greater than 1).*/ - uint32_t reservedBitFields :27; /**< [in]: Reserved bitfields and must be set to 0 */ - uint32_t privDataSize; /**< [in]: Reserved private data buffer size and must be set to 0 */ - void* privData; /**< [in]: Reserved private data buffer and must be set to NULL */ - NV_ENC_CONFIG* encodeConfig; /**< [in]: Specifies the advanced codec specific structure. If client has sent a valid codec config structure, it will override parameters set by the NV_ENC_INITIALIZE_PARAMS::presetGUID parameter. If set to NULL the NvEncodeAPI interface will use the NV_ENC_INITIALIZE_PARAMS::presetGUID to set the codec specific parameters. - Client can also optionally query the NvEncodeAPI interface to get codec specific parameters for a presetGUID using ::NvEncGetEncodePresetConfig() API. It can then modify (if required) some of the codec config parameters and send down a custom config structure as part of ::_NV_ENC_INITIALIZE_PARAMS. - Even in this case client is recommended to pass the same preset guid it has used in ::NvEncGetEncodePresetConfig() API to query the config structure; as NV_ENC_INITIALIZE_PARAMS::presetGUID. This will not override the custom config structure but will be used to determine other Encoder HW specific parameters not exposed in the API. */ - uint32_t maxEncodeWidth; /**< [in]: Maximum encode width to be used for current Encode session. - Client should allocate output buffers according to this dimension for dynamic resolution change. If set to 0, Encoder will not allow dynamic resolution change. */ - uint32_t maxEncodeHeight; /**< [in]: Maximum encode height to be allowed for current Encode session. - Client should allocate output buffers according to this dimension for dynamic resolution change. If set to 0, Encode will not allow dynamic resolution change. */ - NVENC_EXTERNAL_ME_HINT_COUNTS_PER_BLOCKTYPE maxMEHintCountsPerBlock[2]; /**< [in]: If Client wants to pass external motion vectors in NV_ENC_PIC_PARAMS::meExternalHints buffer it must specify the maximum number of hint candidates per block per direction for the encode session. - The NV_ENC_INITIALIZE_PARAMS::maxMEHintCountsPerBlock[0] is for L0 predictors and NV_ENC_INITIALIZE_PARAMS::maxMEHintCountsPerBlock[1] is for L1 predictors. - This client must also set NV_ENC_INITIALIZE_PARAMS::enableExternalMEHints to 1. */ - uint32_t reserved [289]; /**< [in]: Reserved and must be set to 0 */ - void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ -} NV_ENC_INITIALIZE_PARAMS; - -/** macro for constructing the version field of ::_NV_ENC_INITIALIZE_PARAMS */ -#define NV_ENC_INITIALIZE_PARAMS_VER (NVENCAPI_STRUCT_VERSION(5) | ( 1<<31 )) - - -/** - * \struct _NV_ENC_RECONFIGURE_PARAMS - * Encode Session Reconfigured parameters. - */ -typedef struct _NV_ENC_RECONFIGURE_PARAMS -{ - uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_RECONFIGURE_PARAMS_VER. */ - NV_ENC_INITIALIZE_PARAMS reInitEncodeParams; /**< [in]: Encoder session re-initialization parameters. */ - uint32_t resetEncoder :1; /**< [in]: This resets the rate control states and other internal encoder states. This should be used only with an IDR frame. - If NV_ENC_INITIALIZE_PARAMS::enablePTD is set to 1, encoder will force the frame type to IDR */ - uint32_t forceIDR :1; /**< [in]: Encode the current picture as an IDR picture. This flag is only valid when Picture type decision is taken by the Encoder - [_NV_ENC_INITIALIZE_PARAMS::enablePTD == 1]. */ - uint32_t reserved :30; - -}NV_ENC_RECONFIGURE_PARAMS; - -/** macro for constructing the version field of ::_NV_ENC_RECONFIGURE_PARAMS */ -#define NV_ENC_RECONFIGURE_PARAMS_VER (NVENCAPI_STRUCT_VERSION(1) | ( 1<<31 )) - -/** - * \struct _NV_ENC_PRESET_CONFIG - * Encoder preset config - */ -typedef struct _NV_ENC_PRESET_CONFIG -{ - uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_PRESET_CONFIG_VER. */ - NV_ENC_CONFIG presetCfg; /**< [out]: preset config returned by the Nvidia Video Encoder interface. */ - uint32_t reserved1[255]; /**< [in]: Reserved and must be set to 0 */ - void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ -}NV_ENC_PRESET_CONFIG; - -/** macro for constructing the version field of ::_NV_ENC_PRESET_CONFIG */ -#define NV_ENC_PRESET_CONFIG_VER (NVENCAPI_STRUCT_VERSION(4) | ( 1<<31 )) - - -/** - * \struct _NV_ENC_SEI_PAYLOAD - * User SEI message - */ -typedef struct _NV_ENC_SEI_PAYLOAD -{ - uint32_t payloadSize; /**< [in] SEI payload size in bytes. SEI payload must be byte aligned, as described in Annex D */ - uint32_t payloadType; /**< [in] SEI payload types and syntax can be found in Annex D of the H.264 Specification. */ - uint8_t *payload; /**< [in] pointer to user data */ -} NV_ENC_SEI_PAYLOAD; - -#define NV_ENC_H264_SEI_PAYLOAD NV_ENC_SEI_PAYLOAD - -/** - * \struct _NV_ENC_PIC_PARAMS_H264 - * H264 specific enc pic params. sent on a per frame basis. - */ -typedef struct _NV_ENC_PIC_PARAMS_H264 -{ - uint32_t displayPOCSyntax; /**< [in]: Specifies the display POC syntax This is required to be set if client is handling the picture type decision. */ - uint32_t reserved3; /**< [in]: Reserved and must be set to 0 */ - uint32_t refPicFlag; /**< [in]: Set to 1 for a reference picture. This is ignored if NV_ENC_INITIALIZE_PARAMS::enablePTD is set to 1. */ - uint32_t colourPlaneId; /**< [in]: Specifies the colour plane ID associated with the current input. */ - uint32_t forceIntraRefreshWithFrameCnt; /**< [in]: Forces an intra refresh with duration equal to intraRefreshFrameCnt. - When outputRecoveryPointSEI is set this is value is used for recovery_frame_cnt in recovery point SEI message - forceIntraRefreshWithFrameCnt cannot be used if B frames are used in the GOP structure specified */ - uint32_t constrainedFrame :1; /**< [in]: Set to 1 if client wants to encode this frame with each slice completely independent of other slices in the frame. - NV_ENC_INITIALIZE_PARAMS::enableConstrainedEncoding should be set to 1 */ - uint32_t sliceModeDataUpdate :1; /**< [in]: Set to 1 if client wants to change the sliceModeData field to specify new sliceSize Parameter - When forceIntraRefreshWithFrameCnt is set it will have priority over sliceMode setting */ - uint32_t ltrMarkFrame :1; /**< [in]: Set to 1 if client wants to mark this frame as LTR */ - uint32_t ltrUseFrames :1; /**< [in]: Set to 1 if client allows encoding this frame using the LTR frames specified in ltrFrameBitmap */ - uint32_t reservedBitFields :28; /**< [in]: Reserved bit fields and must be set to 0 */ - uint8_t* sliceTypeData; /**< [in]: Deprecated. */ - uint32_t sliceTypeArrayCnt; /**< [in]: Deprecated. */ - uint32_t seiPayloadArrayCnt; /**< [in]: Specifies the number of elements allocated in seiPayloadArray array. */ - NV_ENC_SEI_PAYLOAD* seiPayloadArray; /**< [in]: Array of SEI payloads which will be inserted for this frame. */ - uint32_t sliceMode; /**< [in]: This parameter in conjunction with sliceModeData specifies the way in which the picture is divided into slices - sliceMode = 0 MB based slices, sliceMode = 1 Byte based slices, sliceMode = 2 MB row based slices, sliceMode = 3, numSlices in Picture - When forceIntraRefreshWithFrameCnt is set it will have priority over sliceMode setting - When sliceMode == 0 and sliceModeData == 0 whole picture will be coded with one slice */ - uint32_t sliceModeData; /**< [in]: Specifies the parameter needed for sliceMode. For: - sliceMode = 0, sliceModeData specifies # of MBs in each slice (except last slice) - sliceMode = 1, sliceModeData specifies maximum # of bytes in each slice (except last slice) - sliceMode = 2, sliceModeData specifies # of MB rows in each slice (except last slice) - sliceMode = 3, sliceModeData specifies number of slices in the picture. Driver will divide picture into slices optimally */ - uint32_t ltrMarkFrameIdx; /**< [in]: Specifies the long term referenceframe index to use for marking this frame as LTR.*/ - uint32_t ltrUseFrameBitmap; /**< [in]: Specifies the the associated bitmap of LTR frame indices to use when encoding this frame. */ - uint32_t ltrUsageMode; /**< [in]: Not supported. Reserved for future use and must be set to 0. */ - uint32_t reserved [243]; /**< [in]: Reserved and must be set to 0. */ - void* reserved2[62]; /**< [in]: Reserved and must be set to NULL. */ -} NV_ENC_PIC_PARAMS_H264; - -/** - * \struct _NV_ENC_PIC_PARAMS_HEVC - * HEVC specific enc pic params. sent on a per frame basis. - */ -typedef struct _NV_ENC_PIC_PARAMS_HEVC -{ - uint32_t displayPOCSyntax; /**< [in]: Specifies the display POC syntax This is required to be set if client is handling the picture type decision. */ - uint32_t refPicFlag; /**< [in]: Set to 1 for a reference picture. This is ignored if NV_ENC_INITIALIZE_PARAMS::enablePTD is set to 1. */ - uint32_t temporalId; /**< [in]: Specifies the temporal id of the picture */ - uint32_t forceIntraRefreshWithFrameCnt; /**< [in]: Forces an intra refresh with duration equal to intraRefreshFrameCnt. - When outputRecoveryPointSEI is set this is value is used for recovery_frame_cnt in recovery point SEI message - forceIntraRefreshWithFrameCnt cannot be used if B frames are used in the GOP structure specified */ - uint32_t constrainedFrame :1; /**< [in]: Set to 1 if client wants to encode this frame with each slice completely independent of other slices in the frame. - NV_ENC_INITIALIZE_PARAMS::enableConstrainedEncoding should be set to 1 */ - uint32_t sliceModeDataUpdate :1; /**< [in]: Set to 1 if client wants to change the sliceModeData field to specify new sliceSize Parameter - When forceIntraRefreshWithFrameCnt is set it will have priority over sliceMode setting */ - uint32_t ltrMarkFrame :1; /**< [in]: Set to 1 if client wants to mark this frame as LTR */ - uint32_t ltrUseFrames :1; /**< [in]: Set to 1 if client allows encoding this frame using the LTR frames specified in ltrFrameBitmap */ - uint32_t reservedBitFields :28; /**< [in]: Reserved bit fields and must be set to 0 */ - uint8_t* sliceTypeData; /**< [in]: Array which specifies the slice type used to force intra slice for a particular slice. Currently supported only for NV_ENC_CONFIG_H264::sliceMode == 3. - Client should allocate array of size sliceModeData where sliceModeData is specified in field of ::_NV_ENC_CONFIG_H264 - Array element with index n corresponds to nth slice. To force a particular slice to intra client should set corresponding array element to NV_ENC_SLICE_TYPE_I - all other array elements should be set to NV_ENC_SLICE_TYPE_DEFAULT */ - uint32_t sliceTypeArrayCnt; /**< [in]: Client should set this to the number of elements allocated in sliceTypeData array. If sliceTypeData is NULL then this should be set to 0 */ - uint32_t sliceMode; /**< [in]: This parameter in conjunction with sliceModeData specifies the way in which the picture is divided into slices - sliceMode = 0 CTU based slices, sliceMode = 1 Byte based slices, sliceMode = 2 CTU row based slices, sliceMode = 3, numSlices in Picture - When forceIntraRefreshWithFrameCnt is set it will have priority over sliceMode setting - When sliceMode == 0 and sliceModeData == 0 whole picture will be coded with one slice */ - uint32_t sliceModeData; /**< [in]: Specifies the parameter needed for sliceMode. For: - sliceMode = 0, sliceModeData specifies # of CTUs in each slice (except last slice) - sliceMode = 1, sliceModeData specifies maximum # of bytes in each slice (except last slice) - sliceMode = 2, sliceModeData specifies # of CTU rows in each slice (except last slice) - sliceMode = 3, sliceModeData specifies number of slices in the picture. Driver will divide picture into slices optimally */ - uint32_t ltrMarkFrameIdx; /**< [in]: Specifies the long term reference frame index to use for marking this frame as LTR.*/ - uint32_t ltrUseFrameBitmap; /**< [in]: Specifies the associated bitmap of LTR frame indices to use when encoding this frame. */ - uint32_t ltrUsageMode; /**< [in]: Not supported. Reserved for future use and must be set to 0. */ - uint32_t seiPayloadArrayCnt; /**< [in]: Specifies the number of elements allocated in seiPayloadArray array. */ - uint32_t reserved; /**< [in]: Reserved and must be set to 0. */ - NV_ENC_SEI_PAYLOAD* seiPayloadArray; /**< [in]: Array of SEI payloads which will be inserted for this frame. */ - uint32_t reserved2 [244]; /**< [in]: Reserved and must be set to 0. */ - void* reserved3[61]; /**< [in]: Reserved and must be set to NULL. */ -} NV_ENC_PIC_PARAMS_HEVC; - - -/** - * Codec specific per-picture encoding parameters. - */ -typedef union _NV_ENC_CODEC_PIC_PARAMS -{ - NV_ENC_PIC_PARAMS_H264 h264PicParams; /**< [in]: H264 encode picture params. */ - NV_ENC_PIC_PARAMS_HEVC hevcPicParams; /**< [in]: HEVC encode picture params. */ - uint32_t reserved[256]; /**< [in]: Reserved and must be set to 0. */ -} NV_ENC_CODEC_PIC_PARAMS; - -/** - * \struct _NV_ENC_PIC_PARAMS - * Encoding parameters that need to be sent on a per frame basis. - */ -typedef struct _NV_ENC_PIC_PARAMS -{ - uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_PIC_PARAMS_VER. */ - uint32_t inputWidth; /**< [in]: Specifies the input buffer width */ - uint32_t inputHeight; /**< [in]: Specifies the input buffer height */ - uint32_t inputPitch; /**< [in]: Specifies the input buffer pitch. If pitch value is not known, set this to inputWidth. */ - uint32_t encodePicFlags; /**< [in]: Specifies bit-wise OR`ed encode pic flags. See ::NV_ENC_PIC_FLAGS enum. */ - uint32_t frameIdx; /**< [in]: Specifies the frame index associated with the input frame [optional]. */ - uint64_t inputTimeStamp; /**< [in]: Specifies presentation timestamp associated with the input picture. */ - uint64_t inputDuration; /**< [in]: Specifies duration of the input picture */ - NV_ENC_INPUT_PTR inputBuffer; /**< [in]: Specifies the input buffer pointer. Client must use a pointer obtained from ::NvEncCreateInputBuffer() or ::NvEncMapInputResource() APIs.*/ - NV_ENC_OUTPUT_PTR outputBitstream; /**< [in]: Specifies the pointer to output buffer. Client should use a pointer obtained from ::NvEncCreateBitstreamBuffer() API. */ - void* completionEvent; /**< [in]: Specifies an event to be signalled on completion of encoding of this Frame [only if operating in Asynchronous mode]. Each output buffer should be associated with a distinct event pointer. */ - NV_ENC_BUFFER_FORMAT bufferFmt; /**< [in]: Specifies the input buffer format. */ - NV_ENC_PIC_STRUCT pictureStruct; /**< [in]: Specifies structure of the input picture. */ - NV_ENC_PIC_TYPE pictureType; /**< [in]: Specifies input picture type. Client required to be set explicitly by the client if the client has not set NV_ENC_INITALIZE_PARAMS::enablePTD to 1 while calling NvInitializeEncoder. */ - NV_ENC_CODEC_PIC_PARAMS codecPicParams; /**< [in]: Specifies the codec specific per-picture encoding parameters. */ - NVENC_EXTERNAL_ME_HINT_COUNTS_PER_BLOCKTYPE meHintCountsPerBlock[2]; /**< [in]: Specifies the number of hint candidates per block per direction for the current frame. meHintCountsPerBlock[0] is for L0 predictors and meHintCountsPerBlock[1] is for L1 predictors. - The candidate count in NV_ENC_PIC_PARAMS::meHintCountsPerBlock[lx] must never exceed NV_ENC_INITIALIZE_PARAMS::maxMEHintCountsPerBlock[lx] provided during encoder intialization. */ - NVENC_EXTERNAL_ME_HINT *meExternalHints; /**< [in]: Specifies the pointer to ME external hints for the current frame. The size of ME hint buffer should be equal to number of macroblocks * the total number of candidates per macroblock. - The total number of candidates per MB per direction = 1*meHintCountsPerBlock[Lx].numCandsPerBlk16x16 + 2*meHintCountsPerBlock[Lx].numCandsPerBlk16x8 + 2*meHintCountsPerBlock[Lx].numCandsPerBlk8x8 - + 4*meHintCountsPerBlock[Lx].numCandsPerBlk8x8. For frames using bidirectional ME , the total number of candidates for single macroblock is sum of total number of candidates per MB for each direction (L0 and L1) */ - uint32_t reserved1[6]; /**< [in]: Reserved and must be set to 0 */ - void* reserved2[2]; /**< [in]: Reserved and must be set to NULL */ - int8_t *qpDeltaMap; /**< [in]: Specifies the pointer to signed byte array containing QP delta value per MB in raster scan order in the current picture. This QP modifier is applied on top of the QP chosen by rate control. */ - uint32_t qpDeltaMapSize; /**< [in]: Specifies the size in bytes of qpDeltaMap surface allocated by client and pointed to by NV_ENC_PIC_PARAMS::qpDeltaMap. Surface (array) should be picWidthInMbs * picHeightInMbs */ - uint32_t reservedBitFields; /**< [in]: Reserved bitfields and must be set to 0 */ - uint16_t meHintRefPicDist[2]; /**< [in]: Specifies temporal distance for reference picture (NVENC_EXTERNAL_ME_HINT::refidx = 0) used during external ME with NV_ENC_INITALIZE_PARAMS::enablePTD = 1 . meHintRefPicDist[0] is for L0 hints and meHintRefPicDist[1] is for L1 hints. - If not set, will internally infer distance of 1. Ignored for NV_ENC_INITALIZE_PARAMS::enablePTD = 0 */ - uint32_t reserved3[286]; /**< [in]: Reserved and must be set to 0 */ - void* reserved4[60]; /**< [in]: Reserved and must be set to NULL */ -} NV_ENC_PIC_PARAMS; - -/** Macro for constructing the version field of ::_NV_ENC_PIC_PARAMS */ -#define NV_ENC_PIC_PARAMS_VER (NVENCAPI_STRUCT_VERSION(4) | ( 1<<31 )) - - -/** - * \struct _NV_ENC_MEONLY_PARAMS - * MEOnly parameters that need to be sent on a per motion estimation basis. - * NV_ENC_MEONLY_PARAMS::meExternalHints is supported for H264 only. - */ -typedef struct _NV_ENC_MEONLY_PARAMS -{ - uint32_t version; /**< [in]: Struct version. Must be set to NV_ENC_MEONLY_PARAMS_VER.*/ - uint32_t inputWidth; /**< [in]: Specifies the input buffer width */ - uint32_t inputHeight; /**< [in]: Specifies the input buffer height */ - NV_ENC_INPUT_PTR inputBuffer; /**< [in]: Specifies the input buffer pointer. Client must use a pointer obtained from NvEncCreateInputBuffer() or NvEncMapInputResource() APIs. */ - NV_ENC_INPUT_PTR referenceFrame; /**< [in]: Specifies the reference frame pointer */ - NV_ENC_OUTPUT_PTR mvBuffer; /**< [in]: Specifies the pointer to motion vector data buffer allocated by NvEncCreateMVBuffer. Client must lock mvBuffer using ::NvEncLockBitstream() API to get the motion vector data. */ - NV_ENC_BUFFER_FORMAT bufferFmt; /**< [in]: Specifies the input buffer format. */ - void* completionEvent; /**< [in]: Specifies an event to be signalled on completion of motion estimation - of this Frame [only if operating in Asynchronous mode]. - Each output buffer should be associated with a distinct event pointer. */ - uint32_t viewID; /**< [in]: Specifies left,right viewID if NV_ENC_CONFIG_H264_MEONLY::bStereoEnable is set. - viewID can be 0,1 if bStereoEnable is set, 0 otherwise. */ - NVENC_EXTERNAL_ME_HINT_COUNTS_PER_BLOCKTYPE - meHintCountsPerBlock[2]; /**< [in]: Specifies the number of hint candidates per block for the current frame. meHintCountsPerBlock[0] is for L0 predictors. - The candidate count in NV_ENC_PIC_PARAMS::meHintCountsPerBlock[lx] must never exceed NV_ENC_INITIALIZE_PARAMS::maxMEHintCountsPerBlock[lx] provided during encoder intialization. */ - NVENC_EXTERNAL_ME_HINT *meExternalHints; /**< [in]: Specifies the pointer to ME external hints for the current frame. The size of ME hint buffer should be equal to number of macroblocks * the total number of candidates per macroblock. - The total number of candidates per MB per direction = 1*meHintCountsPerBlock[Lx].numCandsPerBlk16x16 + 2*meHintCountsPerBlock[Lx].numCandsPerBlk16x8 + 2*meHintCountsPerBlock[Lx].numCandsPerBlk8x8 - + 4*meHintCountsPerBlock[Lx].numCandsPerBlk8x8. For frames using bidirectional ME , the total number of candidates for single macroblock is sum of total number of candidates per MB for each direction (L0 and L1) */ - uint32_t reserved1[243]; /**< [in]: Reserved and must be set to 0 */ - void* reserved2[59]; /**< [in]: Reserved and must be set to NULL */ -} NV_ENC_MEONLY_PARAMS; - -/** NV_ENC_MEONLY_PARAMS struct version*/ -#define NV_ENC_MEONLY_PARAMS_VER NVENCAPI_STRUCT_VERSION(3) - - -/** - * \struct _NV_ENC_LOCK_BITSTREAM - * Bitstream buffer lock parameters. - */ -typedef struct _NV_ENC_LOCK_BITSTREAM -{ - uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_LOCK_BITSTREAM_VER. */ - uint32_t doNotWait :1; /**< [in]: If this flag is set, the NvEncodeAPI interface will return buffer pointer even if operation is not completed. If not set, the call will block until operation completes. */ - uint32_t ltrFrame :1; /**< [out]: Flag indicating this frame is marked as LTR frame */ - uint32_t reservedBitFields :30; /**< [in]: Reserved bit fields and must be set to 0 */ - void* outputBitstream; /**< [in]: Pointer to the bitstream buffer being locked. */ - uint32_t* sliceOffsets; /**< [in,out]: Array which receives the slice offsets. This is not supported if NV_ENC_CONFIG_H264::sliceMode is 1 on Kepler GPUs. Array size must be equal to size of frame in MBs. */ - uint32_t frameIdx; /**< [out]: Frame no. for which the bitstream is being retrieved. */ - uint32_t hwEncodeStatus; /**< [out]: The NvEncodeAPI interface status for the locked picture. */ - uint32_t numSlices; /**< [out]: Number of slices in the encoded picture. Will be reported only if NV_ENC_INITIALIZE_PARAMS::reportSliceOffsets set to 1. */ - uint32_t bitstreamSizeInBytes; /**< [out]: Actual number of bytes generated and copied to the memory pointed by bitstreamBufferPtr. */ - uint64_t outputTimeStamp; /**< [out]: Presentation timestamp associated with the encoded output. */ - uint64_t outputDuration; /**< [out]: Presentation duration associates with the encoded output. */ - void* bitstreamBufferPtr; /**< [out]: Pointer to the generated output bitstream. - For MEOnly mode _NV_ENC_LOCK_BITSTREAM::bitstreamBufferPtr should be typecast to - NV_ENC_H264_MV_DATA/NV_ENC_HEVC_MV_DATA pointer respectively for H264/HEVC */ - NV_ENC_PIC_TYPE pictureType; /**< [out]: Picture type of the encoded picture. */ - NV_ENC_PIC_STRUCT pictureStruct; /**< [out]: Structure of the generated output picture. */ - uint32_t frameAvgQP; /**< [out]: Average QP of the frame. */ - uint32_t frameSatd; /**< [out]: Total SATD cost for whole frame. */ - uint32_t ltrFrameIdx; /**< [out]: Frame index associated with this LTR frame. */ - uint32_t ltrFrameBitmap; /**< [out]: Bitmap of LTR frames indices which were used for encoding this frame. Value of 0 if no LTR frames were used. */ - uint32_t reserved [236]; /**< [in]: Reserved and must be set to 0 */ - void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ -} NV_ENC_LOCK_BITSTREAM; - -/** Macro for constructing the version field of ::_NV_ENC_LOCK_BITSTREAM */ -#define NV_ENC_LOCK_BITSTREAM_VER NVENCAPI_STRUCT_VERSION(1) - - -/** - * \struct _NV_ENC_LOCK_INPUT_BUFFER - * Uncompressed Input Buffer lock parameters. - */ -typedef struct _NV_ENC_LOCK_INPUT_BUFFER -{ - uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_LOCK_INPUT_BUFFER_VER. */ - uint32_t doNotWait :1; /**< [in]: Set to 1 to make ::NvEncLockInputBuffer() a unblocking call. If the encoding is not completed, driver will return ::NV_ENC_ERR_ENCODER_BUSY error code. */ - uint32_t reservedBitFields :31; /**< [in]: Reserved bitfields and must be set to 0 */ - NV_ENC_INPUT_PTR inputBuffer; /**< [in]: Pointer to the input buffer to be locked, client should pass the pointer obtained from ::NvEncCreateInputBuffer() or ::NvEncMapInputResource API. */ - void* bufferDataPtr; /**< [out]: Pointed to the locked input buffer data. Client can only access input buffer using the \p bufferDataPtr. */ - uint32_t pitch; /**< [out]: Pitch of the locked input buffer. */ - uint32_t reserved1[251]; /**< [in]: Reserved and must be set to 0 */ - void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ -} NV_ENC_LOCK_INPUT_BUFFER; - -/** Macro for constructing the version field of ::_NV_ENC_LOCK_INPUT_BUFFER */ -#define NV_ENC_LOCK_INPUT_BUFFER_VER NVENCAPI_STRUCT_VERSION(1) - - -/** - * \struct _NV_ENC_MAP_INPUT_RESOURCE - * Map an input resource to a Nvidia Encoder Input Buffer - */ -typedef struct _NV_ENC_MAP_INPUT_RESOURCE -{ - uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_MAP_INPUT_RESOURCE_VER. */ - uint32_t subResourceIndex; /**< [in]: Deprecated. Do not use. */ - void* inputResource; /**< [in]: Deprecated. Do not use. */ - NV_ENC_REGISTERED_PTR registeredResource; /**< [in]: The Registered resource handle obtained by calling NvEncRegisterInputResource. */ - NV_ENC_INPUT_PTR mappedResource; /**< [out]: Mapped pointer corresponding to the registeredResource. This pointer must be used in NV_ENC_PIC_PARAMS::inputBuffer parameter in ::NvEncEncodePicture() API. */ - NV_ENC_BUFFER_FORMAT mappedBufferFmt; /**< [out]: Buffer format of the outputResource. This buffer format must be used in NV_ENC_PIC_PARAMS::bufferFmt if client using the above mapped resource pointer. */ - uint32_t reserved1[251]; /**< [in]: Reserved and must be set to 0. */ - void* reserved2[63]; /**< [in]: Reserved and must be set to NULL */ -} NV_ENC_MAP_INPUT_RESOURCE; - -/** Macro for constructing the version field of ::_NV_ENC_MAP_INPUT_RESOURCE */ -#define NV_ENC_MAP_INPUT_RESOURCE_VER NVENCAPI_STRUCT_VERSION(4) - -/** - * \struct _NV_ENC_INPUT_RESOURCE_OPENGL_TEX - * NV_ENC_REGISTER_RESOURCE::resourceToRegister must be a pointer to a variable of this type, - * when NV_ENC_REGISTER_RESOURCE::resourceType is NV_ENC_INPUT_RESOURCE_TYPE_OPENGL_TEX - */ -typedef struct _NV_ENC_INPUT_RESOURCE_OPENGL_TEX -{ - uint32_t texture; /**< [in]: The name of the texture to be used. */ - uint32_t target; /**< [in]: Accepted values are GL_TEXTURE_RECTANGLE and GL_TEXTURE_2D. */ -} NV_ENC_INPUT_RESOURCE_OPENGL_TEX; - -/** - * \struct _NV_ENC_REGISTER_RESOURCE - * Register a resource for future use with the Nvidia Video Encoder Interface. - */ -typedef struct _NV_ENC_REGISTER_RESOURCE -{ - uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_REGISTER_RESOURCE_VER. */ - NV_ENC_INPUT_RESOURCE_TYPE resourceType; /**< [in]: Specifies the type of resource to be registered. - Supported values are - ::NV_ENC_INPUT_RESOURCE_TYPE_DIRECTX, - ::NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR, - ::NV_ENC_INPUT_RESOURCE_TYPE_OPENGL_TEX */ - uint32_t width; /**< [in]: Input buffer Width. */ - uint32_t height; /**< [in]: Input buffer Height. */ - uint32_t pitch; /**< [in]: Input buffer Pitch. */ - uint32_t subResourceIndex; /**< [in]: Subresource Index of the DirectX resource to be registered. Should be set to 0 for other interfaces. */ - void* resourceToRegister; /**< [in]: Handle to the resource that is being registered. */ - NV_ENC_REGISTERED_PTR registeredResource; /**< [out]: Registered resource handle. This should be used in future interactions with the Nvidia Video Encoder Interface. */ - NV_ENC_BUFFER_FORMAT bufferFormat; /**< [in]: Buffer format of resource to be registered. */ - uint32_t reserved1[248]; /**< [in]: Reserved and must be set to 0. */ - void* reserved2[62]; /**< [in]: Reserved and must be set to NULL. */ -} NV_ENC_REGISTER_RESOURCE; - -/** Macro for constructing the version field of ::_NV_ENC_REGISTER_RESOURCE */ -#define NV_ENC_REGISTER_RESOURCE_VER NVENCAPI_STRUCT_VERSION(3) - -/** - * \struct _NV_ENC_STAT - * Encode Stats structure. - */ -typedef struct _NV_ENC_STAT -{ - uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_STAT_VER. */ - uint32_t reserved; /**< [in]: Reserved and must be set to 0 */ - NV_ENC_OUTPUT_PTR outputBitStream; /**< [out]: Specifies the pointer to output bitstream. */ - uint32_t bitStreamSize; /**< [out]: Size of generated bitstream in bytes. */ - uint32_t picType; /**< [out]: Picture type of encoded picture. See ::NV_ENC_PIC_TYPE. */ - uint32_t lastValidByteOffset; /**< [out]: Offset of last valid bytes of completed bitstream */ - uint32_t sliceOffsets[16]; /**< [out]: Offsets of each slice */ - uint32_t picIdx; /**< [out]: Picture number */ - uint32_t reserved1[233]; /**< [in]: Reserved and must be set to 0 */ - void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ -} NV_ENC_STAT; - -/** Macro for constructing the version field of ::_NV_ENC_STAT */ -#define NV_ENC_STAT_VER NVENCAPI_STRUCT_VERSION(1) - - -/** - * \struct _NV_ENC_SEQUENCE_PARAM_PAYLOAD - * Sequence and picture paramaters payload. - */ -typedef struct _NV_ENC_SEQUENCE_PARAM_PAYLOAD -{ - uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_INITIALIZE_PARAMS_VER. */ - uint32_t inBufferSize; /**< [in]: Specifies the size of the spsppsBuffer provied by the client */ - uint32_t spsId; /**< [in]: Specifies the SPS id to be used in sequence header. Default value is 0. */ - uint32_t ppsId; /**< [in]: Specifies the PPS id to be used in picture header. Default value is 0. */ - void* spsppsBuffer; /**< [in]: Specifies bitstream header pointer of size NV_ENC_SEQUENCE_PARAM_PAYLOAD::inBufferSize. It is the client's responsibility to manage this memory. */ - uint32_t* outSPSPPSPayloadSize; /**< [out]: Size of the sequence and picture header in bytes written by the NvEncodeAPI interface to the SPSPPSBuffer. */ - uint32_t reserved [250]; /**< [in]: Reserved and must be set to 0 */ - void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ -} NV_ENC_SEQUENCE_PARAM_PAYLOAD; - -/** Macro for constructing the version field of ::_NV_ENC_SEQUENCE_PARAM_PAYLOAD */ -#define NV_ENC_SEQUENCE_PARAM_PAYLOAD_VER NVENCAPI_STRUCT_VERSION(1) - - -/** - * Event registration/unregistration parameters. - */ -typedef struct _NV_ENC_EVENT_PARAMS -{ - uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_EVENT_PARAMS_VER. */ - uint32_t reserved; /**< [in]: Reserved and must be set to 0 */ - void* completionEvent; /**< [in]: Handle to event to be registered/unregistered with the NvEncodeAPI interface. */ - uint32_t reserved1[253]; /**< [in]: Reserved and must be set to 0 */ - void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ -} NV_ENC_EVENT_PARAMS; - -/** Macro for constructing the version field of ::_NV_ENC_EVENT_PARAMS */ -#define NV_ENC_EVENT_PARAMS_VER NVENCAPI_STRUCT_VERSION(1) - -/** - * Encoder Session Creation parameters - */ -typedef struct _NV_ENC_OPEN_ENCODE_SESSIONEX_PARAMS -{ - uint32_t version; /**< [in]: Struct version. Must be set to ::NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER. */ - NV_ENC_DEVICE_TYPE deviceType; /**< [in]: Specified the device Type */ - void* device; /**< [in]: Pointer to client device. */ - void* reserved; /**< [in]: Reserved and must be set to 0. */ - uint32_t apiVersion; /**< [in]: API version. Should be set to NVENCAPI_VERSION. */ - uint32_t reserved1[253]; /**< [in]: Reserved and must be set to 0 */ - void* reserved2[64]; /**< [in]: Reserved and must be set to NULL */ -} NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS; -/** Macro for constructing the version field of ::_NV_ENC_OPEN_ENCODE_SESSIONEX_PARAMS */ -#define NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER NVENCAPI_STRUCT_VERSION(1) - -/** @} */ /* END ENCODER_STRUCTURE */ - - -/** - * \addtogroup ENCODE_FUNC NvEncodeAPI Functions - * @{ - */ - -// NvEncOpenEncodeSession -/** - * \brief Opens an encoding session. - * - * Deprecated. - * - * \return - * ::NV_ENC_ERR_INVALID_CALL\n - * - */ -NVENCSTATUS NVENCAPI NvEncOpenEncodeSession (void* device, uint32_t deviceType, void** encoder); - -// NvEncGetEncodeGuidCount -/** - * \brief Retrieves the number of supported encode GUIDs. - * - * The function returns the number of codec guids supported by the NvEncodeAPI - * interface. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [out] encodeGUIDCount - * Number of supported encode GUIDs. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncGetEncodeGUIDCount (void* encoder, uint32_t* encodeGUIDCount); - - -// NvEncGetEncodeGUIDs -/** - * \brief Retrieves an array of supported encoder codec GUIDs. - * - * The function returns an array of codec guids supported by the NvEncodeAPI interface. - * The client must allocate an array where the NvEncodeAPI interface can - * fill the supported guids and pass the pointer in \p *GUIDs parameter. - * The size of the array can be determined by using ::NvEncGetEncodeGUIDCount() API. - * The Nvidia Encoding interface returns the number of codec guids it has actually - * filled in the guid array in the \p GUIDCount parameter. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in] guidArraySize - * Number of GUIDs to retrieved. Should be set to the number retrieved using - * ::NvEncGetEncodeGUIDCount. - * \param [out] GUIDs - * Array of supported Encode GUIDs. - * \param [out] GUIDCount - * Number of supported Encode GUIDs. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncGetEncodeGUIDs (void* encoder, GUID* GUIDs, uint32_t guidArraySize, uint32_t* GUIDCount); - - -// NvEncGetEncodeProfileGuidCount -/** - * \brief Retrieves the number of supported profile GUIDs. - * - * The function returns the number of profile GUIDs supported for a given codec. - * The client must first enumerate the codec guids supported by the NvEncodeAPI - * interface. After determining the codec guid, it can query the NvEncodeAPI - * interface to determine the number of profile guids supported for a particular - * codec guid. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in] encodeGUID - * The codec guid for which the profile guids are being enumerated. - * \param [out] encodeProfileGUIDCount - * Number of encode profiles supported for the given encodeGUID. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncGetEncodeProfileGUIDCount (void* encoder, GUID encodeGUID, uint32_t* encodeProfileGUIDCount); - - -// NvEncGetEncodeProfileGUIDs -/** - * \brief Retrieves an array of supported encode profile GUIDs. - * - * The function returns an array of supported profile guids for a particular - * codec guid. The client must allocate an array where the NvEncodeAPI interface - * can populate the profile guids. The client can determine the array size using - * ::NvEncGetEncodeProfileGUIDCount() API. The client must also validiate that the - * NvEncodeAPI interface supports the GUID the client wants to pass as \p encodeGUID - * parameter. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in] encodeGUID - * The encode guid whose profile guids are being enumerated. - * \param [in] guidArraySize - * Number of GUIDs to be retrieved. Should be set to the number retrieved using - * ::NvEncGetEncodeProfileGUIDCount. - * \param [out] profileGUIDs - * Array of supported Encode Profile GUIDs - * \param [out] GUIDCount - * Number of valid encode profile GUIDs in \p profileGUIDs array. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncGetEncodeProfileGUIDs (void* encoder, GUID encodeGUID, GUID* profileGUIDs, uint32_t guidArraySize, uint32_t* GUIDCount); - -// NvEncGetInputFormatCount -/** - * \brief Retrieve the number of supported Input formats. - * - * The function returns the number of supported input formats. The client must - * query the NvEncodeAPI interface to determine the supported input formats - * before creating the input surfaces. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in] encodeGUID - * Encode GUID, corresponding to which the number of supported input formats - * is to be retrieved. - * \param [out] inputFmtCount - * Number of input formats supported for specified Encode GUID. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_GENERIC \n - */ -NVENCSTATUS NVENCAPI NvEncGetInputFormatCount (void* encoder, GUID encodeGUID, uint32_t* inputFmtCount); - - -// NvEncGetInputFormats -/** - * \brief Retrieves an array of supported Input formats - * - * Returns an array of supported input formats The client must use the input - * format to create input surface using ::NvEncCreateInputBuffer() API. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in] encodeGUID - * Encode GUID, corresponding to which the number of supported input formats - * is to be retrieved. - *\param [in] inputFmtArraySize - * Size input format count array passed in \p inputFmts. - *\param [out] inputFmts - * Array of input formats supported for this Encode GUID. - *\param [out] inputFmtCount - * The number of valid input format types returned by the NvEncodeAPI - * interface in \p inputFmts array. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncGetInputFormats (void* encoder, GUID encodeGUID, NV_ENC_BUFFER_FORMAT* inputFmts, uint32_t inputFmtArraySize, uint32_t* inputFmtCount); - - -// NvEncGetEncodeCaps -/** - * \brief Retrieves the capability value for a specified encoder attribute. - * - * The function returns the capability value for a given encoder attribute. The - * client must validate the encodeGUID using ::NvEncGetEncodeGUIDs() API before - * calling this function. The encoder attribute being queried are enumerated in - * ::NV_ENC_CAPS_PARAM enum. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in] encodeGUID - * Encode GUID, corresponding to which the capability attribute is to be retrieved. - * \param [in] capsParam - * Used to specify attribute being queried. Refer ::NV_ENC_CAPS_PARAM for more - * details. - * \param [out] capsVal - * The value corresponding to the capability attribute being queried. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_GENERIC \n - */ -NVENCSTATUS NVENCAPI NvEncGetEncodeCaps (void* encoder, GUID encodeGUID, NV_ENC_CAPS_PARAM* capsParam, int* capsVal); - - -// NvEncGetEncodePresetCount -/** - * \brief Retrieves the number of supported preset GUIDs. - * - * The function returns the number of preset GUIDs available for a given codec. - * The client must validate the codec guid using ::NvEncGetEncodeGUIDs() API - * before calling this function. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in] encodeGUID - * Encode GUID, corresponding to which the number of supported presets is to - * be retrieved. - * \param [out] encodePresetGUIDCount - * Receives the number of supported preset GUIDs. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncGetEncodePresetCount (void* encoder, GUID encodeGUID, uint32_t* encodePresetGUIDCount); - - -// NvEncGetEncodePresetGUIDs -/** - * \brief Receives an array of supported encoder preset GUIDs. - * - * The function returns an array of encode preset guids available for a given codec. - * The client can directly use one of the preset guids based upon the use case - * or target device. The preset guid chosen can be directly used in - * NV_ENC_INITIALIZE_PARAMS::presetGUID parameter to ::NvEncEncodePicture() API. - * Alternately client can also use the preset guid to retrieve the encoding config - * parameters being used by NvEncodeAPI interface for that given preset, using - * ::NvEncGetEncodePresetConfig() API. It can then modify preset config parameters - * as per its use case and send it to NvEncodeAPI interface as part of - * NV_ENC_INITIALIZE_PARAMS::encodeConfig parameter for NvEncInitializeEncoder() - * API. - * - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in] encodeGUID - * Encode GUID, corresponding to which the list of supported presets is to be - * retrieved. - * \param [in] guidArraySize - * Size of array of preset guids passed in \p preset GUIDs - * \param [out] presetGUIDs - * Array of supported Encode preset GUIDs from the NvEncodeAPI interface - * to client. - * \param [out] encodePresetGUIDCount - * Receives the number of preset GUIDs returned by the NvEncodeAPI - * interface. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncGetEncodePresetGUIDs (void* encoder, GUID encodeGUID, GUID* presetGUIDs, uint32_t guidArraySize, uint32_t* encodePresetGUIDCount); - - -// NvEncGetEncodePresetConfig -/** - * \brief Returns a preset config structure supported for given preset GUID. - * - * The function returns a preset config structure for a given preset guid. Before - * using this function the client must enumerate the preset guids available for - * a given codec. The preset config structure can be modified by the client depending - * upon its use case and can be then used to initialize the encoder using - * ::NvEncInitializeEncoder() API. The client can use this function only if it - * wants to modify the NvEncodeAPI preset configuration, otherwise it can - * directly use the preset guid. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in] encodeGUID - * Encode GUID, corresponding to which the list of supported presets is to be - * retrieved. - * \param [in] presetGUID - * Preset GUID, corresponding to which the Encoding configurations is to be - * retrieved. - * \param [out] presetConfig - * The requested Preset Encoder Attribute set. Refer ::_NV_ENC_CONFIG for -* more details. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_INVALID_VERSION \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncGetEncodePresetConfig (void* encoder, GUID encodeGUID, GUID presetGUID, NV_ENC_PRESET_CONFIG* presetConfig); - -// NvEncInitializeEncoder -/** - * \brief Initialize the encoder. - * - * This API must be used to initialize the encoder. The initialization parameter - * is passed using \p *createEncodeParams The client must send the following - * fields of the _NV_ENC_INITIALIZE_PARAMS structure with a valid value. - * - NV_ENC_INITIALIZE_PARAMS::encodeGUID - * - NV_ENC_INITIALIZE_PARAMS::encodeWidth - * - NV_ENC_INITIALIZE_PARAMS::encodeHeight - * - * The client can pass a preset guid directly to the NvEncodeAPI interface using - * NV_ENC_INITIALIZE_PARAMS::presetGUID field. If the client doesn't pass - * NV_ENC_INITIALIZE_PARAMS::encodeConfig structure, the codec specific parameters - * will be selected based on the preset guid. The preset guid must have been - * validated by the client using ::NvEncGetEncodePresetGUIDs() API. - * If the client passes a custom ::_NV_ENC_CONFIG structure through - * NV_ENC_INITIALIZE_PARAMS::encodeConfig , it will override the codec specific parameters - * based on the preset guid. It is recommended that even if the client passes a custom config, - * it should also send a preset guid. In this case, the preset guid passed by the client - * will not override any of the custom config parameters programmed by the client, - * it is only used as a hint by the NvEncodeAPI interface to determine certain encoder parameters - * which are not exposed to the client. - * - * There are two modes of operation for the encoder namely: - * - Asynchronous mode - * - Synchronous mode - * - * The client can select asynchronous or synchronous mode by setting the \p - * enableEncodeAsync field in ::_NV_ENC_INITIALIZE_PARAMS to 1 or 0 respectively. - *\par Asynchronous mode of operation: - * The Asynchronous mode can be enabled by setting NV_ENC_INITIALIZE_PARAMS::enableEncodeAsync to 1. - * The client operating in asynchronous mode must allocate completion event object - * for each output buffer and pass the completion event object in the - * ::NvEncEncodePicture() API. The client can create another thread and wait on - * the event object to be signalled by NvEncodeAPI interface on completion of the - * encoding process for the output frame. This should unblock the main thread from - * submitting work to the encoder. When the event is signalled the client can call - * NvEncodeAPI interfaces to copy the bitstream data using ::NvEncLockBitstream() - * API. This is the preferred mode of operation. - * - * NOTE: Asynchronous mode is not supported on Linux. - * - *\par Synchronous mode of operation: - * The client can select synchronous mode by setting NV_ENC_INITIALIZE_PARAMS::enableEncodeAsync to 0. - * The client working in synchronous mode can work in a single threaded or multi - * threaded mode. The client need not allocate any event objects. The client can - * only lock the bitstream data after NvEncodeAPI interface has returned - * ::NV_ENC_SUCCESS from encode picture. The NvEncodeAPI interface can return - * ::NV_ENC_ERR_NEED_MORE_INPUT error code from ::NvEncEncodePicture() API. The - * client must not lock the output buffer in such case but should send the next - * frame for encoding. The client must keep on calling ::NvEncEncodePicture() API - * until it returns ::NV_ENC_SUCCESS. \n - * The client must always lock the bitstream data in order in which it has submitted. - * This is true for both asynchronous and synchronous mode. - * - *\par Picture type decision: - * If the client is taking the picture type decision and it must disable the picture - * type decision module in NvEncodeAPI by setting NV_ENC_INITIALIZE_PARAMS::enablePTD - * to 0. In this case the client is required to send the picture in encoding - * order to NvEncodeAPI by doing the re-ordering for B frames. \n - * If the client doesn't want to take the picture type decision it can enable - * picture type decision module in the NvEncodeAPI interface by setting - * NV_ENC_INITIALIZE_PARAMS::enablePTD to 1 and send the input pictures in display - * order. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in] createEncodeParams - * Refer ::_NV_ENC_INITIALIZE_PARAMS for details. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_INVALID_VERSION \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncInitializeEncoder (void* encoder, NV_ENC_INITIALIZE_PARAMS* createEncodeParams); - - -// NvEncCreateInputBuffer -/** - * \brief Allocates Input buffer. - * - * This function is used to allocate an input buffer. The client must enumerate - * the input buffer format before allocating the input buffer resources. The - * NV_ENC_INPUT_PTR returned by the NvEncodeAPI interface in the - * NV_ENC_CREATE_INPUT_BUFFER::inputBuffer field can be directly used in - * ::NvEncEncodePicture() API. The number of input buffers to be allocated by the - * client must be at least 4 more than the number of B frames being used for encoding. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in,out] createInputBufferParams - * Pointer to the ::NV_ENC_CREATE_INPUT_BUFFER structure. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_INVALID_VERSION \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncCreateInputBuffer (void* encoder, NV_ENC_CREATE_INPUT_BUFFER* createInputBufferParams); - - -// NvEncDestroyInputBuffer -/** - * \brief Release an input buffers. - * - * This function is used to free an input buffer. If the client has allocated - * any input buffer using ::NvEncCreateInputBuffer() API, it must free those - * input buffers by calling this function. The client must release the input - * buffers before destroying the encoder using ::NvEncDestroyEncoder() API. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in] inputBuffer - * Pointer to the input buffer to be released. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_INVALID_VERSION \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncDestroyInputBuffer (void* encoder, NV_ENC_INPUT_PTR inputBuffer); - - -// NvEncCreateBitstreamBuffer -/** - * \brief Allocates an output bitstream buffer - * - * This function is used to allocate an output bitstream buffer and returns a - * NV_ENC_OUTPUT_PTR to bitstream buffer to the client in the - * NV_ENC_CREATE_BITSTREAM_BUFFER::bitstreamBuffer field. - * The client can only call this function after the encoder session has been - * initialized using ::NvEncInitializeEncoder() API. The minimum number of output - * buffers allocated by the client must be at least 4 more than the number of B - * B frames being used for encoding. The client can only access the output - * bitsteam data by locking the \p bitstreamBuffer using the ::NvEncLockBitstream() - * function. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in,out] createBitstreamBufferParams - * Pointer ::NV_ENC_CREATE_BITSTREAM_BUFFER for details. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_INVALID_VERSION \n - * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncCreateBitstreamBuffer (void* encoder, NV_ENC_CREATE_BITSTREAM_BUFFER* createBitstreamBufferParams); - - -// NvEncDestroyBitstreamBuffer -/** - * \brief Release a bitstream buffer. - * - * This function is used to release the output bitstream buffer allocated using - * the ::NvEncCreateBitstreamBuffer() function. The client must release the output - * bitstreamBuffer using this function before destroying the encoder session. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in] bitstreamBuffer - * Pointer to the bitstream buffer being released. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_INVALID_VERSION \n - * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncDestroyBitstreamBuffer (void* encoder, NV_ENC_OUTPUT_PTR bitstreamBuffer); - -// NvEncEncodePicture -/** - * \brief Submit an input picture for encoding. - * - * This function is used to submit an input picture buffer for encoding. The - * encoding parameters are passed using \p *encodePicParams which is a pointer - * to the ::_NV_ENC_PIC_PARAMS structure. - * - * If the client has set NV_ENC_INITIALIZE_PARAMS::enablePTD to 0, then it must - * send a valid value for the following fields. - * - NV_ENC_PIC_PARAMS::pictureType - * - NV_ENC_PIC_PARAMS_H264::displayPOCSyntax (H264 only) - * - NV_ENC_PIC_PARAMS_H264::frameNumSyntax(H264 only) - * - NV_ENC_PIC_PARAMS_H264::refPicFlag(H264 only) - * - * - *\par Asynchronous Encoding - * If the client has enabled asynchronous mode of encoding by setting - * NV_ENC_INITIALIZE_PARAMS::enableEncodeAsync to 1 in the ::NvEncInitializeEncoder() - * API ,then the client must send a valid NV_ENC_PIC_PARAMS::completionEvent. - * Incase of asynchronous mode of operation, client can queue the ::NvEncEncodePicture() - * API commands from the main thread and then queue output buffers to be processed - * to a secondary worker thread. Before the locking the output buffers in the - * secondary thread , the client must wait on NV_ENC_PIC_PARAMS::completionEvent - * it has queued in ::NvEncEncodePicture() API call. The client must always process - * completion event and the output buffer in the same order in which they have been - * submitted for encoding. The NvEncodeAPI interface is responsible for any - * re-ordering required for B frames and will always ensure that encoded bitstream - * data is written in the same order in which output buffer is submitted. - *\code - The below example shows how asynchronous encoding in case of 1 B frames - ------------------------------------------------------------------------ - Suppose the client allocated 4 input buffers(I1,I2..), 4 output buffers(O1,O2..) - and 4 completion events(E1, E2, ...). The NvEncodeAPI interface will need to - keep a copy of the input buffers for re-ordering and it allocates following - internal buffers (NvI1, NvI2...). These internal buffers are managed by NvEncodeAPI - and the client is not responsible for the allocating or freeing the memory of - the internal buffers. - - a) The client main thread will queue the following encode frame calls. - Note the picture type is unknown to the client, the decision is being taken by - NvEncodeAPI interface. The client should pass ::_NV_ENC_PIC_PARAMS parameter - consisting of allocated input buffer, output buffer and output events in successive - ::NvEncEncodePicture() API calls along with other required encode picture params. - For example: - 1st EncodePicture parameters - (I1, O1, E1) - 2nd EncodePicture parameters - (I2, O2, E2) - 3rd EncodePicture parameters - (I3, O3, E3) - - b) NvEncodeAPI SW will receive the following encode Commands from the client. - The left side shows input from client in the form (Input buffer, Output Buffer, - Output Event). The right hand side shows a possible picture type decision take by - the NvEncodeAPI interface. - (I1, O1, E1) ---P1 Frame - (I2, O2, E2) ---B2 Frame - (I3, O3, E3) ---P3 Frame - - c) NvEncodeAPI interface will make a copy of the input buffers to its internal - buffersfor re-ordering. These copies are done as part of nvEncEncodePicture - function call from the client and NvEncodeAPI interface is responsible for - synchronization of copy operation with the actual encoding operation. - I1 --> NvI1 - I2 --> NvI2 - I3 --> NvI3 - - d) After returning from ::NvEncEncodePicture() call , the client must queue the output - bitstream processing work to the secondary thread. The output bitstream processing - for asynchronous mode consist of first waiting on completion event(E1, E2..) - and then locking the output bitstream buffer(O1, O2..) for reading the encoded - data. The work queued to the secondary thread by the client is in the following order - (I1, O1, E1) - (I2, O2, E2) - (I3, O3, E3) - Note they are in the same order in which client calls ::NvEncEncodePicture() API - in \p step a). - - e) NvEncodeAPI interface will do the re-ordering such that Encoder HW will receive - the following encode commands: - (NvI1, O1, E1) ---P1 Frame - (NvI3, O2, E2) ---P3 Frame - (NvI2, O3, E3) ---B2 frame - - f) After the encoding operations are completed, the events will be signalled - by NvEncodeAPI interface in the following order : - (O1, E1) ---P1 Frame ,output bitstream copied to O1 and event E1 signalled. - (O2, E2) ---P3 Frame ,output bitstream copied to O2 and event E2 signalled. - (O3, E3) ---B2 Frame ,output bitstream copied to O3 and event E3 signalled. - - g) The client must lock the bitstream data using ::NvEncLockBitstream() API in - the order O1,O2,O3 to read the encoded data, after waiting for the events - to be signalled in the same order i.e E1, E2 and E3.The output processing is - done in the secondary thread in the following order: - Waits on E1, copies encoded bitstream from O1 - Waits on E2, copies encoded bitstream from O2 - Waits on E3, copies encoded bitstream from O3 - - -Note the client will receive the events signalling and output buffer in the - same order in which they have submitted for encoding. - -Note the LockBitstream will have picture type field which will notify the - output picture type to the clients. - -Note the input, output buffer and the output completion event are free to be - reused once NvEncodeAPI interfaced has signalled the event and the client has - copied the data from the output buffer. - - * \endcode - * - *\par Synchronous Encoding - * The client can enable synchronous mode of encoding by setting - * NV_ENC_INITIALIZE_PARAMS::enableEncodeAsync to 0 in ::NvEncInitializeEncoder() API. - * The NvEncodeAPI interface may return ::NV_ENC_ERR_NEED_MORE_INPUT error code for - * some ::NvEncEncodePicture() API calls when NV_ENC_INITIALIZE_PARAMS::enablePTD - * is set to 1, but the client must not treat it as a fatal error. The NvEncodeAPI - * interface might not be able to submit an input picture buffer for encoding - * immediately due to re-ordering for B frames. The NvEncodeAPI interface cannot - * submit the input picture which is decided to be encoded as B frame as it waits - * for backward reference from temporally subsequent frames. This input picture - * is buffered internally and waits for more input picture to arrive. The client - * must not call ::NvEncLockBitstream() API on the output buffers whose - * ::NvEncEncodePicture() API returns ::NV_ENC_ERR_NEED_MORE_INPUT. The client must - * wait for the NvEncodeAPI interface to return ::NV_ENC_SUCCESS before locking the - * output bitstreams to read the encoded bitstream data. The following example - * explains the scenario with synchronous encoding with 2 B frames. - *\code - The below example shows how synchronous encoding works in case of 1 B frames - ----------------------------------------------------------------------------- - Suppose the client allocated 4 input buffers(I1,I2..), 4 output buffers(O1,O2..) - and 4 completion events(E1, E2, ...). The NvEncodeAPI interface will need to - keep a copy of the input buffers for re-ordering and it allocates following - internal buffers (NvI1, NvI2...). These internal buffers are managed by NvEncodeAPI - and the client is not responsible for the allocating or freeing the memory of - the internal buffers. - - The client calls ::NvEncEncodePicture() API with input buffer I1 and output buffer O1. - The NvEncodeAPI decides to encode I1 as P frame and submits it to encoder - HW and returns ::NV_ENC_SUCCESS. - The client can now read the encoded data by locking the output O1 by calling - NvEncLockBitstream API. - - The client calls ::NvEncEncodePicture() API with input buffer I2 and output buffer O2. - The NvEncodeAPI decides to encode I2 as B frame and buffers I2 by copying it - to internal buffer and returns ::NV_ENC_ERR_NEED_MORE_INPUT. - The error is not fatal and it notifies client that it cannot read the encoded - data by locking the output O2 by calling ::NvEncLockBitstream() API without submitting - more work to the NvEncodeAPI interface. - - The client calls ::NvEncEncodePicture() with input buffer I3 and output buffer O3. - The NvEncodeAPI decides to encode I3 as P frame and it first submits I3 for - encoding which will be used as backward reference frame for I2. - The NvEncodeAPI then submits I2 for encoding and returns ::NV_ENC_SUCESS. Both - the submission are part of the same ::NvEncEncodePicture() function call. - The client can now read the encoded data for both the frames by locking the output - O2 followed by O3 ,by calling ::NvEncLockBitstream() API. - - The client must always lock the output in the same order in which it has submitted - to receive the encoded bitstream in correct encoding order. - - * \endcode - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in,out] encodePicParams - * Pointer to the ::_NV_ENC_PIC_PARAMS structure. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_INVALID_VERSION \n - * ::NV_ENC_ERR_ENCODER_BUSY \n - * ::NV_ENC_ERR_NEED_MORE_INPUT \n - * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncEncodePicture (void* encoder, NV_ENC_PIC_PARAMS* encodePicParams); - - -// NvEncLockBitstream -/** - * \brief Lock output bitstream buffer - * - * This function is used to lock the bitstream buffer to read the encoded data. - * The client can only access the encoded data by calling this function. - * The pointer to client accessible encoded data is returned in the - * NV_ENC_LOCK_BITSTREAM::bitstreamBufferPtr field. The size of the encoded data - * in the output buffer is returned in the NV_ENC_LOCK_BITSTREAM::bitstreamSizeInBytes - * The NvEncodeAPI interface also returns the output picture type and picture structure - * of the encoded frame in NV_ENC_LOCK_BITSTREAM::pictureType and - * NV_ENC_LOCK_BITSTREAM::pictureStruct fields respectively. If the client has - * set NV_ENC_LOCK_BITSTREAM::doNotWait to 1, the function might return - * ::NV_ENC_ERR_LOCK_BUSY if client is operating in synchronous mode. This is not - * a fatal failure if NV_ENC_LOCK_BITSTREAM::doNotWait is set to 1. In the above case the client can - * retry the function after few milliseconds. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in,out] lockBitstreamBufferParams - * Pointer to the ::_NV_ENC_LOCK_BITSTREAM structure. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_INVALID_VERSION \n - * ::NV_ENC_ERR_LOCK_BUSY \n - * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncLockBitstream (void* encoder, NV_ENC_LOCK_BITSTREAM* lockBitstreamBufferParams); - - -// NvEncUnlockBitstream -/** - * \brief Unlock the output bitstream buffer - * - * This function is used to unlock the output bitstream buffer after the client - * has read the encoded data from output buffer. The client must call this function - * to unlock the output buffer which it has previously locked using ::NvEncLockBitstream() - * function. Using a locked bitstream buffer in ::NvEncEncodePicture() API will cause - * the function to fail. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in,out] bitstreamBuffer - * bitstream buffer pointer being unlocked - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncUnlockBitstream (void* encoder, NV_ENC_OUTPUT_PTR bitstreamBuffer); - - -// NvLockInputBuffer -/** - * \brief Locks an input buffer - * - * This function is used to lock the input buffer to load the uncompressed YUV - * pixel data into input buffer memory. The client must pass the NV_ENC_INPUT_PTR - * it had previously allocated using ::NvEncCreateInputBuffer()in the - * NV_ENC_LOCK_INPUT_BUFFER::inputBuffer field. - * The NvEncodeAPI interface returns pointer to client accessible input buffer - * memory in NV_ENC_LOCK_INPUT_BUFFER::bufferDataPtr field. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in,out] lockInputBufferParams - * Pointer to the ::_NV_ENC_LOCK_INPUT_BUFFER structure - * - * \return - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_INVALID_VERSION \n - * ::NV_ENC_ERR_LOCK_BUSY \n - * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncLockInputBuffer (void* encoder, NV_ENC_LOCK_INPUT_BUFFER* lockInputBufferParams); - - -// NvUnlockInputBuffer -/** - * \brief Unlocks the input buffer - * - * This function is used to unlock the input buffer memory previously locked for - * uploading YUV pixel data. The input buffer must be unlocked before being used - * again for encoding, otherwise NvEncodeAPI will fail the ::NvEncEncodePicture() - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in] inputBuffer - * Pointer to the input buffer that is being unlocked. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_VERSION \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n - * ::NV_ENC_ERR_GENERIC \n - * - * - */ -NVENCSTATUS NVENCAPI NvEncUnlockInputBuffer (void* encoder, NV_ENC_INPUT_PTR inputBuffer); - - -// NvEncGetEncodeStats -/** - * \brief Get encoding statistics. - * - * This function is used to retrieve the encoding statistics. - * This API is not supported when encode device type is CUDA. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in,out] encodeStats - * Pointer to the ::_NV_ENC_STAT structure. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncGetEncodeStats (void* encoder, NV_ENC_STAT* encodeStats); - - -// NvEncGetSequenceParams -/** - * \brief Get encoded sequence and picture header. - * - * This function can be used to retrieve the sequence and picture header out of - * band. The client must call this function only after the encoder has been - * initialized using ::NvEncInitializeEncoder() function. The client must - * allocate the memory where the NvEncodeAPI interface can copy the bitstream - * header and pass the pointer to the memory in NV_ENC_SEQUENCE_PARAM_PAYLOAD::spsppsBuffer. - * The size of buffer is passed in the field NV_ENC_SEQUENCE_PARAM_PAYLOAD::inBufferSize. - * The NvEncodeAPI interface will copy the bitstream header payload and returns - * the actual size of the bitstream header in the field - * NV_ENC_SEQUENCE_PARAM_PAYLOAD::outSPSPPSPayloadSize. - * The client must call ::NvEncGetSequenceParams() function from the same thread which is - * being used to call ::NvEncEncodePicture() function. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in,out] sequenceParamPayload - * Pointer to the ::_NV_ENC_SEQUENCE_PARAM_PAYLOAD structure. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_VERSION \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncGetSequenceParams (void* encoder, NV_ENC_SEQUENCE_PARAM_PAYLOAD* sequenceParamPayload); - - -// NvEncRegisterAsyncEvent -/** - * \brief Register event for notification to encoding completion. - * - * This function is used to register the completion event with NvEncodeAPI - * interface. The event is required when the client has configured the encoder to - * work in asynchronous mode. In this mode the client needs to send a completion - * event with every output buffer. The NvEncodeAPI interface will signal the - * completion of the encoding process using this event. Only after the event is - * signalled the client can get the encoded data using ::NvEncLockBitstream() function. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in] eventParams - * Pointer to the ::_NV_ENC_EVENT_PARAMS structure. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_VERSION \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncRegisterAsyncEvent (void* encoder, NV_ENC_EVENT_PARAMS* eventParams); - - -// NvEncUnregisterAsyncEvent -/** - * \brief Unregister completion event. - * - * This function is used to unregister completion event which has been previously - * registered using ::NvEncRegisterAsyncEvent() function. The client must unregister - * all events before destroying the encoder using ::NvEncDestroyEncoder() function. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in] eventParams - * Pointer to the ::_NV_ENC_EVENT_PARAMS structure. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_VERSION \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncUnregisterAsyncEvent (void* encoder, NV_ENC_EVENT_PARAMS* eventParams); - - -// NvEncMapInputResource -/** - * \brief Map an externally created input resource pointer for encoding. - * - * Maps an externally allocated input resource [using and returns a NV_ENC_INPUT_PTR - * which can be used for encoding in the ::NvEncEncodePicture() function. The - * mapped resource is returned in the field NV_ENC_MAP_INPUT_RESOURCE::outputResourcePtr. - * The NvEncodeAPI interface also returns the buffer format of the mapped resource - * in the field NV_ENC_MAP_INPUT_RESOURCE::outbufferFmt. - * This function provides synchronization guarantee that any graphics or compute - * work submitted on the input buffer is completed before the buffer is used for encoding. - * The client should not access any input buffer while they are mapped by the encoder. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in,out] mapInputResParams - * Pointer to the ::_NV_ENC_MAP_INPUT_RESOURCE structure. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_VERSION \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n - * ::NV_ENC_ERR_RESOURCE_NOT_REGISTERED \n - * ::NV_ENC_ERR_MAP_FAILED \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncMapInputResource (void* encoder, NV_ENC_MAP_INPUT_RESOURCE* mapInputResParams); - - -// NvEncUnmapInputResource -/** - * \brief UnMaps a NV_ENC_INPUT_PTR which was mapped for encoding - * - * - * UnMaps an input buffer which was previously mapped using ::NvEncMapInputResource() - * API. The mapping created using ::NvEncMapInputResource() should be invalidated - * using this API before the external resource is destroyed by the client. The client - * must unmap the buffer after ::NvEncLockBitstream() API returns succuessfully for encode - * work submitted using the mapped input buffer. - * - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in] mappedInputBuffer - * Pointer to the NV_ENC_INPUT_PTR - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_VERSION \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n - * ::NV_ENC_ERR_RESOURCE_NOT_REGISTERED \n - * ::NV_ENC_ERR_RESOURCE_NOT_MAPPED \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncUnmapInputResource (void* encoder, NV_ENC_INPUT_PTR mappedInputBuffer); - -// NvEncDestroyEncoder -/** - * \brief Destroy Encoding Session - * - * Destroys the encoder session previously created using ::NvEncOpenEncodeSession() - * function. The client must flush the encoder before freeing any resources. In order - * to flush the encoder the client must pass a NULL encode picture packet and either - * wait for the ::NvEncEncodePicture() function to return in synchronous mode or wait - * for the flush event to be signaled by the encoder in asynchronous mode. - * The client must free all the input and output resources created using the - * NvEncodeAPI interface before destroying the encoder. If the client is operating - * in asynchronous mode, it must also unregister the completion events previously - * registered. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncDestroyEncoder (void* encoder); - -// NvEncInvalidateRefFrames -/** - * \brief Invalidate reference frames - * - * Invalidates reference frame based on the time stamp provided by the client. - * The encoder marks any reference frames or any frames which have been reconstructed - * using the corrupt frame as invalid for motion estimation and uses older reference - * frames for motion estimation. The encoded forces the current frame to be encoded - * as an intra frame if no reference frames are left after invalidation process. - * This is useful for low latency application for error resiliency. The client - * is recommended to set NV_ENC_CONFIG_H264::maxNumRefFrames to a large value so - * that encoder can keep a backup of older reference frames in the DPB and can use them - * for motion estimation when the newer reference frames have been invalidated. - * This API can be called multiple times. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in] invalidRefFrameTimeStamp - * Timestamp of the invalid reference frames which needs to be invalidated. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncInvalidateRefFrames(void* encoder, uint64_t invalidRefFrameTimeStamp); - -// NvEncOpenEncodeSessionEx -/** - * \brief Opens an encoding session. - * - * Opens an encoding session and returns a pointer to the encoder interface in - * the \p **encoder parameter. The client should start encoding process by calling - * this API first. - * The client must pass a pointer to IDirect3DDevice9 device or CUDA context in the \p *device parameter. - * For the OpenGL interface, \p device must be NULL. An OpenGL context must be current when - * calling all NvEncodeAPI functions. - * If the creation of encoder session fails, the client must call ::NvEncDestroyEncoder API - * before exiting. - * - * \param [in] openSessionExParams - * Pointer to a ::NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS structure. - * \param [out] encoder - * Encode Session pointer to the NvEncodeAPI interface. - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_NO_ENCODE_DEVICE \n - * ::NV_ENC_ERR_UNSUPPORTED_DEVICE \n - * ::NV_ENC_ERR_INVALID_DEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncOpenEncodeSessionEx (NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS *openSessionExParams, void** encoder); - -// NvEncRegisterResource -/** - * \brief Registers a resource with the Nvidia Video Encoder Interface. - * - * Registers a resource with the Nvidia Video Encoder Interface for book keeping. - * The client is expected to pass the registered resource handle as well, while calling ::NvEncMapInputResource API. - * - * \param [in] encoder - * Pointer to the NVEncodeAPI interface. - * - * \param [in] registerResParams - * Pointer to a ::_NV_ENC_REGISTER_RESOURCE structure - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_VERSION \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n - * ::NV_ENC_ERR_RESOURCE_REGISTER_FAILED \n - * ::NV_ENC_ERR_GENERIC \n - * ::NV_ENC_ERR_UNIMPLEMENTED \n - * - */ -NVENCSTATUS NVENCAPI NvEncRegisterResource (void* encoder, NV_ENC_REGISTER_RESOURCE* registerResParams); - -// NvEncUnregisterResource -/** - * \brief Unregisters a resource previously registered with the Nvidia Video Encoder Interface. - * - * Unregisters a resource previously registered with the Nvidia Video Encoder Interface. - * The client is expected to unregister any resource that it has registered with the - * Nvidia Video Encoder Interface before destroying the resource. - * - * \param [in] encoder - * Pointer to the NVEncodeAPI interface. - * - * \param [in] registeredResource - * The registered resource pointer that was returned in ::NvEncRegisterResource. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_VERSION \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n - * ::NV_ENC_ERR_RESOURCE_NOT_REGISTERED \n - * ::NV_ENC_ERR_GENERIC \n - * ::NV_ENC_ERR_UNIMPLEMENTED \n - * - */ -NVENCSTATUS NVENCAPI NvEncUnregisterResource (void* encoder, NV_ENC_REGISTERED_PTR registeredResource); - -// NvEncReconfigureEncoder -/** - * \brief Reconfigure an existing encoding session. - * - * Reconfigure an existing encoding session. - * The client should call this API to change/reconfigure the parameter passed during - * NvEncInitializeEncoder API call. - * Currently Reconfiguration of following are not supported. - * Change in GOP structure. - * Change in sync-Async mode. - * Change in MaxWidth & MaxHeight. - * Change in PTDmode. - * - * Resolution change is possible only if maxEncodeWidth & maxEncodeHeight of NV_ENC_INITIALIZE_PARAMS - * is set while creating encoder session. - * - * \param [in] encoder - * Pointer to the NVEncodeAPI interface. - * - * \param [in] reInitEncodeParams - * Pointer to a ::NV_ENC_RECONFIGURE_PARAMS structure. - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_NO_ENCODE_DEVICE \n - * ::NV_ENC_ERR_UNSUPPORTED_DEVICE \n - * ::NV_ENC_ERR_INVALID_DEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_GENERIC \n - * - */ -NVENCSTATUS NVENCAPI NvEncReconfigureEncoder (void *encoder, NV_ENC_RECONFIGURE_PARAMS* reInitEncodeParams); - - - -// NvEncCreateMVBuffer -/** - * \brief Allocates output MV buffer for ME only mode. - * - * This function is used to allocate an output MV buffer. The size of the mvBuffer is - * dependent on the frame height and width of the last ::NvEncCreateInputBuffer() call. - * The NV_ENC_OUTPUT_PTR returned by the NvEncodeAPI interface in the - * ::NV_ENC_CREATE_MV_BUFFER::mvBuffer field should be used in - * ::NvEncRunMotionEstimationOnly() API. - * Client must lock ::NV_ENC_CREATE_MV_BUFFER::mvBuffer using ::NvEncLockBitstream() API to get the motion vector data. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in,out] createMVBufferParams - * Pointer to the ::NV_ENC_CREATE_MV_BUFFER structure. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_INVALID_VERSION \n - * ::NV_ENC_ERR_GENERIC \n - */ -NVENCSTATUS NVENCAPI NvEncCreateMVBuffer (void* encoder, NV_ENC_CREATE_MV_BUFFER* createMVBufferParams); - - -// NvEncDestroyMVBuffer -/** - * \brief Release an output MV buffer for ME only mode. - * - * This function is used to release the output MV buffer allocated using - * the ::NvEncCreateMVBuffer() function. The client must release the output - * mvBuffer using this function before destroying the encoder session. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in] mvBuffer - * Pointer to the mvBuffer being released. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_INVALID_VERSION \n - * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n - * ::NV_ENC_ERR_GENERIC \n - */ -NVENCSTATUS NVENCAPI NvEncDestroyMVBuffer (void* encoder, NV_ENC_OUTPUT_PTR mvBuffer); - - -// NvEncRunMotionEstimationOnly -/** - * \brief Submit an input picture and reference frame for motion estimation in ME only mode. - * - * This function is used to submit the input frame and reference frame for motion - * estimation. The ME parameters are passed using *meOnlyParams which is a pointer - * to ::_NV_ENC_MEONLY_PARAMS structure. - * Client must lock ::NV_ENC_CREATE_MV_BUFFER::mvBuffer using ::NvEncLockBitstream() API to get the motion vector data. - * to get motion vector data. - * - * \param [in] encoder - * Pointer to the NvEncodeAPI interface. - * \param [in] meOnlyParams - * Pointer to the ::_NV_ENC_MEONLY_PARAMS structure. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - * ::NV_ENC_ERR_INVALID_ENCODERDEVICE \n - * ::NV_ENC_ERR_DEVICE_NOT_EXIST \n - * ::NV_ENC_ERR_UNSUPPORTED_PARAM \n - * ::NV_ENC_ERR_OUT_OF_MEMORY \n - * ::NV_ENC_ERR_INVALID_PARAM \n - * ::NV_ENC_ERR_INVALID_VERSION \n - * ::NV_ENC_ERR_NEED_MORE_INPUT \n - * ::NV_ENC_ERR_ENCODER_NOT_INITIALIZED \n - * ::NV_ENC_ERR_GENERIC \n - */ -NVENCSTATUS NVENCAPI NvEncRunMotionEstimationOnly (void* encoder, NV_ENC_MEONLY_PARAMS* meOnlyParams); - -// NvEncodeAPIGetMaxSupportedVersion -/** - * \brief Get the largest NvEncodeAPI version supported by the driver. - * - * This function can be used by clients to determine if the driver supports - * the NvEncodeAPI header the application was compiled with. - * - * \param [out] version - * Pointer to the requested value. The 4 least significant bits in the returned - * indicate the minor version and the rest of the bits indicate the major - * version of the largest supported version. - * - * \return - * ::NV_ENC_SUCCESS \n - * ::NV_ENC_ERR_INVALID_PTR \n - */ -NVENCSTATUS NVENCAPI NvEncodeAPIGetMaxSupportedVersion (uint32_t* version); - - -/// \cond API PFN -/* - * Defines API function pointers - */ -typedef NVENCSTATUS (NVENCAPI* PNVENCOPENENCODESESSION) (void* device, uint32_t deviceType, void** encoder); -typedef NVENCSTATUS (NVENCAPI* PNVENCGETENCODEGUIDCOUNT) (void* encoder, uint32_t* encodeGUIDCount); -typedef NVENCSTATUS (NVENCAPI* PNVENCGETENCODEGUIDS) (void* encoder, GUID* GUIDs, uint32_t guidArraySize, uint32_t* GUIDCount); -typedef NVENCSTATUS (NVENCAPI* PNVENCGETENCODEPROFILEGUIDCOUNT) (void* encoder, GUID encodeGUID, uint32_t* encodeProfileGUIDCount); -typedef NVENCSTATUS (NVENCAPI* PNVENCGETENCODEPROFILEGUIDS) (void* encoder, GUID encodeGUID, GUID* profileGUIDs, uint32_t guidArraySize, uint32_t* GUIDCount); -typedef NVENCSTATUS (NVENCAPI* PNVENCGETINPUTFORMATCOUNT) (void* encoder, GUID encodeGUID, uint32_t* inputFmtCount); -typedef NVENCSTATUS (NVENCAPI* PNVENCGETINPUTFORMATS) (void* encoder, GUID encodeGUID, NV_ENC_BUFFER_FORMAT* inputFmts, uint32_t inputFmtArraySize, uint32_t* inputFmtCount); -typedef NVENCSTATUS (NVENCAPI* PNVENCGETENCODECAPS) (void* encoder, GUID encodeGUID, NV_ENC_CAPS_PARAM* capsParam, int* capsVal); -typedef NVENCSTATUS (NVENCAPI* PNVENCGETENCODEPRESETCOUNT) (void* encoder, GUID encodeGUID, uint32_t* encodePresetGUIDCount); -typedef NVENCSTATUS (NVENCAPI* PNVENCGETENCODEPRESETGUIDS) (void* encoder, GUID encodeGUID, GUID* presetGUIDs, uint32_t guidArraySize, uint32_t* encodePresetGUIDCount); -typedef NVENCSTATUS (NVENCAPI* PNVENCGETENCODEPRESETCONFIG) (void* encoder, GUID encodeGUID, GUID presetGUID, NV_ENC_PRESET_CONFIG* presetConfig); -typedef NVENCSTATUS (NVENCAPI* PNVENCINITIALIZEENCODER) (void* encoder, NV_ENC_INITIALIZE_PARAMS* createEncodeParams); -typedef NVENCSTATUS (NVENCAPI* PNVENCCREATEINPUTBUFFER) (void* encoder, NV_ENC_CREATE_INPUT_BUFFER* createInputBufferParams); -typedef NVENCSTATUS (NVENCAPI* PNVENCDESTROYINPUTBUFFER) (void* encoder, NV_ENC_INPUT_PTR inputBuffer); -typedef NVENCSTATUS (NVENCAPI* PNVENCCREATEBITSTREAMBUFFER) (void* encoder, NV_ENC_CREATE_BITSTREAM_BUFFER* createBitstreamBufferParams); -typedef NVENCSTATUS (NVENCAPI* PNVENCDESTROYBITSTREAMBUFFER) (void* encoder, NV_ENC_OUTPUT_PTR bitstreamBuffer); -typedef NVENCSTATUS (NVENCAPI* PNVENCENCODEPICTURE) (void* encoder, NV_ENC_PIC_PARAMS* encodePicParams); -typedef NVENCSTATUS (NVENCAPI* PNVENCLOCKBITSTREAM) (void* encoder, NV_ENC_LOCK_BITSTREAM* lockBitstreamBufferParams); -typedef NVENCSTATUS (NVENCAPI* PNVENCUNLOCKBITSTREAM) (void* encoder, NV_ENC_OUTPUT_PTR bitstreamBuffer); -typedef NVENCSTATUS (NVENCAPI* PNVENCLOCKINPUTBUFFER) (void* encoder, NV_ENC_LOCK_INPUT_BUFFER* lockInputBufferParams); -typedef NVENCSTATUS (NVENCAPI* PNVENCUNLOCKINPUTBUFFER) (void* encoder, NV_ENC_INPUT_PTR inputBuffer); -typedef NVENCSTATUS (NVENCAPI* PNVENCGETENCODESTATS) (void* encoder, NV_ENC_STAT* encodeStats); -typedef NVENCSTATUS (NVENCAPI* PNVENCGETSEQUENCEPARAMS) (void* encoder, NV_ENC_SEQUENCE_PARAM_PAYLOAD* sequenceParamPayload); -typedef NVENCSTATUS (NVENCAPI* PNVENCREGISTERASYNCEVENT) (void* encoder, NV_ENC_EVENT_PARAMS* eventParams); -typedef NVENCSTATUS (NVENCAPI* PNVENCUNREGISTERASYNCEVENT) (void* encoder, NV_ENC_EVENT_PARAMS* eventParams); -typedef NVENCSTATUS (NVENCAPI* PNVENCMAPINPUTRESOURCE) (void* encoder, NV_ENC_MAP_INPUT_RESOURCE* mapInputResParams); -typedef NVENCSTATUS (NVENCAPI* PNVENCUNMAPINPUTRESOURCE) (void* encoder, NV_ENC_INPUT_PTR mappedInputBuffer); -typedef NVENCSTATUS (NVENCAPI* PNVENCDESTROYENCODER) (void* encoder); -typedef NVENCSTATUS (NVENCAPI* PNVENCINVALIDATEREFFRAMES) (void* encoder, uint64_t invalidRefFrameTimeStamp); -typedef NVENCSTATUS (NVENCAPI* PNVENCOPENENCODESESSIONEX) (NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS *openSessionExParams, void** encoder); -typedef NVENCSTATUS (NVENCAPI* PNVENCREGISTERRESOURCE) (void* encoder, NV_ENC_REGISTER_RESOURCE* registerResParams); -typedef NVENCSTATUS (NVENCAPI* PNVENCUNREGISTERRESOURCE) (void* encoder, NV_ENC_REGISTERED_PTR registeredRes); -typedef NVENCSTATUS (NVENCAPI* PNVENCRECONFIGUREENCODER) (void* encoder, NV_ENC_RECONFIGURE_PARAMS* reInitEncodeParams); - -typedef NVENCSTATUS (NVENCAPI* PNVENCCREATEMVBUFFER) (void* encoder, NV_ENC_CREATE_MV_BUFFER* createMVBufferParams); -typedef NVENCSTATUS (NVENCAPI* PNVENCDESTROYMVBUFFER) (void* encoder, NV_ENC_OUTPUT_PTR mvBuffer); -typedef NVENCSTATUS (NVENCAPI* PNVENCRUNMOTIONESTIMATIONONLY) (void* encoder, NV_ENC_MEONLY_PARAMS* meOnlyParams); - - -/// \endcond - - -/** @} */ /* END ENCODE_FUNC */ - -/** - * \ingroup ENCODER_STRUCTURE - * NV_ENCODE_API_FUNCTION_LIST - */ -typedef struct _NV_ENCODE_API_FUNCTION_LIST -{ - uint32_t version; /**< [in]: Client should pass NV_ENCODE_API_FUNCTION_LIST_VER. */ - uint32_t reserved; /**< [in]: Reserved and should be set to 0. */ - PNVENCOPENENCODESESSION nvEncOpenEncodeSession; /**< [out]: Client should access ::NvEncOpenEncodeSession() API through this pointer. */ - PNVENCGETENCODEGUIDCOUNT nvEncGetEncodeGUIDCount; /**< [out]: Client should access ::NvEncGetEncodeGUIDCount() API through this pointer. */ - PNVENCGETENCODEPRESETCOUNT nvEncGetEncodeProfileGUIDCount; /**< [out]: Client should access ::NvEncGetEncodeProfileGUIDCount() API through this pointer.*/ - PNVENCGETENCODEPRESETGUIDS nvEncGetEncodeProfileGUIDs; /**< [out]: Client should access ::NvEncGetEncodeProfileGUIDs() API through this pointer. */ - PNVENCGETENCODEGUIDS nvEncGetEncodeGUIDs; /**< [out]: Client should access ::NvEncGetEncodeGUIDs() API through this pointer. */ - PNVENCGETINPUTFORMATCOUNT nvEncGetInputFormatCount; /**< [out]: Client should access ::NvEncGetInputFormatCount() API through this pointer. */ - PNVENCGETINPUTFORMATS nvEncGetInputFormats; /**< [out]: Client should access ::NvEncGetInputFormats() API through this pointer. */ - PNVENCGETENCODECAPS nvEncGetEncodeCaps; /**< [out]: Client should access ::NvEncGetEncodeCaps() API through this pointer. */ - PNVENCGETENCODEPRESETCOUNT nvEncGetEncodePresetCount; /**< [out]: Client should access ::NvEncGetEncodePresetCount() API through this pointer. */ - PNVENCGETENCODEPRESETGUIDS nvEncGetEncodePresetGUIDs; /**< [out]: Client should access ::NvEncGetEncodePresetGUIDs() API through this pointer. */ - PNVENCGETENCODEPRESETCONFIG nvEncGetEncodePresetConfig; /**< [out]: Client should access ::NvEncGetEncodePresetConfig() API through this pointer. */ - PNVENCINITIALIZEENCODER nvEncInitializeEncoder; /**< [out]: Client should access ::NvEncInitializeEncoder() API through this pointer. */ - PNVENCCREATEINPUTBUFFER nvEncCreateInputBuffer; /**< [out]: Client should access ::NvEncCreateInputBuffer() API through this pointer. */ - PNVENCDESTROYINPUTBUFFER nvEncDestroyInputBuffer; /**< [out]: Client should access ::NvEncDestroyInputBuffer() API through this pointer. */ - PNVENCCREATEBITSTREAMBUFFER nvEncCreateBitstreamBuffer; /**< [out]: Client should access ::NvEncCreateBitstreamBuffer() API through this pointer. */ - PNVENCDESTROYBITSTREAMBUFFER nvEncDestroyBitstreamBuffer; /**< [out]: Client should access ::NvEncDestroyBitstreamBuffer() API through this pointer. */ - PNVENCENCODEPICTURE nvEncEncodePicture; /**< [out]: Client should access ::NvEncEncodePicture() API through this pointer. */ - PNVENCLOCKBITSTREAM nvEncLockBitstream; /**< [out]: Client should access ::NvEncLockBitstream() API through this pointer. */ - PNVENCUNLOCKBITSTREAM nvEncUnlockBitstream; /**< [out]: Client should access ::NvEncUnlockBitstream() API through this pointer. */ - PNVENCLOCKINPUTBUFFER nvEncLockInputBuffer; /**< [out]: Client should access ::NvEncLockInputBuffer() API through this pointer. */ - PNVENCUNLOCKINPUTBUFFER nvEncUnlockInputBuffer; /**< [out]: Client should access ::NvEncUnlockInputBuffer() API through this pointer. */ - PNVENCGETENCODESTATS nvEncGetEncodeStats; /**< [out]: Client should access ::NvEncGetEncodeStats() API through this pointer. */ - PNVENCGETSEQUENCEPARAMS nvEncGetSequenceParams; /**< [out]: Client should access ::NvEncGetSequenceParams() API through this pointer. */ - PNVENCREGISTERASYNCEVENT nvEncRegisterAsyncEvent; /**< [out]: Client should access ::NvEncRegisterAsyncEvent() API through this pointer. */ - PNVENCUNREGISTERASYNCEVENT nvEncUnregisterAsyncEvent; /**< [out]: Client should access ::NvEncUnregisterAsyncEvent() API through this pointer. */ - PNVENCMAPINPUTRESOURCE nvEncMapInputResource; /**< [out]: Client should access ::NvEncMapInputResource() API through this pointer. */ - PNVENCUNMAPINPUTRESOURCE nvEncUnmapInputResource; /**< [out]: Client should access ::NvEncUnmapInputResource() API through this pointer. */ - PNVENCDESTROYENCODER nvEncDestroyEncoder; /**< [out]: Client should access ::NvEncDestroyEncoder() API through this pointer. */ - PNVENCINVALIDATEREFFRAMES nvEncInvalidateRefFrames; /**< [out]: Client should access ::NvEncInvalidateRefFrames() API through this pointer. */ - PNVENCOPENENCODESESSIONEX nvEncOpenEncodeSessionEx; /**< [out]: Client should access ::NvEncOpenEncodeSession() API through this pointer. */ - PNVENCREGISTERRESOURCE nvEncRegisterResource; /**< [out]: Client should access ::NvEncRegisterResource() API through this pointer. */ - PNVENCUNREGISTERRESOURCE nvEncUnregisterResource; /**< [out]: Client should access ::NvEncUnregisterResource() API through this pointer. */ - PNVENCRECONFIGUREENCODER nvEncReconfigureEncoder; /**< [out]: Client should access ::NvEncReconfigureEncoder() API through this pointer. */ - void* reserved1; - PNVENCCREATEMVBUFFER nvEncCreateMVBuffer; /**< [out]: Client should access ::NvEncCreateMVBuffer API through this pointer. */ - PNVENCDESTROYMVBUFFER nvEncDestroyMVBuffer; /**< [out]: Client should access ::NvEncDestroyMVBuffer API through this pointer. */ - PNVENCRUNMOTIONESTIMATIONONLY nvEncRunMotionEstimationOnly; /**< [out]: Client should access ::NvEncRunMotionEstimationOnly API through this pointer. */ - void* reserved2[281]; /**< [in]: Reserved and must be set to NULL */ -} NV_ENCODE_API_FUNCTION_LIST; - -/** Macro for constructing the version field of ::_NV_ENCODEAPI_FUNCTION_LIST. */ -#define NV_ENCODE_API_FUNCTION_LIST_VER NVENCAPI_STRUCT_VERSION(2) - -// NvEncodeAPICreateInstance -/** - * \ingroup ENCODE_FUNC - * Entry Point to the NvEncodeAPI interface. - * - * Creates an instance of the NvEncodeAPI interface, and populates the - * pFunctionList with function pointers to the API routines implemented by the - * NvEncodeAPI interface. - * - * \param [out] functionList - * - * \return - * ::NV_ENC_SUCCESS - * ::NV_ENC_ERR_INVALID_PTR - */ -NVENCSTATUS NVENCAPI NvEncodeAPICreateInstance(NV_ENCODE_API_FUNCTION_LIST *functionList); - -#ifdef __cplusplus -} -#endif - - -#endif - diff --git a/compat/os2threads.h b/compat/os2threads.h index 40a119ffe1751..2177a033ecbb0 100644 --- a/compat/os2threads.h +++ b/compat/os2threads.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011 KO Myung-Hun + * Copyright (c) 2011-2017 KO Myung-Hun * * This file is part of FFmpeg. * @@ -46,9 +46,11 @@ typedef struct { typedef void pthread_attr_t; -typedef HMTX pthread_mutex_t; +typedef _fmutex pthread_mutex_t; typedef void pthread_mutexattr_t; +#define PTHREAD_MUTEX_INITIALIZER _FMUTEX_INITIALIZER + typedef struct { HEV event_sem; HEV ack_sem; @@ -98,28 +100,28 @@ static av_always_inline int pthread_join(pthread_t thread, void **value_ptr) static av_always_inline int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) { - DosCreateMutexSem(NULL, (PHMTX)mutex, 0, FALSE); + _fmutex_create(mutex, 0); return 0; } static av_always_inline int pthread_mutex_destroy(pthread_mutex_t *mutex) { - DosCloseMutexSem(*(PHMTX)mutex); + _fmutex_close(mutex); return 0; } static av_always_inline int pthread_mutex_lock(pthread_mutex_t *mutex) { - DosRequestMutexSem(*(PHMTX)mutex, SEM_INDEFINITE_WAIT); + _fmutex_request(mutex, 0); return 0; } static av_always_inline int pthread_mutex_unlock(pthread_mutex_t *mutex) { - DosReleaseMutexSem(*(PHMTX)mutex); + _fmutex_release(mutex); return 0; } diff --git a/compat/w32dlfcn.h b/compat/w32dlfcn.h index 78cc8f4c96d6c..c83bdc933307b 100644 --- a/compat/w32dlfcn.h +++ b/compat/w32dlfcn.h @@ -21,6 +21,7 @@ #ifdef _WIN32 #include +#include "config.h" #if (_WIN32_WINNT < 0x0602) || HAVE_WINRT #include "libavutil/wchar_filename.h" #endif diff --git a/compat/w32pthreads.h b/compat/w32pthreads.h index eeead6051f2da..21acfd2ba1a94 100644 --- a/compat/w32pthreads.h +++ b/compat/w32pthreads.h @@ -39,11 +39,6 @@ #include #include -#if _WIN32_WINNT < 0x0600 && defined(__MINGW32__) -#undef MemoryBarrier -#define MemoryBarrier __sync_synchronize -#endif - #include "libavutil/attributes.h" #include "libavutil/common.h" #include "libavutil/internal.h" @@ -56,24 +51,15 @@ typedef struct pthread_t { void *ret; } pthread_t; -/* the conditional variable api for windows 6.0+ uses critical sections and - * not mutexes */ -typedef CRITICAL_SECTION pthread_mutex_t; - -/* This is the CONDITION_VARIABLE typedef for using Windows' native - * conditional variables on kernels 6.0+. */ -#if HAVE_CONDITION_VARIABLE_PTR +/* use light weight mutex/condition variable API for Windows Vista and later */ +typedef SRWLOCK pthread_mutex_t; typedef CONDITION_VARIABLE pthread_cond_t; -#else -typedef struct pthread_cond_t { - void *Ptr; -} pthread_cond_t; -#endif -#if _WIN32_WINNT >= 0x0600 +#define PTHREAD_MUTEX_INITIALIZER SRWLOCK_INIT +#define PTHREAD_COND_INITIALIZER CONDITION_VARIABLE_INIT + #define InitializeCriticalSection(x) InitializeCriticalSectionEx(x, 0, 0) #define WaitForSingleObject(a, b) WaitForSingleObjectEx(a, b, FALSE) -#endif static av_unused unsigned __stdcall attribute_align_arg win32thread_worker(void *arg) { @@ -114,26 +100,25 @@ static av_unused int pthread_join(pthread_t thread, void **value_ptr) static inline int pthread_mutex_init(pthread_mutex_t *m, void* attr) { - InitializeCriticalSection(m); + InitializeSRWLock(m); return 0; } static inline int pthread_mutex_destroy(pthread_mutex_t *m) { - DeleteCriticalSection(m); + /* Unlocked SWR locks use no resources */ return 0; } static inline int pthread_mutex_lock(pthread_mutex_t *m) { - EnterCriticalSection(m); + AcquireSRWLockExclusive(m); return 0; } static inline int pthread_mutex_unlock(pthread_mutex_t *m) { - LeaveCriticalSection(m); + ReleaseSRWLockExclusive(m); return 0; } -#if _WIN32_WINNT >= 0x0600 typedef INIT_ONCE pthread_once_t; #define PTHREAD_ONCE_INIT INIT_ONCE_STATIC_INIT @@ -167,7 +152,7 @@ static inline int pthread_cond_broadcast(pthread_cond_t *cond) static inline int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) { - SleepConditionVariableCS(cond, mutex, INFINITE); + SleepConditionVariableSRW(cond, mutex, INFINITE, 0); return 0; } @@ -177,242 +162,4 @@ static inline int pthread_cond_signal(pthread_cond_t *cond) return 0; } -#else // _WIN32_WINNT < 0x0600 - -/* atomic init state of dynamically loaded functions */ -static LONG w32thread_init_state = 0; -static av_unused void w32thread_init(void); - -/* for pre-Windows 6.0 platforms, define INIT_ONCE struct, - * compatible to the one used in the native API */ - -typedef union pthread_once_t { - void * Ptr; ///< For the Windows 6.0+ native functions - LONG state; ///< For the pre-Windows 6.0 compat code -} pthread_once_t; - -#define PTHREAD_ONCE_INIT {0} - -/* function pointers to init once API on windows 6.0+ kernels */ -static BOOL (WINAPI *initonce_begin)(pthread_once_t *lpInitOnce, DWORD dwFlags, BOOL *fPending, void **lpContext); -static BOOL (WINAPI *initonce_complete)(pthread_once_t *lpInitOnce, DWORD dwFlags, void *lpContext); - -/* pre-Windows 6.0 compat using a spin-lock */ -static inline void w32thread_once_fallback(LONG volatile *state, void (*init_routine)(void)) -{ - switch (InterlockedCompareExchange(state, 1, 0)) { - /* Initial run */ - case 0: - init_routine(); - InterlockedExchange(state, 2); - break; - /* Another thread is running init */ - case 1: - while (1) { - MemoryBarrier(); - if (*state == 2) - break; - Sleep(0); - } - break; - /* Initialization complete */ - case 2: - break; - } -} - -static av_unused int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)) -{ - w32thread_once_fallback(&w32thread_init_state, w32thread_init); - - /* Use native functions on Windows 6.0+ */ - if (initonce_begin && initonce_complete) { - BOOL pending = FALSE; - initonce_begin(once_control, 0, &pending, NULL); - if (pending) - init_routine(); - initonce_complete(once_control, 0, NULL); - return 0; - } - - w32thread_once_fallback(&once_control->state, init_routine); - return 0; -} - -/* for pre-Windows 6.0 platforms we need to define and use our own condition - * variable and api */ - -typedef struct win32_cond_t { - pthread_mutex_t mtx_broadcast; - pthread_mutex_t mtx_waiter_count; - volatile int waiter_count; - HANDLE semaphore; - HANDLE waiters_done; - volatile int is_broadcast; -} win32_cond_t; - -/* function pointers to conditional variable API on windows 6.0+ kernels */ -static void (WINAPI *cond_broadcast)(pthread_cond_t *cond); -static void (WINAPI *cond_init)(pthread_cond_t *cond); -static void (WINAPI *cond_signal)(pthread_cond_t *cond); -static BOOL (WINAPI *cond_wait)(pthread_cond_t *cond, pthread_mutex_t *mutex, - DWORD milliseconds); - -static av_unused int pthread_cond_init(pthread_cond_t *cond, const void *unused_attr) -{ - win32_cond_t *win32_cond = NULL; - - w32thread_once_fallback(&w32thread_init_state, w32thread_init); - - if (cond_init) { - cond_init(cond); - return 0; - } - - /* non native condition variables */ - win32_cond = (win32_cond_t*)av_mallocz(sizeof(win32_cond_t)); - if (!win32_cond) - return ENOMEM; - cond->Ptr = win32_cond; - win32_cond->semaphore = CreateSemaphore(NULL, 0, 0x7fffffff, NULL); - if (!win32_cond->semaphore) - return ENOMEM; - win32_cond->waiters_done = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!win32_cond->waiters_done) - return ENOMEM; - - pthread_mutex_init(&win32_cond->mtx_waiter_count, NULL); - pthread_mutex_init(&win32_cond->mtx_broadcast, NULL); - return 0; -} - -static av_unused int pthread_cond_destroy(pthread_cond_t *cond) -{ - win32_cond_t *win32_cond = (win32_cond_t*)cond->Ptr; - /* native condition variables do not destroy */ - if (cond_init) - return 0; - - /* non native condition variables */ - CloseHandle(win32_cond->semaphore); - CloseHandle(win32_cond->waiters_done); - pthread_mutex_destroy(&win32_cond->mtx_waiter_count); - pthread_mutex_destroy(&win32_cond->mtx_broadcast); - av_freep(&win32_cond); - cond->Ptr = NULL; - return 0; -} - -static av_unused int pthread_cond_broadcast(pthread_cond_t *cond) -{ - win32_cond_t *win32_cond = (win32_cond_t*)cond->Ptr; - int have_waiter; - - if (cond_broadcast) { - cond_broadcast(cond); - return 0; - } - - /* non native condition variables */ - pthread_mutex_lock(&win32_cond->mtx_broadcast); - pthread_mutex_lock(&win32_cond->mtx_waiter_count); - have_waiter = 0; - - if (win32_cond->waiter_count) { - win32_cond->is_broadcast = 1; - have_waiter = 1; - } - - if (have_waiter) { - ReleaseSemaphore(win32_cond->semaphore, win32_cond->waiter_count, NULL); - pthread_mutex_unlock(&win32_cond->mtx_waiter_count); - WaitForSingleObject(win32_cond->waiters_done, INFINITE); - ResetEvent(win32_cond->waiters_done); - win32_cond->is_broadcast = 0; - } else - pthread_mutex_unlock(&win32_cond->mtx_waiter_count); - pthread_mutex_unlock(&win32_cond->mtx_broadcast); - return 0; -} - -static av_unused int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) -{ - win32_cond_t *win32_cond = (win32_cond_t*)cond->Ptr; - int last_waiter; - if (cond_wait) { - cond_wait(cond, mutex, INFINITE); - return 0; - } - - /* non native condition variables */ - pthread_mutex_lock(&win32_cond->mtx_broadcast); - pthread_mutex_lock(&win32_cond->mtx_waiter_count); - win32_cond->waiter_count++; - pthread_mutex_unlock(&win32_cond->mtx_waiter_count); - pthread_mutex_unlock(&win32_cond->mtx_broadcast); - - // unlock the external mutex - pthread_mutex_unlock(mutex); - WaitForSingleObject(win32_cond->semaphore, INFINITE); - - pthread_mutex_lock(&win32_cond->mtx_waiter_count); - win32_cond->waiter_count--; - last_waiter = !win32_cond->waiter_count || !win32_cond->is_broadcast; - pthread_mutex_unlock(&win32_cond->mtx_waiter_count); - - if (last_waiter) - SetEvent(win32_cond->waiters_done); - - // lock the external mutex - return pthread_mutex_lock(mutex); -} - -static av_unused int pthread_cond_signal(pthread_cond_t *cond) -{ - win32_cond_t *win32_cond = (win32_cond_t*)cond->Ptr; - int have_waiter; - if (cond_signal) { - cond_signal(cond); - return 0; - } - - pthread_mutex_lock(&win32_cond->mtx_broadcast); - - /* non-native condition variables */ - pthread_mutex_lock(&win32_cond->mtx_waiter_count); - have_waiter = win32_cond->waiter_count; - pthread_mutex_unlock(&win32_cond->mtx_waiter_count); - - if (have_waiter) { - ReleaseSemaphore(win32_cond->semaphore, 1, NULL); - WaitForSingleObject(win32_cond->waiters_done, INFINITE); - ResetEvent(win32_cond->waiters_done); - } - - pthread_mutex_unlock(&win32_cond->mtx_broadcast); - return 0; -} -#endif - -static av_unused void w32thread_init(void) -{ -#if _WIN32_WINNT < 0x0600 - HMODULE kernel_dll = GetModuleHandle(TEXT("kernel32.dll")); - /* if one is available, then they should all be available */ - cond_init = (void (WINAPI*)(pthread_cond_t *)) - GetProcAddress(kernel_dll, "InitializeConditionVariable"); - cond_broadcast = (void (WINAPI*)(pthread_cond_t *)) - GetProcAddress(kernel_dll, "WakeAllConditionVariable"); - cond_signal = (void (WINAPI*)(pthread_cond_t *)) - GetProcAddress(kernel_dll, "WakeConditionVariable"); - cond_wait = (BOOL (WINAPI*)(pthread_cond_t *, pthread_mutex_t *, DWORD)) - GetProcAddress(kernel_dll, "SleepConditionVariableCS"); - initonce_begin = (BOOL (WINAPI*)(pthread_once_t *, DWORD, BOOL *, void **)) - GetProcAddress(kernel_dll, "InitOnceBeginInitialize"); - initonce_complete = (BOOL (WINAPI*)(pthread_once_t *, DWORD, void *)) - GetProcAddress(kernel_dll, "InitOnceComplete"); -#endif - -} - #endif /* COMPAT_W32PTHREADS_H */ diff --git a/compat/windows/makedef b/compat/windows/makedef index fcaf108332c42..7258b94a92034 100755 --- a/compat/windows/makedef +++ b/compat/windows/makedef @@ -45,7 +45,11 @@ libname=$(mktemp -u "library").lib trap 'rm -f -- $libname' EXIT -lib -out:${libname} $@ >/dev/null +if [ -n "$AR" ]; then + $AR rcs ${libname} $@ >/dev/null +else + lib -out:${libname} $@ >/dev/null +fi if [ $? != 0 ]; then echo "Could not create temporary library." >&2 exit 1 @@ -54,23 +58,7 @@ fi IFS=' ' -# Determine if we're building for x86 or x86_64 and -# set the symbol prefix accordingly. -prefix="" -arch=$(dumpbin -headers ${libname} | - tr '\t' ' ' | - grep '^ \+.\+machine \+(.\+)' | - head -1 | - sed -e 's/^ \{1,\}.\{1,\} \{1,\}machine \{1,\}(\(...\)).*/\1/') - -if [ "${arch}" = "x86" ]; then - prefix="_" -else - if [ "${arch}" != "ARM" ] && [ "${arch}" != "x64" ]; then - echo "Unknown machine type." >&2 - exit 1 - fi -fi +prefix="$EXTERN_PREFIX" started=0 regex="none" @@ -112,7 +100,19 @@ for line in $(cat ${vscript} | tr '\t' ' '); do ' done -dump=$(dumpbin -linkermember:1 ${libname}) +if [ -n "$NM" ]; then + # Use eval, since NM="nm -g" + dump=$(eval "$NM --defined-only -g ${libname}" | + grep -v : | + grep -v ^$ | + cut -d' ' -f3 | + sed -e "s/^${prefix}//") +else + dump=$(dumpbin -linkermember:1 ${libname} | + sed -e '/public symbols/,$!d' -e '/^ \{1,\}Summary/,$d' -e "s/ \{1,\}${prefix}/ /" -e 's/ \{1,\}/ /g' | + tail -n +2 | + cut -d' ' -f3) +fi rm ${libname} @@ -121,9 +121,6 @@ list="" for exp in ${regex}; do list="${list}"' '$(echo "${dump}" | - sed -e '/public symbols/,$!d' -e '/^ \{1,\}Summary/,$d' -e "s/ \{1,\}${prefix}/ /" -e 's/ \{1,\}/ /g' | - tail -n +2 | - cut -d' ' -f3 | grep "^${exp}" | sed -e 's/^/ /') done diff --git a/configure b/configure index e2ef54fb3b213..dee507cb6ae29 100755 --- a/configure +++ b/configure @@ -116,7 +116,6 @@ Program options: --disable-ffmpeg disable ffmpeg build --disable-ffplay disable ffplay build --disable-ffprobe disable ffprobe build - --disable-ffserver disable ffserver build Documentation options: --disable-doc do not build documentation @@ -133,7 +132,7 @@ Component options: --disable-swscale disable libswscale build --disable-postproc disable libpostproc build --disable-avfilter disable libavfilter build - --enable-avresample enable libavresample build [no] + --enable-avresample enable libavresample build (deprecated) [no] --disable-pthreads disable pthreads [autodetect] --disable-w32threads disable Win32 threads [autodetect] --disable-os2threads disable OS/2 threads [autodetect] @@ -185,7 +184,6 @@ Individual component options: --enable-filter=NAME enable filter NAME --disable-filter=NAME disable filter NAME --disable-filters disable all filters - --disable-v4l2_m2m disable V4L2 mem2mem code [autodetect] External library support: @@ -215,11 +213,11 @@ External library support: --enable-gmp enable gmp, needed for rtmp(t)e support if openssl or librtmp is not used [no] --enable-gnutls enable gnutls, needed for https support - if openssl is not used [no] + if openssl or libtls is not used [no] --disable-iconv disable iconv [autodetect] - --disable-jack disable libjack support [autodetect] --enable-jni enable JNI support [no] --enable-ladspa enable LADSPA audio filtering [no] + --enable-libaom enable AV1 video encoding/decoding via libaom [no] --enable-libass enable libass subtitles rendering, needed for subtitles and ass filter [no] --enable-libbluray enable BluRay reading using libbluray [no] @@ -227,6 +225,7 @@ External library support: --enable-libcaca enable textual display using libcaca [no] --enable-libcelt enable CELT decoding via libcelt [no] --enable-libcdio enable audio CD grabbing with libcdio [no] + --enable-libcodec2 enable codec2 en/decoding using libcodec2 [no] --enable-libdc1394 enable IIDC-1394 grabbing using libdc1394 and libraw1394 [no] --enable-libfdk-aac enable AAC de/encoding via libfdk-aac [no] @@ -238,6 +237,7 @@ External library support: --enable-libgsm enable GSM de/encoding via libgsm [no] --enable-libiec61883 enable iec61883 via libiec61883 [no] --enable-libilbc enable iLBC de/encoding via libilbc [no] + --enable-libjack enable JACK audio sound server [no] --enable-libkvazaar enable HEVC encoding via libkvazaar [no] --enable-libmodplug enable ModPlug via libmodplug [no] --enable-libmp3lame enable MP3 encoding via libmp3lame [no] @@ -257,9 +257,12 @@ External library support: --enable-libsnappy enable Snappy compression, needed for hap encoding [no] --enable-libsoxr enable Include libsoxr resampling [no] --enable-libspeex enable Speex de/encoding via libspeex [no] + --enable-libsrt enable Haivision SRT protocol via libsrt [no] --enable-libssh enable SFTP protocol via libssh [no] --enable-libtesseract enable Tesseract, needed for ocr filter [no] --enable-libtheora enable Theora encoding via libtheora [no] + --enable-libtls enable LibreSSL (via libtls), needed for https support + if openssl or gnutls is not used [no] --enable-libtwolame enable MP2 encoding via libtwolame [no] --enable-libv4l2 enable libv4l2/v4l-utils [no] --enable-libvidstab enable video stabilization using vid.stab [no] @@ -283,16 +286,17 @@ External library support: --enable-libzimg enable z.lib, needed for zscale filter [no] --enable-libzmq enable message passing via libzmq [no] --enable-libzvbi enable teletext support via libzvbi [no] + --enable-lv2 enable LV2 audio filtering [no] --disable-lzma disable lzma [autodetect] --enable-decklink enable Blackmagic DeckLink I/O support [no] --enable-libndi_newtek enable Newteck NDI I/O support [no] --enable-mediacodec enable Android MediaCodec support [no] --enable-libmysofa enable libmysofa, needed for sofalizer filter [no] --enable-openal enable OpenAL 1.1 capture support [no] - --enable-opencl enable OpenCL code + --enable-opencl enable OpenCL processing [no] --enable-opengl enable OpenGL rendering [no] --enable-openssl enable openssl, needed for https support - if gnutls is not used [no] + if gnutls or libtls is not used [no] --disable-sndio disable sndio support [autodetect] --disable-schannel disable SChannel SSP, needed for TLS support on Windows if openssl and gnutls are not used [autodetect] @@ -303,22 +307,24 @@ External library support: --disable-zlib disable zlib [autodetect] The following libraries provide various hardware acceleration features: + --disable-amf disable AMF video encoding code [autodetect] --disable-audiotoolbox disable Apple AudioToolbox code [autodetect] - --disable-cuda disable dynamically linked Nvidia CUDA code [autodetect] --enable-cuda-sdk enable CUDA features that require the CUDA SDK [no] --disable-cuvid disable Nvidia CUVID support [autodetect] --disable-d3d11va disable Microsoft Direct3D 11 video acceleration code [autodetect] --disable-dxva2 disable Microsoft DirectX 9 video acceleration code [autodetect] + --disable-ffnvcodec disable dynamically linked Nvidia code [autodetect] --enable-libdrm enable DRM code (Linux) [no] --enable-libmfx enable Intel MediaSDK (AKA Quick Sync Video) code via libmfx [no] --enable-libnpp enable Nvidia Performance Primitives-based code [no] --enable-mmal enable Broadcom Multi-Media Abstraction Layer (Raspberry Pi) via MMAL [no] + --disable-nvdec disable Nvidia video decoding acceleration (via hwaccel) [autodetect] --disable-nvenc disable Nvidia video encoding code [autodetect] --enable-omx enable OpenMAX IL code [no] --enable-omx-rpi enable OpenMAX IL code for Raspberry Pi [no] --enable-rkmpp enable Rockchip Media Process Platform code [no] + --disable-v4l2-m2m disable V4L2 mem2mem code [autodetect] --disable-vaapi disable Video Acceleration API (mainly Unix/Intel) code [autodetect] - --disable-vda disable Apple Video Decode Acceleration code [autodetect] --disable-vdpau disable Nvidia Video Decode and Presentation API for Unix code [autodetect] --disable-videotoolbox disable VideoToolbox code [autodetect] @@ -337,6 +343,10 @@ Toolchain options: --target-samples=DIR path to samples directory on target --tempprefix=PATH force fixed dir/prefix instead of mktemp for checks --toolchain=NAME set tool defaults according to NAME + (gcc-asan, clang-asan, gcc-msan, clang-msan, + gcc-tsan, clang-tsan, gcc-usan, clang-usan, + valgrind-massif, valgrind-memcheck, + msvc, icl, gcov, llvm-cov, hardened) --nm=NM use nm tool NM [$nm_default] --ar=AR use archive tool AR [$ar_default] --as=AS use assembler AS [$as_default] @@ -366,7 +376,7 @@ Toolchain options: --extra-objcflags=FLAGS add FLAGS to OBJCFLAGS [$CFLAGS] --extra-ldflags=ELDFLAGS add ELDFLAGS to LDFLAGS [$LDFLAGS] --extra-ldexeflags=ELDFLAGS add ELDFLAGS to LDEXEFLAGS [$LDEXEFLAGS] - --extra-ldlibflags=ELDFLAGS add ELDFLAGS to LDLIBFLAGS [$LDLIBFLAGS] + --extra-ldsoflags=ELDFLAGS add ELDFLAGS to LDSOFLAGS [$LDSOFLAGS] --extra-libs=ELIBS add ELIBS [$ELIBS] --extra-version=STRING version string suffix [] --optflags=OPTFLAGS override optimization-related compiler flags @@ -407,6 +417,7 @@ Optimization options (experts only): --disable-fma3 disable FMA3 optimizations --disable-fma4 disable FMA4 optimizations --disable-avx2 disable AVX2 optimizations + --disable-avx512 disable AVX-512 optimizations --disable-aesni disable AESNI optimizations --disable-armv5te disable armv5te optimizations --disable-armv6 disable armv6 optimizations @@ -462,7 +473,6 @@ EOF exit 0 } -quotes='""' if test -t 1 && which tput >/dev/null 2>&1; then ncolors=$(tput colors) if test -n "$ncolors" && test $ncolors -ge 8; then @@ -541,7 +551,7 @@ filter(){ pat=$1 shift for v; do - eval "case $v in $pat) printf '%s ' $v ;; esac" + eval "case '$v' in $pat) printf '%s ' '$v' ;; esac" done } @@ -549,7 +559,7 @@ filter_out(){ pat=$1 shift for v; do - eval "case $v in $pat) ;; *) printf '%s ' $v ;; esac" + eval "case '$v' in $pat) ;; *) printf '%s ' '$v' ;; esac" done } @@ -565,6 +575,12 @@ add_suffix(){ for v; do echo ${v}${suffix}; done } +remove_suffix(){ + suffix=$1 + shift + for v; do echo ${v%$suffix}; done +} + set_all(){ value=$1 shift @@ -585,13 +601,13 @@ sanitize_var_name(){ echo $@ | sed 's/[^A-Za-z0-9_]/_/g' } -set_safe(){ +set_sanitized(){ var=$1 shift eval $(sanitize_var_name "$var")='$*' } -get_safe(){ +get_sanitized(){ eval echo \$$(sanitize_var_name "$1") } @@ -637,15 +653,15 @@ disable_weak(){ set_weak no $* } -enable_safe(){ +enable_sanitized(){ for var; do - enable $(echo "$var" | sed 's/[^A-Za-z0-9_]/_/g') + enable $(sanitize_var_name $var) done } -disable_safe(){ +disable_sanitized(){ for var; do - disable $(echo "$var" | sed 's/[^A-Za-z0-9_]/_/g') + disable $(sanitize_var_name $var) done } @@ -678,17 +694,17 @@ enable_deep_weak(){ } requested(){ - test "${1#!}" = "$1" && op='=' || op=!= + test "${1#!}" = "$1" && op="=" || op="!=" eval test "x\$${1#!}_requested" $op "xyes" } enabled(){ - test "${1#!}" = "$1" && op='=' || op=!= + test "${1#!}" = "$1" && op="=" || op="!=" eval test "x\$${1#!}" $op "xyes" } disabled(){ - test "${1#!}" = "$1" && op='=' || op=!= + test "${1#!}" = "$1" && op="=" || op="!=" eval test "x\$${1#!}" $op "xno" } @@ -732,12 +748,11 @@ is_in(){ return 1 } -do_check_deps(){ +check_deps(){ for cfg; do enabled ${cfg}_checking && die "Circular dependency for $cfg." disabled ${cfg}_checking && continue enable ${cfg}_checking - append allopts $cfg eval dep_all="\$${cfg}_deps" eval dep_any="\$${cfg}_deps_any" @@ -748,7 +763,7 @@ do_check_deps(){ eval dep_ifn="\$${cfg}_if_any" pushvar cfg dep_all dep_any dep_con dep_sel dep_sgs dep_ifa dep_ifn - do_check_deps $dep_all $dep_any $dep_con $dep_sel $dep_sgs $dep_ifa $dep_ifn + check_deps $dep_all $dep_any $dep_con $dep_sel $dep_sgs $dep_ifa $dep_ifn popvar cfg dep_all dep_any dep_con dep_sel dep_sgs dep_ifa dep_ifn [ -n "$dep_ifa" ] && { enabled_all $dep_ifa && enable_weak $cfg; } @@ -758,24 +773,15 @@ do_check_deps(){ disabled_all $dep_con || { disable $cfg && requested $cfg && die "ERROR: $cfg requested, but some conflicting dependencies are unsatisfied: $dep_con"; } disabled_any $dep_sel && { disable $cfg && requested $cfg && die "ERROR: $cfg requested, but some selected dependency is unsatisfied: $dep_sel"; } - if enabled $cfg; then - enable_deep $dep_sel - enable_deep_weak $dep_sgs - fi - - disable ${cfg}_checking - done -} + enabled $cfg && enable_deep_weak $dep_sel $dep_sgs -check_deps(){ - unset allopts - - do_check_deps "$@" + for dep in $dep_all $dep_any $dep_sel $dep_sgs; do + # filter out library deps, these do not belong in extralibs + is_in $dep $LIBRARY_LIST && continue + enabled $dep && eval append ${cfg}_extralibs ${dep}_extralibs + done - for cfg in $allopts; do - enabled $cfg || continue - eval dep_extralibs="\$${cfg}_extralibs" - test -n "$dep_extralibs" && add_extralibs $dep_extralibs + disable ${cfg}_checking done } @@ -839,6 +845,15 @@ unique(){ eval "$var=\"${uniq_list}\"" } +resolve(){ + var=$1 + tmpvar= + for entry in $(eval echo \$$var); do + tmpvar="$tmpvar $(eval echo \$${entry})" + done + eval "$var=\"${tmpvar}\"" +} + add_cppflags(){ append CPPFLAGS "$@" } @@ -871,8 +886,8 @@ add_ldexeflags(){ append LDEXEFLAGS $($ldflags_filter "$@") } -add_ldlibflags(){ - append LDLIBFLAGS $($ldflags_filter "$@") +add_ldsoflags(){ + append LDSOFLAGS $($ldflags_filter "$@") } add_stripflags(){ @@ -901,13 +916,13 @@ add_compat(){ map 'add_cppflags -D$v' "$@" } -check_cmd(){ +test_cmd(){ log "$@" "$@" >> $logfile 2>&1 } -check_stat(){ - log check_stat "$@" +test_stat(){ + log test_stat "$@" stat "$1" >> $logfile 2>&1 } @@ -919,43 +934,74 @@ cc_e(){ eval printf '%s\\n' $CC_E } -check_cc(){ - log check_cc "$@" +test_cc(){ + log test_cc "$@" cat > $TMPC log_file $TMPC - check_cmd $cc $CPPFLAGS $CFLAGS "$@" $CC_C $(cc_o $TMPO) $TMPC + test_cmd $cc $CPPFLAGS $CFLAGS "$@" $CC_C $(cc_o $TMPO) $TMPC } -check_cxx(){ - log check_cxx "$@" +test_cxx(){ + log test_cxx "$@" cat > $TMPCPP log_file $TMPCPP - check_cmd $cxx $CPPFLAGS $CFLAGS $CXXFLAGS "$@" $CXX_C -o $TMPO $TMPCPP + test_cmd $cxx $CPPFLAGS $CFLAGS $CXXFLAGS "$@" $CXX_C -o $TMPO $TMPCPP } -check_objcc(){ - log check_objcc "$@" +test_objcc(){ + log test_objcc "$@" cat > $TMPM log_file $TMPM - check_cmd $objcc -Werror=missing-prototypes $CPPFLAGS $CFLAGS $OBJCFLAGS "$@" $OBJCC_C $(cc_o $TMPO) $TMPM + test_cmd $objcc -Werror=missing-prototypes $CPPFLAGS $CFLAGS $OBJCFLAGS "$@" $OBJCC_C $(cc_o $TMPO) $TMPM } -check_cpp(){ - log check_cpp "$@" +test_cpp(){ + log test_cpp "$@" cat > $TMPC log_file $TMPC - check_cmd $cc $CPPFLAGS $CFLAGS "$@" $(cc_e $TMPO) $TMPC + test_cmd $cc $CPPFLAGS $CFLAGS "$@" $(cc_e $TMPO) $TMPC } as_o(){ eval printf '%s\\n' $AS_O } -check_as(){ - log check_as "$@" +test_as(){ + log test_as "$@" cat > $TMPS log_file $TMPS - check_cmd $as $CPPFLAGS $ASFLAGS "$@" $AS_C $(as_o $TMPO) $TMPS + test_cmd $as $CPPFLAGS $ASFLAGS "$@" $AS_C $(as_o $TMPO) $TMPS +} + +x86asm_o(){ + eval printf '%s\\n' $X86ASM_O +} + +test_x86asm(){ + log test_x86asm "$@" + echo "$1" > $TMPASM + log_file $TMPASM + shift + test_cmd $x86asmexe $X86ASMFLAGS -Werror "$@" $(x86asm_o $TMPO) $TMPASM +} + +check_cmd(){ + log check_cmd "$@" + cmd=$1 + disabled $cmd && return + disable $cmd + test_cmd $@ && enable $cmd +} + +check_as(){ + log check_as "$@" + name=$1 + code=$2 + shift 2 + disable $name + test_as $@ < $TMPS - log_file $TMPS - shift 1 - check_cmd $x86asmexe $X86ASMFLAGS -Werror "$@" -o $TMPO $TMPS + name=$1 + shift + disable $name + test_x86asm "$@" && enable $name } ld_o(){ eval printf '%s\\n' $LD_O } -check_ld(){ - log check_ld "$@" +test_ld(){ + log test_ld "$@" type=$1 shift 1 flags=$(filter_out '-l*|*.so' $@) libs=$(filter '-l*|*.so' $@) - check_$type $($cflags_filter $flags) || return + test_$type $($cflags_filter $flags) || return flags=$($ldflags_filter $flags) libs=$($ldflags_filter $libs) - check_cmd $ld $LDFLAGS $LDEXEFLAGS $flags $(ld_o $TMPE) $TMPO $libs $extralibs + test_cmd $ld $LDFLAGS $LDEXEFLAGS $flags $(ld_o $TMPE) $TMPO $libs $extralibs +} + +check_ld(){ + log check_ld "$@" + type=$1 + name=$2 + shift 2 + disable $name + test_ld $type $@ && enable $name } print_include(){ @@ -1025,8 +1080,8 @@ print_include(){ echo "#include <$hdr>" } -check_code(){ - log check_code "$@" +test_code(){ + log test_code "$@" check=$1 headers=$2 code=$3 @@ -1036,12 +1091,12 @@ check_code(){ print_include $hdr done echo "int main(void) { $code; return 0; }" - } | check_$check "$@" + } | test_$check "$@" } check_cppflags(){ log check_cppflags "$@" - check_cpp "$@" < EOF } @@ -1049,7 +1104,7 @@ EOF test_cflags(){ log test_cflags "$@" set -- $($cflags_filter "$@") - check_cc "$@" < -int x; -EOF + disable_sanitized $headers + { + for hdr in $headers; do + print_include $hdr + done + echo "int x;" + } | test_cpp "$@" && enable_sanitized $headers } check_header_objcc(){ @@ -1122,11 +1180,11 @@ check_header_objcc(){ rm -f -- "$TMPO" header=$1 shift - disable_safe $header + disable_sanitized $header { echo "#include <$header>" echo "int main(void) { return 0; }" - } | check_objcc && check_stat "$TMPO" && enable_safe $header + } | test_objcc && test_stat "$TMPO" && enable_sanitized $header } check_apple_framework(){ @@ -1135,7 +1193,8 @@ check_apple_framework(){ name="$(tolower $framework)" header="${framework}/${framework}.h" disable $name - check_header_objcc $header && enable $name && add_extralibs "-framework $framework" + check_header_objcc $header && + enable $name && eval ${name}_extralibs='"-framework $framework"' } check_func(){ @@ -1143,7 +1202,7 @@ check_func(){ func=$1 shift disable $func - check_ld "cc" "$@" < #include float foo(complex float f, complex float g) { return $func($args); } @@ -1171,7 +1230,7 @@ check_mathfunc(){ shift 2 test $narg = 2 && args="f, g" || args="f" disable $func - check_ld "cc" "$@" < float foo(float f, float g) { return $func($args); } int main(void){ return (int) foo; } @@ -1197,7 +1256,7 @@ check_func_headers(){ echo " ret |= ((intptr_t)check_$func) & 0xFFFF;" done echo "return ret; }" - } | check_ld "cc" "$@" && enable $funcs && enable_safe $headers + } | test_ld "cc" "$@" && enable $funcs && enable_sanitized $headers } check_class_headers_cpp(){ @@ -1216,15 +1275,15 @@ check_class_headers_cpp(){ i=$(expr $i + 1) done echo "return 0; }" - } | check_ld "cxx" "$@" && enable $funcs && enable_safe $headers + } | test_ld "cxx" "$@" && enable $funcs && enable_sanitized $headers } -check_cpp_condition(){ - log check_cpp_condition "$@" +test_cpp_condition(){ + log test_cpp_condition "$@" header=$1 condition=$2 shift 2 - check_cpp "$@" < #if !($condition) #error "unsatisfied condition: $condition" @@ -1232,6 +1291,14 @@ check_cpp_condition(){ EOF } +check_cpp_condition(){ + log check_cpp_condition "$@" + name=$1 + shift 1 + disable $name + test_cpp_condition "$@" && enable $name +} + test_cflags_cc(){ log test_cflags_cc "$@" flags=$1 @@ -1239,7 +1306,7 @@ test_cflags_cc(){ condition=$3 shift 3 set -- $($cflags_filter "$flags") - check_cc "$@" < #if !($condition) #error "unsatisfied condition: $condition" @@ -1255,19 +1322,22 @@ check_lib(){ shift 3 disable $name check_func_headers "$headers" "$funcs" "$@" && - enable $name && add_extralibs "$@" + enable $name && eval ${name}_extralibs="\$@" } check_lib_cpp(){ log check_lib_cpp "$@" - headers="$1" - classes="$2" - shift 2 - check_class_headers_cpp "$headers" "$classes" "$@" && add_extralibs "$@" + name="$1" + headers="$2" + classes="$3" + shift 3 + disable $name + check_class_headers_cpp "$headers" "$classes" "$@" && + enable $name && eval ${name}_extralibs="\$@" } -check_pkg_config(){ - log check_pkg_config "$@" +test_pkg_config(){ + log test_pkg_config "$@" name="$1" pkg_version="$2" pkg="${2%% *}" @@ -1275,17 +1345,24 @@ check_pkg_config(){ funcs="$4" shift 4 disable $name - check_cmd $pkg_config --exists --print-errors $pkg_version || return + test_cmd $pkg_config --exists --print-errors $pkg_version || return pkg_cflags=$($pkg_config --cflags $pkg_config_flags $pkg) pkg_libs=$($pkg_config --libs $pkg_config_flags $pkg) check_func_headers "$headers" "$funcs" $pkg_cflags $pkg_libs "$@" && enable $name && - set_safe "${pkg}_cflags" $pkg_cflags && - set_safe "${pkg}_extralibs" $pkg_libs + set_sanitized "${name}_cflags" $pkg_cflags && + set_sanitized "${name}_extralibs" $pkg_libs } -check_exec(){ - check_ld "cc" "$@" && { enabled cross_compile || $TMPE >> $logfile 2>&1; } +check_pkg_config(){ + log check_pkg_config "$@" + name="$1" + test_pkg_config "$@" && + eval add_cflags \$${name}_cflags +} + +test_exec(){ + test_ld "cc" "$@" && { enabled cross_compile || $TMPE >> $logfile 2>&1; } } check_exec_crash(){ @@ -1298,7 +1375,7 @@ check_exec_crash(){ # can redirect the "Terminated" message from the shell. SIGBUS # is not defined by standard C so it is used conditionally. - (check_exec "$@") >> $logfile 2>&1 <> $logfile 2>&1 < static void sighandler(int sig){ raise(SIGTERM); @@ -1324,8 +1401,8 @@ check_type(){ headers=$1 type=$2 shift 2 - disable_safe "$type" - check_code cc "$headers" "$type v" "$@" && enable_safe "$type" + disable_sanitized "$type" + test_code cc "$headers" "$type v" "$@" && enable_sanitized "$type" } check_struct(){ @@ -1334,9 +1411,9 @@ check_struct(){ struct=$2 member=$3 shift 3 - disable_safe "${struct}_${member}" - check_code cc "$headers" "const void *p = &(($struct *)0)->$member" "$@" && - enable_safe "${struct}_${member}" + disable_sanitized "${struct}_${member}" + test_code cc "$headers" "const void *p = &(($struct *)0)->$member" "$@" && + enable_sanitized "${struct}_${member}" } check_builtin(){ @@ -1346,7 +1423,7 @@ check_builtin(){ builtin=$3 shift 3 disable "$name" - check_code ld "$headers" "$builtin" "cc" "$@" && enable "$name" + test_code ld "$headers" "$builtin" "cc" "$@" && enable "$name" } check_compile_assert(){ @@ -1356,17 +1433,30 @@ check_compile_assert(){ condition=$3 shift 3 disable "$name" - check_code cc "$headers" "char c[2 * !!($condition) - 1]" "$@" && enable "$name" + test_code cc "$headers" "char c[2 * !!($condition) - 1]" "$@" && enable "$name" +} + +check_cc(){ + log check_cc "$@" + name=$1 + shift + disable "$name" + test_code cc "$@" && enable "$name" } require(){ log require "$@" name_version="$1" name="${1%% *}" - headers="$2" - func="$3" - shift 3 - check_lib $name "$headers" $func "$@" || die "ERROR: $name_version not found" + shift + check_lib $name "$@" || die "ERROR: $name_version not found" +} + +require_cc(){ + log require_cc "$@" + name="$1" + shift + test_code cc "$@" || die "ERROR: $name failed" } require_cpp(){ @@ -1378,32 +1468,21 @@ require_cpp(){ } require_header(){ - log require "$@" - header="$1" - shift - check_header "$header" "$@" || die "ERROR: $header header not found" + log require_header "$@" + headers="$1" + check_header "$@" || die "ERROR: $headers not found" } require_cpp_condition(){ - log require "$@" - header="$1" + log require_cpp_condition "$@" condition="$2" - shift 2 - check_cpp_condition "$header" "$condition" "$@" || die "ERROR: $condition not satisfied" -} - -use_pkg_config(){ - log use_pkg_config "$@" - pkg="${2%% *}" - check_pkg_config "$@" || return 1 - add_cflags $(get_safe "${pkg}_cflags") - add_extralibs $(get_safe "${pkg}_extralibs") + test_cpp_condition "$@" || die "ERROR: $condition not satisfied" } require_pkg_config(){ log require_pkg_config "$@" pkg_version="$2" - use_pkg_config "$@" || die "ERROR: $pkg_version not found using pkg-config$pkg_config_fail_message" + check_pkg_config "$@" || die "ERROR: $pkg_version not found using pkg-config$pkg_config_fail_message" } hostcc_e(){ @@ -1414,23 +1493,23 @@ hostcc_o(){ eval printf '%s\\n' $HOSTCC_O } -check_host_cc(){ - log check_host_cc "$@" +test_host_cc(){ + log test_host_cc "$@" cat > $TMPC log_file $TMPC - check_cmd $host_cc $host_cflags "$@" $HOSTCC_C $(hostcc_o $TMPO) $TMPC + test_cmd $host_cc $host_cflags "$@" $HOSTCC_C $(hostcc_o $TMPO) $TMPC } -check_host_cpp(){ - log check_host_cpp "$@" +test_host_cpp(){ + log test_host_cpp "$@" cat > $TMPC log_file $TMPC - check_cmd $host_cc $host_cppflags $host_cflags "$@" $(hostcc_e $TMPO) $TMPC + test_cmd $host_cc $host_cppflags $host_cflags "$@" $(hostcc_e $TMPO) $TMPC } check_host_cppflags(){ log check_host_cppflags "$@" - check_host_cpp "$@" < EOF } @@ -1438,17 +1517,17 @@ EOF check_host_cflags(){ log check_host_cflags "$@" set -- $($host_cflags_filter "$@") - check_host_cc "$@" < #if !($condition) #error "unsatisfied condition: $condition" @@ -1456,6 +1535,14 @@ check_host_cpp_condition(){ EOF } +check_host_cpp_condition(){ + log check_host_cpp_condition "$@" + name=$1 + shift 1 + disable $name + test_host_cpp_condition "$@" && enable $name +} + cp_if_changed(){ cmp -s "$1" "$2" && { test "$quiet" != "yes" && echo "$2 is unchanged"; } && return mkdir -p "$(dirname $2)" @@ -1488,17 +1575,11 @@ AVFORMAT_COMPONENTS=" protocols " -AVRESAMPLE_COMPONENTS="" - -AVUTIL_COMPONENTS="" - COMPONENT_LIST=" $AVCODEC_COMPONENTS $AVDEVICE_COMPONENTS $AVFILTER_COMPONENTS $AVFORMAT_COMPONENTS - $AVRESAMPLE_COMPONENTS - $AVUTIL_COMPONENTS " EXAMPLE_LIST=" @@ -1523,6 +1604,8 @@ EXAMPLE_LIST=" scaling_video_example transcode_aac_example transcoding_example + vaapi_encode_example + vaapi_transcode_example " EXTERNAL_AUTODETECT_LIBRARY_LIST=" @@ -1532,7 +1615,6 @@ EXTERNAL_AUTODETECT_LIBRARY_LIST=" bzlib coreimage iconv - jack libxcb libxcb_shm libxcb_shape @@ -1563,12 +1645,14 @@ EXTERNAL_LIBRARY_NONFREE_LIST=" libndi_newtek libfdk_aac openssl + libtls " EXTERNAL_LIBRARY_VERSION3_LIST=" gmp libopencore_amrnb libopencore_amrwb + libvmaf libvo_amrwbenc rkmpp " @@ -1578,7 +1662,6 @@ EXTERNAL_LIBRARY_GPLV3_LIST=" " EXTERNAL_LIBRARY_LIST=" - $EXTERNAL_AUTODETECT_LIBRARY_LIST $EXTERNAL_LIBRARY_GPL_LIST $EXTERNAL_LIBRARY_NONFREE_LIST $EXTERNAL_LIBRARY_VERSION3_LIST @@ -1588,11 +1671,13 @@ EXTERNAL_LIBRARY_LIST=" gnutls jni ladspa + libaom libass libbluray libbs2b libcaca libcelt + libcodec2 libdc1394 libdrm libflite @@ -1603,6 +1688,7 @@ EXTERNAL_LIBRARY_LIST=" libgsm libiec61883 libilbc + libjack libkvazaar libmodplug libmp3lame @@ -1620,12 +1706,12 @@ EXTERNAL_LIBRARY_LIST=" libsnappy libsoxr libspeex + libsrt libssh libtesseract libtheora libtwolame libv4l2 - libvmaf libvorbis libvpx libwavpack @@ -1634,39 +1720,47 @@ EXTERNAL_LIBRARY_LIST=" libzimg libzmq libzvbi + lv2 mediacodec openal - opencl opengl " HWACCEL_AUTODETECT_LIBRARY_LIST=" + amf audiotoolbox crystalhd cuda cuvid d3d11va dxva2 + ffnvcodec + nvdec nvenc vaapi - vda vdpau videotoolbox v4l2_m2m xvmc " +# catchall list of things that require external libs to link +EXTRALIBS_LIST=" + cpu_init + cws2fws +" + HWACCEL_LIBRARY_NONFREE_LIST=" cuda_sdk libnpp " HWACCEL_LIBRARY_LIST=" - $HWACCEL_AUTODETECT_LIBRARY_LIST $HWACCEL_LIBRARY_NONFREE_LIST libmfx mmal omx + opencl " DOCUMENT_LIST=" @@ -1711,7 +1805,6 @@ LICENSE_LIST=" PROGRAM_LIST=" ffplay ffprobe - ffserver ffmpeg " @@ -1735,7 +1828,9 @@ CONFIG_LIST=" $DOCUMENT_LIST $EXAMPLE_LIST $EXTERNAL_LIBRARY_LIST + $EXTERNAL_AUTODETECT_LIBRARY_LIST $HWACCEL_LIBRARY_LIST + $HWACCEL_AUTODETECT_LIBRARY_LIST $FEATURE_LIST $LICENSE_LIST $LIBRARY_LIST @@ -1834,6 +1929,7 @@ ARCH_EXT_LIST_X86_SIMD=" amd3dnowext avx avx2 + avx512 fma3 fma4 mmx @@ -1875,11 +1971,10 @@ ARCH_FEATURES=" fast_64bit fast_clz fast_cmov - local_aligned_8 - local_aligned_16 - local_aligned_32 + local_aligned simd_align_16 simd_align_32 + simd_align_64 " BUILTIN_LIST=" @@ -1888,7 +1983,6 @@ BUILTIN_LIST=" MemoryBarrier mm_empty rdtsc - sarestart sem_timedwait sync_val_compare_and_swap " @@ -1904,13 +1998,11 @@ HAVE_LIST_PUB=" " HEADERS_LIST=" - altivec_h arpa_inet_h asm_types_h cdio_paranoia_h cdio_paranoia_paranoia_h cuda_h - d3d11_h dispatch_dispatch_h dev_bktr_ioctl_bt848_h dev_bktr_ioctl_meteor_h @@ -1919,27 +2011,18 @@ HEADERS_LIST=" dev_video_meteor_ioctl_meteor_h direct_h dirent_h - dlfcn_h dxgidebug_h dxva_h ES2_gl_h gsm_h io_h - mach_mach_time_h + linux_perf_event_h machine_ioctl_bt848_h machine_ioctl_meteor_h malloc_h opencv2_core_core_c_h - openjpeg_2_3_openjpeg_h - openjpeg_2_2_openjpeg_h - openjpeg_2_1_openjpeg_h - openjpeg_2_0_openjpeg_h - openjpeg_1_5_openjpeg_h OpenGL_gl3_h poll_h - soundcard_h - stdatomic_h - sys_mman_h sys_param_h sys_resource_h sys_select_h @@ -1996,6 +2079,16 @@ MATH_FUNCS=" truncf " +SYSTEM_FEATURES=" + dos_paths + libc_msvcrt + MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS + section_data_rel_ro + threads + uwp + winrt +" + SYSTEM_FUNCS=" access aligned_malloc @@ -2003,11 +2096,7 @@ SYSTEM_FUNCS=" clock_gettime closesocket CommandLineToArgvW - CoTaskMemFree - CryptGenRandom fcntl - flt_lim - fork getaddrinfo gethrtime getopt @@ -2022,9 +2111,7 @@ SYSTEM_FUNCS=" gmtime_r inet_aton isatty - jack_port_get_latency_range kbhit - LoadLibrary localtime_r lstat lzo1x_999_compress @@ -2039,6 +2126,7 @@ SYSTEM_FUNCS=" posix_memalign pthread_cancel sched_getaffinity + SecItemImport SetConsoleTextAttribute SetConsoleCtrlHandler setmode @@ -2053,14 +2141,20 @@ SYSTEM_FUNCS=" wglGetProcAddress " +SYSTEM_LIBRARIES=" + bcrypt + vaapi_drm + vaapi_x11 + vdpau_x11 +" + TOOLCHAIN_FEATURES=" + as_arch_directive as_dn_directive as_fpu_directive as_func as_object_arch asm_mod_q - attribute_may_alias - attribute_packed blocks_extension ebp_available ebx_available @@ -2080,7 +2174,6 @@ TOOLCHAIN_FEATURES=" " TYPES_LIST=" - CONDITION_VARIABLE_Ptr kCMVideoCodecType_HEVC socklen_t struct_addrinfo @@ -2103,7 +2196,6 @@ HAVE_LIST=" $(add_suffix _external $ARCH_EXT_LIST) $(add_suffix _inline $ARCH_EXT_LIST) $ARCH_FEATURES - $ATOMICS_LIST $BUILTIN_LIST $COMPLEX_FUNCS $HAVE_LIST_CMDLINE @@ -2111,37 +2203,39 @@ HAVE_LIST=" $HEADERS_LIST $INTRINSICS_LIST $MATH_FUNCS + $SYSTEM_FEATURES $SYSTEM_FUNCS + $SYSTEM_LIBRARIES $THREADS_LIST $TOOLCHAIN_FEATURES $TYPES_LIST - atomics_native - dos_paths - libc_msvcrt makeinfo makeinfo_html - MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS + opencl_d3d11 + opencl_drm_arm + opencl_drm_beignet + opencl_dxva2 + opencl_vaapi_beignet + opencl_vaapi_intel_media perl pod2man - section_data_rel_ro texi2html - threads - uwp - vaapi_drm - vaapi_x11 - vdpau_x11 - winrt " # options emitted with CONFIG_ prefix but not available on the command line CONFIG_EXTRA=" aandcttables ac3dsp + adts_header audio_frame_queue audiodsp blockdsp bswapdsp cabac + cbs + cbs_h264 + cbs_h265 + cbs_mpeg2 dirac_parse dvprofile exif @@ -2192,6 +2286,7 @@ CONFIG_EXTRA=" qsv qsvdec qsvenc + qsvvpp rangecoder riffdec riffenc @@ -2277,6 +2372,7 @@ CMDLINE_SET=" malloc_prefix nm optflags + nvcc nvccflags pkg_config pkg_config_flags @@ -2321,25 +2417,25 @@ setend_deps="arm" map 'eval ${v}_inline_deps=inline_asm' $ARCH_EXT_LIST_ARM +altivec_deps="ppc" +dcbzl_deps="ppc" +ldbrx_deps="ppc" +ppc4xx_deps="ppc" +vsx_deps="altivec" +power8_deps="vsx" + loongson2_deps="mips" loongson3_deps="mips" -mipsfpu_deps="mips" -mipsdsp_deps="mips" -mipsdspr2_deps="mips" mips32r2_deps="mips" mips32r5_deps="mips" mips32r6_deps="mips" mips64r2_deps="mips" mips64r6_deps="mips" -msa_deps="mipsfpu" +mipsfpu_deps="mips" +mipsdsp_deps="mips" +mipsdspr2_deps="mips" mmi_deps="mips" - -altivec_deps="ppc" -dcbzl_deps="ppc" -ldbrx_deps="ppc" -ppc4xx_deps="ppc" -vsx_deps="altivec" -power8_deps="vsx" +msa_deps="mipsfpu" cpunop_deps="i686" x86_64_select="i686" @@ -2362,9 +2458,10 @@ xop_deps="avx" fma3_deps="avx" fma4_deps="avx" avx2_deps="avx" +avx512_deps="avx2" mmx_external_deps="x86asm" -mmx_inline_deps="inline_asm" +mmx_inline_deps="inline_asm x86" mmx_suggest="mmx_external mmx_inline" for ext in $(filter_out mmx $ARCH_EXT_LIST_X86_SIMD); do @@ -2380,8 +2477,10 @@ fast_clz_if_any="aarch64 alpha avr32 mips ppc x86" fast_unaligned_if_any="aarch64 ppc x86" simd_align_16_if_any="altivec neon sse" simd_align_32_if_any="avx" +simd_align_64_if_any="avx512" # system capabilities +linux_perf_deps="linux_perf_event_h" symver_if_any="symver_asm_label symver_gnu_asm" valgrind_backtrace_conflict="optimizations" valgrind_backtrace_deps="valgrind_valgrind_h" @@ -2395,11 +2494,16 @@ w32threads_deps="atomics_native" threads_if_any="$THREADS_LIST" # subsystems +cbs_h264_select="cbs golomb" +cbs_h265_select="cbs golomb" +cbs_mpeg2_select="cbs" dct_select="rdft" dirac_parse_select="golomb" error_resilience_select="me_cmp" -faandct_deps="faan fdctdsp" -faanidct_deps="faan idctdsp" +faandct_deps="faan" +faandct_select="fdctdsp" +faanidct_deps="faan" +faanidct_select="idctdsp" h264dsp_select="startcode" hevcparse_select="golomb" frame_thread_encoder_deps="encoders threads" @@ -2416,8 +2520,8 @@ vc1dsp_select="h264chroma qpeldsp startcode" rdft_select="fft" # decoders / encoders -aac_decoder_select="mdct15 mdct sinewin" -aac_fixed_decoder_select="mdct sinewin" +aac_decoder_select="adts_header mdct15 mdct sinewin" +aac_fixed_decoder_select="adts_header mdct sinewin" aac_encoder_select="audio_frame_queue iirfilter lpc mdct sinewin" aac_latm_decoder_select="aac_decoder aac_latm_parser" ac3_decoder_select="ac3_parser ac3dsp bswapdsp fmtconvert mdct" @@ -2434,8 +2538,13 @@ amrwb_decoder_select="lsp" amv_decoder_select="sp5x_decoder exif" amv_encoder_select="aandcttables jpegtables mpegvideoenc" ape_decoder_select="bswapdsp llauddsp" -apng_decoder_select="zlib" -apng_encoder_select="llvidencdsp zlib" +apng_decoder_deps="zlib" +apng_encoder_deps="zlib" +apng_encoder_select="llvidencdsp" +aptx_decoder_select="audio_frame_queue" +aptx_encoder_select="audio_frame_queue" +aptx_hd_decoder_select="audio_frame_queue" +aptx_hd_encoder_select="audio_frame_queue" asv1_decoder_select="blockdsp bswapdsp idctdsp" asv1_encoder_select="bswapdsp fdctdsp pixblockdsp" asv2_decoder_select="blockdsp bswapdsp idctdsp" @@ -2462,14 +2571,14 @@ dnxhd_encoder_select="aandcttables blockdsp fdctdsp idctdsp mpegvideoenc pixbloc dolby_e_decoder_select="mdct" dvvideo_decoder_select="dvprofile idctdsp" dvvideo_encoder_select="dvprofile fdctdsp me_cmp pixblockdsp" -dxa_decoder_select="zlib" +dxa_decoder_deps="zlib" dxv_decoder_select="lzf texturedsp" eac3_decoder_select="ac3_decoder" eac3_encoder_select="ac3_encoder" eamad_decoder_select="aandcttables blockdsp bswapdsp idctdsp mpegvideo" eatgq_decoder_select="aandcttables" eatqi_decoder_select="aandcttables blockdsp bswapdsp idctdsp" -exr_decoder_select="zlib" +exr_decoder_deps="zlib" ffv1_decoder_select="rangecoder" ffv1_encoder_select="rangecoder" ffvhuff_decoder_select="huffyuv_decoder" @@ -2477,15 +2586,16 @@ ffvhuff_encoder_select="huffyuv_encoder" fic_decoder_select="golomb" flac_decoder_select="flacdsp" flac_encoder_select="bswapdsp flacdsp lpc" -flashsv2_decoder_select="zlib" -flashsv2_encoder_select="zlib" -flashsv_decoder_select="zlib" -flashsv_encoder_select="zlib" +flashsv2_decoder_deps="zlib" +flashsv2_encoder_deps="zlib" +flashsv_decoder_deps="zlib" +flashsv_encoder_deps="zlib" flv_decoder_select="h263_decoder" flv_encoder_select="h263_encoder" fourxm_decoder_select="blockdsp bswapdsp" fraps_decoder_select="bswapdsp huffman" -g2m_decoder_select="blockdsp idctdsp jpegtables zlib" +g2m_decoder_deps="zlib" +g2m_decoder_select="blockdsp idctdsp jpegtables" g729_decoder_select="audiodsp" h261_decoder_select="mpegvideo" h261_encoder_select="aandcttables mpegvideoenc" @@ -2513,6 +2623,7 @@ jv_decoder_select="blockdsp" lagarith_decoder_select="llviddsp" ljpeg_encoder_select="aandcttables idctdsp jpegtables mpegvideoenc" magicyuv_decoder_select="llviddsp" +magicyuv_encoder_select="llvidencdsp" mdec_decoder_select="blockdsp idctdsp mpegvideo" metasound_decoder_select="lsp mdct sinewin" mimic_decoder_select="blockdsp bswapdsp hpeldsp idctdsp" @@ -2534,8 +2645,6 @@ mp3on4_decoder_select="mpegaudio" mp3on4float_decoder_select="mpegaudio" mpc7_decoder_select="bswapdsp mpegaudiodsp" mpc8_decoder_select="mpegaudiodsp" -mpeg_xvmc_decoder_deps="X11_extensions_XvMClib_h" -mpeg_xvmc_decoder_select="mpeg2video_decoder" mpegvideo_decoder_select="mpegvideo" mpeg1video_decoder_select="mpegvideo" mpeg1video_encoder_select="aandcttables mpegvideoenc h263dsp" @@ -2544,7 +2653,7 @@ mpeg2video_encoder_select="aandcttables mpegvideoenc h263dsp" mpeg4_decoder_select="h263_decoder mpeg4video_parser" mpeg4_encoder_select="h263_encoder" msa1_decoder_select="mss34dsp" -mscc_decoder_select="zlib" +mscc_decoder_deps="zlib" msmpeg4v1_decoder_select="h263_decoder" msmpeg4v2_decoder_select="h263_decoder" msmpeg4v2_encoder_select="h263_encoder" @@ -2560,8 +2669,9 @@ on2avc_decoder_select="mdct" opus_decoder_deps="swresample" opus_decoder_select="mdct15" opus_encoder_select="audio_frame_queue mdct15" -png_decoder_select="zlib" -png_encoder_select="llvidencdsp zlib" +png_decoder_deps="zlib" +png_encoder_deps="zlib" +png_encoder_select="llvidencdsp" prores_decoder_select="blockdsp idctdsp" prores_encoder_select="fdctdsp" qcelp_decoder_select="lsp" @@ -2570,7 +2680,7 @@ ra_144_decoder_select="audiodsp" ra_144_encoder_select="audio_frame_queue lpc audiodsp" ralf_decoder_select="golomb" rawvideo_decoder_select="bswapdsp" -rscc_decoder_select="zlib" +rscc_decoder_deps="zlib" rtjpeg_decoder_select="me_cmp" rv10_decoder_select="h263_decoder" rv10_encoder_select="h263_encoder" @@ -2578,7 +2688,7 @@ rv20_decoder_select="h263_decoder" rv20_encoder_select="h263_encoder" rv30_decoder_select="golomb h264pred h264qpel mpegvideo rv34dsp" rv40_decoder_select="golomb h264pred h264qpel mpegvideo rv34dsp" -screenpresso_decoder_select="zlib" +screenpresso_decoder_deps="zlib" shorten_decoder_select="bswapdsp" sipr_decoder_select="lsp" snow_decoder_select="dwt h264qpel hpeldsp me_cmp rangecoder videodsp" @@ -2587,13 +2697,14 @@ sonic_decoder_select="golomb rangecoder" sonic_encoder_select="golomb rangecoder" sonic_ls_encoder_select="golomb rangecoder" sp5x_decoder_select="mjpeg_decoder" -srgc_decoder_select="zlib" +srgc_decoder_deps="zlib" svq1_decoder_select="hpeldsp" svq1_encoder_select="aandcttables hpeldsp me_cmp mpegvideoenc" svq3_decoder_select="golomb h264dsp h264parse h264pred hpeldsp tpeldsp videodsp" svq3_decoder_suggest="zlib" tak_decoder_select="audiodsp" -tdsc_decoder_select="zlib mjpeg_decoder" +tdsc_decoder_deps="zlib" +tdsc_decoder_select="mjpeg_decoder" theora_decoder_select="vp3_decoder" thp_decoder_select="mjpeg_decoder" tiff_decoder_suggest="zlib lzma" @@ -2602,18 +2713,16 @@ truehd_decoder_select="mlp_parser" truehd_encoder_select="lpc" truemotion2_decoder_select="bswapdsp" truespeech_decoder_select="bswapdsp" -tscc_decoder_select="zlib" +tscc_decoder_deps="zlib" twinvq_decoder_select="mdct lsp sinewin" txd_decoder_select="texturedsp" utvideo_decoder_select="bswapdsp llviddsp" utvideo_encoder_select="bswapdsp huffman llvidencdsp" vble_decoder_select="llviddsp" vc1_decoder_select="blockdsp h263_decoder h264qpel intrax8 mpegvideo vc1dsp" -vc1_qsv_decoder_deps="libmfx" -vc1_qsv_decoder_select="qsvdec vc1_qsv_hwaccel vc1_parser" vc1image_decoder_select="vc1_decoder" vorbis_decoder_select="mdct" -vorbis_encoder_select="mdct" +vorbis_encoder_select="audio_frame_queue mdct" vp3_decoder_select="hpeldsp vp3dsp videodsp" vp5_decoder_select="h264chroma hpeldsp videodsp vp3dsp vp56dsp" vp6_decoder_select="h264chroma hpeldsp huffman videodsp vp3dsp vp56dsp" @@ -2621,7 +2730,7 @@ vp6a_decoder_select="vp6_decoder" vp6f_decoder_select="vp6_decoder" vp7_decoder_select="h264pred videodsp vp8dsp" vp8_decoder_select="h264pred videodsp vp8dsp" -vp9_decoder_select="videodsp vp9_parser" +vp9_decoder_select="videodsp vp9_parser vp9_superframe_split_bsf" webp_decoder_select="vp8_decoder exif" wmalossless_decoder_select="llauddsp" wmapro_decoder_select="mdct sinewin wma_freqs" @@ -2638,23 +2747,20 @@ wmv3_decoder_select="vc1_decoder" wmv3image_decoder_select="wmv3_decoder" xma1_decoder_select="wmapro_decoder" xma2_decoder_select="wmapro_decoder" -zerocodec_decoder_select="zlib" -zlib_decoder_select="zlib" -zlib_encoder_select="zlib" -zmbv_decoder_select="zlib" -zmbv_encoder_select="zlib" +zerocodec_decoder_deps="zlib" +zlib_decoder_deps="zlib" +zlib_encoder_deps="zlib" +zmbv_decoder_deps="zlib" +zmbv_encoder_deps="zlib" # hardware accelerators crystalhd_deps="libcrystalhd_libcrystalhd_if_h" -cuda_deps_any="libdl LoadLibrary" -cuvid_deps="cuda" -d3d11va_deps="d3d11_h dxva_h ID3D11VideoDecoder ID3D11VideoContext" -dxva2_deps="dxva2api_h DXVA2_ConfigPictureDecode ole32" -dxva2_extralibs="-luser32" -vda_framework_deps="VideoDecodeAcceleration_VDADecoder_h blocks_extension" -vda_framework_extralibs="-framework VideoDecodeAcceleration" -vda_deps="vda_framework pthreads" -vda_extralibs="-framework CoreFoundation -framework QuartzCore" +cuda_deps="ffnvcodec" +cuvid_deps="ffnvcodec" +d3d11va_deps="dxva_h ID3D11VideoDecoder ID3D11VideoContext" +dxva2_deps="dxva2api_h DXVA2_ConfigPictureDecode ole32 user32" +ffnvcodec_deps_any="libdl LoadLibrary" +nvdec_deps="ffnvcodec" videotoolbox_hwaccel_deps="videotoolbox pthreads" videotoolbox_hwaccel_extralibs="-framework QuartzCore" xvmc_deps="X11_extensions_XvMClib_h" @@ -2663,67 +2769,56 @@ h263_vaapi_hwaccel_deps="vaapi" h263_vaapi_hwaccel_select="h263_decoder" h263_videotoolbox_hwaccel_deps="videotoolbox" h263_videotoolbox_hwaccel_select="h263_decoder" -h264_cuvid_hwaccel_deps="cuda cuvid" -h264_cuvid_hwaccel_select="h264_cuvid_decoder" h264_d3d11va_hwaccel_deps="d3d11va" h264_d3d11va_hwaccel_select="h264_decoder" h264_d3d11va2_hwaccel_deps="d3d11va" h264_d3d11va2_hwaccel_select="h264_decoder" h264_dxva2_hwaccel_deps="dxva2" h264_dxva2_hwaccel_select="h264_decoder" -h264_mediacodec_hwaccel_deps="mediacodec" -h264_mmal_hwaccel_deps="mmal" -h264_qsv_hwaccel_deps="libmfx" +h264_nvdec_hwaccel_deps="nvdec" +h264_nvdec_hwaccel_select="h264_decoder" h264_vaapi_hwaccel_deps="vaapi" h264_vaapi_hwaccel_select="h264_decoder" -h264_vda_hwaccel_deps="vda" -h264_vda_hwaccel_select="h264_decoder" -h264_vda_old_hwaccel_deps="vda" -h264_vda_old_hwaccel_select="h264_decoder" h264_vdpau_hwaccel_deps="vdpau" h264_vdpau_hwaccel_select="h264_decoder" h264_videotoolbox_hwaccel_deps="videotoolbox" h264_videotoolbox_hwaccel_select="h264_decoder" -hevc_cuvid_hwaccel_deps="cuda cuvid" -hevc_cuvid_hwaccel_select="hevc_cuvid_decoder" hevc_d3d11va_hwaccel_deps="d3d11va DXVA_PicParams_HEVC" hevc_d3d11va_hwaccel_select="hevc_decoder" -hevc_mediacodec_hwaccel_deps="mediacodec" hevc_d3d11va2_hwaccel_deps="d3d11va DXVA_PicParams_HEVC" hevc_d3d11va2_hwaccel_select="hevc_decoder" hevc_dxva2_hwaccel_deps="dxva2 DXVA_PicParams_HEVC" hevc_dxva2_hwaccel_select="hevc_decoder" -hevc_qsv_hwaccel_deps="libmfx" +hevc_nvdec_hwaccel_deps="nvdec" +hevc_nvdec_hwaccel_select="hevc_decoder" hevc_vaapi_hwaccel_deps="vaapi VAPictureParameterBufferHEVC" hevc_vaapi_hwaccel_select="hevc_decoder" hevc_vdpau_hwaccel_deps="vdpau VdpPictureInfoHEVC" hevc_vdpau_hwaccel_select="hevc_decoder" hevc_videotoolbox_hwaccel_deps="videotoolbox" hevc_videotoolbox_hwaccel_select="hevc_decoder" -mjpeg_cuvid_hwaccel_deps="cuda cuvid" -mjpeg_cuvid_hwaccel_select="mjpeg_cuvid_decoder" +mjpeg_nvdec_hwaccel_deps="nvdec" +mjpeg_nvdec_hwaccel_select="mjpeg_decoder" +mjpeg_vaapi_hwaccel_deps="vaapi" +mjpeg_vaapi_hwaccel_select="mjpeg_decoder" mpeg_xvmc_hwaccel_deps="xvmc" mpeg_xvmc_hwaccel_select="mpeg2video_decoder" -mpeg1_cuvid_hwaccel_deps="cuda cuvid" -mpeg1_cuvid_hwaccel_select="mpeg1_cuvid_decoder" +mpeg1_nvdec_hwaccel_deps="nvdec" +mpeg1_nvdec_hwaccel_select="mpeg1video_decoder" mpeg1_vdpau_hwaccel_deps="vdpau" mpeg1_vdpau_hwaccel_select="mpeg1video_decoder" mpeg1_videotoolbox_hwaccel_deps="videotoolbox" mpeg1_videotoolbox_hwaccel_select="mpeg1video_decoder" mpeg1_xvmc_hwaccel_deps="xvmc" mpeg1_xvmc_hwaccel_select="mpeg1video_decoder" -mpeg2_cuvid_hwaccel_deps="cuda cuvid" -mpeg2_cuvid_hwaccel_select="mpeg2_cuvid_decoder" mpeg2_d3d11va_hwaccel_deps="d3d11va" mpeg2_d3d11va_hwaccel_select="mpeg2video_decoder" mpeg2_d3d11va2_hwaccel_deps="d3d11va" mpeg2_d3d11va2_hwaccel_select="mpeg2video_decoder" mpeg2_dxva2_hwaccel_deps="dxva2" mpeg2_dxva2_hwaccel_select="mpeg2video_decoder" -mpeg2_mediacodec_hwaccel_deps="mediacodec" -mpeg2_mmal_hwaccel_deps="mmal" -mpeg2_qsv_hwaccel_deps="libmfx" -mpeg2_qsv_hwaccel_select="qsvdec_mpeg2" +mpeg2_nvdec_hwaccel_deps="nvdec" +mpeg2_nvdec_hwaccel_select="mpeg2video_decoder" mpeg2_vaapi_hwaccel_deps="vaapi" mpeg2_vaapi_hwaccel_select="mpeg2video_decoder" mpeg2_vdpau_hwaccel_deps="vdpau" @@ -2732,165 +2827,149 @@ mpeg2_videotoolbox_hwaccel_deps="videotoolbox" mpeg2_videotoolbox_hwaccel_select="mpeg2video_decoder" mpeg2_xvmc_hwaccel_deps="xvmc" mpeg2_xvmc_hwaccel_select="mpeg2video_decoder" -mpeg4_cuvid_hwaccel_deps="cuda cuvid" -mpeg4_cuvid_hwaccel_select="mpeg4_cuvid_decoder" -mpeg4_mediacodec_hwaccel_deps="mediacodec" -mpeg4_mmal_hwaccel_deps="mmal" +mpeg4_nvdec_hwaccel_deps="nvdec" +mpeg4_nvdec_hwaccel_select="mpeg4_decoder" mpeg4_vaapi_hwaccel_deps="vaapi" mpeg4_vaapi_hwaccel_select="mpeg4_decoder" mpeg4_vdpau_hwaccel_deps="vdpau" mpeg4_vdpau_hwaccel_select="mpeg4_decoder" mpeg4_videotoolbox_hwaccel_deps="videotoolbox" mpeg4_videotoolbox_hwaccel_select="mpeg4_decoder" -vc1_cuvid_hwaccel_deps="cuda cuvid" -vc1_cuvid_hwaccel_select="vc1_cuvid_decoder" vc1_d3d11va_hwaccel_deps="d3d11va" vc1_d3d11va_hwaccel_select="vc1_decoder" vc1_d3d11va2_hwaccel_deps="d3d11va" vc1_d3d11va2_hwaccel_select="vc1_decoder" vc1_dxva2_hwaccel_deps="dxva2" vc1_dxva2_hwaccel_select="vc1_decoder" -vc1_mmal_hwaccel_deps="mmal" -vc1_qsv_hwaccel_deps="libmfx" -vc1_qsv_hwaccel_select="qsvdec_vc1" +vc1_nvdec_hwaccel_deps="nvdec" +vc1_nvdec_hwaccel_select="vc1_decoder" vc1_vaapi_hwaccel_deps="vaapi" vc1_vaapi_hwaccel_select="vc1_decoder" vc1_vdpau_hwaccel_deps="vdpau" vc1_vdpau_hwaccel_select="vc1_decoder" -vp8_cuvid_hwaccel_deps="cuda cuvid" -vp8_cuvid_hwaccel_select="vp8_cuvid_decoder" -vp9_cuvid_hwaccel_deps="cuda cuvid" -vp9_cuvid_hwaccel_select="vp9_cuvid_decoder" -vp8_mediacodec_hwaccel_deps="mediacodec" -vp8_qsv_hwaccel_deps="libmfx" +vp8_nvdec_hwaccel_deps="nvdec" +vp8_nvdec_hwaccel_select="vp8_decoder" +vp8_vaapi_hwaccel_deps="vaapi VAPictureParameterBufferVP8" +vp8_vaapi_hwaccel_select="vp8_decoder" vp9_d3d11va_hwaccel_deps="d3d11va DXVA_PicParams_VP9" vp9_d3d11va_hwaccel_select="vp9_decoder" vp9_d3d11va2_hwaccel_deps="d3d11va DXVA_PicParams_VP9" vp9_d3d11va2_hwaccel_select="vp9_decoder" vp9_dxva2_hwaccel_deps="dxva2 DXVA_PicParams_VP9" vp9_dxva2_hwaccel_select="vp9_decoder" -vp9_mediacodec_hwaccel_deps="mediacodec" +vp9_nvdec_hwaccel_deps="nvdec" +vp9_nvdec_hwaccel_select="vp9_decoder" vp9_vaapi_hwaccel_deps="vaapi VADecPictureParameterBufferVP9_bit_depth" vp9_vaapi_hwaccel_select="vp9_decoder" wmv3_d3d11va_hwaccel_select="vc1_d3d11va_hwaccel" wmv3_d3d11va2_hwaccel_select="vc1_d3d11va2_hwaccel" wmv3_dxva2_hwaccel_select="vc1_dxva2_hwaccel" +wmv3_nvdec_hwaccel_select="vc1_nvdec_hwaccel" wmv3_vaapi_hwaccel_select="vc1_vaapi_hwaccel" wmv3_vdpau_hwaccel_select="vc1_vdpau_hwaccel" # hardware-accelerated codecs omx_deps="libdl pthreads" omx_rpi_select="omx" +qsv_deps="libmfx" qsvdec_select="qsv" qsvenc_select="qsv" +qsvvpp_select="qsv" vaapi_encode_deps="vaapi" v4l2_m2m_deps_any="linux_videodev2_h" -hwupload_cuda_filter_deps="cuda" -scale_npp_filter_deps="cuda libnpp" +hwupload_cuda_filter_deps="ffnvcodec" +scale_npp_filter_deps="ffnvcodec libnpp" scale_cuda_filter_deps="cuda_sdk" thumbnail_cuda_filter_deps="cuda_sdk" -nvenc_deps="cuda" +amf_deps_any="libdl LoadLibrary" +nvenc_deps="ffnvcodec" nvenc_deps_any="libdl LoadLibrary" nvenc_encoder_deps="nvenc" h263_v4l2m2m_decoder_deps="v4l2_m2m h263_v4l2_m2m" h263_v4l2m2m_encoder_deps="v4l2_m2m h263_v4l2_m2m" +h264_amf_encoder_deps="amf" h264_crystalhd_decoder_select="crystalhd h264_mp4toannexb_bsf h264_parser" -h264_cuvid_decoder_deps="cuda cuvid" +h264_cuvid_decoder_deps="cuvid" h264_cuvid_decoder_select="h264_mp4toannexb_bsf" h264_mediacodec_decoder_deps="mediacodec" h264_mediacodec_decoder_select="h264_mp4toannexb_bsf h264_parser" h264_mmal_decoder_deps="mmal" h264_nvenc_encoder_deps="nvenc" h264_omx_encoder_deps="omx" -h264_qsv_decoder_deps="libmfx" -h264_qsv_decoder_select="h264_mp4toannexb_bsf h264_parser qsvdec h264_qsv_hwaccel" -h264_qsv_encoder_deps="libmfx" +h264_qsv_decoder_select="h264_mp4toannexb_bsf h264_parser qsvdec" h264_qsv_encoder_select="qsvenc" h264_rkmpp_decoder_deps="rkmpp" h264_rkmpp_decoder_select="h264_mp4toannexb_bsf" h264_vaapi_encoder_deps="VAEncPictureParameterBufferH264" -h264_vaapi_encoder_select="vaapi_encode golomb" -h264_vda_decoder_deps="vda" -h264_vda_decoder_select="h264_decoder" -h264_vdpau_decoder_deps="vdpau" -h264_vdpau_decoder_select="h264_decoder" +h264_vaapi_encoder_select="cbs_h264 vaapi_encode" h264_v4l2m2m_decoder_deps="v4l2_m2m h264_v4l2_m2m" h264_v4l2m2m_encoder_deps="v4l2_m2m h264_v4l2_m2m" -hevc_cuvid_decoder_deps="cuda cuvid" +hevc_amf_encoder_deps="amf" +hevc_cuvid_decoder_deps="cuvid" hevc_cuvid_decoder_select="hevc_mp4toannexb_bsf" hevc_mediacodec_decoder_deps="mediacodec" hevc_mediacodec_decoder_select="hevc_mp4toannexb_bsf hevc_parser" hevc_nvenc_encoder_deps="nvenc" -hevc_qsv_decoder_deps="libmfx" -hevc_qsv_decoder_select="hevc_mp4toannexb_bsf hevc_parser qsvdec hevc_qsv_hwaccel" -hevc_qsv_encoder_deps="libmfx" +hevc_qsv_decoder_select="hevc_mp4toannexb_bsf hevc_parser qsvdec" hevc_qsv_encoder_select="hevcparse qsvenc" hevc_rkmpp_decoder_deps="rkmpp" hevc_rkmpp_decoder_select="hevc_mp4toannexb_bsf" hevc_vaapi_encoder_deps="VAEncPictureParameterBufferHEVC" -hevc_vaapi_encoder_select="vaapi_encode golomb" +hevc_vaapi_encoder_select="cbs_h265 vaapi_encode" hevc_v4l2m2m_decoder_deps="v4l2_m2m hevc_v4l2_m2m" hevc_v4l2m2m_encoder_deps="v4l2_m2m hevc_v4l2_m2m" -mjpeg_cuvid_decoder_deps="cuda cuvid" +mjpeg_cuvid_decoder_deps="cuvid" +mjpeg_qsv_encoder_deps="libmfx" +mjpeg_qsv_encoder_select="qsvenc" mjpeg_vaapi_encoder_deps="VAEncPictureParameterBufferJPEG" mjpeg_vaapi_encoder_select="vaapi_encode jpegtables" -mpeg1_cuvid_decoder_deps="cuda cuvid" -mpeg1_vdpau_decoder_deps="vdpau" -mpeg1_vdpau_decoder_select="mpeg1video_decoder" +mpeg1_cuvid_decoder_deps="cuvid" mpeg1_v4l2m2m_decoder_deps="v4l2_m2m mpeg1_v4l2_m2m" mpeg2_crystalhd_decoder_select="crystalhd" -mpeg2_cuvid_decoder_deps="cuda cuvid" +mpeg2_cuvid_decoder_deps="cuvid" mpeg2_mmal_decoder_deps="mmal" mpeg2_mediacodec_decoder_deps="mediacodec" -mpeg2_qsv_decoder_deps="libmfx" -mpeg2_qsv_decoder_select="qsvdec mpeg2_qsv_hwaccel" -mpeg2_qsv_encoder_deps="libmfx" +mpeg2_qsv_decoder_select="qsvdec mpegvideo_parser" mpeg2_qsv_encoder_select="qsvenc" mpeg2_vaapi_encoder_deps="VAEncPictureParameterBufferMPEG2" -mpeg2_vaapi_encoder_select="vaapi_encode" +mpeg2_vaapi_encoder_select="cbs_mpeg2 vaapi_encode" mpeg2_v4l2m2m_decoder_deps="v4l2_m2m mpeg2_v4l2_m2m" mpeg4_crystalhd_decoder_select="crystalhd" -mpeg4_cuvid_decoder_deps="cuda cuvid" +mpeg4_cuvid_decoder_deps="cuvid" mpeg4_mediacodec_decoder_deps="mediacodec" mpeg4_mmal_decoder_deps="mmal" mpeg4_omx_encoder_deps="omx" -mpeg4_vdpau_decoder_deps="vdpau" -mpeg4_vdpau_decoder_select="mpeg4_decoder" mpeg4_v4l2m2m_decoder_deps="v4l2_m2m mpeg4_v4l2_m2m" mpeg4_v4l2m2m_encoder_deps="v4l2_m2m mpeg4_v4l2_m2m" -mpeg_vdpau_decoder_deps="vdpau" -mpeg_vdpau_decoder_select="mpeg2video_decoder" msmpeg4_crystalhd_decoder_select="crystalhd" nvenc_h264_encoder_select="h264_nvenc_encoder" nvenc_hevc_encoder_select="hevc_nvenc_encoder" vc1_crystalhd_decoder_select="crystalhd" -vc1_cuvid_decoder_deps="cuda cuvid" +vc1_cuvid_decoder_deps="cuvid" vc1_mmal_decoder_deps="mmal" -vc1_vdpau_decoder_deps="vdpau" -vc1_vdpau_decoder_select="vc1_decoder" +vc1_qsv_decoder_select="qsvdec vc1_parser" vc1_v4l2m2m_decoder_deps="v4l2_m2m vc1_v4l2_m2m" -vp8_cuvid_decoder_deps="cuda cuvid" +vp8_cuvid_decoder_deps="cuvid" vp8_mediacodec_decoder_deps="mediacodec" -vp8_qsv_decoder_deps="libmfx" -vp8_qsv_decoder_select="qsvdec vp8_qsv_hwaccel vp8_parser" +vp8_qsv_decoder_select="qsvdec vp8_parser" vp8_rkmpp_decoder_deps="rkmpp" vp8_vaapi_encoder_deps="VAEncPictureParameterBufferVP8" vp8_vaapi_encoder_select="vaapi_encode" vp8_v4l2m2m_decoder_deps="v4l2_m2m vp8_v4l2_m2m" vp8_v4l2m2m_encoder_deps="v4l2_m2m vp8_v4l2_m2m" -vp9_cuvid_decoder_deps="cuda cuvid" +vp9_cuvid_decoder_deps="cuvid" vp9_mediacodec_decoder_deps="mediacodec" vp9_rkmpp_decoder_deps="rkmpp" vp9_vaapi_encoder_deps="VAEncPictureParameterBufferVP9" vp9_vaapi_encoder_select="vaapi_encode" vp9_v4l2m2m_decoder_deps="v4l2_m2m vp9_v4l2_m2m" wmv3_crystalhd_decoder_select="crystalhd" -wmv3_vdpau_decoder_select="vc1_vdpau_decoder" # parsers +aac_parser_select="adts_header" h264_parser_select="golomb h264dsp h264parse" hevc_parser_select="hevcparse" mpegaudio_parser_select="mpegaudioheader" @@ -2899,10 +2978,19 @@ mpeg4video_parser_select="h263dsp mpegvideo qpeldsp" vc1_parser_select="vc1dsp" # bitstream_filters +aac_adtstoasc_bsf_select="adts_header" +filter_units_bsf_select="cbs" +h264_metadata_bsf_deps="const_nan" +h264_metadata_bsf_select="cbs_h264" +h264_redundant_pps_bsf_select="cbs_h264" +hevc_metadata_bsf_select="cbs_h265" mjpeg2jpeg_bsf_select="jpegtables" +mpeg2_metadata_bsf_select="cbs_mpeg2" +trace_headers_bsf_select="cbs" # external libraries aac_at_decoder_deps="audiotoolbox" +aac_at_decoder_select="aac_adtstoasc_bsf" ac3_at_decoder_deps="audiotoolbox" ac3_at_decoder_select="ac3_parser" adpcm_ima_qt_at_decoder_deps="audiotoolbox" @@ -2938,7 +3026,13 @@ pcm_mulaw_at_encoder_select="audio_frame_queue" chromaprint_muxer_deps="chromaprint" h264_videotoolbox_encoder_deps="pthreads" h264_videotoolbox_encoder_select="videotoolbox_encoder" +hevc_videotoolbox_encoder_deps="pthreads" +hevc_videotoolbox_encoder_select="videotoolbox_encoder" +libaom_av1_decoder_deps="libaom" +libaom_av1_encoder_deps="libaom" libcelt_decoder_deps="libcelt" +libcodec2_decoder_deps="libcodec2" +libcodec2_encoder_deps="libcodec2" libfdk_aac_decoder_deps="libfdk_aac" libfdk_aac_encoder_deps="libfdk_aac" libfdk_aac_encoder_select="audio_frame_queue" @@ -2976,7 +3070,7 @@ libtheora_encoder_deps="libtheora" libtwolame_encoder_deps="libtwolame" libvo_amrwbenc_encoder_deps="libvo_amrwbenc" libvorbis_decoder_deps="libvorbis" -libvorbis_encoder_deps="libvorbis" +libvorbis_encoder_deps="libvorbis libvorbisenc" libvorbis_encoder_select="audio_frame_queue" libvpx_vp8_decoder_deps="libvpx" libvpx_vp8_encoder_deps="libvpx" @@ -2994,9 +3088,9 @@ libx265_encoder_deps="libx265" libxavs_encoder_deps="libxavs" libxvid_encoder_deps="libxvid" libzvbi_teletext_decoder_deps="libzvbi" -videotoolbox_extralibs="-framework CoreFoundation -framework VideoToolbox -framework CoreMedia -framework CoreVideo" +videotoolbox_suggest="coreservices" +videotoolbox_deps="corefoundation coremedia corevideo" videotoolbox_encoder_deps="videotoolbox VTCompressionSessionPrepareToEncodeFrames" -videotoolbox_encoder_suggest="vda_framework" # demuxers / muxers ac3_demuxer_select="ac3_parser" @@ -3023,6 +3117,7 @@ fifo_muxer_deps="threads" flac_demuxer_select="flac_parser" hds_muxer_select="flv_muxer" hls_muxer_select="mpegts_muxer" +hls_muxer_suggest="gcrypt openssl" image2_alias_pix_demuxer_select="image2_demuxer" image2_brender_pix_demuxer_select="image2_demuxer" ipod_muxer_select="mov_muxer" @@ -3059,7 +3154,8 @@ sap_demuxer_select="sdp_demuxer" sap_muxer_select="rtp_muxer rtp_protocol rtpenc_chain" sdp_demuxer_select="rtpdec" smoothstreaming_muxer_select="ismv_muxer" -spdif_muxer_select="aac_parser" +spdif_demuxer_select="adts_header" +spdif_muxer_select="adts_header" spx_muxer_select="ogg_muxer" swf_demuxer_suggest="zlib" tak_demuxer_select="tak_parser" @@ -3078,10 +3174,13 @@ xmv_demuxer_select="riffdec" xwma_demuxer_select="riffdec" # indevs / outdevs +android_camera_indev_deps="android camera2ndk mediandk pthreads" +android_camera_indev_extralibs="-landroid -lcamera2ndk -lmediandk" alsa_indev_deps="alsa" alsa_outdev_deps="alsa" -avfoundation_indev_deps="avfoundation pthreads" -avfoundation_indev_extralibs="-framework Foundation -framework CoreVideo -framework CoreMedia" +avfoundation_indev_deps="avfoundation corevideo coremedia pthreads" +avfoundation_indev_suggest="coregraphics applicationservices" +avfoundation_indev_extralibs="-framework Foundation" bktr_indev_deps_any="dev_bktr_ioctl_bt848_h machine_ioctl_bt848_h dev_video_bktr_ioctl_bt848_h dev_ic_bt8xx_h" caca_outdev_deps="libcaca" decklink_deps_any="libdl LoadLibrary" @@ -3089,9 +3188,9 @@ decklink_indev_deps="decklink threads" decklink_indev_extralibs="-lstdc++" decklink_outdev_deps="decklink threads" decklink_outdev_extralibs="-lstdc++" -libndi_newtek_indev_deps="libndi_newtek libdl" +libndi_newtek_indev_deps="libndi_newtek" libndi_newtek_indev_extralibs="-lndi" -libndi_newtek_outdev_deps="libndi_newtek libdl" +libndi_newtek_outdev_deps="libndi_newtek" libndi_newtek_outdev_extralibs="-lndi" dshow_indev_deps="IBaseFilter" dshow_indev_extralibs="-lpsapi -lole32 -lstrmiids -luuid -loleaut32 -lshlwapi" @@ -3101,26 +3200,28 @@ gdigrab_indev_deps="CreateDIBSection" gdigrab_indev_extralibs="-lgdi32" gdigrab_indev_select="bmp_decoder" iec61883_indev_deps="libiec61883" -jack_indev_deps="jack" +jack_indev_deps="libjack" jack_indev_deps_any="sem_timedwait dispatch_dispatch_h" kmsgrab_indev_deps="libdrm" lavfi_indev_deps="avfilter" libcdio_indev_deps="libcdio" libdc1394_indev_deps="libdc1394" -libv4l2_indev_deps="libv4l2" openal_indev_deps="openal" opengl_outdev_deps="opengl" -oss_indev_deps_any="soundcard_h sys_soundcard_h" -oss_outdev_deps_any="soundcard_h sys_soundcard_h" +oss_indev_deps_any="sys_soundcard_h" +oss_outdev_deps_any="sys_soundcard_h" pulse_indev_deps="libpulse" pulse_outdev_deps="libpulse" sdl2_outdev_deps="sdl2" sndio_indev_deps="sndio" sndio_outdev_deps="sndio" v4l2_indev_deps_any="linux_videodev2_h sys_videoio_h" +v4l2_indev_suggest="libv4l2" v4l2_outdev_deps_any="linux_videodev2_h sys_videoio_h" +v4l2_outdev_suggest="libv4l2" vfwcap_indev_deps="vfw32 vfwcap_defines" xcbgrab_indev_deps="libxcb" +xcbgrab_indev_suggest="libxcb_shm libxcb_shape libxcb_xfixes" xv_outdev_deps="X11_extensions_Xvlib_h XvGetPortAttribute" xv_outdev_extralibs="-lXv -lX11 -lXext" @@ -3135,8 +3236,11 @@ ffrtmphttp_protocol_select="http_protocol" ftp_protocol_select="tcp_protocol" gopher_protocol_select="network" http_protocol_select="tcp_protocol" +http_protocol_suggest="zlib" httpproxy_protocol_select="tcp_protocol" +httpproxy_protocol_suggest="zlib" https_protocol_select="tls_protocol" +https_protocol_suggest="zlib" icecast_protocol_select="http_protocol" librtmp_protocol_deps="librtmp" librtmpe_protocol_deps="librtmp" @@ -3145,32 +3249,34 @@ librtmpt_protocol_deps="librtmp" librtmpte_protocol_deps="librtmp" libsmbclient_protocol_deps="libsmbclient gplv3" libssh_protocol_deps="libssh" +libtls_conflict="openssl gnutls" mmsh_protocol_select="http_protocol" mmst_protocol_select="network" +libsrt_protocol_deps="libsrt" +libsrt_protocol_select="network" rtmp_protocol_conflict="librtmp_protocol" rtmp_protocol_select="tcp_protocol" +rtmp_protocol_suggest="zlib" rtmpe_protocol_select="ffrtmpcrypt_protocol" +rtmpe_protocol_suggest="zlib" rtmps_protocol_conflict="librtmp_protocol" rtmps_protocol_select="tls_protocol" +rtmps_protocol_suggest="zlib" rtmpt_protocol_select="ffrtmphttp_protocol" +rtmpt_protocol_suggest="zlib" rtmpte_protocol_select="ffrtmpcrypt_protocol ffrtmphttp_protocol" +rtmpte_protocol_suggest="zlib" rtmpts_protocol_select="ffrtmphttp_protocol https_protocol" +rtmpts_protocol_suggest="zlib" rtp_protocol_select="udp_protocol" +schannel_conflict="openssl gnutls libtls" sctp_protocol_deps="struct_sctp_event_subscribe struct_msghdr_msg_flags" sctp_protocol_select="network" +securetransport_conflict="openssl gnutls libtls" srtp_protocol_select="rtp_protocol srtp" tcp_protocol_select="network" -tls_gnutls_protocol_conflict="tls_schannel_protocol tls_securetransport_protocol" -tls_gnutls_protocol_deps="gnutls" -tls_gnutls_protocol_select="tcp_protocol" -tls_openssl_protocol_conflict="tls_schannel_protocol tls_securetransport_protocol tls_gnutls_protocol" -tls_openssl_protocol_deps="openssl" -tls_openssl_protocol_select="tcp_protocol" -tls_schannel_protocol_deps="schannel" -tls_schannel_protocol_select="tcp_protocol" -tls_securetransport_protocol_deps="securetransport" -tls_securetransport_protocol_select="tcp_protocol" -tls_protocol_deps_any="tls_schannel_protocol tls_securetransport_protocol tls_gnutls_protocol tls_openssl_protocol" +tls_protocol_deps_any="gnutls openssl schannel securetransport libtls" +tls_protocol_select="tcp_protocol" udp_protocol_select="network" udplite_protocol_select="network" unix_protocol_deps="sys_un_h" @@ -3186,22 +3292,30 @@ aresample_filter_deps="swresample" ass_filter_deps="libass" atempo_filter_deps="avcodec" atempo_filter_select="rdft" +avgblur_opencl_filter_deps="opencl" azmq_filter_deps="libzmq" blackframe_filter_deps="gpl" boxblur_filter_deps="gpl" bs2b_filter_deps="libbs2b" colormatrix_filter_deps="gpl" +convolution_opencl_filter_deps="opencl" +convolve_filter_deps="avcodec" +convolve_filter_select="fft" coreimage_filter_deps="coreimage appkit" coreimage_filter_extralibs="-framework OpenGL" coreimagesrc_filter_deps="coreimage appkit" coreimagesrc_filter_extralibs="-framework OpenGL" cover_rect_filter_deps="avcodec avformat gpl" cropdetect_filter_deps="gpl" +deconvolve_filter_deps="avcodec" +deconvolve_filter_select="fft" deinterlace_qsv_filter_deps="libmfx" deinterlace_vaapi_filter_deps="vaapi" delogo_filter_deps="gpl" +denoise_vaapi_filter_deps="vaapi VAProcPipelineParameterBuffer" deshake_filter_select="pixelutils" drawtext_filter_deps="libfreetype" +drawtext_filter_suggest="libfontconfig libfribidi" elbg_filter_deps="avcodec" eq_filter_deps="gpl" fftfilt_filter_deps="avcodec" @@ -3220,6 +3334,7 @@ hqdn3d_filter_deps="gpl" interlace_filter_deps="gpl" kerndeint_filter_deps="gpl" ladspa_filter_deps="ladspa libdl" +lv2_filter_deps="lv2" mcdeint_filter_deps="avcodec gpl" movie_filter_deps="avcodec avformat" mpdecimate_filter_deps="gpl" @@ -3229,12 +3344,18 @@ negate_filter_deps="lut_filter" nnedi_filter_deps="gpl" ocr_filter_deps="libtesseract" ocv_filter_deps="libopencv" +openclsrc_filter_deps="opencl" +overlay_opencl_filter_deps="opencl" +overlay_qsv_filter_deps="libmfx" +overlay_qsv_filter_select="qsvvpp" owdenoise_filter_deps="gpl" pan_filter_deps="swresample" perspective_filter_deps="gpl" phase_filter_deps="gpl" pp7_filter_deps="gpl" pp_filter_deps="gpl postproc" +procamp_vaapi_filter_deps="vaapi VAProcPipelineParameterBuffer" +program_opencl_filter_deps="opencl" pullup_filter_deps="gpl" removelogo_filter_deps="avcodec avformat swscale" repeatfields_filter_deps="gpl" @@ -3245,7 +3366,9 @@ scale2ref_filter_deps="swscale" scale_filter_deps="swscale" scale_qsv_filter_deps="libmfx" select_filter_select="pixelutils" +sharpness_vaapi_filter_deps="vaapi VAProcPipelineParameterBuffer" showcqt_filter_deps="avcodec avformat swscale" +showcqt_filter_suggest="libfontconfig libfreetype" showcqt_filter_select="fft" showfreqs_filter_deps="avcodec" showfreqs_filter_select="fft" @@ -3269,15 +3392,18 @@ tinterlace_filter_deps="gpl" tinterlace_merge_test_deps="tinterlace_filter" tinterlace_pad_test_deps="tinterlace_filter" tonemap_filter_deps="const_nan" +unsharp_opencl_filter_deps="opencl" uspp_filter_deps="gpl avcodec" vaguedenoiser_filter_deps="gpl" vidstabdetect_filter_deps="libvidstab" vidstabtransform_filter_deps="libvidstab" -libvmaf_filter_deps="libvmaf" +libvmaf_filter_deps="libvmaf pthreads" zmq_filter_deps="libzmq" zoompan_filter_deps="swscale" zscale_filter_deps="libzimg const_nan" scale_vaapi_filter_deps="vaapi VAProcPipelineParameterBuffer" +vpp_qsv_filter_deps="libmfx" +vpp_qsv_filter_select="qsvvpp" # examples avio_dir_cmd_deps="avformat avutil" @@ -3301,30 +3427,48 @@ resampling_audio_example_deps="avutil swresample" scaling_video_example_deps="avutil swscale" transcode_aac_example_deps="avcodec avformat swresample" transcoding_example_deps="avfilter avcodec avformat avutil" +vaapi_encode_example_deps="avcodec avutil h264_vaapi_encoder" +vaapi_transcode_example_deps="avcodec avformat avutil h264_vaapi_encoder" + +# EXTRALIBS_LIST +cpu_init_extralibs="pthreads_extralibs" +cws2fws_extralibs="zlib_extralibs" # libraries, in linking order avcodec_deps="avutil" +avcodec_suggest="libm" avcodec_select="null_bsf" avdevice_deps="avformat avcodec avutil" +avdevice_suggest="libm" avfilter_deps="avutil" +avfilter_suggest="libm" avformat_deps="avcodec avutil" -avformat_suggest="network" +avformat_suggest="libm network zlib" avresample_deps="avutil" +avresample_suggest="libm" +avutil_suggest="clock_gettime ffnvcodec libm libdrm libmfx opencl user32 vaapi videotoolbox corefoundation corevideo coremedia bcrypt" postproc_deps="avutil gpl" +postproc_suggest="libm" swresample_deps="avutil" +swresample_suggest="libm libsoxr" swscale_deps="avutil" +swscale_suggest="libm" + +avcodec_extralibs="pthreads_extralibs iconv_extralibs" +avfilter_extralibs="pthreads_extralibs" +avutil_extralibs="d3d11va_extralibs nanosleep_extralibs pthreads_extralibs vaapi_drm_extralibs vaapi_x11_extralibs vdpau_x11_extralibs" # programs ffmpeg_deps="avcodec avfilter avformat swresample" ffmpeg_select="aformat_filter anull_filter atrim_filter format_filter null_filter trim_filter" +ffmpeg_suggest="ole32 psapi shell32" ffplay_deps="avcodec avformat swscale swresample sdl2" -ffplay_extralibs='$sdl2_extralibs' ffplay_select="rdft crop_filter transpose_filter hflip_filter vflip_filter rotate_filter" +ffplay_suggest="shell32" ffprobe_deps="avcodec avformat" -ffserver_deps="avformat fork sarestart" -ffserver_select="ffm_muxer rtp_protocol rtsp_demuxer" +ffprobe_suggest="shell32" # documentation podpages_deps="perl" @@ -3360,6 +3504,7 @@ pkg_config_default=pkg-config ranlib_default="ranlib" strip_default="strip" version_script='--version-script' +objformat="elf32" x86asmexe_default="nasm" windres_default="windres" nvcc_default="nvcc" @@ -3401,6 +3546,12 @@ enable valgrind_backtrace sws_max_filter_size_default=256 set_default sws_max_filter_size +# internal components are enabled by default +enable $EXTRALIBS_LIST + +# Avoid external, non-system, libraries getting enabled by dependency resolution +disable $EXTERNAL_LIBRARY_LIST $HWACCEL_LIBRARY_LIST + # build settings SHFLAGS='-shared -Wl,-soname,$$(@F)' LIBPREF="lib" @@ -3474,47 +3625,66 @@ for v in "$@"; do FFMPEG_CONFIGURATION="${FFMPEG_CONFIGURATION# } ${l}${r}" done -find_things(){ +find_things_extern(){ thing=$1 pattern=$2 file=$source_path/$3 - sed -n "s/^[^#]*$pattern.*([^,]*, *\([^,]*\)\(,.*\)*).*/\1_$thing/p" "$file" + out=${4:-$thing} + sed -n "s/^[^#]*extern.*$pattern *ff_\([^ ]*\)_$thing;/\1_$out/p" "$file" } -ENCODER_LIST=$(find_things encoder ENC libavcodec/allcodecs.c) -DECODER_LIST=$(find_things decoder DEC libavcodec/allcodecs.c) -HWACCEL_LIST=$(find_things hwaccel HWACCEL libavcodec/allcodecs.c) -PARSER_LIST=$(find_things parser PARSER libavcodec/allcodecs.c) -MUXER_LIST=$(find_things muxer _MUX libavformat/allformats.c) -DEMUXER_LIST=$(find_things demuxer DEMUX libavformat/allformats.c) -OUTDEV_LIST=$(find_things outdev OUTDEV libavdevice/alldevices.c) -INDEV_LIST=$(find_things indev _IN libavdevice/alldevices.c) -FILTER_LIST=$(find_things filter FILTER libavfilter/allfilters.c) - -find_things_extern(){ - thing=$1 - pattern=$2 - file=$source_path/$3 - sed -n "s/^[^#]*extern.*$pattern *ff_\([^ ]*\)_$thing;/\1_$thing/p" "$file" +find_filters_extern(){ + file=$source_path/$1 + #sed -n "s/^extern AVFilter ff_\([avfsinkrc]\{2,5\}\)_\(\w\+\);/\2_filter/p" $file + sed -E -n "s/^extern AVFilter ff_([avfsinkrc]{2,5})_([a-zA-Z0-9_]+);/\2_filter/p" $file } +FILTER_LIST=$(find_filters_extern libavfilter/allfilters.c) +OUTDEV_LIST=$(find_things_extern muxer AVOutputFormat libavdevice/alldevices.c outdev) +INDEV_LIST=$(find_things_extern demuxer AVInputFormat libavdevice/alldevices.c indev) +MUXER_LIST=$(find_things_extern muxer AVOutputFormat libavformat/allformats.c) +DEMUXER_LIST=$(find_things_extern demuxer AVInputFormat libavformat/allformats.c) +ENCODER_LIST=$(find_things_extern encoder AVCodec libavcodec/allcodecs.c) +DECODER_LIST=$(find_things_extern decoder AVCodec libavcodec/allcodecs.c) +CODEC_LIST=" + $ENCODER_LIST + $DECODER_LIST +" +PARSER_LIST=$(find_things_extern parser AVCodecParser libavcodec/parser.c) BSF_LIST=$(find_things_extern bsf AVBitStreamFilter libavcodec/bitstream_filters.c) +HWACCEL_LIST=$(find_things_extern hwaccel AVHWAccel libavcodec/hwaccels.h) PROTOCOL_LIST=$(find_things_extern protocol URLProtocol libavformat/protocols.c) -ALL_COMPONENTS=" +AVCODEC_COMPONENTS_LIST=" $BSF_LIST $DECODER_LIST - $DEMUXER_LIST $ENCODER_LIST - $FILTER_LIST $HWACCEL_LIST + $PARSER_LIST +" + +AVDEVICE_COMPONENTS_LIST=" $INDEV_LIST - $MUXER_LIST $OUTDEV_LIST - $PARSER_LIST +" + +AVFILTER_COMPONENTS_LIST=" + $FILTER_LIST +" + +AVFORMAT_COMPONENTS_LIST=" + $DEMUXER_LIST + $MUXER_LIST $PROTOCOL_LIST " +ALL_COMPONENTS=" + $AVCODEC_COMPONENTS_LIST + $AVDEVICE_COMPONENTS_LIST + $AVFILTER_COMPONENTS_LIST + $AVFORMAT_COMPONENTS_LIST +" + for n in $COMPONENT_LIST; do v=$(toupper ${n%s})_LIST eval enable \$$v @@ -3571,8 +3741,13 @@ for opt do --extra-ldexeflags=*) add_ldexeflags $optval ;; + --extra-ldsoflags=*) + add_ldsoflags $optval + ;; --extra-ldlibflags=*) - add_ldlibflags $optval + warn "The --extra-ldlibflags option is only provided for compatibility and will be\n"\ + "removed in the future. Use --extra-ldsoflags instead." + add_ldsoflags $optval ;; --extra-libs=*) add_extralibs $optval @@ -3688,6 +3863,19 @@ enable_weak $HWACCEL_AUTODETECT_LIBRARY_LIST disabled logging && logfile=/dev/null +# command line configuration sanity checks + +# we need to build at least one lib type +if ! enabled_any static shared; then + cat </dev/null | head -n1) _cflags_speed='-O5' _cflags_size='-O5 -qcompact' - elif $_cc -V 2>/dev/null | grep -q Compaq; then - _type=ccc - _ident=$($_cc -V | head -n1 | cut -d' ' -f1-3) - _DEPFLAGS='-M' - _cflags_speed='-fast' - _cflags_size='-O1' - _flags_filter=ccc_flags elif $_cc --vsn 2>/dev/null | grep -Eq "ARM (C/C\+\+ )?Compiler"; then test -d "$sysroot" || die "No valid sysroot specified." _type=armcc @@ -4200,17 +4340,7 @@ probe_cc(){ _depflags='-MMD' _cflags_speed='-O3' _cflags_size='-Os' - elif $_cc -version 2>/dev/null | grep -Eq 'TMS470|TI ARM'; then - _type=tms470 - _ident=$($_cc -version | head -n1 | tr -s ' ') - _flags='--gcc --abi=eabi -me' - _cc_e='-ppl -fe=$@' - _cc_o='-fe=$@' - _depflags='-ppa -ppd=$(@:.o=.d)' - _cflags_speed='-O3 -mf=5' - _cflags_size='-O3 -mf=2' - _flags_filter=tms470_flags - elif $_cc -v 2>&1 | grep -q clang; then + elif $_cc -v 2>&1 | grep -q clang && ! $_cc -? > /dev/null 2>&1; then _type=clang _ident=$($_cc --version 2>/dev/null | head -n1) _depflags='-MMD -MF $(@:.o=.d) -MT $@' @@ -4239,14 +4369,6 @@ probe_cc(){ _cflags_speed='-O2' _cflags_size='-Os' _flags_filter='filter_out -Wdisabled-optimization|-Wtype-limits|-fno-signed-zeros' - elif $_cc -V 2>&1 | grep -q Portland; then - _type=pgi - _ident="PGI $($_cc -V 2>&1 | awk '/^pgcc/ { print $2; exit }')" - opt_common='-alias=ansi -Mdse -Mlre -Mpre' - _cflags_speed="-O3 -Mautoinline -Munroll=c:4 $opt_common" - _cflags_size="-O2 -Munroll=c:1 $opt_common" - _cflags_noopt="-O" - _flags_filter=pgi_flags elif $_cc 2>&1 | grep -q 'Microsoft.*ARM.*Assembler'; then _type=armasm _ident=$($_cc | head -n1) @@ -4289,9 +4411,9 @@ probe_cc(){ _flags_filter=msvc_flags _ld_lib='lib%.a' _ld_path='-libpath:' - elif $_cc -nologo- 2>&1 | grep -q Microsoft; then + elif $_cc -nologo- 2>&1 | grep -q Microsoft || { $_cc -v 2>&1 | grep -q clang && $_cc -? > /dev/null 2>&1; }; then _type=msvc - _ident=$($_cc 2>&1 | head -n1) + _ident=$($_cc 2>&1 | head -n1 | tr -d '\r') _DEPCMD='$(DEP$(1)) $(DEP$(1)FLAGS) $($(1)DEP_FLAGS) $< 2>&1 | awk '\''/including/ { sub(/^.*file: */, ""); gsub(/\\/, "/"); if (!match($$0, / /)) print "$@:", $$0 }'\'' > $(@:.o=.d)' _DEPFLAGS='$(CPPFLAGS) $(CFLAGS) -showIncludes -Zs' _cflags_speed="-O2" @@ -4395,12 +4517,6 @@ fi if $ar 2>&1 | grep -q Microsoft; then arflags="-nologo" ar_o='-out:$@' -elif $ar 2>&1 | grep -q 'Texas Instruments'; then - arflags="rq" - ar_o='$@' -elif $ar 2>&1 | grep -q 'Usage: ar.*-X.*any'; then - arflags='-Xany -r -c' - ar_o='$@' elif $ar 2>&1 | grep -q "\[D\] "; then arflags="rcD" ar_o='$@' @@ -4419,13 +4535,6 @@ if test -n "$sysroot"; then gcc|llvm_gcc|clang) add_cppflags --sysroot="$sysroot" add_ldflags --sysroot="$sysroot" -# On Darwin --sysroot may be ignored, -isysroot always affects headers and linking - add_cppflags -isysroot "$sysroot" - add_ldflags -isysroot "$sysroot" - ;; - tms470) - add_cppflags -I"$sysinclude" - add_ldflags --sysroot="$sysroot" ;; esac fi @@ -4529,7 +4638,7 @@ elif enabled alpha; then elif enabled arm; then check_arm_arch() { - check_cpp_condition stddef.h \ + test_cpp_condition stddef.h \ "defined __ARM_ARCH_${1}__ || defined __TARGET_ARCH_${2:-$1}" \ $cpuflags } @@ -4546,6 +4655,7 @@ elif enabled arm; then elif check_arm_arch 6J; then echo armv6j elif check_arm_arch 6K; then echo armv6k elif check_arm_arch 6Z; then echo armv6z + elif check_arm_arch 6KZ; then echo armv6zk elif check_arm_arch 6ZK; then echo armv6zk elif check_arm_arch 6T2; then echo armv6t2 elif check_arm_arch 7; then echo armv7 @@ -4637,7 +4747,7 @@ elif enabled mips; then loongson*) enable loongson2 enable loongson3 - enable local_aligned_8 local_aligned_16 local_aligned_32 + enable local_aligned enable simd_align_16 enable fast_64bit enable fast_clz @@ -4818,7 +4928,7 @@ if [ "$cpu" != generic ]; then fi # compiler sanity check -check_exec < 4'} + test_code cc "" "int test[2*($expr) - 1]" && subarch=$arch64 || subarch=$arch32 + enable $subarch } case "$arch" in aarch64|alpha|ia64) - spic=$shared + enabled shared && enable_weak pic ;; mips) check_64bit mips mips64 '_MIPS_SIM > 1' - spic=$shared + enabled shared && enable_weak pic ;; parisc) - check_64bit parisc parisc64 'sizeof(void *) > 4' - spic=$shared + check_64bit parisc parisc64 + enabled shared && enable_weak pic ;; ppc) - check_64bit ppc ppc64 'sizeof(void *) > 4' - spic=$shared + check_64bit ppc ppc64 + enabled shared && enable_weak pic ;; s390) - check_64bit s390 s390x 'sizeof(void *) > 4' - spic=$shared + check_64bit s390 s390x + enabled shared && enable_weak pic ;; sparc) - check_64bit sparc sparc64 'sizeof(void *) > 4' - spic=$shared + check_64bit sparc sparc64 + enabled shared && enable_weak pic ;; x86) - check_64bit x86_32 x86_64 'sizeof(void *) > 4' - # Treat x32 as x64 for now. Note it also needs spic=$shared - test "$subarch" = "x86_32" && check_cpp_condition stddef.h 'defined(__x86_64__)' && - subarch=x86_64 - if test "$subarch" = "x86_64"; then - spic=$shared + check_64bit x86_32 x86_64 + # Treat x32 as x64 for now. Note it also needs pic if shared + test "$subarch" = "x86_32" && test_cpp_condition stddef.h 'defined(__x86_64__)' && + subarch=x86_64 && enable x86_64 && disable x86_32 + if enabled x86_64; then + enabled shared && enable_weak pic + objformat=elf64 fi ;; - ppc) - check_cc < $$(@:$(SLIBSUF)=.def); lib.exe -nologo -machine:$(LIBTARGET) -def:$$(@:$(SLIBSUF)=.def) -out:$(SUBDIR)$(SLIBNAME:$(SLIBSUF)=.lib)' + if test_cmd lib.exe -list; then + SLIB_EXTRA_CMD=-'lib.exe -nologo -machine:$(LIBTARGET) -def:$$(@:$(SLIBSUF)=.def) -out:$(SUBDIR)$(SLIBNAME:$(SLIBSUF)=.lib)' if enabled x86_64; then LIBTARGET=x64 fi - elif check_cmd $dlltool --version; then - SLIB_EXTRA_CMD=-'sed -e "s/ @[^ ]*//" $$(@:$(SLIBSUF)=.orig.def) > $$(@:$(SLIBSUF)=.def); $(DLLTOOL) -m $(LIBTARGET) -d $$(@:$(SLIBSUF)=.def) -l $(SUBDIR)$(SLIBNAME:$(SLIBSUF)=.lib) -D $(SLIBNAME_WITH_MAJOR)' + else + SLIB_EXTRA_CMD=-'$(DLLTOOL) -m $(LIBTARGET) -d $$(@:$(SLIBSUF)=.def) -l $(SUBDIR)$(SLIBNAME:$(SLIBSUF)=.lib) -D $(SLIBNAME_WITH_MAJOR)' fi SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)' SLIB_INSTALL_LINKS= SLIB_INSTALL_EXTRA_SHLIB='$(SLIBNAME:$(SLIBSUF)=.lib)' SLIB_INSTALL_EXTRA_LIB='lib$(SLIBNAME:$(SLIBSUF)=.dll.a) $(SLIBNAME_WITH_MAJOR:$(SLIBSUF)=.def)' - SHFLAGS='-shared -Wl,--output-def,$$(@:$(SLIBSUF)=.orig.def) -Wl,--out-implib,$(SUBDIR)lib$(SLIBNAME:$(SLIBSUF)=.dll.a) -Wl,--enable-runtime-pseudo-reloc -Wl,--disable-auto-image-base' + SLIB_CREATE_DEF_CMD='EXTERN_PREFIX="$(EXTERN_PREFIX)" AR="$(AR_CMD)" NM="$(NM_CMD)" $(SRC_PATH)/compat/windows/makedef $(SUBDIR)lib$(NAME).ver $(OBJS) > $$(@:$(SLIBSUF)=.def)' + SHFLAGS='-shared -Wl,--out-implib,$(SUBDIR)lib$(SLIBNAME:$(SLIBSUF)=.dll.a) -Wl,--disable-auto-image-base $$(@:$(SLIBSUF)=.def)' enabled x86_64 && objformat="win64" || objformat="win32" + dlltool="${cross_prefix}dlltool" ranlib=: enable dos_paths check_ldflags -Wl,--nxcompat,--dynamicbase @@ -5049,7 +5161,7 @@ case $target_os in SLIBSUF=".dll" SLIBNAME_WITH_VERSION='$(SLIBPREF)$(FULLNAME)-$(LIBVERSION)$(SLIBSUF)' SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)-$(LIBMAJOR)$(SLIBSUF)' - SLIB_CREATE_DEF_CMD='$(SRC_PATH)/compat/windows/makedef $(SUBDIR)lib$(NAME).ver $(OBJS) > $$(@:$(SLIBSUF)=.def)' + SLIB_CREATE_DEF_CMD='EXTERN_PREFIX="$(EXTERN_PREFIX)" $(SRC_PATH)/compat/windows/makedef $(SUBDIR)lib$(NAME).ver $(OBJS) > $$(@:$(SLIBSUF)=.def)' SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)' SLIB_INSTALL_LINKS= SLIB_INSTALL_EXTRA_SHLIB='$(SLIBNAME:$(SLIBSUF)=.lib)' @@ -5072,7 +5184,7 @@ case $target_os in SHFLAGS='-shared -Wl,--out-implib,$(SUBDIR)lib$(FULLNAME).dll.a' enabled x86_64 && objformat="win64" || objformat="win32" enable dos_paths - enabled shared && ! enabled small && check_cmd $windres --version && enable gnu_windres + enabled shared && ! enabled small && test_cmd $windres --version && enable gnu_windres add_cppflags -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 ;; *-dos|freedos|opendos) @@ -5135,9 +5247,6 @@ case $target_os in -l:drtaeabi.dso -l:scppnwdl.dso -lsupc++ -lgcc \ -l:libc.dso -l:libm.dso -l:euser.dso -l:libcrt0.lib ;; - osf1) - add_cppflags -D_OSF_SOURCE -D_POSIX_PII -D_REENTRANT - ;; minix) ;; none) @@ -5173,42 +5282,44 @@ probe_libc(){ pfx=$1 pfx_no_=${pfx%_} # uclibc defines __GLIBC__, so it needs to be checked before glibc. - if check_${pfx}cpp_condition features.h "defined __UCLIBC__"; then + if test_${pfx}cpp_condition features.h "defined __UCLIBC__"; then eval ${pfx}libc_type=uclibc add_${pfx}cppflags -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 - elif check_${pfx}cpp_condition features.h "defined __GLIBC__"; then + elif test_${pfx}cpp_condition features.h "defined __GLIBC__"; then eval ${pfx}libc_type=glibc add_${pfx}cppflags -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 # MinGW headers can be installed on Cygwin, so check for newlib first. - elif check_${pfx}cpp_condition newlib.h "defined _NEWLIB_VERSION"; then + elif test_${pfx}cpp_condition newlib.h "defined _NEWLIB_VERSION"; then eval ${pfx}libc_type=newlib add_${pfx}cppflags -U__STRICT_ANSI__ -D_XOPEN_SOURCE=600 # MinGW64 is backwards compatible with MinGW32, so check for it first. - elif check_${pfx}cpp_condition _mingw.h "defined __MINGW64_VERSION_MAJOR"; then + elif test_${pfx}cpp_condition _mingw.h "defined __MINGW64_VERSION_MAJOR"; then eval ${pfx}libc_type=mingw64 - if check_${pfx}cpp_condition _mingw.h "__MINGW64_VERSION_MAJOR < 3"; then + if test_${pfx}cpp_condition _mingw.h "__MINGW64_VERSION_MAJOR < 3"; then add_compat msvcrt/snprintf.o add_cflags "-include $source_path/compat/msvcrt/snprintf.h" fi add_${pfx}cppflags -U__STRICT_ANSI__ -D__USE_MINGW_ANSI_STDIO=1 eval test \$${pfx_no_}cc_type = "gcc" && add_${pfx}cppflags -D__printf__=__gnu_printf__ - elif check_${pfx}cpp_condition _mingw.h "defined __MINGW_VERSION" || - check_${pfx}cpp_condition _mingw.h "defined __MINGW32_VERSION"; then + test_${pfx}cpp_condition windows.h "!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600" && + add_${pfx}cppflags -D_WIN32_WINNT=0x0600 + elif test_${pfx}cpp_condition _mingw.h "defined __MINGW_VERSION" || + test_${pfx}cpp_condition _mingw.h "defined __MINGW32_VERSION"; then eval ${pfx}libc_type=mingw32 - check_${pfx}cpp_condition _mingw.h "__MINGW32_MAJOR_VERSION > 3 || \ + test_${pfx}cpp_condition _mingw.h "__MINGW32_MAJOR_VERSION > 3 || \ (__MINGW32_MAJOR_VERSION == 3 && __MINGW32_MINOR_VERSION >= 15)" || die "ERROR: MinGW32 runtime version must be >= 3.15." add_${pfx}cppflags -U__STRICT_ANSI__ -D__USE_MINGW_ANSI_STDIO=1 - check_${pfx}cpp_condition _mingw.h "defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0502" || - add_${pfx}cppflags -D_WIN32_WINNT=0x0502 - check_${pfx}cpp_condition _mingw.h "__MSVCRT_VERSION__ < 0x0700" && + test_${pfx}cpp_condition _mingw.h "__MSVCRT_VERSION__ < 0x0700" && add_${pfx}cppflags -D__MSVCRT_VERSION__=0x0700 + test_${pfx}cpp_condition windows.h "!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600" && + add_${pfx}cppflags -D_WIN32_WINNT=0x0600 eval test \$${pfx_no_}cc_type = "gcc" && add_${pfx}cppflags -D__printf__=__gnu_printf__ - elif check_${pfx}cpp_condition crtversion.h "defined _VC_CRT_MAJOR_VERSION"; then + elif test_${pfx}cpp_condition crtversion.h "defined _VC_CRT_MAJOR_VERSION"; then eval ${pfx}libc_type=msvcrt - if check_${pfx}cpp_condition crtversion.h "_VC_CRT_MAJOR_VERSION < 14"; then + if test_${pfx}cpp_condition crtversion.h "_VC_CRT_MAJOR_VERSION < 14"; then if [ "$pfx" = host_ ]; then add_host_cppflags -Dsnprintf=_snprintf else @@ -5223,14 +5334,14 @@ probe_libc(){ # 0x601 by default unless something else is set by the user. # This can easily lead to us detecting functions only present # in such new versions and producing binaries requiring windows 7.0. - # Therefore explicitly set the default to XP unless the user has + # Therefore explicitly set the default to Vista unless the user has # set something else on the command line. # Don't do this if WINAPI_FAMILY is set and is set to a non-desktop # family. For these cases, configure is free to use any functions # found in the SDK headers by default. (Alternatively, we could force # _WIN32_WINNT to 0x0602 in that case.) - check_${pfx}cpp_condition stdlib.h "defined(_WIN32_WINNT)" || - { check_${pfx}cpp < #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) @@ -5242,29 +5353,28 @@ EOF check_func strtoll || add_cflags -Dstrtoll=_strtoi64 check_func strtoull || add_cflags -Dstrtoull=_strtoui64 fi - elif check_${pfx}cpp_condition stddef.h "defined __KLIBC__"; then + elif test_${pfx}cpp_condition stddef.h "defined __KLIBC__"; then eval ${pfx}libc_type=klibc - elif check_${pfx}cpp_condition sys/cdefs.h "defined __BIONIC__"; then + elif test_${pfx}cpp_condition sys/cdefs.h "defined __BIONIC__"; then eval ${pfx}libc_type=bionic - elif check_${pfx}cpp_condition sys/brand.h "defined LABELED_BRAND_NAME"; then + elif test_${pfx}cpp_condition sys/brand.h "defined LABELED_BRAND_NAME"; then eval ${pfx}libc_type=solaris add_${pfx}cppflags -D__EXTENSIONS__ -D_XOPEN_SOURCE=600 fi - check_${pfx}cc < void *v = localtime_r; EOF -test "$?" != 0 && check_${pfx}cc -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 < void *v = localtime_r; EOF + eval test -n "\${${pfx}libc_type}" && enable ${pfx}libc_${libc_type} } probe_libc -test -n "$libc_type" && enable libc_$libc_type probe_libc host_ -test -n "$host_libc_type" && enable host_libc_$host_libc_type # hacks for compiler/libc/os combinations @@ -5272,29 +5382,12 @@ case $libc_type in bionic) add_compat strtod.o strtod=avpriv_strtod ;; - glibc) - if enabled tms470; then - CPPFLAGS="-I${source_path}/compat/tms470 ${CPPFLAGS}" - add_cppflags -D__USER_LABEL_PREFIX__= - add_cppflags -D__builtin_memset=memset - add_cppflags -D__gnuc_va_list=va_list -D_VA_LIST_DEFINED - add_cflags -pds=48 # incompatible redefinition of macro - elif enabled ccc; then - add_ldflags -Wl,-z,now # calls to libots crash without this - fi - ;; esac check_compile_assert flt_lim "float.h limits.h" "DBL_MAX == (double)DBL_MAX" || add_cppflags '-I\$(SRC_PATH)/compat/float' -esc(){ - echo "$*" | sed 's/%/%25/g;s/:/%3a/g' -} - -echo "config:$arch:$subarch:$cpu:$target_os:$(esc $cc_ident):$(esc $FFMPEG_CONFIGURATION)" > ffbuild/config.fate - -check_cpp_condition stdlib.h "defined(__PIC__) || defined(__pic__) || defined(PIC)" && enable_weak pic +test_cpp_condition stdlib.h "defined(__PIC__) || defined(__pic__) || defined(PIC)" && enable_weak pic set_default libdir : ${shlibdir_default:="$libdir"} @@ -5303,17 +5396,6 @@ set_default libdir set_default $PATHS_LIST set_default nm -# we need to build at least one lib type -if ! enabled_any static shared; then - cat < -void foo(void) { struct { double d; } static const bar[] = { { NAN } }; } -EOF +check_cc const_nan math.h "struct { double d; } static const bar[] = { { NAN } }" if ! enabled ppc64 || enabled bigendian; then disable vsx @@ -5376,18 +5443,13 @@ fi check_gas() { log "check_gas using '$as' as AS" # :vararg is used on aarch64, arm and ppc altivec - check_as <= 30"; then - enable vfp_args - elif ! check_cpp_condition stddef.h "defined __ARM_PCS || defined __SOFTFP__" && [ $target_os != darwin ]; then + if check_cpp_condition vfp_args stddef.h "defined __ARM_PCS_VFP"; then + : + elif check_cpp_condition vfp_args stddef.h "defined _M_ARM_FP && _M_ARM_FP >= 30"; then + : + elif ! test_cpp_condition stddef.h "defined __ARM_PCS || defined __SOFTFP__" && [ $target_os != darwin ]; then case "${cross_prefix:-$cc}" in - *hardfloat*) enable vfp_args; fpabi=vfp ;; - *) check_ld "cc" <= 8.0.14.1" \ + "ffnvcodec/nvEncodeAPI.h ffnvcodec/dynlink_cuda.h ffnvcodec/dynlink_cuviddec.h ffnvcodec/dynlink_nvcuvid.h" "" +fi + +check_cpp_condition winrt windows.h "!WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)" if ! disabled w32threads && ! enabled pthreads; then check_func_headers "windows.h process.h" _beginthreadex && + check_type "windows.h" CONDITION_VARIABLE && + check_type "windows.h" INIT_ONCE && enable w32threads || disable w32threads if ! enabled w32threads && enabled winrt; then check_func_headers "windows.h" CreateThread && @@ -5861,17 +5919,14 @@ if ! disabled pthreads && ! enabled w32threads && ! enabled os2threads; then elif check_func pthread_join && check_func pthread_create; then enable pthreads fi - check_code cc "pthread.h" "static pthread_mutex_t atomic_lock = PTHREAD_MUTEX_INITIALIZER" || disable pthreads -fi - + check_cc pthreads "pthread.h" "static pthread_mutex_t atomic_lock = PTHREAD_MUTEX_INITIALIZER" -if enabled pthreads; then - check_func pthread_cancel + if enabled pthreads; then + check_builtin sem_timedwait semaphore.h "sem_t *s; sem_init(s,0,0); sem_timedwait(s,0); sem_destroy(s)" $pthreads_extralibs + check_func pthread_cancel $pthreads_extralibs + fi fi -enabled pthreads && - check_builtin sem_timedwait semaphore.h "sem_t *s; sem_init(s,0,0); sem_timedwait(s,0); sem_destroy(s)" - enabled zlib && check_lib zlib zlib.h zlibVersion -lz enabled bzlib && check_lib bzlib bzlib.h BZ2_bzlibVersion -lbz2 enabled lzma && check_lib lzma lzma.h lzma_version_number -llzma @@ -5879,7 +5934,7 @@ enabled lzma && check_lib lzma lzma.h lzma_version_number -llzma # On some systems dynamic loading requires no extra linker flags check_lib libdl dlfcn.h "dlopen dlsym" || check_lib libdl dlfcn.h "dlopen dlsym" -ldl -check_lib libm math.h sin -lm && LIBM="-lm" +check_lib libm math.h sin -lm atan2f_args=2 copysign_args=2 @@ -5888,7 +5943,7 @@ ldexpf_args=2 powf_args=2 for func in $MATH_FUNCS; do - eval check_mathfunc $func \${${func}_args:-1} $LIBM + eval check_mathfunc $func \${${func}_args:-1} $libm_extralibs done for func in $COMPLEX_FUNCS; do @@ -5897,17 +5952,17 @@ done # these are off by default, so fail if requested and not available enabled cuda_sdk && require cuda_sdk cuda.h cuCtxCreate -lcuda -enabled cuvid && { enabled cuda || - die "ERROR: CUVID requires CUDA"; } enabled chromaprint && require chromaprint chromaprint.h chromaprint_get_version -lchromaprint enabled decklink && { require_header DeckLinkAPI.h && - { check_cpp_condition DeckLinkAPIVersion.h "BLACKMAGIC_DECKLINK_API_VERSION >= 0x0a060100" || die "ERROR: Decklink API version must be >= 10.6.1."; } } + { test_cpp_condition DeckLinkAPIVersion.h "BLACKMAGIC_DECKLINK_API_VERSION >= 0x0a060100" || die "ERROR: Decklink API version must be >= 10.6.1."; } } enabled libndi_newtek && require_header Processing.NDI.Lib.h enabled frei0r && require_header frei0r.h enabled gmp && require gmp gmp.h mpz_export -lgmp enabled gnutls && require_pkg_config gnutls gnutls gnutls/gnutls.h gnutls_global_init enabled jni && { [ $target_os = "android" ] && check_header jni.h && enabled pthreads || die "ERROR: jni not found"; } enabled ladspa && require_header ladspa.h +enabled libaom && require_pkg_config libaom "aom >= 0.1.0" aom/aom_codec.h aom_codec_version +enabled lv2 && require_pkg_config lv2 lilv-0 "lilv-0/lilv/lilv.h" lilv_world_new enabled libiec61883 && require libiec61883 libiec61883/iec61883.h iec61883_cmp_connect -lraw1394 -lavc1394 -lrom1394 -liec61883 enabled libass && require_pkg_config libass libass ass/ass.h ass_library_init enabled libbluray && require_pkg_config libbluray libbluray libbluray/bluray.h bd_open @@ -5916,23 +5971,24 @@ enabled libcelt && require libcelt celt/celt.h celt_decode -lcelt0 && { check_lib libcelt celt/celt.h celt_decoder_create_custom -lcelt0 || die "ERROR: libcelt must be installed and version must be >= 0.11.0."; } enabled libcaca && require_pkg_config libcaca caca caca.h caca_create_canvas +enabled libcodec2 && require libcodec2 codec2/codec2.h codec2_create -lcodec2 enabled libdc1394 && require_pkg_config libdc1394 libdc1394-2 dc1394/dc1394.h dc1394_new enabled libdrm && require_pkg_config libdrm libdrm xf86drm.h drmGetVersion -enabled libfdk_aac && { use_pkg_config libfdk_aac fdk-aac "fdk-aac/aacenc_lib.h" aacEncOpen || +enabled libfdk_aac && { check_pkg_config libfdk_aac fdk-aac "fdk-aac/aacenc_lib.h" aacEncOpen || { require libfdk_aac fdk-aac/aacenc_lib.h aacEncOpen -lfdk-aac && warn "using libfdk without pkg-config"; } } flite_extralibs="-lflite_cmu_time_awb -lflite_cmu_us_awb -lflite_cmu_us_kal -lflite_cmu_us_kal16 -lflite_cmu_us_rms -lflite_cmu_us_slt -lflite_usenglish -lflite_cmulex -lflite" enabled libflite && require libflite "flite/flite.h" flite_init $flite_extralibs enabled fontconfig && enable libfontconfig enabled libfontconfig && require_pkg_config libfontconfig fontconfig "fontconfig/fontconfig.h" FcInit -enabled libfreetype && require_pkg_config libfreetype2 freetype2 "ft2build.h FT_FREETYPE_H" FT_Init_FreeType +enabled libfreetype && require_pkg_config libfreetype freetype2 "ft2build.h FT_FREETYPE_H" FT_Init_FreeType enabled libfribidi && require_pkg_config libfribidi fribidi fribidi.h fribidi_version_info -enabled libgme && { use_pkg_config libgme libgme gme/gme.h gme_new_emu || +enabled libgme && { check_pkg_config libgme libgme gme/gme.h gme_new_emu || require libgme gme/gme.h gme_new_emu -lgme -lstdc++; } enabled libgsm && { for gsm_hdr in "gsm.h" "gsm/gsm.h"; do check_lib libgsm "${gsm_hdr}" gsm_create -lgsm && break; done || die "ERROR: libgsm not found"; } -enabled libilbc && require libilbc ilbc.h WebRtcIlbcfix_InitDecode -lilbc +enabled libilbc && require libilbc ilbc.h WebRtcIlbcfix_InitDecode -lilbc $pthreads_extralibs enabled libkvazaar && require_pkg_config libkvazaar "kvazaar >= 0.8.1" kvazaar.h kvz_api_get # While it may appear that require is being used as a pkg-config # fallback for libmfx, it is actually being used to detect a different @@ -5940,32 +5996,24 @@ enabled libkvazaar && require_pkg_config libkvazaar "kvazaar >= 0.8.1" kv # Media SDK or Intel Media Server Studio, these don't come with # pkg-config support. Instead, users should make sure that the build # can find the libraries and headers through other means. -enabled libmfx && { use_pkg_config libmfx libmfx "mfx/mfxvideo.h" MFXInit || - { require libmfx "mfx/mfxvideo.h" MFXInit -llibmfx && warn "using libmfx without pkg-config"; } } +enabled libmfx && { check_pkg_config libmfx libmfx "mfx/mfxvideo.h" MFXInit || + { require libmfx "mfx/mfxvideo.h" MFXInit "-llibmfx $advapi32_extralibs" && warn "using libmfx without pkg-config"; } } enabled libmodplug && require_pkg_config libmodplug libmodplug libmodplug/modplug.h ModPlug_Load -enabled libmp3lame && require "libmp3lame >= 3.98.3" lame/lame.h lame_set_VBR_quality -lmp3lame -enabled libmysofa && require libmysofa "mysofa.h" mysofa_load -lmysofa +enabled libmp3lame && require "libmp3lame >= 3.98.3" lame/lame.h lame_set_VBR_quality -lmp3lame $libm_extralibs +enabled libmysofa && require libmysofa "mysofa.h" mysofa_load -lmysofa $zlib_extralibs enabled libnpp && { check_lib libnpp npp.h nppGetLibVersion -lnppig -lnppicc -lnppc || check_lib libnpp npp.h nppGetLibVersion -lnppi -lnppc || die "ERROR: libnpp not found"; } enabled libopencore_amrnb && require libopencore_amrnb opencore-amrnb/interf_dec.h Decoder_Interface_init -lopencore-amrnb enabled libopencore_amrwb && require libopencore_amrwb opencore-amrwb/dec_if.h D_IF_init -lopencore-amrwb enabled libopencv && { check_header opencv2/core/core_c.h && - { use_pkg_config libopencv opencv opencv2/core/core_c.h cvCreateImageHeader || - require opencv opencv2/core/core_c.h cvCreateImageHeader -lopencv_core -lopencv_imgproc; } || + { check_pkg_config libopencv opencv opencv2/core/core_c.h cvCreateImageHeader || + require libopencv opencv2/core/core_c.h cvCreateImageHeader -lopencv_core -lopencv_imgproc; } || require_pkg_config libopencv opencv opencv/cxcore.h cvCreateImageHeader; } enabled libopenh264 && require_pkg_config libopenh264 openh264 wels/codec_api.h WelsGetCodecVersion -enabled libopenjpeg && { { check_lib libopenjpeg openjpeg-2.3/openjpeg.h opj_version -lopenjp2 -DOPJ_STATIC && add_cppflags -DOPJ_STATIC; } || - check_lib libopenjpeg openjpeg-2.3/openjpeg.h opj_version -lopenjp2 || - { check_lib libopenjpeg openjpeg-2.2/openjpeg.h opj_version -lopenjp2 -DOPJ_STATIC && add_cppflags -DOPJ_STATIC; } || - check_lib libopenjpeg openjpeg-2.2/openjpeg.h opj_version -lopenjp2 || - { check_lib libopenjpeg openjpeg-2.1/openjpeg.h opj_version -lopenjp2 -DOPJ_STATIC && add_cppflags -DOPJ_STATIC; } || - check_lib libopenjpeg openjpeg-2.1/openjpeg.h opj_version -lopenjp2 || - { check_lib libopenjpeg openjpeg-2.0/openjpeg.h opj_version -lopenjp2 -DOPJ_STATIC && add_cppflags -DOPJ_STATIC; } || - { check_lib libopenjpeg openjpeg-1.5/openjpeg.h opj_version -lopenjpeg -DOPJ_STATIC && add_cppflags -DOPJ_STATIC; } || - { check_lib libopenjpeg openjpeg.h opj_version -lopenjpeg -DOPJ_STATIC && add_cppflags -DOPJ_STATIC; } || - die "ERROR: libopenjpeg not found"; } -enabled libopenmpt && require_pkg_config libopenmpt "libopenmpt >= 0.2.6557" libopenmpt/libopenmpt.h openmpt_module_create +enabled libopenjpeg && { check_pkg_config libopenjpeg "libopenjp2 >= 2.1.0" openjpeg.h opj_version || + { require_pkg_config libopenjpeg "libopenjp2 >= 2.1.0" openjpeg.h opj_version -DOPJ_STATIC && add_cppflags -DOPJ_STATIC; } } +enabled libopenmpt && require_pkg_config libopenmpt "libopenmpt >= 0.2.6557" libopenmpt/libopenmpt.h openmpt_module_create -lstdc++ && append libopenmpt_extralibs "-lstdc++" enabled libopus && { enabled libopus_decoder && { require_pkg_config libopus opus opus_multistream.h opus_multistream_decoder_create @@ -5977,44 +6025,46 @@ enabled libopus && { enabled libpulse && require_pkg_config libpulse libpulse pulse/pulseaudio.h pa_context_new enabled librsvg && require_pkg_config librsvg librsvg-2.0 librsvg-2.0/librsvg/rsvg.h rsvg_handle_render_cairo enabled librtmp && require_pkg_config librtmp librtmp librtmp/rtmp.h RTMP_Socket -enabled librubberband && require_pkg_config librubberband "rubberband >= 1.8.1" rubberband/rubberband-c.h rubberband_new +enabled librubberband && require_pkg_config librubberband "rubberband >= 1.8.1" rubberband/rubberband-c.h rubberband_new -lstdc++ && append librubberband_extralibs "-lstdc++" enabled libshine && require_pkg_config libshine shine shine/layer3.h shine_encode_buffer -enabled libsmbclient && { use_pkg_config libsmbclient smbclient libsmbclient.h smbc_init || - require smbclient libsmbclient.h smbc_init -lsmbclient; } -enabled libsnappy && require libsnappy snappy-c.h snappy_compress -lsnappy -enabled libsoxr && require libsoxr soxr.h soxr_create -lsoxr && LIBSOXR="-lsoxr" +enabled libsmbclient && { check_pkg_config libsmbclient smbclient libsmbclient.h smbc_init || + require libsmbclient libsmbclient.h smbc_init -lsmbclient; } +enabled libsnappy && require libsnappy snappy-c.h snappy_compress -lsnappy -lstdc++ +enabled libsoxr && require libsoxr soxr.h soxr_create -lsoxr enabled libssh && require_pkg_config libssh libssh libssh/sftp.h sftp_init -enabled libspeex && require_pkg_config libspeex speex speex/speex.h speex_decoder_init -lspeex +enabled libspeex && require_pkg_config libspeex speex speex/speex.h speex_decoder_init +enabled libsrt && require_pkg_config libsrt "srt >= 1.2.0" srt/srt.h srt_socket enabled libtesseract && require_pkg_config libtesseract tesseract tesseract/capi.h TessBaseAPICreate enabled libtheora && require libtheora theora/theoraenc.h th_info_init -ltheoraenc -ltheoradec -logg +enabled libtls && require_pkg_config libtls libtls tls.h tls_configure enabled libtwolame && require libtwolame twolame.h twolame_init -ltwolame && { check_lib libtwolame twolame.h twolame_encode_buffer_float32_interleaved -ltwolame || die "ERROR: libtwolame must be installed and version must be >= 0.3.10"; } enabled libv4l2 && require_pkg_config libv4l2 libv4l2 libv4l2.h v4l2_ioctl enabled libvidstab && require_pkg_config libvidstab "vidstab >= 0.98" vid.stab/libvidstab.h vsMotionDetectInit -enabled libvmaf && require_pkg_config libvmaf libvmaf libvmaf.h compute_vmaf +enabled libvmaf && require_pkg_config libvmaf "libvmaf >= 0.6.2" libvmaf.h compute_vmaf enabled libvo_amrwbenc && require libvo_amrwbenc vo-amrwbenc/enc_if.h E_IF_init -lvo-amrwbenc enabled libvorbis && require_pkg_config libvorbis vorbis vorbis/codec.h vorbis_info_init && require_pkg_config libvorbisenc vorbisenc vorbis/vorbisenc.h vorbis_encode_init enabled libvpx && { enabled libvpx_vp8_decoder && { - use_pkg_config libvpx_vp8_decoder "vpx >= 0.9.1" "vpx/vpx_decoder.h vpx/vp8dx.h" vpx_codec_vp8_dx || - check_lib libvpx_vp8_decoder "vpx/vpx_decoder.h vpx/vp8dx.h" vpx_codec_dec_init_ver -lvpx || - die "ERROR: libvpx decoder version must be >=0.9.1"; + check_pkg_config libvpx_vp8_decoder "vpx >= 1.4.0" "vpx/vpx_decoder.h vpx/vp8dx.h" vpx_codec_vp8_dx || + check_lib libvpx_vp8_decoder "vpx/vpx_decoder.h vpx/vp8dx.h" "vpx_codec_dec_init_ver VPX_IMG_FMT_HIGHBITDEPTH" -lvpx || + die "ERROR: libvpx decoder version must be >=1.4.0"; } enabled libvpx_vp8_encoder && { - use_pkg_config libvpx_vp8_encoder "vpx >= 0.9.7" "vpx/vpx_encoder.h vpx/vp8cx.h" vpx_codec_vp8_cx || - check_lib libvpx_vp8_encoder "vpx/vpx_encoder.h vpx/vp8cx.h" "vpx_codec_enc_init_ver VP8E_SET_MAX_INTRA_BITRATE_PCT" -lvpx || - die "ERROR: libvpx encoder version must be >=0.9.7"; + check_pkg_config libvpx_vp8_encoder "vpx >= 1.4.0" "vpx/vpx_encoder.h vpx/vp8cx.h" vpx_codec_vp8_cx || + check_lib libvpx_vp8_encoder "vpx/vpx_encoder.h vpx/vp8cx.h" "vpx_codec_enc_init_ver VPX_IMG_FMT_HIGHBITDEPTH" -lvpx || + die "ERROR: libvpx encoder version must be >=1.4.0"; } enabled libvpx_vp9_decoder && { - use_pkg_config libvpx_vp9_decoder "vpx >= 1.3.0" "vpx/vpx_decoder.h vpx/vp8dx.h" vpx_codec_vp9_dx || - check_lib libvpx_vp9_decoder "vpx/vpx_decoder.h vpx/vp8dx.h" "vpx_codec_vp9_dx" -lvpx + check_pkg_config libvpx_vp9_decoder "vpx >= 1.4.0" "vpx/vpx_decoder.h vpx/vp8dx.h" vpx_codec_vp9_dx || + check_lib libvpx_vp9_decoder "vpx/vpx_decoder.h vpx/vp8dx.h" "vpx_codec_vp9_dx VPX_IMG_FMT_HIGHBITDEPTH" "-lvpx $libm_extralibs" } enabled libvpx_vp9_encoder && { - use_pkg_config libvpx_vp9_encoder "vpx >= 1.3.0" "vpx/vpx_encoder.h vpx/vp8cx.h" vpx_codec_vp9_cx || - check_lib libvpx_vp9_encoder "vpx/vpx_encoder.h vpx/vp8cx.h" "vpx_codec_vp9_cx VP9E_SET_AQ_MODE" -lvpx + check_pkg_config libvpx_vp9_encoder "vpx >= 1.4.0" "vpx/vpx_encoder.h vpx/vp8cx.h" vpx_codec_vp9_cx || + check_lib libvpx_vp9_encoder "vpx/vpx_encoder.h vpx/vp8cx.h" "vpx_codec_vp9_cx VPX_IMG_FMT_HIGHBITDEPTH" "-lvpx $libm_extralibs" } if disabled_all libvpx_vp8_decoder libvpx_vp9_decoder libvpx_vp8_encoder libvpx_vp9_encoder; then die "libvpx enabled but no supported decoders found" @@ -6024,21 +6074,20 @@ enabled libvpx && { enabled libwavpack && require libwavpack wavpack/wavpack.h WavpackOpenFileOutput -lwavpack enabled libwebp && { enabled libwebp_encoder && require_pkg_config libwebp "libwebp >= 0.2.0" webp/encode.h WebPGetEncoderVersion - enabled libwebp_anim_encoder && use_pkg_config libwebp_anim_encoder "libwebpmux >= 0.4.0" webp/mux.h WebPAnimEncoderOptionsInit; } -enabled libx264 && { use_pkg_config libx264 x264 "stdint.h x264.h" x264_encoder_encode || - { require libx264 "stdint.h x264.h" x264_encoder_encode -lx264 && + enabled libwebp_anim_encoder && check_pkg_config libwebp_anim_encoder "libwebpmux >= 0.4.0" webp/mux.h WebPAnimEncoderOptionsInit; } +enabled libx264 && { check_pkg_config libx264 x264 "stdint.h x264.h" x264_encoder_encode || + { require libx264 "stdint.h x264.h" x264_encoder_encode "-lx264 $pthreads_extralibs $libm_extralibs" && warn "using libx264 without pkg-config"; } } && require_cpp_condition x264.h "X264_BUILD >= 118" && - { check_cpp_condition x264.h "X264_MPEG2" && - enable libx262; } + check_cpp_condition libx262 x264.h "X264_MPEG2" enabled libx265 && require_pkg_config libx265 x265 x265.h x265_api_get && require_cpp_condition x265.h "X265_BUILD >= 68" -enabled libxavs && require libxavs "stdint.h xavs.h" xavs_encoder_encode -lxavs +enabled libxavs && require libxavs "stdint.h xavs.h" xavs_encoder_encode "-lxavs $pthreads_extralibs $libm_extralibs" enabled libxvid && require libxvid xvid.h xvid_global -lxvidcore -enabled libzimg && require_pkg_config libzimg "zimg >= 2.3.0" zimg.h zimg_get_api_version +enabled libzimg && require_pkg_config libzimg "zimg >= 2.7.0" zimg.h zimg_get_api_version enabled libzmq && require_pkg_config libzmq libzmq zmq.h zmq_ctx_new -enabled libzvbi && require libzvbi libzvbi.h vbi_decoder_new -lzvbi && - { check_cpp_condition libzvbi.h "VBI_VERSION_MAJOR > 0 || VBI_VERSION_MINOR > 2 || VBI_VERSION_MINOR == 2 && VBI_VERSION_MICRO >= 28" || +enabled libzvbi && require_pkg_config libzvbi zvbi-0.2 libzvbi.h vbi_decoder_new && + { test_cpp_condition libzvbi.h "VBI_VERSION_MAJOR > 0 || VBI_VERSION_MINOR > 2 || VBI_VERSION_MINOR == 2 && VBI_VERSION_MICRO >= 28" || enabled gpl || die "ERROR: libzvbi requires version 0.2.28 or --enable-gpl."; } enabled libxml2 && require_pkg_config libxml2 libxml-2.0 libxml2/libxml/xmlversion.h xmlCheckVersion enabled mediacodec && { enabled jni || die "ERROR: mediacodec requires --enable-jni"; } @@ -6052,13 +6101,13 @@ enabled mmal && { check_lib mmal interface/mmal/mmal.h mmal_port_co enabled openal && { { for al_extralibs in "${OPENAL_LIBS}" "-lopenal" "-lOpenAL32"; do check_lib openal 'AL/al.h' alGetError "${al_extralibs}" && break; done } || die "ERROR: openal not found"; } && - { check_cpp_condition "AL/al.h" "defined(AL_VERSION_1_1)" || + { test_cpp_condition "AL/al.h" "defined(AL_VERSION_1_1)" || die "ERROR: openal must be installed and version must be 1.1 or compatible"; } enabled opencl && { check_lib opencl OpenCL/cl.h clEnqueueNDRangeKernel -Wl,-framework,OpenCL || check_lib opencl CL/cl.h clEnqueueNDRangeKernel -lOpenCL || die "ERROR: opencl not found"; } && - { check_cpp_condition "OpenCL/cl.h" "defined(CL_VERSION_1_2)" || - check_cpp_condition "CL/cl.h" "defined(CL_VERSION_1_2)" || + { test_cpp_condition "OpenCL/cl.h" "defined(CL_VERSION_1_2)" || + test_cpp_condition "CL/cl.h" "defined(CL_VERSION_1_2)" || die "ERROR: opencl must be installed and version must be 1.2 or compatible"; } enabled opengl && { check_lib opengl GL/glx.h glXGetProcAddress "-lGL" || check_lib opengl windows.h wglGetProcAddress "-lopengl32 -lgdi32" || @@ -6066,20 +6115,18 @@ enabled opengl && { check_lib opengl GL/glx.h glXGetProcAddress "-lGL check_lib opengl ES2/gl.h glGetError "-isysroot=${sysroot} -Wl,-framework,OpenGLES" || die "ERROR: opengl not found." } +enabled omx && require_header OMX_Core.h enabled omx_rpi && { check_header OMX_Core.h || { ! enabled cross_compile && add_cflags -isystem/opt/vc/include/IL && check_header OMX_Core.h ; } || - die "ERROR: OpenMAX IL headers not found"; } -enabled omx && require_header OMX_Core.h -enabled openssl && { use_pkg_config openssl openssl openssl/ssl.h OPENSSL_init_ssl || - use_pkg_config openssl openssl openssl/ssl.h SSL_library_init || + die "ERROR: OpenMAX IL headers not found"; } && enable omx +enabled openssl && { check_pkg_config openssl openssl openssl/ssl.h OPENSSL_init_ssl || + check_pkg_config openssl openssl openssl/ssl.h SSL_library_init || check_lib openssl openssl/ssl.h SSL_library_init -lssl -lcrypto || check_lib openssl openssl/ssl.h SSL_library_init -lssl32 -leay32 || check_lib openssl openssl/ssl.h SSL_library_init -lssl -lcrypto -lws2_32 -lgdi32 || die "ERROR: openssl not found"; } -enabled rkmpp && { { require_pkg_config rockchip_mpp rockchip_mpp rockchip/rk_mpi.h mpp_create || - die "ERROR : Rockchip MPP was not found."; } && - { check_func_headers rockchip/rk_mpi_cmd.h "MPP_DEC_GET_FREE_PACKET_SLOT_COUNT" || - die "ERROR: Rockchip MPP is outdated, please get a more recent one."; } && +enabled rkmpp && { require_pkg_config rkmpp rockchip_mpp rockchip/rk_mpi.h mpp_create && + require_pkg_config rockchip_mpp "rockchip_mpp >= 1.3.7" rockchip/rk_mpi.h mpp_create && { enabled libdrm || die "ERROR: rkmpp requires --enable-libdrm"; } } @@ -6091,7 +6138,7 @@ if enabled gcrypt; then gcrypt_extralibs=$("${GCRYPT_CONFIG}" --libs) check_func_headers gcrypt.h gcry_mpi_new $gcrypt_cflags $gcrypt_extralibs || die "ERROR: gcrypt not found" - add_cflags $gcrypt_cflags && add_extralibs $gcrypt_extralibs + add_cflags $gcrypt_cflags else require gcrypt gcrypt.h gcry_mpi_new -lgcrypt fi @@ -6099,22 +6146,19 @@ fi if enabled sdl2; then SDL2_CONFIG="${cross_prefix}sdl2-config" - if check_pkg_config sdl2 "sdl2 >= 2.0.1 sdl2 < 2.1.0" SDL_events.h SDL_PollEvent; then - check_func SDL_Init $sdl2_extralibs $sdl2_cflags || - disable sdl2 - elif "${SDL2_CONFIG}" --version > /dev/null 2>&1; then + test_pkg_config sdl2 "sdl2 >= 2.0.1 sdl2 < 2.1.0" SDL_events.h SDL_PollEvent + if disabled sdl2 && "${SDL2_CONFIG}" --version > /dev/null 2>&1; then sdl2_cflags=$("${SDL2_CONFIG}" --cflags) sdl2_extralibs=$("${SDL2_CONFIG}" --libs) - check_cpp_condition SDL.h "(SDL_MAJOR_VERSION<<16 | SDL_MINOR_VERSION<<8 | SDL_PATCHLEVEL) >= 0x020001" $sdl2_cflags && - check_cpp_condition SDL.h "(SDL_MAJOR_VERSION<<16 | SDL_MINOR_VERSION<<8 | SDL_PATCHLEVEL) < 0x020100" $sdl2_cflags && - check_func SDL_Init $sdl2_extralibs $sdl2_cflags && + test_cpp_condition SDL.h "(SDL_MAJOR_VERSION<<16 | SDL_MINOR_VERSION<<8 | SDL_PATCHLEVEL) >= 0x020001" $sdl2_cflags && + test_cpp_condition SDL.h "(SDL_MAJOR_VERSION<<16 | SDL_MINOR_VERSION<<8 | SDL_PATCHLEVEL) < 0x020100" $sdl2_cflags && + check_func_headers SDL_events.h SDL_PollEvent $sdl2_extralibs $sdl2_cflags && enable sdl2 fi if test $target_os = "mingw32"; then sdl2_extralibs=$(filter_out '-mwindows' $sdl2_extralibs) fi fi -enabled sdl2 && add_cflags $(filter_out '-Dmain=SDL_main' $sdl2_cflags) && add_extralibs $sdl2_extralibs if enabled decklink; then case $target_os in @@ -6127,13 +6171,16 @@ fi enabled securetransport && check_func SecIdentityCreate "-Wl,-framework,CoreFoundation -Wl,-framework,Security" && - check_lib securetransport "Security/SecureTransport.h Security/Security.h" "SSLCreateContext SecItemImport" "-Wl,-framework,CoreFoundation -Wl,-framework,Security" || + check_lib securetransport "Security/SecureTransport.h Security/Security.h" "SSLCreateContext" "-Wl,-framework,CoreFoundation -Wl,-framework,Security" || disable securetransport +enabled securetransport && + check_func SecItemImport "-Wl,-framework,CoreFoundation -Wl,-framework,Security" + enabled schannel && check_func_headers "windows.h security.h" InitializeSecurityContext -DSECURITY_WIN32 -lsecur32 && - check_cpp_condition winerror.h "defined(SEC_I_CONTEXT_EXPIRED)" && - add_extralibs -lsecur32 || + test_cpp_condition winerror.h "defined(SEC_I_CONTEXT_EXPIRED)" && + schannel_extralibs="-lsecur32" || disable schannel makeinfo --version > /dev/null 2>&1 && enable makeinfo || disable makeinfo @@ -6148,56 +6195,55 @@ rsync --help 2> /dev/null | grep -q 'contimeout' && enable rsync_contimeout || d # check V4L2 codecs available in the API check_header linux/fb.h check_header linux/videodev2.h -check_code cc linux/videodev2.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_safe struct_v4l2_frmivalenum_discrete -check_code cc linux/videodev2.h "int i = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_VIDEO_M2M | V4L2_BUF_FLAG_LAST;" || disable v4l2_m2m -check_code cc linux/videodev2.h "int i = V4L2_PIX_FMT_VC1_ANNEX_G;" && enable vc1_v4l2_m2m -check_code cc linux/videodev2.h "int i = V4L2_PIX_FMT_MPEG1;" && enable mpeg1_v4l2_m2m -check_code cc linux/videodev2.h "int i = V4L2_PIX_FMT_MPEG2;" && enable mpeg2_v4l2_m2m -check_code cc linux/videodev2.h "int i = V4L2_PIX_FMT_MPEG4;" && enable mpeg4_v4l2_m2m -check_code cc linux/videodev2.h "int i = V4L2_PIX_FMT_HEVC;" && enable hevc_v4l2_m2m -check_code cc linux/videodev2.h "int i = V4L2_PIX_FMT_H263;" && enable h263_v4l2_m2m -check_code cc linux/videodev2.h "int i = V4L2_PIX_FMT_H264;" && enable h264_v4l2_m2m -check_code cc linux/videodev2.h "int i = V4L2_PIX_FMT_VP8;" && enable vp8_v4l2_m2m -check_code cc linux/videodev2.h "int i = V4L2_PIX_FMT_VP9;" && enable vp9_v4l2_m2m +test_code cc linux/videodev2.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_sanitized struct_v4l2_frmivalenum_discrete +check_cc v4l2_m2m linux/videodev2.h "int i = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_VIDEO_M2M | V4L2_BUF_FLAG_LAST;" +check_cc vc1_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_VC1_ANNEX_G;" +check_cc mpeg1_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_MPEG1;" +check_cc mpeg2_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_MPEG2;" +check_cc mpeg4_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_MPEG4;" +check_cc hevc_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_HEVC;" +check_cc h263_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_H263;" +check_cc h264_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_H264;" +check_cc vp8_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_VP8;" +check_cc vp9_v4l2_m2m linux/videodev2.h "int i = V4L2_PIX_FMT_VP9;" check_header sys/videoio.h -check_code cc sys/videoio.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_safe struct_v4l2_frmivalenum_discrete +test_code cc sys/videoio.h "struct v4l2_frmsizeenum vfse; vfse.discrete.width = 0;" && enable_sanitized struct_v4l2_frmivalenum_discrete check_lib user32 "windows.h winuser.h" GetShellWindow -luser32 check_lib vfw32 "windows.h vfw.h" capCreateCaptureWindow -lvfw32 # check that WM_CAP_DRIVER_CONNECT is defined to the proper value # w32api 3.12 had it defined wrong -check_cpp_condition vfw.h "WM_CAP_DRIVER_CONNECT > WM_USER" && enable vfwcap_defines +check_cpp_condition vfwcap_defines vfw.h "WM_CAP_DRIVER_CONNECT > WM_USER" check_type "dshow.h" IBaseFilter # check for ioctl_meteor.h, ioctl_bt848.h and alternatives -{ check_header dev/bktr/ioctl_meteor.h && - check_header dev/bktr/ioctl_bt848.h; } || -{ check_header machine/ioctl_meteor.h && - check_header machine/ioctl_bt848.h; } || -{ check_header dev/video/meteor/ioctl_meteor.h && - check_header dev/video/bktr/ioctl_bt848.h; } || -check_header dev/ic/bt8xx.h +check_header "dev/bktr/ioctl_meteor.h dev/bktr/ioctl_bt848.h" || + check_header "machine/ioctl_meteor.h machine/ioctl_bt848.h" || + check_header "dev/video/meteor/ioctl_meteor.h dev/video/bktr/ioctl_bt848.h" || + check_header "dev/ic/bt8xx.h" if check_struct sys/soundcard.h audio_buf_info bytes; then - enable_safe sys/soundcard.h + enable_sanitized sys/soundcard.h else - check_cc -D__BSD_VISIBLE -D__XSI_VISIBLE < audio_buf_info abc; EOF fi -check_header soundcard.h -enabled alsa && check_lib alsa alsa/asoundlib.h snd_pcm_htimestamp -lasound +enabled alsa && check_pkg_config alsa alsa "alsa/asoundlib.h" snd_pcm_htimestamp || + check_lib alsa alsa/asoundlib.h snd_pcm_htimestamp -lasound -enabled jack && check_lib jack jack/jack.h jack_client_open -ljack && - check_func jack_port_get_latency_range -ljack +enabled libjack && + require_pkg_config libjack jack jack/jack.h jack_port_get_latency_range enabled sndio && check_lib sndio sndio.h sio_open -lsndio if enabled libcdio; then + check_pkg_config libcdio libcdio_paranoia "cdio/cdda.h cdio/paranoia.h" cdio_cddap_open || + check_pkg_config libcdio libcdio_paranoia "cdio/paranoia/cdda.h cdio/paranoia/paranoia.h" cdio_cddap_open || check_lib libcdio "cdio/cdda.h cdio/paranoia.h" cdio_cddap_open -lcdio_paranoia -lcdio_cdda -lcdio || check_lib libcdio "cdio/paranoia/cdda.h cdio/paranoia/paranoia.h" cdio_cddap_open -lcdio_paranoia -lcdio_cdda -lcdio || die "ERROR: No usable libcdio/cdparanoia found" @@ -6210,16 +6256,13 @@ if enabled libxcb; then enabled libxcb_shm && check_pkg_config libxcb_shm xcb-shm xcb/shm.h xcb_shm_attach enabled libxcb_shape && check_pkg_config libxcb_shape xcb-shape xcb/shape.h xcb_shape_get_rectangles enabled libxcb_xfixes && check_pkg_config libxcb_xfixes xcb-xfixes xcb/xfixes.h xcb_xfixes_get_cursor_image - - add_cflags $xcb_cflags $xcb_shm_cflags $xcb_xfixes_cflags $xcb_shape_cflags - add_extralibs $xcb_extralibs $xcb_shm_extralibs $xcb_xfixes_extralibs $xcb_shape_extralibs fi check_func_headers "windows.h" CreateDIBSection "$gdigrab_indev_extralibs" # d3d11va requires linking directly to dxgi and d3d11 if not building for # the desktop api partition -check_cpp < #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) @@ -6236,22 +6279,43 @@ enabled vaapi && check_lib vaapi va/va.h vaInitialize -lva enabled vaapi && - check_code cc "va/va.h" "vaCreateSurfaces(0, 0, 0, 0, 0, 0, 0, 0)" || - disable vaapi + check_cc vaapi "va/va.h" "vaCreateSurfaces(0, 0, 0, 0, 0, 0, 0, 0)" -enabled vaapi && +if enabled vaapi; then check_lib vaapi_drm "va/va.h va/va_drm.h" vaGetDisplayDRM -lva -lva-drm - -enabled vaapi && check_lib vaapi_x11 "va/va.h va/va_x11.h" vaGetDisplay -lva -lva-x11 -lX11 +fi enabled vaapi && - check_cpp_condition "va/va.h" "VA_CHECK_VERSION(1, 0, 0)" && - enable vaapi_1 + check_cpp_condition vaapi_1 "va/va.h" "VA_CHECK_VERSION(1, 0, 0)" + +if enabled_all opencl libdrm ; then + check_type "CL/cl_intel.h" "clCreateImageFromFdINTEL_fn" && + enable opencl_drm_beignet + check_func_headers "CL/cl_ext.h" clImportMemoryARM && + enable opencl_drm_arm +fi + +if enabled_all opencl vaapi ; then + enabled opencl_drm_beignet && enable opencl_vaapi_beignet + if enabled libmfx ; then + check_type "CL/cl.h CL/va_ext.h" "clCreateFromVA_APIMediaSurfaceINTEL_fn" && + enable opencl_vaapi_intel_media + fi +fi + +if enabled_all opencl dxva2 ; then + check_type "CL/cl_dx9_media_sharing.h" cl_dx9_surface_info_khr && + enable opencl_dxva2 +fi + +if enabled_all opencl d3d11va ; then + check_type "CL/cl_d3d11.h" clGetDeviceIDsFromD3D11KHR_fn && + enable opencl_d3d11 +fi enabled vdpau && - check_cpp_condition vdpau/vdpau.h "defined VDP_DECODER_PROFILE_MPEG4_PART2_ASP" || - disable vdpau + check_cpp_condition vdpau vdpau/vdpau.h "defined VDP_DECODER_PROFILE_MPEG4_PART2_ASP" enabled vdpau && check_lib vdpau_x11 "vdpau/vdpau.h vdpau/vdpau_x11.h" vdp_device_create_x11 -lvdpau -lX11 @@ -6263,21 +6327,27 @@ if enabled x86; then mingw32*|mingw64*|win32|win64|linux|cygwin*) ;; *) - disable cuda cuvid nvenc + disable ffnvcodec cuvid nvdec nvenc ;; esac else - disable cuda cuvid nvenc + disable ffnvcodec cuvid nvdec nvenc fi +enabled ffnvcodec && enable cuda + enabled nvenc && - check_cc -I$source_path < NV_ENCODE_API_FUNCTION_LIST flist; void f(void) { struct { const GUID guid; } s[] = { { NV_ENC_PRESET_HQ_GUID } }; } int main(void) { return 0; } EOF +enabled amf && + check_cpp_condition amf "AMF/core/Version.h" \ + "(AMF_VERSION_MAJOR << 48 | AMF_VERSION_MINOR << 32 | AMF_VERSION_RELEASE << 16 | AMF_VERSION_BUILD_NUM) >= 0x0001000400040001" + # Funny iconv installations are not unusual, so check it after all flags have been set if enabled libc_iconv; then check_func_headers iconv.h iconv @@ -6309,9 +6379,14 @@ fi check_disable_warning(){ warning_flag=-W${1#-Wno-} - test_cflags $warning_flag && add_cflags $1 + test_cflags $unknown_warning_flags $warning_flag && add_cflags $1 } +test_cflags -Werror=unused-command-line-argument && + append unknown_warning_flags "-Werror=unused-command-line-argument" +test_cflags -Werror=unknown-warning-option && + append unknown_warning_flags "-Werror=unknown-warning-option" + check_disable_warning -Wno-parentheses check_disable_warning -Wno-switch check_disable_warning -Wno-format-zero-length @@ -6327,15 +6402,14 @@ check_disable_warning_headers(){ check_disable_warning_headers -Wno-deprecated-declarations check_disable_warning_headers -Wno-unused-variable -check_cc < $TMPV if test_ldflags -Wl,${version_script},$TMPV; then append SHFLAGS '-Wl,${version_script},\$(SUBDIR)lib\$(NAME).ver' - check_cc <= 1400" && + test_cpp_condition "windows.h" "__ICL < 1300 || __ICL >= 1400" && add_cflags -Qansi-alias # Some inline asm is not compilable in debug if enabled debug; then @@ -6525,24 +6620,24 @@ elif enabled_any msvc icl; then fi fi # msvcrt10 x64 incorrectly enables log2, only msvcrt12 (MSVC 2013) onwards actually has log2. - check_cpp_condition crtversion.h "_VC_CRT_MAJOR_VERSION >= 12" || disable log2 + check_cpp_condition log2 crtversion.h "_VC_CRT_MAJOR_VERSION >= 12" # The CRT headers contain __declspec(restrict) in a few places, but if redefining # restrict, this might break. MSVC 2010 and 2012 fail with __declspec(__restrict) # (as it ends up if the restrict redefine is done before including stdlib.h), while # MSVC 2013 and newer can handle it fine. # If this declspec fails, force including stdlib.h before the restrict redefinition # happens in config.h. - if [ $_restrict != restrict ]; then - check_cc <= 190024218" || + test_cpp_condition windows.h "_MSC_FULL_VER >= 190024218" || check_cflags -d2SSAOptimizer- # enable utf-8 source processing on VS2015 U2 and newer - check_cpp_condition windows.h "_MSC_FULL_VER >= 190023918" && + test_cpp_condition windows.h "_MSC_FULL_VER >= 190023918" && add_cflags -utf-8 fi @@ -6550,7 +6645,7 @@ for pfx in "" host_; do varname=${pfx%_}cc_type eval "type=\$$varname" if [ "$type" = "msvc" ]; then - check_${pfx}cc < enable ${lib}_deps_${dep} -# -> add $dep to ${lib}_deps only once -add_dep() { - lib=$1 - dep=$2 - enabled "${lib}_deps_${dep}" && return 0 - enable "${lib}_deps_${dep}" - prepend "${lib}_deps" $dep -} - -# merge deps lib components -# merge all ${component}_deps into ${lib}_deps and ${lib}_deps_* -merge_deps() { - lib=$1 - shift - for comp in $*; do - enabled $comp || continue - eval "dep=\"\$${comp}_deps\"" - for d in $dep; do - add_dep $lib $d - done +flatten_extralibs(){ + unset nested_entries + list_name=$1 + eval list=\$${1} + for entry in $list; do + entry_copy=$entry + resolve entry_copy + append nested_entries $(filter '*_extralibs' $entry_copy) + flat_entries=$(filter_out '*_extralibs' $entry_copy) + eval $entry="\$flat_entries" done + append $list_name "$nested_entries" + + resolve nested_entries + if test -n "$(filter '*_extralibs' $nested_entries)"; then + flatten_extralibs $list_name + fi } -merge_deps libavfilter $FILTER_LIST +flatten_extralibs_wrapper(){ + list_name=$1 + flatten_extralibs $list_name + unique $list_name + resolve $list_name + eval $list_name=\$\(\$ldflags_filter \$$list_name\) + eval printf \''%s'\' \""\$$list_name"\" +} + +for linkunit in $LIBRARY_LIST; do + unset current_extralibs + eval components=\$$(toupper ${linkunit})_COMPONENTS_LIST + for comp in ${components}; do + enabled $comp || continue + comp_extralibs="${comp}_extralibs" + append current_extralibs $comp_extralibs + done + eval prepend ${linkunit}_extralibs $current_extralibs +done + +for linkunit in $LIBRARY_LIST $PROGRAM_LIST $EXTRALIBS_LIST; do + eval ${linkunit}_extralibs=\$\(flatten_extralibs_wrapper ${linkunit}_extralibs\) +done map 'enabled $v && intrinsics=${v#intrinsics_}' $INTRINSICS_LIST @@ -6628,7 +6733,7 @@ for thread in $THREADS_LIST; do fi done -if disabled stdatomic_h; then +if disabled stdatomic; then if enabled atomics_gcc; then add_cppflags '-I\$(SRC_PATH)/compat/atomics/gcc' elif enabled atomics_win32; then @@ -6658,6 +6763,8 @@ enabled amovie_filter && prepend avfilter_deps "avformat avcodec" enabled aresample_filter && prepend avfilter_deps "swresample" enabled atempo_filter && prepend avfilter_deps "avcodec" enabled cover_rect_filter && prepend avfilter_deps "avformat avcodec" +enabled convolve_filter && prepend avfilter_deps "avcodec" +enabled deconvolve_filter && prepend avfilter_deps "avcodec" enabled ebur128_filter && enabled swresample && prepend avfilter_deps "swresample" enabled elbg_filter && prepend avfilter_deps "avcodec" enabled fftfilt_filter && prepend avfilter_deps "avcodec" @@ -6686,6 +6793,9 @@ enabled zoompan_filter && prepend avfilter_deps "swscale" enabled lavfi_indev && prepend avdevice_deps "avfilter" +#FIXME +enabled sdl2_outdev && add_cflags $(filter_out '-Dmain=SDL_main' $sdl2_cflags) + enabled opus_decoder && prepend avcodec_deps "swresample" expand_deps(){ @@ -6700,17 +6810,6 @@ postproc_deps="$(filter_out 'gpl' $postproc_deps)" map 'expand_deps $v' $LIBRARY_LIST -license="LGPL version 2.1 or later" -if enabled nonfree; then - license="nonfree and unredistributable" -elif enabled gplv3; then - license="GPL version 3 or later" -elif enabled lgplv3; then - license="LGPL version 3 or later" -elif enabled gpl; then - license="GPL version 2 or later" -fi - if test "$quiet" != "yes"; then echo "install prefix $prefix" @@ -6745,6 +6844,7 @@ if enabled x86; then echo "AESNI enabled ${aesni-no}" echo "AVX enabled ${avx-no}" echo "AVX2 enabled ${avx2-no}" + echo "AVX-512 enabled ${avx512-no}" echo "XOP enabled ${xop-no}" echo "FMA3 enabled ${fma3-no}" echo "FMA4 enabled ${fma4-no}" @@ -6799,11 +6899,11 @@ test -n "$random_seed" && echo echo "External libraries:" -print_enabled '' $EXTERNAL_LIBRARY_LIST | print_in_columns +print_enabled '' $EXTERNAL_LIBRARY_LIST $EXTERNAL_AUTODETECT_LIBRARY_LIST | print_in_columns echo echo "External libraries providing hardware acceleration:" -print_enabled '' $HWACCEL_LIBRARY_LIST | print_in_columns +print_enabled '' $HWACCEL_LIBRARY_LIST $HWACCEL_AUTODETECT_LIBRARY_LIST | print_in_columns echo echo "Libraries:" @@ -6830,12 +6930,21 @@ fi echo "License: $license" -echo "Creating configuration files ..." - fi # test "$quiet" != "yes" +if test -n "$WARNINGS"; then + printf "\n%s%s$WARNINGS%s" "$warn_color" "$bold_color" "$reset_color" + enabled fatal_warnings && exit 1 +fi + test -e Makefile || echo "include $source_path/Makefile" > Makefile +esc(){ + echo "$*" | sed 's/%/%25/g;s/:/%3a/g' +} + +echo "config:$arch:$subarch:$cpu:$target_os:$(esc $cc_ident):$(esc $FFMPEG_CONFIGURATION)" > ffbuild/config.fate + enabled stripping || strip="echo skipping strip" enabled stripping || striptype="" @@ -6864,6 +6973,7 @@ endif CC_IDENT=$cc_ident ARCH=$arch INTRINSICS=$intrinsics +EXTERN_PREFIX=$extern_prefix CC=$cc CXX=$cxx AS=$as @@ -6879,6 +6989,8 @@ DEPX86ASMFLAGS=\$(X86ASMFLAGS) AR=$ar ARFLAGS=$arflags AR_O=$ar_o +AR_CMD=$ar +NM_CMD=$nm RANLIB=$ranlib STRIP=$strip STRIPTYPE=$striptype @@ -6913,7 +7025,7 @@ DEPWINDRES=$dep_cc DOXYGEN=$doxygen LDFLAGS=$LDFLAGS LDEXEFLAGS=$LDEXEFLAGS -LDLIBFLAGS=$LDLIBFLAGS +LDSOFLAGS=$LDSOFLAGS SHFLAGS=$(echo $($ldflags_filter $SHFLAGS)) ASMSTRIPFLAGS=$ASMSTRIPFLAGS X86ASMFLAGS=$X86ASMFLAGS @@ -6957,7 +7069,6 @@ TARGET_PATH=$target_path TARGET_SAMPLES=${target_samples:-\$(SAMPLES)} CFLAGS-ffplay=${sdl2_cflags} CFLAGS_HEADERS=$CFLAGS_HEADERS -ZLIB=$($ldflags_filter -lz) LIB_INSTALL_EXTRA_CMD=$LIB_INSTALL_EXTRA_CMD EXTRALIBS=$extralibs COMPAT_OBJS=$compat_objs @@ -6981,12 +7092,9 @@ EOF map 'eval echo "${v}_FFLIBS=\$${v}_deps" >> ffbuild/config.mak' $LIBRARY_LIST -print_program_extralibs(){ - eval "program_extralibs=\$${1}_extralibs" - eval echo "EXTRALIBS-${1}=${program_extralibs}" >> ffbuild/config.mak -} - -map 'print_program_extralibs $v' $PROGRAM_LIST +for entry in $LIBRARY_LIST $PROGRAM_LIST $EXTRALIBS_LIST; do + eval echo "EXTRALIBS-${entry}=\$${entry}_extralibs" >> ffbuild/config.mak +done cat > $TMPH < $TMPH <$TMPASM + cat > $TMPASM <> $TMPH @@ -7042,7 +7152,7 @@ touch ffbuild/.config enabled x86asm && cp_if_changed $TMPASM config.asm cat > $TMPH <> $TMPH cp_if_changed $TMPH libavutil/avconfig.h +full_filter_name(){ + sed -n "s/^extern AVFilter ff_\([avfsinkrc]\{2,5\}\)_$1;/\1_$1/p" $source_path/libavfilter/allfilters.c +} + # generate the lists of enabled components print_enabled_components(){ file=$1 @@ -7061,23 +7175,43 @@ print_enabled_components(){ shift 3 echo "static const $struct_name * const $name[] = {" > $TMPH for c in $*; do - enabled $c && printf " &ff_%s,\n" $c >> $TMPH + if enabled $c; then + case $name in + filter_list) + c=$(full_filter_name $(remove_suffix _filter $c)) + ;; + indev_list) + c=$(add_suffix _demuxer $(remove_suffix _indev $c)) + ;; + outdev_list) + c=$(add_suffix _muxer $(remove_suffix _outdev $c)) + ;; + esac + printf " &ff_%s,\n" $c >> $TMPH + fi done + if [ "$name" = "filter_list" ]; then + for c in asrc_abuffer vsrc_buffer asink_abuffer vsink_buffer; do + printf " &ff_%s,\n" $c >> $TMPH + done + fi echo " NULL };" >> $TMPH cp_if_changed $TMPH $file } +print_enabled_components libavfilter/filter_list.c AVFilter filter_list $FILTER_LIST +print_enabled_components libavcodec/codec_list.c AVCodec codec_list $CODEC_LIST +print_enabled_components libavcodec/parser_list.c AVCodecParser parser_list $PARSER_LIST print_enabled_components libavcodec/bsf_list.c AVBitStreamFilter bitstream_filters $BSF_LIST +print_enabled_components libavformat/demuxer_list.c AVInputFormat demuxer_list $DEMUXER_LIST +print_enabled_components libavformat/muxer_list.c AVOutputFormat muxer_list $MUXER_LIST +print_enabled_components libavdevice/indev_list.c AVInputFormat indev_list $INDEV_LIST +print_enabled_components libavdevice/outdev_list.c AVOutputFormat outdev_list $OUTDEV_LIST print_enabled_components libavformat/protocol_list.c URLProtocol url_protocols $PROTOCOL_LIST -if test -n "$WARNINGS"; then - printf "\n%s%s$WARNINGS%s" "$warn_color" "$bold_color" "$reset_color" - enabled fatal_warnings && exit 1 -fi - # Settings for pkg-config files -cat > ffbuild/config.sh < $TMPH <> ffbuild/config.sh + echo ${lib}_deps=\"$lib_deps\" >> $TMPH done + +cp_if_changed $TMPH ffbuild/config.sh diff --git a/doc/APIchanges b/doc/APIchanges index 6803eaaea2d62..4f6ac2a031f0e 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -2,19 +2,166 @@ Never assume the API of libav* to be stable unless at least 1 month has passed since the last major version increase or the API was added. The last version increases were: -libavcodec: 2015-08-28 -libavdevice: 2015-08-28 -libavfilter: 2015-08-28 -libavformat: 2015-08-28 -libavresample: 2015-08-28 -libpostproc: 2015-08-28 -libswresample: 2015-08-28 -libswscale: 2015-08-28 -libavutil: 2015-08-28 +libavcodec: 2017-10-21 +libavdevice: 2017-10-21 +libavfilter: 2017-10-21 +libavformat: 2017-10-21 +libavresample: 2017-10-21 +libpostproc: 2017-10-21 +libswresample: 2017-10-21 +libswscale: 2017-10-21 +libavutil: 2017-10-21 API changes, most recent first: +-------- 8< --------- FFmpeg 4.0 was cut here -------- 8< --------- + +2018-04-03 - d6fc031caf - lavu 56.13.100 - pixdesc.h + Deprecate AV_PIX_FMT_FLAG_PSEUDOPAL and make allocating a pseudo palette + optional for API users (see AV_PIX_FMT_FLAG_PSEUDOPAL doxygen for details). + +2018-04-01 - 860086ee16 - lavc 58.17.100 - avcodec.h + Add av_packet_make_refcounted(). + +2018-04-01 - f1805d160d - lavfi 7.14.100 - avfilter.h + Deprecate use of avfilter_register(), avfilter_register_all(), + avfilter_next(). Add av_filter_iterate(). + +2018-03-25 - b7d0d912ef - lavc 58.16.100 - avcodec.h + Add FF_SUB_CHARENC_MODE_IGNORE. + +2018-03-23 - db2a7c947e - lavu 56.12.100 - encryption_info.h + Add AVEncryptionInitInfo and AVEncryptionInfo structures to hold new side-data + for encryption info. + +2018-03-21 - f14ca60001 - lavc 58.15.100 - avcodec.h + Add av_packet_make_writable(). + +2018-03-18 - 4b86ac27a0 - lavu 56.11.100 - frame.h + Add AV_FRAME_DATA_QP_TABLE_PROPERTIES and AV_FRAME_DATA_QP_TABLE_DATA. + +2018-03-15 - e0e72539cf - lavu 56.10.100 - opt.h + Add AV_OPT_FLAG_BSF_PARAM + +2018-03-07 - 950170bd3b - lavu 56.9.100 - crc.h + Add AV_CRC_8_EBU crc variant. + +2018-03-07 - 2a0eb86857 - lavc 58.14.100 - mediacodec.h + Change the default behavior of avcodec_flush() on mediacodec + video decoders. To restore the previous behavior, use the new + delay_flush=1 option. + +2018-03-01 - 6731f60598 - lavu 56.8.100 - frame.h + Add av_frame_new_side_data_from_buf(). + +2018-02-15 - 8a8d0b319a + Change av_ripemd_update(), av_murmur3_update() and av_hash_update() length + parameter type to size_t at next major bump. + +2018-02-12 - bcab11a1a2 - lavfi 7.12.100 - avfilter.h + Add AVFilterContext.extra_hw_frames. + +2018-02-12 - d23fff0d8a - lavc 58.11.100 - avcodec.h + Add AVCodecContext.extra_hw_frames. + +2018-02-06 - 0694d87024 - lavf 58.9.100 - avformat.h + Deprecate use of av_register_input_format(), av_register_output_format(), + av_register_all(), av_iformat_next(), av_oformat_next(). + Add av_demuxer_iterate(), and av_muxer_iterate(). + +2018-02-06 - 36c85d6e77 - lavc 58.10.100 - avcodec.h + Deprecate use of avcodec_register(), avcodec_register_all(), + av_codec_next(), av_register_codec_parser(), and av_parser_next(). + Add av_codec_iterate() and av_parser_iterate(). + +2018-02-04 - ff46124b0d - lavf 58.8.100 - avformat.h + Deprecate the current names of the RTSP "timeout", "stimeout", "user-agent" + options. Introduce "listen_timeout" as replacement for the current "timeout" + option, and "user_agent" as replacement for "user-agent". Once the deprecation + is over, the old "timeout" option will be removed, and "stimeout" will be + renamed to "stimeout" (the "timeout" option will essentially change semantics). + +2018-01-28 - ea3672b7d6 - lavf 58.7.100 - avformat.h + Deprecate AVFormatContext filename field which had limited length, use the + new dynamically allocated url field instead. + +2018-01-28 - ea3672b7d6 - lavf 58.7.100 - avformat.h + Add url field to AVFormatContext and add ff_format_set_url helper function. + +2018-01-27 - 6194d7e564 - lavf 58.6.100 - avformat.h + Add AVFMTCTX_UNSEEKABLE (for HLS demuxer). + +2018-01-23 - 9f07cf7c00 - lavu 56.9.100 - aes_ctr.h + Add method to set the 16-byte IV. + +2018-01-16 - 631c56a8e4 - lavf 58.5.100 - avformat.h + Explicitly make avformat_network_init() and avformat_network_deinit() optional. + If these are not called, network initialization and deinitialization is + automatic, and unlike in older versions, fully supported, unless libavformat + is linked to ancient GnuTLS and OpenSSL. + +2018-01-16 - 6512ff72f9 - lavf 58.4.100 - avformat.h + Deprecate AVStream.recommended_encoder_configuration. It was useful only for + FFserver, which has been removed. + +2018-01-05 - 798dcf2432 - lavfi 7.11.101 - avfilter.h + Deprecate avfilter_link_get_channels(). Use av_buffersink_get_channels(). + +2017-01-04 - c29038f304 - lavr 4.0.0 - avresample.h + Deprecate the entire library. Merged years ago to provide compatibility + with Libav, it remained unmaintained by the FFmpeg project and duplicated + functionality provided by libswresample. + + In order to improve consistency and reduce attack surface, it has been deprecated. + Users of this library are asked to migrate to libswresample, which, as well as + providing more functionality, is faster and has higher accuracy. + +2017-12-26 - a04c2c707d - lavc 58.9.100 - avcodec.h + Deprecate av_lockmgr_register(). You need to build FFmpeg with threading + support enabled to get basic thread-safety (which is the default build + configuration). + +2017-12-24 - 8b81eabe57 - lavu 56.7.100 - cpu.h + AVX-512 flags added. + +2017-12-16 - 8bf4e6d3ce - lavc 58.8.100 - avcodec.h + The MediaCodec decoders now support AVCodecContext.hw_device_ctx. + +2017-12-16 - e4d9f05ca7 - lavu 56.6.100 - hwcontext.h hwcontext_mediacodec.h + Add AV_HWDEVICE_TYPE_MEDIACODEC and a new installed header with + MediaCodec-specific hwcontext definitions. + +2017-12-14 - b945fed629 - lavc 58.7.100 - avcodec.h + Add AV_CODEC_CAP_HARDWARE, AV_CODEC_CAP_HYBRID, and AVCodec.wrapper_name, + and mark all AVCodecs accordingly. + +2017-11-29 - d268094f88 - lavu 56.4.100 / 56.7.0 - stereo3d.h + Add view field to AVStereo3D structure and AVStereo3DView enum. + +2017-11-26 - 3a71bcc213 - lavc 58.6.100 - avcodec.h + Add const to AVCodecContext.hwaccel. + +2017-11-26 - 3536a3efb9 - lavc 58.5.100 - avcodec.h + Deprecate user visibility of the AVHWAccel structure and the functions + av_register_hwaccel() and av_hwaccel_next(). + +2017-11-26 - 24cc0a53e9 - lavc 58.4.100 - avcodec.h + Add AVCodecHWConfig and avcodec_get_hw_config(). + +2017-11-22 - 3650cb2dfa - lavu 56.3.100 - opencl.h + Remove experimental OpenCL API (av_opencl_*). + +2017-11-22 - b25d8ef0a7 - lavu 56.2.100 - hwcontext.h hwcontext_opencl.h + Add AV_HWDEVICE_TYPE_OPENCL and a new installed header with + OpenCL-specific hwcontext definitions. + +2017-11-22 - a050f56c09 - lavu 56.1.100 - pixfmt.h + Add AV_PIX_FMT_OPENCL. + +2017-11-11 - 48e4eda11d - lavc 58.3.100 - avcodec.h + Add avcodec_get_hw_frames_parameters(). + -------- 8< --------- FFmpeg 3.4 was cut here -------- 8< --------- 2017-09-28 - b6cf66ae1c - lavc 57.106.104 - avcodec.h @@ -742,7 +889,7 @@ API changes, most recent first: Add av_opt_get_dict_val/set_dict_val with AV_OPT_TYPE_DICT to support dictionary types being set as options. -2014-08-13 - afbd4b8 - lavf 56.01.0 - avformat.h +2014-08-13 - afbd4b7e09 - lavf 56.01.0 - avformat.h Add AVFormatContext.event_flags and AVStream.event_flags for signaling to the user when events happen in the file/stream. @@ -759,7 +906,7 @@ API changes, most recent first: 2014-08-08 - 5c3c671 - lavf 55.53.100 - avio.h Add avio_feof() and deprecate url_feof(). -2014-08-07 - bb78903 - lsws 2.1.3 - swscale.h +2014-08-07 - bb789016d4 - lsws 2.1.3 - swscale.h sws_getContext is not going to be removed in the future. 2014-08-07 - a561662 / ad1ee5f - lavc 55.73.101 / 55.57.3 - avcodec.h diff --git a/doc/Doxyfile b/doc/Doxyfile index 0891899505ce1..ccec314d3e40d 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = FFmpeg # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = +PROJECT_NUMBER = 4.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/doc/bitstream_filters.texi b/doc/bitstream_filters.texi index 2dffe021f9296..7322af6550d5c 100644 --- a/doc/bitstream_filters.texi +++ b/doc/bitstream_filters.texi @@ -50,21 +50,22 @@ DTS-HD. Add extradata to the beginning of the filtered packets. +@table @option +@item freq The additional argument specifies which packets should be filtered. It accepts the values: @table @samp -@item a -add extradata to all key packets, but only if @var{local_header} is -set in the @option{flags2} codec context field - @item k +@item keyframe add extradata to all key packets @item e +@item all add extradata to all packets @end table +@end table -If not specified it is assumed @samp{k}. +If not specified it is assumed @samp{e}. For example the following @command{ffmpeg} command forces a global header (thus disabling individual packet headers) in the H.264 packets @@ -74,6 +75,10 @@ the header stored in extradata to the key packets: ffmpeg -i INPUT -map 0 -flags:v +global_header -c:v libx264 -bsf:v dump_extra out.ts @end example +@section eac3_core + +Extract the core from a E-AC-3 stream, dropping extra channels. + @section extract_extradata Extract the in-band extradata. @@ -92,6 +97,126 @@ When this option is enabled, the long-term headers are removed from the bitstream after extraction. @end table +@section filter_units + +Remove units with types in or not in a given set from the stream. + +@table @option +@item pass_types +List of unit types or ranges of unit types to pass through while removing +all others. This is specified as a '|'-separated list of unit type values +or ranges of values with '-'. + +@item remove_types +Identical to @option{pass_types}, except the units in the given set +removed and all others passed through. +@end table + +Extradata is unchanged by this transformation, but note that if the stream +contains inline parameter sets then the output may be unusable if they are +removed. + +For example, to remove all non-VCL NAL units from an H.264 stream: +@example +ffmpeg -i INPUT -c:v copy -bsf:v 'filter_units=pass_types=1-5' OUTPUT +@end example + +To remove all AUDs, SEI and filler from an H.265 stream: +@example +ffmpeg -i INPUT -c:v copy -bsf:v 'filter_units=remove_types=35|38-40' OUTPUT +@end example + +@section hapqa_extract + +Extract Rgb or Alpha part of an HAPQA file, without recompression, in order to create an HAPQ or an HAPAlphaOnly file. + +@table @option +@item texture +Specifies the texture to keep. + +@table @option +@item color +@item alpha +@end table + +@end table + +Convert HAPQA to HAPQ +@example +ffmpeg -i hapqa_inputfile.mov -c copy -bsf:v hapqa_extract=texture=color -tag:v HapY -metadata:s:v:0 encoder="HAPQ" hapq_file.mov +@end example + +Convert HAPQA to HAPAlphaOnly +@example +ffmpeg -i hapqa_inputfile.mov -c copy -bsf:v hapqa_extract=texture=alpha -tag:v HapA -metadata:s:v:0 encoder="HAPAlpha Only" hapalphaonly_file.mov +@end example + +@section h264_metadata + +Modify metadata embedded in an H.264 stream. + +@table @option +@item aud +Insert or remove AUD NAL units in all access units of the stream. + +@table @samp +@item insert +@item remove +@end table + +@item sample_aspect_ratio +Set the sample aspect ratio of the stream in the VUI parameters. + +@item video_format +@item video_full_range_flag +Set the video format in the stream (see H.264 section E.2.1 and +table E-2). + +@item colour_primaries +@item transfer_characteristics +@item matrix_coefficients +Set the colour description in the stream (see H.264 section E.2.1 +and tables E-3, E-4 and E-5). + +@item chroma_sample_loc_type +Set the chroma sample location in the stream (see H.264 section +E.2.1 and figure E-1). + +@item tick_rate +Set the tick rate (num_units_in_tick / time_scale) in the VUI +parameters. This is the smallest time unit representable in the +stream, and in many cases represents the field rate of the stream +(double the frame rate). +@item fixed_frame_rate_flag +Set whether the stream has fixed framerate - typically this indicates +that the framerate is exactly half the tick rate, but the exact +meaning is dependent on interlacing and the picture structure (see +H.264 section E.2.1 and table E-6). + +@item crop_left +@item crop_right +@item crop_top +@item crop_bottom +Set the frame cropping offsets in the SPS. These values will replace +the current ones if the stream is already cropped. + +These fields are set in pixels. Note that some sizes may not be +representable if the chroma is subsampled or the stream is interlaced +(see H.264 section 7.4.2.1.1). + +@item sei_user_data +Insert a string as SEI unregistered user data. The argument must +be of the form @emph{UUID+string}, where the UUID is as hex digits +possibly separated by hyphens, and the string can be anything. + +For example, @samp{086f3693-b7b3-4f2c-9653-21492feee5b8+hello} will +insert the string ``hello'' associated with the given UUID. + +@item delete_filler +Deletes both filler NAL units and filler SEI messages. + +@end table + @section h264_mp4toannexb Convert an H.264 bitstream from length prefixed mode to start code @@ -111,6 +236,69 @@ ffmpeg -i INPUT.mp4 -codec copy -bsf:v h264_mp4toannexb OUTPUT.ts Please note that this filter is auto-inserted for MPEG-TS (muxer @code{mpegts}) and raw H.264 (muxer @code{h264}) output formats. +@section h264_redundant_pps + +This applies a specific fixup to some Blu-ray streams which contain +redundant PPSs modifying irrelevant parameters of the stream which +confuse other transformations which require correct extradata. + +A new single global PPS is created, and all of the redundant PPSs +within the stream are removed. + +@section hevc_metadata + +Modify metadata embedded in an HEVC stream. + +@table @option +@item aud +Insert or remove AUD NAL units in all access units of the stream. + +@table @samp +@item insert +@item remove +@end table + +@item sample_aspect_ratio +Set the sample aspect ratio in the stream in the VUI parameters. + +@item video_format +@item video_full_range_flag +Set the video format in the stream (see H.265 section E.3.1 and +table E.2). + +@item colour_primaries +@item transfer_characteristics +@item matrix_coefficients +Set the colour description in the stream (see H.265 section E.3.1 +and tables E.3, E.4 and E.5). + +@item chroma_sample_loc_type +Set the chroma sample location in the stream (see H.265 section +E.3.1 and figure E.1). + +@item tick_rate +Set the tick rate in the VPS and VUI parameters (num_units_in_tick / +time_scale). Combined with @option{num_ticks_poc_diff_one}, this can +set a constant framerate in the stream. Note that it is likely to be +overridden by container parameters when the stream is in a container. + +@item num_ticks_poc_diff_one +Set poc_proportional_to_timing_flag in VPS and VUI and use this value +to set num_ticks_poc_diff_one_minus1 (see H.265 sections 7.4.3.1 and +E.3.1). Ignored if @option{tick_rate} is not also set. + +@item crop_left +@item crop_right +@item crop_top +@item crop_bottom +Set the conformance window cropping offsets in the SPS. These values +will replace the current ones if the stream is already cropped. + +These fields are set in pixels. Note that some sizes may not be +representable if the chroma is subsampled (H.265 section 7.4.3.2.1). + +@end table + @section hevc_mp4toannexb Convert an HEVC/H.265 bitstream from length prefixed mode to start code @@ -198,6 +386,42 @@ See also the @ref{text2movsub} filter. Decompress non-standard compressed MP3 audio headers. +@section mpeg2_metadata + +Modify metadata embedded in an MPEG-2 stream. + +@table @option +@item display_aspect_ratio +Set the display aspect ratio in the stream. + +The following fixed values are supported: +@table @option +@item 4/3 +@item 16/9 +@item 221/100 +@end table +Any other value will result in square pixels being signalled instead +(see H.262 section 6.3.3 and table 6-3). + +@item frame_rate +Set the frame rate in the stream. This is constructed from a table +of known values combined with a small multiplier and divisor - if +the supplied value is not exactly representable, the nearest +representable value will be used instead (see H.262 section 6.3.3 +and table 6-4). + +@item video_format +Set the video format in the stream (see H.262 section 6.3.6 and +table 6-6). + +@item colour_primaries +@item transfer_characteristics +@item matrix_coefficients +Set the colour description in the stream (see H.262 section 6.3.6 +and tables 6-7, 6-8 and 6-9). + +@end table + @section mpeg4_unpack_bframes Unpack DivX-style packed B-frames. @@ -275,6 +499,14 @@ codec) with metadata headers. See also the @ref{mov2textsub} filter. +@section trace_headers + +Log trace output containing all syntax elements in the coded stream +headers (everything above the level of individual coded blocks). +This can be useful for debugging low-level stream issues. + +Supports H.264, H.265 and MPEG-2. + @section vp9_superframe Merge VP9 invisible (alt-ref) frames back into VP9 superframes. This diff --git a/doc/codecs.texi b/doc/codecs.texi index 40f64fe4c88b8..c9b9a1136dceb 100644 --- a/doc/codecs.texi +++ b/doc/codecs.texi @@ -44,12 +44,6 @@ Use 1/4 pel motion compensation. Use loop filter. @item qscale Use fixed qscale. -@item gmc -Use gmc. -@item mv0 -Always try a mb with mv=<0,0>. -@item input_preserved - @item pass1 Use internal 2pass ratecontrol in first pass mode. @item pass2 @@ -62,8 +56,6 @@ Do not draw edges. Set error[?] variables during encoding. @item truncated -@item naq -Normalize adaptive quantization. @item ildct Use interlaced DCT. @item low_delay @@ -475,8 +467,6 @@ rate control macroblock (MB) type @item qp per-block quantization parameter (QP) -@item mv -motion vector @item dct_coeff @item green_metadata @@ -486,18 +476,12 @@ display complexity metadata for the upcoming frame, GoP or for a given duration. @item startcode -@item pts - @item er error recognition @item mmco memory management control operations (H.264) @item bugs -@item vis_qp -visualize quantization parameter (QP), lower QP are tinted greener -@item vis_mb_type -visualize block types @item buffers picture buffer allocations @item thread_ops @@ -506,21 +490,6 @@ threading operations skip motion compensation @end table -@item vismv @var{integer} (@emph{decoding,video}) -Visualize motion vectors (MVs). - -This option is deprecated, see the codecview filter instead. - -Possible values: -@table @samp -@item pf -forward predicted MVs of P-frames -@item bf -forward predicted MVs of B-frames -@item bb -backward predicted MVs of B-frames -@end table - @item cmp @var{integer} (@emph{encoding,video}) Set full pel me compare function. @@ -757,8 +726,6 @@ Set context model. @item slice_flags @var{integer} -@item xvmc_acceleration @var{integer} - @item mbd @var{integer} (@emph{encoding,video}) Set macroblock decision algorithm (high quality mode). diff --git a/doc/decoders.texi b/doc/decoders.texi index d149d2bea5142..a9510bdf02d19 100644 --- a/doc/decoders.texi +++ b/doc/decoders.texi @@ -25,13 +25,6 @@ enabled decoders. A description of some of the currently available video decoders follows. -@section hevc - -HEVC / H.265 decoder. - -Note: the @option{skip_loop_filter} option has effect only at level -@code{all}. - @section rawvideo Raw video decoder. diff --git a/doc/demuxers.texi b/doc/demuxers.texi index 73dc0feec194a..e7c2abce57d7b 100644 --- a/doc/demuxers.texi +++ b/doc/demuxers.texi @@ -244,6 +244,16 @@ file subdir/file-2.wav @end example @end itemize +@section dash + +Dynamic Adaptive Streaming over HTTP demuxer. + +This demuxer presents all AVStreams found in the manifest. +By setting the discard flags on AVStreams the caller can decide +which streams to actually receive. +Each stream mirrors the @code{id} and @code{bandwidth} properties from the +@code{} as metadata keys named "id" and "variant_bitrate" respectively. + @section flv, live_flv Adobe Flash Video Format demuxer. @@ -316,6 +326,14 @@ segment index to start live streams at (negative values are from the end). @item max_reload Maximum number of times a insufficient list is attempted to be reloaded. Default value is 1000. + +@item http_persistent +Use persistent HTTP connections. Applicable only for HTTP streams. +Enabled by default. + +@item http_multiple +Use multiple HTTP connections for downloading HTTP segments. +Enabled by default for HTTP/1.1 servers. @end table @section image2 diff --git a/doc/developer.texi b/doc/developer.texi index 98540c8f992ca..a0eeefe242dc4 100644 --- a/doc/developer.texi +++ b/doc/developer.texi @@ -10,9 +10,7 @@ @contents -@chapter Developers Guide - -@section Notes for external developers +@chapter Notes for external developers This document is mostly useful for internal FFmpeg developers. External developers who need to use the API in their application should @@ -30,15 +28,13 @@ For more detailed legal information about the use of FFmpeg in external programs read the @file{LICENSE} file in the source tree and consult @url{https://ffmpeg.org/legal.html}. -@section Contributing +@chapter Contributing -There are 3 ways by which code gets into FFmpeg. +There are 2 ways by which code gets into FFmpeg: @itemize @bullet -@item Submitting patches to the main developer mailing list. +@item Submitting patches to the ffmpeg-devel mailing list. See @ref{Submitting patches} for details. @item Directly committing changes to the main tree. -@item Committing changes to a git clone, for example on github.com or - gitorious.org. And asking us to merge these changes. @end itemize Whichever way, changes should be reviewed by the maintainer of the code @@ -47,9 +43,9 @@ The developer making the commit and the author are responsible for their changes and should try to fix issues their commit causes. @anchor{Coding Rules} -@section Coding Rules +@chapter Coding Rules -@subsection Code formatting conventions +@section Code formatting conventions There are the following guidelines regarding the indentation in files: @@ -74,7 +70,7 @@ The presentation is one inspired by 'indent -i4 -kr -nut'. The main priority in FFmpeg is simplicity and small code size in order to minimize the bug count. -@subsection Comments +@section Comments Use the JavaDoc/Doxygen format (see examples below) so that code documentation can be generated automatically. All nontrivial functions should have a comment above them explaining what the function does, even if it is just one sentence. @@ -114,7 +110,7 @@ int myfunc(int my_parameter) ... @end example -@subsection C language features +@section C language features FFmpeg is programmed in the ISO C90 language with a few additional features from ISO C99, namely: @@ -160,7 +156,7 @@ mixing statements and declarations; GCC statement expressions (@samp{(x = (@{ int y = 4; y; @})}). @end itemize -@subsection Naming conventions +@section Naming conventions All names should be composed with underscores (_), not CamelCase. For example, @samp{avfilter_get_video_buffer} is an acceptable function name and @samp{AVFilterGetVideo} is not. The exception from this are type names, like @@ -184,7 +180,7 @@ e.g. @samp{ff_w64_demuxer}. @item For variables and functions visible outside of file scope, used internally across multiple libraries, use @code{avpriv_} as prefix, for example, -@samp{avpriv_aac_parse_header}. +@samp{avpriv_report_missing_feature}. @item Each library has its own prefix for public symbols, in addition to the @@ -204,7 +200,7 @@ letter as they are reserved by the C standard. Names starting with @code{_} are reserved at the file level and may not be used for externally visible symbols. If in doubt, just avoid names starting with @code{_} altogether. -@subsection Miscellaneous conventions +@section Miscellaneous conventions @itemize @bullet @item @@ -216,7 +212,7 @@ Casts should be used only when necessary. Unneeded parentheses should also be avoided if they don't make the code easier to understand. @end itemize -@subsection Editor configuration +@section Editor configuration In order to configure Vim to follow FFmpeg formatting conventions, paste the following snippet into your @file{.vimrc}: @example @@ -249,9 +245,9 @@ For Emacs, add these roughly equivalent lines to your @file{.emacs.d/init.el}: (setq c-default-style "ffmpeg") @end lisp -@section Development Policy +@chapter Development Policy -@subsection Patches/Committing +@section Patches/Committing @subheading Licenses for patches must be compatible with FFmpeg. Contributions should be licensed under the @uref{http://www.gnu.org/licenses/lgpl-2.1.html, LGPL 2.1}, @@ -350,7 +346,7 @@ time-frame (12h for build failures and security fixes, 3 days small changes, 1 week for big patches) then commit your patch if you think it is OK. Also note, the maintainer can simply ask for more time to review! -@subsection Code +@section Code @subheading API/ABI changes should be discussed before they are made. Do not change behavior of the programs (renaming options etc) or public API or ABI without first discussing it on the ffmpeg-devel mailing list. @@ -381,12 +377,29 @@ Never write to unallocated memory, never write over the end of arrays, always check values read from some untrusted source before using them as array index or other risky things. -@subsection Documentation/Other +@section Documentation/Other +@subheading Subscribe to the ffmpeg-devel mailing list. +It is important to be subscribed to the +@uref{https://lists.ffmpeg.org/mailman/listinfo/ffmpeg-devel, ffmpeg-devel} +mailing list. Almost any non-trivial patch is to be sent there for review. +Other developers may have comments about your contribution. We expect you see +those comments, and to improve it if requested. (N.B. Experienced committers +have other channels, and may sometimes skip review for trivial fixes.) Also, +discussion here about bug fixes and FFmpeg improvements by other developers may +be helpful information for you. Finally, by being a list subscriber, your +contribution will be posted immediately to the list, without the moderation +hold which messages from non-subscribers experience. + +However, it is more important to the project that we receive your patch than +that you be subscribed to the ffmpeg-devel list. If you have a patch, and don't +want to subscribe and discuss the patch, then please do send it to the list +anyway. + @subheading Subscribe to the ffmpeg-cvslog mailing list. -It is important to do this as the diffs of all commits are sent there and -reviewed by all the other developers. Bugs and possible improvements or -general questions regarding commits are discussed there. We expect you to -react if problems with your code are uncovered. +Diffs of all commits are sent to the +@uref{https://lists.ffmpeg.org/mailman/listinfo/ffmpeg-cvslog, ffmpeg-cvslog} +mailing list. Some developers read this list to review all code base changes +from all sources. Subscribing to this list is not mandatory. @subheading Keep the documentation up to date. Update the documentation if you change behavior or add features. If you are @@ -406,7 +419,7 @@ finding a new maintainer and also don't forget to update the @file{MAINTAINERS} We think our rules are not too hard. If you have comments, contact us. -@section Code of conduct +@chapter Code of conduct Be friendly and respectful towards others and third parties. Treat others the way you yourself want to be treated. @@ -436,7 +449,7 @@ Finally, keep in mind the immortal words of Bill and Ted, "Be excellent to each other." @anchor{Submitting patches} -@section Submitting patches +@chapter Submitting patches First, read the @ref{Coding Rules} above if you did not yet, in particular the rules regarding patch submission. @@ -485,7 +498,7 @@ Give us a few days to react. But if some time passes without reaction, send a reminder by email. Your patch should eventually be dealt with. -@section New codecs or formats checklist +@chapter New codecs or formats checklist @enumerate @item @@ -537,7 +550,7 @@ Did you make sure it compiles standalone, i.e. with @end enumerate -@section patch submission checklist +@chapter Patch submission checklist @enumerate @item @@ -547,9 +560,9 @@ Does @code{make fate} pass with the patch applied? Was the patch generated with git format-patch or send-email? @item -Did you sign off your patch? (git commit -s) -See @url{http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=blob_plain;f=Documentation/SubmittingPatches} for the meaning -of sign off. +Did you sign-off your patch? (@code{git commit -s}) +See @uref{https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/Documentation/process/submitting-patches.rst, Sign your work} for the meaning +of @dfn{sign-off}. @item Did you provide a clear git commit log message? @@ -650,7 +663,7 @@ Test your code with valgrind and or Address Sanitizer to ensure it's free of leaks, out of array accesses, etc. @end enumerate -@section Patch review process +@chapter Patch review process All patches posted to ffmpeg-devel will be reviewed, unless they contain a clear note that the patch is not for the git master branch. @@ -681,7 +694,7 @@ to be reviewed, please consider helping to review other patches, that is a great way to get everyone's patches reviewed sooner. @anchor{Regression tests} -@section Regression tests +@chapter Regression tests Before submitting a patch (or committing to the repository), you should at least test that you did not break anything. @@ -692,7 +705,7 @@ Running 'make fate' accomplishes this, please see @url{fate.html} for details. this case, the reference results of the regression tests shall be modified accordingly]. -@subsection Adding files to the fate-suite dataset +@section Adding files to the fate-suite dataset When there is no muxer or encoder available to generate test media for a specific test then the media has to be included in the fate-suite. @@ -703,7 +716,7 @@ Once you have a working fate test and fate sample, provide in the commit message or introductory message for the patch series that you post to the ffmpeg-devel mailing list, a direct link to download the sample media. -@subsection Visualizing Test Coverage +@section Visualizing Test Coverage The FFmpeg build system allows visualizing the test coverage in an easy manner with the coverage tools @code{gcov}/@code{lcov}. This involves @@ -730,7 +743,7 @@ You can use the command @code{make lcov-reset} to reset the coverage measurements. You will need to rerun @code{make lcov} after running a new test. -@subsection Using Valgrind +@section Using Valgrind The configure script provides a shortcut for using valgrind to spot bugs related to memory handling. Just add the option @@ -744,7 +757,7 @@ In case you need finer control over how valgrind is invoked, use the your configure line instead. @anchor{Release process} -@section Release process +@chapter Release process FFmpeg maintains a set of @strong{release branches}, which are the recommended deliverable for system integrators and distributors (such as @@ -776,7 +789,7 @@ adjustments to the symbol versioning file. Please discuss such changes on the @strong{ffmpeg-devel} mailing list in time to allow forward planning. @anchor{Criteria for Point Releases} -@subsection Criteria for Point Releases +@section Criteria for Point Releases Changes that match the following criteria are valid candidates for inclusion into a point release: @@ -800,7 +813,7 @@ point releases of the same release branch. The order for checking the rules is (1 OR 2 OR 3) AND 4. -@subsection Release Checklist +@section Release Checklist The release process involves the following steps: diff --git a/doc/encoders.texi b/doc/encoders.texi index 431777c457859..7b095754d1d98 100644 --- a/doc/encoders.texi +++ b/doc/encoders.texi @@ -64,7 +64,6 @@ to find an optimal combination by adding or subtracting a specific value from all quantizers and adjusting some individual quantizer a little. Will tune itself based on whether @option{aac_is}, @option{aac_ms} and @option{aac_pns} are enabled. -This is the default choice for a coder. @item anmr Average noise to mask ratio (ANMR) trellis-based solution. @@ -77,10 +76,10 @@ Not currently recommended. @item fast Constant quantizer method. -This method sets a constant quantizer for all bands. This is the fastest of all -the methods and has no rate control or support for @option{aac_is} or -@option{aac_pns}. -Not recommended. +Uses a cheaper version of twoloop algorithm that doesn't try to do as many +clever adjustments. Worse with low bitrates (less than 64kbps), but is better +and much faster at higher bitrates. +This is the default choice for a coder @end table @@ -982,6 +981,11 @@ Other values include 0 for mono and stereo, 1 for surround sound with masking and LFE bandwidth optimizations, and 255 for independent streams with an unspecified channel layout. +@item apply_phase_inv (N.A.) (requires libopus >= 1.2) +If set to 0, disables the use of phase inversion for intensity stereo, +improving the quality of mono downmixes, but slightly reducing normal stereo +quality. The default is 1 (phase inversion enabled). + @end table @anchor{libshine} @@ -1681,6 +1685,13 @@ colorspaces: @end table @item row-mt @var{boolean} Enable row based multi-threading. +@item tune-content +Set content type: default (0), screen (1), film (2). +@item corpus-complexity +Corpus VBR mode is a variant of standard VBR where the complexity distribution +midpoint is passed in rather than calculated for a specific clip or chunk. + +The valid range is [0, 10000]. 0 (default) uses standard VBR. @end table @end table @@ -2148,6 +2159,12 @@ Set the x265 preset. @item tune Set the x265 tune parameter. +@item profile +Set profile restrictions. + +@item crf +Set the quality for constant quality mode. + @item forced-idr Normally, when forcing a I-frame type, the encoder can select any type of I-frame. This option forces it to choose an IDR-frame. @@ -2348,6 +2365,11 @@ Never write it. @itemx always Always write it. @end table +@item video_format @var{integer} +Specifies the video_format written into the sequence display extension +indicating the source of the video pictures. The default is @samp{unspecified}, +can be @samp{component}, @samp{pal}, @samp{ntsc}, @samp{secam} or @samp{mac}. +For maximum compatibility, use @samp{component}. @end table @section png diff --git a/doc/examples/Makefile b/doc/examples/Makefile index 58afd71b85bb9..928ff306b356e 100644 --- a/doc/examples/Makefile +++ b/doc/examples/Makefile @@ -19,6 +19,8 @@ EXAMPLES-$(CONFIG_RESAMPLING_AUDIO_EXAMPLE) += resampling_audio EXAMPLES-$(CONFIG_SCALING_VIDEO_EXAMPLE) += scaling_video EXAMPLES-$(CONFIG_TRANSCODE_AAC_EXAMPLE) += transcode_aac EXAMPLES-$(CONFIG_TRANSCODING_EXAMPLE) += transcoding +EXAMPLES-$(CONFIG_VAAPI_ENCODE_EXAMPLE) += vaapi_encode +EXAMPLES-$(CONFIG_VAAPI_TRANSCODE_EXAMPLE) += vaapi_transcode EXAMPLES := $(EXAMPLES-yes:%=doc/examples/%$(PROGSSUF)$(EXESUF)) EXAMPLES_G := $(EXAMPLES-yes:%=doc/examples/%$(PROGSSUF)_g$(EXESUF)) diff --git a/doc/examples/avio_dir_cmd.c b/doc/examples/avio_dir_cmd.c index 50c435cf8f89b..0722bd9ab154c 100644 --- a/doc/examples/avio_dir_cmd.c +++ b/doc/examples/avio_dir_cmd.c @@ -143,8 +143,6 @@ int main(int argc, char *argv[]) return 1; } - /* register codecs and formats and other lavf/lavc components*/ - av_register_all(); avformat_network_init(); op = argv[1]; diff --git a/doc/examples/avio_reading.c b/doc/examples/avio_reading.c index 02474e907af61..cbfeb174b8ce4 100644 --- a/doc/examples/avio_reading.c +++ b/doc/examples/avio_reading.c @@ -44,6 +44,8 @@ static int read_packet(void *opaque, uint8_t *buf, int buf_size) struct buffer_data *bd = (struct buffer_data *)opaque; buf_size = FFMIN(buf_size, bd->size); + if (!buf_size) + return AVERROR_EOF; printf("ptr:%p size:%zu\n", bd->ptr, bd->size); /* copy internal buffer data to buf */ @@ -72,9 +74,6 @@ int main(int argc, char *argv[]) } input_filename = argv[1]; - /* register codecs and formats and other lavf/lavc components*/ - av_register_all(); - /* slurp file content into buffer */ ret = av_file_map(input_filename, &buffer, &buffer_size, 0, NULL); if (ret < 0) diff --git a/doc/examples/decode_audio.c b/doc/examples/decode_audio.c index fb9a9af2f60b0..19dcafd2c82c3 100644 --- a/doc/examples/decode_audio.c +++ b/doc/examples/decode_audio.c @@ -94,9 +94,6 @@ int main(int argc, char **argv) filename = argv[1]; outfilename = argv[2]; - /* register all the codecs */ - avcodec_register_all(); - pkt = av_packet_alloc(); /* find the MPEG audio decoder */ diff --git a/doc/examples/decode_video.c b/doc/examples/decode_video.c index 4377fd49e0dc6..5a9d43f689733 100644 --- a/doc/examples/decode_video.c +++ b/doc/examples/decode_video.c @@ -101,8 +101,6 @@ int main(int argc, char **argv) filename = argv[1]; outfilename = argv[2]; - avcodec_register_all(); - pkt = av_packet_alloc(); if (!pkt) exit(1); diff --git a/doc/examples/demuxing_decoding.c b/doc/examples/demuxing_decoding.c index b1a216abb4cb7..69a31a893519c 100644 --- a/doc/examples/demuxing_decoding.c +++ b/doc/examples/demuxing_decoding.c @@ -252,9 +252,6 @@ int main (int argc, char **argv) video_dst_filename = argv[2]; audio_dst_filename = argv[3]; - /* register all formats and codecs */ - av_register_all(); - /* open input file, and allocate format context */ if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) { fprintf(stderr, "Could not open source file %s\n", src_filename); diff --git a/doc/examples/encode_audio.c b/doc/examples/encode_audio.c index d1ef105d9dabd..ab3586be7fd6e 100644 --- a/doc/examples/encode_audio.c +++ b/doc/examples/encode_audio.c @@ -138,9 +138,6 @@ int main(int argc, char **argv) } filename = argv[1]; - /* register all the codecs */ - avcodec_register_all(); - /* find the MP2 encoder */ codec = avcodec_find_encoder(AV_CODEC_ID_MP2); if (!codec) { diff --git a/doc/examples/encode_video.c b/doc/examples/encode_video.c index 8cd13219bb560..6731b2ad19bf1 100644 --- a/doc/examples/encode_video.c +++ b/doc/examples/encode_video.c @@ -84,8 +84,6 @@ int main(int argc, char **argv) filename = argv[1]; codec_name = argv[2]; - avcodec_register_all(); - /* find the mpeg1video encoder */ codec = avcodec_find_encoder_by_name(codec_name); if (!codec) { diff --git a/doc/examples/extract_mvs.c b/doc/examples/extract_mvs.c index 7ae934ead3d51..de31ccd2b9877 100644 --- a/doc/examples/extract_mvs.c +++ b/doc/examples/extract_mvs.c @@ -129,8 +129,6 @@ int main(int argc, char **argv) } src_filename = argv[1]; - av_register_all(); - if (avformat_open_input(&fmt_ctx, src_filename, NULL, NULL) < 0) { fprintf(stderr, "Could not open source file %s\n", src_filename); exit(1); diff --git a/doc/examples/filter_audio.c b/doc/examples/filter_audio.c index 01761dcee4504..1611e3d952e5b 100644 --- a/doc/examples/filter_audio.c +++ b/doc/examples/filter_audio.c @@ -64,13 +64,13 @@ static int init_filter_graph(AVFilterGraph **graph, AVFilterContext **src, { AVFilterGraph *filter_graph; AVFilterContext *abuffer_ctx; - AVFilter *abuffer; + const AVFilter *abuffer; AVFilterContext *volume_ctx; - AVFilter *volume; + const AVFilter *volume; AVFilterContext *aformat_ctx; - AVFilter *aformat; + const AVFilter *aformat; AVFilterContext *abuffersink_ctx; - AVFilter *abuffersink; + const AVFilter *abuffersink; AVDictionary *options_dict = NULL; uint8_t options_str[1024]; @@ -289,8 +289,6 @@ int main(int argc, char *argv[]) return 1; } - avfilter_register_all(); - /* Allocate the frame we will be using to store the data. */ frame = av_frame_alloc(); if (!frame) { diff --git a/doc/examples/filtering_audio.c b/doc/examples/filtering_audio.c index 9fc4f1cb7e396..b109dbcb96d70 100644 --- a/doc/examples/filtering_audio.c +++ b/doc/examples/filtering_audio.c @@ -32,7 +32,6 @@ #include #include -#include #include #include #include @@ -90,8 +89,8 @@ static int init_filters(const char *filters_descr) { char args[512]; int ret = 0; - AVFilter *abuffersrc = avfilter_get_by_name("abuffer"); - AVFilter *abuffersink = avfilter_get_by_name("abuffersink"); + const AVFilter *abuffersrc = avfilter_get_by_name("abuffer"); + const AVFilter *abuffersink = avfilter_get_by_name("abuffersink"); AVFilterInOut *outputs = avfilter_inout_alloc(); AVFilterInOut *inputs = avfilter_inout_alloc(); static const enum AVSampleFormat out_sample_fmts[] = { AV_SAMPLE_FMT_S16, -1 }; @@ -229,9 +228,6 @@ int main(int argc, char **argv) exit(1); } - av_register_all(); - avfilter_register_all(); - if ((ret = open_input_file(argv[1])) < 0) goto end; if ((ret = init_filters(filter_descr)) < 0) diff --git a/doc/examples/filtering_video.c b/doc/examples/filtering_video.c index 4e09c6fba4729..ed4e7bbd81d2d 100644 --- a/doc/examples/filtering_video.c +++ b/doc/examples/filtering_video.c @@ -32,7 +32,6 @@ #include #include -#include #include #include #include @@ -93,8 +92,8 @@ static int init_filters(const char *filters_descr) { char args[512]; int ret = 0; - AVFilter *buffersrc = avfilter_get_by_name("buffer"); - AVFilter *buffersink = avfilter_get_by_name("buffersink"); + const AVFilter *buffersrc = avfilter_get_by_name("buffer"); + const AVFilter *buffersink = avfilter_get_by_name("buffersink"); AVFilterInOut *outputs = avfilter_inout_alloc(); AVFilterInOut *inputs = avfilter_inout_alloc(); AVRational time_base = fmt_ctx->streams[video_stream_index]->time_base; @@ -223,9 +222,6 @@ int main(int argc, char **argv) exit(1); } - av_register_all(); - avfilter_register_all(); - if ((ret = open_input_file(argv[1])) < 0) goto end; if ((ret = init_filters(filter_descr)) < 0) diff --git a/doc/examples/http_multiclient.c b/doc/examples/http_multiclient.c index e2c2201a08f36..831e89c60a496 100644 --- a/doc/examples/http_multiclient.c +++ b/doc/examples/http_multiclient.c @@ -114,7 +114,6 @@ int main(int argc, char **argv) in_uri = argv[1]; out_uri = argv[2]; - av_register_all(); avformat_network_init(); if ((ret = av_dict_set(&options, "listen", "2", 0)) < 0) { diff --git a/doc/examples/hw_decode.c b/doc/examples/hw_decode.c index 9c7adbf51a072..77ae8df35b5af 100644 --- a/doc/examples/hw_decode.c +++ b/doc/examples/hw_decode.c @@ -44,34 +44,6 @@ static AVBufferRef *hw_device_ctx = NULL; static enum AVPixelFormat hw_pix_fmt; static FILE *output_file = NULL; -static enum AVPixelFormat find_fmt_by_hw_type(const enum AVHWDeviceType type) -{ - enum AVPixelFormat fmt; - - switch (type) { - case AV_HWDEVICE_TYPE_VAAPI: - fmt = AV_PIX_FMT_VAAPI; - break; - case AV_HWDEVICE_TYPE_DXVA2: - fmt = AV_PIX_FMT_DXVA2_VLD; - break; - case AV_HWDEVICE_TYPE_D3D11VA: - fmt = AV_PIX_FMT_D3D11; - break; - case AV_HWDEVICE_TYPE_VDPAU: - fmt = AV_PIX_FMT_VDPAU; - break; - case AV_HWDEVICE_TYPE_VIDEOTOOLBOX: - fmt = AV_PIX_FMT_VIDEOTOOLBOX; - break; - default: - fmt = AV_PIX_FMT_NONE; - break; - } - - return fmt; -} - static int hw_decoder_init(AVCodecContext *ctx, const enum AVHWDeviceType type) { int err = 0; @@ -114,7 +86,7 @@ static int decode_write(AVCodecContext *avctx, AVPacket *packet) return ret; } - while (ret >= 0) { + while (1) { if (!(frame = av_frame_alloc()) || !(sw_frame = av_frame_alloc())) { fprintf(stderr, "Can not alloc frame\n"); ret = AVERROR(ENOMEM); @@ -166,13 +138,10 @@ static int decode_write(AVCodecContext *avctx, AVPacket *packet) fail: av_frame_free(&frame); av_frame_free(&sw_frame); - if (buffer) - av_freep(&buffer); + av_freep(&buffer); if (ret < 0) return ret; } - - return 0; } int main(int argc, char *argv[]) @@ -184,18 +153,20 @@ int main(int argc, char *argv[]) AVCodec *decoder = NULL; AVPacket packet; enum AVHWDeviceType type; + int i; if (argc < 4) { - fprintf(stderr, "Usage: %s \n", argv[0]); + fprintf(stderr, "Usage: %s \n", argv[0]); return -1; } - av_register_all(); - type = av_hwdevice_find_type_by_name(argv[1]); - hw_pix_fmt = find_fmt_by_hw_type(type); - if (hw_pix_fmt == -1) { - fprintf(stderr, "Cannot support '%s' in this example.\n", argv[1]); + if (type == AV_HWDEVICE_TYPE_NONE) { + fprintf(stderr, "Device type %s is not supported.\n", argv[1]); + fprintf(stderr, "Available device types:"); + while((type = av_hwdevice_iterate_types(type)) != AV_HWDEVICE_TYPE_NONE) + fprintf(stderr, " %s", av_hwdevice_get_type_name(type)); + fprintf(stderr, "\n"); return -1; } @@ -218,6 +189,20 @@ int main(int argc, char *argv[]) } video_stream = ret; + for (i = 0;; i++) { + const AVCodecHWConfig *config = avcodec_get_hw_config(decoder, i); + if (!config) { + fprintf(stderr, "Decoder %s does not support device type %s.\n", + decoder->name, av_hwdevice_get_type_name(type)); + return -1; + } + if (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX && + config->device_type == type) { + hw_pix_fmt = config->pix_fmt; + break; + } + } + if (!(decoder_ctx = avcodec_alloc_context3(decoder))) return AVERROR(ENOMEM); diff --git a/doc/examples/metadata.c b/doc/examples/metadata.c index f73c2673692c1..e330d077a9393 100644 --- a/doc/examples/metadata.c +++ b/doc/examples/metadata.c @@ -44,7 +44,6 @@ int main (int argc, char **argv) return 1; } - av_register_all(); if ((ret = avformat_open_input(&fmt_ctx, argv[1], NULL, NULL))) return ret; diff --git a/doc/examples/muxing.c b/doc/examples/muxing.c index e1a4770eb1228..08da98e574a91 100644 --- a/doc/examples/muxing.c +++ b/doc/examples/muxing.c @@ -488,9 +488,9 @@ static AVFrame *get_video_frame(OutputStream *ost) } } fill_yuv_image(ost->tmp_frame, ost->next_pts, c->width, c->height); - sws_scale(ost->sws_ctx, - (const uint8_t * const *)ost->tmp_frame->data, ost->tmp_frame->linesize, - 0, c->height, ost->frame->data, ost->frame->linesize); + sws_scale(ost->sws_ctx, (const uint8_t * const *) ost->tmp_frame->data, + ost->tmp_frame->linesize, 0, c->height, ost->frame->data, + ost->frame->linesize); } else { fill_yuv_image(ost->frame, ost->next_pts, c->width, c->height); } @@ -564,9 +564,6 @@ int main(int argc, char **argv) AVDictionary *opt = NULL; int i; - /* Initialize libavcodec, and register all codecs and formats. */ - av_register_all(); - if (argc < 2) { printf("usage: %s output_file\n" "API example program to output a media file with libavformat.\n" diff --git a/doc/examples/qsvdec.c b/doc/examples/qsvdec.c index 46e6ddcb0dc63..7415eefca5b82 100644 --- a/doc/examples/qsvdec.c +++ b/doc/examples/qsvdec.c @@ -150,8 +150,6 @@ int main(int argc, char **argv) int ret, i; - av_register_all(); - if (argc < 3) { fprintf(stderr, "Usage: %s \n", argv[0]); return 1; @@ -210,7 +208,6 @@ int main(int argc, char **argv) video_st->codecpar->extradata_size); decoder_ctx->extradata_size = video_st->codecpar->extradata_size; } - decoder_ctx->refcounted_frames = 1; decoder_ctx->opaque = &decode; decoder_ctx->get_format = get_format; diff --git a/doc/examples/remuxing.c b/doc/examples/remuxing.c index 59594181a7090..9e4d1031b4a59 100644 --- a/doc/examples/remuxing.c +++ b/doc/examples/remuxing.c @@ -65,8 +65,6 @@ int main(int argc, char **argv) in_filename = argv[1]; out_filename = argv[2]; - av_register_all(); - if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) { fprintf(stderr, "Could not open input file '%s'", in_filename); goto end; diff --git a/doc/examples/transcode_aac.c b/doc/examples/transcode_aac.c index 6c2f4fb47560c..e0c76f5b35bec 100644 --- a/doc/examples/transcode_aac.c +++ b/doc/examples/transcode_aac.c @@ -1,4 +1,6 @@ /* + * Copyright (c) 2013-2018 Andreas Unterweger + * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -8,7 +10,7 @@ * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public @@ -18,10 +20,11 @@ /** * @file - * simple audio converter + * Simple audio converter * * @example transcode_aac.c * Convert an input audio file to AAC in an MP4 container using FFmpeg. + * Formats other than MP4 are supported based on the output file extension. * @author Andreas Unterweger (dustsigns@gmail.com) */ @@ -40,12 +43,18 @@ #include "libswresample/swresample.h" -/** The output bit rate in kbit/s */ +/* The output bit rate in bit/s */ #define OUTPUT_BIT_RATE 96000 -/** The number of output channels */ +/* The number of output channels */ #define OUTPUT_CHANNELS 2 -/** Open an input file and the required decoder. */ +/** + * Open an input file and the required decoder. + * @param filename File to be opened + * @param[out] input_format_context Format context of opened file + * @param[out] input_codec_context Codec context of opened file + * @return Error code (0 if successful) + */ static int open_input_file(const char *filename, AVFormatContext **input_format_context, AVCodecContext **input_codec_context) @@ -54,7 +63,7 @@ static int open_input_file(const char *filename, AVCodec *input_codec; int error; - /** Open the input file to read from it. */ + /* Open the input file to read from it. */ if ((error = avformat_open_input(input_format_context, filename, NULL, NULL)) < 0) { fprintf(stderr, "Could not open input file '%s' (error '%s')\n", @@ -63,7 +72,7 @@ static int open_input_file(const char *filename, return error; } - /** Get information on the input file (number of streams etc.). */ + /* Get information on the input file (number of streams etc.). */ if ((error = avformat_find_stream_info(*input_format_context, NULL)) < 0) { fprintf(stderr, "Could not open find stream info (error '%s')\n", av_err2str(error)); @@ -71,7 +80,7 @@ static int open_input_file(const char *filename, return error; } - /** Make sure that there is only one stream in the input file. */ + /* Make sure that there is only one stream in the input file. */ if ((*input_format_context)->nb_streams != 1) { fprintf(stderr, "Expected one audio input stream, but found %d\n", (*input_format_context)->nb_streams); @@ -79,14 +88,14 @@ static int open_input_file(const char *filename, return AVERROR_EXIT; } - /** Find a decoder for the audio stream. */ + /* Find a decoder for the audio stream. */ if (!(input_codec = avcodec_find_decoder((*input_format_context)->streams[0]->codecpar->codec_id))) { fprintf(stderr, "Could not find input codec\n"); avformat_close_input(input_format_context); return AVERROR_EXIT; } - /** allocate a new decoding context */ + /* Allocate a new decoding context. */ avctx = avcodec_alloc_context3(input_codec); if (!avctx) { fprintf(stderr, "Could not allocate a decoding context\n"); @@ -94,7 +103,7 @@ static int open_input_file(const char *filename, return AVERROR(ENOMEM); } - /** initialize the stream parameters with demuxer information */ + /* Initialize the stream parameters with demuxer information. */ error = avcodec_parameters_to_context(avctx, (*input_format_context)->streams[0]->codecpar); if (error < 0) { avformat_close_input(input_format_context); @@ -102,7 +111,7 @@ static int open_input_file(const char *filename, return error; } - /** Open the decoder for the audio stream to use it later. */ + /* Open the decoder for the audio stream to use it later. */ if ((error = avcodec_open2(avctx, input_codec, NULL)) < 0) { fprintf(stderr, "Could not open input codec (error '%s')\n", av_err2str(error)); @@ -111,7 +120,7 @@ static int open_input_file(const char *filename, return error; } - /** Save the decoder context for easier access later. */ + /* Save the decoder context for easier access later. */ *input_codec_context = avctx; return 0; @@ -121,6 +130,11 @@ static int open_input_file(const char *filename, * Open an output file and the required encoder. * Also set some basic encoder parameters. * Some of these parameters are based on the input file's parameters. + * @param filename File to be opened + * @param input_codec_context Codec context of input file + * @param[out] output_format_context Format context of output file + * @param[out] output_codec_context Codec context of output file + * @return Error code (0 if successful) */ static int open_output_file(const char *filename, AVCodecContext *input_codec_context, @@ -133,7 +147,7 @@ static int open_output_file(const char *filename, AVCodec *output_codec = NULL; int error; - /** Open the output file to write to it. */ + /* Open the output file to write to it. */ if ((error = avio_open(&output_io_context, filename, AVIO_FLAG_WRITE)) < 0) { fprintf(stderr, "Could not open output file '%s' (error '%s')\n", @@ -141,32 +155,35 @@ static int open_output_file(const char *filename, return error; } - /** Create a new format context for the output container format. */ + /* Create a new format context for the output container format. */ if (!(*output_format_context = avformat_alloc_context())) { fprintf(stderr, "Could not allocate output format context\n"); return AVERROR(ENOMEM); } - /** Associate the output file (pointer) with the container format context. */ + /* Associate the output file (pointer) with the container format context. */ (*output_format_context)->pb = output_io_context; - /** Guess the desired container format based on the file extension. */ + /* Guess the desired container format based on the file extension. */ if (!((*output_format_context)->oformat = av_guess_format(NULL, filename, NULL))) { fprintf(stderr, "Could not find output file format\n"); goto cleanup; } - av_strlcpy((*output_format_context)->filename, filename, - sizeof((*output_format_context)->filename)); + if (!((*output_format_context)->url = av_strdup(filename))) { + fprintf(stderr, "Could not allocate url.\n"); + error = AVERROR(ENOMEM); + goto cleanup; + } - /** Find the encoder to be used by its name. */ + /* Find the encoder to be used by its name. */ if (!(output_codec = avcodec_find_encoder(AV_CODEC_ID_AAC))) { fprintf(stderr, "Could not find an AAC encoder.\n"); goto cleanup; } - /** Create a new audio stream in the output file container. */ + /* Create a new audio stream in the output file container. */ if (!(stream = avformat_new_stream(*output_format_context, NULL))) { fprintf(stderr, "Could not create new stream\n"); error = AVERROR(ENOMEM); @@ -180,31 +197,27 @@ static int open_output_file(const char *filename, goto cleanup; } - /** - * Set the basic encoder parameters. - * The input file's sample rate is used to avoid a sample rate conversion. - */ + /* Set the basic encoder parameters. + * The input file's sample rate is used to avoid a sample rate conversion. */ avctx->channels = OUTPUT_CHANNELS; avctx->channel_layout = av_get_default_channel_layout(OUTPUT_CHANNELS); avctx->sample_rate = input_codec_context->sample_rate; avctx->sample_fmt = output_codec->sample_fmts[0]; avctx->bit_rate = OUTPUT_BIT_RATE; - /** Allow the use of the experimental AAC encoder */ + /* Allow the use of the experimental AAC encoder. */ avctx->strict_std_compliance = FF_COMPLIANCE_EXPERIMENTAL; - /** Set the sample rate for the container. */ + /* Set the sample rate for the container. */ stream->time_base.den = input_codec_context->sample_rate; stream->time_base.num = 1; - /** - * Some container formats (like MP4) require global headers to be present - * Mark the encoder so that it behaves accordingly. - */ + /* Some container formats (like MP4) require global headers to be present. + * Mark the encoder so that it behaves accordingly. */ if ((*output_format_context)->oformat->flags & AVFMT_GLOBALHEADER) avctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; - /** Open the encoder for the audio stream to use it later. */ + /* Open the encoder for the audio stream to use it later. */ if ((error = avcodec_open2(avctx, output_codec, NULL)) < 0) { fprintf(stderr, "Could not open output codec (error '%s')\n", av_err2str(error)); @@ -217,7 +230,7 @@ static int open_output_file(const char *filename, goto cleanup; } - /** Save the encoder context for easier access later. */ + /* Save the encoder context for easier access later. */ *output_codec_context = avctx; return 0; @@ -230,16 +243,23 @@ static int open_output_file(const char *filename, return error < 0 ? error : AVERROR_EXIT; } -/** Initialize one data packet for reading or writing. */ +/** + * Initialize one data packet for reading or writing. + * @param packet Packet to be initialized + */ static void init_packet(AVPacket *packet) { av_init_packet(packet); - /** Set the packet data and size so that it is recognized as being empty. */ + /* Set the packet data and size so that it is recognized as being empty. */ packet->data = NULL; packet->size = 0; } -/** Initialize one audio frame for reading from the input file */ +/** + * Initialize one audio frame for reading from the input file. + * @param[out] frame Frame to be initialized + * @return Error code (0 if successful) + */ static int init_input_frame(AVFrame **frame) { if (!(*frame = av_frame_alloc())) { @@ -253,6 +273,10 @@ static int init_input_frame(AVFrame **frame) * Initialize the audio resampler based on the input and output codec settings. * If the input and output sample formats differ, a conversion is required * libswresample takes care of this, but requires initialization. + * @param input_codec_context Codec context of the input file + * @param output_codec_context Codec context of the output file + * @param[out] resample_context Resample context for the required conversion + * @return Error code (0 if successful) */ static int init_resampler(AVCodecContext *input_codec_context, AVCodecContext *output_codec_context, @@ -260,7 +284,7 @@ static int init_resampler(AVCodecContext *input_codec_context, { int error; - /** + /* * Create a resampler context for the conversion. * Set the conversion parameters. * Default channel layouts based on the number of channels @@ -279,14 +303,14 @@ static int init_resampler(AVCodecContext *input_codec_context, fprintf(stderr, "Could not allocate resample context\n"); return AVERROR(ENOMEM); } - /** + /* * Perform a sanity check so that the number of converted samples is * not greater than the number of samples to be converted. * If the sample rates differ, this case has to be handled differently */ av_assert0(output_codec_context->sample_rate == input_codec_context->sample_rate); - /** Open the resampler with the specified parameters. */ + /* Open the resampler with the specified parameters. */ if ((error = swr_init(*resample_context)) < 0) { fprintf(stderr, "Could not open resample context\n"); swr_free(resample_context); @@ -295,10 +319,15 @@ static int init_resampler(AVCodecContext *input_codec_context, return 0; } -/** Initialize a FIFO buffer for the audio samples to be encoded. */ +/** + * Initialize a FIFO buffer for the audio samples to be encoded. + * @param[out] fifo Sample buffer + * @param output_codec_context Codec context of the output file + * @return Error code (0 if successful) + */ static int init_fifo(AVAudioFifo **fifo, AVCodecContext *output_codec_context) { - /** Create the FIFO buffer based on the specified output sample format. */ + /* Create the FIFO buffer based on the specified output sample format. */ if (!(*fifo = av_audio_fifo_alloc(output_codec_context->sample_fmt, output_codec_context->channels, 1))) { fprintf(stderr, "Could not allocate FIFO\n"); @@ -307,7 +336,11 @@ static int init_fifo(AVAudioFifo **fifo, AVCodecContext *output_codec_context) return 0; } -/** Write the header of the output file container. */ +/** + * Write the header of the output file container. + * @param output_format_context Format context of the output file + * @return Error code (0 if successful) + */ static int write_output_file_header(AVFormatContext *output_format_context) { int error; @@ -319,20 +352,32 @@ static int write_output_file_header(AVFormatContext *output_format_context) return 0; } -/** Decode one audio frame from the input file. */ +/** + * Decode one audio frame from the input file. + * @param frame Audio frame to be decoded + * @param input_format_context Format context of the input file + * @param input_codec_context Codec context of the input file + * @param[out] data_present Indicates whether data has been decoded + * @param[out] finished Indicates whether the end of file has + * been reached and all data has been + * decoded. If this flag is false, there + * is more data to be decoded, i.e., this + * function has to be called again. + * @return Error code (0 if successful) + */ static int decode_audio_frame(AVFrame *frame, AVFormatContext *input_format_context, AVCodecContext *input_codec_context, int *data_present, int *finished) { - /** Packet used for temporary storage. */ + /* Packet used for temporary storage. */ AVPacket input_packet; int error; init_packet(&input_packet); - /** Read one audio frame from the input file into a temporary packet. */ + /* Read one audio frame from the input file into a temporary packet. */ if ((error = av_read_frame(input_format_context, &input_packet)) < 0) { - /** If we are at the end of the file, flush the decoder below. */ + /* If we are at the end of the file, flush the decoder below. */ if (error == AVERROR_EOF) *finished = 1; else { @@ -342,34 +387,52 @@ static int decode_audio_frame(AVFrame *frame, } } - /** - * Decode the audio frame stored in the temporary packet. - * The input audio stream decoder is used to do this. - * If we are at the end of the file, pass an empty packet to the decoder - * to flush it. - */ - if ((error = avcodec_decode_audio4(input_codec_context, frame, - data_present, &input_packet)) < 0) { - fprintf(stderr, "Could not decode frame (error '%s')\n", + /* Send the audio frame stored in the temporary packet to the decoder. + * The input audio stream decoder is used to do this. */ + if ((error = avcodec_send_packet(input_codec_context, &input_packet)) < 0) { + fprintf(stderr, "Could not send packet for decoding (error '%s')\n", av_err2str(error)); - av_packet_unref(&input_packet); return error; } - /** - * If the decoder has not been flushed completely, we are not finished, - * so that this function has to be called again. - */ - if (*finished && *data_present) - *finished = 0; + /* Receive one frame from the decoder. */ + error = avcodec_receive_frame(input_codec_context, frame); + /* If the decoder asks for more data to be able to decode a frame, + * return indicating that no data is present. */ + if (error == AVERROR(EAGAIN)) { + error = 0; + goto cleanup; + /* If the end of the input file is reached, stop decoding. */ + } else if (error == AVERROR_EOF) { + *finished = 1; + error = 0; + goto cleanup; + } else if (error < 0) { + fprintf(stderr, "Could not decode frame (error '%s')\n", + av_err2str(error)); + goto cleanup; + /* Default case: Return decoded data. */ + } else { + *data_present = 1; + goto cleanup; + } + +cleanup: av_packet_unref(&input_packet); - return 0; + return error; } /** * Initialize a temporary storage for the specified number of audio samples. * The conversion requires temporary storage due to the different format. * The number of audio samples to be allocated is specified in frame_size. + * @param[out] converted_input_samples Array of converted samples. The + * dimensions are reference, channel + * (for multi-channel audio), sample. + * @param output_codec_context Codec context of the output file + * @param frame_size Number of samples to be converted in + * each round + * @return Error code (0 if successful) */ static int init_converted_samples(uint8_t ***converted_input_samples, AVCodecContext *output_codec_context, @@ -377,8 +440,7 @@ static int init_converted_samples(uint8_t ***converted_input_samples, { int error; - /** - * Allocate as many pointers as there are audio channels. + /* Allocate as many pointers as there are audio channels. * Each pointer will later point to the audio samples of the corresponding * channels (although it may be NULL for interleaved formats). */ @@ -388,10 +450,8 @@ static int init_converted_samples(uint8_t ***converted_input_samples, return AVERROR(ENOMEM); } - /** - * Allocate memory for the samples of all channels in one consecutive - * block for convenience. - */ + /* Allocate memory for the samples of all channels in one consecutive + * block for convenience. */ if ((error = av_samples_alloc(*converted_input_samples, NULL, output_codec_context->channels, frame_size, @@ -408,8 +468,15 @@ static int init_converted_samples(uint8_t ***converted_input_samples, /** * Convert the input audio samples into the output sample format. - * The conversion happens on a per-frame basis, the size of which is specified - * by frame_size. + * The conversion happens on a per-frame basis, the size of which is + * specified by frame_size. + * @param input_data Samples to be decoded. The dimensions are + * channel (for multi-channel audio), sample. + * @param[out] converted_data Converted samples. The dimensions are channel + * (for multi-channel audio), sample. + * @param frame_size Number of samples to be converted + * @param resample_context Resample context for the conversion + * @return Error code (0 if successful) */ static int convert_samples(const uint8_t **input_data, uint8_t **converted_data, const int frame_size, @@ -417,7 +484,7 @@ static int convert_samples(const uint8_t **input_data, { int error; - /** Convert the samples using the resampler. */ + /* Convert the samples using the resampler. */ if ((error = swr_convert(resample_context, converted_data, frame_size, input_data , frame_size)) < 0) { @@ -429,23 +496,28 @@ static int convert_samples(const uint8_t **input_data, return 0; } -/** Add converted input audio samples to the FIFO buffer for later processing. */ +/** + * Add converted input audio samples to the FIFO buffer for later processing. + * @param fifo Buffer to add the samples to + * @param converted_input_samples Samples to be added. The dimensions are channel + * (for multi-channel audio), sample. + * @param frame_size Number of samples to be converted + * @return Error code (0 if successful) + */ static int add_samples_to_fifo(AVAudioFifo *fifo, uint8_t **converted_input_samples, const int frame_size) { int error; - /** - * Make the FIFO as large as it needs to be to hold both, - * the old and the new samples. - */ + /* Make the FIFO as large as it needs to be to hold both, + * the old and the new samples. */ if ((error = av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + frame_size)) < 0) { fprintf(stderr, "Could not reallocate FIFO\n"); return error; } - /** Store the new samples in the FIFO buffer. */ + /* Store the new samples in the FIFO buffer. */ if (av_audio_fifo_write(fifo, (void **)converted_input_samples, frame_size) < frame_size) { fprintf(stderr, "Could not write data to FIFO\n"); @@ -455,8 +527,20 @@ static int add_samples_to_fifo(AVAudioFifo *fifo, } /** - * Read one audio frame from the input file, decodes, converts and stores + * Read one audio frame from the input file, decode, convert and store * it in the FIFO buffer. + * @param fifo Buffer used for temporary storage + * @param input_format_context Format context of the input file + * @param input_codec_context Codec context of the input file + * @param output_codec_context Codec context of the output file + * @param resampler_context Resample context for the conversion + * @param[out] finished Indicates whether the end of file has + * been reached and all data has been + * decoded. If this flag is false, + * there is more data to be decoded, + * i.e., this function has to be called + * again. + * @return Error code (0 if successful) */ static int read_decode_convert_and_store(AVAudioFifo *fifo, AVFormatContext *input_format_context, @@ -465,45 +549,41 @@ static int read_decode_convert_and_store(AVAudioFifo *fifo, SwrContext *resampler_context, int *finished) { - /** Temporary storage of the input samples of the frame read from the file. */ + /* Temporary storage of the input samples of the frame read from the file. */ AVFrame *input_frame = NULL; - /** Temporary storage for the converted input samples. */ + /* Temporary storage for the converted input samples. */ uint8_t **converted_input_samples = NULL; - int data_present; + int data_present = 0; int ret = AVERROR_EXIT; - /** Initialize temporary storage for one input frame. */ + /* Initialize temporary storage for one input frame. */ if (init_input_frame(&input_frame)) goto cleanup; - /** Decode one frame worth of audio samples. */ + /* Decode one frame worth of audio samples. */ if (decode_audio_frame(input_frame, input_format_context, input_codec_context, &data_present, finished)) goto cleanup; - /** - * If we are at the end of the file and there are no more samples + /* If we are at the end of the file and there are no more samples * in the decoder which are delayed, we are actually finished. - * This must not be treated as an error. - */ - if (*finished && !data_present) { + * This must not be treated as an error. */ + if (*finished) { ret = 0; goto cleanup; } - /** If there is decoded data, convert and store it */ + /* If there is decoded data, convert and store it. */ if (data_present) { - /** Initialize the temporary storage for the converted input samples. */ + /* Initialize the temporary storage for the converted input samples. */ if (init_converted_samples(&converted_input_samples, output_codec_context, input_frame->nb_samples)) goto cleanup; - /** - * Convert the input samples to the desired output sample format. - * This requires a temporary storage provided by converted_input_samples. - */ + /* Convert the input samples to the desired output sample format. + * This requires a temporary storage provided by converted_input_samples. */ if (convert_samples((const uint8_t**)input_frame->extended_data, converted_input_samples, input_frame->nb_samples, resampler_context)) goto cleanup; - /** Add the converted input samples to the FIFO buffer for later processing. */ + /* Add the converted input samples to the FIFO buffer for later processing. */ if (add_samples_to_fifo(fifo, converted_input_samples, input_frame->nb_samples)) goto cleanup; @@ -524,6 +604,10 @@ static int read_decode_convert_and_store(AVAudioFifo *fifo, /** * Initialize one input frame for writing to the output file. * The frame will be exactly frame_size samples large. + * @param[out] frame Frame to be initialized + * @param output_codec_context Codec context of the output file + * @param frame_size Size of the frame + * @return Error code (0 if successful) */ static int init_output_frame(AVFrame **frame, AVCodecContext *output_codec_context, @@ -531,28 +615,24 @@ static int init_output_frame(AVFrame **frame, { int error; - /** Create a new frame to store the audio samples. */ + /* Create a new frame to store the audio samples. */ if (!(*frame = av_frame_alloc())) { fprintf(stderr, "Could not allocate output frame\n"); return AVERROR_EXIT; } - /** - * Set the frame's parameters, especially its size and format. + /* Set the frame's parameters, especially its size and format. * av_frame_get_buffer needs this to allocate memory for the * audio samples of the frame. * Default channel layouts based on the number of channels - * are assumed for simplicity. - */ + * are assumed for simplicity. */ (*frame)->nb_samples = frame_size; (*frame)->channel_layout = output_codec_context->channel_layout; (*frame)->format = output_codec_context->sample_fmt; (*frame)->sample_rate = output_codec_context->sample_rate; - /** - * Allocate the samples of the created frame. This call will make - * sure that the audio frame can hold as many samples as specified. - */ + /* Allocate the samples of the created frame. This call will make + * sure that the audio frame can hold as many samples as specified. */ if ((error = av_frame_get_buffer(*frame, 0)) < 0) { fprintf(stderr, "Could not allocate output frame samples (error '%s')\n", av_err2str(error)); @@ -563,87 +643,114 @@ static int init_output_frame(AVFrame **frame, return 0; } -/** Global timestamp for the audio frames */ +/* Global timestamp for the audio frames. */ static int64_t pts = 0; -/** Encode one frame worth of audio to the output file. */ +/** + * Encode one frame worth of audio to the output file. + * @param frame Samples to be encoded + * @param output_format_context Format context of the output file + * @param output_codec_context Codec context of the output file + * @param[out] data_present Indicates whether data has been + * encoded + * @return Error code (0 if successful) + */ static int encode_audio_frame(AVFrame *frame, AVFormatContext *output_format_context, AVCodecContext *output_codec_context, int *data_present) { - /** Packet used for temporary storage. */ + /* Packet used for temporary storage. */ AVPacket output_packet; int error; init_packet(&output_packet); - /** Set a timestamp based on the sample rate for the container. */ + /* Set a timestamp based on the sample rate for the container. */ if (frame) { frame->pts = pts; pts += frame->nb_samples; } - /** - * Encode the audio frame and store it in the temporary packet. - * The output audio stream encoder is used to do this. - */ - if ((error = avcodec_encode_audio2(output_codec_context, &output_packet, - frame, data_present)) < 0) { - fprintf(stderr, "Could not encode frame (error '%s')\n", + /* Send the audio frame stored in the temporary packet to the encoder. + * The output audio stream encoder is used to do this. */ + error = avcodec_send_frame(output_codec_context, frame); + /* The encoder signals that it has nothing more to encode. */ + if (error == AVERROR_EOF) { + error = 0; + goto cleanup; + } else if (error < 0) { + fprintf(stderr, "Could not send packet for encoding (error '%s')\n", av_err2str(error)); - av_packet_unref(&output_packet); return error; } - /** Write one audio frame from the temporary packet to the output file. */ - if (*data_present) { - if ((error = av_write_frame(output_format_context, &output_packet)) < 0) { - fprintf(stderr, "Could not write frame (error '%s')\n", - av_err2str(error)); - av_packet_unref(&output_packet); - return error; - } + /* Receive one encoded frame from the encoder. */ + error = avcodec_receive_packet(output_codec_context, &output_packet); + /* If the encoder asks for more data to be able to provide an + * encoded frame, return indicating that no data is present. */ + if (error == AVERROR(EAGAIN)) { + error = 0; + goto cleanup; + /* If the last frame has been encoded, stop encoding. */ + } else if (error == AVERROR_EOF) { + error = 0; + goto cleanup; + } else if (error < 0) { + fprintf(stderr, "Could not encode frame (error '%s')\n", + av_err2str(error)); + goto cleanup; + /* Default case: Return encoded data. */ + } else { + *data_present = 1; + } - av_packet_unref(&output_packet); + /* Write one audio frame from the temporary packet to the output file. */ + if (*data_present && + (error = av_write_frame(output_format_context, &output_packet)) < 0) { + fprintf(stderr, "Could not write frame (error '%s')\n", + av_err2str(error)); + goto cleanup; } - return 0; +cleanup: + av_packet_unref(&output_packet); + return error; } /** * Load one audio frame from the FIFO buffer, encode and write it to the * output file. + * @param fifo Buffer used for temporary storage + * @param output_format_context Format context of the output file + * @param output_codec_context Codec context of the output file + * @return Error code (0 if successful) */ static int load_encode_and_write(AVAudioFifo *fifo, AVFormatContext *output_format_context, AVCodecContext *output_codec_context) { - /** Temporary storage of the output samples of the frame written to the file. */ + /* Temporary storage of the output samples of the frame written to the file. */ AVFrame *output_frame; - /** - * Use the maximum number of possible samples per frame. + /* Use the maximum number of possible samples per frame. * If there is less than the maximum possible frame size in the FIFO - * buffer use this number. Otherwise, use the maximum possible frame size - */ + * buffer use this number. Otherwise, use the maximum possible frame size. */ const int frame_size = FFMIN(av_audio_fifo_size(fifo), output_codec_context->frame_size); int data_written; - /** Initialize temporary storage for one output frame. */ + /* Initialize temporary storage for one output frame. */ if (init_output_frame(&output_frame, output_codec_context, frame_size)) return AVERROR_EXIT; - /** - * Read as many samples from the FIFO buffer as required to fill the frame. - * The samples are stored in the frame temporarily. - */ + /* Read as many samples from the FIFO buffer as required to fill the frame. + * The samples are stored in the frame temporarily. */ if (av_audio_fifo_read(fifo, (void **)output_frame->data, frame_size) < frame_size) { fprintf(stderr, "Could not read data from FIFO\n"); av_frame_free(&output_frame); return AVERROR_EXIT; } - /** Encode one frame worth of audio samples. */ + /* Encode one frame worth of audio samples. */ if (encode_audio_frame(output_frame, output_format_context, output_codec_context, &data_written)) { av_frame_free(&output_frame); @@ -653,7 +760,11 @@ static int load_encode_and_write(AVAudioFifo *fifo, return 0; } -/** Write the trailer of the output file container. */ +/** + * Write the trailer of the output file container. + * @param output_format_context Format context of the output file + * @return Error code (0 if successful) + */ static int write_output_file_trailer(AVFormatContext *output_format_context) { int error; @@ -665,7 +776,6 @@ static int write_output_file_trailer(AVFormatContext *output_format_context) return 0; } -/** Convert an audio file to an AAC file in an MP4 container. */ int main(int argc, char **argv) { AVFormatContext *input_format_context = NULL, *output_format_context = NULL; @@ -674,90 +784,75 @@ int main(int argc, char **argv) AVAudioFifo *fifo = NULL; int ret = AVERROR_EXIT; - if (argc < 3) { + if (argc != 3) { fprintf(stderr, "Usage: %s \n", argv[0]); exit(1); } - /** Register all codecs and formats so that they can be used. */ - av_register_all(); - /** Open the input file for reading. */ + /* Open the input file for reading. */ if (open_input_file(argv[1], &input_format_context, &input_codec_context)) goto cleanup; - /** Open the output file for writing. */ + /* Open the output file for writing. */ if (open_output_file(argv[2], input_codec_context, &output_format_context, &output_codec_context)) goto cleanup; - /** Initialize the resampler to be able to convert audio sample formats. */ + /* Initialize the resampler to be able to convert audio sample formats. */ if (init_resampler(input_codec_context, output_codec_context, &resample_context)) goto cleanup; - /** Initialize the FIFO buffer to store audio samples to be encoded. */ + /* Initialize the FIFO buffer to store audio samples to be encoded. */ if (init_fifo(&fifo, output_codec_context)) goto cleanup; - /** Write the header of the output file container. */ + /* Write the header of the output file container. */ if (write_output_file_header(output_format_context)) goto cleanup; - /** - * Loop as long as we have input samples to read or output samples - * to write; abort as soon as we have neither. - */ + /* Loop as long as we have input samples to read or output samples + * to write; abort as soon as we have neither. */ while (1) { - /** Use the encoder's desired frame size for processing. */ + /* Use the encoder's desired frame size for processing. */ const int output_frame_size = output_codec_context->frame_size; int finished = 0; - /** - * Make sure that there is one frame worth of samples in the FIFO + /* Make sure that there is one frame worth of samples in the FIFO * buffer so that the encoder can do its work. * Since the decoder's and the encoder's frame size may differ, we * need to FIFO buffer to store as many frames worth of input samples - * that they make up at least one frame worth of output samples. - */ + * that they make up at least one frame worth of output samples. */ while (av_audio_fifo_size(fifo) < output_frame_size) { - /** - * Decode one frame worth of audio samples, convert it to the - * output sample format and put it into the FIFO buffer. - */ + /* Decode one frame worth of audio samples, convert it to the + * output sample format and put it into the FIFO buffer. */ if (read_decode_convert_and_store(fifo, input_format_context, input_codec_context, output_codec_context, resample_context, &finished)) goto cleanup; - /** - * If we are at the end of the input file, we continue - * encoding the remaining audio samples to the output file. - */ + /* If we are at the end of the input file, we continue + * encoding the remaining audio samples to the output file. */ if (finished) break; } - /** - * If we have enough samples for the encoder, we encode them. + /* If we have enough samples for the encoder, we encode them. * At the end of the file, we pass the remaining samples to - * the encoder. - */ + * the encoder. */ while (av_audio_fifo_size(fifo) >= output_frame_size || (finished && av_audio_fifo_size(fifo) > 0)) - /** - * Take one frame worth of audio samples from the FIFO buffer, - * encode it and write it to the output file. - */ + /* Take one frame worth of audio samples from the FIFO buffer, + * encode it and write it to the output file. */ if (load_encode_and_write(fifo, output_format_context, output_codec_context)) goto cleanup; - /** - * If we are at the end of the input file and have encoded - * all remaining samples, we can exit this loop and finish. - */ + /* If we are at the end of the input file and have encoded + * all remaining samples, we can exit this loop and finish. */ if (finished) { int data_written; - /** Flush the encoder as it may have delayed frames. */ + /* Flush the encoder as it may have delayed frames. */ do { + data_written = 0; if (encode_audio_frame(NULL, output_format_context, output_codec_context, &data_written)) goto cleanup; @@ -766,7 +861,7 @@ int main(int argc, char **argv) } } - /** Write the trailer of the output file container. */ + /* Write the trailer of the output file container. */ if (write_output_file_trailer(output_format_context)) goto cleanup; ret = 0; diff --git a/doc/examples/transcoding.c b/doc/examples/transcoding.c index fb15a2148d63c..a83fa3a185817 100644 --- a/doc/examples/transcoding.c +++ b/doc/examples/transcoding.c @@ -30,7 +30,6 @@ #include #include -#include #include #include #include @@ -228,8 +227,8 @@ static int init_filter(FilteringContext* fctx, AVCodecContext *dec_ctx, { char args[512]; int ret = 0; - AVFilter *buffersrc = NULL; - AVFilter *buffersink = NULL; + const AVFilter *buffersrc = NULL; + const AVFilter *buffersink = NULL; AVFilterContext *buffersrc_ctx = NULL; AVFilterContext *buffersink_ctx = NULL; AVFilterInOut *outputs = avfilter_inout_alloc(); @@ -518,9 +517,6 @@ int main(int argc, char **argv) return 1; } - av_register_all(); - avfilter_register_all(); - if ((ret = open_input_file(argv[1])) < 0) goto end; if ((ret = open_output_file(argv[2])) < 0) diff --git a/doc/examples/vaapi_encode.c b/doc/examples/vaapi_encode.c new file mode 100644 index 0000000000000..3bdc62bef37da --- /dev/null +++ b/doc/examples/vaapi_encode.c @@ -0,0 +1,222 @@ +/* + * Video Acceleration API (video encoding) encode sample + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Intel VAAPI-accelerated encoding example. + * + * @example vaapi_encode.c + * This example shows how to do VAAPI-accelerated encoding. now only support NV12 + * raw file, usage like: vaapi_encode 1920 1080 input.yuv output.h264 + * + */ + +#include +#include +#include + +#include +#include +#include + +static int width, height; +static AVBufferRef *hw_device_ctx = NULL; + +static int set_hwframe_ctx(AVCodecContext *ctx, AVBufferRef *hw_device_ctx) +{ + AVBufferRef *hw_frames_ref; + AVHWFramesContext *frames_ctx = NULL; + int err = 0; + + if (!(hw_frames_ref = av_hwframe_ctx_alloc(hw_device_ctx))) { + fprintf(stderr, "Failed to create VAAPI frame context.\n"); + return -1; + } + frames_ctx = (AVHWFramesContext *)(hw_frames_ref->data); + frames_ctx->format = AV_PIX_FMT_VAAPI; + frames_ctx->sw_format = AV_PIX_FMT_NV12; + frames_ctx->width = width; + frames_ctx->height = height; + frames_ctx->initial_pool_size = 20; + if ((err = av_hwframe_ctx_init(hw_frames_ref)) < 0) { + fprintf(stderr, "Failed to initialize VAAPI frame context." + "Error code: %s\n",av_err2str(err)); + av_buffer_unref(&hw_frames_ref); + return err; + } + ctx->hw_frames_ctx = av_buffer_ref(hw_frames_ref); + if (!ctx->hw_frames_ctx) + err = AVERROR(ENOMEM); + + av_buffer_unref(&hw_frames_ref); + return err; +} + +static int encode_write(AVCodecContext *avctx, AVFrame *frame, FILE *fout) +{ + int ret = 0; + AVPacket enc_pkt; + + av_init_packet(&enc_pkt); + enc_pkt.data = NULL; + enc_pkt.size = 0; + + if ((ret = avcodec_send_frame(avctx, frame)) < 0) { + fprintf(stderr, "Error code: %s\n", av_err2str(ret)); + goto end; + } + while (1) { + ret = avcodec_receive_packet(avctx, &enc_pkt); + if (ret) + break; + + enc_pkt.stream_index = 0; + ret = fwrite(enc_pkt.data, enc_pkt.size, 1, fout); + av_packet_unref(&enc_pkt); + } + +end: + ret = ((ret == AVERROR(EAGAIN)) ? 0 : -1); + return ret; +} + +int main(int argc, char *argv[]) +{ + int size, err; + FILE *fin = NULL, *fout = NULL; + AVFrame *sw_frame = NULL, *hw_frame = NULL; + AVCodecContext *avctx = NULL; + AVCodec *codec = NULL; + const char *enc_name = "h264_vaapi"; + + if (argc < 5) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return -1; + } + + width = atoi(argv[1]); + height = atoi(argv[2]); + size = width * height; + + if (!(fin = fopen(argv[3], "r"))) { + fprintf(stderr, "Fail to open input file : %s\n", strerror(errno)); + return -1; + } + if (!(fout = fopen(argv[4], "w+b"))) { + fprintf(stderr, "Fail to open output file : %s\n", strerror(errno)); + err = -1; + goto close; + } + + err = av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI, + NULL, NULL, 0); + if (err < 0) { + fprintf(stderr, "Failed to create a VAAPI device. Error code: %s\n", av_err2str(err)); + goto close; + } + + if (!(codec = avcodec_find_encoder_by_name(enc_name))) { + fprintf(stderr, "Could not find encoder.\n"); + err = -1; + goto close; + } + + if (!(avctx = avcodec_alloc_context3(codec))) { + err = AVERROR(ENOMEM); + goto close; + } + + avctx->width = width; + avctx->height = height; + avctx->time_base = (AVRational){1, 25}; + avctx->framerate = (AVRational){25, 1}; + avctx->sample_aspect_ratio = (AVRational){1, 1}; + avctx->pix_fmt = AV_PIX_FMT_VAAPI; + + /* set hw_frames_ctx for encoder's AVCodecContext */ + if ((err = set_hwframe_ctx(avctx, hw_device_ctx)) < 0) { + fprintf(stderr, "Failed to set hwframe context.\n"); + goto close; + } + + if ((err = avcodec_open2(avctx, codec, NULL)) < 0) { + fprintf(stderr, "Cannot open video encoder codec. Error code: %s\n", av_err2str(err)); + goto close; + } + + while (1) { + if (!(sw_frame = av_frame_alloc())) { + err = AVERROR(ENOMEM); + goto close; + } + /* read data into software frame, and transfer them into hw frame */ + sw_frame->width = width; + sw_frame->height = height; + sw_frame->format = AV_PIX_FMT_NV12; + if ((err = av_frame_get_buffer(sw_frame, 32)) < 0) + goto close; + if ((err = fread((uint8_t*)(sw_frame->data[0]), size, 1, fin)) <= 0) + break; + if ((err = fread((uint8_t*)(sw_frame->data[1]), size/2, 1, fin)) <= 0) + break; + + if (!(hw_frame = av_frame_alloc())) { + err = AVERROR(ENOMEM); + goto close; + } + if ((err = av_hwframe_get_buffer(avctx->hw_frames_ctx, hw_frame, 0)) < 0) { + fprintf(stderr, "Error code: %s.\n", av_err2str(err)); + goto close; + } + if (!hw_frame->hw_frames_ctx) { + err = AVERROR(ENOMEM); + goto close; + } + if ((err = av_hwframe_transfer_data(hw_frame, sw_frame, 0)) < 0) { + fprintf(stderr, "Error while transferring frame data to surface." + "Error code: %s.\n", av_err2str(err)); + goto close; + } + + if ((err = (encode_write(avctx, hw_frame, fout))) < 0) { + fprintf(stderr, "Failed to encode.\n"); + goto close; + } + av_frame_free(&hw_frame); + av_frame_free(&sw_frame); + } + + /* flush encoder */ + err = encode_write(avctx, NULL, fout); + if (err == AVERROR_EOF) + err = 0; + +close: + if (fin) + fclose(fin); + if (fout) + fclose(fout); + av_frame_free(&sw_frame); + av_frame_free(&hw_frame); + avcodec_free_context(&avctx); + av_buffer_unref(&hw_device_ctx); + + return err; +} diff --git a/doc/examples/vaapi_transcode.c b/doc/examples/vaapi_transcode.c new file mode 100644 index 0000000000000..649f48b97c308 --- /dev/null +++ b/doc/examples/vaapi_transcode.c @@ -0,0 +1,304 @@ +/* + * Video Acceleration API (video transcoding) transcode sample + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Intel VAAPI-accelerated transcoding example. + * + * @example vaapi_transcode.c + * This example shows how to do VAAPI-accelerated transcoding. + * Usage: vaapi_transcode input_stream codec output_stream + * e.g: - vaapi_transcode input.mp4 h264_vaapi output_h264.mp4 + * - vaapi_transcode input.mp4 vp9_vaapi output_vp9.ivf + */ + +#include +#include + +#include +#include +#include + +static AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL; +static AVBufferRef *hw_device_ctx = NULL; +static AVCodecContext *decoder_ctx = NULL, *encoder_ctx = NULL; +static int video_stream = -1; +static AVStream *ost; +static int initialized = 0; + +static enum AVPixelFormat get_vaapi_format(AVCodecContext *ctx, + const enum AVPixelFormat *pix_fmts) +{ + const enum AVPixelFormat *p; + + for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { + if (*p == AV_PIX_FMT_VAAPI) + return *p; + } + + fprintf(stderr, "Unable to decode this file using VA-API.\n"); + return AV_PIX_FMT_NONE; +} + +static int open_input_file(const char *filename) +{ + int ret; + AVCodec *decoder = NULL; + AVStream *video = NULL; + + if ((ret = avformat_open_input(&ifmt_ctx, filename, NULL, NULL)) < 0) { + fprintf(stderr, "Cannot open input file '%s', Error code: %s\n", + filename, av_err2str(ret)); + return ret; + } + + if ((ret = avformat_find_stream_info(ifmt_ctx, NULL)) < 0) { + fprintf(stderr, "Cannot find input stream information. Error code: %s\n", + av_err2str(ret)); + return ret; + } + + ret = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, &decoder, 0); + if (ret < 0) { + fprintf(stderr, "Cannot find a video stream in the input file. " + "Error code: %s\n", av_err2str(ret)); + return ret; + } + video_stream = ret; + + if (!(decoder_ctx = avcodec_alloc_context3(decoder))) + return AVERROR(ENOMEM); + + video = ifmt_ctx->streams[video_stream]; + if ((ret = avcodec_parameters_to_context(decoder_ctx, video->codecpar)) < 0) { + fprintf(stderr, "avcodec_parameters_to_context error. Error code: %s\n", + av_err2str(ret)); + return ret; + } + + decoder_ctx->hw_device_ctx = av_buffer_ref(hw_device_ctx); + if (!decoder_ctx->hw_device_ctx) { + fprintf(stderr, "A hardware device reference create failed.\n"); + return AVERROR(ENOMEM); + } + decoder_ctx->get_format = get_vaapi_format; + + if ((ret = avcodec_open2(decoder_ctx, decoder, NULL)) < 0) + fprintf(stderr, "Failed to open codec for decoding. Error code: %s\n", + av_err2str(ret)); + + return ret; +} + +static int encode_write(AVFrame *frame) +{ + int ret = 0; + AVPacket enc_pkt; + + av_init_packet(&enc_pkt); + enc_pkt.data = NULL; + enc_pkt.size = 0; + + if ((ret = avcodec_send_frame(encoder_ctx, frame)) < 0) { + fprintf(stderr, "Error during encoding. Error code: %s\n", av_err2str(ret)); + goto end; + } + while (1) { + ret = avcodec_receive_packet(encoder_ctx, &enc_pkt); + if (ret) + break; + + enc_pkt.stream_index = 0; + av_packet_rescale_ts(&enc_pkt, ifmt_ctx->streams[video_stream]->time_base, + ofmt_ctx->streams[0]->time_base); + ret = av_interleaved_write_frame(ofmt_ctx, &enc_pkt); + if (ret < 0) { + fprintf(stderr, "Error during writing data to output file. " + "Error code: %s\n", av_err2str(ret)); + return -1; + } + } + +end: + if (ret == AVERROR_EOF) + return 0; + ret = ((ret == AVERROR(EAGAIN)) ? 0:-1); + return ret; +} + +static int dec_enc(AVPacket *pkt, AVCodec *enc_codec) +{ + AVFrame *frame; + int ret = 0; + + ret = avcodec_send_packet(decoder_ctx, pkt); + if (ret < 0) { + fprintf(stderr, "Error during decoding. Error code: %s\n", av_err2str(ret)); + return ret; + } + + while (ret >= 0) { + if (!(frame = av_frame_alloc())) + return AVERROR(ENOMEM); + + ret = avcodec_receive_frame(decoder_ctx, frame); + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { + av_frame_free(&frame); + return 0; + } else if (ret < 0) { + fprintf(stderr, "Error while decoding. Error code: %s\n", av_err2str(ret)); + goto fail; + } + + if (!initialized) { + /* we need to ref hw_frames_ctx of decoder to initialize encoder's codec. + Only after we get a decoded frame, can we obtain its hw_frames_ctx */ + encoder_ctx->hw_frames_ctx = av_buffer_ref(decoder_ctx->hw_frames_ctx); + if (!encoder_ctx->hw_frames_ctx) { + ret = AVERROR(ENOMEM); + goto fail; + } + /* set AVCodecContext Parameters for encoder, here we keep them stay + * the same as decoder. + * xxx: now the the sample can't handle resolution change case. + */ + encoder_ctx->time_base = av_inv_q(decoder_ctx->framerate); + encoder_ctx->pix_fmt = AV_PIX_FMT_VAAPI; + encoder_ctx->width = decoder_ctx->width; + encoder_ctx->height = decoder_ctx->height; + + if ((ret = avcodec_open2(encoder_ctx, enc_codec, NULL)) < 0) { + fprintf(stderr, "Failed to open encode codec. Error code: %s\n", + av_err2str(ret)); + goto fail; + } + + if (!(ost = avformat_new_stream(ofmt_ctx, enc_codec))) { + fprintf(stderr, "Failed to allocate stream for output format.\n"); + ret = AVERROR(ENOMEM); + goto fail; + } + + ost->time_base = encoder_ctx->time_base; + ret = avcodec_parameters_from_context(ost->codecpar, encoder_ctx); + if (ret < 0) { + fprintf(stderr, "Failed to copy the stream parameters. " + "Error code: %s\n", av_err2str(ret)); + goto fail; + } + + /* write the stream header */ + if ((ret = avformat_write_header(ofmt_ctx, NULL)) < 0) { + fprintf(stderr, "Error while writing stream header. " + "Error code: %s\n", av_err2str(ret)); + goto fail; + } + + initialized = 1; + } + + if ((ret = encode_write(frame)) < 0) + fprintf(stderr, "Error during encoding and writing.\n"); + +fail: + av_frame_free(&frame); + if (ret < 0) + return ret; + } + return 0; +} + +int main(int argc, char **argv) +{ + int ret = 0; + AVPacket dec_pkt; + AVCodec *enc_codec; + + if (argc != 4) { + fprintf(stderr, "Usage: %s \n" + "The output format is guessed according to the file extension.\n" + "\n", argv[0]); + return -1; + } + + ret = av_hwdevice_ctx_create(&hw_device_ctx, AV_HWDEVICE_TYPE_VAAPI, NULL, NULL, 0); + if (ret < 0) { + fprintf(stderr, "Failed to create a VAAPI device. Error code: %s\n", av_err2str(ret)); + return -1; + } + + if ((ret = open_input_file(argv[1])) < 0) + goto end; + + if (!(enc_codec = avcodec_find_encoder_by_name(argv[2]))) { + fprintf(stderr, "Could not find encoder '%s'\n", argv[2]); + ret = -1; + goto end; + } + + if ((ret = (avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, argv[3]))) < 0) { + fprintf(stderr, "Failed to deduce output format from file extension. Error code: " + "%s\n", av_err2str(ret)); + goto end; + } + + if (!(encoder_ctx = avcodec_alloc_context3(enc_codec))) { + ret = AVERROR(ENOMEM); + goto end; + } + + ret = avio_open(&ofmt_ctx->pb, argv[3], AVIO_FLAG_WRITE); + if (ret < 0) { + fprintf(stderr, "Cannot open output file. " + "Error code: %s\n", av_err2str(ret)); + goto end; + } + + /* read all packets and only transcoding video */ + while (ret >= 0) { + if ((ret = av_read_frame(ifmt_ctx, &dec_pkt)) < 0) + break; + + if (video_stream == dec_pkt.stream_index) + ret = dec_enc(&dec_pkt, enc_codec); + + av_packet_unref(&dec_pkt); + } + + /* flush decoder */ + dec_pkt.data = NULL; + dec_pkt.size = 0; + ret = dec_enc(&dec_pkt, enc_codec); + av_packet_unref(&dec_pkt); + + /* flush encoder */ + ret = encode_write(NULL); + + /* write the trailer for output stream */ + av_write_trailer(ofmt_ctx); + +end: + avformat_close_input(&ifmt_ctx); + avformat_close_input(&ofmt_ctx); + avcodec_free_context(&decoder_ctx); + avcodec_free_context(&encoder_ctx); + av_buffer_unref(&hw_device_ctx); + return ret; +} diff --git a/doc/faq.texi b/doc/faq.texi index dcaf89c6d2c5f..73624c647e501 100644 --- a/doc/faq.texi +++ b/doc/faq.texi @@ -501,6 +501,71 @@ ffmpeg -i ega_screen.nut -vf setdar=4/3 ega_screen_anamorphic.nut ffmpeg -i ega_screen.nut -aspect 4/3 -c copy ega_screen_overridden.nut @end example +@anchor{background task} +@section How do I run ffmpeg as a background task? + +ffmpeg normally checks the console input, for entries like "q" to stop +and "?" to give help, while performing operations. ffmpeg does not have a way of +detecting when it is running as a background task. +When it checks the console input, that can cause the process running ffmpeg +in the background to suspend. + +To prevent those input checks, allowing ffmpeg to run as a background task, +use the @url{ffmpeg.html#stdin-option, @code{-nostdin} option} +in the ffmpeg invocation. This is effective whether you run ffmpeg in a shell +or invoke ffmpeg in its own process via an operating system API. + +As an alternative, when you are running ffmpeg in a shell, you can redirect +standard input to @code{/dev/null} (on Linux and Mac OS) +or @code{NUL} (on Windows). You can do this redirect either +on the ffmpeg invocation, or from a shell script which calls ffmpeg. + +For example: + +@example +ffmpeg -nostdin -i INPUT OUTPUT +@end example + +or (on Linux, Mac OS, and other UNIX-like shells): + +@example +ffmpeg -i INPUT OUTPUT ~/tmp/log.txt & +[1] 93352 +% +[1] + suspended (tty output) ffmpeg -i INPUT OUTPUT &> +@end example + +The message "tty output" notwithstanding, the problem here is that +ffmpeg normally checks the console input when it runs. The operating system +detects this, and suspends the process until you can bring it to the +foreground and attend to it. + +The solution is to use the right techniques to tell ffmpeg not to consult +console input. You can use the +@url{ffmpeg.html#stdin-option, @code{-nostdin} option}, +or redirect standard input with @code{< /dev/null}. +See FAQ +@ref{background task, @emph{How do I run ffmpeg as a background task?}} +for details. + @chapter Development @section Are there examples illustrating how to use the FFmpeg libraries, particularly libavcodec and libavformat? diff --git a/doc/fate.texi b/doc/fate.texi index 7a96c25c72ad8..c9c0d3aea9842 100644 --- a/doc/fate.texi +++ b/doc/fate.texi @@ -147,6 +147,26 @@ process. The only thing left is to automate the execution of the fate.sh script and the synchronisation of the samples directory. +@chapter Uploading new samples to the fate suite + +This is for developers who have an account on the fate suite server. +If you upload new samples, please make sure they are as small as possible, +space on each client, network bandwidth and so on benefit from smaller test cases. +Also keep in mind older checkouts use existing sample files, that means in +practice generally do not replace, remove or overwrite files as it likely would +break older checkouts or releases. + +@example +#First update your local samples copy: +rsync -vauL --chmod=Dg+s,Duo+x,ug+rw,o+r,o-w,+X fate-suite.ffmpeg.org:/home/samples/fate-suite/ ~/fate-suite + +#Then do a dry run checking what would be uploaded: +rsync -vanL --no-g --chmod=Dg+s,Duo+x,ug+rw,o+r,o-w,+X ~/fate-suite/ fate-suite.ffmpeg.org:/home/samples/fate-suite + +#Upload the files: +rsync -vaL --no-g --chmod=Dg+s,Duo+x,ug+rw,o+r,o-w,+X ~/fate-suite/ fate-suite.ffmpeg.org:/home/samples/fate-suite +@end example + @chapter FATE makefile targets and variables diff --git a/doc/ffmpeg-bitstream-filters.texi b/doc/ffmpeg-bitstream-filters.texi index bbde25708fcf9..63c0b33a32ebe 100644 --- a/doc/ffmpeg-bitstream-filters.texi +++ b/doc/ffmpeg-bitstream-filters.texi @@ -26,12 +26,12 @@ bitstream level modifications without performing decoding. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{libavcodec.html,libavcodec} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavcodec(3) +ffmpeg(1), ffplay(1), ffprobe(1), libavcodec(3) @end ifnothtml @include authors.texi diff --git a/doc/ffmpeg-codecs.texi b/doc/ffmpeg-codecs.texi index 7df4391ae7bee..e46cd3aeb8f7e 100644 --- a/doc/ffmpeg-codecs.texi +++ b/doc/ffmpeg-codecs.texi @@ -23,12 +23,12 @@ the libavcodec library. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{libavcodec.html,libavcodec} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavcodec(3) +ffmpeg(1), ffplay(1), ffprobe(1), libavcodec(3) @end ifnothtml @include authors.texi diff --git a/doc/ffmpeg-devices.texi b/doc/ffmpeg-devices.texi index 721c0df800b0a..a51de0014ab4b 100644 --- a/doc/ffmpeg-devices.texi +++ b/doc/ffmpeg-devices.texi @@ -23,12 +23,12 @@ libavdevice library. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{libavdevice.html,libavdevice} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavdevice(3) +ffmpeg(1), ffplay(1), ffprobe(1), libavdevice(3) @end ifnothtml @include authors.texi diff --git a/doc/ffmpeg-filters.texi b/doc/ffmpeg-filters.texi index b643f2c02754e..a8ababa9cfbc8 100644 --- a/doc/ffmpeg-filters.texi +++ b/doc/ffmpeg-filters.texi @@ -23,12 +23,12 @@ libavfilter library. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{libavfilter.html,libavfilter} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavfilter(3) +ffmpeg(1), ffplay(1), ffprobe(1), libavfilter(3) @end ifnothtml @include authors.texi diff --git a/doc/ffmpeg-formats.texi b/doc/ffmpeg-formats.texi index d916ee84b72cd..a1917a7267a79 100644 --- a/doc/ffmpeg-formats.texi +++ b/doc/ffmpeg-formats.texi @@ -23,12 +23,12 @@ provided by the libavformat library. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{libavformat.html,libavformat} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavformat(3) +ffmpeg(1), ffplay(1), ffprobe(1), libavformat(3) @end ifnothtml @include authors.texi diff --git a/doc/ffmpeg-protocols.texi b/doc/ffmpeg-protocols.texi index f3a09f6a6957e..7f0e62ac6550d 100644 --- a/doc/ffmpeg-protocols.texi +++ b/doc/ffmpeg-protocols.texi @@ -23,12 +23,12 @@ libavformat library. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{libavformat.html,libavformat} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavformat(3) +ffmpeg(1), ffplay(1), ffprobe(1), libavformat(3) @end ifnothtml @include authors.texi diff --git a/doc/ffmpeg-resampler.texi b/doc/ffmpeg-resampler.texi index be3784f3ed1b4..0e9a3dd950f2f 100644 --- a/doc/ffmpeg-resampler.texi +++ b/doc/ffmpeg-resampler.texi @@ -25,12 +25,12 @@ and convert audio format and packing layout. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{libswresample.html,libswresample} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libswresample(3) +ffmpeg(1), ffplay(1), ffprobe(1), libswresample(3) @end ifnothtml @include authors.texi diff --git a/doc/ffmpeg-scaler.texi b/doc/ffmpeg-scaler.texi index 9ab12a1f95625..d259da9035242 100644 --- a/doc/ffmpeg-scaler.texi +++ b/doc/ffmpeg-scaler.texi @@ -24,12 +24,12 @@ image rescaling and pixel format conversion. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{libswscale.html,libswscale} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libswscale(3) +ffmpeg(1), ffplay(1), ffprobe(1), libswscale(3) @end ifnothtml @include authors.texi diff --git a/doc/ffmpeg-utils.texi b/doc/ffmpeg-utils.texi index e39cfa85ec572..d8e08841ef700 100644 --- a/doc/ffmpeg-utils.texi +++ b/doc/ffmpeg-utils.texi @@ -23,12 +23,12 @@ by the libavutil library. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{libavutil.html,libavutil} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), libavutil(3) +ffmpeg(1), ffplay(1), ffprobe(1), libavutil(3) @end ifnothtml @include authors.texi diff --git a/doc/ffmpeg.texi b/doc/ffmpeg.texi index 0405d009b967f..86c6fd864cd76 100644 --- a/doc/ffmpeg.texi +++ b/doc/ffmpeg.texi @@ -289,8 +289,8 @@ see @ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) -to and -t are mutually exclusive and -t has priority. -@item -to @var{position} (@emph{output}) -Stop writing the output at @var{position}. +@item -to @var{position} (@emph{input/output}) +Stop writing the output or reading the input at @var{position}. @var{position} must be a time duration specification, see @ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) manual,ffmpeg-utils}. @@ -413,6 +413,10 @@ they do not conflict with the standard, as in: ffmpeg -i myfile.avi -target vcd -bf 2 /tmp/vcd.mpg @end example +@item -dn (@emph{output}) +Disable data recording. For full manual control see the @code{-map} +option. + @item -dframes @var{number} (@emph{output}) Set the number of data frames to output. This is an obsolete alias for @code{-frames:d}, which you should use instead. @@ -470,6 +474,7 @@ the encoding process. It is made of "@var{key}=@var{value}" lines. @var{key} consists of only alphanumeric characters. The last key of a sequence of progress information is always "progress". +@anchor{stdin option} @item -stdin Enable interaction on standard input. On by default unless standard input is used as an input. To explicitly disable interaction you need to specify @@ -570,7 +575,8 @@ stored at container level, but not the aspect ratio stored in encoded frames, if it exists. @item -vn (@emph{output}) -Disable video recording. +Disable video recording. For full manual control see the @code{-map} +option. @item -vcodec @var{codec} (@emph{output}) Set the video codec. This is an alias for @code{-codec:v}. @@ -756,6 +762,43 @@ If not specified, @samp{auto_any} is used. platform-appropriate subdevice (@samp{dxva2} or @samp{vaapi}) and then deriving a QSV device from that.) +@item opencl +@var{device} selects the platform and device as @emph{platform_index.device_index}. + +The set of devices can also be filtered using the key-value pairs to find only +devices matching particular platform or device strings. + +The strings usable as filters are: +@table @option +@item platform_profile +@item platform_version +@item platform_name +@item platform_vendor +@item platform_extensions +@item device_name +@item device_vendor +@item driver_version +@item device_version +@item device_profile +@item device_extensions +@item device_type +@end table + +The indices and filters must together uniquely select a device. + +Examples: +@table @emph +@item -init_hw_device opencl:0.1 +Choose the second device on the first platform. + +@item -init_hw_device opencl:,device_name=Foo9000 +Choose the device with a name containing the string @emph{Foo9000}. + +@item -init_hw_device opencl:1,device_type=gpu,device_extensions=cl_khr_fp16 +Choose the GPU device on the second platform supporting the @emph{cl_khr_fp16} +extension. +@end table + @end table @item -init_hw_device @var{type}[=@var{name}]@@@var{source} @@ -786,9 +829,6 @@ Do not use any hardware acceleration (the default). @item auto Automatically select the hardware acceleration method. -@item vda -Use Apple VDA hardware acceleration. - @item vdpau Use VDPAU (Video Decode and Presentation API for Unix) hardware acceleration. @@ -851,7 +891,8 @@ default to the number of input audio channels. For input streams this option only makes sense for audio grabbing devices and raw demuxers and is mapped to the corresponding demuxer options. @item -an (@emph{output}) -Disable audio recording. +Disable audio recording. For full manual control see the @code{-map} +option. @item -acodec @var{codec} (@emph{input/output}) Set the audio codec. This is an alias for @code{-codec:a}. @item -sample_fmt[:@var{stream_specifier}] @var{sample_fmt} (@emph{output,per-stream}) @@ -886,7 +927,8 @@ stereo but not 6 channels as 5.1. The default is to always try to guess. Use @item -scodec @var{codec} (@emph{input/output}) Set the subtitle codec. This is an alias for @code{-codec:s}. @item -sn (@emph{output}) -Disable subtitle recording. +Disable subtitle recording. For full manual control see the @code{-map} +option. @item -sbsf @var{bitstream_filter} Deprecated, see -bsf @end table @@ -1132,10 +1174,6 @@ loss). By default @command{ffmpeg} attempts to read the input(s) as fast as possible. This option will slow down the reading of the input(s) to the native frame rate of the input(s). It is useful for real-time output (e.g. live streaming). -@item -loop_input -Loop over the input stream. Currently it works only for image -streams. This option is used for automatic FFserver testing. -This option is deprecated, use -loop 1. @item -loop_output @var{number_of_times} Repeatedly loop output for formats that support looping such as animated GIF (0 will loop the output infinitely). @@ -1253,6 +1291,8 @@ or as a floating point number (e.g. 0.04166, 2.0833e-5) Default value is 0. +@item -bitexact (@emph{input/output}) +Enable bitexact mode for (de)muxer and (de/en)coder @item -shortest (@emph{output}) Finish encoding when the shortest input stream ends. @item -dts_delta_threshold @@ -1375,16 +1415,6 @@ file or device. With low latency / high rate live streams, packets may be discarded if they are not read in a timely manner; raising this value can avoid it. -@item -override_ffserver (@emph{global}) -Overrides the input specifications from @command{ffserver}. Using this -option you can map any input stream to @command{ffserver} and control -many aspects of the encoding from @command{ffmpeg}. Without this -option @command{ffmpeg} will transmit to @command{ffserver} what is -requested by @command{ffserver}. - -The option is intended for cases where features are needed that cannot be -specified to @command{ffserver} but can be to @command{ffmpeg}. - @item -sdp_file @var{file} (@emph{global}) Print sdp information for an output stream to @var{file}. This allows dumping sdp information when at least one output isn't an @@ -1739,7 +1769,7 @@ ffmpeg -i src.ext -lmax 21*QP2LAMBDA dst.ext @ifset config-not-all @url{ffmpeg-all.html,ffmpeg-all}, @end ifset -@url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffmpeg-utils.html,ffmpeg-utils}, @url{ffmpeg-scaler.html,ffmpeg-scaler}, @url{ffmpeg-resampler.html,ffmpeg-resampler}, @@ -1758,7 +1788,7 @@ ffmpeg(1), @ifset config-not-all ffmpeg-all(1), @end ifset -ffplay(1), ffprobe(1), ffserver(1), +ffplay(1), ffprobe(1), ffmpeg-utils(1), ffmpeg-scaler(1), ffmpeg-resampler(1), ffmpeg-codecs(1), ffmpeg-bitstream-filters(1), ffmpeg-formats(1), ffmpeg-devices(1), ffmpeg-protocols(1), ffmpeg-filters(1) diff --git a/doc/ffplay.texi b/doc/ffplay.texi index a76bed4663a46..c95956ea170ad 100644 --- a/doc/ffplay.texi +++ b/doc/ffplay.texi @@ -291,7 +291,7 @@ Toggle full screen. @ifset config-not-all @url{ffplay-all.html,ffmpeg-all}, @end ifset -@url{ffmpeg.html,ffmpeg}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffprobe.html,ffprobe}, @url{ffmpeg-utils.html,ffmpeg-utils}, @url{ffmpeg-scaler.html,ffmpeg-scaler}, @url{ffmpeg-resampler.html,ffmpeg-resampler}, @@ -310,7 +310,7 @@ ffplay(1), @ifset config-not-all ffplay-all(1), @end ifset -ffmpeg(1), ffprobe(1), ffserver(1), +ffmpeg(1), ffprobe(1), ffmpeg-utils(1), ffmpeg-scaler(1), ffmpeg-resampler(1), ffmpeg-codecs(1), ffmpeg-bitstream-filters(1), ffmpeg-formats(1), ffmpeg-devices(1), ffmpeg-protocols(1), ffmpeg-filters(1) diff --git a/doc/ffprobe.texi b/doc/ffprobe.texi index e3c34babdc7a0..4e9f184a1db83 100644 --- a/doc/ffprobe.texi +++ b/doc/ffprobe.texi @@ -653,7 +653,7 @@ DV, GXF and AVI timecodes are available in format metadata @ifset config-not-all @url{ffprobe-all.html,ffprobe-all}, @end ifset -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffmpeg-utils.html,ffmpeg-utils}, @url{ffmpeg-scaler.html,ffmpeg-scaler}, @url{ffmpeg-resampler.html,ffmpeg-resampler}, @@ -672,7 +672,7 @@ ffprobe(1), @ifset config-not-all ffprobe-all(1), @end ifset -ffmpeg(1), ffplay(1), ffserver(1), +ffmpeg(1), ffplay(1), ffmpeg-utils(1), ffmpeg-scaler(1), ffmpeg-resampler(1), ffmpeg-codecs(1), ffmpeg-bitstream-filters(1), ffmpeg-formats(1), ffmpeg-devices(1), ffmpeg-protocols(1), ffmpeg-filters(1) diff --git a/doc/ffserver.conf b/doc/ffserver.conf deleted file mode 100644 index e3f99bbfb3d72..0000000000000 --- a/doc/ffserver.conf +++ /dev/null @@ -1,372 +0,0 @@ -# Port on which the server is listening. You must select a different -# port from your standard HTTP web server if it is running on the same -# computer. -HTTPPort 8090 - -# Address on which the server is bound. Only useful if you have -# several network interfaces. -HTTPBindAddress 0.0.0.0 - -# Number of simultaneous HTTP connections that can be handled. It has -# to be defined *before* the MaxClients parameter, since it defines the -# MaxClients maximum limit. -MaxHTTPConnections 2000 - -# Number of simultaneous requests that can be handled. Since FFServer -# is very fast, it is more likely that you will want to leave this high -# and use MaxBandwidth, below. -MaxClients 1000 - -# This the maximum amount of kbit/sec that you are prepared to -# consume when streaming to clients. -MaxBandwidth 1000 - -# Access log file (uses standard Apache log file format) -# '-' is the standard output. -CustomLog - - -################################################################## -# Definition of the live feeds. Each live feed contains one video -# and/or audio sequence coming from an ffmpeg encoder or another -# ffserver. This sequence may be encoded simultaneously with several -# codecs at several resolutions. - - - -# You must use 'ffmpeg' to send a live feed to ffserver. In this -# example, you can type: -# -# ffmpeg http://localhost:8090/feed1.ffm - -# ffserver can also do time shifting. It means that it can stream any -# previously recorded live stream. The request should contain: -# "http://xxxx?date=[YYYY-MM-DDT][[HH:]MM:]SS[.m...]".You must specify -# a path where the feed is stored on disk. You also specify the -# maximum size of the feed, where zero means unlimited. Default: -# File=/tmp/feed_name.ffm FileMaxSize=5M -File /tmp/feed1.ffm -FileMaxSize 200K - -# You could specify -# ReadOnlyFile /saved/specialvideo.ffm -# This marks the file as readonly and it will not be deleted or updated. - -# Specify launch in order to start ffmpeg automatically. -# First ffmpeg must be defined with an appropriate path if needed, -# after that options can follow, but avoid adding the http:// field -#Launch ffmpeg - -# Only allow connections from localhost to the feed. -ACL allow 127.0.0.1 - - - - -################################################################## -# Now you can define each stream which will be generated from the -# original audio and video stream. Each format has a filename (here -# 'test1.mpg'). FFServer will send this stream when answering a -# request containing this filename. - - - -# coming from live feed 'feed1' -Feed feed1.ffm - -# Format of the stream : you can choose among: -# mpeg : MPEG-1 multiplexed video and audio -# mpegvideo : only MPEG-1 video -# mp2 : MPEG-2 audio (use AudioCodec to select layer 2 and 3 codec) -# ogg : Ogg format (Vorbis audio codec) -# rm : RealNetworks-compatible stream. Multiplexed audio and video. -# ra : RealNetworks-compatible stream. Audio only. -# mpjpeg : Multipart JPEG (works with Netscape without any plugin) -# jpeg : Generate a single JPEG image. -# mjpeg : Generate a M-JPEG stream. -# asf : ASF compatible streaming (Windows Media Player format). -# swf : Macromedia Flash compatible stream -# avi : AVI format (MPEG-4 video, MPEG audio sound) -Format mpeg - -# Bitrate for the audio stream. Codecs usually support only a few -# different bitrates. -AudioBitRate 32 - -# Number of audio channels: 1 = mono, 2 = stereo -AudioChannels 1 - -# Sampling frequency for audio. When using low bitrates, you should -# lower this frequency to 22050 or 11025. The supported frequencies -# depend on the selected audio codec. -AudioSampleRate 44100 - -# Bitrate for the video stream -VideoBitRate 64 - -# Ratecontrol buffer size -VideoBufferSize 40 - -# Number of frames per second -VideoFrameRate 3 - -# Size of the video frame: WxH (default: 160x128) -# The following abbreviations are defined: sqcif, qcif, cif, 4cif, qqvga, -# qvga, vga, svga, xga, uxga, qxga, sxga, qsxga, hsxga, wvga, wxga, wsxga, -# wuxga, woxga, wqsxga, wquxga, whsxga, whuxga, cga, ega, hd480, hd720, -# hd1080 -VideoSize 160x128 - -# Transmit only intra frames (useful for low bitrates, but kills frame rate). -#VideoIntraOnly - -# If non-intra only, an intra frame is transmitted every VideoGopSize -# frames. Video synchronization can only begin at an intra frame. -VideoGopSize 12 - -# More MPEG-4 parameters -# VideoHighQuality -# Video4MotionVector - -# Choose your codecs: -#AudioCodec mp2 -#VideoCodec mpeg1video - -# Suppress audio -#NoAudio - -# Suppress video -#NoVideo - -#VideoQMin 3 -#VideoQMax 31 - -# Set this to the number of seconds backwards in time to start. Note that -# most players will buffer 5-10 seconds of video, and also you need to allow -# for a keyframe to appear in the data stream. -#Preroll 15 - -# ACL: - -# You can allow ranges of addresses (or single addresses) -#ACL ALLOW - -# You can deny ranges of addresses (or single addresses) -#ACL DENY - -# You can repeat the ACL allow/deny as often as you like. It is on a per -# stream basis. The first match defines the action. If there are no matches, -# then the default is the inverse of the last ACL statement. -# -# Thus 'ACL allow localhost' only allows access from localhost. -# 'ACL deny 1.0.0.0 1.255.255.255' would deny the whole of network 1 and -# allow everybody else. - - - - -################################################################## -# Example streams - - -# Multipart JPEG - -# -#Feed feed1.ffm -#Format mpjpeg -#VideoFrameRate 2 -#VideoIntraOnly -#NoAudio -#Strict -1 -# - - -# Single JPEG - -# -#Feed feed1.ffm -#Format jpeg -#VideoFrameRate 2 -#VideoIntraOnly -##VideoSize 352x240 -#NoAudio -#Strict -1 -# - - -# Flash - -# -#Feed feed1.ffm -#Format swf -#VideoFrameRate 2 -#VideoIntraOnly -#NoAudio -# - - -# ASF compatible - - -Feed feed1.ffm -Format asf -VideoFrameRate 15 -VideoSize 352x240 -VideoBitRate 256 -VideoBufferSize 40 -VideoGopSize 30 -AudioBitRate 64 -StartSendOnKey - - - -# MP3 audio - -# -#Feed feed1.ffm -#Format mp2 -#AudioCodec mp3 -#AudioBitRate 64 -#AudioChannels 1 -#AudioSampleRate 44100 -#NoVideo -# - - -# Ogg Vorbis audio - -# -#Feed feed1.ffm -#Metadata title "Stream title" -#AudioBitRate 64 -#AudioChannels 2 -#AudioSampleRate 44100 -#NoVideo -# - - -# Real with audio only at 32 kbits - -# -#Feed feed1.ffm -#Format rm -#AudioBitRate 32 -#NoVideo -#NoAudio -# - - -# Real with audio and video at 64 kbits - -# -#Feed feed1.ffm -#Format rm -#AudioBitRate 32 -#VideoBitRate 128 -#VideoFrameRate 25 -#VideoGopSize 25 -#NoAudio -# - - -################################################################## -# A stream coming from a file: you only need to set the input -# filename and optionally a new format. Supported conversions: -# AVI -> ASF - -# -#File "/usr/local/httpd/htdocs/tlive.rm" -#NoAudio -# - -# -#File "/usr/local/httpd/htdocs/test.asf" -#NoAudio -#Metadata author "Me" -#Metadata copyright "Super MegaCorp" -#Metadata title "Test stream from disk" -#Metadata comment "Test comment" -# - - -################################################################## -# RTSP examples -# -# You can access this stream with the RTSP URL: -# rtsp://localhost:5454/test1-rtsp.mpg -# -# A non-standard RTSP redirector is also created. Its URL is: -# http://localhost:8090/test1-rtsp.rtsp - -# -#Format rtp -#File "/usr/local/httpd/htdocs/test1.mpg" -# - - -# Transcode an incoming live feed to another live feed, -# using libx264 and video presets - -# -#Format rtp -#Feed feed1.ffm -#VideoCodec libx264 -#VideoFrameRate 24 -#VideoBitRate 100 -#VideoSize 480x272 -#AVPresetVideo default -#AVPresetVideo baseline -#AVOptionVideo flags +global_header -# -#AudioCodec aac -#AudioBitRate 32 -#AudioChannels 2 -#AudioSampleRate 22050 -#AVOptionAudio flags +global_header -# - -################################################################## -# SDP/multicast examples -# -# If you want to send your stream in multicast, you must set the -# multicast address with MulticastAddress. The port and the TTL can -# also be set. -# -# An SDP file is automatically generated by ffserver by adding the -# 'sdp' extension to the stream name (here -# http://localhost:8090/test1-sdp.sdp). You should usually give this -# file to your player to play the stream. -# -# The 'NoLoop' option can be used to avoid looping when the stream is -# terminated. - -# -#Format rtp -#File "/usr/local/httpd/htdocs/test1.mpg" -#MulticastAddress 224.124.0.1 -#MulticastPort 5000 -#MulticastTTL 16 -#NoLoop -# - - -################################################################## -# Special streams - -# Server status - - -Format status - -# Only allow local people to get the status -ACL allow localhost -ACL allow 192.168.0.0 192.168.255.255 - -#FaviconURL http://pond1.gladstonefamily.net:8080/favicon.ico - - - -# Redirect index.html to the appropriate site - - -URL http://www.ffmpeg.org/ - diff --git a/doc/ffserver.texi b/doc/ffserver.texi deleted file mode 100644 index b3e1f1d7ef9a7..0000000000000 --- a/doc/ffserver.texi +++ /dev/null @@ -1,923 +0,0 @@ -\input texinfo @c -*- texinfo -*- -@documentencoding UTF-8 - -@settitle ffserver Documentation -@titlepage -@center @titlefont{ffserver Documentation} -@end titlepage - -@top - -@contents - -@chapter Synopsis - -ffserver [@var{options}] - -@chapter Description -@c man begin DESCRIPTION - -@command{ffserver} is a streaming server for both audio and video. -It supports several live feeds, streaming from files and time shifting -on live feeds. You can seek to positions in the past on each live -feed, provided you specify a big enough feed storage. - -@command{ffserver} is configured through a configuration file, which -is read at startup. If not explicitly specified, it will read from -@file{/etc/ffserver.conf}. - -@command{ffserver} receives prerecorded files or FFM streams from some -@command{ffmpeg} instance as input, then streams them over -RTP/RTSP/HTTP. - -An @command{ffserver} instance will listen on some port as specified -in the configuration file. You can launch one or more instances of -@command{ffmpeg} and send one or more FFM streams to the port where -ffserver is expecting to receive them. Alternately, you can make -@command{ffserver} launch such @command{ffmpeg} instances at startup. - -Input streams are called feeds, and each one is specified by a -@code{} section in the configuration file. - -For each feed you can have different output streams in various -formats, each one specified by a @code{} section in the -configuration file. - -@chapter Detailed description - -@command{ffserver} works by forwarding streams encoded by -@command{ffmpeg}, or pre-recorded streams which are read from disk. - -Precisely, @command{ffserver} acts as an HTTP server, accepting POST -requests from @command{ffmpeg} to acquire the stream to publish, and -serving RTSP clients or HTTP clients GET requests with the stream -media content. - -A feed is an @ref{FFM} stream created by @command{ffmpeg}, and sent to -a port where @command{ffserver} is listening. - -Each feed is identified by a unique name, corresponding to the name -of the resource published on @command{ffserver}, and is configured by -a dedicated @code{Feed} section in the configuration file. - -The feed publish URL is given by: -@example -http://@var{ffserver_ip_address}:@var{http_port}/@var{feed_name} -@end example - -where @var{ffserver_ip_address} is the IP address of the machine where -@command{ffserver} is installed, @var{http_port} is the port number of -the HTTP server (configured through the @option{HTTPPort} option), and -@var{feed_name} is the name of the corresponding feed defined in the -configuration file. - -Each feed is associated to a file which is stored on disk. This stored -file is used to send pre-recorded data to a player as fast as -possible when new content is added in real-time to the stream. - -A "live-stream" or "stream" is a resource published by -@command{ffserver}, and made accessible through the HTTP protocol to -clients. - -A stream can be connected to a feed, or to a file. In the first case, -the published stream is forwarded from the corresponding feed -generated by a running instance of @command{ffmpeg}, in the second -case the stream is read from a pre-recorded file. - -Each stream is identified by a unique name, corresponding to the name -of the resource served by @command{ffserver}, and is configured by -a dedicated @code{Stream} section in the configuration file. - -The stream access HTTP URL is given by: -@example -http://@var{ffserver_ip_address}:@var{http_port}/@var{stream_name}[@var{options}] -@end example - -The stream access RTSP URL is given by: -@example -http://@var{ffserver_ip_address}:@var{rtsp_port}/@var{stream_name}[@var{options}] -@end example - -@var{stream_name} is the name of the corresponding stream defined in -the configuration file. @var{options} is a list of options specified -after the URL which affects how the stream is served by -@command{ffserver}. @var{http_port} and @var{rtsp_port} are the HTTP -and RTSP ports configured with the options @var{HTTPPort} and -@var{RTSPPort} respectively. - -In case the stream is associated to a feed, the encoding parameters -must be configured in the stream configuration. They are sent to -@command{ffmpeg} when setting up the encoding. This allows -@command{ffserver} to define the encoding parameters used by -the @command{ffmpeg} encoders. - -The @command{ffmpeg} @option{override_ffserver} commandline option -allows one to override the encoding parameters set by the server. - -Multiple streams can be connected to the same feed. - -For example, you can have a situation described by the following -graph: - -@verbatim - _________ __________ - | | | | -ffmpeg 1 -----| feed 1 |-----| stream 1 | - \ |_________|\ |__________| - \ \ - \ \ __________ - \ \ | | - \ \| stream 2 | - \ |__________| - \ - \ _________ __________ - \ | | | | - \| feed 2 |-----| stream 3 | - |_________| |__________| - - _________ __________ - | | | | -ffmpeg 2 -----| feed 3 |-----| stream 4 | - |_________| |__________| - - _________ __________ - | | | | - | file 1 |-----| stream 5 | - |_________| |__________| - -@end verbatim - -@anchor{FFM} -@section FFM, FFM2 formats - -FFM and FFM2 are formats used by ffserver. They allow storing a wide variety of -video and audio streams and encoding options, and can store a moving time segment -of an infinite movie or a whole movie. - -FFM is version specific, and there is limited compatibility of FFM files -generated by one version of ffmpeg/ffserver and another version of -ffmpeg/ffserver. It may work but it is not guaranteed to work. - -FFM2 is extensible while maintaining compatibility and should work between -differing versions of tools. FFM2 is the default. - -@section Status stream - -@command{ffserver} supports an HTTP interface which exposes the -current status of the server. - -Simply point your browser to the address of the special status stream -specified in the configuration file. - -For example if you have: -@example - -Format status - -# Only allow local people to get the status -ACL allow localhost -ACL allow 192.168.0.0 192.168.255.255 - -@end example - -then the server will post a page with the status information when -the special stream @file{status.html} is requested. - -@section How do I make it work? - -As a simple test, just run the following two command lines where INPUTFILE -is some file which you can decode with ffmpeg: - -@example -ffserver -f doc/ffserver.conf & -ffmpeg -i INPUTFILE http://localhost:8090/feed1.ffm -@end example - -At this point you should be able to go to your Windows machine and fire up -Windows Media Player (WMP). Go to Open URL and enter - -@example - http://:8090/test.asf -@end example - -You should (after a short delay) see video and hear audio. - -WARNING: trying to stream test1.mpg doesn't work with WMP as it tries to -transfer the entire file before starting to play. -The same is true of AVI files. - -You should edit the @file{ffserver.conf} file to suit your needs (in -terms of frame rates etc). Then install @command{ffserver} and -@command{ffmpeg}, write a script to start them up, and off you go. - -@section What else can it do? - -You can replay video from .ffm files that was recorded earlier. -However, there are a number of caveats, including the fact that the -ffserver parameters must match the original parameters used to record the -file. If they do not, then ffserver deletes the file before recording into it. -(Now that I write this, it seems broken). - -You can fiddle with many of the codec choices and encoding parameters, and -there are a bunch more parameters that you cannot control. Post a message -to the mailing list if there are some 'must have' parameters. Look in -ffserver.conf for a list of the currently available controls. - -It will automatically generate the ASX or RAM files that are often used -in browsers. These files are actually redirections to the underlying ASF -or RM file. The reason for this is that the browser often fetches the -entire file before starting up the external viewer. The redirection files -are very small and can be transferred quickly. [The stream itself is -often 'infinite' and thus the browser tries to download it and never -finishes.] - -@section Tips - -* When you connect to a live stream, most players (WMP, RA, etc) want to -buffer a certain number of seconds of material so that they can display the -signal continuously. However, ffserver (by default) starts sending data -in realtime. This means that there is a pause of a few seconds while the -buffering is being done by the player. The good news is that this can be -cured by adding a '?buffer=5' to the end of the URL. This means that the -stream should start 5 seconds in the past -- and so the first 5 seconds -of the stream are sent as fast as the network will allow. It will then -slow down to real time. This noticeably improves the startup experience. - -You can also add a 'Preroll 15' statement into the ffserver.conf that will -add the 15 second prebuffering on all requests that do not otherwise -specify a time. In addition, ffserver will skip frames until a key_frame -is found. This further reduces the startup delay by not transferring data -that will be discarded. - -@section Why does the ?buffer / Preroll stop working after a time? - -It turns out that (on my machine at least) the number of frames successfully -grabbed is marginally less than the number that ought to be grabbed. This -means that the timestamp in the encoded data stream gets behind realtime. -This means that if you say 'Preroll 10', then when the stream gets 10 -or more seconds behind, there is no Preroll left. - -Fixing this requires a change in the internals of how timestamps are -handled. - -@section Does the @code{?date=} stuff work. - -Yes (subject to the limitation outlined above). Also note that whenever you -start ffserver, it deletes the ffm file (if any parameters have changed), -thus wiping out what you had recorded before. - -The format of the @code{?date=xxxxxx} is fairly flexible. You should use one -of the following formats (the 'T' is literal): - -@example -* YYYY-MM-DDTHH:MM:SS (localtime) -* YYYY-MM-DDTHH:MM:SSZ (UTC) -@end example - -You can omit the YYYY-MM-DD, and then it refers to the current day. However -note that @samp{?date=16:00:00} refers to 16:00 on the current day -- this -may be in the future and so is unlikely to be useful. - -You use this by adding the ?date= to the end of the URL for the stream. -For example: @samp{http://localhost:8080/test.asf?date=2002-07-26T23:05:00}. -@c man end - -@chapter Options -@c man begin OPTIONS - -@include fftools-common-opts.texi - -@section Main options - -@table @option -@item -f @var{configfile} -Read configuration file @file{configfile}. If not specified it will -read by default from @file{/etc/ffserver.conf}. - -@item -n -Enable no-launch mode. This option disables all the @code{Launch} -directives within the various @code{} sections. Since -@command{ffserver} will not launch any @command{ffmpeg} instances, you -will have to launch them manually. - -@item -d -Enable debug mode. This option increases log verbosity, and directs -log messages to stdout. When specified, the @option{CustomLog} option -is ignored. -@end table - -@chapter Configuration file syntax - -@command{ffserver} reads a configuration file containing global -options and settings for each stream and feed. - -The configuration file consists of global options and dedicated -sections, which must be introduced by "<@var{SECTION_NAME} -@var{ARGS}>" on a separate line and must be terminated by a line in -the form "". @var{ARGS} is optional. - -Currently the following sections are recognized: @samp{Feed}, -@samp{Stream}, @samp{Redirect}. - -A line starting with @code{#} is ignored and treated as a comment. - -Name of options and sections are case-insensitive. - -@section ACL syntax -An ACL (Access Control List) specifies the address which are allowed -to access a given stream, or to write a given feed. - -It accepts the following forms -@itemize -@item -Allow/deny access to @var{address}. -@example -ACL ALLOW
-ACL DENY
-@end example - -@item -Allow/deny access to ranges of addresses from @var{first_address} to -@var{last_address}. -@example -ACL ALLOW -ACL DENY -@end example -@end itemize - -You can repeat the ACL allow/deny as often as you like. It is on a per -stream basis. The first match defines the action. If there are no matches, -then the default is the inverse of the last ACL statement. - -Thus 'ACL allow localhost' only allows access from localhost. -'ACL deny 1.0.0.0 1.255.255.255' would deny the whole of network 1 and -allow everybody else. - -@section Global options -@table @option -@item HTTPPort @var{port_number} -@item Port @var{port_number} -@item RTSPPort @var{port_number} - -@var{HTTPPort} sets the HTTP server listening TCP port number, -@var{RTSPPort} sets the RTSP server listening TCP port number. - -@var{Port} is the equivalent of @var{HTTPPort} and is deprecated. - -You must select a different port from your standard HTTP web server if -it is running on the same computer. - -If not specified, no corresponding server will be created. - -@item HTTPBindAddress @var{ip_address} -@item BindAddress @var{ip_address} -@item RTSPBindAddress @var{ip_address} -Set address on which the HTTP/RTSP server is bound. Only useful if you -have several network interfaces. - -@var{BindAddress} is the equivalent of @var{HTTPBindAddress} and is -deprecated. - -@item MaxHTTPConnections @var{n} -Set number of simultaneous HTTP connections that can be handled. It -has to be defined @emph{before} the @option{MaxClients} parameter, -since it defines the @option{MaxClients} maximum limit. - -Default value is 2000. - -@item MaxClients @var{n} -Set number of simultaneous requests that can be handled. Since -@command{ffserver} is very fast, it is more likely that you will want -to leave this high and use @option{MaxBandwidth}. - -Default value is 5. - -@item MaxBandwidth @var{kbps} -Set the maximum amount of kbit/sec that you are prepared to consume -when streaming to clients. - -Default value is 1000. - -@item CustomLog @var{filename} -Set access log file (uses standard Apache log file format). '-' is the -standard output. - -If not specified @command{ffserver} will produce no log. - -In case the commandline option @option{-d} is specified this option is -ignored, and the log is written to standard output. - -@item NoDaemon -Set no-daemon mode. This option is currently ignored since now -@command{ffserver} will always work in no-daemon mode, and is -deprecated. - -@item UseDefaults -@item NoDefaults -Control whether default codec options are used for the all streams or not. -Each stream may overwrite this setting for its own. Default is @var{UseDefaults}. -The last occurrence overrides the previous if multiple definitions exist. -@end table - -@section Feed section - -A Feed section defines a feed provided to @command{ffserver}. - -Each live feed contains one video and/or audio sequence coming from an -@command{ffmpeg} encoder or another @command{ffserver}. This sequence -may be encoded simultaneously with several codecs at several -resolutions. - -A feed instance specification is introduced by a line in the form: -@example - -@end example - -where @var{FEED_FILENAME} specifies the unique name of the FFM stream. - -The following options are recognized within a Feed section. - -@table @option -@item File @var{filename} -@item ReadOnlyFile @var{filename} -Set the path where the feed file is stored on disk. - -If not specified, the @file{/tmp/FEED.ffm} is assumed, where -@var{FEED} is the feed name. - -If @option{ReadOnlyFile} is used the file is marked as read-only and -it will not be deleted or updated. - -@item Truncate -Truncate the feed file, rather than appending to it. By default -@command{ffserver} will append data to the file, until the maximum -file size value is reached (see @option{FileMaxSize} option). - -@item FileMaxSize @var{size} -Set maximum size of the feed file in bytes. 0 means unlimited. The -postfixes @code{K} (2^10), @code{M} (2^20), and @code{G} (2^30) are -recognized. - -Default value is 5M. - -@item Launch @var{args} -Launch an @command{ffmpeg} command when creating @command{ffserver}. - -@var{args} must be a sequence of arguments to be provided to an -@command{ffmpeg} instance. The first provided argument is ignored, and -it is replaced by a path with the same dirname of the @command{ffserver} -instance, followed by the remaining argument and terminated with a -path corresponding to the feed. - -When the launched process exits, @command{ffserver} will launch -another program instance. - -In case you need a more complex @command{ffmpeg} configuration, -e.g. if you need to generate multiple FFM feeds with a single -@command{ffmpeg} instance, you should launch @command{ffmpeg} by hand. - -This option is ignored in case the commandline option @option{-n} is -specified. - -@item ACL @var{spec} -Specify the list of IP address which are allowed or denied to write -the feed. Multiple ACL options can be specified. -@end table - -@section Stream section - -A Stream section defines a stream provided by @command{ffserver}, and -identified by a single name. - -The stream is sent when answering a request containing the stream -name. - -A stream section must be introduced by the line: -@example - -@end example - -where @var{STREAM_NAME} specifies the unique name of the stream. - -The following options are recognized within a Stream section. - -Encoding options are marked with the @emph{encoding} tag, and they are -used to set the encoding parameters, and are mapped to libavcodec -encoding options. Not all encoding options are supported, in -particular it is not possible to set encoder private options. In order -to override the encoding options specified by @command{ffserver}, you -can use the @command{ffmpeg} @option{override_ffserver} commandline -option. - -Only one of the @option{Feed} and @option{File} options should be set. - -@table @option -@item Feed @var{feed_name} -Set the input feed. @var{feed_name} must correspond to an existing -feed defined in a @code{Feed} section. - -When this option is set, encoding options are used to setup the -encoding operated by the remote @command{ffmpeg} process. - -@item File @var{filename} -Set the filename of the pre-recorded input file to stream. - -When this option is set, encoding options are ignored and the input -file content is re-streamed as is. - -@item Format @var{format_name} -Set the format of the output stream. - -Must be the name of a format recognized by FFmpeg. If set to -@samp{status}, it is treated as a status stream. - -@item InputFormat @var{format_name} -Set input format. If not specified, it is automatically guessed. - -@item Preroll @var{n} -Set this to the number of seconds backwards in time to start. Note that -most players will buffer 5-10 seconds of video, and also you need to allow -for a keyframe to appear in the data stream. - -Default value is 0. - -@item StartSendOnKey -Do not send stream until it gets the first key frame. By default -@command{ffserver} will send data immediately. - -@item MaxTime @var{n} -Set the number of seconds to run. This value set the maximum duration -of the stream a client will be able to receive. - -A value of 0 means that no limit is set on the stream duration. - -@item ACL @var{spec} -Set ACL for the stream. - -@item DynamicACL @var{spec} - -@item RTSPOption @var{option} - -@item MulticastAddress @var{address} - -@item MulticastPort @var{port} - -@item MulticastTTL @var{integer} - -@item NoLoop - -@item FaviconURL @var{url} -Set favicon (favourite icon) for the server status page. It is ignored -for regular streams. - -@item Author @var{value} -@item Comment @var{value} -@item Copyright @var{value} -@item Title @var{value} -Set metadata corresponding to the option. All these options are -deprecated in favor of @option{Metadata}. - -@item Metadata @var{key} @var{value} -Set metadata value on the output stream. - -@item UseDefaults -@item NoDefaults -Control whether default codec options are used for the stream or not. -Default is @var{UseDefaults} unless disabled globally. - -@item NoAudio -@item NoVideo -Suppress audio/video. - -@item AudioCodec @var{codec_name} (@emph{encoding,audio}) -Set audio codec. - -@item AudioBitRate @var{rate} (@emph{encoding,audio}) -Set bitrate for the audio stream in kbits per second. - -@item AudioChannels @var{n} (@emph{encoding,audio}) -Set number of audio channels. - -@item AudioSampleRate @var{n} (@emph{encoding,audio}) -Set sampling frequency for audio. When using low bitrates, you should -lower this frequency to 22050 or 11025. The supported frequencies -depend on the selected audio codec. - -@item AVOptionAudio [@var{codec}:]@var{option} @var{value} (@emph{encoding,audio}) -Set generic or private option for audio stream. -Private option must be prefixed with codec name or codec must be defined before. - -@item AVPresetAudio @var{preset} (@emph{encoding,audio}) -Set preset for audio stream. - -@item VideoCodec @var{codec_name} (@emph{encoding,video}) -Set video codec. - -@item VideoBitRate @var{n} (@emph{encoding,video}) -Set bitrate for the video stream in kbits per second. - -@item VideoBitRateRange @var{range} (@emph{encoding,video}) -Set video bitrate range. - -A range must be specified in the form @var{minrate}-@var{maxrate}, and -specifies the @option{minrate} and @option{maxrate} encoding options -expressed in kbits per second. - -@item VideoBitRateRangeTolerance @var{n} (@emph{encoding,video}) -Set video bitrate tolerance in kbits per second. - -@item PixelFormat @var{pixel_format} (@emph{encoding,video}) -Set video pixel format. - -@item Debug @var{integer} (@emph{encoding,video}) -Set video @option{debug} encoding option. - -@item Strict @var{integer} (@emph{encoding,video}) -Set video @option{strict} encoding option. - -@item VideoBufferSize @var{n} (@emph{encoding,video}) -Set ratecontrol buffer size, expressed in KB. - -@item VideoFrameRate @var{n} (@emph{encoding,video}) -Set number of video frames per second. - -@item VideoSize (@emph{encoding,video}) -Set size of the video frame, must be an abbreviation or in the form -@var{W}x@var{H}. See @ref{video size syntax,,the Video size section -in the ffmpeg-utils(1) manual,ffmpeg-utils}. - -Default value is @code{160x128}. - -@item VideoIntraOnly (@emph{encoding,video}) -Transmit only intra frames (useful for low bitrates, but kills frame rate). - -@item VideoGopSize @var{n} (@emph{encoding,video}) -If non-intra only, an intra frame is transmitted every VideoGopSize -frames. Video synchronization can only begin at an intra frame. - -@item VideoTag @var{tag} (@emph{encoding,video}) -Set video tag. - -@item VideoHighQuality (@emph{encoding,video}) -@item Video4MotionVector (@emph{encoding,video}) - -@item BitExact (@emph{encoding,video}) -Set bitexact encoding flag. - -@item IdctSimple (@emph{encoding,video}) -Set simple IDCT algorithm. - -@item Qscale @var{n} (@emph{encoding,video}) -Enable constant quality encoding, and set video qscale (quantization -scale) value, expressed in @var{n} QP units. - -@item VideoQMin @var{n} (@emph{encoding,video}) -@item VideoQMax @var{n} (@emph{encoding,video}) -Set video qmin/qmax. - -@item VideoQDiff @var{integer} (@emph{encoding,video}) -Set video @option{qdiff} encoding option. - -@item LumiMask @var{float} (@emph{encoding,video}) -@item DarkMask @var{float} (@emph{encoding,video}) -Set @option{lumi_mask}/@option{dark_mask} encoding options. - -@item AVOptionVideo [@var{codec}:]@var{option} @var{value} (@emph{encoding,video}) -Set generic or private option for video stream. -Private option must be prefixed with codec name or codec must be defined before. - -@item AVPresetVideo @var{preset} (@emph{encoding,video}) -Set preset for video stream. - -@var{preset} must be the path of a preset file. -@end table - -@subsection Server status stream - -A server status stream is a special stream which is used to show -statistics about the @command{ffserver} operations. - -It must be specified setting the option @option{Format} to -@samp{status}. - -@section Redirect section - -A redirect section specifies where to redirect the requested URL to -another page. - -A redirect section must be introduced by the line: -@example - -@end example - -where @var{NAME} is the name of the page which should be redirected. - -It only accepts the option @option{URL}, which specify the redirection -URL. - -@chapter Stream examples - -@itemize -@item -Multipart JPEG -@example - -Feed feed1.ffm -Format mpjpeg -VideoFrameRate 2 -VideoIntraOnly -NoAudio -Strict -1 - -@end example - -@item -Single JPEG -@example - -Feed feed1.ffm -Format jpeg -VideoFrameRate 2 -VideoIntraOnly -VideoSize 352x240 -NoAudio -Strict -1 - -@end example - -@item -Flash -@example - -Feed feed1.ffm -Format swf -VideoFrameRate 2 -VideoIntraOnly -NoAudio - -@end example - -@item -ASF compatible -@example - -Feed feed1.ffm -Format asf -VideoFrameRate 15 -VideoSize 352x240 -VideoBitRate 256 -VideoBufferSize 40 -VideoGopSize 30 -AudioBitRate 64 -StartSendOnKey - -@end example - -@item -MP3 audio -@example - -Feed feed1.ffm -Format mp2 -AudioCodec mp3 -AudioBitRate 64 -AudioChannels 1 -AudioSampleRate 44100 -NoVideo - -@end example - -@item -Ogg Vorbis audio -@example - -Feed feed1.ffm -Metadata title "Stream title" -AudioBitRate 64 -AudioChannels 2 -AudioSampleRate 44100 -NoVideo - -@end example - -@item -Real with audio only at 32 kbits -@example - -Feed feed1.ffm -Format rm -AudioBitRate 32 -NoVideo - -@end example - -@item -Real with audio and video at 64 kbits -@example - -Feed feed1.ffm -Format rm -AudioBitRate 32 -VideoBitRate 128 -VideoFrameRate 25 -VideoGopSize 25 - -@end example - -@item -For stream coming from a file: you only need to set the input filename -and optionally a new format. - -@example - -File "/usr/local/httpd/htdocs/tlive.rm" -NoAudio - -@end example - -@example - -File "/usr/local/httpd/htdocs/test.asf" -NoAudio -Metadata author "Me" -Metadata copyright "Super MegaCorp" -Metadata title "Test stream from disk" -Metadata comment "Test comment" - -@end example -@end itemize - -@c man end - -@include config.texi -@ifset config-all -@ifset config-avutil -@include utils.texi -@end ifset -@ifset config-avcodec -@include codecs.texi -@include bitstream_filters.texi -@end ifset -@ifset config-avformat -@include formats.texi -@include protocols.texi -@end ifset -@ifset config-avdevice -@include devices.texi -@end ifset -@ifset config-swresample -@include resampler.texi -@end ifset -@ifset config-swscale -@include scaler.texi -@end ifset -@ifset config-avfilter -@include filters.texi -@end ifset -@end ifset - -@chapter See Also - -@ifhtml -@ifset config-all -@url{ffserver.html,ffserver}, -@end ifset -@ifset config-not-all -@url{ffserver-all.html,ffserver-all}, -@end ifset -the @file{doc/ffserver.conf} example, -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, -@url{ffmpeg-utils.html,ffmpeg-utils}, -@url{ffmpeg-scaler.html,ffmpeg-scaler}, -@url{ffmpeg-resampler.html,ffmpeg-resampler}, -@url{ffmpeg-codecs.html,ffmpeg-codecs}, -@url{ffmpeg-bitstream-filters.html,ffmpeg-bitstream-filters}, -@url{ffmpeg-formats.html,ffmpeg-formats}, -@url{ffmpeg-devices.html,ffmpeg-devices}, -@url{ffmpeg-protocols.html,ffmpeg-protocols}, -@url{ffmpeg-filters.html,ffmpeg-filters} -@end ifhtml - -@ifnothtml -@ifset config-all -ffserver(1), -@end ifset -@ifset config-not-all -ffserver-all(1), -@end ifset -the @file{doc/ffserver.conf} example, ffmpeg(1), ffplay(1), ffprobe(1), -ffmpeg-utils(1), ffmpeg-scaler(1), ffmpeg-resampler(1), -ffmpeg-codecs(1), ffmpeg-bitstream-filters(1), ffmpeg-formats(1), -ffmpeg-devices(1), ffmpeg-protocols(1), ffmpeg-filters(1) -@end ifnothtml - -@include authors.texi - -@ignore - -@setfilename ffserver -@settitle ffserver video server - -@end ignore - -@bye diff --git a/doc/fftools-common-opts.texi b/doc/fftools-common-opts.texi index 2eff33a36f59f..84705c0b68a19 100644 --- a/doc/fftools-common-opts.texi +++ b/doc/fftools-common-opts.texi @@ -42,10 +42,20 @@ streams, 'V' only matches video streams which are not attached pictures, video thumbnails or cover arts. If @var{stream_index} is given, then it matches stream number @var{stream_index} of this type. Otherwise, it matches all streams of this type. -@item p:@var{program_id}[:@var{stream_index}] -If @var{stream_index} is given, then it matches the stream with number @var{stream_index} +@item p:@var{program_id}[:@var{stream_index}] or p:@var{program_id}[:@var{stream_type}[:@var{stream_index}]] or +p:@var{program_id}:m:@var{key}[:@var{value}] +In first version, if @var{stream_index} is given, then it matches the stream with number @var{stream_index} in the program with the id @var{program_id}. Otherwise, it matches all streams in the -program. +program. In the second version, @var{stream_type} is one of following: 'v' for video, 'a' for audio, 's' +for subtitle, 'd' for data. If @var{stream_index} is also given, then it matches +stream number @var{stream_index} of this type in the program with the id @var{program_id}. +Otherwise, if only @var{stream_type} is given, it matches all +streams of this type in the program with the id @var{program_id}. +In the third version matches streams in the program with the id @var{program_id} with the metadata +tag @var{key} having the specified value. If +@var{value} is not given, matches streams that contain the given tag with any +value. + @item #@var{stream_id} or i:@var{stream_id} Match the stream by stream id (e.g. PID in MPEG-TS container). @item m:@var{key}[:@var{value}] @@ -168,14 +178,24 @@ The returned list cannot be assumed to be always complete. ffmpeg -sinks pulse,server=192.168.0.4 @end example -@item -loglevel [repeat+]@var{loglevel} | -v [repeat+]@var{loglevel} -Set the logging level used by the library. -Adding "repeat+" indicates that repeated log output should not be compressed -to the first line and the "Last message repeated n times" line will be -omitted. "repeat" can also be used alone. -If "repeat" is used alone, and with no prior loglevel set, the default -loglevel will be used. If multiple loglevel parameters are given, using -'repeat' will not change the loglevel. +@item -loglevel [@var{flags}+]@var{loglevel} | -v [@var{flags}+]@var{loglevel} +Set logging level and flags used by the library. + +The optional @var{flags} prefix can consist of the following values: +@table @samp +@item repeat +Indicates that repeated log output should not be compressed to the first line +and the "Last message repeated n times" line will be omitted. +@item level +Indicates that log output should add a @code{[level]} prefix to each message +line. This can be used as an alternative to log coloring, e.g. when dumping the +log to file. +@end table +Flags can also be used alone by adding a '+'/'-' prefix to set/reset a single +flag without affecting other @var{flags} or changing @var{loglevel}. When +setting both @var{flags} and @var{loglevel}, a '+' separator is expected +between the last @var{flags} value and before @var{loglevel}. + @var{loglevel} is a string or a number containing one of the following values: @table @samp @item quiet, -8 @@ -201,6 +221,17 @@ Show everything, including debugging information. @item trace, 56 @end table +For example to enable repeated log output, add the @code{level} prefix, and set +@var{loglevel} to @code{verbose}: +@example +ffmpeg -loglevel repeat+level+verbose -i input output +@end example +Another example that enables repeated log output without affecting current +state of @code{level} prefix flag or @var{loglevel}: +@example +ffmpeg [...] -loglevel +repeat +@end example + By default the program logs to stderr. If coloring is supported by the terminal, colors are used to mark errors and warnings. Log coloring can be disabled setting the environment variable @@ -315,51 +346,6 @@ Possible flags for this option are: @item k8 @end table @end table - -@item -opencl_bench -This option is used to benchmark all available OpenCL devices and print the -results. This option is only available when FFmpeg has been compiled with -@code{--enable-opencl}. - -When FFmpeg is configured with @code{--enable-opencl}, the options for the -global OpenCL context are set via @option{-opencl_options}. See the -"OpenCL Options" section in the ffmpeg-utils manual for the complete list of -supported options. Amongst others, these options include the ability to select -a specific platform and device to run the OpenCL code on. By default, FFmpeg -will run on the first device of the first platform. While the options for the -global OpenCL context provide flexibility to the user in selecting the OpenCL -device of their choice, most users would probably want to select the fastest -OpenCL device for their system. - -This option assists the selection of the most efficient configuration by -identifying the appropriate device for the user's system. The built-in -benchmark is run on all the OpenCL devices and the performance is measured for -each device. The devices in the results list are sorted based on their -performance with the fastest device listed first. The user can subsequently -invoke @command{ffmpeg} using the device deemed most appropriate via -@option{-opencl_options} to obtain the best performance for the OpenCL -accelerated code. - -Typical usage to use the fastest OpenCL device involve the following steps. - -Run the command: -@example -ffmpeg -opencl_bench -@end example -Note down the platform ID (@var{pidx}) and device ID (@var{didx}) of the first -i.e. fastest device in the list. -Select the platform and device using the command: -@example -ffmpeg -opencl_options platform_idx=@var{pidx}:device_idx=@var{didx} ... -@end example - -@item -opencl_options options (@emph{global}) -Set OpenCL environment options. This option is only available when -FFmpeg has been compiled with @code{--enable-opencl}. - -@var{options} must be a list of @var{key}=@var{value} option pairs -separated by ':'. See the ``OpenCL Options'' section in the -ffmpeg-utils manual for the list of supported options. @end table @section AVOptions diff --git a/doc/filters.texi b/doc/filters.texi index e26dde4b1a9f4..f267d26b9db40 100644 --- a/doc/filters.texi +++ b/doc/filters.texi @@ -221,6 +221,7 @@ Here is a BNF description of the filtergraph syntax: @var{FILTERGRAPH} ::= [sws_flags=@var{flags};] @var{FILTERCHAIN} [;@var{FILTERGRAPH}] @end example +@anchor{filtergraph escaping} @section Notes on filtergraph escaping Filtergraph description composition entails several levels of @@ -429,6 +430,16 @@ How much to use compressed signal in output. Default is 1. Range is between 0 and 1. @end table +@section acontrast +Simple audio dynamic range commpression/expansion filter. + +The filter accepts the following options: + +@table @option +@item contrast +Set contrast. Default is 33. Allowed range is between 0 and 100. +@end table + @section acopy Copy the input audio source unchanged to the output. This is mainly useful for @@ -499,7 +510,7 @@ An Anti-Aliasing setting is able to produce "softer" crushing sounds. Another feature of this filter is the logarithmic mode. This setting switches from linear distances between bits to logarithmic ones. The result is a much more "natural" sounding crusher which doesn't gate low -signals for example. The human ear has a logarithmic perception, too +signals for example. The human ear has a logarithmic perception, so this kind of crushing is much more pleasant. Logarithmic crushing is also able to get anti-aliased. @@ -916,6 +927,7 @@ afftfilt="1-clip((b/nb)*b,0,1)" @end example @end itemize +@anchor{afir} @section afir Apply an arbitrary Frequency Impulse Response filter. @@ -1049,6 +1061,89 @@ the reduction. Default is @code{average}. Can be @code{average} or @code{maximum}. @end table +@section aiir + +Apply an arbitrary Infinite Impulse Response filter. + +It accepts the following parameters: + +@table @option +@item z +Set numerator/zeros coefficients. + +@item p +Set denominator/poles coefficients. + +@item k +Set channels gains. + +@item dry_gain +Set input gain. + +@item wet_gain +Set output gain. + +@item f +Set coefficients format. + +@table @samp +@item tf +transfer function +@item zp +Z-plane zeros/poles, cartesian (default) +@item pr +Z-plane zeros/poles, polar radians +@item pd +Z-plane zeros/poles, polar degrees +@end table + +@item r +Set kind of processing. +Can be @code{d} - direct or @code{s} - serial cascading. Defauls is @code{s}. + +@item e +Set filtering precision. + +@table @samp +@item dbl +double-precision floating-point (default) +@item flt +single-precision floating-point +@item i32 +32-bit integers +@item i16 +16-bit integers +@end table + +@end table + +Coefficients in @code{tf} format are separated by spaces and are in ascending +order. + +Coefficients in @code{zp} format are separated by spaces and order of coefficients +doesn't matter. Coefficients in @code{zp} format are complex numbers with @var{i} +imaginary unit. + +Different coefficients and gains can be provided for every channel, in such case +use '|' to separate coefficients or gains. Last provided coefficients will be +used for all remaining channels. + +@subsection Examples + +@itemize +@item +Apply 2 pole elliptic notch at arround 5000Hz for 48000 Hz sample rate: +@example +aiir=k=1:z=7.957584807809675810E-1 -2.575128568908332300 3.674839853930788710 -2.57512875289799137 7.957586296317130880E-1:p=1 -2.86950072432325953 3.63022088054647218 -2.28075678147272232 6.361362326477423500E-1:f=tf:r=d +@end example + +@item +Same as above but in @code{zp} format: +@example +aiir=k=0.79575848078096756:z=0.80918701+0.58773007i 0.80918701-0.58773007i 0.80884700+0.58784055i 0.80884700-0.58784055i:p=0.63892345+0.59951235i 0.63892345-0.59951235i 0.79582691+0.44198673i 0.79582691-0.44198673i:f=zp:r=s +@end example +@end itemize + @section alimiter The limiter prevents an input signal from rising over a desired threshold. @@ -1117,6 +1212,8 @@ Q-Factor octave @item s slope +@item k +kHz @end table @item width, w @@ -1126,6 +1223,23 @@ Specify the band-width of a filter in width_type units. Specify which channels to filter, by default all available are filtered. @end table +@subsection Commands + +This filter supports the following commands: +@table @option +@item frequency, f +Change allpass frequency. +Syntax for the command is : "@var{frequency}" + +@item width_type, t +Change allpass width_type. +Syntax for the command is : "@var{width_type}" + +@item width, w +Change allpass width. +Syntax for the command is : "@var{width}" +@end table + @section aloop Loop audio samples. @@ -1134,13 +1248,14 @@ The filter accepts the following options: @table @option @item loop -Set the number of loops. +Set the number of loops. Setting this value to -1 will result in infinite loops. +Default is 0. @item size -Set maximal number of samples. +Set maximal number of samples. Default is 0. @item start -Set first sample of loop. +Set first sample of loop. Default is 0. @end table @anchor{amerge} @@ -1236,6 +1351,9 @@ The duration of the first input. The transition time, in seconds, for volume renormalization when an input stream ends. The default value is 2 seconds. +@item weights +Specify weight of each input audio stream as sequence. +Each weight is separated by space. By default all inputs have same weight. @end table @section anequalizer @@ -1497,7 +1615,7 @@ The filter accepts the syntax [@var{sample_rate}:]@var{resampler_options}, where @var{sample_rate} expresses a sample rate and @var{resampler_options} is a list of @var{key}=@var{value} pairs, separated by ":". See the -@ref{Resampler Options,,the "Resampler Options" section in the +@ref{Resampler Options,,"Resampler Options" section in the ffmpeg-resampler(1) manual,ffmpeg-resampler} for the complete list of supported options. @@ -1632,7 +1750,7 @@ It accepts the following option: @table @option @item length Short window length in seconds, used for peak and trough RMS measurement. -Default is @code{0.05} (50 milliseconds). Allowed range is @code{[0.1 - 10]}. +Default is @code{0.05} (50 milliseconds). Allowed range is @code{[0.01 - 10]}. @item metadata @@ -1856,6 +1974,8 @@ Q-Factor octave @item s slope +@item k +kHz @end table @item width, w @@ -1865,6 +1985,23 @@ Specify the band-width of a filter in width_type units. Specify which channels to filter, by default all available are filtered. @end table +@subsection Commands + +This filter supports the following commands: +@table @option +@item frequency, f +Change bandpass frequency. +Syntax for the command is : "@var{frequency}" + +@item width_type, t +Change bandpass width_type. +Syntax for the command is : "@var{width_type}" + +@item width, w +Change bandpass width. +Syntax for the command is : "@var{width}" +@end table + @section bandreject Apply a two-pole Butterworth band-reject filter with central @@ -1888,6 +2025,8 @@ Q-Factor octave @item s slope +@item k +kHz @end table @item width, w @@ -1897,6 +2036,23 @@ Specify the band-width of a filter in width_type units. Specify which channels to filter, by default all available are filtered. @end table +@subsection Commands + +This filter supports the following commands: +@table @option +@item frequency, f +Change bandreject frequency. +Syntax for the command is : "@var{frequency}" + +@item width_type, t +Change bandreject width_type. +Syntax for the command is : "@var{width_type}" + +@item width, w +Change bandreject width. +Syntax for the command is : "@var{width}" +@end table + @section bass Boost or cut the bass (lower) frequencies of the audio using a two-pole @@ -1927,6 +2083,8 @@ Q-Factor octave @item s slope +@item k +kHz @end table @item width, w @@ -1936,6 +2094,27 @@ Determine how steep is the filter's shelf transition. Specify which channels to filter, by default all available are filtered. @end table +@subsection Commands + +This filter supports the following commands: +@table @option +@item frequency, f +Change bass frequency. +Syntax for the command is : "@var{frequency}" + +@item width_type, t +Change bass width_type. +Syntax for the command is : "@var{width_type}" + +@item width, w +Change bass width. +Syntax for the command is : "@var{width}" + +@item gain, g +Change bass gain. +Syntax for the command is : "@var{gain}" +@end table + @section biquad Apply a biquad IIR filter with the given coefficients. @@ -1944,6 +2123,20 @@ are the numerator and denominator coefficients respectively. and @var{channels}, @var{c} specify which channels to filter, by default all available are filtered. +@subsection Commands + +This filter supports the following commands: +@table @option +@item a0 +@item a1 +@item a2 +@item b0 +@item b1 +@item b2 +Change biquad parameter. +Syntax for the command is : "@var{value}" +@end table + @section bs2b Bauer stereo to binaural transformation, which improves headphone listening of stereo audio records. @@ -1999,6 +2192,10 @@ The channel layout of the output stream. If no mapping is present, the filter will implicitly map input channels to output channels, preserving indices. +@subsection Examples + +@itemize +@item For example, assuming a 5.1+downmix input MOV file, @example ffmpeg -i in.mov -filter 'channelmap=map=DL-FL|DR-FR' out.wav @@ -2006,10 +2203,12 @@ ffmpeg -i in.mov -filter 'channelmap=map=DL-FL|DR-FR' out.wav will create an output WAV file tagged as stereo from the downmix channels of the input. +@item To fix a 5.1 WAV improperly encoded in AAC's native channel order @example ffmpeg -i in.wav -filter 'channelmap=1|2|0|5|3|4:5.1' out.wav @end example +@end itemize @section channelsplit @@ -2019,8 +2218,17 @@ It accepts the following parameters: @table @option @item channel_layout The channel layout of the input stream. The default is "stereo". +@item channels +A channel layout describing the channels to be extracted as separate output streams +or "all" to extract each input channel as a separate stream. The default is "all". + +Choosing channels not present in channel layout in the input will result in an error. @end table +@subsection Examples + +@itemize +@item For example, assuming a stereo input MP3 file, @example ffmpeg -i in.mp3 -filter_complex channelsplit out.mkv @@ -2028,6 +2236,7 @@ ffmpeg -i in.mp3 -filter_complex channelsplit out.mkv will create an output Matroska file with two audio streams, one containing only the left channel and the other the right channel. +@item Split a 5.1 WAV file into per-channel files: @example ffmpeg -i in.wav -filter_complex @@ -2037,6 +2246,14 @@ front_center.wav -map '[LFE]' lfe.wav -map '[SL]' side_left.wav -map '[SR]' side_right.wav @end example +@item +Extract only LFE from a 5.1 WAV file: +@example +ffmpeg -i in.wav -filter_complex 'channelsplit=channel_layout=5.1:channels=LFE[LFE]' +-map '[LFE]' lfe.wav +@end example +@end itemize + @section chorus Add a chorus effect to the audio. @@ -2349,6 +2566,21 @@ Optional. It should have a value much less than 1 (e.g. 0.05 or 0.02) and is used to prevent clipping. @end table +@section drmeter +Measure audio dynamic range. + +DR values of 14 and higher is found in very dynamic material. DR of 8 to 13 +is found in transition material. And anything less that 8 have very poor dynamics +and is very compressed. + +The filter accepts the following options: + +@table @option +@item length +Set window length in seconds used to split audio into segments of equal length. +Default is 3 seconds. +@end table + @section dynaudnorm Dynamic Audio Normalizer. @@ -2545,6 +2777,8 @@ Q-Factor octave @item s slope +@item k +kHz @end table @item width, w @@ -2573,6 +2807,27 @@ equalizer=f=1000:t=q:w=1:g=2,equalizer=f=100:t=q:w=2:g=-5 @end example @end itemize +@subsection Commands + +This filter supports the following commands: +@table @option +@item frequency, f +Change equalizer frequency. +Syntax for the command is : "@var{frequency}" + +@item width_type, t +Change equalizer width_type. +Syntax for the command is : "@var{width_type}" + +@item width, w +Change equalizer width. +Syntax for the command is : "@var{width}" + +@item gain, g +Change equalizer gain. +Syntax for the command is : "@var{gain}" +@end table + @section extrastereo Linearly increases the difference between left and right channels which @@ -2920,6 +3175,21 @@ Default is @var{freq}. @item lfe Set custom gain for LFE channels. Value is in dB. Default is 0. + +@item size +Set size of frame in number of samples which will be processed at once. +Default value is @var{1024}. Allowed range is from 1024 to 96000. + +@item hrir +Set format of hrir stream. +Default value is @var{stereo}. Alternative value is @var{multich}. +If value is set to @var{stereo}, number of additional streams should +be greater or equal to number of input channels in first input stream. +Also each additional stream should have stereo number of channels. +If value is set to @var{multich}, number of additional streams should +be exactly one. Also number of input channels of additional stream +should be equal or greater than twice number of channels of first input +stream. @end table @subsection Examples @@ -2933,6 +3203,14 @@ The files give coefficients for each position of virtual loudspeaker: ffmpeg -i input.wav -lavfi-complex "amovie=azi_270_ele_0_DFC.wav[sr],amovie=azi_90_ele_0_DFC.wav[sl],amovie=azi_225_ele_0_DFC.wav[br],amovie=azi_135_ele_0_DFC.wav[bl],amovie=azi_0_ele_0_DFC.wav,asplit[fc][lfe],amovie=azi_35_ele_0_DFC.wav[fl],amovie=azi_325_ele_0_DFC.wav[fr],[a:0][fl][fr][fc][lfe][bl][br][sl][sr]headphone=FL|FR|FC|LFE|BL|BR|SL|SR" output.wav @end example + +@item +Full example using wav files as coefficients with amovie filters for 7.1 downmix, +but now in @var{multich} @var{hrir} format. +@example +ffmpeg -i input.wav -lavfi-complex "amovie=minp.wav[hrirs],[a:0][hrirs]headphone=map=FL|FR|FC|LFE|BL|BR|SL|SR:hrir=multich" +output.wav +@end example @end itemize @section highpass @@ -2961,6 +3239,8 @@ Q-Factor octave @item s slope +@item k +kHz @end table @item width, w @@ -2972,6 +3252,23 @@ The default is 0.707q and gives a Butterworth response. Specify which channels to filter, by default all available are filtered. @end table +@subsection Commands + +This filter supports the following commands: +@table @option +@item frequency, f +Change highpass frequency. +Syntax for the command is : "@var{frequency}" + +@item width_type, t +Change highpass width_type. +Syntax for the command is : "@var{width_type}" + +@item width, w +Change highpass width. +Syntax for the command is : "@var{width}" +@end table + @section join Join multiple input streams into one multi-channel stream. @@ -3250,6 +3547,8 @@ Q-Factor octave @item s slope +@item k +kHz @end table @item width, w @@ -3270,6 +3569,98 @@ lowpass=c=LFE @end example @end itemize +@subsection Commands + +This filter supports the following commands: +@table @option +@item frequency, f +Change lowpass frequency. +Syntax for the command is : "@var{frequency}" + +@item width_type, t +Change lowpass width_type. +Syntax for the command is : "@var{width_type}" + +@item width, w +Change lowpass width. +Syntax for the command is : "@var{width}" +@end table + +@section lv2 + +Load a LV2 (LADSPA Version 2) plugin. + +To enable compilation of this filter you need to configure FFmpeg with +@code{--enable-lv2}. + +@table @option +@item plugin, p +Specifies the plugin URI. You may need to escape ':'. + +@item controls, c +Set the '|' separated list of controls which are zero or more floating point +values that determine the behavior of the loaded plugin (for example delay, +threshold or gain). +If @option{controls} is set to @code{help}, all available controls and +their valid ranges are printed. + +@item sample_rate, s +Specify the sample rate, default to 44100. Only used if plugin have +zero inputs. + +@item nb_samples, n +Set the number of samples per channel per each output frame, default +is 1024. Only used if plugin have zero inputs. + +@item duration, d +Set the minimum duration of the sourced audio. See +@ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) manual,ffmpeg-utils} +for the accepted syntax. +Note that the resulting duration may be greater than the specified duration, +as the generated audio is always cut at the end of a complete frame. +If not specified, or the expressed duration is negative, the audio is +supposed to be generated forever. +Only used if plugin have zero inputs. +@end table + +@subsection Examples + +@itemize +@item +Apply bass enhancer plugin from Calf: +@example +lv2=p=http\\\\://calf.sourceforge.net/plugins/BassEnhancer:c=amount=2 +@end example + +@item +Apply vinyl plugin from Calf: +@example +lv2=p=http\\\\://calf.sourceforge.net/plugins/Vinyl:c=drone=0.2|aging=0.5 +@end example + +@item +Apply bit crusher plugin from ArtyFX: +@example +lv2=p=http\\\\://www.openavproductions.com/artyfx#bitta:c=crush=0.3 +@end example +@end itemize + +@section mcompand +Multiband Compress or expand the audio's dynamic range. + +The input audio is divided into bands using 4th order Linkwitz-Riley IIRs. +This is akin to the crossover of a loudspeaker, and results in flat frequency +response when absent compander action. + +It accepts the following parameters: + +@table @option +@item args +This option syntax is: +attack,decay,[attack,decay..] soft-knee points crossover_frequency [delay [initial_volume [gain]]] | attack,decay ... +For explanation of each item refer to compand filter documentation. +@end table + @anchor{pan} @section pan @@ -4067,6 +4458,8 @@ Q-Factor octave @item s slope +@item k +kHz @end table @item width, w @@ -4076,6 +4469,27 @@ Determine how steep is the filter's shelf transition. Specify which channels to filter, by default all available are filtered. @end table +@subsection Commands + +This filter supports the following commands: +@table @option +@item frequency, f +Change treble frequency. +Syntax for the command is : "@var{frequency}" + +@item width_type, t +Change treble width_type. +Syntax for the command is : "@var{width_type}" + +@item width, w +Change treble width. +Syntax for the command is : "@var{width}" + +@item gain, g +Change treble gain. +Syntax for the command is : "@var{gain}" +@end table + @section tremolo Sinusoidal amplitude modulation. @@ -4512,7 +4926,7 @@ Synthesize a voice utterance using the libflite library. To enable compilation of this filter you need to configure FFmpeg with @code{--enable-libflite}. -Note that the flite library is not thread-safe. +Note that versions of the flite library prior to 2.0 are not thread-safe. The filter accepts the following options: @@ -4567,7 +4981,7 @@ ffplay -f lavfi flite=text='No more be grieved for which that thou hast done.' @end itemize For more information about libflite, check: -@url{http://www.speech.cs.cmu.edu/flite/} +@url{http://www.festvox.org/flite/} @section anoisesrc @@ -4609,6 +5023,33 @@ anoisesrc=d=60:c=pink:r=44100:a=0.5 @end example @end itemize +@section hilbert + +Generate odd-tap Hilbert transform FIR coefficients. + +The resulting stream can be used with @ref{afir} filter for phase-shifting +the signal by 90 degrees. + +This is used in many matrix coding schemes and for analytic signal generation. +The process is often written as a multiplication by i (or j), the imaginary unit. + +The filter accepts the following options: + +@table @option + +@item sample_rate, s +Set sample rate, default is 44100. + +@item taps, t +Set length of FIR filter, default is 22051. + +@item nb_samples, n +Set number of samples per each frame. + +@item win_func, w +Set window function to be used when generating FIR coefficients. +@end table + @section sine Generate an audio signal made of a sine wave with amplitude 1/8. @@ -5939,7 +6380,7 @@ colorspace=smpte240m @section convolution -Apply convolution 3x3 or 5x5 filter. +Apply convolution 3x3, 5x5 or 7x7 filter. The filter accepts the following options: @@ -5949,7 +6390,7 @@ The filter accepts the following options: @item 2m @item 3m Set matrix for each plane. -Matrix is sequence of 9 or 25 signed integers. +Matrix is sequence of 9, 25 or 49 signed integers. @item 0rdiv @item 1rdiv @@ -6673,6 +7114,29 @@ Set whether or not chroma is considered in the metric calculations. Default is @code{1}. @end table +@section deconvolve + +Apply 2D deconvolution of video stream in frequency domain using second stream +as impulse. + +The filter accepts the following options: + +@table @option +@item planes +Set which planes to process. + +@item impulse +Set which impulse video frames will be processed, can be @var{first} +or @var{all}. Default is @var{all}. + +@item noise +Set noise when doing divisions. Default is @var{0.0000001}. Useful when width +and height are not same and not power of 2 or if stream prior to convolving +had noise. +@end table + +The @code{deconvolve} filter also supports the @ref{framesync} options. + @section deflate Apply deflate effect to the video. @@ -6887,10 +7351,6 @@ Default value is @samp{exhaustive}. If set then a detailed log of the motion search is written to the specified file. -@item opencl -If set to 1, specify using OpenCL capabilities, only available if -FFmpeg was configured with @code{--enable-opencl}. Default value is 0. - @end table @section despill @@ -7055,14 +7515,20 @@ the input width and height. It defaults to 0. @item color, c Specify the color of the box to write. For the general syntax of this option, -check the "Color" section in the ffmpeg-utils manual. If the special +check the @ref{color syntax,,"Color" section in the ffmpeg-utils manual,ffmpeg-utils}. If the special value @code{invert} is used, the box edge color is the same as the video with inverted luma. @item thickness, t -The expression which sets the thickness of the box edge. Default value is @code{3}. +The expression which sets the thickness of the box edge. +A value of @code{fill} will create a filled box. Default value is @code{3}. See below for the list of accepted constants. + +@item replace +Applicable if the input has alpha. With value @code{1}, the pixels of the painted box +will overwrite the video's color and alpha pixels. +Default is @code{0}, which composites the box onto the input, leaving the video's alpha intact. @end table The parameters for @var{x}, @var{y}, @var{w} and @var{h} and @var{t} are expressions containing the @@ -7123,7 +7589,7 @@ drawbox=x=10:y=20:w=200:h=60:color=red@@0.5 @item Fill the box with pink color: @example -drawbox=x=10:y=10:w=100:h=100:color=pink@@0.5:t=max +drawbox=x=10:y=10:w=100:h=100:color=pink@@0.5:t=fill @end example @item @@ -7152,7 +7618,7 @@ framed. Default to 0. @item color, c Specify the color of the grid. For the general syntax of this option, -check the "Color" section in the ffmpeg-utils manual. If the special +check the @ref{color syntax,,"Color" section in the ffmpeg-utils manual,ffmpeg-utils}. If the special value @code{invert} is used, the grid color is the same as the video with inverted luma. @@ -7160,6 +7626,11 @@ video with inverted luma. The expression which sets the thickness of the grid line. Default value is @code{1}. See below for the list of accepted constants. + +@item replace +Applicable if the input has alpha. With @code{1} the pixels of the painted grid +will overwrite the video's color and alpha pixels. +Default is @code{0}, which composites the grid onto the input, leaving the video's alpha intact. @end table The parameters for @var{x}, @var{y}, @var{w} and @var{h} and @var{t} are expressions containing the @@ -7243,7 +7714,7 @@ The default value of @var{boxborderw} is 0. @item boxcolor The color to be used for drawing box around text. For the syntax of this -option, check the "Color" section in the ffmpeg-utils manual. +option, check the @ref{color syntax,,"Color" section in the ffmpeg-utils manual,ffmpeg-utils}. The default value of @var{boxcolor} is "white". @@ -7257,7 +7728,7 @@ The default value of @var{borderw} is 0. @item bordercolor Set the color to be used for drawing border around text. For the syntax of this -option, check the "Color" section in the ffmpeg-utils manual. +option, check the @ref{color syntax,,"Color" section in the ffmpeg-utils manual,ffmpeg-utils}. The default value of @var{bordercolor} is "black". @@ -7278,7 +7749,7 @@ If true, check and fix text coords to avoid clipping. @item fontcolor The color to be used for drawing fonts. For the syntax of this option, check -the "Color" section in the ffmpeg-utils manual. +the @ref{color syntax,,"Color" section in the ffmpeg-utils manual,ffmpeg-utils}. The default value of @var{fontcolor} is "black". @@ -7341,7 +7812,8 @@ libfreetype flags. @item shadowcolor The color to be used for drawing a shadow behind the drawn text. For the -syntax of this option, check the "Color" section in the ffmpeg-utils manual. +syntax of this option, check the @ref{color syntax,,"Color" section in the +ffmpeg-utils manual,ffmpeg-utils}. The default value of @var{shadowcolor} is "black". @@ -7365,7 +7837,9 @@ format. It can be used with or without text parameter. @var{timecode_rate} option must be specified. @item timecode_rate, rate, r -Set the timecode frame rate (timecode only). +Set the timecode frame rate (timecode only). Value will be rounded to nearest +integer. Minimum value is "1". +Drop-frame timecode is supported for frame rates 30 & 60. @item tc24hmax If set to 1, the output of the timecode option will wrap around at 24 hours. @@ -7924,6 +8398,20 @@ Set pal8 output pixel format. This option does not work with codebook length greater than 256. @end table +@section entropy + +Measure graylevel entropy in histogram of color channels of video frames. + +It accepts the following parameters: + +@table @option +@item mode +Can be either @var{normal} or @var{diff}. Default is @var{normal}. + +@var{diff} mode measures entropy of histogram delta values, absolute differences +between neighbour histogram values. +@end table + @section fade Apply a fade-in/out effect to the input video. @@ -8525,6 +9013,48 @@ framework. It does not take parameters. +@section fillborders + +Fill borders of the input video, without changing video stream dimensions. +Sometimes video can have garbage at the four edges and you may not want to +crop video input to keep size multiple of some number. + +This filter accepts the following options: + +@table @option +@item left +Number of pixels to fill from left border. + +@item right +Number of pixels to fill from right border. + +@item top +Number of pixels to fill from top border. + +@item bottom +Number of pixels to fill from bottom border. + +@item mode +Set fill mode. + +It accepts the following values: +@table @samp +@item smear +fill pixels using outermost pixels + +@item mirror +fill pixels using mirroring + +@item fixed +fill pixels with constant value +@end table + +Default is @var{smear}. + +@item color +Set color for pixels in fixed mode. Default is @var{black}. +@end table + @section find_rect Find a rectangular object @@ -8806,7 +9336,7 @@ Specify the level at which a scene change is detected as a value between 0 and 100 to indicate a new scene; a low value reflects a low probability for the current frame to introduce a new scene, while a higher value means the current frame is more likely to be one. -The default is @code{7}. +The default is @code{8.2}. @item flags Specify flags influencing the filter process. @@ -8859,8 +9389,9 @@ A '|'-separated list of parameters to pass to the frei0r effect. A frei0r effect parameter can be a boolean (its value is either "y" or "n"), a double, a color (specified as @var{R}/@var{G}/@var{B}, where @var{R}, @var{G}, and @var{B} are floating point -numbers between 0.0 and 1.0, inclusive) or by a color description specified in the "Color" -section in the ffmpeg-utils manual), a position (specified as @var{X}/@var{Y}, where +numbers between 0.0 and 1.0, inclusive) or a color description as specified in the +@ref{color syntax,,"Color" section in the ffmpeg-utils manual,ffmpeg-utils}, +a position (specified as @var{X}/@var{Y}, where @var{X} and @var{Y} are floating point numbers) and/or a string. The number and types of parameters depend on the loaded effect. If an @@ -9865,15 +10396,17 @@ The filter accepts the following options: @item cx Relative x-coordinate of the focal point of the image, and thereby the center of the distortion. This value has a range [0,1] and is expressed as fractions of the image -width. +width. Default is 0.5. @item cy Relative y-coordinate of the focal point of the image, and thereby the center of the distortion. This value has a range [0,1] and is expressed as fractions of the image -height. +height. Default is 0.5. @item k1 -Coefficient of the quadratic correction term. 0.5 means no correction. +Coefficient of the quadratic correction term. This value has a range [-1,1]. 0 means +no correction. Default is 0. @item k2 -Coefficient of the double quadratic correction term. 0.5 means no correction. +Coefficient of the double quadratic correction term. This value has a range [-1,1]. +0 means no correction. Default is 0. @end table The formula that generates the correction is: @@ -9885,25 +10418,16 @@ distances from the focal point in the source and target images, respectively. @section libvmaf -Obtain the average VMAF (Video Multi-Method Assessment Fusion) -score between two input videos. - -This filter takes two input videos. - -Both video inputs must have the same resolution and pixel format for -this filter to work correctly. Also it assumes that both inputs -have the same number of frames, which are compared one by one. +Obtain the VMAF (Video Multi-Method Assessment Fusion) +score between two input videos. -The obtained average VMAF score is printed through the logging system. +The obtained VMAF score is printed through the logging system. It requires Netflix's vmaf library (libvmaf) as a pre-requisite. After installing the library it can be enabled using: @code{./configure --enable-libvmaf}. If no model path is specified it uses the default model: @code{vmaf_v0.6.1.pkl}. -On the below examples the input file @file{main.mpg} being processed is -compared with the reference file @file{ref.mpg}. - The filter has following options: @table @option @@ -9934,12 +10458,14 @@ Enables computing ssim along with vmaf. Enables computing ms_ssim along with vmaf. @item pool -Set the pool method to be used for computing vmaf. +Set the pool method (mean, min or harmonic mean) to be used for computing vmaf. @end table This filter also supports the @ref{framesync} options. -For example: +On the below examples the input file @file{main.mpg} being processed is +compared with the reference file @file{ref.mpg}. + @example ffmpeg -i main.mpg -i ref.mpg -lavfi libvmaf -f null - @end example @@ -9974,13 +10500,14 @@ The filter accepts the following options: @table @option @item loop -Set the number of loops. +Set the number of loops. Setting this value to -1 will result in infinite loops. +Default is 0. @item size -Set maximal size in number of frames. +Set maximal size in number of frames. Default is 0. @item start -Set first frame of loop. +Set first frame of loop. Default is 0. @end table @anchor{lut3d} @@ -10550,6 +11077,34 @@ Default method is @samp{fdiff}. Scene change detection threshold. Default is @code{5.0}. @end table +@section mix + +Mix several video input streams into one video stream. + +A description of the accepted options follows. + +@table @option +@item nb_inputs +The number of inputs. If unspecified, it defaults to 2. + +@item weights +Specify weight of each input video stream as sequence. +Each weight is separated by space. + +@item duration +Specify how end of stream is determined. +@table @samp +@item longest +The duration of the longest input. (default) + +@item shortest +The duration of the shortest input. + +@item first +The duration of the first input. +@end table +@end table + @section mpdecimate Drop frames that do not differ greatly from the previous frame in @@ -10820,6 +11375,86 @@ Add temporal and uniform noise to input video: noise=alls=20:allf=t+u @end example +@section normalize + +Normalize RGB video (aka histogram stretching, contrast stretching). +See: https://en.wikipedia.org/wiki/Normalization_(image_processing) + +For each channel of each frame, the filter computes the input range and maps +it linearly to the user-specified output range. The output range defaults +to the full dynamic range from pure black to pure white. + +Temporal smoothing can be used on the input range to reduce flickering (rapid +changes in brightness) caused when small dark or bright objects enter or leave +the scene. This is similar to the auto-exposure (automatic gain control) on a +video camera, and, like a video camera, it may cause a period of over- or +under-exposure of the video. + +The R,G,B channels can be normalized independently, which may cause some +color shifting, or linked together as a single channel, which prevents +color shifting. Linked normalization preserves hue. Independent normalization +does not, so it can be used to remove some color casts. Independent and linked +normalization can be combined in any ratio. + +The normalize filter accepts the following options: + +@table @option +@item blackpt +@item whitept +Colors which define the output range. The minimum input value is mapped to +the @var{blackpt}. The maximum input value is mapped to the @var{whitept}. +The defaults are black and white respectively. Specifying white for +@var{blackpt} and black for @var{whitept} will give color-inverted, +normalized video. Shades of grey can be used to reduce the dynamic range +(contrast). Specifying saturated colors here can create some interesting +effects. + +@item smoothing +The number of previous frames to use for temporal smoothing. The input range +of each channel is smoothed using a rolling average over the current frame +and the @var{smoothing} previous frames. The default is 0 (no temporal +smoothing). + +@item independence +Controls the ratio of independent (color shifting) channel normalization to +linked (color preserving) normalization. 0.0 is fully linked, 1.0 is fully +independent. Defaults to 1.0 (fully independent). + +@item strength +Overall strength of the filter. 1.0 is full strength. 0.0 is a rather +expensive no-op. Defaults to 1.0 (full strength). + +@end table + +@subsection Examples + +Stretch video contrast to use the full dynamic range, with no temporal +smoothing; may flicker depending on the source content: +@example +normalize=blackpt=black:whitept=white:smoothing=0 +@end example + +As above, but with 50 frames of temporal smoothing; flicker should be +reduced, depending on the source content: +@example +normalize=blackpt=black:whitept=white:smoothing=50 +@end example + +As above, but with hue-preserving linked channel normalization: +@example +normalize=blackpt=black:whitept=white:smoothing=50:independence=0 +@end example + +As above, but with half strength: +@example +normalize=blackpt=black:whitept=white:smoothing=50:independence=0:strength=0.5 +@end example + +Map the darkest input color to red, the brightest input color to cyan: +@example +normalize=blackpt=red:whitept=cyan +@end example + @section null Pass the video source unchanged to the output. @@ -11099,6 +11734,10 @@ Default value is @samp{yuv420}. @item repeatlast See @ref{framesync}. + +@item alpha +Set format of alpha of the overlaid video, it can be @var{straight} or +@var{premultiplied}. Default is @var{straight}. @end table The @option{x}, and @option{y} expressions can contain the following @@ -11312,7 +11951,8 @@ so the input image is centered on the padded area. @item color Specify the color of the padded area. For the syntax of this option, -check the "Color" section in the ffmpeg-utils manual. +check the @ref{color syntax,,"Color" section in the ffmpeg-utils +manual,ffmpeg-utils}. The default value of @var{color} is "black". @@ -11458,6 +12098,9 @@ If not set, the maximum of colors in the palette will be 256. You probably want to disable this option for a standalone image. Set by default. +@item transparency_color +Set the color that will be used as background for transparency. + @item stats_mode Set statistics mode. @@ -11545,6 +12188,13 @@ Default is @var{none}. @item new Take new palette for each output frame. + +@item alpha_threshold +Sets the alpha threshold for transparency. Alpha values above this threshold +will be treated as completely opaque, and values below this threshold will be +treated as completely transparent. + +The option must be an integer value in the range [0,255]. Default is @var{128}. @end table @subsection Examples @@ -11974,6 +12624,136 @@ Set value which will be multiplied with filtered result. Set value which will be added to filtered result. @end table +@anchor{program_opencl} +@section program_opencl + +Filter video using an OpenCL program. + +@table @option + +@item source +OpenCL program source file. + +@item kernel +Kernel name in program. + +@item inputs +Number of inputs to the filter. Defaults to 1. + +@item size, s +Size of output frames. Defaults to the same as the first input. + +@end table + +The program source file must contain a kernel function with the given name, +which will be run once for each plane of the output. Each run on a plane +gets enqueued as a separate 2D global NDRange with one work-item for each +pixel to be generated. The global ID offset for each work-item is therefore +the coordinates of a pixel in the destination image. + +The kernel function needs to take the following arguments: +@itemize +@item +Destination image, @var{__write_only image2d_t}. + +This image will become the output; the kernel should write all of it. +@item +Frame index, @var{unsigned int}. + +This is a counter starting from zero and increasing by one for each frame. +@item +Source images, @var{__read_only image2d_t}. + +These are the most recent images on each input. The kernel may read from +them to generate the output, but they can't be written to. +@end itemize + +Example programs: + +@itemize +@item +Copy the input to the output (output must be the same size as the input). +@verbatim +__kernel void copy(__write_only image2d_t destination, + unsigned int index, + __read_only image2d_t source) +{ + const sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE; + + int2 location = (int2)(get_global_id(0), get_global_id(1)); + + float4 value = read_imagef(source, sampler, location); + + write_imagef(destination, location, value); +} +@end verbatim + +@item +Apply a simple transformation, rotating the input by an amount increasing +with the index counter. Pixel values are linearly interpolated by the +sampler, and the output need not have the same dimensions as the input. +@verbatim +__kernel void rotate_image(__write_only image2d_t dst, + unsigned int index, + __read_only image2d_t src) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_FILTER_LINEAR); + + float angle = (float)index / 100.0f; + + float2 dst_dim = convert_float2(get_image_dim(dst)); + float2 src_dim = convert_float2(get_image_dim(src)); + + float2 dst_cen = dst_dim / 2.0f; + float2 src_cen = src_dim / 2.0f; + + int2 dst_loc = (int2)(get_global_id(0), get_global_id(1)); + + float2 dst_pos = convert_float2(dst_loc) - dst_cen; + float2 src_pos = { + cos(angle) * dst_pos.x - sin(angle) * dst_pos.y, + sin(angle) * dst_pos.x + cos(angle) * dst_pos.y + }; + src_pos = src_pos * src_dim / dst_dim; + + float2 src_loc = src_pos + src_cen; + + if (src_loc.x < 0.0f || src_loc.y < 0.0f || + src_loc.x > src_dim.x || src_loc.y > src_dim.y) + write_imagef(dst, dst_loc, 0.5f); + else + write_imagef(dst, dst_loc, read_imagef(src, sampler, src_loc)); +} +@end verbatim + +@item +Blend two inputs together, with the amount of each input used varying +with the index counter. +@verbatim +__kernel void blend_images(__write_only image2d_t dst, + unsigned int index, + __read_only image2d_t src1, + __read_only image2d_t src2) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_FILTER_LINEAR); + + float blend = (cos((float)index / 50.0f) + 1.0f) / 2.0f; + + int2 dst_loc = (int2)(get_global_id(0), get_global_id(1)); + int2 src1_loc = dst_loc * get_image_dim(src1) / get_image_dim(dst); + int2 src2_loc = dst_loc * get_image_dim(src2) / get_image_dim(dst); + + float4 val1 = read_imagef(src1, sampler, src1_loc); + float4 val2 = read_imagef(src2, sampler, src2_loc); + + write_imagef(dst, dst_loc, val1 * blend + val2 * (1.0f - blend)); +} +@end verbatim + +@end itemize + @section pseudocolor Alter frame colors in video with pseudocolors. @@ -12105,7 +12885,7 @@ sequential number of the input frame, starting from 1 Mean Square Error pixel-by-pixel average difference of the compared frames, averaged over all the image components. -@item mse_y, mse_u, mse_v, mse_r, mse_g, mse_g, mse_a +@item mse_y, mse_u, mse_v, mse_r, mse_g, mse_b, mse_a Mean Square Error pixel-by-pixel average difference of the compared frames for the component specified by the suffix. @@ -12564,8 +13344,9 @@ it. Default value is 1. @item fillcolor, c Set the color used to fill the output area not covered by the rotated -image. For the general syntax of this option, check the "Color" section in the -ffmpeg-utils manual. If the special value "none" is selected then no +image. For the general syntax of this option, check the +@ref{color syntax,,"Color" section in the ffmpeg-utils manual,ffmpeg-utils}. +If the special value "none" is selected then no background is printed (useful for example if the background is never shown). Default value is "black". @@ -12847,13 +13628,13 @@ a specific value used for the output and encoder. If not specified, the range depends on the pixel format. Possible values: @table @samp -@item auto +@item auto/unknown Choose automatically. @item jpeg/full/pc Set full range (0-255 in case of 8-bit luma). -@item mpeg/tv +@item mpeg/limited/tv Set "MPEG" range (16-235 in case of 8-bit luma). @end table @@ -13012,6 +13793,19 @@ keeping the same aspect ratio as the input: @example scale=w='min(500\, iw*3/2):h=-1' @end example + +@item +Make pixels square by combining scale and setsar: +@example +scale='trunc(ih*dar):ih',setsar=1/1 +@end example + +@item +Make pixels square by combining scale and setsar, +making sure the resulting resolution is even (required by some codecs): +@example +scale='trunc(ih*dar/2)*2:trunc(ih/2)*2',setsar=1/1 +@end example @end itemize @subsection Commands @@ -14434,8 +15228,17 @@ refer to the pad video filter. @item color Specify the color of the unused area. For the syntax of this option, check the -"Color" section in the ffmpeg-utils manual. The default value of @var{color} -is "black". +@ref{color syntax,,"Color" section in the ffmpeg-utils manual,ffmpeg-utils}. +The default value of @var{color} is "black". + +@item overlap +Set the number of frames to overlap when tiling several successive frames together. +The value must be between @code{0} and @var{nb_frames - 1}. + +@item init_padding +Set the number of frames to initially be empty before displaying first output frame. +This controls how soon will one get first output frame. +The value must be between @code{0} and @var{nb_frames - 1}. @end table @subsection Examples @@ -15013,10 +15816,6 @@ sharpen it, a value of zero will disable the effect. Default value is 0.0. -@item opencl -If set to 1, specify using OpenCL capabilities, only available if -FFmpeg was configured with @code{--enable-opencl}. Default value is 0. - @end table All parameters are optional and default to the equivalent of the @@ -15472,6 +16271,17 @@ For example, to vertically flip a video with @command{ffmpeg}: ffmpeg -i in.avi -vf "vflip" out.avi @end example +@section vfrdet + +Detect variable frame rate video. + +This filter tries to detect if the input is variable or constant frame rate. + +At end it will output number of frames detected as having variable delta pts, +and ones with constant delta pts. +If there was frames with variable delta, than it will also show min and max delta +encountered. + @anchor{vignette} @section vignette @@ -15745,6 +16555,9 @@ Luma and chroma combined together. @item aflat Similar as above, but shows difference between blue and red chroma. +@item xflat +Similar as above, but use different colors. + @item chroma Displays only chroma. @@ -15764,6 +16577,9 @@ Do not display graticule. @item green Display green graticule showing legal broadcast ranges. + +@item orange +Display orange graticule showing legal broadcast ranges. @end table @item opacity, o @@ -16571,8 +17387,8 @@ Set frame rate, expressed as number of frames per second. Default value is "25". @item size, s -Set frame size. For the syntax of this option, check the "Video -size" section in the ffmpeg-utils manual. Default value is "640x480". +Set frame size. For the syntax of this option, check the @ref{video size syntax,,"Video +size" section in the ffmpeg-utils manual,ffmpeg-utils}. Default value is "640x480". @item start_scale Set the initial scale value. Default value is 3.0. @@ -16771,8 +17587,8 @@ used to represent a dead cell. @item mold_color Set mold color, for definitely dead and moldy cells. -For the syntax of these 3 color options, check the "Color" section in the -ffmpeg-utils manual. +For the syntax of these 3 color options, check the @ref{color syntax,,"Color" section in the +ffmpeg-utils manual,ffmpeg-utils}. @end table @subsection Examples @@ -16855,28 +17671,24 @@ The sources accept the following parameters: @table @option -@item alpha -Specify the alpha (opacity) of the background, only available in the -@code{testsrc2} source. The value must be between 0 (fully transparent) and -255 (fully opaque, the default). - -@item color, c -Specify the color of the source, only available in the @code{color} -source. For the syntax of this option, check the "Color" section in the -ffmpeg-utils manual. - @item level Specify the level of the Hald CLUT, only available in the @code{haldclutsrc} source. A level of @code{N} generates a picture of @code{N*N*N} by @code{N*N*N} pixels to be used as identity matrix for 3D lookup tables. Each component is coded on a @code{1/(N*N)} scale. +@item color, c +Specify the color of the source, only available in the @code{color} +source. For the syntax of this option, check the +@ref{color syntax,,"Color" section in the ffmpeg-utils manual,ffmpeg-utils}. + @item size, s Specify the size of the sourced video. For the syntax of this option, check the @ref{video size syntax,,"Video size" section in the ffmpeg-utils manual,ffmpeg-utils}. The default value is @code{320x240}. -This option is not available with the @code{haldclutsrc} filter. +This option is not available with the @code{allrgb}, @code{allyuv}, and +@code{haldclutsrc} filters. @item rate, r Specify the frame rate of the sourced video, as the number of frames @@ -16885,9 +17697,6 @@ generated per second. It has to be a string in the format number or a valid video frame rate abbreviation. The default value is "25". -@item sar -Set the sample aspect ratio of the sourced video. - @item duration, d Set the duration of the sourced video. See @ref{time duration syntax,,the Time duration section in the ffmpeg-utils(1) manual,ffmpeg-utils} @@ -16896,6 +17705,14 @@ for the accepted syntax. If not specified, or the expressed duration is negative, the video is supposed to be generated forever. +@item sar +Set the sample aspect ratio of the sourced video. + +@item alpha +Specify the alpha (opacity) of the background, only available in the +@code{testsrc2} source. The value must be between 0 (fully transparent) and +255 (fully opaque, the default). + @item decimals, n Set the number of decimals to show in the timestamp, only available in the @code{testsrc} source. @@ -16905,27 +17722,32 @@ timestamp value multiplied by the power of 10 of the specified value. Default value is 0. @end table -For example the following: +@subsection Examples + +@itemize +@item +Generate a video with a duration of 5.3 seconds, with size +176x144 and a frame rate of 10 frames per second: @example testsrc=duration=5.3:size=qcif:rate=10 @end example -will generate a video with a duration of 5.3 seconds, with size -176x144 and a frame rate of 10 frames per second. - +@item The following graph description will generate a red source with an opacity of 0.2, with size "qcif" and a frame rate of 10 -frames per second. +frames per second: @example color=c=red@@0.2:s=qcif:r=10 @end example +@item If the input content is to be ignored, @code{nullsrc} can be used. The following command generates noise in the luminance plane by employing the @code{geq} filter: @example nullsrc=s=256x256, geq=random(1)*255:128:128 @end example +@end itemize @subsection Commands @@ -16937,6 +17759,78 @@ Set the color of the created image. Accepts the same syntax of the corresponding @option{color} option. @end table +@section openclsrc + +Generate video using an OpenCL program. + +@table @option + +@item source +OpenCL program source file. + +@item kernel +Kernel name in program. + +@item size, s +Size of frames to generate. This must be set. + +@item format +Pixel format to use for the generated frames. This must be set. + +@item rate, r +Number of frames generated every second. Default value is '25'. + +@end table + +For details of how the program loading works, see the @ref{program_opencl} +filter. + +Example programs: + +@itemize +@item +Generate a colour ramp by setting pixel values from the position of the pixel +in the output image. (Note that this will work with all pixel formats, but +the generated output will not be the same.) +@verbatim +__kernel void ramp(__write_only image2d_t dst, + unsigned int index) +{ + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + + float4 val; + val.xy = val.zw = convert_float2(loc) / convert_float2(get_image_dim(dst)); + + write_imagef(dst, loc, val); +} +@end verbatim + +@item +Generate a Sierpinski carpet pattern, panning by a single pixel each frame. +@verbatim +__kernel void sierpinski_carpet(__write_only image2d_t dst, + unsigned int index) +{ + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + + float4 value = 0.0f; + int x = loc.x + index; + int y = loc.y + index; + while (x > 0 || y > 0) { + if (x % 3 == 1 && y % 3 == 1) { + value = 1.0f; + break; + } + x /= 3; + y /= 3; + } + + write_imagef(dst, loc, value); +} +@end verbatim + +@end itemize + @c man end VIDEO SOURCES @chapter Video Sinks @@ -17197,6 +18091,26 @@ Cubic root. Logarithmic. @end table +@item swap +Swap left channel axis with right channel axis. + +@item mirror +Mirror axis. + +@table @samp +@item none +No mirror. + +@item x +Mirror only x axis. + +@item y +Mirror only y axis. + +@item xy +Mirror both axis. +@end table + @end table @subsection Examples @@ -17324,6 +18238,14 @@ do not have exactly the same duration in the first file. @end itemize +@subsection Commands + +This filter supports the following commands: +@table @option +@item next +Close the current segment and step to the next one +@end table + @section drawgraph, adrawgraph Draw a graph using input video or audio metadata. @@ -17679,7 +18601,7 @@ with AV_LOG_INFO loglevel. @itemize @item -Print all metadata values for frames with key @code{lavfi.singnalstats.YDIF} with values +Print all metadata values for frames with key @code{lavfi.signalstats.YDIF} with values between 0 and 1. @example signalstats,metadata=print:key=lavfi.signalstats.YDIF:value=0:function=expr:expr='between(VALUE1,0,1)' @@ -17807,7 +18729,7 @@ The PTS of the previously filtered video frame. It's NAN if undefined. The PTS of the last previously filtered video frame. It's NAN if undefined. @item prev_selected_t -The PTS of the last previously selected video frame. It's NAN if undefined. +The PTS of the last previously selected video frame, expressed in seconds. It's NAN if undefined. @item start_pts The PTS of the first video frame in the video. It's NAN if undefined. @@ -18232,6 +19154,37 @@ asetpts=N/SR/TB @end itemize +@section setrange + +Force color range for the output video frame. + +The @code{setrange} filter marks the color range property for the +output frames. It does not change the input frame, but only sets the +corresponding property, which affects how the frame is treated by +following filters. + +The filter accepts the following options: + +@table @option + +@item range +Available values are: + +@table @samp +@item auto +Keep the same color range property. + +@item unspecified, unknown +Set the color range as unspecified. + +@item limited, tv, mpeg +Set the color range as limited. + +@item full, pc, jpeg +Set the color range as full. +@end table +@end table + @section settb, asettb Set the timebase to use for the output frames timestamps. @@ -19023,7 +19976,7 @@ Set channel width, allowed range is [80, 8192]. Default is 400. Set channel height, allowed range is [1, 900]. Default is 20. @item f -Set fade, allowed range is [0.001, 1]. Default is 0.95. +Set fade, allowed range is [0, 1]. Default is 0.95. @item c Set volume color expression. @@ -19048,12 +20001,33 @@ If set, displays channel names. Default is enabled. If set, displays volume values. Default is enabled. @item o -Set orientation, can be @code{horizontal} or @code{vertical}, -default is @code{horizontal}. +Set orientation, can be horizontal: @code{h} or vertical: @code{v}, +default is @code{h}. @item s -Set step size, allowed range s [0, 5]. Default is 0, which means +Set step size, allowed range is [0, 5]. Default is 0, which means step is disabled. + +@item p +Set background opacity, allowed range is [0, 1]. Default is 0. + +@item m +Set metering mode, can be peak: @code{p} or rms: @code{r}, +default is @code{p}. + +@item ds +Set display scale, can be linear: @code{lin} or log: @code{log}, +default is @code{lin}. + +@item dm +In second. +If set to > 0., display a line for the max level +in the previous seconds. +default is disabled: @code{0.} + +@item dmc +The color of the max line. Use when @code{dm} option is set to > 0. +default is: @code{orange} @end table @section showwaves @@ -19123,6 +20097,20 @@ Cubic root. @end table Default is linear. + +@item draw +Set the draw mode. This is mostly useful to set for high @var{n}. + +Available values are: +@table @samp +@item scale +Scale pixel values for each drawn sample. + +@item full +Draw every sample directly. +@end table + +Default value is @code{scale}. @end table @subsection Examples @@ -19333,7 +20321,7 @@ filters in the filtergraph. @code{zmq} and @code{azmq} work as a pass-through filters. @code{zmq} must be inserted between two video filters, @code{azmq} between two -audio filters. +audio filters. Both are capable to send messages to any filter type. To enable these filters you need to install the libzmq library and headers and configure FFmpeg with @code{--enable-libzmq}. @@ -19343,7 +20331,10 @@ For more information about libzmq see: The @code{zmq} and @code{azmq} filters work as a libzmq server, which receives messages sent through a network interface defined by the -@option{bind_address} option. +@option{bind_address} (or the abbreviation "@option{b}") option. +Default value of this option is @file{tcp://localhost:5555}. You may +want to alter this value to your needs, but do not forget to escape any +':' signs (see @ref{filtergraph escaping}). The received message must be in the form: @example @@ -19351,7 +20342,10 @@ The received message must be in the form: @end example @var{TARGET} specifies the target of the command, usually the name of -the filter class or a specific filter instance name. +the filter class or a specific filter instance name. The default +filter instance name uses the pattern @samp{Parsed__}, +but you can override this by using the @samp{filter_name@@id} syntax +(see @ref{Filtergraph syntax}). @var{COMMAND} specifies the name of the command for the target filter. @@ -19373,14 +20367,17 @@ will send a reply to the client, adopting the format: Look at @file{tools/zmqsend} for an example of a zmq client which can be used to send commands processed by these filters. -Consider the following filtergraph generated by @command{ffplay} +Consider the following filtergraph generated by @command{ffplay}. +In this example the last overlay filter has an instance name. All other +filters will have default instance names. + @example ffplay -dumpgraph 1 -f lavfi " color=s=100x100:c=red [l]; color=s=100x100:c=blue [r]; nullsrc=s=200x100, zmq [bg]; -[bg][l] overlay [bg+l]; -[bg+l][r] overlay=x=100 " +[bg][l] overlay [bg+l]; +[bg+l][r] overlay@@my=x=100 " @end example To change the color of the left side of the video, the following @@ -19394,6 +20391,12 @@ To change the right side: echo Parsed_color_1 c pink | tools/zmqsend @end example +To change the position of the right side: +@example +echo overlay@@my x 150 | tools/zmqsend +@end example + + @c man end MULTIMEDIA FILTERS @chapter Multimedia Sources @@ -19432,8 +20435,8 @@ postfix. The default value is "0". @item streams, s Specifies the streams to read. Several streams can be specified, separated by "+". The source will then have as many outputs, in the -same order. The syntax is explained in the ``Stream specifiers'' -section in the ffmpeg manual. Two special names, "dv" and "da" specify +same order. The syntax is explained in the @ref{Stream specifiers,,"Stream specifiers" +section in the ffmpeg manual,ffmpeg}. Two special names, "dv" and "da" specify respectively the default (best suited) video and audio stream. Default is "dv", or "da" if the filter is called as "amovie". diff --git a/doc/general.texi b/doc/general.texi index a40400612ea03..2583006b14781 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -17,6 +17,14 @@ for more formats. None of them are used by default, their use has to be explicitly requested by passing the appropriate flags to @command{./configure}. +@section Alliance for Open Media libaom + +FFmpeg can make use of the libaom library for AV1 decoding. + +Go to @url{http://aomedia.org/} and follow the instructions for +installing the library. Then pass @code{--enable-libaom} to configure to +enable it. + @section OpenJPEG FFmpeg can use the OpenJPEG libraries for encoding/decoding J2K videos. Go to @@ -85,6 +93,24 @@ Go to @url{http://www.twolame.org/} and follow the instructions for installing the library. Then pass @code{--enable-libtwolame} to configure to enable it. +@section libcodec2 / codec2 general + +FFmpeg can make use of libcodec2 for codec2 encoding and decoding. +There is currently no native decoder, so libcodec2 must be used for decoding. + +Go to @url{http://freedv.org/}, download "Codec 2 source archive". +Build and install using CMake. Debian users can install the libcodec2-dev package instead. +Once libcodec2 is installed you can pass @code{--enable-libcodec2} to configure to enable it. + +The easiest way to use codec2 is with .c2 files, since they contain the mode information required for decoding. +To encode such a file, use a .c2 file extension and give the libcodec2 encoder the -mode option: +@code{ffmpeg -i input.wav -mode 700C output.c2}. +Playback is as simple as @code{ffplay output.c2}. +For a list of supported modes, run @code{ffmpeg -h encoder=libcodec2}. +Raw codec2 files are also supported. +To make sense of them the mode in use needs to be specified as a format option: +@code{ffmpeg -f codec2raw -mode 1300 -i input.raw output.wav}. + @section libvpx FFmpeg can make use of the libvpx library for VP8/VP9 encoding. @@ -225,6 +251,18 @@ The dispatcher is open source and can be downloaded from with the @code{--enable-libmfx} option and @code{pkg-config} needs to be able to locate the dispatcher's @code{.pc} files. +@section AMD VCE + +FFmpeg can use the AMD Advanced Media Framework library for accelerated H.264 +and HEVC encoding on VCE enabled hardware under Windows. + +To enable support you must obtain the AMF framework header files from +@url{https://github.com/GPUOpen-LibrariesAndSDKs/AMF.git}. + +Create an @code{AMF/} directory in the system include path. +Copy the contents of @code{AMF/amf/public/include/} into that directory. +Then configure FFmpeg with @code{--enable-amf}. + @chapter Supported File Formats, Codecs or Features @@ -290,6 +328,10 @@ library: @item BRSTM @tab @tab X @tab Audio format used on the Nintendo Wii. @item BWF @tab X @tab X +@item codec2 (raw) @tab X @tab X + @tab Must be given -mode format option to decode correctly. +@item codec2 (.c2 files) @tab X @tab X + @tab Contains header with version and mode info, simplifying playback. @item CRI ADX @tab X @tab X @tab Audio-only format used in console video games. @item Discworld II BMV @tab @tab X @@ -365,6 +407,7 @@ library: @item Interplay MVE @tab @tab X @tab Format used in various Interplay computer games. @item Iterated Systems ClearVideo @tab @tab X + @tab I-frames only @item IV8 @tab @tab X @tab A format generated by IndigoVision 8000 video server. @item IVF (On2) @tab X @tab X @@ -424,6 +467,7 @@ library: @item NC camera feed @tab @tab X @tab NC (AVIP NC4600) camera streams @item NIST SPeech HEader REsources @tab @tab X +@item Computerized Speech Lab NSP @tab @tab X @item NTT TwinVQ (VQF) @tab @tab X @tab Nippon Telegraph and Telephone Corporation TwinVQ. @item Nullsoft Streaming Video @tab @tab X @@ -438,6 +482,10 @@ library: @item QCP @tab @tab X @item raw ADTS (AAC) @tab X @tab X @item raw AC-3 @tab X @tab X +@item raw AMR-NB @tab @tab X +@item raw AMR-WB @tab @tab X +@item raw aptX @tab X @tab X +@item raw aptX HD @tab X @tab X @item raw Chinese AVS video @tab X @tab X @item raw CRI ADX @tab X @tab X @item raw Dirac @tab X @tab X @@ -461,6 +509,7 @@ library: @item raw NULL @tab X @tab @item raw video @tab X @tab X @item raw id RoQ @tab X @tab +@item raw SBC @tab X @tab X @item raw Shorten @tab @tab X @item raw TAK @tab @tab X @item raw TrueHD @tab X @tab X @@ -510,7 +559,7 @@ library: @item SAP @tab X @tab X @item SBG @tab @tab X @item SDP @tab @tab X -@item Sega FILM/CPK @tab @tab X +@item Sega FILM/CPK @tab X @tab X @tab Used in many Sega Saturn console games. @item Silicon Graphics Movie @tab @tab X @item Sierra SOL @tab @tab X @@ -678,6 +727,8 @@ following image formats are supported: @item Autodesk Animator Flic video @tab @tab X @item Autodesk RLE @tab @tab X @tab fourcc: AASC +@item AV1 @tab @tab E + @tab Supported through external library libaom @item Avid 1:1 10-bit RGB Packer @tab X @tab X @tab fourcc: AVrp @item AVS (Audio Video Standard) video @tab @tab X @@ -792,7 +843,7 @@ following image formats are supported: @item LucasArts SANM/Smush @tab @tab X @tab Used in LucasArts games / SMUSH animations. @item lossless MJPEG @tab X @tab X -@item MagicYUV Video @tab @tab X +@item MagicYUV Video @tab X @tab X @item Mandsoft Screen Capture Codec @tab @tab X @item Microsoft ATC Screen @tab @tab X @tab Also known as Microsoft Screen 3. @@ -990,6 +1041,10 @@ following image formats are supported: @item Amazing Studio PAF Audio @tab @tab X @item Apple lossless audio @tab X @tab X @tab QuickTime fourcc 'alac' +@item aptX @tab X @tab X + @tab Used in Bluetooth A2DP +@item aptX HD @tab X @tab X + @tab Used in Bluetooth A2DP @item ATRAC1 @tab @tab X @item ATRAC3 @tab @tab X @item ATRAC3+ @tab @tab X @@ -997,6 +1052,8 @@ following image formats are supported: @tab Used in Bink and Smacker files in many games. @item CELT @tab @tab E @tab decoding supported through external library libcelt +@item codec2 @tab E @tab E + @tab en/decoding supported through external library libcodec2 @item Delphine Software International CIN audio @tab @tab X @tab Codec used in Delphine Software International games. @item Digital Speech Standard - Standard Play mode (DSS SP) @tab @tab X @@ -1095,6 +1152,8 @@ following image formats are supported: @tab Real low bitrate AC-3 codec @item RealAudio Lossless @tab @tab X @item RealAudio SIPR / ACELP.NET @tab @tab X +@item SBC (low-complexity subband codec) @tab X @tab X + @tab Used in Bluetooth A2DP @item Shorten @tab @tab X @item Sierra VMD audio @tab @tab X @tab Used in Sierra VMD files. diff --git a/doc/indevs.texi b/doc/indevs.texi index 55a4084bb2240..6951940a93a44 100644 --- a/doc/indevs.texi +++ b/doc/indevs.texi @@ -63,6 +63,46 @@ Set the number of channels. Default is 2. @end table +@section android_camera + +Android camera input device. + +This input devices uses the Android Camera2 NDK API which is +available on devices with API level 24+. The availability of +android_camera is autodetected during configuration. + +This device allows capturing from all cameras on an Android device, +which are integrated into the Camera2 NDK API. + +The available cameras are enumerated internally and can be selected +with the @var{camera_index} parameter. The input file string is +discarded. + +Generally the back facing camera has index 0 while the front facing +camera has index 1. + +@subsection Options + +@table @option + +@item video_size +Set the video size given as a string such as 640x480 or hd720. +Falls back to the first available configuration reported by +Android if requested video size is not available or by default. + +@item framerate +Set the video framerate. +Falls back to the first available configuration reported by +Android if requested framerate is not available or by default (-1). + +@item camera_index +Set the index of the camera to use. Default is 0. + +@item input_queue_size +Set the maximum number of frames to buffer. Default is 5. + +@end table + @section avfoundation AVFoundation input device. @@ -238,6 +278,8 @@ This sets the input video format to the format given by the FourCC. To see the supported values of your device(s) use @option{list_formats}. Note that there is a FourCC @option{'pal '} that can also be used as @option{pal} (3 letters). +Default behavior is autodetection of the input video format, if the hardware +supports it. @item bm_v210 This is a deprecated option, you can use @option{raw_format} instead. @@ -296,11 +338,13 @@ Sets the audio input source. Must be @samp{unset}, @samp{embedded}, @item video_pts Sets the video packet timestamp source. Must be @samp{video}, @samp{audio}, -@samp{reference} or @samp{wallclock}. Defaults to @samp{video}. +@samp{reference}, @samp{wallclock} or @samp{abs_wallclock}. +Defaults to @samp{video}. @item audio_pts Sets the audio packet timestamp source. Must be @samp{video}, @samp{audio}, -@samp{reference} or @samp{wallclock}. Defaults to @samp{audio}. +@samp{reference}, @samp{wallclock} or @samp{abs_wallclock}. +Defaults to @samp{audio}. @item draw_bars If set to @samp{true}, color bars are drawn in the event of a signal loss. @@ -311,6 +355,15 @@ Sets maximum input buffer size in bytes. If the buffering reaches this value, incoming frames will be dropped. Defaults to @samp{1073741824}. +@item audio_depth +Sets the audio sample bit depth. Must be @samp{16} or @samp{32}. +Defaults to @samp{16}. + +@item decklink_copyts +If set to @option{true}, timestamps are forwarded as they are without removing +the initial offset. +Defaults to @option{false}. + @end table @subsection Examples diff --git a/doc/issue_tracker.txt b/doc/issue_tracker.txt index e8e85304b378c..5d9805a4b9708 100644 --- a/doc/issue_tracker.txt +++ b/doc/issue_tracker.txt @@ -193,9 +193,6 @@ ffplay ffprobe issues in or related to ffprobe.c -ffserver - issues in or related to ffserver.c - postproc issues in libpostproc/* diff --git a/doc/libav-merge.txt b/doc/libav-merge.txt index 4a46bfcf464a8..4ba08fc588f9e 100644 --- a/doc/libav-merge.txt +++ b/doc/libav-merge.txt @@ -94,13 +94,13 @@ Stuff that didn't reach the codebase: - a853388d2 hevc: change the stride of the MC buffer to be in bytes instead of elements - 0cef06df0 checkasm: add HEVC MC tests - e7078e842 hevcdsp: add x86 SIMD for MC -- VAAPI VP8 decode hwaccel (currently under review: http://ffmpeg.org/pipermail/ffmpeg-devel/2017-February/thread.html#207348) -- Removal of the custom atomic API (5cc0057f49, see http://ffmpeg.org/pipermail/ffmpeg-devel/2017-March/209003.html) + - 7993ec19a hevc: Add hevc_get_pixel_4/8/12/16/24/32/48/64 - new bitstream reader (see http://ffmpeg.org/pipermail/ffmpeg-devel/2017-April/209609.html) -- use of the bsf instead of our parser for vp9 superframes (see fa1749dd34) - use av_cpu_max_align() instead of hardcoding alignment requirements (see https://ffmpeg.org/pipermail/ffmpeg-devel/2017-September/215834.html) - f44ec22e0 lavc: use av_cpu_max_align() instead of hardcoding alignment requirements - 4de220d2e frame: allow align=0 (meaning automatic) for av_frame_get_buffer() +- Support recovery from an already present HLS playlist (see 16cb06bb30) +- Remove all output devices (see 8e7e042d41, 8d3db95f20, 6ce13070bd, d46cd24986 and https://ffmpeg.org/pipermail/ffmpeg-devel/2017-September/216904.html) Collateral damage that needs work locally: ------------------------------------------ diff --git a/doc/libavcodec.texi b/doc/libavcodec.texi index 87b90db48c479..b22c47ae87c77 100644 --- a/doc/libavcodec.texi +++ b/doc/libavcodec.texi @@ -26,13 +26,13 @@ implementing robust and fast codecs as well as for experimentation. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffmpeg-codecs.html,ffmpeg-codecs}, @url{ffmpeg-bitstream-filters.html,bitstream-filters}, @url{libavutil.html,libavutil} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), +ffmpeg(1), ffplay(1), ffprobe(1), ffmpeg-codecs(1), ffmpeg-bitstream-filters(1), libavutil(3) @end ifnothtml diff --git a/doc/libavdevice.texi b/doc/libavdevice.texi index 9b10282cde8be..0abdaaff06f0d 100644 --- a/doc/libavdevice.texi +++ b/doc/libavdevice.texi @@ -23,13 +23,13 @@ VfW, DShow, and ALSA. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffmpeg-devices.html,ffmpeg-devices}, @url{libavutil.html,libavutil}, @url{libavcodec.html,libavcodec}, @url{libavformat.html,libavformat} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), +ffmpeg(1), ffplay(1), ffprobe(1), ffmpeg-devices(1), libavutil(3), libavcodec(3), libavformat(3) @end ifnothtml diff --git a/doc/libavfilter.texi b/doc/libavfilter.texi index 52e075369cf49..d9472eb0ad3b8 100644 --- a/doc/libavfilter.texi +++ b/doc/libavfilter.texi @@ -21,14 +21,14 @@ framework containing several filters, sources and sinks. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffmpeg-filters.html,ffmpeg-filters}, @url{libavutil.html,libavutil}, @url{libswscale.html,libswscale}, @url{libswresample.html,libswresample}, @url{libavcodec.html,libavcodec}, @url{libavformat.html,libavformat}, @url{libavdevice.html,libavdevice} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), +ffmpeg(1), ffplay(1), ffprobe(1), ffmpeg-filters(1), libavutil(3), libswscale(3), libswresample(3), libavcodec(3), libavformat(3), libavdevice(3) @end ifnothtml diff --git a/doc/libavformat.texi b/doc/libavformat.texi index d505d644f698f..7cf41fdfd4552 100644 --- a/doc/libavformat.texi +++ b/doc/libavformat.texi @@ -26,13 +26,13 @@ resource. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffmpeg-formats.html,ffmpeg-formats}, @url{ffmpeg-protocols.html,ffmpeg-protocols}, @url{libavutil.html,libavutil}, @url{libavcodec.html,libavcodec} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), +ffmpeg(1), ffplay(1), ffprobe(1), ffmpeg-formats(1), ffmpeg-protocols(1), libavutil(3), libavcodec(3) @end ifnothtml diff --git a/doc/libavutil.texi b/doc/libavutil.texi index 7a1c332b81743..ee50362f69487 100644 --- a/doc/libavutil.texi +++ b/doc/libavutil.texi @@ -42,12 +42,12 @@ It should avoid useless features that almost no one needs. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffmpeg-utils.html,ffmpeg-utils} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), +ffmpeg(1), ffplay(1), ffprobe(1), ffmpeg-utils(1) @end ifnothtml diff --git a/doc/libswresample.texi b/doc/libswresample.texi index bb57278314b22..3108cb1ba490a 100644 --- a/doc/libswresample.texi +++ b/doc/libswresample.texi @@ -48,13 +48,13 @@ enabled through dedicated options. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffmpeg-resampler.html,ffmpeg-resampler}, @url{libavutil.html,libavutil} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), +ffmpeg(1), ffplay(1), ffprobe(1), ffmpeg-resampler(1), libavutil(3) @end ifnothtml diff --git a/doc/libswscale.texi b/doc/libswscale.texi index 757fd24139677..e137c24a499ab 100644 --- a/doc/libswscale.texi +++ b/doc/libswscale.texi @@ -41,13 +41,13 @@ colorspaces differ. @chapter See Also @ifhtml -@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffserver.html,ffserver}, +@url{ffmpeg.html,ffmpeg}, @url{ffplay.html,ffplay}, @url{ffprobe.html,ffprobe}, @url{ffmpeg-scaler.html,ffmpeg-scaler}, @url{libavutil.html,libavutil} @end ifhtml @ifnothtml -ffmpeg(1), ffplay(1), ffprobe(1), ffserver(1), +ffmpeg(1), ffplay(1), ffprobe(1), ffmpeg-scaler(1), libavutil(3) @end ifnothtml diff --git a/doc/mailing-list-faq.texi b/doc/mailing-list-faq.texi index fe2171e42e875..9af89815d5254 100644 --- a/doc/mailing-list-faq.texi +++ b/doc/mailing-list-faq.texi @@ -27,8 +27,7 @@ for examples. @item @url{https://lists.ffmpeg.org/mailman/listinfo/ffmpeg-user/, ffmpeg-user}: For questions involving unscripted usage or compilation of the FFmpeg -command-line tools (@command{ffmpeg}, @command{ffprobe}, @command{ffplay}, -@command{ffserver}). +command-line tools (@command{ffmpeg}, @command{ffprobe}, @command{ffplay}). @item @url{https://lists.ffmpeg.org/mailman/listinfo/libav-user/, libav-user}: diff --git a/doc/muxers.texi b/doc/muxers.texi index 91bbe673c53f7..f288764a23e75 100644 --- a/doc/muxers.texi +++ b/doc/muxers.texi @@ -247,6 +247,16 @@ DASH-templated name to used for the initialization segment. Default is "init-str DASH-templated name to used for the media segments. Default is "chunk-stream$RepresentationID$-$Number%05d$.m4s" @item -utc_timing_url @var{utc_url} URL of the page that will return the UTC timestamp in ISO format. Example: "https://time.akamai.com/?iso" +@item -http_user_agent @var{user_agent} +Override User-Agent field in HTTP header. Applicable only for HTTP output. +@item -http_persistent @var{http_persistent} +Use persistent HTTP connections. Applicable only for HTTP output. +@item -hls_playlist @var{hls_playlist} +Generate HLS playlist files as well. The master playlist is generated with the filename master.m3u8. +One media playlist file is generated for each stream with filenames media_0.m3u8, media_1.m3u8, etc. +@item -streaming @var{streaming} +Enable (1) or disable (0) chunk streaming mode of output. In chunk streaming +mode, each frame will be a moof fragment which forms a chunk. @item -adaptation_sets @var{adaptation_sets} Assign streams to AdaptationSets. Syntax is "id=x,streams=a,b,c id=y,streams=d,e" with x and y being the IDs of the adaptation sets and a,b,c,d and e are the indices of the mapped streams. @@ -254,6 +264,8 @@ of the adaptation sets and a,b,c,d and e are the indices of the mapped streams. To map all video (or audio) streams to an AdaptationSet, "v" (or "a") can be used as stream identifier instead of IDs. When no assignment is defined, this defaults to an AdaptationSet for each stream. +@item -timeout @var{timeout} +Set timeout for socket I/O operations. Applicable only for HTTP output. @end table @anchor{framecrc} @@ -468,9 +480,12 @@ By default, the muxer creates a file for each segment produced. These files have the same name as the playlist, followed by a sequential number and a .ts extension. +Make sure to require a closed GOP when encoding and to set the GOP +size to fit your segment time constraint. + For example, to convert an input file with @command{ffmpeg}: @example -ffmpeg -i in.nut out.m3u8 +ffmpeg -i in.mkv -c:v h264 -flags +cgop -g 30 -hls_time 1 out.m3u8 @end example This example will produce the playlist, @file{out.m3u8}, and segment files: @file{out0.ts}, @file{out1.ts}, @file{out2.ts}, etc. @@ -498,6 +513,12 @@ Segment will be cut on the next key frame after this time has passed. Set the maximum number of playlist entries. If set to 0 the list file will contain all the segments. Default value is 5. +@item hls_delete_threshold @var{size} +Set the number of unreferenced segments to keep on disk before @code{hls_flags delete_segments} +deletes them. Increase this to allow continue clients to download segments which +were recently referenced in the playlist. Default value is 1, meaning segments older than +@code{hls_list_size+1} will be deleted. + @item hls_ts_options @var{options_list} Set output format options using a :-separated list of key=value parameters. Values containing @code{:} special characters must be @@ -567,6 +588,31 @@ Should a relative path be specified, the path of the created segment files will be relative to the current working directory. When use_localtime_mkdir is set, the whole expanded value of @var{filename} will be written into the m3u8 segment list. +When @code{var_stream_map} is set with two or more variant streams, the +@var{filename} pattern must contain the string "%v", this string specifies +the position of variant stream index in the generated segment file names. +@example +ffmpeg -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \ + -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" \ + -hls_segment_filename 'file_%v_%03d.ts' out_%v.m3u8 +@end example +This example will produce the playlists segment file sets: +@file{file_0_000.ts}, @file{file_0_001.ts}, @file{file_0_002.ts}, etc. and +@file{file_1_000.ts}, @file{file_1_001.ts}, @file{file_1_002.ts}, etc. + +The string "%v" may be present in the filename or in the last directory name +containing the file. If the string is present in the directory name, then +sub-directories are created after expanding the directory name pattern. This +enables creation of segments corresponding to different variant streams in +subdirectories. +@example +ffmpeg -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \ + -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" \ + -hls_segment_filename 'vs%v/file_%03d.ts' vs%v/out.m3u8 +@end example +This example will produce the playlists segment file sets: +@file{vs0/file_000.ts}, @file{vs0/file_001.ts}, @file{vs0/file_002.ts}, etc. and +@file{vs1/file_000.ts}, @file{vs1/file_001.ts}, @file{vs1/file_002.ts}, etc. @item use_localtime Use strftime() on @var{filename} to expand the segment filename with localtime. @@ -693,6 +739,15 @@ the fmp4 files is used in hls after version 7. @item hls_fmp4_init_filename @var{filename} set filename to the fragment files header file, default filename is @file{init.mp4}. +When @code{var_stream_map} is set with two or more variant streams, the +@var{filename} pattern must contain the string "%v", this string specifies +the position of variant stream index in the generated init file names. +The string "%v" may be present in the filename or in the last directory name +containing the file. If the string is present in the directory name, then +sub-directories are created after expanding the directory name pattern. This +enables creation of init files corresponding to different variant streams in +subdirectories. + @item hls_flags @var{flags} Possible values: @@ -732,6 +787,10 @@ The file specified by @code{hls_key_info_file} will be checked periodically and detect updates to the encryption info. Be sure to replace this file atomically, including the file containing the AES encryption key. +@item independent_segments +Add the @code{#EXT-X-INDEPENDENT-SEGMENTS} to playlists that has video segments +and when all the segments of that playlist are guaranteed to start with a Key frame. + @item split_by_time Allow segments to start on frames other than keyframes. This improves behavior on some players when the time between keyframes is inconsistent, @@ -794,6 +853,128 @@ files. @item http_user_agent Override User-Agent field in HTTP header. Applicable only for HTTP output. +@item var_stream_map +Map string which specifies how to group the audio, video and subtitle streams +into different variant streams. The variant stream groups are separated +by space. +Expected string format is like this "a:0,v:0 a:1,v:1 ....". Here a:, v:, s: are +the keys to specify audio, video and subtitle streams respectively. +Allowed values are 0 to 9 (limited just based on practical usage). + +When there are two or more variant streams, the output filename pattern must +contain the string "%v", this string specifies the position of variant stream +index in the output media playlist filenames. The string "%v" may be present in +the filename or in the last directory name containing the file. If the string is +present in the directory name, then sub-directories are created after expanding +the directory name pattern. This enables creation of variant streams in +subdirectories. + +@example +ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \ + -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" \ + http://example.com/live/out_%v.m3u8 +@end example +This example creates two hls variant streams. The first variant stream will +contain video stream of bitrate 1000k and audio stream of bitrate 64k and the +second variant stream will contain video stream of bitrate 256k and audio +stream of bitrate 32k. Here, two media playlist with file names out_0.m3u8 and +out_1.m3u8 will be created. +@example +ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k \ + -map 0:v -map 0:a -map 0:v -f hls -var_stream_map "v:0 a:0 v:1" \ + http://example.com/live/out_%v.m3u8 +@end example +This example creates three hls variant streams. The first variant stream will +be a video only stream with video bitrate 1000k, the second variant stream will +be an audio only stream with bitrate 64k and the third variant stream will be a +video only stream with bitrate 256k. Here, three media playlist with file names +out_0.m3u8, out_1.m3u8 and out_2.m3u8 will be created. +@example +ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \ + -map 0:v -map 0:a -map 0:v -map 0:a -f hls -var_stream_map "v:0,a:0 v:1,a:1" \ + http://example.com/live/vs_%v/out.m3u8 +@end example +This example creates the variant streams in subdirectories. Here, the first +media playlist is created at @file{http://example.com/live/vs_0/out.m3u8} and +the second one at @file{http://example.com/live/vs_1/out.m3u8}. +@example +ffmpeg -re -i in.ts -b:a:0 32k -b:a:1 64k -b:v:0 1000k -b:v:1 3000k \ + -map 0:a -map 0:a -map 0:v -map 0:v -f hls \ + -var_stream_map "a:0,agroup:aud_low a:1,agroup:aud_high v:0,agroup:aud_low v:1,agroup:aud_high" \ + -master_pl_name master.m3u8 \ + http://example.com/live/out_%v.m3u8 +@end example +This example creates two audio only and two video only variant streams. In +addition to the #EXT-X-STREAM-INF tag for each variant stream in the master +playlist, #EXT-X-MEDIA tag is also added for the two audio only variant streams +and they are mapped to the two video only variant streams with audio group names +'aud_low' and 'aud_high'. + +By default, a single hls variant containing all the encoded streams is created. + +@item cc_stream_map +Map string which specifies different closed captions groups and their +attributes. The closed captions stream groups are separated by space. +Expected string format is like this +"ccgroup:,instreamid:,language: ....". +'ccgroup' and 'instreamid' are mandatory attributes. 'language' is an optional +attribute. +The closed captions groups configured using this option are mapped to different +variant streams by providing the same 'ccgroup' name in the +@code{var_stream_map} string. If @code{var_stream_map} is not set, then the +first available ccgroup in @code{cc_stream_map} is mapped to the output variant +stream. The examples for these two use cases are given below. + +@example +ffmpeg -re -i in.ts -b:v 1000k -b:a 64k -a53cc 1 -f hls \ + -cc_stream_map "ccgroup:cc,instreamid:CC1,language:en" \ + -master_pl_name master.m3u8 \ + http://example.com/live/out.m3u8 +@end example +This example adds @code{#EXT-X-MEDIA} tag with @code{TYPE=CLOSED-CAPTIONS} in +the master playlist with group name 'cc', langauge 'en' (english) and +INSTREAM-ID 'CC1'. Also, it adds @code{CLOSED-CAPTIONS} attribute with group +name 'cc' for the output variant stream. +@example +ffmpeg -re -i in.ts -b:v:0 1000k -b:v:1 256k -b:a:0 64k -b:a:1 32k \ + -a53cc:0 1 -a53cc:1 1\ + -map 0:v -map 0:a -map 0:v -map 0:a -f hls \ + -cc_stream_map "ccgroup:cc,instreamid:CC1,language:en ccgroup:cc,instreamid:CC2,language:sp" \ + -var_stream_map "v:0,a:0,ccgroup:cc v:1,a:1,ccgroup:cc" \ + -master_pl_name master.m3u8 \ + http://example.com/live/out_%v.m3u8 +@end example +This example adds two @code{#EXT-X-MEDIA} tags with @code{TYPE=CLOSED-CAPTIONS} in +the master playlist for the INSTREAM-IDs 'CC1' and 'CC2'. Also, it adds +@code{CLOSED-CAPTIONS} attribute with group name 'cc' for the two output variant +streams. + +@item master_pl_name +Create HLS master playlist with the given name. + +@example +ffmpeg -re -i in.ts -f hls -master_pl_name master.m3u8 http://example.com/live/out.m3u8 +@end example +This example creates HLS master playlist with name master.m3u8 and it is +published at http://example.com/live/ + +@item master_pl_publish_rate +Publish master play list repeatedly every after specified number of segment intervals. + +@example +ffmpeg -re -i in.ts -f hls -master_pl_name master.m3u8 \ +-hls_time 2 -master_pl_publish_rate 30 http://example.com/live/out.m3u8 +@end example + +This example creates HLS master playlist with name master.m3u8 and keep +publishing it repeatedly every after 30 segments i.e. every after 60s. + +@item http_persistent +Use persistent HTTP connections. Applicable only for HTTP output. + +@item timeout +Set timeout for socket I/O operations. Applicable only for HTTP output. + @end table @anchor{ico} @@ -894,9 +1075,18 @@ can be used: ffmpeg -f v4l2 -r 1 -i /dev/video0 -f image2 -strftime 1 "%Y-%m-%d_%H-%M-%S.jpg" @end example +You can set the file name with current frame's PTS: +@example +ffmpeg -f v4l2 -r 1 -i /dev/video0 -copyts -f image2 -frame_pts true %d.jpg" +@end example + @subsection Options @table @option +@item frame_pts +If set to 1, expand the filename with pts from pkt->pts. +Default value is 0. + @item start_number Start the sequence from the specified number. Default value is 1. @@ -1649,6 +1839,9 @@ segment would usually span. Otherwise, the segment will be filled with the next packet written. Defaults to @code{0}. @end table +Make sure to require a closed GOP when encoding and to set the GOP +size to fit your segment time constraint. + @subsection Examples @itemize @@ -1657,7 +1850,7 @@ Remux the content of file @file{in.mkv} to a list of segments @file{out-000.nut}, @file{out-001.nut}, etc., and write the list of generated segments to @file{out.list}: @example -ffmpeg -i in.mkv -codec copy -map 0 -f segment -segment_list out.list out%03d.nut +ffmpeg -i in.mkv -codec hevc -flags +cgop -g 60 -map 0 -f segment -segment_list out.list out%03d.nut @end example @item diff --git a/doc/protocols.texi b/doc/protocols.texi index a7968ff56e3e1..e19504d0730ba 100644 --- a/doc/protocols.texi +++ b/doc/protocols.texi @@ -296,6 +296,9 @@ Use persistent connections if set to 1, default is 0. @item post_data Set custom HTTP post data. +@item referer +Set the Referer header. Include 'Referer: URL' header in HTTP request. + @item user_agent Override the User-Agent header. If not specified the protocol will use a string describing the libavformat build. ("Lavf/") @@ -321,6 +324,9 @@ Sets the maximum delay in seconds after which to give up reconnecting @item mime_type Export the MIME type. +@item http_version +Exports the HTTP response version number. Usually "1.0" or "1.1". + @item icy If set to 1 request ICY (SHOUTcast) metadata from the server. If the server supports this, the metadata has to be retrieved by the application by reading @@ -363,7 +369,7 @@ If set to 1 enables experimental HTTP server. This can be used to send data when used as an output option, or read data from a client with HTTP POST when used as an input option. If set to 2 enables experimental multi-client HTTP server. This is not yet implemented -in ffmpeg.c or ffserver.c and thus must not be used as a command line option. +in ffmpeg.c and thus must not be used as a command line option. @example # Server side (sending): ffmpeg -i somefile.ogg -c copy -listen 1 -f ogg http://@var{server}:@var{port} @@ -1149,6 +1155,146 @@ If set to any value, listen for an incoming connection. Outgoing connection is d Set the maximum number of streams. By default no limit is set. @end table +@section srt + +Haivision Secure Reliable Transport Protocol via libsrt. + +The supported syntax for a SRT URL is: +@example +srt://@var{hostname}:@var{port}[?@var{options}] +@end example + +@var{options} contains a list of &-separated options of the form +@var{key}=@var{val}. + +or + +@example +@var{options} srt://@var{hostname}:@var{port} +@end example + +@var{options} contains a list of '-@var{key} @var{val}' +options. + +This protocol accepts the following options. + +@table @option +@item connect_timeout +Connection timeout; SRT cannot connect for RTT > 1500 msec +(2 handshake exchanges) with the default connect timeout of +3 seconds. This option applies to the caller and rendezvous +connection modes. The connect timeout is 10 times the value +set for the rendezvous mode (which can be used as a +workaround for this connection problem with earlier versions). + +@item ffs=@var{bytes} +Flight Flag Size (Window Size), in bytes. FFS is actually an +internal parameter and you should set it to not less than +@option{recv_buffer_size} and @option{mss}. The default value +is relatively large, therefore unless you set a very large receiver buffer, +you do not need to change this option. Default value is 25600. + +@item inputbw=@var{bytes/seconds} +Sender nominal input rate, in bytes per seconds. Used along with +@option{oheadbw}, when @option{maxbw} is set to relative (0), to +calculate maximum sending rate when recovery packets are sent +along with the main media stream: +@option{inputbw} * (100 + @option{oheadbw}) / 100 +if @option{inputbw} is not set while @option{maxbw} is set to +relative (0), the actual input rate is evaluated inside +the library. Default value is 0. + +@item iptos=@var{tos} +IP Type of Service. Applies to sender only. Default value is 0xB8. + +@item ipttl=@var{ttl} +IP Time To Live. Applies to sender only. Default value is 64. + +@item listen_timeout +Set socket listen timeout. + +@item maxbw=@var{bytes/seconds} +Maximum sending bandwidth, in bytes per seconds. +-1 infinite (CSRTCC limit is 30mbps) +0 relative to input rate (see @option{inputbw}) +>0 absolute limit value +Default value is 0 (relative) + +@item mode=@var{caller|listener|rendezvous} +Connection mode. +@option{caller} opens client connection. +@option{listener} starts server to listen for incoming connections. +@option{rendezvous} use Rendez-Vous connection mode. +Default value is caller. + +@item mss=@var{bytes} +Maximum Segment Size, in bytes. Used for buffer allocation +and rate calculation using a packet counter assuming fully +filled packets. The smallest MSS between the peers is +used. This is 1500 by default in the overall internet. +This is the maximum size of the UDP packet and can be +only decreased, unless you have some unusual dedicated +network settings. Default value is 1500. + +@item nakreport=@var{1|0} +If set to 1, Receiver will send `UMSG_LOSSREPORT` messages +periodically until a lost packet is retransmitted or +intentionally dropped. Default value is 1. + +@item oheadbw=@var{percents} +Recovery bandwidth overhead above input rate, in percents. +See @option{inputbw}. Default value is 25%. + +@item passphrase=@var{string} +HaiCrypt Encryption/Decryption Passphrase string, length +from 10 to 79 characters. The passphrase is the shared +secret between the sender and the receiver. It is used +to generate the Key Encrypting Key using PBKDF2 +(Password-Based Key Derivation Function). It is used +only if @option{pbkeylen} is non-zero. It is used on +the receiver only if the received data is encrypted. +The configured passphrase cannot be recovered (write-only). + +@item pbkeylen=@var{bytes} +Sender encryption key length, in bytes. +Only can be set to 0, 16, 24 and 32. +Enable sender encryption if not 0. +Not required on receiver (set to 0), +key size obtained from sender in HaiCrypt handshake. +Default value is 0. + +@item recv_buffer_size=@var{bytes} +Set receive buffer size, expressed in bytes. + +@item send_buffer_size=@var{bytes} +Set send buffer size, expressed in bytes. + +@item rw_timeout +Set raise error timeout for read/write optations. + +This option is only relevant in read mode: +if no data arrived in more than this time +interval, raise error. + +@item tlpktdrop=@var{1|0} +Too-late Packet Drop. When enabled on receiver, it skips +missing packets that have not been delivered in time and +delivers the following packets to the application when +their time-to-play has come. It also sends a fake ACK to +the sender. When enabled on sender and enabled on the +receiving peer, the sender drops the older packets that +have no chance of being delivered in time. It was +automatically enabled in the sender if the receiver +supports it. + +@item tsbpddelay +Timestamp-based Packet Delivery Delay. +Used to absorb burst of missed packet retransmission. + +@end table + +For more information see: @url{https://github.com/Haivision/srt}. + @section srtp Secure Real-time Transport Protocol. @@ -1186,6 +1332,7 @@ Accepted options: Start offset of the extracted segment, in bytes. @item end End offset of the extracted segment, in bytes. +If set to 0, extract till end of file. @end table Examples: @@ -1201,6 +1348,11 @@ Play an AVI file directly from a TAR archive: subfile,,start,183241728,end,366490624,,:archive.tar @end example +Play a MPEG-TS file from start offset till end: +@example +subfile,,start,32815239,end,0,,:video.ts +@end example + @section tee Writes the output to multiple protocols. The individual outputs are separated @@ -1242,6 +1394,9 @@ Set receive buffer size, expressed bytes. @item send_buffer_size=@var{bytes} Set send buffer size, expressed bytes. + +@item tcp_nodelay=@var{1|0} +Set TCP_NODELAY to disable Nagle's algorithm. Default value is 0. @end table The following example shows how to setup a listening TCP connection @@ -1277,7 +1432,7 @@ If enabled, try to verify the peer that we are communicating with. Note, if using OpenSSL, this currently only makes sure that the peer certificate is signed by one of the root certificates in the CA database, but it does not validate that the certificate actually -matches the host name we are trying to connect to. (With GnuTLS, +matches the host name we are trying to connect to. (With other backends, the host name is validated as well.) This is disabled by default since it requires a CA database to be diff --git a/doc/utils.texi b/doc/utils.texi index e635118565fdc..d55dd315c34fb 100644 --- a/doc/utils.texi +++ b/doc/utils.texi @@ -1057,33 +1057,3 @@ indication of the corresponding powers of 10 and of 2. @end table @c man end EXPRESSION EVALUATION - -@chapter OpenCL Options -@c man begin OPENCL OPTIONS - -When FFmpeg is configured with @code{--enable-opencl}, it is possible -to set the options for the global OpenCL context. - -The list of supported options follows: - -@table @option -@item build_options -Set build options used to compile the registered kernels. - -See reference "OpenCL Specification Version: 1.2 chapter 5.6.4". - -@item platform_idx -Select the index of the platform to run OpenCL code. - -The specified index must be one of the indexes in the device list -which can be obtained with @code{ffmpeg -opencl_bench} or @code{av_opencl_get_device_list()}. - -@item device_idx -Select the index of the device used to run OpenCL code. - -The specified index must be one of the indexes in the device list which -can be obtained with @code{ffmpeg -opencl_bench} or @code{av_opencl_get_device_list()}. - -@end table - -@c man end OPENCL OPTIONS diff --git a/doc/writing_filters.txt b/doc/writing_filters.txt index 5cd4ecd6a4b01..98b9c6f3d29f1 100644 --- a/doc/writing_filters.txt +++ b/doc/writing_filters.txt @@ -31,10 +31,8 @@ If everything went right, you should get a foobar.png with Lena edge-detected. That's it, your new playground is ready. Some little details about what's going on: -libavfilter/allfilters.c:avfilter_register_all() is called at runtime to create -a list of the available filters, but it's important to know that this file is -also parsed by the configure script, which in turn will define variables for -the build system and the C: +libavfilter/allfilters.c:this file is parsed by the configure script, which in turn +will define variables for the build system and the C: --- after running configure --- diff --git a/ffbuild/common.mak b/ffbuild/common.mak index e168fb2cfdde5..eb41b05ee661b 100644 --- a/ffbuild/common.mak +++ b/ffbuild/common.mak @@ -119,7 +119,7 @@ FFLIBS := $($(NAME)_FFLIBS) $(FFLIBS-yes) $(FFLIBS) TESTPROGS += $(TESTPROGS-yes) LDLIBS = $(FFLIBS:%=%$(BUILDSUF)) -FFEXTRALIBS := $(LDLIBS:%=$(LD_LIB)) $(EXTRALIBS) +FFEXTRALIBS := $(LDLIBS:%=$(LD_LIB)) $(foreach lib,EXTRALIBS-$(NAME) $(FFLIBS:%=EXTRALIBS-%),$($(lib))) $(EXTRALIBS) OBJS := $(sort $(OBJS:%=$(SUBDIR)%)) SLIBOBJS := $(sort $(SLIBOBJS:%=$(SUBDIR)%)) @@ -163,8 +163,7 @@ $(TOOLOBJS): | tools OBJDIRS := $(OBJDIRS) $(dir $(OBJS) $(HOBJS) $(HOSTOBJS) $(SLIBOBJS) $(TESTOBJS)) -CLEANSUFFIXES = *.d *.o *~ *.h.c *.gcda *.gcno *.map *.ver *.version *.ho *$(DEFAULT_X86ASMD).asm *.ptx *.ptx.c -DISTCLEANSUFFIXES = *.pc +CLEANSUFFIXES = *.d *.gcda *.gcno *.h.c *.ho *.map *.o *.pc *.ptx *.ptx.c *.ver *.version *$(DEFAULT_X86ASMD).asm *~ LIBSUFFIXES = *.a *.lib *.so *.so.* *.dylib *.dll *.def *.dll.a define RULES diff --git a/ffbuild/library.mak b/ffbuild/library.mak index 4191edcf9ca9b..612bacb980060 100644 --- a/ffbuild/library.mak +++ b/ffbuild/library.mak @@ -1,6 +1,6 @@ include $(SRC_PATH)/ffbuild/common.mak -ifeq (,$(filter %clean,$(MAKECMDGOALS))) +ifeq (,$(filter %clean config,$(MAKECMDGOALS))) -include $(SUBDIR)lib$(NAME).version endif @@ -31,13 +31,15 @@ define RULES $(TOOLS): THISLIB = $(FULLNAME:%=$(LD_LIB)) $(TESTPROGS): THISLIB = $(SUBDIR)$(LIBNAME) +$(LIBOBJS): CPPFLAGS += -DBUILDING_$(NAME) + $(TESTPROGS) $(TOOLS): %$(EXESUF): %.o - $$(LD) $(LDFLAGS) $(LDEXEFLAGS) $$(LD_O) $$(filter %.o,$$^) $$(THISLIB) $(FFEXTRALIBS) $$(ELIBS) + $$(LD) $(LDFLAGS) $(LDEXEFLAGS) $$(LD_O) $$(filter %.o,$$^) $$(THISLIB) $(FFEXTRALIBS) $$(EXTRALIBS-$$(*F)) $$(ELIBS) $(SUBDIR)lib$(NAME).version: $(SUBDIR)version.h | $(SUBDIR) $$(M) $$(SRC_PATH)/ffbuild/libversion.sh $(NAME) $$< > $$@ -$(SUBDIR)lib$(FULLNAME).pc: $(SUBDIR)version.h | $(SUBDIR) +$(SUBDIR)lib$(FULLNAME).pc: $(SUBDIR)version.h ffbuild/config.sh | $(SUBDIR) $$(M) $$(SRC_PATH)/ffbuild/pkgconfig_generate.sh $(NAME) "$(DESC)" $(SUBDIR)lib$(NAME).ver: $(SUBDIR)lib$(NAME).v $(OBJS) @@ -48,7 +50,7 @@ $(SUBDIR)$(SLIBNAME): $(SUBDIR)$(SLIBNAME_WITH_MAJOR) $(SUBDIR)$(SLIBNAME_WITH_MAJOR): $(OBJS) $(SLIBOBJS) $(SUBDIR)lib$(NAME).ver $(SLIB_CREATE_DEF_CMD) - $$(LD) $(SHFLAGS) $(LDFLAGS) $(LDLIBFLAGS) $$(LD_O) $$(filter %.o,$$^) $(FFEXTRALIBS) + $$(LD) $(SHFLAGS) $(LDFLAGS) $(LDSOFLAGS) $$(LD_O) $$(filter %.o,$$^) $(FFEXTRALIBS) $(SLIB_EXTRA_CMD) ifdef SUBDIR @@ -59,10 +61,6 @@ clean:: $(RM) $(addprefix $(SUBDIR),$(CLEANFILES) $(CLEANSUFFIXES) $(LIBSUFFIXES)) \ $(CLEANSUFFIXES:%=$(SUBDIR)$(ARCH)/%) $(CLEANSUFFIXES:%=$(SUBDIR)tests/%) -distclean:: clean - $(RM) $(DISTCLEANSUFFIXES:%=$(SUBDIR)%) $(DISTCLEANSUFFIXES:%=$(SUBDIR)$(ARCH)/%) \ - $(DISTCLEANSUFFIXES:%=$(SUBDIR)tests/%) - install-lib$(NAME)-shared: $(SUBDIR)$(SLIBNAME) $(Q)mkdir -p "$(SHLIBDIR)" $$(INSTALL) -m 755 $$< "$(SHLIBDIR)/$(SLIB_INSTALL_NAME)" @@ -95,8 +93,10 @@ uninstall-libs:: uninstall-headers:: $(RM) $(addprefix "$(INCINSTDIR)/",$(HEADERS) $(BUILT_HEADERS)) - $(RM) "$(PKGCONFIGDIR)/lib$(FULLNAME).pc" -rmdir "$(INCINSTDIR)" + +uninstall-pkgconfig:: + $(RM) "$(PKGCONFIGDIR)/lib$(FULLNAME).pc" endef $(eval $(RULES)) diff --git a/fftools/Makefile b/fftools/Makefile index c867814a71cb7..c3a0ff340b0d4 100644 --- a/fftools/Makefile +++ b/fftools/Makefile @@ -1,12 +1,11 @@ AVPROGS-$(CONFIG_FFMPEG) += ffmpeg AVPROGS-$(CONFIG_FFPLAY) += ffplay AVPROGS-$(CONFIG_FFPROBE) += ffprobe -AVPROGS-$(CONFIG_FFSERVER) += ffserver AVPROGS := $(AVPROGS-yes:%=%$(PROGSSUF)$(EXESUF)) PROGS += $(AVPROGS) -AVBASENAMES = ffmpeg ffplay ffprobe ffserver +AVBASENAMES = ffmpeg ffplay ffprobe ALLAVPROGS = $(AVBASENAMES:%=%$(PROGSSUF)$(EXESUF)) ALLAVPROGS_G = $(AVBASENAMES:%=%$(PROGSSUF)_g$(EXESUF)) @@ -17,7 +16,6 @@ ifndef CONFIG_VIDEOTOOLBOX OBJS-ffmpeg-$(CONFIG_VDA) += fftools/ffmpeg_videotoolbox.o endif OBJS-ffmpeg-$(CONFIG_VIDEOTOOLBOX) += fftools/ffmpeg_videotoolbox.o -OBJS-ffserver += fftools/ffserver_config.o define DOFFTOOL OBJS-$(1) += fftools/cmdutils.o fftools/$(1).o $(OBJS-$(1)-yes) @@ -29,7 +27,6 @@ $(1)$(PROGSSUF)_g$(EXESUF): FF_EXTRALIBS += $(EXTRALIBS-$(1)) -include $$(OBJS-$(1):.o=.d) endef -$(foreach P,$(AVPROGS-yes),$(eval OBJS-$(P)-$(CONFIG_OPENCL) += fftools/cmdutils_opencl.o)) $(foreach P,$(AVPROGS-yes),$(eval $(call DOFFTOOL,$(P)))) all: $(AVPROGS) diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c index 3d428f3eea8a9..8ffc9d240bfaf 100644 --- a/fftools/cmdutils.c +++ b/fftools/cmdutils.c @@ -38,6 +38,7 @@ #include "libswscale/swscale.h" #include "libswresample/swresample.h" #include "libpostproc/postprocess.h" +#include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/bprint.h" @@ -880,28 +881,54 @@ int opt_loglevel(void *optctx, const char *opt, const char *arg) { "debug" , AV_LOG_DEBUG }, { "trace" , AV_LOG_TRACE }, }; + const char *token; char *tail; - int level; - int flags; - int i; - - flags = av_log_get_flags(); - tail = strstr(arg, "repeat"); - if (tail) - flags &= ~AV_LOG_SKIP_REPEATED; - else - flags |= AV_LOG_SKIP_REPEATED; - - av_log_set_flags(flags); - if (tail == arg) - arg += 6 + (arg[6]=='+'); - if(tail && !*arg) - return 0; + int flags = av_log_get_flags(); + int level = av_log_get_level(); + int cmd, i = 0; + + av_assert0(arg); + while (*arg) { + token = arg; + if (*token == '+' || *token == '-') { + cmd = *token++; + } else { + cmd = 0; + } + if (!i && !cmd) { + flags = 0; /* missing relative prefix, build absolute value */ + } + if (!strncmp(token, "repeat", 6)) { + if (cmd == '-') { + flags |= AV_LOG_SKIP_REPEATED; + } else { + flags &= ~AV_LOG_SKIP_REPEATED; + } + arg = token + 6; + } else if (!strncmp(token, "level", 5)) { + if (cmd == '-') { + flags &= ~AV_LOG_PRINT_LEVEL; + } else { + flags |= AV_LOG_PRINT_LEVEL; + } + arg = token + 5; + } else { + break; + } + i++; + } + if (!*arg) { + goto end; + } else if (*arg == '+') { + arg++; + } else if (!i) { + flags = av_log_get_flags(); /* level value without prefix, reset flags */ + } for (i = 0; i < FF_ARRAY_ELEMS(log_levels); i++) { if (!strcmp(log_levels[i].name, arg)) { - av_log_set_level(log_levels[i].level); - return 0; + level = log_levels[i].level; + goto end; } } @@ -913,6 +940,9 @@ int opt_loglevel(void *optctx, const char *opt, const char *arg) av_log(NULL, AV_LOG_FATAL, "\"%s\"\n", log_levels[i].name); exit_program(1); } + +end: + av_log_set_flags(flags); av_log_set_level(level); return 0; } @@ -1258,8 +1288,10 @@ static int is_device(const AVClass *avclass) static int show_formats_devices(void *optctx, const char *opt, const char *arg, int device_only, int muxdemuxers) { - AVInputFormat *ifmt = NULL; - AVOutputFormat *ofmt = NULL; + void *ifmt_opaque = NULL; + const AVInputFormat *ifmt = NULL; + void *ofmt_opaque = NULL; + const AVOutputFormat *ofmt = NULL; const char *last_name; int is_dev; @@ -1275,7 +1307,8 @@ static int show_formats_devices(void *optctx, const char *opt, const char *arg, const char *long_name = NULL; if (muxdemuxers !=SHOW_DEMUXERS) { - while ((ofmt = av_oformat_next(ofmt))) { + ofmt_opaque = NULL; + while ((ofmt = av_muxer_iterate(&ofmt_opaque))) { is_dev = is_device(ofmt->priv_class); if (!is_dev && device_only) continue; @@ -1288,7 +1321,8 @@ static int show_formats_devices(void *optctx, const char *opt, const char *arg, } } if (muxdemuxers != SHOW_MUXERS) { - while ((ifmt = av_iformat_next(ifmt))) { + ifmt_opaque = NULL; + while ((ifmt = av_demuxer_iterate(&ifmt_opaque))) { is_dev = is_device(ifmt->priv_class); if (!is_dev && device_only) continue; @@ -1602,7 +1636,7 @@ int show_bsfs(void *optctx, const char *opt, const char *arg) void *opaque = NULL; printf("Bitstream filters:\n"); - while ((bsf = av_bsf_next(&opaque))) + while ((bsf = av_bsf_iterate(&opaque))) printf("%s\n", bsf->name); printf("\n"); return 0; @@ -1628,6 +1662,7 @@ int show_filters(void *optctx, const char *opt, const char *arg) #if CONFIG_AVFILTER const AVFilter *filter = NULL; char descr[64], *descr_cur; + void *opaque = NULL; int i, j; const AVFilterPad *pad; @@ -1639,7 +1674,7 @@ int show_filters(void *optctx, const char *opt, const char *arg) " V = Video input/output\n" " N = Dynamic number and/or type of input/output\n" " | = Source or sink filter\n"); - while ((filter = avfilter_next(filter))) { + while ((filter = av_filter_iterate(&opaque))) { descr_cur = descr; for (i = 0; i < 2; i++) { if (i) { @@ -1702,7 +1737,7 @@ int show_pix_fmts(void *optctx, const char *opt, const char *arg) #endif while ((pix_desc = av_pix_fmt_desc_next(pix_desc))) { - enum AVPixelFormat pix_fmt = av_pix_fmt_desc_get_id(pix_desc); + enum AVPixelFormat av_unused pix_fmt = av_pix_fmt_desc_get_id(pix_desc); printf("%c%c%c%c%c %-16s %d %2d\n", sws_isSupportedInput (pix_fmt) ? 'I' : '.', sws_isSupportedOutput(pix_fmt) ? 'O' : '.', @@ -1896,6 +1931,22 @@ static void show_help_filter(const char *name) } #endif +static void show_help_bsf(const char *name) +{ + const AVBitStreamFilter *bsf = av_bsf_get_by_name(name); + + if (!bsf) { + av_log(NULL, AV_LOG_ERROR, "Unknown bit stream filter '%s'.\n", name); + return; + } + + printf("Bit stream filter %s\n", bsf->name); + PRINT_CODEC_SUPPORTED(bsf, codec_ids, enum AVCodecID, "codecs", + AV_CODEC_ID_NONE, GET_CODEC_NAME); + if (bsf->priv_class) + show_help_children(bsf->priv_class, AV_OPT_FLAG_BSF_PARAM); +} + int show_help(void *optctx, const char *opt, const char *arg) { char *topic, *par; @@ -1922,6 +1973,8 @@ int show_help(void *optctx, const char *opt, const char *arg) } else if (!strcmp(topic, "filter")) { show_help_filter(par); #endif + } else if (!strcmp(topic, "bsf")) { + show_help_bsf(par); } else { show_help_default(topic, par); } diff --git a/fftools/cmdutils.h b/fftools/cmdutils.h index 2997ee37b5afe..6e2e0a2acbc84 100644 --- a/fftools/cmdutils.h +++ b/fftools/cmdutils.h @@ -105,12 +105,6 @@ int opt_max_alloc(void *optctx, const char *opt, const char *arg); int opt_codec_debug(void *optctx, const char *opt, const char *arg); -#if CONFIG_OPENCL -int opt_opencl(void *optctx, const char *opt, const char *arg); - -int opt_opencl_bench(void *optctx, const char *opt, const char *arg); -#endif - /** * Limit the execution time. */ @@ -155,6 +149,7 @@ typedef struct SpecifierOpt { uint8_t *str; int i; int64_t i64; + uint64_t ui64; float f; double dbl; } u; @@ -206,17 +201,6 @@ typedef struct OptionDef { void show_help_options(const OptionDef *options, const char *msg, int req_flags, int rej_flags, int alt_flags); -#if CONFIG_OPENCL -#define CMDUTILS_COMMON_OPTIONS_OPENCL \ - { "opencl_bench", OPT_EXIT, {.func_arg = opt_opencl_bench}, \ - "run benchmark on all OpenCL devices and show results" }, \ - { "opencl_options", HAS_ARG, {.func_arg = opt_opencl}, \ - "set OpenCL environment options" }, \ - -#else -#define CMDUTILS_COMMON_OPTIONS_OPENCL -#endif - #if CONFIG_AVDEVICE #define CMDUTILS_COMMON_OPTIONS_AVDEVICE \ { "sources" , OPT_EXIT | HAS_ARG, { .func_arg = show_sources }, \ @@ -256,7 +240,6 @@ void show_help_options(const OptionDef *options, const char *msg, int req_flags, { "max_alloc", HAS_ARG, { .func_arg = opt_max_alloc }, "set maximum size of a single allocated block", "bytes" }, \ { "cpuflags", HAS_ARG | OPT_EXPERT, { .func_arg = opt_cpuflags }, "force specific cpu flags", "flags" }, \ { "hide_banner", OPT_BOOL | OPT_EXPERT, {&hide_banner}, "do not show program banner", "hide_banner" }, \ - CMDUTILS_COMMON_OPTIONS_OPENCL \ CMDUTILS_COMMON_OPTIONS_AVDEVICE \ /** @@ -642,6 +625,9 @@ void *grow_array(void *array, int elem_size, int *size, int new_size); #define GET_PIX_FMT_NAME(pix_fmt)\ const char *name = av_get_pix_fmt_name(pix_fmt); +#define GET_CODEC_NAME(id)\ + const char *name = avcodec_descriptor_get(id)->name; + #define GET_SAMPLE_FMT_NAME(sample_fmt)\ const char *name = av_get_sample_fmt_name(sample_fmt) diff --git a/fftools/cmdutils_opencl.c b/fftools/cmdutils_opencl.c deleted file mode 100644 index 906aef4836314..0000000000000 --- a/fftools/cmdutils_opencl.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Copyright (C) 2013 Lenny Wang - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "libavutil/opt.h" -#include "libavutil/time.h" -#include "libavutil/log.h" -#include "libavutil/opencl.h" -#include "libavutil/avstring.h" -#include "cmdutils.h" - -typedef struct { - int platform_idx; - int device_idx; - char device_name[64]; - int64_t runtime; -} OpenCLDeviceBenchmark; - -const char *ocl_bench_source = AV_OPENCL_KERNEL( -inline unsigned char clip_uint8(int a) -{ - if (a & (~0xFF)) - return (-a)>>31; - else - return a; -} - -kernel void unsharp_bench( - global unsigned char *src, - global unsigned char *dst, - global int *mask, - int width, - int height) -{ - int i, j, local_idx, lc_idx, sum = 0; - int2 thread_idx, block_idx, global_idx, lm_idx; - thread_idx.x = get_local_id(0); - thread_idx.y = get_local_id(1); - block_idx.x = get_group_id(0); - block_idx.y = get_group_id(1); - global_idx.x = get_global_id(0); - global_idx.y = get_global_id(1); - local uchar data[32][32]; - local int lc[128]; - - for (i = 0; i <= 1; i++) { - lm_idx.y = -8 + (block_idx.y + i) * 16 + thread_idx.y; - lm_idx.y = lm_idx.y < 0 ? 0 : lm_idx.y; - lm_idx.y = lm_idx.y >= height ? height - 1: lm_idx.y; - for (j = 0; j <= 1; j++) { - lm_idx.x = -8 + (block_idx.x + j) * 16 + thread_idx.x; - lm_idx.x = lm_idx.x < 0 ? 0 : lm_idx.x; - lm_idx.x = lm_idx.x >= width ? width - 1: lm_idx.x; - data[i*16 + thread_idx.y][j*16 + thread_idx.x] = src[lm_idx.y*width + lm_idx.x]; - } - } - local_idx = thread_idx.y*16 + thread_idx.x; - if (local_idx < 128) - lc[local_idx] = mask[local_idx]; - barrier(CLK_LOCAL_MEM_FENCE); - - \n#pragma unroll\n - for (i = -4; i <= 4; i++) { - lm_idx.y = 8 + i + thread_idx.y; - \n#pragma unroll\n - for (j = -4; j <= 4; j++) { - lm_idx.x = 8 + j + thread_idx.x; - lc_idx = (i + 4)*8 + j + 4; - sum += (int)data[lm_idx.y][lm_idx.x] * lc[lc_idx]; - } - } - int temp = (int)data[thread_idx.y + 8][thread_idx.x + 8]; - int res = temp + (((temp - (int)((sum + 1<<15) >> 16))) >> 16); - if (global_idx.x < width && global_idx.y < height) - dst[global_idx.x + global_idx.y*width] = clip_uint8(res); -} -); - -#define OCLCHECK(method, ... ) \ -do { \ - status = method(__VA_ARGS__); \ - if (status != CL_SUCCESS) { \ - av_log(NULL, AV_LOG_ERROR, # method " error '%s'\n", \ - av_opencl_errstr(status)); \ - ret = AVERROR_EXTERNAL; \ - goto end; \ - } \ -} while (0) - -#define CREATEBUF(out, flags, size) \ -do { \ - out = clCreateBuffer(ext_opencl_env->context, flags, size, NULL, &status); \ - if (status != CL_SUCCESS) { \ - av_log(NULL, AV_LOG_ERROR, "Could not create OpenCL buffer\n"); \ - ret = AVERROR_EXTERNAL; \ - goto end; \ - } \ -} while (0) - -static void fill_rand_int(int *data, int n) -{ - int i; - srand(av_gettime()); - for (i = 0; i < n; i++) - data[i] = rand(); -} - -#define OPENCL_NB_ITER 5 -static int64_t run_opencl_bench(AVOpenCLExternalEnv *ext_opencl_env) -{ - int i, arg = 0, width = 1920, height = 1088; - int64_t start, ret = 0; - cl_int status; - size_t kernel_len; - char *inbuf; - int *mask = NULL; - int buf_size = width * height * sizeof(char); - int mask_size = sizeof(uint32_t) * 128; - - cl_mem cl_mask = NULL, cl_inbuf = NULL, cl_outbuf = NULL; - cl_kernel kernel = NULL; - cl_program program = NULL; - size_t local_work_size_2d[2] = {16, 16}; - size_t global_work_size_2d[2] = {(size_t)width, (size_t)height}; - - if (!(inbuf = av_malloc(buf_size)) || !(mask = av_malloc(mask_size))) { - av_log(NULL, AV_LOG_ERROR, "Out of memory\n"); - ret = AVERROR(ENOMEM); - goto end; - } - fill_rand_int((int*)inbuf, buf_size/4); - fill_rand_int(mask, mask_size/4); - - CREATEBUF(cl_mask, CL_MEM_READ_ONLY, mask_size); - CREATEBUF(cl_inbuf, CL_MEM_READ_ONLY, buf_size); - CREATEBUF(cl_outbuf, CL_MEM_READ_WRITE, buf_size); - - kernel_len = strlen(ocl_bench_source); - program = clCreateProgramWithSource(ext_opencl_env->context, 1, &ocl_bench_source, - &kernel_len, &status); - if (status != CL_SUCCESS || !program) { - av_log(NULL, AV_LOG_ERROR, "OpenCL unable to create benchmark program\n"); - ret = AVERROR_EXTERNAL; - goto end; - } - status = clBuildProgram(program, 1, &(ext_opencl_env->device_id), NULL, NULL, NULL); - if (status != CL_SUCCESS) { - av_log(NULL, AV_LOG_ERROR, "OpenCL unable to build benchmark program\n"); - ret = AVERROR_EXTERNAL; - goto end; - } - kernel = clCreateKernel(program, "unsharp_bench", &status); - if (status != CL_SUCCESS) { - av_log(NULL, AV_LOG_ERROR, "OpenCL unable to create benchmark kernel\n"); - ret = AVERROR_EXTERNAL; - goto end; - } - - OCLCHECK(clEnqueueWriteBuffer, ext_opencl_env->command_queue, cl_inbuf, CL_TRUE, 0, - buf_size, inbuf, 0, NULL, NULL); - OCLCHECK(clEnqueueWriteBuffer, ext_opencl_env->command_queue, cl_mask, CL_TRUE, 0, - mask_size, mask, 0, NULL, NULL); - OCLCHECK(clSetKernelArg, kernel, arg++, sizeof(cl_mem), &cl_inbuf); - OCLCHECK(clSetKernelArg, kernel, arg++, sizeof(cl_mem), &cl_outbuf); - OCLCHECK(clSetKernelArg, kernel, arg++, sizeof(cl_mem), &cl_mask); - OCLCHECK(clSetKernelArg, kernel, arg++, sizeof(cl_int), &width); - OCLCHECK(clSetKernelArg, kernel, arg++, sizeof(cl_int), &height); - - start = av_gettime_relative(); - for (i = 0; i < OPENCL_NB_ITER; i++) - OCLCHECK(clEnqueueNDRangeKernel, ext_opencl_env->command_queue, kernel, 2, NULL, - global_work_size_2d, local_work_size_2d, 0, NULL, NULL); - clFinish(ext_opencl_env->command_queue); - ret = (av_gettime_relative() - start)/OPENCL_NB_ITER; -end: - if (kernel) - clReleaseKernel(kernel); - if (program) - clReleaseProgram(program); - if (cl_inbuf) - clReleaseMemObject(cl_inbuf); - if (cl_outbuf) - clReleaseMemObject(cl_outbuf); - if (cl_mask) - clReleaseMemObject(cl_mask); - av_free(inbuf); - av_free(mask); - return ret; -} - -static int compare_ocl_device_desc(const void *a, const void *b) -{ - const OpenCLDeviceBenchmark* va = (const OpenCLDeviceBenchmark*)a; - const OpenCLDeviceBenchmark* vb = (const OpenCLDeviceBenchmark*)b; - return FFDIFFSIGN(va->runtime , vb->runtime); -} - -int opt_opencl_bench(void *optctx, const char *opt, const char *arg) -{ - int i, j, nb_devices = 0, count = 0, ret = 0; - int64_t score = 0; - AVOpenCLDeviceList *device_list; - AVOpenCLDeviceNode *device_node = NULL; - OpenCLDeviceBenchmark *devices = NULL; - cl_platform_id platform; - - ret = av_opencl_get_device_list(&device_list); - if (ret < 0) { - return ret; - } - for (i = 0; i < device_list->platform_num; i++) - nb_devices += device_list->platform_node[i]->device_num; - if (!nb_devices) { - av_log(NULL, AV_LOG_ERROR, "No OpenCL device detected!\n"); - av_opencl_free_device_list(&device_list); - return AVERROR(EINVAL); - } - if (!(devices = av_malloc_array(nb_devices, sizeof(OpenCLDeviceBenchmark)))) { - av_log(NULL, AV_LOG_ERROR, "Could not allocate buffer\n"); - av_opencl_free_device_list(&device_list); - return AVERROR(ENOMEM); - } - - for (i = 0; i < device_list->platform_num; i++) { - for (j = 0; j < device_list->platform_node[i]->device_num; j++) { - device_node = device_list->platform_node[i]->device_node[j]; - platform = device_list->platform_node[i]->platform_id; - score = av_opencl_benchmark(device_node, platform, run_opencl_bench); - if (score > 0) { - devices[count].platform_idx = i; - devices[count].device_idx = j; - devices[count].runtime = score; - av_strlcpy(devices[count].device_name, device_node->device_name, - sizeof(devices[count].device_name)); - count++; - } - } - } - qsort(devices, count, sizeof(OpenCLDeviceBenchmark), compare_ocl_device_desc); - fprintf(stderr, "platform_idx\tdevice_idx\tdevice_name\truntime\n"); - for (i = 0; i < count; i++) - fprintf(stdout, "%d\t%d\t%s\t%"PRId64"\n", - devices[i].platform_idx, devices[i].device_idx, - devices[i].device_name, devices[i].runtime); - - av_opencl_free_device_list(&device_list); - av_free(devices); - return 0; -} - -int opt_opencl(void *optctx, const char *opt, const char *arg) -{ - char *key, *value; - const char *opts = arg; - int ret = 0; - while (*opts) { - ret = av_opt_get_key_value(&opts, "=", ":", 0, &key, &value); - if (ret < 0) - return ret; - ret = av_opencl_set_option(key, value); - if (ret < 0) - return ret; - if (*opts) - opts++; - } - return ret; -} diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 6d64bc1043ad0..4dbe72186df64 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -61,6 +61,7 @@ #include "libavutil/timestamp.h" #include "libavutil/bprint.h" #include "libavutil/time.h" +#include "libavutil/thread.h" #include "libavutil/threadmessage.h" #include "libavcodec/mathops.h" #include "libavformat/os_support.h" @@ -98,10 +99,6 @@ #include #endif -#if HAVE_PTHREADS -#include -#endif - #include #include "ffmpeg.h" @@ -161,7 +158,7 @@ static struct termios oldtty; static int restore_tty; #endif -#if HAVE_PTHREADS +#if HAVE_THREADS static void free_input_threads(void); #endif @@ -220,13 +217,18 @@ static void sub2video_push_ref(InputStream *ist, int64_t pts) { AVFrame *frame = ist->sub2video.frame; int i; + int ret; av_assert1(frame->data[0]); ist->sub2video.last_pts = frame->pts = pts; - for (i = 0; i < ist->nb_filters; i++) - av_buffersrc_add_frame_flags(ist->filters[i]->filter, frame, - AV_BUFFERSRC_FLAG_KEEP_REF | - AV_BUFFERSRC_FLAG_PUSH); + for (i = 0; i < ist->nb_filters; i++) { + ret = av_buffersrc_add_frame_flags(ist->filters[i]->filter, frame, + AV_BUFFERSRC_FLAG_KEEP_REF | + AV_BUFFERSRC_FLAG_PUSH); + if (ret != AVERROR_EOF && ret < 0) + av_log(NULL, AV_LOG_WARNING, "Error while add the frame to buffer source(%s).\n", + av_err2str(ret)); + } } void sub2video_update(InputStream *ist, AVSubtitle *sub) @@ -283,7 +285,8 @@ static void sub2video_heartbeat(InputStream *ist, int64_t pts) /* do not send the heartbeat frame if the subtitle is already ahead */ if (pts2 <= ist2->sub2video.last_pts) continue; - if (pts2 >= ist2->sub2video.end_pts || !ist2->sub2video.frame->data[0]) + if (pts2 >= ist2->sub2video.end_pts || + (!ist2->sub2video.frame->data[0] && ist2->sub2video.end_pts < INT64_MAX)) sub2video_update(ist2, NULL); for (j = 0, nb_reqs = 0; j < ist2->nb_filters; j++) nb_reqs += av_buffersrc_get_nb_failed_requests(ist2->filters[j]->filter); @@ -295,11 +298,15 @@ static void sub2video_heartbeat(InputStream *ist, int64_t pts) static void sub2video_flush(InputStream *ist) { int i; + int ret; if (ist->sub2video.end_pts < INT64_MAX) sub2video_update(ist, NULL); - for (i = 0; i < ist->nb_filters; i++) - av_buffersrc_add_frame(ist->filters[i]->filter, NULL); + for (i = 0; i < ist->nb_filters; i++) { + ret = av_buffersrc_add_frame(ist->filters[i]->filter, NULL); + if (ret != AVERROR_EOF && ret < 0) + av_log(NULL, AV_LOG_WARNING, "Flush the frame error.\n"); + } } /* end of sub2video hack */ @@ -327,13 +334,14 @@ static int main_return_code = 0; static void sigterm_handler(int sig) { + int ret; received_sigterm = sig; received_nb_signals++; term_exit_sigsafe(); if(received_nb_signals > 3) { - write(2/*STDERR_FILENO*/, "Received > 3 system signals, hard exiting\n", - strlen("Received > 3 system signals, hard exiting\n")); - + ret = write(2/*STDERR_FILENO*/, "Received > 3 system signals, hard exiting\n", + strlen("Received > 3 system signals, hard exiting\n")); + if (ret < 0) { /* Do nothing */ }; exit(123); } } @@ -399,6 +407,9 @@ void term_init(void) #ifdef SIGXCPU signal(SIGXCPU, sigterm_handler); #endif +#ifdef SIGPIPE + signal(SIGPIPE, SIG_IGN); /* Broken pipe (POSIX). */ +#endif #if HAVE_SETCONSOLECTRLHANDLER SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE); #endif @@ -541,9 +552,6 @@ static void ffmpeg_cleanup(int ret) av_frame_free(&ost->last_frame); av_dict_free(&ost->encoder_opts); - av_parser_close(ost->parser); - avcodec_free_context(&ost->parser_avctx); - av_freep(&ost->forced_keyframes); av_expr_free(ost->forced_keyframes_pexpr); av_freep(&ost->avfilter); @@ -568,7 +576,7 @@ static void ffmpeg_cleanup(int ret) av_freep(&output_streams[i]); } -#if HAVE_PTHREADS +#if HAVE_THREADS free_input_threads(); #endif for (i = 0; i < nb_input_files; i++) { @@ -1199,24 +1207,6 @@ static void do_video_out(OutputFile *of, #endif return; -#if FF_API_LAVF_FMT_RAWPICTURE - if (of->ctx->oformat->flags & AVFMT_RAWPICTURE && - enc->codec->id == AV_CODEC_ID_RAWVIDEO) { - /* raw pictures are written as AVPicture structure to - avoid any copies. We support temporarily the older - method. */ - if (in_picture->interlaced_frame) - mux_par->field_order = in_picture->top_field_first ? AV_FIELD_TB:AV_FIELD_BT; - else - mux_par->field_order = AV_FIELD_PROGRESSIVE; - pkt.data = (uint8_t *)in_picture; - pkt.size = sizeof(AVPicture); - pkt.pts = av_rescale_q(in_picture->pts, enc->time_base, ost->mux_timebase); - pkt.flags |= AV_PKT_FLAG_KEY; - - output_packet(of, &pkt, ost, 0); - } else -#endif { int forced_keyframe = 0; double pts_time; @@ -1571,7 +1561,7 @@ static void print_final_stats(int64_t total_size) uint64_t total_packets = 0, total_size = 0; av_log(NULL, AV_LOG_VERBOSE, "Input file #%d (%s):\n", - i, f->ctx->filename); + i, f->ctx->url); for (j = 0; j < f->nb_streams; j++) { InputStream *ist = input_streams[f->ist_index + j]; @@ -1605,7 +1595,7 @@ static void print_final_stats(int64_t total_size) uint64_t total_packets = 0, total_size = 0; av_log(NULL, AV_LOG_VERBOSE, "Output file #%d (%s):\n", - i, of->ctx->filename); + i, of->ctx->url); for (j = 0; j < of->ctx->nb_streams; j++) { OutputStream *ost = output_streams[of->ost_index + j]; @@ -1645,8 +1635,7 @@ static void print_final_stats(int64_t total_size) static void print_report(int is_last_report, int64_t timer_start, int64_t cur_time) { - char buf[1024]; - AVBPrint buf_script; + AVBPrint buf, buf_script; OutputStream *ost; AVFormatContext *oc; int64_t total_size; @@ -1658,6 +1647,7 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti static int64_t last_time = -1; static int qp_histogram[52]; int hours, mins, secs, us; + const char *hours_sign; int ret; float t; @@ -1683,8 +1673,8 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti if (total_size <= 0) // FIXME improve avio_size() so it works with non seekable output too total_size = avio_tell(oc->pb); - buf[0] = '\0'; vid = 0; + av_bprint_init(&buf, 0, AV_BPRINT_SIZE_AUTOMATIC); av_bprint_init(&buf_script, 0, 1); for (i = 0; i < nb_output_streams; i++) { float q = -1; @@ -1694,7 +1684,7 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti q = ost->quality / (float) FF_QP2LAMBDA; if (vid && enc->codec_type == AVMEDIA_TYPE_VIDEO) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "q=%2.1f ", q); + av_bprintf(&buf, "q=%2.1f ", q); av_bprintf(&buf_script, "stream_%d_%d_q=%.1f\n", ost->file_index, ost->index, q); } @@ -1703,21 +1693,21 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti frame_number = ost->frame_number; fps = t > 1 ? frame_number / t : 0; - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "frame=%5d fps=%3.*f q=%3.1f ", + av_bprintf(&buf, "frame=%5d fps=%3.*f q=%3.1f ", frame_number, fps < 9.95, fps, q); av_bprintf(&buf_script, "frame=%d\n", frame_number); av_bprintf(&buf_script, "fps=%.1f\n", fps); av_bprintf(&buf_script, "stream_%d_%d_q=%.1f\n", ost->file_index, ost->index, q); if (is_last_report) - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "L"); + av_bprintf(&buf, "L"); if (qp_hist) { int j; int qp = lrintf(q); if (qp >= 0 && qp < FF_ARRAY_ELEMS(qp_histogram)) qp_histogram[qp]++; for (j = 0; j < 32; j++) - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%X", av_log2(qp_histogram[j] + 1)); + av_bprintf(&buf, "%X", av_log2(qp_histogram[j] + 1)); } if ((enc->flags & AV_CODEC_FLAG_PSNR) && (ost->pict_type != AV_PICTURE_TYPE_NONE || is_last_report)) { @@ -1726,7 +1716,7 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti double scale, scale_sum = 0; double p; char type[3] = { 'Y','U','V' }; - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "PSNR="); + av_bprintf(&buf, "PSNR="); for (j = 0; j < 3; j++) { if (is_last_report) { error = enc->error[j]; @@ -1740,12 +1730,12 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti error_sum += error; scale_sum += scale; p = psnr(error / scale); - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%c:%2.2f ", type[j], p); + av_bprintf(&buf, "%c:%2.2f ", type[j], p); av_bprintf(&buf_script, "stream_%d_%d_psnr_%c=%2.2f\n", ost->file_index, ost->index, type[j] | 32, p); } p = psnr(error_sum / scale_sum); - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "*:%2.2f ", psnr(error_sum / scale_sum)); + av_bprintf(&buf, "*:%2.2f ", psnr(error_sum / scale_sum)); av_bprintf(&buf_script, "stream_%d_%d_psnr_all=%2.2f\n", ost->file_index, ost->index, p); } @@ -1765,57 +1755,62 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti secs %= 60; hours = mins / 60; mins %= 60; + hours_sign = (pts < 0) ? "-" : ""; bitrate = pts && total_size >= 0 ? total_size * 8 / (pts / 1000.0) : -1; speed = t != 0.0 ? (double)pts / AV_TIME_BASE / t : -1; - if (total_size < 0) snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - "size=N/A time="); - else snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - "size=%8.0fkB time=", total_size / 1024.0); - if (pts < 0) - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "-"); - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), - "%02d:%02d:%02d.%02d ", hours, mins, secs, - (100 * us) / AV_TIME_BASE); + if (total_size < 0) av_bprintf(&buf, "size=N/A time="); + else av_bprintf(&buf, "size=%8.0fkB time=", total_size / 1024.0); + if (pts == AV_NOPTS_VALUE) { + av_bprintf(&buf, "N/A "); + } else { + av_bprintf(&buf, "%s%02d:%02d:%02d.%02d ", + hours_sign, hours, mins, secs, (100 * us) / AV_TIME_BASE); + } if (bitrate < 0) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),"bitrate=N/A"); + av_bprintf(&buf, "bitrate=N/A"); av_bprintf(&buf_script, "bitrate=N/A\n"); }else{ - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),"bitrate=%6.1fkbits/s", bitrate); + av_bprintf(&buf, "bitrate=%6.1fkbits/s", bitrate); av_bprintf(&buf_script, "bitrate=%6.1fkbits/s\n", bitrate); } if (total_size < 0) av_bprintf(&buf_script, "total_size=N/A\n"); else av_bprintf(&buf_script, "total_size=%"PRId64"\n", total_size); - av_bprintf(&buf_script, "out_time_ms=%"PRId64"\n", pts); - av_bprintf(&buf_script, "out_time=%02d:%02d:%02d.%06d\n", - hours, mins, secs, us); + if (pts == AV_NOPTS_VALUE) { + av_bprintf(&buf_script, "out_time_ms=N/A\n"); + av_bprintf(&buf_script, "out_time=N/A\n"); + } else { + av_bprintf(&buf_script, "out_time_ms=%"PRId64"\n", pts); + av_bprintf(&buf_script, "out_time=%s%02d:%02d:%02d.%06d\n", + hours_sign, hours, mins, secs, us); + } if (nb_frames_dup || nb_frames_drop) - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " dup=%d drop=%d", - nb_frames_dup, nb_frames_drop); + av_bprintf(&buf, " dup=%d drop=%d", nb_frames_dup, nb_frames_drop); av_bprintf(&buf_script, "dup_frames=%d\n", nb_frames_dup); av_bprintf(&buf_script, "drop_frames=%d\n", nb_frames_drop); if (speed < 0) { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf)," speed=N/A"); + av_bprintf(&buf, " speed=N/A"); av_bprintf(&buf_script, "speed=N/A\n"); } else { - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf)," speed=%4.3gx", speed); + av_bprintf(&buf, " speed=%4.3gx", speed); av_bprintf(&buf_script, "speed=%4.3gx\n", speed); } if (print_stats || is_last_report) { const char end = is_last_report ? '\n' : '\r'; if (print_stats==1 && AV_LOG_INFO > av_log_get_level()) { - fprintf(stderr, "%s %c", buf, end); + fprintf(stderr, "%s %c", buf.str, end); } else - av_log(NULL, AV_LOG_INFO, "%s %c", buf, end); + av_log(NULL, AV_LOG_INFO, "%s %c", buf.str, end); fflush(stderr); } + av_bprint_finalize(&buf, NULL); if (progress_avio) { av_bprintf(&buf_script, "progress=%s\n", @@ -1835,6 +1830,19 @@ static void print_report(int is_last_report, int64_t timer_start, int64_t cur_ti print_final_stats(total_size); } +static void ifilter_parameters_from_codecpar(InputFilter *ifilter, AVCodecParameters *par) +{ + // We never got any input. Set a fake format, which will + // come from libavformat. + ifilter->format = par->format; + ifilter->sample_rate = par->sample_rate; + ifilter->channels = par->channels; + ifilter->channel_layout = par->channel_layout; + ifilter->width = par->width; + ifilter->height = par->height; + ifilter->sample_aspect_ratio = par->sample_aspect_ratio; +} + static void flush_encoders(void) { int i, ret; @@ -1861,18 +1869,8 @@ static void flush_encoders(void) int x; for (x = 0; x < fg->nb_inputs; x++) { InputFilter *ifilter = fg->inputs[x]; - if (ifilter->format < 0) { - AVCodecParameters *par = ifilter->ist->st->codecpar; - // We never got any input. Set a fake format, which will - // come from libavformat. - ifilter->format = par->format; - ifilter->sample_rate = par->sample_rate; - ifilter->channels = par->channels; - ifilter->channel_layout = par->channel_layout; - ifilter->width = par->width; - ifilter->height = par->height; - ifilter->sample_aspect_ratio = par->sample_aspect_ratio; - } + if (ifilter->format < 0) + ifilter_parameters_from_codecpar(ifilter, ifilter->ist->st->codecpar); } if (!ifilter_has_all_input_formats(fg)) @@ -1897,10 +1895,6 @@ static void flush_encoders(void) if (enc->codec_type == AVMEDIA_TYPE_AUDIO && enc->frame_size <= 1) continue; -#if FF_API_LAVF_FMT_RAWPICTURE - if (enc->codec_type == AVMEDIA_TYPE_VIDEO && (of->ctx->oformat->flags & AVFMT_RAWPICTURE) && enc->codec->id == AV_CODEC_ID_RAWVIDEO) - continue; -#endif if (enc->codec_type != AVMEDIA_TYPE_VIDEO && enc->codec_type != AVMEDIA_TYPE_AUDIO) continue; @@ -1991,11 +1985,16 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p InputFile *f = input_files [ist->file_index]; int64_t start_time = (of->start_time == AV_NOPTS_VALUE) ? 0 : of->start_time; int64_t ost_tb_start_time = av_rescale_q(start_time, AV_TIME_BASE_Q, ost->mux_timebase); - AVPicture pict; - AVPacket opkt; + AVPacket opkt = { 0 }; av_init_packet(&opkt); + // EOF: flush output bitstream filters. + if (!pkt) { + output_packet(of, &opkt, ost, 1); + return; + } + if ((!ost->frame_number && !(pkt->flags & AV_PKT_FLAG_KEY)) && !ost->copy_initial_nonkeyframes) return; @@ -2053,48 +2052,16 @@ static void do_streamcopy(InputStream *ist, OutputStream *ost, const AVPacket *p opkt.duration = av_rescale_q(pkt->duration, ist->st->time_base, ost->mux_timebase); opkt.flags = pkt->flags; - // FIXME remove the following 2 lines they shall be replaced by the bitstream filters - if ( ost->st->codecpar->codec_id != AV_CODEC_ID_H264 - && ost->st->codecpar->codec_id != AV_CODEC_ID_MPEG1VIDEO - && ost->st->codecpar->codec_id != AV_CODEC_ID_MPEG2VIDEO - && ost->st->codecpar->codec_id != AV_CODEC_ID_VC1 - ) { - int ret = av_parser_change(ost->parser, ost->parser_avctx, - &opkt.data, &opkt.size, - pkt->data, pkt->size, - pkt->flags & AV_PKT_FLAG_KEY); - if (ret < 0) { - av_log(NULL, AV_LOG_FATAL, "av_parser_change failed: %s\n", - av_err2str(ret)); - exit_program(1); - } - if (ret) { - opkt.buf = av_buffer_create(opkt.data, opkt.size, av_buffer_default_free, NULL, 0); - if (!opkt.buf) - exit_program(1); - } - } else { - opkt.data = pkt->data; - opkt.size = pkt->size; - } - av_copy_packet_side_data(&opkt, pkt); -#if FF_API_LAVF_FMT_RAWPICTURE - if (ost->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && - ost->st->codecpar->codec_id == AV_CODEC_ID_RAWVIDEO && - (of->ctx->oformat->flags & AVFMT_RAWPICTURE)) { - /* store AVPicture in AVPacket, as expected by the output format */ - int ret = avpicture_fill(&pict, opkt.data, ost->st->codecpar->format, ost->st->codecpar->width, ost->st->codecpar->height); - if (ret < 0) { - av_log(NULL, AV_LOG_FATAL, "avpicture_fill failed: %s\n", - av_err2str(ret)); + if (pkt->buf) { + opkt.buf = av_buffer_ref(pkt->buf); + if (!opkt.buf) exit_program(1); - } - opkt.data = (uint8_t *)&pict; - opkt.size = sizeof(AVPicture); - opkt.flags |= AV_PKT_FLAG_KEY; } -#endif + opkt.data = pkt->data; + opkt.size = pkt->size; + + av_copy_packet_side_data(&opkt, pkt); output_packet(of, &opkt, ost, 0); } @@ -2129,7 +2096,7 @@ static void check_decode_result(InputStream *ist, int *got_output, int ret) if (exit_on_error && *got_output && ist) { if (ist->decoded_frame->decode_error_flags || (ist->decoded_frame->flags & AV_FRAME_FLAG_CORRUPT)) { - av_log(NULL, AV_LOG_FATAL, "%s: corrupt decoded frame in stream %d\n", input_files[ist->file_index]->ctx->filename, ist->st->index); + av_log(NULL, AV_LOG_FATAL, "%s: corrupt decoded frame in stream %d\n", input_files[ist->file_index]->ctx->url, ist->st->index); exit_program(1); } } @@ -2199,10 +2166,7 @@ static int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame) ret = reap_filters(1); if (ret < 0 && ret != AVERROR_EOF) { - char errbuf[128]; - av_strerror(ret, errbuf, sizeof(errbuf)); - - av_log(NULL, AV_LOG_ERROR, "Error while filtering: %s\n", errbuf); + av_log(NULL, AV_LOG_ERROR, "Error while filtering: %s\n", av_err2str(ret)); return ret; } @@ -2225,7 +2189,7 @@ static int ifilter_send_frame(InputFilter *ifilter, AVFrame *frame) static int ifilter_send_eof(InputFilter *ifilter, int64_t pts) { - int i, j, ret; + int ret; ifilter->eof = 1; @@ -2235,16 +2199,11 @@ static int ifilter_send_eof(InputFilter *ifilter, int64_t pts) return ret; } else { // the filtergraph was never configured - FilterGraph *fg = ifilter->graph; - for (i = 0; i < fg->nb_inputs; i++) - if (!fg->inputs[i]->eof) - break; - if (i == fg->nb_inputs) { - // All the input streams have finished without the filtergraph - // ever being configured. - // Mark the output streams as finished. - for (j = 0; j < fg->nb_outputs; j++) - finish_output_stream(fg->outputs[j]->ost); + if (ifilter->format < 0) + ifilter_parameters_from_codecpar(ifilter, ifilter->ist->st->codecpar); + if (ifilter->format < 0 && (ifilter->type == AVMEDIA_TYPE_AUDIO || ifilter->type == AVMEDIA_TYPE_VIDEO)) { + av_log(NULL, AV_LOG_ERROR, "Cannot determine format of input stream %d:%d after EOF\n", ifilter->ist->file_index, ifilter->ist->st->index); + return AVERROR_INVALIDDATA; } } @@ -2665,8 +2624,13 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo ist->next_dts = AV_NOPTS_VALUE; } - if (got_output) - ist->next_pts += av_rescale_q(duration_pts, ist->st->time_base, AV_TIME_BASE_Q); + if (got_output) { + if (duration_pts > 0) { + ist->next_pts += av_rescale_q(duration_pts, ist->st->time_base, AV_TIME_BASE_Q); + } else { + ist->next_pts += duration_dts; + } + } break; case AVMEDIA_TYPE_SUBTITLE: if (repeating) @@ -2728,7 +2692,7 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo } /* handle stream copy */ - if (!ist->decoding_needed) { + if (!ist->decoding_needed && pkt) { ist->dts = ist->next_dts; switch (ist->dec_ctx->codec_type) { case AVMEDIA_TYPE_AUDIO: @@ -2754,7 +2718,7 @@ static int process_input_packet(InputStream *ist, const AVPacket *pkt, int no_eo ist->pts = ist->dts; ist->next_pts = ist->next_dts; } - for (i = 0; pkt && i < nb_output_streams; i++) { + for (i = 0; i < nb_output_streams; i++) { OutputStream *ost = output_streams[i]; if (!check_output_constraints(ist, ost) || ost->encoding_needed) @@ -2811,44 +2775,77 @@ static void print_sdp(void) av_freep(&avc); } -static const HWAccel *get_hwaccel(enum AVPixelFormat pix_fmt) -{ - int i; - for (i = 0; hwaccels[i].name; i++) - if (hwaccels[i].pix_fmt == pix_fmt) - return &hwaccels[i]; - return NULL; -} - static enum AVPixelFormat get_format(AVCodecContext *s, const enum AVPixelFormat *pix_fmts) { InputStream *ist = s->opaque; const enum AVPixelFormat *p; int ret; - for (p = pix_fmts; *p != -1; p++) { + for (p = pix_fmts; *p != AV_PIX_FMT_NONE; p++) { const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(*p); - const HWAccel *hwaccel; + const AVCodecHWConfig *config = NULL; + int i; if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) break; - hwaccel = get_hwaccel(*p); - if (!hwaccel || - (ist->active_hwaccel_id && ist->active_hwaccel_id != hwaccel->id) || - (ist->hwaccel_id != HWACCEL_AUTO && ist->hwaccel_id != hwaccel->id)) - continue; + if (ist->hwaccel_id == HWACCEL_GENERIC || + ist->hwaccel_id == HWACCEL_AUTO) { + for (i = 0;; i++) { + config = avcodec_get_hw_config(s->codec, i); + if (!config) + break; + if (!(config->methods & + AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX)) + continue; + if (config->pix_fmt == *p) + break; + } + } + if (config) { + if (config->device_type != ist->hwaccel_device_type) { + // Different hwaccel offered, ignore. + continue; + } - ret = hwaccel->init(s); - if (ret < 0) { - if (ist->hwaccel_id == hwaccel->id) { + ret = hwaccel_decode_init(s); + if (ret < 0) { + if (ist->hwaccel_id == HWACCEL_GENERIC) { + av_log(NULL, AV_LOG_FATAL, + "%s hwaccel requested for input stream #%d:%d, " + "but cannot be initialized.\n", + av_hwdevice_get_type_name(config->device_type), + ist->file_index, ist->st->index); + return AV_PIX_FMT_NONE; + } + continue; + } + } else { + const HWAccel *hwaccel = NULL; + int i; + for (i = 0; hwaccels[i].name; i++) { + if (hwaccels[i].pix_fmt == *p) { + hwaccel = &hwaccels[i]; + break; + } + } + if (!hwaccel) { + // No hwaccel supporting this pixfmt. + continue; + } + if (hwaccel->id != ist->hwaccel_id) { + // Does not match requested hwaccel. + continue; + } + + ret = hwaccel->init(s); + if (ret < 0) { av_log(NULL, AV_LOG_FATAL, "%s hwaccel requested for input stream #%d:%d, " "but cannot be initialized.\n", hwaccel->name, ist->file_index, ist->st->index); return AV_PIX_FMT_NONE; } - continue; } if (ist->hw_frames_ctx) { @@ -2857,8 +2854,7 @@ static enum AVPixelFormat get_format(AVCodecContext *s, const enum AVPixelFormat return AV_PIX_FMT_NONE; } - ist->active_hwaccel_id = hwaccel->id; - ist->hwaccel_pix_fmt = *p; + ist->hwaccel_pix_fmt = *p; break; } @@ -2905,7 +2901,7 @@ static int init_input_stream(int ist_index, char *error, int error_len) /* Useful for subtitles retiming by lavf (FIXME), skipping samples in * audio, and video decoders such as cuvid or mediacodec */ - av_codec_set_pkt_timebase(ist->dec_ctx, ist->st->time_base); + ist->dec_ctx->pkt_timebase = ist->st->time_base; if (!av_dict_get(ist->decoder_opts, "threads", NULL, 0)) av_dict_set(&ist->decoder_opts, "threads", "auto", 0); @@ -2976,7 +2972,7 @@ static int check_init_output_file(OutputFile *of, int file_index) //assert_avoptions(of->opts); of->header_written = 1; - av_dump_format(of->ctx, file_index, of->ctx->filename, 1); + av_dump_format(of->ctx, file_index, of->ctx->url, 1); if (sdp_filename || want_sdp) print_sdp(); @@ -3109,11 +3105,6 @@ static int init_output_stream_streamcopy(OutputStream *ost) av_display_rotation_set((int32_t *)sd, -ost->rotate_override_value); } - ost->parser = av_parser_init(par_dst->codec_id); - ost->parser_avctx = avcodec_alloc_context3(NULL); - if (!ost->parser_avctx) - return AVERROR(ENOMEM); - switch (par_dst->codec_type) { case AVMEDIA_TYPE_AUDIO: if (audio_volume != 256) { @@ -3155,7 +3146,7 @@ static void set_encoder_id(OutputFile *of, OutputStream *ost) uint8_t *encoder_string; int encoder_string_len; int format_flags = 0; - int codec_flags = 0; + int codec_flags = ost->enc_ctx->flags; if (av_dict_get(ost->st->metadata, "encoder", NULL, 0)) return; @@ -3489,7 +3480,8 @@ static int init_output_stream(OutputStream *ost, char *error, int error_len) av_buffersink_set_frame_size(ost->filter->filter, ost->enc_ctx->frame_size); assert_avoptions(ost->encoder_opts); - if (ost->enc_ctx->bit_rate && ost->enc_ctx->bit_rate < 1000) + if (ost->enc_ctx->bit_rate && ost->enc_ctx->bit_rate < 1000 && + ost->enc_ctx->codec_id != AV_CODEC_ID_CODEC2 /* don't complain about 700 bit/s modes */) av_log(NULL, AV_LOG_WARNING, "The bitrate parameter is set too low." " It takes bits/s as argument, not kbits/s\n"); @@ -3553,14 +3545,6 @@ static int init_output_stream(OutputStream *ost, char *error, int error_len) ret = init_output_stream_streamcopy(ost); if (ret < 0) return ret; - - /* - * FIXME: will the codec context used by the parser during streamcopy - * This should go away with the new parser API. - */ - ret = avcodec_parameters_to_context(ost->parser_avctx, ost->st->codecpar); - if (ret < 0) - return ret; } // parse user provided disposition, and update stream values @@ -3577,8 +3561,10 @@ static int init_output_stream(OutputStream *ost, char *error, int error_len) { "hearing_impaired" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_HEARING_IMPAIRED }, .unit = "flags" }, { "visual_impaired" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_VISUAL_IMPAIRED }, .unit = "flags" }, { "clean_effects" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_CLEAN_EFFECTS }, .unit = "flags" }, + { "attached_pic" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_ATTACHED_PIC }, .unit = "flags" }, { "captions" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_CAPTIONS }, .unit = "flags" }, { "descriptions" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DESCRIPTIONS }, .unit = "flags" }, + { "dependent" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_DEPENDENT }, .unit = "flags" }, { "metadata" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_DISPOSITION_METADATA }, .unit = "flags" }, { NULL }, }; @@ -3983,7 +3969,7 @@ static int check_keyboard_interaction(int64_t cur_time) return 0; } -#if HAVE_PTHREADS +#if HAVE_THREADS static void *input_thread(void *arg) { InputFile *f = arg; @@ -4093,7 +4079,7 @@ static int get_input_packet(InputFile *f, AVPacket *pkt) } } -#if HAVE_PTHREADS +#if HAVE_THREADS if (nb_input_files > 1) return get_input_packet_mt(f, pkt); #endif @@ -4153,12 +4139,6 @@ static int seek_to_start(InputFile *ifile, AVFormatContext *is) ist = input_streams[ifile->ist_index + i]; avctx = ist->dec_ctx; - // flush decoders - if (ist->decoding_needed) { - process_input_packet(ist, NULL, 1); - avcodec_flush_buffers(avctx); - } - /* duration is the length of the last frame in a stream * when audio stream is present we don't care about * last video frame length because it's not defined exactly */ @@ -4175,14 +4155,17 @@ static int seek_to_start(InputFile *ifile, AVFormatContext *is) AVRational sample_rate = {1, avctx->sample_rate}; duration = av_rescale_q(ist->nb_samples, sample_rate, ist->st->time_base); - } else + } else { continue; + } } else { if (ist->framerate.num) { - duration = av_rescale_q(1, ist->framerate, ist->st->time_base); + duration = av_rescale_q(1, av_inv_q(ist->framerate), ist->st->time_base); } else if (ist->st->avg_frame_rate.num) { - duration = av_rescale_q(1, ist->st->avg_frame_rate, ist->st->time_base); - } else duration = 1; + duration = av_rescale_q(1, av_inv_q(ist->st->avg_frame_rate), ist->st->time_base); + } else { + duration = 1; + } } if (!ifile->duration) ifile->time_base = ist->st->time_base; @@ -4224,9 +4207,22 @@ static int process_input(int file_index) return ret; } if (ret < 0 && ifile->loop) { - if ((ret = seek_to_start(ifile, is)) < 0) - return ret; - ret = get_input_packet(ifile, &pkt); + AVCodecContext *avctx; + for (i = 0; i < ifile->nb_streams; i++) { + ist = input_streams[ifile->ist_index + i]; + avctx = ist->dec_ctx; + if (ist->decoding_needed) { + ret = process_input_packet(ist, NULL, 1); + if (ret>0) + return 0; + avcodec_flush_buffers(avctx); + } + } + ret = seek_to_start(ifile, is); + if (ret < 0) + av_log(NULL, AV_LOG_WARNING, "Seek to start failed.\n"); + else + ret = get_input_packet(ifile, &pkt); if (ret == AVERROR(EAGAIN)) { ifile->eagain = 1; return ret; @@ -4234,7 +4230,7 @@ static int process_input(int file_index) } if (ret < 0) { if (ret != AVERROR_EOF) { - print_error(is->filename, ret); + print_error(is->url, ret); if (exit_on_error) exit_program(1); } @@ -4283,7 +4279,7 @@ static int process_input(int file_index) goto discard_packet; if (exit_on_error && (pkt.flags & AV_PKT_FLAG_CORRUPT)) { - av_log(NULL, AV_LOG_FATAL, "%s: corrupt input packet in stream %d\n", is->filename, pkt.stream_index); + av_log(NULL, AV_LOG_FATAL, "%s: corrupt input packet in stream %d\n", is->url, pkt.stream_index); exit_program(1); } @@ -4531,6 +4527,15 @@ static int transcode_step(void) } if (ost->filter && ost->filter->graph->graph) { + if (!ost->initialized) { + char error[1024] = {0}; + ret = init_output_stream(ost, error, sizeof(error)); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Error initializing output stream %d:%d -- %s\n", + ost->file_index, ost->index, error); + exit_program(1); + } + } if ((ret = transcode_from_filter(ost->filter->graph, &ist)) < 0) return ret; if (!ist) @@ -4588,7 +4593,7 @@ static int transcode(void) timer_start = av_gettime_relative(); -#if HAVE_PTHREADS +#if HAVE_THREADS if ((ret = init_input_threads()) < 0) goto fail; #endif @@ -4609,24 +4614,21 @@ static int transcode(void) ret = transcode_step(); if (ret < 0 && ret != AVERROR_EOF) { - char errbuf[128]; - av_strerror(ret, errbuf, sizeof(errbuf)); - - av_log(NULL, AV_LOG_ERROR, "Error while filtering: %s\n", errbuf); + av_log(NULL, AV_LOG_ERROR, "Error while filtering: %s\n", av_err2str(ret)); break; } /* dump report by using the output first video and audio streams */ print_report(0, timer_start, cur_time); } -#if HAVE_PTHREADS +#if HAVE_THREADS free_input_threads(); #endif /* at the end of stream, we must flush the decoder buffers */ for (i = 0; i < nb_input_streams; i++) { ist = input_streams[i]; - if (!input_files[ist->file_index]->eof_reached && ist->decoding_needed) { + if (!input_files[ist->file_index]->eof_reached) { process_input_packet(ist, NULL, 0); } } @@ -4641,11 +4643,11 @@ static int transcode(void) av_log(NULL, AV_LOG_ERROR, "Nothing was written into output file %d (%s), because " "at least one of its streams received no packets.\n", - i, os->filename); + i, os->url); continue; } if ((ret = av_write_trailer(os)) < 0) { - av_log(NULL, AV_LOG_ERROR, "Error writing trailer of %s: %s\n", os->filename, av_err2str(ret)); + av_log(NULL, AV_LOG_ERROR, "Error writing trailer of %s: %s\n", os->url, av_err2str(ret)); if (exit_on_error) exit_program(1); } @@ -4685,7 +4687,7 @@ static int transcode(void) ret = 0; fail: -#if HAVE_PTHREADS +#if HAVE_THREADS free_input_threads(); #endif @@ -4775,12 +4777,9 @@ int main(int argc, char **argv) argv++; } - avcodec_register_all(); #if CONFIG_AVDEVICE avdevice_register_all(); #endif - avfilter_register_all(); - av_register_all(); avformat_network_init(); show_banner(argc, argv, options); diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index f6c76bcc553c6..d44b7a5c72a52 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -25,10 +25,6 @@ #include #include -#if HAVE_PTHREADS -#include -#endif - #include "cmdutils.h" #include "libavformat/avformat.h" @@ -45,6 +41,7 @@ #include "libavutil/hwcontext.h" #include "libavutil/pixfmt.h" #include "libavutil/rational.h" +#include "libavutil/thread.h" #include "libavutil/threadmessage.h" #include "libswresample/swresample.h" @@ -61,14 +58,10 @@ enum HWAccelID { HWACCEL_NONE = 0, HWACCEL_AUTO, - HWACCEL_VDPAU, - HWACCEL_DXVA2, - HWACCEL_VDA, + HWACCEL_GENERIC, HWACCEL_VIDEOTOOLBOX, HWACCEL_QSV, - HWACCEL_VAAPI, HWACCEL_CUVID, - HWACCEL_D3D11VA, }; typedef struct HWAccel { @@ -76,7 +69,6 @@ typedef struct HWAccel { int (*init)(AVCodecContext *s); enum HWAccelID id; enum AVPixelFormat pix_fmt; - enum AVHWDeviceType device_type; } HWAccel; typedef struct HWDevice { @@ -161,6 +153,7 @@ typedef struct OptionsContext { float mux_preload; float mux_max_delay; int shortest; + int bitexact; int video_disable; int audio_disable; @@ -369,11 +362,11 @@ typedef struct InputStream { /* hwaccel options */ enum HWAccelID hwaccel_id; + enum AVHWDeviceType hwaccel_device_type; char *hwaccel_device; enum AVPixelFormat hwaccel_output_format; /* hwaccel context */ - enum HWAccelID active_hwaccel_id; void *hwaccel_ctx; void (*hwaccel_uninit)(AVCodecContext *s); int (*hwaccel_get_buffer)(AVCodecContext *s, AVFrame *frame, int flags); @@ -419,7 +412,7 @@ typedef struct InputFile { int rate_emu; int accurate_seek; -#if HAVE_PTHREADS +#if HAVE_THREADS AVThreadMessageQueue *in_thread_queue; pthread_t thread; /* thread reading from this file */ int non_blocking; /* reading packets from the thread should not block */ @@ -533,9 +526,6 @@ typedef struct OutputStream { int keep_pix_fmt; - AVCodecParserContext *parser; - AVCodecContext *parser_avctx; - /* stats */ // combined size of all the packets written uint64_t data_size; @@ -624,7 +614,6 @@ extern const AVIOInterruptCB int_cb; extern const OptionDef options[]; extern const HWAccel hwaccels[]; -extern int hwaccel_lax_profile_check; extern AVBufferRef *hw_device_ctx; #if CONFIG_QSV extern char *qsv_device; @@ -662,7 +651,6 @@ int ifilter_parameters_from_frame(InputFilter *ifilter, const AVFrame *frame); int ffmpeg_parse_options(int argc, char **argv); -int vda_init(AVCodecContext *s); int videotoolbox_init(AVCodecContext *s); int qsv_init(AVCodecContext *s); int cuvid_init(AVCodecContext *s); diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c index aacc185059e65..877fd670e622a 100644 --- a/fftools/ffmpeg_filter.c +++ b/fftools/ffmpeg_filter.c @@ -340,6 +340,7 @@ int init_complex_filtergraph(FilterGraph *fg) graph = avfilter_graph_alloc(); if (!graph) return AVERROR(ENOMEM); + graph->nb_threads = 1; ret = avfilter_graph_parse2(graph, fg->graph_desc, &inputs, &outputs); if (ret < 0) diff --git a/fftools/ffmpeg_hw.c b/fftools/ffmpeg_hw.c index a4d1cada591ed..2ec181385430b 100644 --- a/fftools/ffmpeg_hw.c +++ b/fftools/ffmpeg_hw.c @@ -64,6 +64,31 @@ static HWDevice *hw_device_add(void) return hw_devices[nb_hw_devices++]; } +static char *hw_device_default_name(enum AVHWDeviceType type) +{ + // Make an automatic name of the form "type%d". We arbitrarily + // limit at 1000 anonymous devices of the same type - there is + // probably something else very wrong if you get to this limit. + const char *type_name = av_hwdevice_get_type_name(type); + char *name; + size_t index_pos; + int index, index_limit = 1000; + index_pos = strlen(type_name); + name = av_malloc(index_pos + 4); + if (!name) + return NULL; + for (index = 0; index < index_limit; index++) { + snprintf(name, index_pos + 4, "%s%d", type_name, index); + if (!hw_device_get_by_name(name)) + break; + } + if (index >= index_limit) { + av_freep(&name); + return NULL; + } + return name; +} + int hw_device_init_from_string(const char *arg, HWDevice **dev_out) { // "type=name:device,key=value,key2=value2" @@ -111,27 +136,11 @@ int hw_device_init_from_string(const char *arg, HWDevice **dev_out) p += 1 + k; } else { - // Give the device an automatic name of the form "type%d". - // We arbitrarily limit at 1000 anonymous devices of the same - // type - there is probably something else very wrong if you - // get to this limit. - size_t index_pos; - int index, index_limit = 1000; - index_pos = strlen(type_name); - name = av_malloc(index_pos + 4); + name = hw_device_default_name(type); if (!name) { err = AVERROR(ENOMEM); goto fail; } - for (index = 0; index < index_limit; index++) { - snprintf(name, index_pos + 4, "%s%d", type_name, index); - if (!hw_device_get_by_name(name)) - break; - } - if (index >= index_limit) { - errmsg = "too many devices"; - goto invalid; - } } if (!*p) { @@ -214,6 +223,49 @@ int hw_device_init_from_string(const char *arg, HWDevice **dev_out) goto done; } +static int hw_device_init_from_type(enum AVHWDeviceType type, + const char *device, + HWDevice **dev_out) +{ + AVBufferRef *device_ref = NULL; + HWDevice *dev; + char *name; + int err; + + name = hw_device_default_name(type); + if (!name) { + err = AVERROR(ENOMEM); + goto fail; + } + + err = av_hwdevice_ctx_create(&device_ref, type, device, NULL, 0); + if (err < 0) { + av_log(NULL, AV_LOG_ERROR, + "Device creation failed: %d.\n", err); + goto fail; + } + + dev = hw_device_add(); + if (!dev) { + err = AVERROR(ENOMEM); + goto fail; + } + + dev->name = name; + dev->type = type; + dev->device_ref = device_ref; + + if (dev_out) + *dev_out = dev; + + return 0; + +fail: + av_freep(&name); + av_buffer_unref(&device_ref); + return err; +} + void hw_device_free_all(void) { int i; @@ -226,80 +278,130 @@ void hw_device_free_all(void) nb_hw_devices = 0; } -static enum AVHWDeviceType hw_device_match_type_by_hwaccel(enum HWAccelID hwaccel_id) +static HWDevice *hw_device_match_by_codec(const AVCodec *codec) { + const AVCodecHWConfig *config; + HWDevice *dev; int i; - if (hwaccel_id == HWACCEL_NONE) - return AV_HWDEVICE_TYPE_NONE; - for (i = 0; hwaccels[i].name; i++) { - if (hwaccels[i].id == hwaccel_id) - return hwaccels[i].device_type; + for (i = 0;; i++) { + config = avcodec_get_hw_config(codec, i); + if (!config) + return NULL; + if (!(config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX)) + continue; + dev = hw_device_get_by_type(config->device_type); + if (dev) + return dev; } - return AV_HWDEVICE_TYPE_NONE; -} - -static enum AVHWDeviceType hw_device_match_type_in_name(const char *codec_name) -{ - const char *type_name; - enum AVHWDeviceType type; - for (type = av_hwdevice_iterate_types(AV_HWDEVICE_TYPE_NONE); - type != AV_HWDEVICE_TYPE_NONE; - type = av_hwdevice_iterate_types(type)) { - type_name = av_hwdevice_get_type_name(type); - if (strstr(codec_name, type_name)) - return type; - } - return AV_HWDEVICE_TYPE_NONE; } int hw_device_setup_for_decode(InputStream *ist) { + const AVCodecHWConfig *config; enum AVHWDeviceType type; - HWDevice *dev; - int err; + HWDevice *dev = NULL; + int err, auto_device = 0; if (ist->hwaccel_device) { dev = hw_device_get_by_name(ist->hwaccel_device); if (!dev) { - char *tmp; - type = hw_device_match_type_by_hwaccel(ist->hwaccel_id); - if (type == AV_HWDEVICE_TYPE_NONE) { - // No match - this isn't necessarily invalid, though, - // because an explicit device might not be needed or - // the hwaccel setup could be handled elsewhere. + if (ist->hwaccel_id == HWACCEL_AUTO) { + auto_device = 1; + } else if (ist->hwaccel_id == HWACCEL_GENERIC) { + type = ist->hwaccel_device_type; + err = hw_device_init_from_type(type, ist->hwaccel_device, + &dev); + } else { + // This will be dealt with by API-specific initialisation + // (using hwaccel_device), so nothing further needed here. return 0; } - tmp = av_asprintf("%s:%s", av_hwdevice_get_type_name(type), - ist->hwaccel_device); - if (!tmp) - return AVERROR(ENOMEM); - err = hw_device_init_from_string(tmp, &dev); - av_free(tmp); - if (err < 0) - return err; + } else { + if (ist->hwaccel_id == HWACCEL_AUTO) { + ist->hwaccel_device_type = dev->type; + } else if (ist->hwaccel_device_type != dev->type) { + av_log(ist->dec_ctx, AV_LOG_ERROR, "Invalid hwaccel device " + "specified for decoder: device %s of type %s is not " + "usable with hwaccel %s.\n", dev->name, + av_hwdevice_get_type_name(dev->type), + av_hwdevice_get_type_name(ist->hwaccel_device_type)); + return AVERROR(EINVAL); + } } } else { - if (ist->hwaccel_id != HWACCEL_NONE) - type = hw_device_match_type_by_hwaccel(ist->hwaccel_id); - else - type = hw_device_match_type_in_name(ist->dec->name); - if (type != AV_HWDEVICE_TYPE_NONE) { + if (ist->hwaccel_id == HWACCEL_AUTO) { + auto_device = 1; + } else if (ist->hwaccel_id == HWACCEL_GENERIC) { + type = ist->hwaccel_device_type; dev = hw_device_get_by_type(type); + if (!dev) + err = hw_device_init_from_type(type, NULL, &dev); + } else { + dev = hw_device_match_by_codec(ist->dec); if (!dev) { - hw_device_init_from_string(av_hwdevice_get_type_name(type), + // No device for this codec, but not using generic hwaccel + // and therefore may well not need one - ignore. + return 0; + } + } + } + + if (auto_device) { + int i; + if (!avcodec_get_hw_config(ist->dec, 0)) { + // Decoder does not support any hardware devices. + return 0; + } + for (i = 0; !dev; i++) { + config = avcodec_get_hw_config(ist->dec, i); + if (!config) + break; + type = config->device_type; + dev = hw_device_get_by_type(type); + if (dev) { + av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto " + "hwaccel type %s with existing device %s.\n", + av_hwdevice_get_type_name(type), dev->name); + } + } + for (i = 0; !dev; i++) { + config = avcodec_get_hw_config(ist->dec, i); + if (!config) + break; + type = config->device_type; + // Try to make a new device of this type. + err = hw_device_init_from_type(type, ist->hwaccel_device, &dev); + if (err < 0) { + // Can't make a device of this type. + continue; + } + if (ist->hwaccel_device) { + av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto " + "hwaccel type %s with new device created " + "from %s.\n", av_hwdevice_get_type_name(type), + ist->hwaccel_device); + } else { + av_log(ist->dec_ctx, AV_LOG_INFO, "Using auto " + "hwaccel type %s with new default device.\n", + av_hwdevice_get_type_name(type)); } + } + if (dev) { + ist->hwaccel_device_type = type; } else { - // No device required. + av_log(ist->dec_ctx, AV_LOG_INFO, "Auto hwaccel " + "disabled: no device found.\n"); + ist->hwaccel_id = HWACCEL_NONE; return 0; } } if (!dev) { - av_log(ist->dec_ctx, AV_LOG_WARNING, "No device available " - "for decoder (device type %s for codec %s).\n", + av_log(ist->dec_ctx, AV_LOG_ERROR, "No device available " + "for decoder: device type %s needed for codec %s.\n", av_hwdevice_get_type_name(type), ist->dec->name); - return 0; + return err; } ist->dec_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref); @@ -311,24 +413,16 @@ int hw_device_setup_for_decode(InputStream *ist) int hw_device_setup_for_encode(OutputStream *ost) { - enum AVHWDeviceType type; HWDevice *dev; - type = hw_device_match_type_in_name(ost->enc->name); - if (type != AV_HWDEVICE_TYPE_NONE) { - dev = hw_device_get_by_type(type); - if (!dev) { - av_log(ost->enc_ctx, AV_LOG_WARNING, "No device available " - "for encoder (device type %s for codec %s).\n", - av_hwdevice_get_type_name(type), ost->enc->name); - return 0; - } + dev = hw_device_match_by_codec(ost->enc); + if (dev) { ost->enc_ctx->hw_device_ctx = av_buffer_ref(dev->device_ref); if (!ost->enc_ctx->hw_device_ctx) return AVERROR(ENOMEM); return 0; } else { - // No device required. + // No device required, or no device available. return 0; } } diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index 100fa76e46f29..d7a7eb0662806 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -66,41 +66,17 @@ } const HWAccel hwaccels[] = { -#if HAVE_VDPAU_X11 - { "vdpau", hwaccel_decode_init, HWACCEL_VDPAU, AV_PIX_FMT_VDPAU, - AV_HWDEVICE_TYPE_VDPAU }, -#endif -#if CONFIG_D3D11VA - { "d3d11va", hwaccel_decode_init, HWACCEL_D3D11VA, AV_PIX_FMT_D3D11, - AV_HWDEVICE_TYPE_D3D11VA }, -#endif -#if CONFIG_DXVA2 - { "dxva2", hwaccel_decode_init, HWACCEL_DXVA2, AV_PIX_FMT_DXVA2_VLD, - AV_HWDEVICE_TYPE_DXVA2 }, -#endif -#if CONFIG_VDA - { "vda", videotoolbox_init, HWACCEL_VDA, AV_PIX_FMT_VDA, - AV_HWDEVICE_TYPE_NONE }, -#endif #if CONFIG_VIDEOTOOLBOX - { "videotoolbox", videotoolbox_init, HWACCEL_VIDEOTOOLBOX, AV_PIX_FMT_VIDEOTOOLBOX, - AV_HWDEVICE_TYPE_NONE }, + { "videotoolbox", videotoolbox_init, HWACCEL_VIDEOTOOLBOX, AV_PIX_FMT_VIDEOTOOLBOX }, #endif #if CONFIG_LIBMFX - { "qsv", qsv_init, HWACCEL_QSV, AV_PIX_FMT_QSV, - AV_HWDEVICE_TYPE_NONE }, -#endif -#if CONFIG_VAAPI - { "vaapi", hwaccel_decode_init, HWACCEL_VAAPI, AV_PIX_FMT_VAAPI, - AV_HWDEVICE_TYPE_VAAPI }, + { "qsv", qsv_init, HWACCEL_QSV, AV_PIX_FMT_QSV }, #endif #if CONFIG_CUVID - { "cuvid", cuvid_init, HWACCEL_CUVID, AV_PIX_FMT_CUDA, - AV_HWDEVICE_TYPE_NONE }, + { "cuvid", cuvid_init, HWACCEL_CUVID, AV_PIX_FMT_CUDA }, #endif { 0 }, }; -int hwaccel_lax_profile_check = 0; AVBufferRef *hw_device_ctx; HWDevice *filter_hw_device; @@ -141,7 +117,6 @@ static int file_overwrite = 0; static int no_file_overwrite = 0; static int do_psnr = 0; static int input_sync; -static int override_ffserver = 0; static int input_stream_potentially_available = 0; static int ignore_unknown_streams = 0; static int copy_unknown_streams = 0; @@ -195,12 +170,15 @@ static void init_options(OptionsContext *o) static int show_hwaccels(void *optctx, const char *opt, const char *arg) { + enum AVHWDeviceType type = AV_HWDEVICE_TYPE_NONE; int i; printf("Hardware acceleration methods:\n"); - for (i = 0; hwaccels[i].name; i++) { + while ((type = av_hwdevice_iterate_types(type)) != + AV_HWDEVICE_TYPE_NONE) + printf("%s\n", av_hwdevice_get_type_name(type)); + for (i = 0; hwaccels[i].name; i++) printf("%s\n", hwaccels[i].name); - } printf("\n"); return 0; } @@ -723,7 +701,8 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic) AVStream *st = ic->streams[i]; AVCodecParameters *par = st->codecpar; InputStream *ist = av_mallocz(sizeof(*ist)); - char *framerate = NULL, *hwaccel = NULL, *hwaccel_device = NULL; + char *framerate = NULL, *hwaccel_device = NULL; + const char *hwaccel = NULL; char *hwaccel_output_format = NULL; char *codec_tag = NULL; char *next; @@ -787,20 +766,20 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic) exit_program(1); } + if (o->bitexact) + ist->dec_ctx->flags |= AV_CODEC_FLAG_BITEXACT; + switch (par->codec_type) { case AVMEDIA_TYPE_VIDEO: if(!ist->dec) ist->dec = avcodec_find_decoder(par->codec_id); #if FF_API_LOWRES - if (av_codec_get_lowres(st->codec)) { - av_codec_set_lowres(ist->dec_ctx, av_codec_get_lowres(st->codec)); + if (st->codec->lowres) { + ist->dec_ctx->lowres = st->codec->lowres; ist->dec_ctx->width = st->codec->width; ist->dec_ctx->height = st->codec->height; ist->dec_ctx->coded_width = st->codec->coded_width; ist->dec_ctx->coded_height = st->codec->coded_height; -#if FF_API_EMU_EDGE - ist->dec_ctx->flags |= CODEC_FLAG_EMU_EDGE; -#endif } #endif @@ -820,11 +799,16 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic) MATCH_PER_STREAM_OPT(hwaccels, str, hwaccel, ic, st); if (hwaccel) { + // The NVDEC hwaccels use a CUDA device, so remap the name here. + if (!strcmp(hwaccel, "nvdec")) + hwaccel = "cuda"; + if (!strcmp(hwaccel, "none")) ist->hwaccel_id = HWACCEL_NONE; else if (!strcmp(hwaccel, "auto")) ist->hwaccel_id = HWACCEL_AUTO; else { + enum AVHWDeviceType type; int i; for (i = 0; hwaccels[i].name; i++) { if (!strcmp(hwaccels[i].name, hwaccel)) { @@ -833,10 +817,23 @@ static void add_input_streams(OptionsContext *o, AVFormatContext *ic) } } + if (!ist->hwaccel_id) { + type = av_hwdevice_find_type_by_name(hwaccel); + if (type != AV_HWDEVICE_TYPE_NONE) { + ist->hwaccel_id = HWACCEL_GENERIC; + ist->hwaccel_device_type = type; + } + } + if (!ist->hwaccel_id) { av_log(NULL, AV_LOG_FATAL, "Unrecognized hwaccel: %s.\n", hwaccel); av_log(NULL, AV_LOG_FATAL, "Supported hwaccels: "); + type = AV_HWDEVICE_TYPE_NONE; + while ((type = av_hwdevice_iterate_types(type)) != + AV_HWDEVICE_TYPE_NONE) + av_log(NULL, AV_LOG_FATAL, "%s ", + av_hwdevice_get_type_name(type)); for (i = 0; hwaccels[i].name; i++) av_log(NULL, AV_LOG_FATAL, "%s ", hwaccels[i].name); av_log(NULL, AV_LOG_FATAL, "\n"); @@ -977,6 +974,21 @@ static int open_input_file(OptionsContext *o, const char *filename) char * data_codec_name = NULL; int scan_all_pmts_set = 0; + if (o->stop_time != INT64_MAX && o->recording_time != INT64_MAX) { + o->stop_time = INT64_MAX; + av_log(NULL, AV_LOG_WARNING, "-t and -to cannot be used together; using -t.\n"); + } + + if (o->stop_time != INT64_MAX && o->recording_time == INT64_MAX) { + int64_t start_time = o->start_time == AV_NOPTS_VALUE ? 0 : o->start_time; + if (o->stop_time <= start_time) { + av_log(NULL, AV_LOG_ERROR, "-to value smaller than -ss; aborting.\n"); + exit_program(1); + } else { + o->recording_time = o->stop_time - start_time; + } + } + if (o->format) { if (!(file_iformat = av_find_input_format(o->format))) { av_log(NULL, AV_LOG_FATAL, "Unknown input format: '%s'\n", o->format); @@ -996,7 +1008,6 @@ static int open_input_file(OptionsContext *o, const char *filename) print_error(filename, AVERROR(ENOMEM)); exit_program(1); } - ic->flags |= AVFMT_FLAG_KEEP_SIDE_DATA; if (o->nb_audio_sample_rate) { av_dict_set_int(&o->g->format_opts, "sample_rate", o->audio_sample_rate[o->nb_audio_sample_rate - 1].u.i, 0); } @@ -1031,25 +1042,23 @@ static int open_input_file(OptionsContext *o, const char *filename) MATCH_PER_TYPE_OPT(codec_names, str, subtitle_codec_name, ic, "s"); MATCH_PER_TYPE_OPT(codec_names, str, data_codec_name, ic, "d"); - ic->video_codec_id = video_codec_name ? - find_codec_or_die(video_codec_name , AVMEDIA_TYPE_VIDEO , 0)->id : AV_CODEC_ID_NONE; - ic->audio_codec_id = audio_codec_name ? - find_codec_or_die(audio_codec_name , AVMEDIA_TYPE_AUDIO , 0)->id : AV_CODEC_ID_NONE; - ic->subtitle_codec_id= subtitle_codec_name ? - find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0)->id : AV_CODEC_ID_NONE; - ic->data_codec_id = data_codec_name ? - find_codec_or_die(data_codec_name, AVMEDIA_TYPE_DATA, 0)->id : AV_CODEC_ID_NONE; - if (video_codec_name) - av_format_set_video_codec (ic, find_codec_or_die(video_codec_name , AVMEDIA_TYPE_VIDEO , 0)); + ic->video_codec = find_codec_or_die(video_codec_name , AVMEDIA_TYPE_VIDEO , 0); if (audio_codec_name) - av_format_set_audio_codec (ic, find_codec_or_die(audio_codec_name , AVMEDIA_TYPE_AUDIO , 0)); + ic->audio_codec = find_codec_or_die(audio_codec_name , AVMEDIA_TYPE_AUDIO , 0); if (subtitle_codec_name) - av_format_set_subtitle_codec(ic, find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0)); + ic->subtitle_codec = find_codec_or_die(subtitle_codec_name, AVMEDIA_TYPE_SUBTITLE, 0); if (data_codec_name) - av_format_set_data_codec(ic, find_codec_or_die(data_codec_name, AVMEDIA_TYPE_DATA, 0)); + ic->data_codec = find_codec_or_die(data_codec_name , AVMEDIA_TYPE_DATA , 0); + + ic->video_codec_id = video_codec_name ? ic->video_codec->id : AV_CODEC_ID_NONE; + ic->audio_codec_id = audio_codec_name ? ic->audio_codec->id : AV_CODEC_ID_NONE; + ic->subtitle_codec_id = subtitle_codec_name ? ic->subtitle_codec->id : AV_CODEC_ID_NONE; + ic->data_codec_id = data_codec_name ? ic->data_codec->id : AV_CODEC_ID_NONE; ic->flags |= AVFMT_FLAG_NONBLOCK; + if (o->bitexact) + ic->flags |= AVFMT_FLAG_BITEXACT; ic->interrupt_callback = int_cb; if (!av_dict_get(o->g->format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) { @@ -1151,7 +1160,7 @@ static int open_input_file(OptionsContext *o, const char *filename) f->loop = o->loop; f->duration = 0; f->time_base = (AVRational){ 1, 1 }; -#if HAVE_PTHREADS +#if HAVE_THREADS f->thread_queue_size = o->thread_queue_size > 0 ? o->thread_queue_size : 8; #endif @@ -1262,7 +1271,7 @@ static int choose_encoder(OptionsContext *o, AVFormatContext *s, OutputStream *o if (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO || type == AVMEDIA_TYPE_SUBTITLE) { MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, ost->st); if (!codec_name) { - ost->st->codecpar->codec_id = av_guess_codec(s->oformat, NULL, s->filename, + ost->st->codecpar->codec_id = av_guess_codec(s->oformat, NULL, s->url, NULL, ost->st->codecpar->codec_type); ost->enc = avcodec_find_encoder(ost->st->codecpar->codec_id); if (!ost->enc) { @@ -1371,6 +1380,10 @@ static OutputStream *new_output_stream(OptionsContext *o, AVFormatContext *oc, e ost->encoder_opts = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, NULL); } + + if (o->bitexact) + ost->enc_ctx->flags |= AV_CODEC_FLAG_BITEXACT; + MATCH_PER_STREAM_OPT(time_bases, str, time_base, oc, st); if (time_base) { AVRational q; @@ -1663,7 +1676,7 @@ static OutputStream *new_video_stream(OptionsContext *o, AVFormatContext *oc, in av_log(NULL, AV_LOG_FATAL, "Could not allocate memory for intra matrix.\n"); exit_program(1); } - av_codec_set_chroma_intra_matrix(video_enc, p); + video_enc->chroma_intra_matrix = p; parse_matrix_coeffs(p, chroma_intra_matrix); } MATCH_PER_STREAM_OPT(inter_matrices, str, inter_matrix, oc, st); @@ -1983,57 +1996,6 @@ static int copy_chapters(InputFile *ifile, OutputFile *ofile, int copy_metadata) return 0; } -static int read_ffserver_streams(OptionsContext *o, AVFormatContext *s, const char *filename) -{ - int i, err; - AVFormatContext *ic = avformat_alloc_context(); - - ic->flags |= AVFMT_FLAG_KEEP_SIDE_DATA; - ic->interrupt_callback = int_cb; - err = avformat_open_input(&ic, filename, NULL, NULL); - if (err < 0) - return err; - /* copy stream format */ - for(i=0;inb_streams;i++) { - AVStream *st; - OutputStream *ost; - AVCodec *codec; - const char *enc_config; - - codec = avcodec_find_encoder(ic->streams[i]->codecpar->codec_id); - if (!codec) { - av_log(s, AV_LOG_ERROR, "no encoder found for codec id %i\n", ic->streams[i]->codecpar->codec_id); - return AVERROR(EINVAL); - } - if (codec->type == AVMEDIA_TYPE_AUDIO) - opt_audio_codec(o, "c:a", codec->name); - else if (codec->type == AVMEDIA_TYPE_VIDEO) - opt_video_codec(o, "c:v", codec->name); - ost = new_output_stream(o, s, codec->type, -1); - st = ost->st; - - avcodec_get_context_defaults3(st->codec, codec); - enc_config = av_stream_get_recommended_encoder_configuration(ic->streams[i]); - if (enc_config) { - AVDictionary *opts = NULL; - av_dict_parse_string(&opts, enc_config, "=", ",", 0); - av_opt_set_dict2(st->codec, &opts, AV_OPT_SEARCH_CHILDREN); - av_dict_free(&opts); - } - - if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && !ost->stream_copy) - choose_sample_fmt(st, codec); - else if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && !ost->stream_copy) - choose_pixel_fmt(st, st->codec, codec, st->codecpar->format); - avcodec_copy_context(ost->enc_ctx, st->codec); - if (enc_config) - av_dict_parse_string(&ost->encoder_opts, enc_config, "=", ",", 0); - } - - avformat_close_input(&ic); - return err; -} - static void init_output_filter(OutputFilter *ofilter, OptionsContext *o, AVFormatContext *oc) { @@ -2092,7 +2054,6 @@ static int open_output_file(OptionsContext *o, const char *filename) { AVFormatContext *oc; int i, j, err; - AVOutputFormat *file_oformat; OutputFile *of; OutputStream *ost; InputStream *ist; @@ -2141,7 +2102,6 @@ static int open_output_file(OptionsContext *o, const char *filename) if (o->recording_time != INT64_MAX) oc->duration = o->recording_time; - file_oformat= oc->oformat; oc->interrupt_callback = int_cb; e = av_dict_get(o->g->format_opts, "fflags", NULL, 0); @@ -2149,6 +2109,10 @@ static int open_output_file(OptionsContext *o, const char *filename) const AVOption *o = av_opt_find(oc, "fflags", NULL, 0, 0); av_opt_eval_flags(oc, o, e->value, &format_flags); } + if (o->bitexact) { + format_flags |= AVFMT_FLAG_BITEXACT; + oc->flags |= AVFMT_FLAG_BITEXACT; + } /* create streams for all unlabeled output pads */ for (i = 0; i < nb_filtergraphs; i++) { @@ -2168,47 +2132,7 @@ static int open_output_file(OptionsContext *o, const char *filename) } } - /* ffserver seeking with date=... needs a date reference */ - if (!strcmp(file_oformat->name, "ffm") && - !(format_flags & AVFMT_FLAG_BITEXACT) && - av_strstart(filename, "http:", NULL)) { - int err = parse_option(o, "metadata", "creation_time=now", options); - if (err < 0) { - print_error(filename, err); - exit_program(1); - } - } - - if (!strcmp(file_oformat->name, "ffm") && !override_ffserver && - av_strstart(filename, "http:", NULL)) { - int j; - /* special case for files sent to ffserver: we get the stream - parameters from ffserver */ - int err = read_ffserver_streams(o, oc, filename); - if (err < 0) { - print_error(filename, err); - exit_program(1); - } - for(j = nb_output_streams - oc->nb_streams; j < nb_output_streams; j++) { - ost = output_streams[j]; - for (i = 0; i < nb_input_streams; i++) { - ist = input_streams[i]; - if(ist->st->codecpar->codec_type == ost->st->codecpar->codec_type){ - ost->sync_ist= ist; - ost->source_index= i; - if(ost->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) ost->avfilter = av_strdup("anull"); - if(ost->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) ost->avfilter = av_strdup("null"); - ist->discard = 0; - ist->st->discard = ist->user_set_discard; - break; - } - } - if(!ost->sync_ist){ - av_log(NULL, AV_LOG_FATAL, "Missing %s stream which is required by this ffm\n", av_get_media_type_string(ost->st->codecpar->codec_type)); - exit_program(1); - } - } - } else if (!o->nb_stream_maps) { + if (!o->nb_stream_maps) { char *subtitle_codec_name = NULL; /* pick the "best" stream of each type */ @@ -2410,7 +2334,7 @@ static int open_output_file(OptionsContext *o, const char *filename) #endif if (!oc->nb_streams && !(oc->oformat->flags & AVFMT_NOSTREAMS)) { - av_dump_format(oc, nb_output_files - 1, oc->filename, 1); + av_dump_format(oc, nb_output_files - 1, oc->url, 1); av_log(NULL, AV_LOG_ERROR, "Output file #%d does not contain any stream\n", nb_output_files - 1); exit_program(1); } @@ -2542,8 +2466,8 @@ static int open_output_file(OptionsContext *o, const char *filename) /* check filename in case of an image number is expected */ if (oc->oformat->flags & AVFMT_NEEDNUMBER) { - if (!av_filename_number_test(oc->filename)) { - print_error(oc->filename, AVERROR(EINVAL)); + if (!av_filename_number_test(oc->url)) { + print_error(oc->url, AVERROR(EINVAL)); exit_program(1); } } @@ -3190,7 +3114,7 @@ void show_help_default(const char *opt, const char *arg) " -h -- print basic options\n" " -h long -- print more options\n" " -h full -- print all options (including all format and codec specific options, very long)\n" - " -h type=name -- print all options for the named decoder/encoder/demuxer/muxer/filter\n" + " -h type=name -- print all options for the named decoder/encoder/demuxer/muxer/filter/bsf\n" " See man %s for detailed description of the options.\n" "\n", program_name); @@ -3235,6 +3159,7 @@ void show_help_default(const char *opt, const char *arg) #endif show_help_children(swr_get_class(), AV_OPT_FLAG_AUDIO_PARAM); show_help_children(avfilter_get_class(), AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM); + show_help_children(av_bsf_get_class(), AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_BSF_PARAM); } } @@ -3404,7 +3329,7 @@ const OptionDef options[] = { OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(recording_time) }, "record or transcode \"duration\" seconds of audio/video", "duration" }, - { "to", HAS_ARG | OPT_TIME | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(stop_time) }, + { "to", HAS_ARG | OPT_TIME | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(stop_time) }, "record or transcode stop time", "time_stop" }, { "fs", HAS_ARG | OPT_INT64 | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(limit_filesize) }, "set the limit file size in bytes", "limit_size" }, @@ -3472,6 +3397,9 @@ const OptionDef options[] = { { "shortest", OPT_BOOL | OPT_EXPERT | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(shortest) }, "finish encoding within shortest input" }, + { "bitexact", OPT_BOOL | OPT_EXPERT | OPT_OFFSET | + OPT_OUTPUT | OPT_INPUT, { .off = OFFSET(bitexact) }, + "bitexact mode" }, { "apad", OPT_STRING | HAS_ARG | OPT_SPEC | OPT_OUTPUT, { .off = OFFSET(apad) }, "audio pad", "" }, @@ -3530,7 +3458,7 @@ const OptionDef options[] = { { "debug_ts", OPT_BOOL | OPT_EXPERT, { &debug_ts }, "print timestamp debugging info" }, { "max_error_rate", HAS_ARG | OPT_FLOAT, { &max_error_rate }, - "maximum error rate", "ratio of errors (0.0: no errors, 1.0: 100% errors) above which ffmpeg returns an error instead of success." }, + "ratio of errors (0.0: no errors, 1.0: 100% errors) above which ffmpeg returns an error instead of success.", "maximum error rate" }, { "discard", OPT_STRING | HAS_ARG | OPT_SPEC | OPT_INPUT, { .off = OFFSET(discard) }, "discard", "" }, @@ -3632,7 +3560,7 @@ const OptionDef options[] = { { "hwaccel_output_format", OPT_VIDEO | OPT_STRING | HAS_ARG | OPT_EXPERT | OPT_SPEC | OPT_INPUT, { .off = OFFSET(hwaccel_output_formats) }, "select output format used with HW accelerated decoding", "format" }, -#if CONFIG_VDA || CONFIG_VIDEOTOOLBOX +#if CONFIG_VIDEOTOOLBOX { "videotoolbox_pixfmt", HAS_ARG | OPT_STRING | OPT_EXPERT, { &videotoolbox_pixfmt}, "" }, #endif { "hwaccels", OPT_EXIT, { .func_arg = show_hwaccels }, @@ -3640,8 +3568,6 @@ const OptionDef options[] = { { "autorotate", HAS_ARG | OPT_BOOL | OPT_SPEC | OPT_EXPERT | OPT_INPUT, { .off = OFFSET(autorotate) }, "automatically insert correct rotate filters" }, - { "hwaccel_lax_profile_check", OPT_BOOL | OPT_EXPERT, { &hwaccel_lax_profile_check}, - "attempt to decode anyway if HW accelerated decoder's supported profiles do not exactly match the stream" }, /* audio options */ { "aframes", OPT_AUDIO | HAS_ARG | OPT_PERFILE | OPT_OUTPUT, { .func_arg = opt_audio_frames }, @@ -3699,8 +3625,6 @@ const OptionDef options[] = { "set the maximum demux-decode delay", "seconds" }, { "muxpreload", OPT_FLOAT | HAS_ARG | OPT_EXPERT | OPT_OFFSET | OPT_OUTPUT, { .off = OFFSET(mux_preload) }, "set the initial demux-decode delay", "seconds" }, - { "override_ffserver", OPT_BOOL | OPT_EXPERT | OPT_OUTPUT, { &override_ffserver }, - "override the options from ffserver", "" }, { "sdp_file", HAS_ARG | OPT_EXPERT | OPT_OUTPUT, { .func_arg = opt_sdp_file }, "specify a file in which to print sdp information", "file" }, diff --git a/fftools/ffmpeg_videotoolbox.c b/fftools/ffmpeg_videotoolbox.c index e9039654b93de..b820aec017f7d 100644 --- a/fftools/ffmpeg_videotoolbox.c +++ b/fftools/ffmpeg_videotoolbox.c @@ -23,12 +23,7 @@ #endif #include "libavcodec/avcodec.h" -#if CONFIG_VDA -# include "libavcodec/vda.h" -#endif -#if CONFIG_VIDEOTOOLBOX -# include "libavcodec/videotoolbox.h" -#endif +#include "libavcodec/videotoolbox.h" #include "libavutil/imgutils.h" #include "ffmpeg.h" @@ -114,15 +109,7 @@ static void videotoolbox_uninit(AVCodecContext *s) av_frame_free(&vt->tmp_frame); - if (ist->hwaccel_id == HWACCEL_VIDEOTOOLBOX) { -#if CONFIG_VIDEOTOOLBOX - av_videotoolbox_default_free(s); -#endif - } else { -#if CONFIG_VDA - av_vda_default_free(s); -#endif - } + av_videotoolbox_default_free(s); av_freep(&ist->hwaccel_ctx); } @@ -147,8 +134,7 @@ int videotoolbox_init(AVCodecContext *s) goto fail; } - if (ist->hwaccel_id == HWACCEL_VIDEOTOOLBOX) { -#if CONFIG_VIDEOTOOLBOX + // TODO: reindent if (!videotoolbox_pixfmt) { ret = av_videotoolbox_default_init(s); } else { @@ -166,31 +152,8 @@ int videotoolbox_init(AVCodecContext *s) ret = av_videotoolbox_default_init2(s, vtctx); CFRelease(pixfmt_str); } -#endif - } else { -#if CONFIG_VDA - if (!videotoolbox_pixfmt) { - ret = av_vda_default_init(s); - } else { - AVVDAContext *vdactx = av_vda_alloc_context(); - CFStringRef pixfmt_str = CFStringCreateWithCString(kCFAllocatorDefault, - videotoolbox_pixfmt, - kCFStringEncodingUTF8); -#if HAVE_UTGETOSTYPEFROMSTRING - vdactx->cv_pix_fmt_type = UTGetOSTypeFromString(pixfmt_str); -#else - av_log(s, loglevel, "UTGetOSTypeFromString() is not available " - "on this platform, %s pixel format can not be honored from " - "the command line\n", videotoolbox_pixfmt); -#endif - ret = av_vda_default_init2(s, vdactx); - CFRelease(pixfmt_str); - } -#endif - } if (ret < 0) { - av_log(NULL, loglevel, - "Error creating %s decoder.\n", ist->hwaccel_id == HWACCEL_VIDEOTOOLBOX ? "Videotoolbox" : "VDA"); + av_log(NULL, loglevel, "Error creating Videotoolbox decoder.\n"); goto fail; } diff --git a/fftools/ffplay.c b/fftools/ffplay.c index 9f7774613c20a..bc9ddb8885c9e 100644 --- a/fftools/ffplay.c +++ b/fftools/ffplay.c @@ -361,6 +361,8 @@ static AVPacket flush_pkt; static SDL_Window *window; static SDL_Renderer *renderer; +static SDL_RendererInfo renderer_info = {0}; +static SDL_AudioDeviceID audio_dev; static const struct TextureFormatEntry { enum AVPixelFormat format; @@ -607,7 +609,7 @@ static int decoder_decode_frame(Decoder *d, AVFrame *frame, AVSubtitle *sub) { if (ret >= 0) { AVRational tb = (AVRational){1, frame->sample_rate}; if (frame->pts != AV_NOPTS_VALUE) - frame->pts = av_rescale_q(frame->pts, av_codec_get_pkt_timebase(d->avctx), tb); + frame->pts = av_rescale_q(frame->pts, d->avctx->pkt_timebase, tb); else if (d->next_pts != AV_NOPTS_VALUE) frame->pts = av_rescale_q(d->next_pts, d->next_pts_tb, tb); if (frame->pts != AV_NOPTS_VALUE) { @@ -1191,7 +1193,7 @@ static void stream_component_close(VideoState *is, int stream_index) switch (codecpar->codec_type) { case AVMEDIA_TYPE_AUDIO: decoder_abort(&is->auddec, &is->sampq); - SDL_CloseAudio(); + SDL_CloseAudioDevice(audio_dev); decoder_destroy(&is->auddec); swr_free(&is->swr_ctx); av_freep(&is->audio_buf1); @@ -1282,7 +1284,6 @@ static void do_exit(VideoState *is) SDL_DestroyRenderer(renderer); if (window) SDL_DestroyWindow(window); - av_lockmgr_register(NULL); uninit_opts(); #if CONFIG_AVFILTER av_freep(&vfilters_list); @@ -1320,38 +1321,15 @@ static int video_open(VideoState *is) h = default_height; } - if (!window) { - int flags = SDL_WINDOW_SHOWN; - if (!window_title) - window_title = input_filename; - if (is_full_screen) - flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; - if (borderless) - flags |= SDL_WINDOW_BORDERLESS; - else - flags |= SDL_WINDOW_RESIZABLE; - window = SDL_CreateWindow(window_title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w, h, flags); - SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); - if (window) { - SDL_RendererInfo info; - renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); - if (!renderer) { - av_log(NULL, AV_LOG_WARNING, "Failed to initialize a hardware accelerated renderer: %s\n", SDL_GetError()); - renderer = SDL_CreateRenderer(window, -1, 0); - } - if (renderer) { - if (!SDL_GetRendererInfo(renderer, &info)) - av_log(NULL, AV_LOG_VERBOSE, "Initialized %s renderer.\n", info.name); - } - } - } else { - SDL_SetWindowSize(window, w, h); - } + if (!window_title) + window_title = input_filename; + SDL_SetWindowTitle(window, window_title); - if (!window || !renderer) { - av_log(NULL, AV_LOG_FATAL, "SDL: could not set video mode - exiting\n"); - do_exit(is); - } + SDL_SetWindowSize(window, w, h); + SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); + if (is_full_screen) + SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP); + SDL_ShowWindow(window); is->width = w; is->height = h; @@ -1362,7 +1340,7 @@ static int video_open(VideoState *is) /* display the current picture, if any */ static void video_display(VideoState *is) { - if (!window) + if (!is->width) video_open(is); SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); @@ -1850,10 +1828,18 @@ static int configure_video_filters(AVFilterGraph *graph, VideoState *is, const c AVCodecParameters *codecpar = is->video_st->codecpar; AVRational fr = av_guess_frame_rate(is->ic, is->video_st, NULL); AVDictionaryEntry *e = NULL; - int i; + int nb_pix_fmts = 0; + int i, j; - for (i = 0; i < FF_ARRAY_ELEMS(pix_fmts); i++) - pix_fmts[i] = sdl_texture_format_map[i].format; + for (i = 0; i < renderer_info.num_texture_formats; i++) { + for (j = 0; j < FF_ARRAY_ELEMS(sdl_texture_format_map) - 1; j++) { + if (renderer_info.texture_formats[i] == sdl_texture_format_map[j].texture_fmt) { + pix_fmts[nb_pix_fmts++] = sdl_texture_format_map[j].format; + break; + } + } + } + pix_fmts[nb_pix_fmts] = AV_PIX_FMT_NONE; while ((e = av_dict_get(sws_dict, "", e, AV_DICT_IGNORE_SUFFIX))) { if (!strcmp(e->key, "sws_flags")) { @@ -2465,7 +2451,7 @@ static void sdl_audio_callback(void *opaque, Uint8 *stream, int len) else { memset(stream, 0, len1); if (!is->muted && is->audio_buf) - SDL_MixAudio(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, len1, is->audio_volume); + SDL_MixAudioFormat(stream, (uint8_t *)is->audio_buf + is->audio_buf_index, AUDIO_S16SYS, len1, is->audio_volume); } len -= len1; stream += len1; @@ -2510,7 +2496,7 @@ static int audio_open(void *opaque, int64_t wanted_channel_layout, int wanted_nb wanted_spec.samples = FFMAX(SDL_AUDIO_MIN_BUFFER_SIZE, 2 << av_log2(wanted_spec.freq / SDL_AUDIO_MAX_CALLBACKS_PER_SEC)); wanted_spec.callback = sdl_audio_callback; wanted_spec.userdata = opaque; - while (SDL_OpenAudio(&wanted_spec, &spec) < 0) { + while (!(audio_dev = SDL_OpenAudioDevice(NULL, 0, &wanted_spec, &spec, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE | SDL_AUDIO_ALLOW_CHANNELS_CHANGE))) { av_log(NULL, AV_LOG_WARNING, "SDL_OpenAudio (%d channels, %d Hz): %s\n", wanted_spec.channels, wanted_spec.freq, SDL_GetError()); wanted_spec.channels = next_nb_channels[FFMIN(7, wanted_spec.channels)]; @@ -2576,7 +2562,7 @@ static int stream_component_open(VideoState *is, int stream_index) ret = avcodec_parameters_to_context(avctx, ic->streams[stream_index]->codecpar); if (ret < 0) goto fail; - av_codec_set_pkt_timebase(avctx, ic->streams[stream_index]->time_base); + avctx->pkt_timebase = ic->streams[stream_index]->time_base; codec = avcodec_find_decoder(avctx->codec_id); @@ -2597,22 +2583,15 @@ static int stream_component_open(VideoState *is, int stream_index) } avctx->codec_id = codec->id; - if(stream_lowres > av_codec_get_max_lowres(codec)){ + if (stream_lowres > codec->max_lowres) { av_log(avctx, AV_LOG_WARNING, "The maximum value for lowres supported by the decoder is %d\n", - av_codec_get_max_lowres(codec)); - stream_lowres = av_codec_get_max_lowres(codec); + codec->max_lowres); + stream_lowres = codec->max_lowres; } - av_codec_set_lowres(avctx, stream_lowres); + avctx->lowres = stream_lowres; -#if FF_API_EMU_EDGE - if(stream_lowres) avctx->flags |= CODEC_FLAG_EMU_EDGE; -#endif if (fast) avctx->flags2 |= AV_CODEC_FLAG2_FAST; -#if FF_API_EMU_EDGE - if(codec->capabilities & AV_CODEC_CAP_DR1) - avctx->flags |= CODEC_FLAG_EMU_EDGE; -#endif opts = filter_codec_opts(codec_opts, avctx->codec_id, ic, ic->streams[stream_index], codec); if (!av_dict_get(opts, "threads", NULL, 0)) @@ -2680,7 +2659,7 @@ static int stream_component_open(VideoState *is, int stream_index) } if ((ret = decoder_start(&is->auddec, audio_thread, is)) < 0) goto out; - SDL_PauseAudio(0); + SDL_PauseAudioDevice(audio_dev, 0); break; case AVMEDIA_TYPE_VIDEO: is->video_stream = stream_index; @@ -2733,8 +2712,8 @@ static int is_realtime(AVFormatContext *s) ) return 1; - if(s->pb && ( !strncmp(s->filename, "rtp:", 4) - || !strncmp(s->filename, "udp:", 4) + if(s->pb && ( !strncmp(s->url, "rtp:", 4) + || !strncmp(s->url, "udp:", 4) ) ) return 1; @@ -2949,7 +2928,7 @@ static int read_thread(void *arg) ret = avformat_seek_file(is->ic, -1, seek_min, seek_target, seek_max, is->seek_flags); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, - "%s: error while seeking\n", is->ic->filename); + "%s: error while seeking\n", is->ic->url); } else { if (is->audio_stream >= 0) { packet_queue_flush(&is->audioq); @@ -3661,27 +3640,6 @@ void show_help_default(const char *opt, const char *arg) ); } -static int lockmgr(void **mtx, enum AVLockOp op) -{ - switch(op) { - case AV_LOCK_CREATE: - *mtx = SDL_CreateMutex(); - if(!*mtx) { - av_log(NULL, AV_LOG_FATAL, "SDL_CreateMutex(): %s\n", SDL_GetError()); - return 1; - } - return 0; - case AV_LOCK_OBTAIN: - return !!SDL_LockMutex(*mtx); - case AV_LOCK_RELEASE: - return !!SDL_UnlockMutex(*mtx); - case AV_LOCK_DESTROY: - SDL_DestroyMutex(*mtx); - return 0; - } - return 1; -} - /* Called from the main */ int main(int argc, char **argv) { @@ -3697,10 +3655,6 @@ int main(int argc, char **argv) #if CONFIG_AVDEVICE avdevice_register_all(); #endif -#if CONFIG_AVFILTER - avfilter_register_all(); -#endif - av_register_all(); avformat_network_init(); init_opts(); @@ -3743,14 +3697,34 @@ int main(int argc, char **argv) SDL_EventState(SDL_SYSWMEVENT, SDL_IGNORE); SDL_EventState(SDL_USEREVENT, SDL_IGNORE); - if (av_lockmgr_register(lockmgr)) { - av_log(NULL, AV_LOG_FATAL, "Could not initialize lock manager!\n"); - do_exit(NULL); - } - av_init_packet(&flush_pkt); flush_pkt.data = (uint8_t *)&flush_pkt; + if (!display_disable) { + int flags = SDL_WINDOW_HIDDEN; + if (borderless) + flags |= SDL_WINDOW_BORDERLESS; + else + flags |= SDL_WINDOW_RESIZABLE; + window = SDL_CreateWindow(program_name, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, default_width, default_height, flags); + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); + if (window) { + renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); + if (!renderer) { + av_log(NULL, AV_LOG_WARNING, "Failed to initialize a hardware accelerated renderer: %s\n", SDL_GetError()); + renderer = SDL_CreateRenderer(window, -1, 0); + } + if (renderer) { + if (!SDL_GetRendererInfo(renderer, &renderer_info)) + av_log(NULL, AV_LOG_VERBOSE, "Initialized %s renderer.\n", renderer_info.name); + } + } + if (!window || !renderer || !renderer_info.num_texture_formats) { + av_log(NULL, AV_LOG_FATAL, "Failed to create window or renderer: %s", SDL_GetError()); + do_exit(NULL); + } + } + is = stream_open(input_filename, file_iformat); if (!is) { av_log(NULL, AV_LOG_FATAL, "Failed to initialize VideoState!\n"); diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c index b2e8949d9f909..8b2a18b6b12b0 100644 --- a/fftools/ffprobe.c +++ b/fftools/ffprobe.c @@ -2275,7 +2275,8 @@ static av_always_inline int process_frame(WriterContext *w, break; case AVMEDIA_TYPE_SUBTITLE: - ret = avcodec_decode_subtitle2(dec_ctx, &sub, &got_frame, pkt); + if (*packet_new) + ret = avcodec_decode_subtitle2(dec_ctx, &sub, &got_frame, pkt); *packet_new = 0; break; default: @@ -2512,13 +2513,15 @@ static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id case AVMEDIA_TYPE_VIDEO: print_int("width", par->width); print_int("height", par->height); +#if FF_API_LAVF_AVCTX if (dec_ctx) { print_int("coded_width", dec_ctx->coded_width); print_int("coded_height", dec_ctx->coded_height); } +#endif print_int("has_b_frames", par->video_delay); sar = av_guess_sample_aspect_ratio(fmt_ctx, stream, NULL); - if (sar.den) { + if (sar.num) { print_q("sample_aspect_ratio", sar, ':'); av_reduce(&dar.num, &dar.den, par->width * sar.num, @@ -2778,7 +2781,7 @@ static int show_format(WriterContext *w, InputFile *ifile) int ret = 0; writer_print_section_header(w, SECTION_ID_FORMAT); - print_str_validate("filename", fmt_ctx->filename); + print_str_validate("filename", fmt_ctx->url); print_int("nb_streams", fmt_ctx->nb_streams); print_int("nb_programs", fmt_ctx->nb_programs); print_str("format_name", fmt_ctx->iformat->name); @@ -2792,7 +2795,7 @@ static int show_format(WriterContext *w, InputFile *ifile) else print_str_opt("size", "N/A"); if (fmt_ctx->bit_rate > 0) print_val ("bit_rate", fmt_ctx->bit_rate, unit_bit_per_second_str); else print_str_opt("bit_rate", "N/A"); - print_int("probe_score", av_format_get_probe_score(fmt_ctx)); + print_int("probe_score", fmt_ctx->probe_score); if (do_show_format_tags) ret = show_tags(w, fmt_ctx->metadata, SECTION_ID_FORMAT_TAGS); @@ -2828,8 +2831,6 @@ static int open_input_file(InputFile *ifile, const char *filename) exit_program(1); } - fmt_ctx->flags |= AVFMT_FLAG_KEEP_SIDE_DATA; - if (!av_dict_get(format_opts, "scan_all_pmts", NULL, AV_DICT_MATCH_CASE)) { av_dict_set(&format_opts, "scan_all_pmts", "1", AV_DICT_DONT_OVERWRITE); scan_all_pmts_set = 1; @@ -2912,8 +2913,12 @@ static int open_input_file(InputFile *ifile, const char *filename) av_dict_set(&codec_opts, "threads", "1", 0); } - av_codec_set_pkt_timebase(ist->dec_ctx, stream->time_base); + ist->dec_ctx->pkt_timebase = stream->time_base; ist->dec_ctx->framerate = stream->avg_frame_rate; +#if FF_API_LAVF_AVCTX + ist->dec_ctx->coded_width = stream->codec->coded_width; + ist->dec_ctx->coded_height = stream->codec->coded_height; +#endif if (avcodec_open2(ist->dec_ctx, codec, &opts) < 0) { av_log(NULL, AV_LOG_WARNING, "Could not open codec for input stream %d\n", @@ -3113,7 +3118,9 @@ static void ffprobe_show_pixel_formats(WriterContext *w) PRINT_PIX_FMT_FLAG(HWACCEL, "hwaccel"); PRINT_PIX_FMT_FLAG(PLANAR, "planar"); PRINT_PIX_FMT_FLAG(RGB, "rgb"); +#if FF_API_PSEUDOPAL PRINT_PIX_FMT_FLAG(PSEUDOPAL, "pseudopal"); +#endif PRINT_PIX_FMT_FLAG(ALPHA, "alpha"); writer_print_section_footer(w); } @@ -3562,7 +3569,6 @@ int main(int argc, char **argv) options = real_options; parse_loglevel(argc, argv, options); - av_register_all(); avformat_network_init(); init_opts(); #if CONFIG_AVDEVICE diff --git a/fftools/ffserver.c b/fftools/ffserver.c deleted file mode 100644 index d4885dfa0eeac..0000000000000 --- a/fftools/ffserver.c +++ /dev/null @@ -1,4026 +0,0 @@ -/* - * Copyright (c) 2000, 2001, 2002 Fabrice Bellard - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file - * multiple format streaming server based on the FFmpeg libraries - */ - -#include "config.h" -#if !HAVE_CLOSESOCKET -#define closesocket close -#endif -#include -#include -#include -#include "libavformat/avformat.h" -/* FIXME: those are internal headers, ffserver _really_ shouldn't use them */ -#include "libavformat/rtpproto.h" -#include "libavformat/rtsp.h" -#include "libavformat/avio_internal.h" -#include "libavformat/internal.h" - -#include "libavutil/avassert.h" -#include "libavutil/avstring.h" -#include "libavutil/lfg.h" -#include "libavutil/dict.h" -#include "libavutil/intreadwrite.h" -#include "libavutil/mathematics.h" -#include "libavutil/random_seed.h" -#include "libavutil/rational.h" -#include "libavutil/parseutils.h" -#include "libavutil/opt.h" -#include "libavutil/time.h" - -#include -#if HAVE_UNISTD_H -#include -#endif -#include -#include -#if HAVE_POLL_H -#include -#endif -#include -#include -#include -#include - -#include "cmdutils.h" -#include "ffserver_config.h" - -#define PATH_LENGTH 1024 - -const char program_name[] = "ffserver"; -const int program_birth_year = 2000; - -static const OptionDef options[]; - -enum HTTPState { - HTTPSTATE_WAIT_REQUEST, - HTTPSTATE_SEND_HEADER, - HTTPSTATE_SEND_DATA_HEADER, - HTTPSTATE_SEND_DATA, /* sending TCP or UDP data */ - HTTPSTATE_SEND_DATA_TRAILER, - HTTPSTATE_RECEIVE_DATA, - HTTPSTATE_WAIT_FEED, /* wait for data from the feed */ - HTTPSTATE_READY, - - RTSPSTATE_WAIT_REQUEST, - RTSPSTATE_SEND_REPLY, - RTSPSTATE_SEND_PACKET, -}; - -static const char * const http_state[] = { - "HTTP_WAIT_REQUEST", - "HTTP_SEND_HEADER", - - "SEND_DATA_HEADER", - "SEND_DATA", - "SEND_DATA_TRAILER", - "RECEIVE_DATA", - "WAIT_FEED", - "READY", - - "RTSP_WAIT_REQUEST", - "RTSP_SEND_REPLY", - "RTSP_SEND_PACKET", -}; - -#define IOBUFFER_INIT_SIZE 8192 - -/* timeouts are in ms */ -#define HTTP_REQUEST_TIMEOUT (15 * 1000) -#define RTSP_REQUEST_TIMEOUT (3600 * 24 * 1000) - -#define SYNC_TIMEOUT (10 * 1000) - -typedef struct RTSPActionServerSetup { - uint32_t ipaddr; - char transport_option[512]; -} RTSPActionServerSetup; - -typedef struct { - int64_t count1, count2; - int64_t time1, time2; -} DataRateData; - -/* context associated with one connection */ -typedef struct HTTPContext { - enum HTTPState state; - int fd; /* socket file descriptor */ - struct sockaddr_in from_addr; /* origin */ - struct pollfd *poll_entry; /* used when polling */ - int64_t timeout; - uint8_t *buffer_ptr, *buffer_end; - int http_error; - int post; - int chunked_encoding; - int chunk_size; /* 0 if it needs to be read */ - struct HTTPContext *next; - int got_key_frame; /* stream 0 => 1, stream 1 => 2, stream 2=> 4 */ - int64_t data_count; - /* feed input */ - int feed_fd; - /* input format handling */ - AVFormatContext *fmt_in; - int64_t start_time; /* In milliseconds - this wraps fairly often */ - int64_t first_pts; /* initial pts value */ - int64_t cur_pts; /* current pts value from the stream in us */ - int64_t cur_frame_duration; /* duration of the current frame in us */ - int cur_frame_bytes; /* output frame size, needed to compute - the time at which we send each - packet */ - int pts_stream_index; /* stream we choose as clock reference */ - int64_t cur_clock; /* current clock reference value in us */ - /* output format handling */ - struct FFServerStream *stream; - /* -1 is invalid stream */ - int feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */ - int switch_feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */ - int switch_pending; - AVFormatContext *pfmt_ctx; /* instance of FFServerStream for one user */ - int last_packet_sent; /* true if last data packet was sent */ - int suppress_log; - DataRateData datarate; - int wmp_client_id; - char protocol[16]; - char method[16]; - char url[128]; - char clean_url[128*7]; - int buffer_size; - uint8_t *buffer; - int is_packetized; /* if true, the stream is packetized */ - int packet_stream_index; /* current stream for output in state machine */ - - /* RTSP state specific */ - uint8_t *pb_buffer; /* XXX: use that in all the code */ - AVIOContext *pb; - int seq; /* RTSP sequence number */ - - /* RTP state specific */ - enum RTSPLowerTransport rtp_protocol; - char session_id[32]; /* session id */ - AVFormatContext *rtp_ctx[FFSERVER_MAX_STREAMS]; - - /* RTP/UDP specific */ - URLContext *rtp_handles[FFSERVER_MAX_STREAMS]; - - /* RTP/TCP specific */ - struct HTTPContext *rtsp_c; - uint8_t *packet_buffer, *packet_buffer_ptr, *packet_buffer_end; -} HTTPContext; - -static HTTPContext *first_http_ctx; - -static FFServerConfig config = { - .nb_max_http_connections = 2000, - .nb_max_connections = 5, - .max_bandwidth = 1000, - .use_defaults = 1, -}; - -static void new_connection(int server_fd, int is_rtsp); -static void close_connection(HTTPContext *c); - -/* HTTP handling */ -static int handle_connection(HTTPContext *c); -static inline void print_stream_params(AVIOContext *pb, FFServerStream *stream); -static void compute_status(HTTPContext *c); -static int open_input_stream(HTTPContext *c, const char *info); -static int http_parse_request(HTTPContext *c); -static int http_send_data(HTTPContext *c); -static int http_start_receive_data(HTTPContext *c); -static int http_receive_data(HTTPContext *c); - -/* RTSP handling */ -static int rtsp_parse_request(HTTPContext *c); -static void rtsp_cmd_describe(HTTPContext *c, const char *url); -static void rtsp_cmd_options(HTTPContext *c, const char *url); -static void rtsp_cmd_setup(HTTPContext *c, const char *url, - RTSPMessageHeader *h); -static void rtsp_cmd_play(HTTPContext *c, const char *url, - RTSPMessageHeader *h); -static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, - RTSPMessageHeader *h, int pause_only); - -/* SDP handling */ -static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer, - struct in_addr my_ip); - -/* RTP handling */ -static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr, - FFServerStream *stream, - const char *session_id, - enum RTSPLowerTransport rtp_protocol); -static int rtp_new_av_stream(HTTPContext *c, - int stream_index, struct sockaddr_in *dest_addr, - HTTPContext *rtsp_c); -/* utils */ -static size_t htmlencode (const char *src, char **dest); -static inline void cp_html_entity (char *buffer, const char *entity); -static inline int check_codec_match(LayeredAVStream *ccf, AVStream *ccs, int stream); - -static const char *my_program_name; - -static int no_launch; -static int need_to_start_children; - -/* maximum number of simultaneous HTTP connections */ -static unsigned int nb_connections; - -static uint64_t current_bandwidth; - -/* Making this global saves on passing it around everywhere */ -static int64_t cur_time; - -static AVLFG random_state; - -static FILE *logfile = NULL; - -static void unlayer_stream(AVStream *st, LayeredAVStream *lst) -{ - avcodec_free_context(&st->codec); - avcodec_parameters_free(&st->codecpar); -#define COPY(a) st->a = lst->a; - COPY(index) - COPY(id) - COPY(codec) - COPY(codecpar) - COPY(time_base) - COPY(pts_wrap_bits) - COPY(sample_aspect_ratio) - COPY(recommended_encoder_configuration) -} - -static inline void cp_html_entity (char *buffer, const char *entity) { - if (!buffer || !entity) - return; - while (*entity) - *buffer++ = *entity++; -} - -/** - * Substitutes known conflicting chars on a text string with - * their corresponding HTML entities. - * - * Returns the number of bytes in the 'encoded' representation - * not including the terminating NUL. - */ -static size_t htmlencode (const char *src, char **dest) { - const char *amp = "&"; - const char *lt = "<"; - const char *gt = ">"; - const char *start; - char *tmp; - size_t final_size = 0; - - if (!src) - return 0; - - start = src; - - /* Compute needed dest size */ - while (*src != '\0') { - switch(*src) { - case 38: /* & */ - final_size += 5; - break; - case 60: /* < */ - case 62: /* > */ - final_size += 4; - break; - default: - final_size++; - } - src++; - } - - src = start; - *dest = av_mallocz(final_size + 1); - if (!*dest) - return 0; - - /* Build dest */ - tmp = *dest; - while (*src != '\0') { - switch(*src) { - case 38: /* & */ - cp_html_entity (tmp, amp); - tmp += 5; - break; - case 60: /* < */ - cp_html_entity (tmp, lt); - tmp += 4; - break; - case 62: /* > */ - cp_html_entity (tmp, gt); - tmp += 4; - break; - default: - *tmp = *src; - tmp += 1; - } - src++; - } - *tmp = '\0'; - - return final_size; -} - -static int64_t ffm_read_write_index(int fd) -{ - uint8_t buf[8]; - - if (lseek(fd, 8, SEEK_SET) < 0) - return AVERROR(EIO); - if (read(fd, buf, 8) != 8) - return AVERROR(EIO); - return AV_RB64(buf); -} - -static int ffm_write_write_index(int fd, int64_t pos) -{ - uint8_t buf[8]; - int i; - - for(i=0;i<8;i++) - buf[i] = (pos >> (56 - i * 8)) & 0xff; - if (lseek(fd, 8, SEEK_SET) < 0) - goto bail_eio; - if (write(fd, buf, 8) != 8) - goto bail_eio; - - return 8; - -bail_eio: - return AVERROR(EIO); -} - -static void ffm_set_write_index(AVFormatContext *s, int64_t pos, - int64_t file_size) -{ - av_opt_set_int(s, "server_attached", 1, AV_OPT_SEARCH_CHILDREN); - av_opt_set_int(s, "ffm_write_index", pos, AV_OPT_SEARCH_CHILDREN); - av_opt_set_int(s, "ffm_file_size", file_size, AV_OPT_SEARCH_CHILDREN); -} - -static char *ctime1(char *buf2, size_t buf_size) -{ - time_t ti; - char *p; - - ti = time(NULL); - p = ctime(&ti); - if (!p || !*p) { - *buf2 = '\0'; - return buf2; - } - av_strlcpy(buf2, p, buf_size); - p = buf2 + strlen(buf2) - 1; - if (*p == '\n') - *p = '\0'; - return buf2; -} - -static void http_vlog(const char *fmt, va_list vargs) -{ - static int print_prefix = 1; - char buf[32]; - - if (!logfile) - return; - - if (print_prefix) { - ctime1(buf, sizeof(buf)); - fprintf(logfile, "%s ", buf); - } - print_prefix = strstr(fmt, "\n") != NULL; - vfprintf(logfile, fmt, vargs); - fflush(logfile); -} - -#ifdef __GNUC__ -__attribute__ ((format (printf, 1, 2))) -#endif -static void http_log(const char *fmt, ...) -{ - va_list vargs; - va_start(vargs, fmt); - http_vlog(fmt, vargs); - va_end(vargs); -} - -static void http_av_log(void *ptr, int level, const char *fmt, va_list vargs) -{ - static int print_prefix = 1; - AVClass *avc = ptr ? *(AVClass**)ptr : NULL; - if (level > av_log_get_level()) - return; - if (print_prefix && avc) - http_log("[%s @ %p]", avc->item_name(ptr), ptr); - print_prefix = strstr(fmt, "\n") != NULL; - http_vlog(fmt, vargs); -} - -static void log_connection(HTTPContext *c) -{ - if (c->suppress_log) - return; - - http_log("%s - - [%s] \"%s %s\" %d %"PRId64"\n", - inet_ntoa(c->from_addr.sin_addr), c->method, c->url, - c->protocol, (c->http_error ? c->http_error : 200), c->data_count); -} - -static void update_datarate(DataRateData *drd, int64_t count) -{ - if (!drd->time1 && !drd->count1) { - drd->time1 = drd->time2 = cur_time; - drd->count1 = drd->count2 = count; - } else if (cur_time - drd->time2 > 5000) { - drd->time1 = drd->time2; - drd->count1 = drd->count2; - drd->time2 = cur_time; - drd->count2 = count; - } -} - -/* In bytes per second */ -static int compute_datarate(DataRateData *drd, int64_t count) -{ - if (cur_time == drd->time1) - return 0; - - return ((count - drd->count1) * 1000) / (cur_time - drd->time1); -} - - -static void start_children(FFServerStream *feed) -{ - char *pathname; - char *slash; - int i; - size_t cmd_length; - - if (no_launch) - return; - - cmd_length = strlen(my_program_name); - - /** - * FIXME: WIP Safeguard. Remove after clearing all harcoded - * '1024' path lengths - */ - if (cmd_length > PATH_LENGTH - 1) { - http_log("Could not start children. Command line: '%s' exceeds " - "path length limit (%d)\n", my_program_name, PATH_LENGTH); - return; - } - - slash = strrchr(my_program_name, '/'); - if (!slash) { - pathname = av_mallocz(sizeof("ffmpeg")); - } else { - pathname = av_mallocz(slash - my_program_name + sizeof("ffmpeg")); - if (pathname != NULL) { - memcpy(pathname, my_program_name, slash - my_program_name); - } - } - if (!pathname) { - http_log("Could not allocate memory for children cmd line\n"); - return; - } - /* use "ffmpeg" in the path of current program. Ignore user provided path */ - - strcat(pathname, "ffmpeg"); - - for (; feed; feed = feed->next) { - - if (!feed->child_argv || feed->pid) - continue; - - feed->pid_start = time(0); - - feed->pid = fork(); - if (feed->pid < 0) { - http_log("Unable to create children: %s\n", strerror(errno)); - av_free (pathname); - exit(EXIT_FAILURE); - } - - if (feed->pid) - continue; - - /* In child */ - - http_log("Launch command line: "); - http_log("%s ", pathname); - - for (i = 1; feed->child_argv[i] && feed->child_argv[i][0]; i++) - http_log("%s ", feed->child_argv[i]); - http_log("\n"); - - for (i = 3; i < 256; i++) - close(i); - - if (!config.debug) { - if (!freopen("/dev/null", "r", stdin)) - http_log("failed to redirect STDIN to /dev/null\n;"); - if (!freopen("/dev/null", "w", stdout)) - http_log("failed to redirect STDOUT to /dev/null\n;"); - if (!freopen("/dev/null", "w", stderr)) - http_log("failed to redirect STDERR to /dev/null\n;"); - } - - signal(SIGPIPE, SIG_DFL); - execvp(pathname, feed->child_argv); - av_free (pathname); - _exit(1); - } - av_free (pathname); -} - -/* open a listening socket */ -static int socket_open_listen(struct sockaddr_in *my_addr) -{ - int server_fd, tmp; - - server_fd = socket(AF_INET,SOCK_STREAM,0); - if (server_fd < 0) { - perror ("socket"); - return -1; - } - - tmp = 1; - if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp))) - av_log(NULL, AV_LOG_WARNING, "setsockopt SO_REUSEADDR failed\n"); - - my_addr->sin_family = AF_INET; - if (bind (server_fd, (struct sockaddr *) my_addr, sizeof (*my_addr)) < 0) { - char bindmsg[32]; - snprintf(bindmsg, sizeof(bindmsg), "bind(port %d)", - ntohs(my_addr->sin_port)); - perror (bindmsg); - goto fail; - } - - if (listen (server_fd, 5) < 0) { - perror ("listen"); - goto fail; - } - - if (ff_socket_nonblock(server_fd, 1) < 0) - av_log(NULL, AV_LOG_WARNING, "ff_socket_nonblock failed\n"); - - return server_fd; - -fail: - closesocket(server_fd); - return -1; -} - -/* start all multicast streams */ -static void start_multicast(void) -{ - FFServerStream *stream; - char session_id[32]; - HTTPContext *rtp_c; - struct sockaddr_in dest_addr = {0}; - int default_port, stream_index; - unsigned int random0, random1; - - default_port = 6000; - for(stream = config.first_stream; stream; stream = stream->next) { - - if (!stream->is_multicast) - continue; - - random0 = av_lfg_get(&random_state); - random1 = av_lfg_get(&random_state); - - /* open the RTP connection */ - snprintf(session_id, sizeof(session_id), "%08x%08x", random0, random1); - - /* choose a port if none given */ - if (stream->multicast_port == 0) { - stream->multicast_port = default_port; - default_port += 100; - } - - dest_addr.sin_family = AF_INET; - dest_addr.sin_addr = stream->multicast_ip; - dest_addr.sin_port = htons(stream->multicast_port); - - rtp_c = rtp_new_connection(&dest_addr, stream, session_id, - RTSP_LOWER_TRANSPORT_UDP_MULTICAST); - if (!rtp_c) - continue; - - if (open_input_stream(rtp_c, "") < 0) { - http_log("Could not open input stream for stream '%s'\n", - stream->filename); - continue; - } - - /* open each RTP stream */ - for(stream_index = 0; stream_index < stream->nb_streams; - stream_index++) { - dest_addr.sin_port = htons(stream->multicast_port + - 2 * stream_index); - if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, NULL) >= 0) - continue; - - http_log("Could not open output stream '%s/streamid=%d'\n", - stream->filename, stream_index); - exit(1); - } - - rtp_c->state = HTTPSTATE_SEND_DATA; - } -} - -/* main loop of the HTTP server */ -static int http_server(void) -{ - int server_fd = 0, rtsp_server_fd = 0; - int ret, delay; - struct pollfd *poll_table, *poll_entry; - HTTPContext *c, *c_next; - - poll_table = av_mallocz_array(config.nb_max_http_connections + 2, - sizeof(*poll_table)); - if(!poll_table) { - http_log("Impossible to allocate a poll table handling %d " - "connections.\n", config.nb_max_http_connections); - return -1; - } - - if (config.http_addr.sin_port) { - server_fd = socket_open_listen(&config.http_addr); - if (server_fd < 0) - goto quit; - } - - if (config.rtsp_addr.sin_port) { - rtsp_server_fd = socket_open_listen(&config.rtsp_addr); - if (rtsp_server_fd < 0) { - closesocket(server_fd); - goto quit; - } - } - - if (!rtsp_server_fd && !server_fd) { - http_log("HTTP and RTSP disabled.\n"); - goto quit; - } - - http_log("FFserver started.\n"); - - start_children(config.first_feed); - - start_multicast(); - - for(;;) { - poll_entry = poll_table; - if (server_fd) { - poll_entry->fd = server_fd; - poll_entry->events = POLLIN; - poll_entry++; - } - if (rtsp_server_fd) { - poll_entry->fd = rtsp_server_fd; - poll_entry->events = POLLIN; - poll_entry++; - } - - /* wait for events on each HTTP handle */ - c = first_http_ctx; - delay = 1000; - while (c) { - int fd; - fd = c->fd; - switch(c->state) { - case HTTPSTATE_SEND_HEADER: - case RTSPSTATE_SEND_REPLY: - case RTSPSTATE_SEND_PACKET: - c->poll_entry = poll_entry; - poll_entry->fd = fd; - poll_entry->events = POLLOUT; - poll_entry++; - break; - case HTTPSTATE_SEND_DATA_HEADER: - case HTTPSTATE_SEND_DATA: - case HTTPSTATE_SEND_DATA_TRAILER: - if (!c->is_packetized) { - /* for TCP, we output as much as we can - * (may need to put a limit) */ - c->poll_entry = poll_entry; - poll_entry->fd = fd; - poll_entry->events = POLLOUT; - poll_entry++; - } else { - /* when ffserver is doing the timing, we work by - * looking at which packet needs to be sent every - * 10 ms (one tick wait XXX: 10 ms assumed) */ - if (delay > 10) - delay = 10; - } - break; - case HTTPSTATE_WAIT_REQUEST: - case HTTPSTATE_RECEIVE_DATA: - case HTTPSTATE_WAIT_FEED: - case RTSPSTATE_WAIT_REQUEST: - /* need to catch errors */ - c->poll_entry = poll_entry; - poll_entry->fd = fd; - poll_entry->events = POLLIN;/* Maybe this will work */ - poll_entry++; - break; - default: - c->poll_entry = NULL; - break; - } - c = c->next; - } - - /* wait for an event on one connection. We poll at least every - * second to handle timeouts */ - do { - ret = poll(poll_table, poll_entry - poll_table, delay); - if (ret < 0 && ff_neterrno() != AVERROR(EAGAIN) && - ff_neterrno() != AVERROR(EINTR)) { - goto quit; - } - } while (ret < 0); - - cur_time = av_gettime() / 1000; - - if (need_to_start_children) { - need_to_start_children = 0; - start_children(config.first_feed); - } - - /* now handle the events */ - for(c = first_http_ctx; c; c = c_next) { - c_next = c->next; - if (handle_connection(c) < 0) { - log_connection(c); - /* close and free the connection */ - close_connection(c); - } - } - - poll_entry = poll_table; - if (server_fd) { - /* new HTTP connection request ? */ - if (poll_entry->revents & POLLIN) - new_connection(server_fd, 0); - poll_entry++; - } - if (rtsp_server_fd) { - /* new RTSP connection request ? */ - if (poll_entry->revents & POLLIN) - new_connection(rtsp_server_fd, 1); - } - } - -quit: - av_free(poll_table); - return -1; -} - -/* start waiting for a new HTTP/RTSP request */ -static void start_wait_request(HTTPContext *c, int is_rtsp) -{ - c->buffer_ptr = c->buffer; - c->buffer_end = c->buffer + c->buffer_size - 1; /* leave room for '\0' */ - - c->state = is_rtsp ? RTSPSTATE_WAIT_REQUEST : HTTPSTATE_WAIT_REQUEST; - c->timeout = cur_time + - (is_rtsp ? RTSP_REQUEST_TIMEOUT : HTTP_REQUEST_TIMEOUT); -} - -static void http_send_too_busy_reply(int fd) -{ - char buffer[400]; - int len = snprintf(buffer, sizeof(buffer), - "HTTP/1.0 503 Server too busy\r\n" - "Content-type: text/html\r\n" - "\r\n" - "\n" - "Too busy\r\n" - "

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

\r\n" - "

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

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

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

\r\n" - "

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

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

%s Status

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

Available Streams

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

bytes
FormatBit rate
kbit/s
Video
kbit/s

Codec
Audio
kbit/s

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

Feed %s

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

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

Connection Status

\n"); - - avio_printf(pb, "Number of connections: %d / %d
\n", - nb_connections, config.nb_max_connections); - - avio_printf(pb, "Bandwidth in use: %"PRIu64"k / %"PRIu64"k
\n", - current_bandwidth, config.max_bandwidth); - - avio_printf(pb, "\n"); - avio_printf(pb, "
#FileIPURLProtoStateTarget " - "bit/sActual bit/sBytes transferred\n"); - c1 = first_http_ctx; - i = 0; - while (c1) { - int bitrate; - int j; - - bitrate = 0; - if (c1->stream) { - for (j = 0; j < c1->stream->nb_streams; j++) { - if (!c1->stream->feed) - bitrate += c1->stream->streams[j]->codecpar->bit_rate; - else if (c1->feed_streams[j] >= 0) - bitrate += c1->stream->feed->streams[c1->feed_streams[j]]->codecpar->bit_rate; - } - } - - i++; - p = inet_ntoa(c1->from_addr.sin_addr); - clean_html(c1->clean_url, sizeof(c1->clean_url), c1->url); - avio_printf(pb, "
%d%s%s%s%s%s%s" - "", - i, c1->stream ? c1->stream->filename : "", - c1->state == HTTPSTATE_RECEIVE_DATA ? "(input)" : "", - p, - c1->clean_url, - c1->protocol, http_state[c1->state]); - fmt_bytecount(pb, bitrate); - avio_printf(pb, ""); - fmt_bytecount(pb, compute_datarate(&c1->datarate, c1->data_count) * 8); - avio_printf(pb, ""); - fmt_bytecount(pb, c1->data_count); - avio_printf(pb, "\n"); - c1 = c1->next; - } - avio_printf(pb, "
\n"); - - if (!config.bitexact) { - /* date */ - ti = time(NULL); - p = ctime(&ti); - avio_printf(pb, "
Generated at %s", p); - } - avio_printf(pb, "\n\n"); - - len = avio_close_dyn_buf(pb, &c->pb_buffer); - c->buffer_ptr = c->pb_buffer; - c->buffer_end = c->pb_buffer + len; -} - -static int open_input_stream(HTTPContext *c, const char *info) -{ - char buf[128]; - char input_filename[1024]; - AVFormatContext *s = NULL; - int buf_size, i, ret; - int64_t stream_pos; - - /* find file name */ - if (c->stream->feed) { - strcpy(input_filename, c->stream->feed->feed_filename); - buf_size = FFM_PACKET_SIZE; - /* compute position (absolute time) */ - if (av_find_info_tag(buf, sizeof(buf), "date", info)) { - if ((ret = av_parse_time(&stream_pos, buf, 0)) < 0) { - http_log("Invalid date specification '%s' for stream\n", buf); - return ret; - } - } else if (av_find_info_tag(buf, sizeof(buf), "buffer", info)) { - int prebuffer = strtol(buf, 0, 10); - stream_pos = av_gettime() - prebuffer * (int64_t)1000000; - } else - stream_pos = av_gettime() - c->stream->prebuffer * (int64_t)1000; - } else { - strcpy(input_filename, c->stream->feed_filename); - buf_size = 0; - /* compute position (relative time) */ - if (av_find_info_tag(buf, sizeof(buf), "date", info)) { - if ((ret = av_parse_time(&stream_pos, buf, 1)) < 0) { - http_log("Invalid date specification '%s' for stream\n", buf); - return ret; - } - } else - stream_pos = 0; - } - if (!input_filename[0]) { - http_log("No filename was specified for stream\n"); - return AVERROR(EINVAL); - } - - /* open stream */ - ret = avformat_open_input(&s, input_filename, c->stream->ifmt, - &c->stream->in_opts); - if (ret < 0) { - http_log("Could not open input '%s': %s\n", - input_filename, av_err2str(ret)); - return ret; - } - - /* set buffer size */ - if (buf_size > 0) { - ret = ffio_set_buf_size(s->pb, buf_size); - if (ret < 0) { - http_log("Failed to set buffer size\n"); - return ret; - } - } - - s->flags |= AVFMT_FLAG_GENPTS; - c->fmt_in = s; - if (strcmp(s->iformat->name, "ffm") && - (ret = avformat_find_stream_info(c->fmt_in, NULL)) < 0) { - http_log("Could not find stream info for input '%s'\n", input_filename); - avformat_close_input(&s); - return ret; - } - - /* choose stream as clock source (we favor the video stream if - * present) for packet sending */ - c->pts_stream_index = 0; - for(i=0;istream->nb_streams;i++) { - if (c->pts_stream_index == 0 && - c->stream->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { - c->pts_stream_index = i; - } - } - - if (c->fmt_in->iformat->read_seek) - av_seek_frame(c->fmt_in, -1, stream_pos, 0); - /* set the start time (needed for maxtime and RTP packet timing) */ - c->start_time = cur_time; - c->first_pts = AV_NOPTS_VALUE; - return 0; -} - -/* return the server clock (in us) */ -static int64_t get_server_clock(HTTPContext *c) -{ - /* compute current pts value from system time */ - return (cur_time - c->start_time) * 1000; -} - -/* return the estimated time (in us) at which the current packet must be sent */ -static int64_t get_packet_send_clock(HTTPContext *c) -{ - int bytes_left, bytes_sent, frame_bytes; - - frame_bytes = c->cur_frame_bytes; - if (frame_bytes <= 0) - return c->cur_pts; - - bytes_left = c->buffer_end - c->buffer_ptr; - bytes_sent = frame_bytes - bytes_left; - return c->cur_pts + (c->cur_frame_duration * bytes_sent) / frame_bytes; -} - - -static int http_prepare_data(HTTPContext *c) -{ - int i, len, ret; - AVFormatContext *ctx; - - av_freep(&c->pb_buffer); - switch(c->state) { - case HTTPSTATE_SEND_DATA_HEADER: - ctx = avformat_alloc_context(); - if (!ctx) - return AVERROR(ENOMEM); - c->pfmt_ctx = ctx; - av_dict_copy(&(c->pfmt_ctx->metadata), c->stream->metadata, 0); - - for(i=0;istream->nb_streams;i++) { - LayeredAVStream *src; - AVStream *st = avformat_new_stream(c->pfmt_ctx, NULL); - if (!st) - return AVERROR(ENOMEM); - - /* if file or feed, then just take streams from FFServerStream - * struct */ - if (!c->stream->feed || - c->stream->feed == c->stream) - src = c->stream->streams[i]; - else - src = c->stream->feed->streams[c->stream->feed_streams[i]]; - - unlayer_stream(c->pfmt_ctx->streams[i], src); //TODO we no longer copy st->internal, does this matter? - av_assert0(!c->pfmt_ctx->streams[i]->priv_data); - - if (src->codec->flags & AV_CODEC_FLAG_BITEXACT) - c->pfmt_ctx->flags |= AVFMT_FLAG_BITEXACT; - } - /* set output format parameters */ - c->pfmt_ctx->oformat = c->stream->fmt; - av_assert0(c->pfmt_ctx->nb_streams == c->stream->nb_streams); - - c->got_key_frame = 0; - - /* prepare header and save header data in a stream */ - if (avio_open_dyn_buf(&c->pfmt_ctx->pb) < 0) { - /* XXX: potential leak */ - return -1; - } - c->pfmt_ctx->pb->seekable = 0; - - /* - * HACK to avoid MPEG-PS muxer to spit many underflow errors - * Default value from FFmpeg - * Try to set it using configuration option - */ - c->pfmt_ctx->max_delay = (int)(0.7*AV_TIME_BASE); - - if ((ret = avformat_write_header(c->pfmt_ctx, NULL)) < 0) { - http_log("Error writing output header for stream '%s': %s\n", - c->stream->filename, av_err2str(ret)); - return ret; - } - av_dict_free(&c->pfmt_ctx->metadata); - - len = avio_close_dyn_buf(c->pfmt_ctx->pb, &c->pb_buffer); - c->buffer_ptr = c->pb_buffer; - c->buffer_end = c->pb_buffer + len; - - c->state = HTTPSTATE_SEND_DATA; - c->last_packet_sent = 0; - break; - case HTTPSTATE_SEND_DATA: - /* find a new packet */ - /* read a packet from the input stream */ - if (c->stream->feed) - ffm_set_write_index(c->fmt_in, - c->stream->feed->feed_write_index, - c->stream->feed->feed_size); - - if (c->stream->max_time && - c->stream->max_time + c->start_time - cur_time < 0) - /* We have timed out */ - c->state = HTTPSTATE_SEND_DATA_TRAILER; - else { - AVPacket pkt; - redo: - ret = av_read_frame(c->fmt_in, &pkt); - if (ret < 0) { - if (c->stream->feed) { - /* if coming from feed, it means we reached the end of the - * ffm file, so must wait for more data */ - c->state = HTTPSTATE_WAIT_FEED; - return 1; /* state changed */ - } - if (ret == AVERROR(EAGAIN)) { - /* input not ready, come back later */ - return 0; - } - if (c->stream->loop) { - avformat_close_input(&c->fmt_in); - if (open_input_stream(c, "") < 0) - goto no_loop; - goto redo; - } else { - no_loop: - /* must send trailer now because EOF or error */ - c->state = HTTPSTATE_SEND_DATA_TRAILER; - } - } else { - int source_index = pkt.stream_index; - /* update first pts if needed */ - if (c->first_pts == AV_NOPTS_VALUE && pkt.dts != AV_NOPTS_VALUE) { - c->first_pts = av_rescale_q(pkt.dts, c->fmt_in->streams[pkt.stream_index]->time_base, AV_TIME_BASE_Q); - c->start_time = cur_time; - } - /* send it to the appropriate stream */ - if (c->stream->feed) { - /* if coming from a feed, select the right stream */ - if (c->switch_pending) { - c->switch_pending = 0; - for(i=0;istream->nb_streams;i++) { - if (c->switch_feed_streams[i] == pkt.stream_index) - if (pkt.flags & AV_PKT_FLAG_KEY) - c->switch_feed_streams[i] = -1; - if (c->switch_feed_streams[i] >= 0) - c->switch_pending = 1; - } - } - for(i=0;istream->nb_streams;i++) { - if (c->stream->feed_streams[i] == pkt.stream_index) { - AVStream *st = c->fmt_in->streams[source_index]; - pkt.stream_index = i; - if (pkt.flags & AV_PKT_FLAG_KEY && - (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO || - c->stream->nb_streams == 1)) - c->got_key_frame = 1; - if (!c->stream->send_on_key || c->got_key_frame) - goto send_it; - } - } - } else { - AVStream *ist, *ost; - send_it: - ist = c->fmt_in->streams[source_index]; - /* specific handling for RTP: we use several - * output streams (one for each RTP connection). - * XXX: need more abstract handling */ - if (c->is_packetized) { - /* compute send time and duration */ - if (pkt.dts != AV_NOPTS_VALUE) { - c->cur_pts = av_rescale_q(pkt.dts, ist->time_base, AV_TIME_BASE_Q); - c->cur_pts -= c->first_pts; - } - c->cur_frame_duration = av_rescale_q(pkt.duration, ist->time_base, AV_TIME_BASE_Q); - /* find RTP context */ - c->packet_stream_index = pkt.stream_index; - ctx = c->rtp_ctx[c->packet_stream_index]; - if(!ctx) { - av_packet_unref(&pkt); - break; - } - /* only one stream per RTP connection */ - pkt.stream_index = 0; - } else { - ctx = c->pfmt_ctx; - /* Fudge here */ - } - - if (c->is_packetized) { - int max_packet_size; - if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) - max_packet_size = RTSP_TCP_MAX_PACKET_SIZE; - else - max_packet_size = c->rtp_handles[c->packet_stream_index]->max_packet_size; - ret = ffio_open_dyn_packet_buf(&ctx->pb, - max_packet_size); - } else - ret = avio_open_dyn_buf(&ctx->pb); - - if (ret < 0) { - /* XXX: potential leak */ - return -1; - } - ost = ctx->streams[pkt.stream_index]; - - ctx->pb->seekable = 0; - if (pkt.dts != AV_NOPTS_VALUE) - pkt.dts = av_rescale_q(pkt.dts, ist->time_base, - ost->time_base); - if (pkt.pts != AV_NOPTS_VALUE) - pkt.pts = av_rescale_q(pkt.pts, ist->time_base, - ost->time_base); - pkt.duration = av_rescale_q(pkt.duration, ist->time_base, - ost->time_base); - if ((ret = av_write_frame(ctx, &pkt)) < 0) { - http_log("Error writing frame to output for stream '%s': %s\n", - c->stream->filename, av_err2str(ret)); - c->state = HTTPSTATE_SEND_DATA_TRAILER; - } - - av_freep(&c->pb_buffer); - len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer); - ctx->pb = NULL; - c->cur_frame_bytes = len; - c->buffer_ptr = c->pb_buffer; - c->buffer_end = c->pb_buffer + len; - - if (len == 0) { - av_packet_unref(&pkt); - goto redo; - } - } - av_packet_unref(&pkt); - } - } - break; - default: - case HTTPSTATE_SEND_DATA_TRAILER: - /* last packet test ? */ - if (c->last_packet_sent || c->is_packetized) - return -1; - ctx = c->pfmt_ctx; - /* prepare header */ - if (avio_open_dyn_buf(&ctx->pb) < 0) { - /* XXX: potential leak */ - return -1; - } - c->pfmt_ctx->pb->seekable = 0; - av_write_trailer(ctx); - len = avio_close_dyn_buf(ctx->pb, &c->pb_buffer); - c->buffer_ptr = c->pb_buffer; - c->buffer_end = c->pb_buffer + len; - - c->last_packet_sent = 1; - break; - } - return 0; -} - -/* should convert the format at the same time */ -/* send data starting at c->buffer_ptr to the output connection - * (either UDP or TCP) - */ -static int http_send_data(HTTPContext *c) -{ - int len, ret; - - for(;;) { - if (c->buffer_ptr >= c->buffer_end) { - ret = http_prepare_data(c); - if (ret < 0) - return -1; - else if (ret) - /* state change requested */ - break; - } else { - if (c->is_packetized) { - /* RTP data output */ - len = c->buffer_end - c->buffer_ptr; - if (len < 4) { - /* fail safe - should never happen */ - fail1: - c->buffer_ptr = c->buffer_end; - return 0; - } - len = (c->buffer_ptr[0] << 24) | - (c->buffer_ptr[1] << 16) | - (c->buffer_ptr[2] << 8) | - (c->buffer_ptr[3]); - if (len > (c->buffer_end - c->buffer_ptr)) - goto fail1; - if ((get_packet_send_clock(c) - get_server_clock(c)) > 0) { - /* nothing to send yet: we can wait */ - return 0; - } - - c->data_count += len; - update_datarate(&c->datarate, c->data_count); - if (c->stream) - c->stream->bytes_served += len; - - if (c->rtp_protocol == RTSP_LOWER_TRANSPORT_TCP) { - /* RTP packets are sent inside the RTSP TCP connection */ - AVIOContext *pb; - int interleaved_index, size; - uint8_t header[4]; - HTTPContext *rtsp_c; - - rtsp_c = c->rtsp_c; - /* if no RTSP connection left, error */ - if (!rtsp_c) - return -1; - /* if already sending something, then wait. */ - if (rtsp_c->state != RTSPSTATE_WAIT_REQUEST) - break; - if (avio_open_dyn_buf(&pb) < 0) - goto fail1; - interleaved_index = c->packet_stream_index * 2; - /* RTCP packets are sent at odd indexes */ - if (c->buffer_ptr[1] == 200) - interleaved_index++; - /* write RTSP TCP header */ - header[0] = '$'; - header[1] = interleaved_index; - header[2] = len >> 8; - header[3] = len; - avio_write(pb, header, 4); - /* write RTP packet data */ - c->buffer_ptr += 4; - avio_write(pb, c->buffer_ptr, len); - size = avio_close_dyn_buf(pb, &c->packet_buffer); - /* prepare asynchronous TCP sending */ - rtsp_c->packet_buffer_ptr = c->packet_buffer; - rtsp_c->packet_buffer_end = c->packet_buffer + size; - c->buffer_ptr += len; - - /* send everything we can NOW */ - len = send(rtsp_c->fd, rtsp_c->packet_buffer_ptr, - rtsp_c->packet_buffer_end - rtsp_c->packet_buffer_ptr, 0); - if (len > 0) - rtsp_c->packet_buffer_ptr += len; - if (rtsp_c->packet_buffer_ptr < rtsp_c->packet_buffer_end) { - /* if we could not send all the data, we will - * send it later, so a new state is needed to - * "lock" the RTSP TCP connection */ - rtsp_c->state = RTSPSTATE_SEND_PACKET; - break; - } else - /* all data has been sent */ - av_freep(&c->packet_buffer); - } else { - /* send RTP packet directly in UDP */ - c->buffer_ptr += 4; - ffurl_write(c->rtp_handles[c->packet_stream_index], - c->buffer_ptr, len); - c->buffer_ptr += len; - /* here we continue as we can send several packets - * per 10 ms slot */ - } - } else { - /* TCP data output */ - len = send(c->fd, c->buffer_ptr, - c->buffer_end - c->buffer_ptr, 0); - if (len < 0) { - if (ff_neterrno() != AVERROR(EAGAIN) && - ff_neterrno() != AVERROR(EINTR)) - /* error : close connection */ - return -1; - else - return 0; - } - c->buffer_ptr += len; - - c->data_count += len; - update_datarate(&c->datarate, c->data_count); - if (c->stream) - c->stream->bytes_served += len; - break; - } - } - } /* for(;;) */ - return 0; -} - -static int http_start_receive_data(HTTPContext *c) -{ - int fd; - int ret; - int64_t ret64; - - if (c->stream->feed_opened) { - http_log("Stream feed '%s' was not opened\n", - c->stream->feed_filename); - return AVERROR(EINVAL); - } - - /* Don't permit writing to this one */ - if (c->stream->readonly) { - http_log("Cannot write to read-only file '%s'\n", - c->stream->feed_filename); - return AVERROR(EINVAL); - } - - /* open feed */ - fd = open(c->stream->feed_filename, O_RDWR); - if (fd < 0) { - ret = AVERROR(errno); - http_log("Could not open feed file '%s': %s\n", - c->stream->feed_filename, strerror(errno)); - return ret; - } - c->feed_fd = fd; - - if (c->stream->truncate) { - /* truncate feed file */ - ffm_write_write_index(c->feed_fd, FFM_PACKET_SIZE); - http_log("Truncating feed file '%s'\n", c->stream->feed_filename); - if (ftruncate(c->feed_fd, FFM_PACKET_SIZE) < 0) { - ret = AVERROR(errno); - http_log("Error truncating feed file '%s': %s\n", - c->stream->feed_filename, strerror(errno)); - return ret; - } - } else { - ret64 = ffm_read_write_index(fd); - if (ret64 < 0) { - http_log("Error reading write index from feed file '%s': %s\n", - c->stream->feed_filename, strerror(errno)); - return ret64; - } - c->stream->feed_write_index = ret64; - } - - c->stream->feed_write_index = FFMAX(ffm_read_write_index(fd), - FFM_PACKET_SIZE); - c->stream->feed_size = lseek(fd, 0, SEEK_END); - lseek(fd, 0, SEEK_SET); - - /* init buffer input */ - c->buffer_ptr = c->buffer; - c->buffer_end = c->buffer + FFM_PACKET_SIZE; - c->stream->feed_opened = 1; - c->chunked_encoding = !!av_stristr(c->buffer, "Transfer-Encoding: chunked"); - return 0; -} - -static int http_receive_data(HTTPContext *c) -{ - HTTPContext *c1; - int len, loop_run = 0; - - while (c->chunked_encoding && !c->chunk_size && - c->buffer_end > c->buffer_ptr) { - /* read chunk header, if present */ - len = recv(c->fd, c->buffer_ptr, 1, 0); - - if (len < 0) { - if (ff_neterrno() != AVERROR(EAGAIN) && - ff_neterrno() != AVERROR(EINTR)) - /* error : close connection */ - goto fail; - return 0; - } else if (len == 0) { - /* end of connection : close it */ - goto fail; - } else if (c->buffer_ptr - c->buffer >= 2 && - !memcmp(c->buffer_ptr - 1, "\r\n", 2)) { - c->chunk_size = strtol(c->buffer, 0, 16); - if (c->chunk_size <= 0) { // end of stream or invalid chunk size - c->chunk_size = 0; - goto fail; - } - c->buffer_ptr = c->buffer; - break; - } else if (++loop_run > 10) - /* no chunk header, abort */ - goto fail; - else - c->buffer_ptr++; - } - - if (c->buffer_end > c->buffer_ptr) { - len = recv(c->fd, c->buffer_ptr, - FFMIN(c->chunk_size, c->buffer_end - c->buffer_ptr), 0); - if (len < 0) { - if (ff_neterrno() != AVERROR(EAGAIN) && - ff_neterrno() != AVERROR(EINTR)) - /* error : close connection */ - goto fail; - } else if (len == 0) - /* end of connection : close it */ - goto fail; - else { - av_assert0(len <= c->chunk_size); - c->chunk_size -= len; - c->buffer_ptr += len; - c->data_count += len; - update_datarate(&c->datarate, c->data_count); - } - } - - if (c->buffer_ptr - c->buffer >= 2 && c->data_count > FFM_PACKET_SIZE) { - if (c->buffer[0] != 'f' || - c->buffer[1] != 'm') { - http_log("Feed stream has become desynchronized -- disconnecting\n"); - goto fail; - } - } - - if (c->buffer_ptr >= c->buffer_end) { - FFServerStream *feed = c->stream; - /* a packet has been received : write it in the store, except - * if header */ - if (c->data_count > FFM_PACKET_SIZE) { - /* XXX: use llseek or url_seek - * XXX: Should probably fail? */ - if (lseek(c->feed_fd, feed->feed_write_index, SEEK_SET) == -1) - http_log("Seek to %"PRId64" failed\n", feed->feed_write_index); - - if (write(c->feed_fd, c->buffer, FFM_PACKET_SIZE) < 0) { - http_log("Error writing to feed file: %s\n", strerror(errno)); - goto fail; - } - - feed->feed_write_index += FFM_PACKET_SIZE; - /* update file size */ - if (feed->feed_write_index > c->stream->feed_size) - feed->feed_size = feed->feed_write_index; - - /* handle wrap around if max file size reached */ - if (c->stream->feed_max_size && - feed->feed_write_index >= c->stream->feed_max_size) - feed->feed_write_index = FFM_PACKET_SIZE; - - /* write index */ - if (ffm_write_write_index(c->feed_fd, feed->feed_write_index) < 0) { - http_log("Error writing index to feed file: %s\n", - strerror(errno)); - goto fail; - } - - /* wake up any waiting connections */ - for(c1 = first_http_ctx; c1; c1 = c1->next) { - if (c1->state == HTTPSTATE_WAIT_FEED && - c1->stream->feed == c->stream->feed) - c1->state = HTTPSTATE_SEND_DATA; - } - } else { - /* We have a header in our hands that contains useful data */ - AVFormatContext *s = avformat_alloc_context(); - AVIOContext *pb; - AVInputFormat *fmt_in; - int i; - - if (!s) - goto fail; - - /* use feed output format name to find corresponding input format */ - fmt_in = av_find_input_format(feed->fmt->name); - if (!fmt_in) - goto fail; - - pb = avio_alloc_context(c->buffer, c->buffer_end - c->buffer, - 0, NULL, NULL, NULL, NULL); - if (!pb) - goto fail; - - pb->seekable = 0; - - s->pb = pb; - if (avformat_open_input(&s, c->stream->feed_filename, fmt_in, NULL) < 0) { - av_freep(&pb); - goto fail; - } - - /* Now we have the actual streams */ - if (s->nb_streams != feed->nb_streams) { - avformat_close_input(&s); - av_freep(&pb); - http_log("Feed '%s' stream number does not match registered feed\n", - c->stream->feed_filename); - goto fail; - } - - for (i = 0; i < s->nb_streams; i++) { - LayeredAVStream *fst = feed->streams[i]; - AVStream *st = s->streams[i]; - avcodec_parameters_to_context(fst->codec, st->codecpar); - avcodec_parameters_from_context(fst->codecpar, fst->codec); - } - - avformat_close_input(&s); - av_freep(&pb); - } - c->buffer_ptr = c->buffer; - } - - return 0; - fail: - c->stream->feed_opened = 0; - close(c->feed_fd); - /* wake up any waiting connections to stop waiting for feed */ - for(c1 = first_http_ctx; c1; c1 = c1->next) { - if (c1->state == HTTPSTATE_WAIT_FEED && - c1->stream->feed == c->stream->feed) - c1->state = HTTPSTATE_SEND_DATA_TRAILER; - } - return -1; -} - -/********************************************************************/ -/* RTSP handling */ - -static void rtsp_reply_header(HTTPContext *c, enum RTSPStatusCode error_number) -{ - const char *str; - time_t ti; - struct tm *tm; - char buf2[32]; - - str = RTSP_STATUS_CODE2STRING(error_number); - if (!str) - str = "Unknown Error"; - - avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", error_number, str); - avio_printf(c->pb, "CSeq: %d\r\n", c->seq); - - /* output GMT time */ - ti = time(NULL); - tm = gmtime(&ti); - strftime(buf2, sizeof(buf2), "%a, %d %b %Y %H:%M:%S", tm); - avio_printf(c->pb, "Date: %s GMT\r\n", buf2); -} - -static void rtsp_reply_error(HTTPContext *c, enum RTSPStatusCode error_number) -{ - rtsp_reply_header(c, error_number); - avio_printf(c->pb, "\r\n"); -} - -static int rtsp_parse_request(HTTPContext *c) -{ - const char *p, *p1, *p2; - char cmd[32]; - char url[1024]; - char protocol[32]; - char line[1024]; - int len; - RTSPMessageHeader header1 = { 0 }, *header = &header1; - - c->buffer_ptr[0] = '\0'; - p = c->buffer; - - get_word(cmd, sizeof(cmd), &p); - get_word(url, sizeof(url), &p); - get_word(protocol, sizeof(protocol), &p); - - av_strlcpy(c->method, cmd, sizeof(c->method)); - av_strlcpy(c->url, url, sizeof(c->url)); - av_strlcpy(c->protocol, protocol, sizeof(c->protocol)); - - if (avio_open_dyn_buf(&c->pb) < 0) { - /* XXX: cannot do more */ - c->pb = NULL; /* safety */ - return -1; - } - - /* check version name */ - if (strcmp(protocol, "RTSP/1.0")) { - rtsp_reply_error(c, RTSP_STATUS_VERSION); - goto the_end; - } - - /* parse each header line */ - /* skip to next line */ - while (*p != '\n' && *p != '\0') - p++; - if (*p == '\n') - p++; - while (*p != '\0') { - p1 = memchr(p, '\n', (char *)c->buffer_ptr - p); - if (!p1) - break; - p2 = p1; - if (p2 > p && p2[-1] == '\r') - p2--; - /* skip empty line */ - if (p2 == p) - break; - len = p2 - p; - if (len > sizeof(line) - 1) - len = sizeof(line) - 1; - memcpy(line, p, len); - line[len] = '\0'; - ff_rtsp_parse_line(NULL, header, line, NULL, NULL); - p = p1 + 1; - } - - /* handle sequence number */ - c->seq = header->seq; - - if (!strcmp(cmd, "DESCRIBE")) - rtsp_cmd_describe(c, url); - else if (!strcmp(cmd, "OPTIONS")) - rtsp_cmd_options(c, url); - else if (!strcmp(cmd, "SETUP")) - rtsp_cmd_setup(c, url, header); - else if (!strcmp(cmd, "PLAY")) - rtsp_cmd_play(c, url, header); - else if (!strcmp(cmd, "PAUSE")) - rtsp_cmd_interrupt(c, url, header, 1); - else if (!strcmp(cmd, "TEARDOWN")) - rtsp_cmd_interrupt(c, url, header, 0); - else - rtsp_reply_error(c, RTSP_STATUS_METHOD); - - the_end: - len = avio_close_dyn_buf(c->pb, &c->pb_buffer); - c->pb = NULL; /* safety */ - if (len < 0) - /* XXX: cannot do more */ - return -1; - - c->buffer_ptr = c->pb_buffer; - c->buffer_end = c->pb_buffer + len; - c->state = RTSPSTATE_SEND_REPLY; - return 0; -} - -static int prepare_sdp_description(FFServerStream *stream, uint8_t **pbuffer, - struct in_addr my_ip) -{ - AVFormatContext *avc; - AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL); - AVDictionaryEntry *entry = av_dict_get(stream->metadata, "title", NULL, 0); - int i; - - *pbuffer = NULL; - - avc = avformat_alloc_context(); - if (!avc || !rtp_format) - return -1; - - avc->oformat = rtp_format; - av_dict_set(&avc->metadata, "title", - entry ? entry->value : "No Title", 0); - if (stream->is_multicast) { - snprintf(avc->filename, 1024, "rtp://%s:%d?multicast=1?ttl=%d", - inet_ntoa(stream->multicast_ip), - stream->multicast_port, stream->multicast_ttl); - } else - snprintf(avc->filename, 1024, "rtp://0.0.0.0"); - - for(i = 0; i < stream->nb_streams; i++) { - AVStream *st = avformat_new_stream(avc, NULL); - if (!st) - goto sdp_done; - avcodec_parameters_from_context(stream->streams[i]->codecpar, stream->streams[i]->codec); - unlayer_stream(st, stream->streams[i]); - } -#define PBUFFER_SIZE 2048 - *pbuffer = av_mallocz(PBUFFER_SIZE); - if (!*pbuffer) - goto sdp_done; - av_sdp_create(&avc, 1, *pbuffer, PBUFFER_SIZE); - - sdp_done: - av_freep(&avc->streams); - av_dict_free(&avc->metadata); - av_free(avc); - - return *pbuffer ? strlen(*pbuffer) : AVERROR(ENOMEM); -} - -static void rtsp_cmd_options(HTTPContext *c, const char *url) -{ - /* rtsp_reply_header(c, RTSP_STATUS_OK); */ - avio_printf(c->pb, "RTSP/1.0 %d %s\r\n", RTSP_STATUS_OK, "OK"); - avio_printf(c->pb, "CSeq: %d\r\n", c->seq); - avio_printf(c->pb, "Public: %s\r\n", - "OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE"); - avio_printf(c->pb, "\r\n"); -} - -static void rtsp_cmd_describe(HTTPContext *c, const char *url) -{ - FFServerStream *stream; - char path1[1024]; - const char *path; - uint8_t *content; - int content_length; - socklen_t len; - struct sockaddr_in my_addr; - - /* find which URL is asked */ - av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url); - path = path1; - if (*path == '/') - path++; - - for(stream = config.first_stream; stream; stream = stream->next) { - if (!stream->is_feed && - stream->fmt && !strcmp(stream->fmt->name, "rtp") && - !strcmp(path, stream->filename)) { - goto found; - } - } - /* no stream found */ - rtsp_reply_error(c, RTSP_STATUS_NOT_FOUND); - return; - - found: - /* prepare the media description in SDP format */ - - /* get the host IP */ - len = sizeof(my_addr); - getsockname(c->fd, (struct sockaddr *)&my_addr, &len); - content_length = prepare_sdp_description(stream, &content, - my_addr.sin_addr); - if (content_length < 0) { - rtsp_reply_error(c, RTSP_STATUS_INTERNAL); - return; - } - rtsp_reply_header(c, RTSP_STATUS_OK); - avio_printf(c->pb, "Content-Base: %s/\r\n", url); - avio_printf(c->pb, "Content-Type: application/sdp\r\n"); - avio_printf(c->pb, "Content-Length: %d\r\n", content_length); - avio_printf(c->pb, "\r\n"); - avio_write(c->pb, content, content_length); - av_free(content); -} - -static HTTPContext *find_rtp_session(const char *session_id) -{ - HTTPContext *c; - - if (session_id[0] == '\0') - return NULL; - - for(c = first_http_ctx; c; c = c->next) { - if (!strcmp(c->session_id, session_id)) - return c; - } - return NULL; -} - -static RTSPTransportField *find_transport(RTSPMessageHeader *h, enum RTSPLowerTransport lower_transport) -{ - RTSPTransportField *th; - int i; - - for(i=0;inb_transports;i++) { - th = &h->transports[i]; - if (th->lower_transport == lower_transport) - return th; - } - return NULL; -} - -static void rtsp_cmd_setup(HTTPContext *c, const char *url, - RTSPMessageHeader *h) -{ - FFServerStream *stream; - int stream_index, rtp_port, rtcp_port; - char buf[1024]; - char path1[1024]; - const char *path; - HTTPContext *rtp_c; - RTSPTransportField *th; - struct sockaddr_in dest_addr; - RTSPActionServerSetup setup; - - /* find which URL is asked */ - av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url); - path = path1; - if (*path == '/') - path++; - - /* now check each stream */ - for(stream = config.first_stream; stream; stream = stream->next) { - if (stream->is_feed || !stream->fmt || - strcmp(stream->fmt->name, "rtp")) { - continue; - } - /* accept aggregate filenames only if single stream */ - if (!strcmp(path, stream->filename)) { - if (stream->nb_streams != 1) { - rtsp_reply_error(c, RTSP_STATUS_AGGREGATE); - return; - } - stream_index = 0; - goto found; - } - - for(stream_index = 0; stream_index < stream->nb_streams; - stream_index++) { - snprintf(buf, sizeof(buf), "%s/streamid=%d", - stream->filename, stream_index); - if (!strcmp(path, buf)) - goto found; - } - } - /* no stream found */ - rtsp_reply_error(c, RTSP_STATUS_SERVICE); /* XXX: right error ? */ - return; - found: - - /* generate session id if needed */ - if (h->session_id[0] == '\0') { - unsigned random0 = av_lfg_get(&random_state); - unsigned random1 = av_lfg_get(&random_state); - snprintf(h->session_id, sizeof(h->session_id), "%08x%08x", - random0, random1); - } - - /* find RTP session, and create it if none found */ - rtp_c = find_rtp_session(h->session_id); - if (!rtp_c) { - /* always prefer UDP */ - th = find_transport(h, RTSP_LOWER_TRANSPORT_UDP); - if (!th) { - th = find_transport(h, RTSP_LOWER_TRANSPORT_TCP); - if (!th) { - rtsp_reply_error(c, RTSP_STATUS_TRANSPORT); - return; - } - } - - rtp_c = rtp_new_connection(&c->from_addr, stream, h->session_id, - th->lower_transport); - if (!rtp_c) { - rtsp_reply_error(c, RTSP_STATUS_BANDWIDTH); - return; - } - - /* open input stream */ - if (open_input_stream(rtp_c, "") < 0) { - rtsp_reply_error(c, RTSP_STATUS_INTERNAL); - return; - } - } - - /* test if stream is OK (test needed because several SETUP needs - * to be done for a given file) */ - if (rtp_c->stream != stream) { - rtsp_reply_error(c, RTSP_STATUS_SERVICE); - return; - } - - /* test if stream is already set up */ - if (rtp_c->rtp_ctx[stream_index]) { - rtsp_reply_error(c, RTSP_STATUS_STATE); - return; - } - - /* check transport */ - th = find_transport(h, rtp_c->rtp_protocol); - if (!th || (th->lower_transport == RTSP_LOWER_TRANSPORT_UDP && - th->client_port_min <= 0)) { - rtsp_reply_error(c, RTSP_STATUS_TRANSPORT); - return; - } - - /* setup default options */ - setup.transport_option[0] = '\0'; - dest_addr = rtp_c->from_addr; - dest_addr.sin_port = htons(th->client_port_min); - - /* setup stream */ - if (rtp_new_av_stream(rtp_c, stream_index, &dest_addr, c) < 0) { - rtsp_reply_error(c, RTSP_STATUS_TRANSPORT); - return; - } - - /* now everything is OK, so we can send the connection parameters */ - rtsp_reply_header(c, RTSP_STATUS_OK); - /* session ID */ - avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id); - - switch(rtp_c->rtp_protocol) { - case RTSP_LOWER_TRANSPORT_UDP: - rtp_port = ff_rtp_get_local_rtp_port(rtp_c->rtp_handles[stream_index]); - rtcp_port = ff_rtp_get_local_rtcp_port(rtp_c->rtp_handles[stream_index]); - avio_printf(c->pb, "Transport: RTP/AVP/UDP;unicast;" - "client_port=%d-%d;server_port=%d-%d", - th->client_port_min, th->client_port_max, - rtp_port, rtcp_port); - break; - case RTSP_LOWER_TRANSPORT_TCP: - avio_printf(c->pb, "Transport: RTP/AVP/TCP;interleaved=%d-%d", - stream_index * 2, stream_index * 2 + 1); - break; - default: - break; - } - if (setup.transport_option[0] != '\0') - avio_printf(c->pb, ";%s", setup.transport_option); - avio_printf(c->pb, "\r\n"); - - - avio_printf(c->pb, "\r\n"); -} - - -/** - * find an RTP connection by using the session ID. Check consistency - * with filename - */ -static HTTPContext *find_rtp_session_with_url(const char *url, - const char *session_id) -{ - HTTPContext *rtp_c; - char path1[1024]; - const char *path; - char buf[1024]; - int s, len; - - rtp_c = find_rtp_session(session_id); - if (!rtp_c) - return NULL; - - /* find which URL is asked */ - av_url_split(NULL, 0, NULL, 0, NULL, 0, NULL, path1, sizeof(path1), url); - path = path1; - if (*path == '/') - path++; - if(!strcmp(path, rtp_c->stream->filename)) return rtp_c; - for(s=0; sstream->nb_streams; ++s) { - snprintf(buf, sizeof(buf), "%s/streamid=%d", - rtp_c->stream->filename, s); - if(!strncmp(path, buf, sizeof(buf))) - /* XXX: Should we reply with RTSP_STATUS_ONLY_AGGREGATE - * if nb_streams>1? */ - return rtp_c; - } - len = strlen(path); - if (len > 0 && path[len - 1] == '/' && - !strncmp(path, rtp_c->stream->filename, len - 1)) - return rtp_c; - return NULL; -} - -static void rtsp_cmd_play(HTTPContext *c, const char *url, RTSPMessageHeader *h) -{ - HTTPContext *rtp_c; - - rtp_c = find_rtp_session_with_url(url, h->session_id); - if (!rtp_c) { - rtsp_reply_error(c, RTSP_STATUS_SESSION); - return; - } - - if (rtp_c->state != HTTPSTATE_SEND_DATA && - rtp_c->state != HTTPSTATE_WAIT_FEED && - rtp_c->state != HTTPSTATE_READY) { - rtsp_reply_error(c, RTSP_STATUS_STATE); - return; - } - - rtp_c->state = HTTPSTATE_SEND_DATA; - - /* now everything is OK, so we can send the connection parameters */ - rtsp_reply_header(c, RTSP_STATUS_OK); - /* session ID */ - avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id); - avio_printf(c->pb, "\r\n"); -} - -static void rtsp_cmd_interrupt(HTTPContext *c, const char *url, - RTSPMessageHeader *h, int pause_only) -{ - HTTPContext *rtp_c; - - rtp_c = find_rtp_session_with_url(url, h->session_id); - if (!rtp_c) { - rtsp_reply_error(c, RTSP_STATUS_SESSION); - return; - } - - if (pause_only) { - if (rtp_c->state != HTTPSTATE_SEND_DATA && - rtp_c->state != HTTPSTATE_WAIT_FEED) { - rtsp_reply_error(c, RTSP_STATUS_STATE); - return; - } - rtp_c->state = HTTPSTATE_READY; - rtp_c->first_pts = AV_NOPTS_VALUE; - } - - /* now everything is OK, so we can send the connection parameters */ - rtsp_reply_header(c, RTSP_STATUS_OK); - /* session ID */ - avio_printf(c->pb, "Session: %s\r\n", rtp_c->session_id); - avio_printf(c->pb, "\r\n"); - - if (!pause_only) - close_connection(rtp_c); -} - -/********************************************************************/ -/* RTP handling */ - -static HTTPContext *rtp_new_connection(struct sockaddr_in *from_addr, - FFServerStream *stream, - const char *session_id, - enum RTSPLowerTransport rtp_protocol) -{ - HTTPContext *c = NULL; - const char *proto_str; - - /* XXX: should output a warning page when coming - * close to the connection limit */ - if (nb_connections >= config.nb_max_connections) - goto fail; - - /* add a new connection */ - c = av_mallocz(sizeof(HTTPContext)); - if (!c) - goto fail; - - c->fd = -1; - c->poll_entry = NULL; - c->from_addr = *from_addr; - c->buffer_size = IOBUFFER_INIT_SIZE; - c->buffer = av_malloc(c->buffer_size); - if (!c->buffer) - goto fail; - nb_connections++; - c->stream = stream; - av_strlcpy(c->session_id, session_id, sizeof(c->session_id)); - c->state = HTTPSTATE_READY; - c->is_packetized = 1; - c->rtp_protocol = rtp_protocol; - - /* protocol is shown in statistics */ - switch(c->rtp_protocol) { - case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: - proto_str = "MCAST"; - break; - case RTSP_LOWER_TRANSPORT_UDP: - proto_str = "UDP"; - break; - case RTSP_LOWER_TRANSPORT_TCP: - proto_str = "TCP"; - break; - default: - proto_str = "???"; - break; - } - av_strlcpy(c->protocol, "RTP/", sizeof(c->protocol)); - av_strlcat(c->protocol, proto_str, sizeof(c->protocol)); - - current_bandwidth += stream->bandwidth; - - c->next = first_http_ctx; - first_http_ctx = c; - return c; - - fail: - if (c) { - av_freep(&c->buffer); - av_free(c); - } - return NULL; -} - -/** - * add a new RTP stream in an RTP connection (used in RTSP SETUP - * command). If RTP/TCP protocol is used, TCP connection 'rtsp_c' is - * used. - */ -static int rtp_new_av_stream(HTTPContext *c, - int stream_index, struct sockaddr_in *dest_addr, - HTTPContext *rtsp_c) -{ - AVFormatContext *ctx; - AVStream *st; - char *ipaddr; - URLContext *h = NULL; - uint8_t *dummy_buf; - int max_packet_size; - void *st_internal; - - /* now we can open the relevant output stream */ - ctx = avformat_alloc_context(); - if (!ctx) - return -1; - ctx->oformat = av_guess_format("rtp", NULL, NULL); - - st = avformat_new_stream(ctx, NULL); - if (!st) - goto fail; - - st_internal = st->internal; - - if (!c->stream->feed || - c->stream->feed == c->stream) - unlayer_stream(st, c->stream->streams[stream_index]); - else - unlayer_stream(st, - c->stream->feed->streams[c->stream->feed_streams[stream_index]]); - av_assert0(st->priv_data == NULL); - av_assert0(st->internal == st_internal); - - /* build destination RTP address */ - ipaddr = inet_ntoa(dest_addr->sin_addr); - - switch(c->rtp_protocol) { - case RTSP_LOWER_TRANSPORT_UDP: - case RTSP_LOWER_TRANSPORT_UDP_MULTICAST: - /* RTP/UDP case */ - - /* XXX: also pass as parameter to function ? */ - if (c->stream->is_multicast) { - int ttl; - ttl = c->stream->multicast_ttl; - if (!ttl) - ttl = 16; - snprintf(ctx->filename, sizeof(ctx->filename), - "rtp://%s:%d?multicast=1&ttl=%d", - ipaddr, ntohs(dest_addr->sin_port), ttl); - } else { - snprintf(ctx->filename, sizeof(ctx->filename), - "rtp://%s:%d", ipaddr, ntohs(dest_addr->sin_port)); - } - - if (ffurl_open(&h, ctx->filename, AVIO_FLAG_WRITE, NULL, NULL) < 0) - goto fail; - c->rtp_handles[stream_index] = h; - max_packet_size = h->max_packet_size; - break; - case RTSP_LOWER_TRANSPORT_TCP: - /* RTP/TCP case */ - c->rtsp_c = rtsp_c; - max_packet_size = RTSP_TCP_MAX_PACKET_SIZE; - break; - default: - goto fail; - } - - http_log("%s:%d - - \"PLAY %s/streamid=%d %s\"\n", - ipaddr, ntohs(dest_addr->sin_port), - c->stream->filename, stream_index, c->protocol); - - /* normally, no packets should be output here, but the packet size may - * be checked */ - if (ffio_open_dyn_packet_buf(&ctx->pb, max_packet_size) < 0) - /* XXX: close stream */ - goto fail; - - if (avformat_write_header(ctx, NULL) < 0) { - fail: - if (h) - ffurl_close(h); - av_free(st); - av_free(ctx); - return -1; - } - avio_close_dyn_buf(ctx->pb, &dummy_buf); - ctx->pb = NULL; - av_free(dummy_buf); - - c->rtp_ctx[stream_index] = ctx; - return 0; -} - -/********************************************************************/ -/* ffserver initialization */ - -/* FIXME: This code should use avformat_new_stream() */ -static LayeredAVStream *add_av_stream1(FFServerStream *stream, - AVCodecContext *codec, int copy) -{ - LayeredAVStream *fst; - - if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams)) - return NULL; - - fst = av_mallocz(sizeof(*fst)); - if (!fst) - return NULL; - if (copy) { - fst->codec = avcodec_alloc_context3(codec->codec); - if (!fst->codec) { - av_free(fst); - return NULL; - } - avcodec_copy_context(fst->codec, codec); - } else - /* live streams must use the actual feed's codec since it may be - * updated later to carry extradata needed by them. - */ - fst->codec = codec; - - //NOTE we previously allocated internal & internal->avctx, these seemed uneeded though - fst->codecpar = avcodec_parameters_alloc(); - fst->index = stream->nb_streams; - fst->time_base = codec->time_base; - fst->pts_wrap_bits = 33; - fst->sample_aspect_ratio = codec->sample_aspect_ratio; - stream->streams[stream->nb_streams++] = fst; - return fst; -} - -/* return the stream number in the feed */ -static int add_av_stream(FFServerStream *feed, LayeredAVStream *st) -{ - LayeredAVStream *fst; - AVCodecContext *av, *av1; - int i; - - av = st->codec; - for(i=0;inb_streams;i++) { - av1 = feed->streams[i]->codec; - if (av1->codec_id == av->codec_id && - av1->codec_type == av->codec_type && - av1->bit_rate == av->bit_rate) { - - switch(av->codec_type) { - case AVMEDIA_TYPE_AUDIO: - if (av1->channels == av->channels && - av1->sample_rate == av->sample_rate) - return i; - break; - case AVMEDIA_TYPE_VIDEO: - if (av1->width == av->width && - av1->height == av->height && - av1->time_base.den == av->time_base.den && - av1->time_base.num == av->time_base.num && - av1->gop_size == av->gop_size) - return i; - break; - default: - abort(); - } - } - } - - fst = add_av_stream1(feed, av, 0); - if (!fst) - return -1; - if (st->recommended_encoder_configuration) - fst->recommended_encoder_configuration = - av_strdup(st->recommended_encoder_configuration); - return feed->nb_streams - 1; -} - -static void remove_stream(FFServerStream *stream) -{ - FFServerStream **ps; - ps = &config.first_stream; - while (*ps) { - if (*ps == stream) - *ps = (*ps)->next; - else - ps = &(*ps)->next; - } -} - -/* compute the needed AVStream for each file */ -static void build_file_streams(void) -{ - FFServerStream *stream; - AVFormatContext *infile; - int i, ret; - - /* gather all streams */ - for(stream = config.first_stream; stream; stream = stream->next) { - infile = NULL; - - if (stream->stream_type != STREAM_TYPE_LIVE || stream->feed) - continue; - - /* the stream comes from a file */ - /* try to open the file */ - /* open stream */ - - - /* specific case: if transport stream output to RTP, - * we use a raw transport stream reader */ - if (stream->fmt && !strcmp(stream->fmt->name, "rtp")) - av_dict_set(&stream->in_opts, "mpeg2ts_compute_pcr", "1", 0); - - if (!stream->feed_filename[0]) { - http_log("Unspecified feed file for stream '%s'\n", - stream->filename); - goto fail; - } - - http_log("Opening feed file '%s' for stream '%s'\n", - stream->feed_filename, stream->filename); - - ret = avformat_open_input(&infile, stream->feed_filename, - stream->ifmt, &stream->in_opts); - if (ret < 0) { - http_log("Could not open '%s': %s\n", stream->feed_filename, - av_err2str(ret)); - /* remove stream (no need to spend more time on it) */ - fail: - remove_stream(stream); - } else { - /* find all the AVStreams inside and reference them in - * 'stream' */ - if (avformat_find_stream_info(infile, NULL) < 0) { - http_log("Could not find codec parameters from '%s'\n", - stream->feed_filename); - avformat_close_input(&infile); - goto fail; - } - - for(i=0;inb_streams;i++) - add_av_stream1(stream, infile->streams[i]->codec, 1); - - avformat_close_input(&infile); - } - } -} - -static inline -int check_codec_match(LayeredAVStream *ccf, AVStream *ccs, int stream) -{ - int matches = 1; - -/* FIXME: Missed check on AVCodecContext.flags */ -#define CHECK_CODEC(x) (ccf->codecpar->x != ccs->codecpar->x) - if (CHECK_CODEC(codec_id) || CHECK_CODEC(codec_type)) { - http_log("Codecs do not match for stream %d\n", stream); - matches = 0; - } else if (CHECK_CODEC(bit_rate)) { - http_log("Codec bitrates do not match for stream %d\n", stream); - matches = 0; - } else if (ccf->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - if (av_cmp_q(ccf->time_base, ccs->time_base) || - CHECK_CODEC(width) || CHECK_CODEC(height)) { - http_log("Codec width, height or framerate do not match for stream %d\n", stream); - matches = 0; - } - } else if (ccf->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - if (CHECK_CODEC(sample_rate) || - CHECK_CODEC(channels) || - CHECK_CODEC(frame_size)) { - http_log("Codec sample_rate, channels, frame_size do not match for stream %d\n", stream); - matches = 0; - } - } else { - http_log("Unknown codec type for stream %d\n", stream); - matches = 0; - } - - return matches; -} - -/* compute the needed AVStream for each feed */ -static int build_feed_streams(void) -{ - FFServerStream *stream, *feed; - int i, fd; - - /* gather all streams */ - for(stream = config.first_stream; stream; stream = stream->next) { - feed = stream->feed; - if (!feed) - continue; - - if (stream->is_feed) { - for(i=0;inb_streams;i++) - stream->feed_streams[i] = i; - continue; - } - /* we handle a stream coming from a feed */ - for(i=0;inb_streams;i++) - stream->feed_streams[i] = add_av_stream(feed, stream->streams[i]); - } - - /* create feed files if needed */ - for(feed = config.first_feed; feed; feed = feed->next_feed) { - - if (avio_check(feed->feed_filename, AVIO_FLAG_READ) > 0) { - AVFormatContext *s = NULL; - int matches = 0; - - /* See if it matches */ - - if (avformat_open_input(&s, feed->feed_filename, NULL, NULL) < 0) { - http_log("Deleting feed file '%s' as it appears " - "to be corrupt\n", - feed->feed_filename); - goto drop; - } - - /* set buffer size */ - if (ffio_set_buf_size(s->pb, FFM_PACKET_SIZE) < 0) { - http_log("Failed to set buffer size\n"); - avformat_close_input(&s); - goto bail; - } - - /* Now see if it matches */ - if (s->nb_streams != feed->nb_streams) { - http_log("Deleting feed file '%s' as stream counts " - "differ (%d != %d)\n", - feed->feed_filename, s->nb_streams, feed->nb_streams); - goto drop; - } - - matches = 1; - for(i=0;inb_streams;i++) { - AVStream *ss; - LayeredAVStream *sf; - - sf = feed->streams[i]; - ss = s->streams[i]; - - if (sf->index != ss->index || sf->id != ss->id) { - http_log("Index & Id do not match for stream %d (%s)\n", - i, feed->feed_filename); - matches = 0; - break; - } - - matches = check_codec_match (sf, ss, i); - if (!matches) - break; - } - -drop: - if (s) - avformat_close_input(&s); - - if (!matches) { - if (feed->readonly) { - http_log("Unable to delete read-only feed file '%s'\n", - feed->feed_filename); - goto bail; - } - unlink(feed->feed_filename); - } - } - - if (avio_check(feed->feed_filename, AVIO_FLAG_WRITE) <= 0) { - AVFormatContext *s = avformat_alloc_context(); - - if (!s) { - http_log("Failed to allocate context\n"); - goto bail; - } - - if (feed->readonly) { - http_log("Unable to create feed file '%s' as it is " - "marked readonly\n", - feed->feed_filename); - avformat_free_context(s); - goto bail; - } - - /* only write the header of the ffm file */ - if (avio_open(&s->pb, feed->feed_filename, AVIO_FLAG_WRITE) < 0) { - http_log("Could not open output feed file '%s'\n", - feed->feed_filename); - avformat_free_context(s); - goto bail; - } - s->oformat = feed->fmt; - for (i = 0; inb_streams; i++) { - AVStream *st = avformat_new_stream(s, NULL); // FIXME free this - if (!st) { - http_log("Failed to allocate stream\n"); - goto bail; - } - unlayer_stream(st, feed->streams[i]); - } - if (avformat_write_header(s, NULL) < 0) { - http_log("Container doesn't support the required parameters\n"); - avio_closep(&s->pb); - s->streams = NULL; - s->nb_streams = 0; - avformat_free_context(s); - goto bail; - } - /* XXX: need better API */ - av_freep(&s->priv_data); - avio_closep(&s->pb); - s->streams = NULL; - s->nb_streams = 0; - avformat_free_context(s); - } - - /* get feed size and write index */ - fd = open(feed->feed_filename, O_RDONLY); - if (fd < 0) { - http_log("Could not open output feed file '%s'\n", - feed->feed_filename); - goto bail; - } - - feed->feed_write_index = FFMAX(ffm_read_write_index(fd), - FFM_PACKET_SIZE); - feed->feed_size = lseek(fd, 0, SEEK_END); - /* ensure that we do not wrap before the end of file */ - if (feed->feed_max_size && feed->feed_max_size < feed->feed_size) - feed->feed_max_size = feed->feed_size; - - close(fd); - } - return 0; - -bail: - return -1; -} - -/* compute the bandwidth used by each stream */ -static void compute_bandwidth(void) -{ - unsigned bandwidth; - int i; - FFServerStream *stream; - - for(stream = config.first_stream; stream; stream = stream->next) { - bandwidth = 0; - for(i=0;inb_streams;i++) { - LayeredAVStream *st = stream->streams[i]; - switch(st->codec->codec_type) { - case AVMEDIA_TYPE_AUDIO: - case AVMEDIA_TYPE_VIDEO: - bandwidth += st->codec->bit_rate; - break; - default: - break; - } - } - stream->bandwidth = (bandwidth + 999) / 1000; - } -} - -static void handle_child_exit(int sig) -{ - pid_t pid; - int status; - time_t uptime; - - while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { - FFServerStream *feed; - - for (feed = config.first_feed; feed; feed = feed->next) { - if (feed->pid != pid) - continue; - - uptime = time(0) - feed->pid_start; - feed->pid = 0; - fprintf(stderr, - "%s: Pid %"PRId64" exited with status %d after %"PRId64" " - "seconds\n", - feed->filename, (int64_t) pid, status, (int64_t)uptime); - - if (uptime < 30) - /* Turn off any more restarts */ - ffserver_free_child_args(&feed->child_argv); - } - } - - need_to_start_children = 1; -} - -static void opt_debug(void) -{ - config.debug = 1; - snprintf(config.logfilename, sizeof(config.logfilename), "-"); -} - -void show_help_default(const char *opt, const char *arg) -{ - printf("usage: ffserver [options]\n" - "Hyper fast multi format Audio/Video streaming server\n"); - printf("\n"); - show_help_options(options, "Main options:", 0, 0, 0); -} - -static const OptionDef options[] = { - CMDUTILS_COMMON_OPTIONS - { "n", OPT_BOOL, {(void *)&no_launch }, "enable no-launch mode" }, - { "d", 0, {(void*)opt_debug}, "enable debug mode" }, - { "f", HAS_ARG | OPT_STRING, {(void*)&config.filename }, "use configfile instead of /etc/ffserver.conf", "configfile" }, - { NULL }, -}; - -int main(int argc, char **argv) -{ - struct sigaction sigact = { { 0 } }; - int cfg_parsed; - int ret = EXIT_FAILURE; - - init_dynload(); - - config.filename = av_strdup("/etc/ffserver.conf"); - - parse_loglevel(argc, argv, options); - av_register_all(); - avformat_network_init(); - - show_banner(argc, argv, options); - - my_program_name = argv[0]; - - parse_options(NULL, argc, argv, options, NULL); - - unsetenv("http_proxy"); /* Kill the http_proxy */ - - av_lfg_init(&random_state, av_get_random_seed()); - - sigact.sa_handler = handle_child_exit; - sigact.sa_flags = SA_NOCLDSTOP | SA_RESTART; - sigaction(SIGCHLD, &sigact, 0); - - if ((cfg_parsed = ffserver_parse_ffconfig(config.filename, &config)) < 0) { - fprintf(stderr, "Error reading configuration file '%s': %s\n", - config.filename, av_err2str(cfg_parsed)); - goto bail; - } - - /* open log file if needed */ - if (config.logfilename[0] != '\0') { - if (!strcmp(config.logfilename, "-")) - logfile = stdout; - else - logfile = fopen(config.logfilename, "a"); - av_log_set_callback(http_av_log); - } - - build_file_streams(); - - if (build_feed_streams() < 0) { - http_log("Could not setup feed streams\n"); - goto bail; - } - - compute_bandwidth(); - - /* signal init */ - signal(SIGPIPE, SIG_IGN); - - if (http_server() < 0) { - http_log("Could not start server\n"); - goto bail; - } - - ret=EXIT_SUCCESS; - -bail: - av_freep (&config.filename); - avformat_network_deinit(); - return ret; -} diff --git a/fftools/ffserver_config.c b/fftools/ffserver_config.c deleted file mode 100644 index 54135be989c90..0000000000000 --- a/fftools/ffserver_config.c +++ /dev/null @@ -1,1325 +0,0 @@ -/* - * Copyright (c) 2000, 2001, 2002 Fabrice Bellard - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include "libavutil/opt.h" -#include "libavutil/parseutils.h" -#include "libavutil/avstring.h" -#include "libavutil/pixdesc.h" -#include "libavutil/avassert.h" - -#include "cmdutils.h" -#include "ffserver_config.h" - -#define MAX_CHILD_ARGS 64 - -static int ffserver_save_avoption(const char *opt, const char *arg, int type, - FFServerConfig *config); -static void vreport_config_error(const char *filename, int line_num, - int log_level, int *errors, const char *fmt, - va_list vl); -static void report_config_error(const char *filename, int line_num, - int log_level, int *errors, const char *fmt, - ...); - -#define ERROR(...) report_config_error(config->filename, config->line_num,\ - AV_LOG_ERROR, &config->errors, __VA_ARGS__) -#define WARNING(...) report_config_error(config->filename, config->line_num,\ - AV_LOG_WARNING, &config->warnings, __VA_ARGS__) - -/* FIXME: make ffserver work with IPv6 */ -/* resolve host with also IP address parsing */ -static int resolve_host(struct in_addr *sin_addr, const char *hostname) -{ - - if (!ff_inet_aton(hostname, sin_addr)) { -#if HAVE_GETADDRINFO - struct addrinfo *ai, *cur; - struct addrinfo hints = { 0 }; - hints.ai_family = AF_INET; - if (getaddrinfo(hostname, NULL, &hints, &ai)) - return -1; - /* getaddrinfo returns a linked list of addrinfo structs. - * Even if we set ai_family = AF_INET above, make sure - * that the returned one actually is of the correct type. */ - for (cur = ai; cur; cur = cur->ai_next) { - if (cur->ai_family == AF_INET) { - *sin_addr = ((struct sockaddr_in *)cur->ai_addr)->sin_addr; - freeaddrinfo(ai); - return 0; - } - } - freeaddrinfo(ai); - return -1; -#else - struct hostent *hp; - hp = gethostbyname(hostname); - if (!hp) - return -1; - memcpy(sin_addr, hp->h_addr_list[0], sizeof(struct in_addr)); -#endif - } - return 0; -} - -void ffserver_get_arg(char *buf, int buf_size, const char **pp) -{ - const char *p; - char *q; - int quote = 0; - - p = *pp; - q = buf; - - while (av_isspace(*p)) p++; - - if (*p == '\"' || *p == '\'') - quote = *p++; - - while (*p != '\0') { - if (quote && *p == quote || !quote && av_isspace(*p)) - break; - if ((q - buf) < buf_size - 1) - *q++ = *p; - p++; - } - - *q = '\0'; - if (quote && *p == quote) - p++; - *pp = p; -} - -void ffserver_parse_acl_row(FFServerStream *stream, FFServerStream* feed, - FFServerIPAddressACL *ext_acl, - const char *p, const char *filename, int line_num) -{ - char arg[1024]; - FFServerIPAddressACL acl; - FFServerIPAddressACL *nacl; - FFServerIPAddressACL **naclp; - - ffserver_get_arg(arg, sizeof(arg), &p); - if (av_strcasecmp(arg, "allow") == 0) - acl.action = IP_ALLOW; - else if (av_strcasecmp(arg, "deny") == 0) - acl.action = IP_DENY; - else { - fprintf(stderr, "%s:%d: ACL action '%s' should be ALLOW or DENY.\n", - filename, line_num, arg); - goto bail; - } - - ffserver_get_arg(arg, sizeof(arg), &p); - - if (resolve_host(&acl.first, arg)) { - fprintf(stderr, - "%s:%d: ACL refers to invalid host or IP address '%s'\n", - filename, line_num, arg); - goto bail; - } - - acl.last = acl.first; - - ffserver_get_arg(arg, sizeof(arg), &p); - - if (arg[0]) { - if (resolve_host(&acl.last, arg)) { - fprintf(stderr, - "%s:%d: ACL refers to invalid host or IP address '%s'\n", - filename, line_num, arg); - goto bail; - } - } - - nacl = av_mallocz(sizeof(*nacl)); - if (!nacl) { - fprintf(stderr, "Failed to allocate FFServerIPAddressACL\n"); - goto bail; - } - - naclp = 0; - - acl.next = 0; - *nacl = acl; - - if (stream) - naclp = &stream->acl; - else if (feed) - naclp = &feed->acl; - else if (ext_acl) - naclp = &ext_acl; - else - fprintf(stderr, "%s:%d: ACL found not in or \n", - filename, line_num); - - if (naclp) { - while (*naclp) - naclp = &(*naclp)->next; - - *naclp = nacl; - } else - av_free(nacl); - -bail: - return; - -} - -/* add a codec and set the default parameters */ -static void add_codec(FFServerStream *stream, AVCodecContext *av, - FFServerConfig *config) -{ - LayeredAVStream *st; - AVDictionary **opts, *recommended = NULL; - char *enc_config; - - if(stream->nb_streams >= FF_ARRAY_ELEMS(stream->streams)) - return; - - opts = av->codec_type == AVMEDIA_TYPE_AUDIO ? - &config->audio_opts : &config->video_opts; - av_dict_copy(&recommended, *opts, 0); - av_opt_set_dict2(av->priv_data, opts, AV_OPT_SEARCH_CHILDREN); - av_opt_set_dict2(av, opts, AV_OPT_SEARCH_CHILDREN); - - if (av_dict_count(*opts)) - av_log(NULL, AV_LOG_WARNING, - "Something is wrong, %d options are not set!\n", - av_dict_count(*opts)); - - if (!config->stream_use_defaults) { - switch(av->codec_type) { - case AVMEDIA_TYPE_AUDIO: - if (av->bit_rate == 0) - report_config_error(config->filename, config->line_num, - AV_LOG_ERROR, &config->errors, - "audio bit rate is not set\n"); - if (av->sample_rate == 0) - report_config_error(config->filename, config->line_num, - AV_LOG_ERROR, &config->errors, - "audio sample rate is not set\n"); - break; - case AVMEDIA_TYPE_VIDEO: - if (av->width == 0 || av->height == 0) - report_config_error(config->filename, config->line_num, - AV_LOG_ERROR, &config->errors, - "video size is not set\n"); - break; - default: - av_assert0(0); - } - goto done; - } - - /* stream_use_defaults = true */ - - /* compute default parameters */ - switch(av->codec_type) { - case AVMEDIA_TYPE_AUDIO: - if (!av_dict_get(recommended, "b", NULL, 0)) { - av->bit_rate = 64000; - av_dict_set_int(&recommended, "b", av->bit_rate, 0); - WARNING("Setting default value for audio bit rate = %d. " - "Use NoDefaults to disable it.\n", - av->bit_rate); - } - if (!av_dict_get(recommended, "ar", NULL, 0)) { - av->sample_rate = 22050; - av_dict_set_int(&recommended, "ar", av->sample_rate, 0); - WARNING("Setting default value for audio sample rate = %d. " - "Use NoDefaults to disable it.\n", - av->sample_rate); - } - if (!av_dict_get(recommended, "ac", NULL, 0)) { - av->channels = 1; - av_dict_set_int(&recommended, "ac", av->channels, 0); - WARNING("Setting default value for audio channel count = %d. " - "Use NoDefaults to disable it.\n", - av->channels); - } - break; - case AVMEDIA_TYPE_VIDEO: - if (!av_dict_get(recommended, "b", NULL, 0)) { - av->bit_rate = 64000; - av_dict_set_int(&recommended, "b", av->bit_rate, 0); - WARNING("Setting default value for video bit rate = %d. " - "Use NoDefaults to disable it.\n", - av->bit_rate); - } - if (!av_dict_get(recommended, "time_base", NULL, 0)){ - av->time_base.den = 5; - av->time_base.num = 1; - av_dict_set(&recommended, "time_base", "1/5", 0); - WARNING("Setting default value for video frame rate = %d. " - "Use NoDefaults to disable it.\n", - av->time_base.den); - } - if (!av_dict_get(recommended, "video_size", NULL, 0)) { - av->width = 160; - av->height = 128; - av_dict_set(&recommended, "video_size", "160x128", 0); - WARNING("Setting default value for video size = %dx%d. " - "Use NoDefaults to disable it.\n", - av->width, av->height); - } - /* Bitrate tolerance is less for streaming */ - if (!av_dict_get(recommended, "bt", NULL, 0)) { - av->bit_rate_tolerance = FFMAX(av->bit_rate / 4, - (int64_t)av->bit_rate*av->time_base.num/av->time_base.den); - av_dict_set_int(&recommended, "bt", av->bit_rate_tolerance, 0); - WARNING("Setting default value for video bit rate tolerance = %d. " - "Use NoDefaults to disable it.\n", - av->bit_rate_tolerance); - } - - if (!av_dict_get(recommended, "rc_eq", NULL, 0)) { - av->rc_eq = av_strdup("tex^qComp"); - av_dict_set(&recommended, "rc_eq", "tex^qComp", 0); - WARNING("Setting default value for video rate control equation = " - "%s. Use NoDefaults to disable it.\n", - av->rc_eq); - } - if (!av_dict_get(recommended, "maxrate", NULL, 0)) { - av->rc_max_rate = av->bit_rate * 2; - av_dict_set_int(&recommended, "maxrate", av->rc_max_rate, 0); - WARNING("Setting default value for video max rate = %d. " - "Use NoDefaults to disable it.\n", - av->rc_max_rate); - } - - if (av->rc_max_rate && !av_dict_get(recommended, "bufsize", NULL, 0)) { - av->rc_buffer_size = av->rc_max_rate; - av_dict_set_int(&recommended, "bufsize", av->rc_buffer_size, 0); - WARNING("Setting default value for video buffer size = %d. " - "Use NoDefaults to disable it.\n", - av->rc_buffer_size); - } - break; - default: - abort(); - } - -done: - st = av_mallocz(sizeof(*st)); - if (!st) - return; - av_dict_get_string(recommended, &enc_config, '=', ','); - av_dict_free(&recommended); - st->recommended_encoder_configuration = enc_config; - st->codec = av; - st->codecpar = avcodec_parameters_alloc(); - avcodec_parameters_from_context(st->codecpar, av); - stream->streams[stream->nb_streams++] = st; -} - -static int ffserver_set_codec(AVCodecContext *ctx, const char *codec_name, - FFServerConfig *config) -{ - int ret; - AVCodec *codec = avcodec_find_encoder_by_name(codec_name); - if (!codec || codec->type != ctx->codec_type) { - report_config_error(config->filename, config->line_num, AV_LOG_ERROR, - &config->errors, - "Invalid codec name: '%s'\n", codec_name); - return 0; - } - if (ctx->codec_id == AV_CODEC_ID_NONE && !ctx->priv_data) { - if ((ret = avcodec_get_context_defaults3(ctx, codec)) < 0) - return ret; - ctx->codec = codec; - } - if (ctx->codec_id != codec->id) - report_config_error(config->filename, config->line_num, AV_LOG_ERROR, - &config->errors, - "Inconsistent configuration: trying to set '%s' " - "codec option, but '%s' codec is used previously\n", - codec_name, avcodec_get_name(ctx->codec_id)); - return 0; -} - -static int ffserver_opt_preset(const char *arg, int type, FFServerConfig *config) -{ - FILE *f=NULL; - char filename[1000], tmp[1000], tmp2[1000], line[1000]; - int ret = 0; - AVCodecContext *avctx; - const AVCodec *codec; - - switch(type) { - case AV_OPT_FLAG_AUDIO_PARAM: - avctx = config->dummy_actx; - break; - case AV_OPT_FLAG_VIDEO_PARAM: - avctx = config->dummy_vctx; - break; - default: - av_assert0(0); - } - codec = avcodec_find_encoder(avctx->codec_id); - - if (!(f = get_preset_file(filename, sizeof(filename), arg, 0, - codec ? codec->name : NULL))) { - av_log(NULL, AV_LOG_ERROR, "File for preset '%s' not found\n", arg); - return AVERROR(EINVAL); - } - - while(!feof(f)){ - int e= fscanf(f, "%999[^\n]\n", line) - 1; - if(line[0] == '#' && !e) - continue; - e|= sscanf(line, "%999[^=]=%999[^\n]\n", tmp, tmp2) - 2; - if(e){ - av_log(NULL, AV_LOG_ERROR, "%s: Invalid syntax: '%s'\n", filename, - line); - ret = AVERROR(EINVAL); - break; - } - if (!strcmp(tmp, "acodec") && avctx->codec_type == AVMEDIA_TYPE_AUDIO || - !strcmp(tmp, "vcodec") && avctx->codec_type == AVMEDIA_TYPE_VIDEO) - { - if (ffserver_set_codec(avctx, tmp2, config) < 0) - break; - } else if (!strcmp(tmp, "scodec")) { - av_log(NULL, AV_LOG_ERROR, "Subtitles preset found.\n"); - ret = AVERROR(EINVAL); - break; - } else if (ffserver_save_avoption(tmp, tmp2, type, config) < 0) - break; - } - - fclose(f); - - return ret; -} - -static AVOutputFormat *ffserver_guess_format(const char *short_name, - const char *filename, - const char *mime_type) -{ - AVOutputFormat *fmt = av_guess_format(short_name, filename, mime_type); - - if (fmt) { - AVOutputFormat *stream_fmt; - char stream_format_name[64]; - - snprintf(stream_format_name, sizeof(stream_format_name), "%s_stream", - fmt->name); - stream_fmt = av_guess_format(stream_format_name, NULL, NULL); - - if (stream_fmt) - fmt = stream_fmt; - } - - return fmt; -} - -static void vreport_config_error(const char *filename, int line_num, - int log_level, int *errors, const char *fmt, - va_list vl) -{ - av_log(NULL, log_level, "%s:%d: ", filename, line_num); - av_vlog(NULL, log_level, fmt, vl); - if (errors) - (*errors)++; -} - -static void report_config_error(const char *filename, int line_num, - int log_level, int *errors, - const char *fmt, ...) -{ - va_list vl; - va_start(vl, fmt); - vreport_config_error(filename, line_num, log_level, errors, fmt, vl); - va_end(vl); -} - -static int ffserver_set_int_param(int *dest, const char *value, int factor, - int min, int max, FFServerConfig *config, - const char *error_msg, ...) -{ - int tmp; - char *tailp; - if (!value || !value[0]) - goto error; - errno = 0; - tmp = strtol(value, &tailp, 0); - if (tmp < min || tmp > max) - goto error; - if (factor) { - if (tmp == INT_MIN || FFABS(tmp) > INT_MAX / FFABS(factor)) - goto error; - tmp *= factor; - } - if (tailp[0] || errno) - goto error; - if (dest) - *dest = tmp; - return 0; - error: - if (config) { - va_list vl; - va_start(vl, error_msg); - vreport_config_error(config->filename, config->line_num, AV_LOG_ERROR, - &config->errors, error_msg, vl); - va_end(vl); - } - return AVERROR(EINVAL); -} - -static int ffserver_set_float_param(float *dest, const char *value, - float factor, float min, float max, - FFServerConfig *config, - const char *error_msg, ...) -{ - double tmp; - char *tailp; - if (!value || !value[0]) - goto error; - errno = 0; - tmp = strtod(value, &tailp); - if (tmp < min || tmp > max) - goto error; - if (factor) - tmp *= factor; - if (tailp[0] || errno) - goto error; - if (dest) - *dest = tmp; - return 0; - error: - if (config) { - va_list vl; - va_start(vl, error_msg); - vreport_config_error(config->filename, config->line_num, AV_LOG_ERROR, - &config->errors, error_msg, vl); - va_end(vl); - } - return AVERROR(EINVAL); -} - -static int ffserver_save_avoption(const char *opt, const char *arg, int type, - FFServerConfig *config) -{ - static int hinted = 0; - int ret = 0; - AVDictionaryEntry *e; - const AVOption *o = NULL; - const char *option = NULL; - const char *codec_name = NULL; - char buff[1024]; - AVCodecContext *ctx; - AVDictionary **dict; - enum AVCodecID guessed_codec_id; - - switch (type) { - case AV_OPT_FLAG_VIDEO_PARAM: - ctx = config->dummy_vctx; - dict = &config->video_opts; - guessed_codec_id = config->guessed_video_codec_id != AV_CODEC_ID_NONE ? - config->guessed_video_codec_id : AV_CODEC_ID_H264; - break; - case AV_OPT_FLAG_AUDIO_PARAM: - ctx = config->dummy_actx; - dict = &config->audio_opts; - guessed_codec_id = config->guessed_audio_codec_id != AV_CODEC_ID_NONE ? - config->guessed_audio_codec_id : AV_CODEC_ID_AAC; - break; - default: - av_assert0(0); - } - - if (strchr(opt, ':')) { - //explicit private option - snprintf(buff, sizeof(buff), "%s", opt); - codec_name = buff; - if(!(option = strchr(buff, ':'))){ - report_config_error(config->filename, config->line_num, - AV_LOG_ERROR, &config->errors, - "Syntax error. Unmatched ':'\n"); - return -1; - - } - buff[option - buff] = '\0'; - option++; - if ((ret = ffserver_set_codec(ctx, codec_name, config)) < 0) - return ret; - if (!ctx->codec || !ctx->priv_data) - return -1; - } else { - option = opt; - } - - o = av_opt_find(ctx, option, NULL, type | AV_OPT_FLAG_ENCODING_PARAM, - AV_OPT_SEARCH_CHILDREN); - if (!o && - (!strcmp(option, "time_base") || !strcmp(option, "pixel_format") || - !strcmp(option, "video_size") || !strcmp(option, "codec_tag"))) - o = av_opt_find(ctx, option, NULL, 0, 0); - if (!o) { - report_config_error(config->filename, config->line_num, AV_LOG_ERROR, - &config->errors, "Option not found: '%s'\n", opt); - if (!hinted && ctx->codec_id == AV_CODEC_ID_NONE) { - hinted = 1; - report_config_error(config->filename, config->line_num, - AV_LOG_ERROR, NULL, "If '%s' is a codec private" - "option, then prefix it with codec name, for " - "example '%s:%s %s' or define codec earlier.\n", - opt, avcodec_get_name(guessed_codec_id) ,opt, - arg); - } - } else if ((ret = av_opt_set(ctx, option, arg, AV_OPT_SEARCH_CHILDREN)) < 0) { - report_config_error(config->filename, config->line_num, AV_LOG_ERROR, - &config->errors, "Invalid value for option %s (%s): %s\n", opt, - arg, av_err2str(ret)); - } else if ((e = av_dict_get(*dict, option, NULL, 0))) { - if ((o->type == AV_OPT_TYPE_FLAGS) && arg && - (arg[0] == '+' || arg[0] == '-')) - return av_dict_set(dict, option, arg, AV_DICT_APPEND); - report_config_error(config->filename, config->line_num, AV_LOG_ERROR, - &config->errors, "Redeclaring value of option '%s'." - "Previous value was: '%s'.\n", opt, e->value); - } else if (av_dict_set(dict, option, arg, 0) < 0) { - return AVERROR(ENOMEM); - } - return 0; -} - -static int ffserver_save_avoption_int(const char *opt, int64_t arg, - int type, FFServerConfig *config) -{ - char buf[22]; - snprintf(buf, sizeof(buf), "%"PRId64, arg); - return ffserver_save_avoption(opt, buf, type, config); -} - -static int ffserver_parse_config_global(FFServerConfig *config, const char *cmd, - const char **p) -{ - int val; - char arg[1024]; - if (!av_strcasecmp(cmd, "Port") || !av_strcasecmp(cmd, "HTTPPort")) { - if (!av_strcasecmp(cmd, "Port")) - WARNING("Port option is deprecated. Use HTTPPort instead.\n"); - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_int_param(&val, arg, 0, 1, 65535, config, - "Invalid port: %s\n", arg); - if (val < 1024) - WARNING("Trying to use IETF assigned system port: '%d'\n", val); - config->http_addr.sin_port = htons(val); - } else if (!av_strcasecmp(cmd, "HTTPBindAddress") || - !av_strcasecmp(cmd, "BindAddress")) { - if (!av_strcasecmp(cmd, "BindAddress")) - WARNING("BindAddress option is deprecated. Use HTTPBindAddress " - "instead.\n"); - ffserver_get_arg(arg, sizeof(arg), p); - if (resolve_host(&config->http_addr.sin_addr, arg)) - ERROR("Invalid host/IP address: '%s'\n", arg); - } else if (!av_strcasecmp(cmd, "NoDaemon")) { - WARNING("NoDaemon option has no effect. You should remove it.\n"); - } else if (!av_strcasecmp(cmd, "RTSPPort")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_int_param(&val, arg, 0, 1, 65535, config, - "Invalid port: %s\n", arg); - config->rtsp_addr.sin_port = htons(val); - } else if (!av_strcasecmp(cmd, "RTSPBindAddress")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (resolve_host(&config->rtsp_addr.sin_addr, arg)) - ERROR("Invalid host/IP address: %s\n", arg); - } else if (!av_strcasecmp(cmd, "MaxHTTPConnections")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_int_param(&val, arg, 0, 1, 65535, config, - "Invalid MaxHTTPConnections: %s\n", arg); - config->nb_max_http_connections = val; - if (config->nb_max_connections > config->nb_max_http_connections) { - ERROR("Inconsistent configuration: MaxClients(%d) > " - "MaxHTTPConnections(%d)\n", config->nb_max_connections, - config->nb_max_http_connections); - } - } else if (!av_strcasecmp(cmd, "MaxClients")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_int_param(&val, arg, 0, 1, 65535, config, - "Invalid MaxClients: '%s'\n", arg); - config->nb_max_connections = val; - if (config->nb_max_connections > config->nb_max_http_connections) { - ERROR("Inconsistent configuration: MaxClients(%d) > " - "MaxHTTPConnections(%d)\n", config->nb_max_connections, - config->nb_max_http_connections); - } - } else if (!av_strcasecmp(cmd, "MaxBandwidth")) { - int64_t llval; - char *tailp; - ffserver_get_arg(arg, sizeof(arg), p); - errno = 0; - llval = strtoll(arg, &tailp, 10); - if (llval < 10 || llval > 10000000 || tailp[0] || errno) - ERROR("Invalid MaxBandwidth: '%s'\n", arg); - else - config->max_bandwidth = llval; - } else if (!av_strcasecmp(cmd, "CustomLog")) { - if (!config->debug) { - ffserver_get_arg(config->logfilename, sizeof(config->logfilename), - p); - } - } else if (!av_strcasecmp(cmd, "LoadModule")) { - ERROR("Loadable modules are no longer supported\n"); - } else if (!av_strcasecmp(cmd, "NoDefaults")) { - config->use_defaults = 0; - } else if (!av_strcasecmp(cmd, "UseDefaults")) { - config->use_defaults = 1; - } else - ERROR("Incorrect keyword: '%s'\n", cmd); - return 0; -} - -static int ffserver_parse_config_feed(FFServerConfig *config, const char *cmd, - const char **p, FFServerStream **pfeed) -{ - FFServerStream *feed; - char arg[1024]; - av_assert0(pfeed); - feed = *pfeed; - if (!av_strcasecmp(cmd, "filename, sizeof(feed->filename), p); - q = strrchr(feed->filename, '>'); - if (*q) - *q = '\0'; - - for (s = config->first_feed; s; s = s->next) { - if (!strcmp(feed->filename, s->filename)) - ERROR("Feed '%s' already registered\n", s->filename); - } - - feed->fmt = av_guess_format("ffm", NULL, NULL); - /* default feed file */ - snprintf(feed->feed_filename, sizeof(feed->feed_filename), - "/tmp/%s.ffm", feed->filename); - feed->feed_max_size = 5 * 1024 * 1024; - feed->is_feed = 1; - feed->feed = feed; /* self feeding :-) */ - *pfeed = feed; - return 0; - } - av_assert0(feed); - if (!av_strcasecmp(cmd, "Launch")) { - int i; - - feed->child_argv = av_mallocz_array(MAX_CHILD_ARGS, sizeof(char *)); - if (!feed->child_argv) - return AVERROR(ENOMEM); - for (i = 0; i < MAX_CHILD_ARGS - 2; i++) { - ffserver_get_arg(arg, sizeof(arg), p); - if (!arg[0]) - break; - - feed->child_argv[i] = av_strdup(arg); - if (!feed->child_argv[i]) - return AVERROR(ENOMEM); - } - - feed->child_argv[i] = - av_asprintf("http://%s:%d/%s", - (config->http_addr.sin_addr.s_addr == INADDR_ANY) ? - "127.0.0.1" : inet_ntoa(config->http_addr.sin_addr), - ntohs(config->http_addr.sin_port), feed->filename); - if (!feed->child_argv[i]) - return AVERROR(ENOMEM); - } else if (!av_strcasecmp(cmd, "ACL")) { - ffserver_parse_acl_row(NULL, feed, NULL, *p, config->filename, - config->line_num); - } else if (!av_strcasecmp(cmd, "File") || - !av_strcasecmp(cmd, "ReadOnlyFile")) { - ffserver_get_arg(feed->feed_filename, sizeof(feed->feed_filename), p); - feed->readonly = !av_strcasecmp(cmd, "ReadOnlyFile"); - } else if (!av_strcasecmp(cmd, "Truncate")) { - ffserver_get_arg(arg, sizeof(arg), p); - /* assume Truncate is true in case no argument is specified */ - if (!arg[0]) { - feed->truncate = 1; - } else { - WARNING("Truncate N syntax in configuration file is deprecated. " - "Use Truncate alone with no arguments.\n"); - feed->truncate = strtod(arg, NULL); - } - } else if (!av_strcasecmp(cmd, "FileMaxSize")) { - char *p1; - double fsize; - - ffserver_get_arg(arg, sizeof(arg), p); - p1 = arg; - fsize = strtod(p1, &p1); - switch(av_toupper(*p1)) { - case 'K': - fsize *= 1024; - break; - case 'M': - fsize *= 1024 * 1024; - break; - case 'G': - fsize *= 1024 * 1024 * 1024; - break; - default: - ERROR("Invalid file size: '%s'\n", arg); - break; - } - feed->feed_max_size = (int64_t)fsize; - if (feed->feed_max_size < FFM_PACKET_SIZE*4) { - ERROR("Feed max file size is too small. Must be at least %d.\n", - FFM_PACKET_SIZE*4); - } - } else if (!av_strcasecmp(cmd, "")) { - *pfeed = NULL; - } else { - ERROR("Invalid entry '%s' inside \n", cmd); - } - return 0; -} - -static int ffserver_parse_config_stream(FFServerConfig *config, const char *cmd, - const char **p, - FFServerStream **pstream) -{ - char arg[1024], arg2[1024]; - FFServerStream *stream; - int val; - - av_assert0(pstream); - stream = *pstream; - - if (!av_strcasecmp(cmd, "dummy_actx = avcodec_alloc_context3(NULL); - config->dummy_vctx = avcodec_alloc_context3(NULL); - if (!config->dummy_vctx || !config->dummy_actx) { - av_free(stream); - avcodec_free_context(&config->dummy_vctx); - avcodec_free_context(&config->dummy_actx); - return AVERROR(ENOMEM); - } - config->dummy_actx->codec_type = AVMEDIA_TYPE_AUDIO; - config->dummy_vctx->codec_type = AVMEDIA_TYPE_VIDEO; - ffserver_get_arg(stream->filename, sizeof(stream->filename), p); - q = strrchr(stream->filename, '>'); - if (q) - *q = '\0'; - - for (s = config->first_stream; s; s = s->next) { - if (!strcmp(stream->filename, s->filename)) - ERROR("Stream '%s' already registered\n", s->filename); - } - - stream->fmt = ffserver_guess_format(NULL, stream->filename, NULL); - if (stream->fmt) { - config->guessed_audio_codec_id = stream->fmt->audio_codec; - config->guessed_video_codec_id = stream->fmt->video_codec; - } else { - config->guessed_audio_codec_id = AV_CODEC_ID_NONE; - config->guessed_video_codec_id = AV_CODEC_ID_NONE; - } - config->stream_use_defaults = config->use_defaults; - *pstream = stream; - return 0; - } - av_assert0(stream); - if (!av_strcasecmp(cmd, "Feed")) { - FFServerStream *sfeed; - ffserver_get_arg(arg, sizeof(arg), p); - sfeed = config->first_feed; - while (sfeed) { - if (!strcmp(sfeed->filename, arg)) - break; - sfeed = sfeed->next_feed; - } - if (!sfeed) - ERROR("Feed with name '%s' for stream '%s' is not defined\n", arg, - stream->filename); - else - stream->feed = sfeed; - } else if (!av_strcasecmp(cmd, "Format")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (!strcmp(arg, "status")) { - stream->stream_type = STREAM_TYPE_STATUS; - stream->fmt = NULL; - } else { - stream->stream_type = STREAM_TYPE_LIVE; - /* JPEG cannot be used here, so use single frame MJPEG */ - if (!strcmp(arg, "jpeg")) { - strcpy(arg, "singlejpeg"); - stream->single_frame=1; - } - stream->fmt = ffserver_guess_format(arg, NULL, NULL); - if (!stream->fmt) - ERROR("Unknown Format: '%s'\n", arg); - } - if (stream->fmt) { - config->guessed_audio_codec_id = stream->fmt->audio_codec; - config->guessed_video_codec_id = stream->fmt->video_codec; - } - } else if (!av_strcasecmp(cmd, "InputFormat")) { - ffserver_get_arg(arg, sizeof(arg), p); - stream->ifmt = av_find_input_format(arg); - if (!stream->ifmt) - ERROR("Unknown input format: '%s'\n", arg); - } else if (!av_strcasecmp(cmd, "FaviconURL")) { - if (stream->stream_type == STREAM_TYPE_STATUS) - ffserver_get_arg(stream->feed_filename, - sizeof(stream->feed_filename), p); - else - ERROR("FaviconURL only permitted for status streams\n"); - } else if (!av_strcasecmp(cmd, "Author") || - !av_strcasecmp(cmd, "Comment") || - !av_strcasecmp(cmd, "Copyright") || - !av_strcasecmp(cmd, "Title")) { - char key[32]; - int i; - ffserver_get_arg(arg, sizeof(arg), p); - for (i = 0; i < strlen(cmd); i++) - key[i] = av_tolower(cmd[i]); - key[i] = 0; - WARNING("Deprecated '%s' option in configuration file. Use " - "'Metadata %s VALUE' instead.\n", cmd, key); - if (av_dict_set(&stream->metadata, key, arg, 0) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "Metadata")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_get_arg(arg2, sizeof(arg2), p); - if (av_dict_set(&stream->metadata, arg, arg2, 0) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "Preroll")) { - ffserver_get_arg(arg, sizeof(arg), p); - stream->prebuffer = atof(arg) * 1000; - } else if (!av_strcasecmp(cmd, "StartSendOnKey")) { - stream->send_on_key = 1; - } else if (!av_strcasecmp(cmd, "AudioCodec")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_codec(config->dummy_actx, arg, config); - } else if (!av_strcasecmp(cmd, "VideoCodec")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_codec(config->dummy_vctx, arg, config); - } else if (!av_strcasecmp(cmd, "MaxTime")) { - ffserver_get_arg(arg, sizeof(arg), p); - stream->max_time = atof(arg) * 1000; - } else if (!av_strcasecmp(cmd, "AudioBitRate")) { - float f; - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_float_param(&f, arg, 1000, -FLT_MAX, FLT_MAX, config, - "Invalid %s: '%s'\n", cmd, arg); - if (ffserver_save_avoption_int("b", (int64_t)lrintf(f), - AV_OPT_FLAG_AUDIO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "AudioChannels")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (ffserver_save_avoption("ac", arg, AV_OPT_FLAG_AUDIO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "AudioSampleRate")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (ffserver_save_avoption("ar", arg, AV_OPT_FLAG_AUDIO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "VideoBitRateRange")) { - int minrate, maxrate; - char *dash; - ffserver_get_arg(arg, sizeof(arg), p); - dash = strchr(arg, '-'); - if (dash) { - *dash = '\0'; - dash++; - if (ffserver_set_int_param(&minrate, arg, 1000, 0, INT_MAX, config, "Invalid %s: '%s'", cmd, arg) >= 0 && - ffserver_set_int_param(&maxrate, dash, 1000, 0, INT_MAX, config, "Invalid %s: '%s'", cmd, arg) >= 0) { - if (ffserver_save_avoption_int("minrate", minrate, AV_OPT_FLAG_VIDEO_PARAM, config) < 0 || - ffserver_save_avoption_int("maxrate", maxrate, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } - } else - ERROR("Incorrect format for VideoBitRateRange. It should be " - "-: '%s'.\n", arg); - } else if (!av_strcasecmp(cmd, "Debug")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (ffserver_save_avoption("debug", arg, AV_OPT_FLAG_AUDIO_PARAM, config) < 0 || - ffserver_save_avoption("debug", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "Strict")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (ffserver_save_avoption("strict", arg, AV_OPT_FLAG_AUDIO_PARAM, config) < 0 || - ffserver_save_avoption("strict", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "VideoBufferSize")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_int_param(&val, arg, 8*1024, 0, INT_MAX, config, - "Invalid %s: '%s'", cmd, arg); - if (ffserver_save_avoption_int("bufsize", val, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "VideoBitRateTolerance")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_int_param(&val, arg, 1000, INT_MIN, INT_MAX, config, - "Invalid %s: '%s'", cmd, arg); - if (ffserver_save_avoption_int("bt", val, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "VideoBitRate")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_int_param(&val, arg, 1000, INT_MIN, INT_MAX, config, - "Invalid %s: '%s'", cmd, arg); - if (ffserver_save_avoption_int("b", val, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "VideoSize")) { - int ret, w, h; - ffserver_get_arg(arg, sizeof(arg), p); - ret = av_parse_video_size(&w, &h, arg); - if (ret < 0) - ERROR("Invalid video size '%s'\n", arg); - else { - if (w % 2 || h % 2) - WARNING("Image size is not a multiple of 2\n"); - if (ffserver_save_avoption("video_size", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } - } else if (!av_strcasecmp(cmd, "VideoFrameRate")) { - ffserver_get_arg(&arg[2], sizeof(arg) - 2, p); - arg[0] = '1'; arg[1] = '/'; - if (ffserver_save_avoption("time_base", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "PixelFormat")) { - enum AVPixelFormat pix_fmt; - ffserver_get_arg(arg, sizeof(arg), p); - pix_fmt = av_get_pix_fmt(arg); - if (pix_fmt == AV_PIX_FMT_NONE) - ERROR("Unknown pixel format: '%s'\n", arg); - else if (ffserver_save_avoption("pixel_format", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "VideoGopSize")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (ffserver_save_avoption("g", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "VideoIntraOnly")) { - if (ffserver_save_avoption("g", "1", AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "VideoHighQuality")) { - if (ffserver_save_avoption("mbd", "+bits", AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "Video4MotionVector")) { - if (ffserver_save_avoption("mbd", "+bits", AV_OPT_FLAG_VIDEO_PARAM, config) < 0 || //FIXME remove - ffserver_save_avoption("flags", "+mv4", AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "AVOptionVideo") || - !av_strcasecmp(cmd, "AVOptionAudio")) { - int ret; - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_get_arg(arg2, sizeof(arg2), p); - if (!av_strcasecmp(cmd, "AVOptionVideo")) - ret = ffserver_save_avoption(arg, arg2, AV_OPT_FLAG_VIDEO_PARAM, - config); - else - ret = ffserver_save_avoption(arg, arg2, AV_OPT_FLAG_AUDIO_PARAM, - config); - if (ret < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "AVPresetVideo") || - !av_strcasecmp(cmd, "AVPresetAudio")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (!av_strcasecmp(cmd, "AVPresetVideo")) - ffserver_opt_preset(arg, AV_OPT_FLAG_VIDEO_PARAM, config); - else - ffserver_opt_preset(arg, AV_OPT_FLAG_AUDIO_PARAM, config); - } else if (!av_strcasecmp(cmd, "VideoTag")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (strlen(arg) == 4 && - ffserver_save_avoption_int("codec_tag", - MKTAG(arg[0], arg[1], arg[2], arg[3]), - AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "BitExact")) { - config->bitexact = 1; - if (ffserver_save_avoption("flags", "+bitexact", AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "DctFastint")) { - if (ffserver_save_avoption("dct", "fastint", AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "IdctSimple")) { - if (ffserver_save_avoption("idct", "simple", AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "Qscale")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_int_param(&val, arg, 0, INT_MIN, INT_MAX, config, - "Invalid Qscale: '%s'\n", arg); - if (ffserver_save_avoption("flags", "+qscale", AV_OPT_FLAG_VIDEO_PARAM, config) < 0 || - ffserver_save_avoption_int("global_quality", FF_QP2LAMBDA * val, - AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "VideoQDiff")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (ffserver_save_avoption("qdiff", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "VideoQMax")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (ffserver_save_avoption("qmax", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "VideoQMin")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (ffserver_save_avoption("qmin", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "LumiMask")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (ffserver_save_avoption("lumi_mask", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "DarkMask")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (ffserver_save_avoption("dark_mask", arg, AV_OPT_FLAG_VIDEO_PARAM, config) < 0) - goto nomem; - } else if (!av_strcasecmp(cmd, "NoVideo")) { - config->no_video = 1; - } else if (!av_strcasecmp(cmd, "NoAudio")) { - config->no_audio = 1; - } else if (!av_strcasecmp(cmd, "ACL")) { - ffserver_parse_acl_row(stream, NULL, NULL, *p, config->filename, - config->line_num); - } else if (!av_strcasecmp(cmd, "DynamicACL")) { - ffserver_get_arg(stream->dynamic_acl, sizeof(stream->dynamic_acl), p); - } else if (!av_strcasecmp(cmd, "RTSPOption")) { - ffserver_get_arg(arg, sizeof(arg), p); - av_freep(&stream->rtsp_option); - stream->rtsp_option = av_strdup(arg); - } else if (!av_strcasecmp(cmd, "MulticastAddress")) { - ffserver_get_arg(arg, sizeof(arg), p); - if (resolve_host(&stream->multicast_ip, arg)) - ERROR("Invalid host/IP address: '%s'\n", arg); - stream->is_multicast = 1; - stream->loop = 1; /* default is looping */ - } else if (!av_strcasecmp(cmd, "MulticastPort")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_int_param(&val, arg, 0, 1, 65535, config, - "Invalid MulticastPort: '%s'\n", arg); - stream->multicast_port = val; - } else if (!av_strcasecmp(cmd, "MulticastTTL")) { - ffserver_get_arg(arg, sizeof(arg), p); - ffserver_set_int_param(&val, arg, 0, INT_MIN, INT_MAX, config, - "Invalid MulticastTTL: '%s'\n", arg); - stream->multicast_ttl = val; - } else if (!av_strcasecmp(cmd, "NoLoop")) { - stream->loop = 0; - } else if (!av_strcasecmp(cmd, "")) { - config->stream_use_defaults &= 1; - if (stream->feed && stream->fmt && strcmp(stream->fmt->name, "ffm")) { - if (config->dummy_actx->codec_id == AV_CODEC_ID_NONE) - config->dummy_actx->codec_id = config->guessed_audio_codec_id; - if (!config->no_audio && - config->dummy_actx->codec_id != AV_CODEC_ID_NONE) { - AVCodecContext *audio_enc = avcodec_alloc_context3(avcodec_find_encoder(config->dummy_actx->codec_id)); - add_codec(stream, audio_enc, config); - } - if (config->dummy_vctx->codec_id == AV_CODEC_ID_NONE) - config->dummy_vctx->codec_id = config->guessed_video_codec_id; - if (!config->no_video && - config->dummy_vctx->codec_id != AV_CODEC_ID_NONE) { - AVCodecContext *video_enc = avcodec_alloc_context3(avcodec_find_encoder(config->dummy_vctx->codec_id)); - add_codec(stream, video_enc, config); - } - } - av_dict_free(&config->video_opts); - av_dict_free(&config->audio_opts); - avcodec_free_context(&config->dummy_vctx); - avcodec_free_context(&config->dummy_actx); - config->no_video = 0; - config->no_audio = 0; - *pstream = NULL; - } else if (!av_strcasecmp(cmd, "File") || - !av_strcasecmp(cmd, "ReadOnlyFile")) { - ffserver_get_arg(stream->feed_filename, sizeof(stream->feed_filename), - p); - } else if (!av_strcasecmp(cmd, "UseDefaults")) { - if (config->stream_use_defaults > 1) - WARNING("Multiple UseDefaults/NoDefaults entries.\n"); - config->stream_use_defaults = 3; - } else if (!av_strcasecmp(cmd, "NoDefaults")) { - if (config->stream_use_defaults > 1) - WARNING("Multiple UseDefaults/NoDefaults entries.\n"); - config->stream_use_defaults = 2; - } else { - ERROR("Invalid entry '%s' inside \n", cmd); - } - return 0; - nomem: - av_log(NULL, AV_LOG_ERROR, "Out of memory. Aborting.\n"); - av_dict_free(&config->video_opts); - av_dict_free(&config->audio_opts); - avcodec_free_context(&config->dummy_vctx); - avcodec_free_context(&config->dummy_actx); - return AVERROR(ENOMEM); -} - -static int ffserver_parse_config_redirect(FFServerConfig *config, - const char *cmd, const char **p, - FFServerStream **predirect) -{ - FFServerStream *redirect; - av_assert0(predirect); - redirect = *predirect; - - if (!av_strcasecmp(cmd, "filename, sizeof(redirect->filename), p); - q = strrchr(redirect->filename, '>'); - if (*q) - *q = '\0'; - redirect->stream_type = STREAM_TYPE_REDIRECT; - *predirect = redirect; - return 0; - } - av_assert0(redirect); - if (!av_strcasecmp(cmd, "URL")) { - ffserver_get_arg(redirect->feed_filename, - sizeof(redirect->feed_filename), p); - } else if (!av_strcasecmp(cmd, "
")) { - if (!redirect->feed_filename[0]) - ERROR("No URL found for \n"); - *predirect = NULL; - } else { - ERROR("Invalid entry '%s' inside \n", cmd); - } - return 0; -} - -int ffserver_parse_ffconfig(const char *filename, FFServerConfig *config) -{ - FILE *f; - char line[1024]; - char cmd[64]; - const char *p; - FFServerStream **last_stream, *stream = NULL, *redirect = NULL; - FFServerStream **last_feed, *feed = NULL; - int ret = 0; - - av_assert0(config); - - f = fopen(filename, "r"); - if (!f) { - ret = AVERROR(errno); - av_log(NULL, AV_LOG_ERROR, - "Could not open the configuration file '%s'\n", filename); - return ret; - } - - config->first_stream = NULL; - config->first_feed = NULL; - config->errors = config->warnings = 0; - - last_stream = &config->first_stream; - last_feed = &config->first_feed; - - config->line_num = 0; - while (fgets(line, sizeof(line), f) != NULL) { - config->line_num++; - p = line; - while (av_isspace(*p)) - p++; - if (*p == '\0' || *p == '#') - continue; - - ffserver_get_arg(cmd, sizeof(cmd), &p); - - if (feed || !av_strcasecmp(cmd, "next; - last_feed = &feed->next_feed; - } - } - } else if (stream || !av_strcasecmp(cmd, "next; - } - } - } else if (redirect || !av_strcasecmp(cmd, "next; - } - } - } else { - ffserver_parse_config_global(config, cmd, &p); - } - } - if (stream || feed || redirect) - ERROR("Missing closing tag\n", - stream ? "Stream" : (feed ? "Feed" : "Redirect")); - - fclose(f); - if (ret < 0) - return ret; - if (config->errors) - return AVERROR(EINVAL); - else - return 0; -} - -#undef ERROR -#undef WARNING - -void ffserver_free_child_args(void *argsp) -{ - int i; - char **args; - if (!argsp) - return; - args = *(char ***)argsp; - if (!args) - return; - for (i = 0; i < MAX_CHILD_ARGS; i++) - av_free(args[i]); - av_freep(argsp); -} diff --git a/fftools/ffserver_config.h b/fftools/ffserver_config.h deleted file mode 100644 index 089b8484da310..0000000000000 --- a/fftools/ffserver_config.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Copyright (c) 2000, 2001, 2002 Fabrice Bellard - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef FFTOOLS_FFSERVER_CONFIG_H -#define FFTOOLS_FFSERVER_CONFIG_H - -#define FFM_PACKET_SIZE 4096 - -#include "libavutil/dict.h" -#include "libavformat/avformat.h" -#include "libavformat/network.h" - -#define FFSERVER_MAX_STREAMS 20 - -/* each generated stream is described here */ -enum FFServerStreamType { - STREAM_TYPE_LIVE, - STREAM_TYPE_STATUS, - STREAM_TYPE_REDIRECT, -}; - -enum FFServerIPAddressAction { - IP_ALLOW = 1, - IP_DENY, -}; - -typedef struct FFServerIPAddressACL { - struct FFServerIPAddressACL *next; - enum FFServerIPAddressAction action; - /* These are in host order */ - struct in_addr first; - struct in_addr last; -} FFServerIPAddressACL; - -/** - * This holds the stream parameters for an AVStream, it cannot be a AVStream - * because AVStreams cannot be instanciated without a AVFormatContext, especially - * not outside libavformat. - * - * The fields of this struct have the same semantics as the fields of an AVStream. - */ -typedef struct LayeredAVStream { - int index; - int id; - AVCodecParameters *codecpar; - AVCodecContext *codec; - AVRational time_base; - int pts_wrap_bits; - AVRational sample_aspect_ratio; - char *recommended_encoder_configuration; -} LayeredAVStream; - -/* description of each stream of the ffserver.conf file */ -typedef struct FFServerStream { - enum FFServerStreamType stream_type; - char filename[1024]; /* stream filename */ - struct FFServerStream *feed; /* feed we are using (can be null if coming from file) */ - AVDictionary *in_opts; /* input parameters */ - AVDictionary *metadata; /* metadata to set on the stream */ - AVInputFormat *ifmt; /* if non NULL, force input format */ - AVOutputFormat *fmt; - FFServerIPAddressACL *acl; - char dynamic_acl[1024]; - int nb_streams; - int prebuffer; /* Number of milliseconds early to start */ - int64_t max_time; /* Number of milliseconds to run */ - int send_on_key; - LayeredAVStream *streams[FFSERVER_MAX_STREAMS]; - int feed_streams[FFSERVER_MAX_STREAMS]; /* index of streams in the feed */ - char feed_filename[1024]; /* file name of the feed storage, or - input file name for a stream */ - pid_t pid; /* Of ffmpeg process */ - time_t pid_start; /* Of ffmpeg process */ - char **child_argv; - struct FFServerStream *next; - unsigned bandwidth; /* bandwidth, in kbits/s */ - /* RTSP options */ - char *rtsp_option; - /* multicast specific */ - int is_multicast; - struct in_addr multicast_ip; - int multicast_port; /* first port used for multicast */ - int multicast_ttl; - int loop; /* if true, send the stream in loops (only meaningful if file) */ - char single_frame; /* only single frame */ - - /* feed specific */ - int feed_opened; /* true if someone is writing to the feed */ - int is_feed; /* true if it is a feed */ - int readonly; /* True if writing is prohibited to the file */ - int truncate; /* True if feeder connection truncate the feed file */ - int conns_served; - int64_t bytes_served; - int64_t feed_max_size; /* maximum storage size, zero means unlimited */ - int64_t feed_write_index; /* current write position in feed (it wraps around) */ - int64_t feed_size; /* current size of feed */ - struct FFServerStream *next_feed; -} FFServerStream; - -typedef struct FFServerConfig { - char *filename; - FFServerStream *first_feed; /* contains only feeds */ - FFServerStream *first_stream; /* contains all streams, including feeds */ - unsigned int nb_max_http_connections; - unsigned int nb_max_connections; - uint64_t max_bandwidth; - int debug; - int bitexact; - char logfilename[1024]; - struct sockaddr_in http_addr; - struct sockaddr_in rtsp_addr; - int errors; - int warnings; - int use_defaults; - // Following variables MUST NOT be used outside configuration parsing code. - enum AVCodecID guessed_audio_codec_id; - enum AVCodecID guessed_video_codec_id; - AVDictionary *video_opts; /* AVOptions for video encoder */ - AVDictionary *audio_opts; /* AVOptions for audio encoder */ - AVCodecContext *dummy_actx; /* Used internally to test audio AVOptions. */ - AVCodecContext *dummy_vctx; /* Used internally to test video AVOptions. */ - int no_audio; - int no_video; - int line_num; - int stream_use_defaults; -} FFServerConfig; - -void ffserver_get_arg(char *buf, int buf_size, const char **pp); - -void ffserver_parse_acl_row(FFServerStream *stream, FFServerStream* feed, - FFServerIPAddressACL *ext_acl, - const char *p, const char *filename, int line_num); - -int ffserver_parse_ffconfig(const char *filename, FFServerConfig *config); - -void ffserver_free_child_args(void *argsp); - -#endif /* FFTOOLS_FFSERVER_CONFIG_H */ diff --git a/libavcodec/.gitignore b/libavcodec/.gitignore index 77a2ab1bd8075..28814f72331a6 100644 --- a/libavcodec/.gitignore +++ b/libavcodec/.gitignore @@ -2,3 +2,5 @@ /*_tables.c /*_tables.h /bsf_list.c +/codec_list.c +/parser_list.c diff --git a/libavcodec/Makefile b/libavcodec/Makefile index c4ec09b1c4535..4b8ad121dbeb6 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -1,7 +1,9 @@ NAME = avcodec DESC = FFmpeg codec library -HEADERS = avcodec.h \ +HEADERS = ac3_parser.h \ + adts_parser.h \ + avcodec.h \ avdct.h \ avfft.h \ d3d11va.h \ @@ -12,15 +14,15 @@ HEADERS = avcodec.h \ mediacodec.h \ qsv.h \ vaapi.h \ - vda.h \ vdpau.h \ version.h \ videotoolbox.h \ vorbis_parser.h \ xvmc.h \ -OBJS = allcodecs.o \ - audioconvert.o \ +OBJS = ac3_parser.o \ + adts_parser.o \ + allcodecs.o \ avdct.o \ avpacket.o \ avpicture.o \ @@ -45,8 +47,6 @@ OBJS = allcodecs.o \ profiles.o \ qsv_api.o \ raw.o \ - resample.o \ - resample2.o \ utils.o \ vorbis_parser.o \ xiph.o \ @@ -54,11 +54,17 @@ OBJS = allcodecs.o \ # subsystems OBJS-$(CONFIG_AANDCTTABLES) += aandcttab.o OBJS-$(CONFIG_AC3DSP) += ac3dsp.o ac3.o ac3tab.o +OBJS-$(CONFIG_ADTS_HEADER) += adts_header.o mpeg4audio.o +OBJS-$(CONFIG_AMF) += amfenc.o OBJS-$(CONFIG_AUDIO_FRAME_QUEUE) += audio_frame_queue.o OBJS-$(CONFIG_AUDIODSP) += audiodsp.o OBJS-$(CONFIG_BLOCKDSP) += blockdsp.o OBJS-$(CONFIG_BSWAPDSP) += bswapdsp.o OBJS-$(CONFIG_CABAC) += cabac.o +OBJS-$(CONFIG_CBS) += cbs.o +OBJS-$(CONFIG_CBS_H264) += cbs_h2645.o h2645_parse.o +OBJS-$(CONFIG_CBS_H265) += cbs_h2645.o h2645_parse.o +OBJS-$(CONFIG_CBS_MPEG2) += cbs_mpeg2.o OBJS-$(CONFIG_CRYSTALHD) += crystalhd.o OBJS-$(CONFIG_DCT) += dct.o dct32_fixed.o dct32_float.o OBJS-$(CONFIG_ERROR_RESILIENCE) += error_resilience.o @@ -91,7 +97,6 @@ OBJS-$(CONFIG_INTRAX8) += intrax8.o intrax8dsp.o msmpeg4data.o OBJS-$(CONFIG_IVIDSP) += ivi_dsp.o OBJS-$(CONFIG_JNI) += ffjni.o jni.o OBJS-$(CONFIG_JPEGTABLES) += jpegtables.o -OBJS-$(CONFIG_LIBXVID) += libxvid_rc.o OBJS-$(CONFIG_LLAUDDSP) += lossless_audiodsp.o OBJS-$(CONFIG_LLVIDDSP) += lossless_videodsp.o OBJS-$(CONFIG_LLVIDENCDSP) += lossless_videoencdsp.o @@ -146,10 +151,10 @@ OBJS-$(CONFIG_ZERO12V_DECODER) += 012v.o OBJS-$(CONFIG_A64MULTI_ENCODER) += a64multienc.o elbg.o OBJS-$(CONFIG_A64MULTI5_ENCODER) += a64multienc.o elbg.o OBJS-$(CONFIG_AAC_DECODER) += aacdec.o aactab.o aacsbr.o aacps_float.o \ - aacadtsdec.o mpeg4audio.o kbdwin.o \ + mpeg4audio.o kbdwin.o \ sbrdsp.o aacpsdsp_float.o cbrt_data.o OBJS-$(CONFIG_AAC_FIXED_DECODER) += aacdec_fixed.o aactab.o aacsbr_fixed.o aacps_fixed.o \ - aacadtsdec.o mpeg4audio.o kbdwin.o \ + mpeg4audio.o kbdwin.o \ sbrdsp_fixed.o aacpsdsp_fixed.o cbrt_data_fixed.o OBJS-$(CONFIG_AAC_ENCODER) += aacenc.o aaccoder.o aacenctab.o \ aacpsy.o aactab.o \ @@ -183,6 +188,10 @@ OBJS-$(CONFIG_AMV_ENCODER) += mjpegenc.o mjpegenc_common.o \ OBJS-$(CONFIG_ANM_DECODER) += anm.o OBJS-$(CONFIG_ANSI_DECODER) += ansi.o cga_data.o OBJS-$(CONFIG_APE_DECODER) += apedec.o +OBJS-$(CONFIG_APTX_DECODER) += aptx.o +OBJS-$(CONFIG_APTX_ENCODER) += aptx.o +OBJS-$(CONFIG_APTX_HD_DECODER) += aptx.o +OBJS-$(CONFIG_APTX_HD_ENCODER) += aptx.o OBJS-$(CONFIG_APNG_DECODER) += png.o pngdec.o pngdsp.o OBJS-$(CONFIG_APNG_ENCODER) += png.o pngenc.o OBJS-$(CONFIG_SSA_DECODER) += assdec.o ass.o @@ -331,18 +340,18 @@ OBJS-$(CONFIG_H264_DECODER) += h264dec.o h264_cabac.o h264_cavlc.o \ h264_mb.o h264_picture.o \ h264_refs.o h264_sei.o \ h264_slice.o h264data.o -OBJS-$(CONFIG_H264_CUVID_DECODER) += cuvid.o +OBJS-$(CONFIG_H264_AMF_ENCODER) += amfenc_h264.o +OBJS-$(CONFIG_H264_CUVID_DECODER) += cuviddec.o OBJS-$(CONFIG_H264_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_H264_MMAL_DECODER) += mmaldec.o OBJS-$(CONFIG_H264_NVENC_ENCODER) += nvenc_h264.o OBJS-$(CONFIG_NVENC_ENCODER) += nvenc_h264.o OBJS-$(CONFIG_NVENC_H264_ENCODER) += nvenc_h264.o -OBJS-$(CONFIG_H264_VDA_DECODER) += vda_h264_dec.o OBJS-$(CONFIG_H264_OMX_ENCODER) += omx.o OBJS-$(CONFIG_H264_QSV_DECODER) += qsvdec_h2645.o OBJS-$(CONFIG_H264_QSV_ENCODER) += qsvenc_h264.o OBJS-$(CONFIG_H264_RKMPP_DECODER) += rkmppdec.o -OBJS-$(CONFIG_H264_VAAPI_ENCODER) += vaapi_encode_h264.o vaapi_encode_h26x.o +OBJS-$(CONFIG_H264_VAAPI_ENCODER) += vaapi_encode_h264.o OBJS-$(CONFIG_H264_VIDEOTOOLBOX_ENCODER) += videotoolboxenc.o OBJS-$(CONFIG_H264_V4L2M2M_DECODER) += v4l2_m2m_dec.o OBJS-$(CONFIG_H264_V4L2M2M_ENCODER) += v4l2_m2m_enc.o @@ -351,7 +360,8 @@ OBJS-$(CONFIG_HAP_ENCODER) += hapenc.o hap.o OBJS-$(CONFIG_HEVC_DECODER) += hevcdec.o hevc_mvs.o \ hevc_cabac.o hevc_refs.o hevcpred.o \ hevcdsp.o hevc_filter.o hevc_data.o -OBJS-$(CONFIG_HEVC_CUVID_DECODER) += cuvid.o +OBJS-$(CONFIG_HEVC_AMF_ENCODER) += amfenc_hevc.o +OBJS-$(CONFIG_HEVC_CUVID_DECODER) += cuviddec.o OBJS-$(CONFIG_HEVC_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_HEVC_NVENC_ENCODER) += nvenc_hevc.o OBJS-$(CONFIG_NVENC_HEVC_ENCODER) += nvenc_hevc.o @@ -359,7 +369,7 @@ OBJS-$(CONFIG_HEVC_QSV_DECODER) += qsvdec_h2645.o OBJS-$(CONFIG_HEVC_QSV_ENCODER) += qsvenc_hevc.o hevc_ps_enc.o \ hevc_data.o OBJS-$(CONFIG_HEVC_RKMPP_DECODER) += rkmppdec.o -OBJS-$(CONFIG_HEVC_VAAPI_ENCODER) += vaapi_encode_h265.o vaapi_encode_h26x.o +OBJS-$(CONFIG_HEVC_VAAPI_ENCODER) += vaapi_encode_h265.o OBJS-$(CONFIG_HEVC_V4L2M2M_DECODER) += v4l2_m2m_dec.o OBJS-$(CONFIG_HEVC_V4L2M2M_ENCODER) += v4l2_m2m_enc.o OBJS-$(CONFIG_HNM4_VIDEO_DECODER) += hnm4video.o @@ -396,6 +406,7 @@ OBJS-$(CONFIG_M101_DECODER) += m101.o OBJS-$(CONFIG_MACE3_DECODER) += mace.o OBJS-$(CONFIG_MACE6_DECODER) += mace.o OBJS-$(CONFIG_MAGICYUV_DECODER) += magicyuv.o +OBJS-$(CONFIG_MAGICYUV_ENCODER) += magicyuvenc.o OBJS-$(CONFIG_MDEC_DECODER) += mdec.o mpeg12.o mpeg12data.o OBJS-$(CONFIG_METASOUND_DECODER) += metasound.o metasound_data.o \ twinvq.o @@ -405,6 +416,8 @@ OBJS-$(CONFIG_MJPEG_DECODER) += mjpegdec.o OBJS-$(CONFIG_MJPEG_ENCODER) += mjpegenc.o mjpegenc_common.o \ mjpegenc_huffman.o OBJS-$(CONFIG_MJPEGB_DECODER) += mjpegbdec.o +OBJS-$(CONFIG_MJPEG_CUVID_DECODER) += cuviddec.o +OBJS-$(CONFIG_MJPEG_QSV_ENCODER) += qsvenc_jpeg.o OBJS-$(CONFIG_MJPEG_VAAPI_ENCODER) += vaapi_encode_mjpeg.o OBJS-$(CONFIG_MLP_DECODER) += mlpdec.o mlpdsp.o OBJS-$(CONFIG_MLP_ENCODER) += mlpenc.o mlp.o @@ -431,16 +444,19 @@ OBJS-$(CONFIG_MPC8_DECODER) += mpc8.o mpc.o OBJS-$(CONFIG_MPEGVIDEO_DECODER) += mpeg12dec.o mpeg12.o mpeg12data.o OBJS-$(CONFIG_MPEG1VIDEO_DECODER) += mpeg12dec.o mpeg12.o mpeg12data.o OBJS-$(CONFIG_MPEG1VIDEO_ENCODER) += mpeg12enc.o mpeg12.o +OBJS-$(CONFIG_MPEG1_CUVID_DECODER) += cuviddec.o OBJS-$(CONFIG_MPEG1_V4L2M2M_DECODER) += v4l2_m2m_dec.o OBJS-$(CONFIG_MPEG2_MMAL_DECODER) += mmaldec.o OBJS-$(CONFIG_MPEG2_QSV_DECODER) += qsvdec_other.o OBJS-$(CONFIG_MPEG2_QSV_ENCODER) += qsvenc_mpeg2.o OBJS-$(CONFIG_MPEG2VIDEO_DECODER) += mpeg12dec.o mpeg12.o mpeg12data.o OBJS-$(CONFIG_MPEG2VIDEO_ENCODER) += mpeg12enc.o mpeg12.o +OBJS-$(CONFIG_MPEG2_CUVID_DECODER) += cuviddec.o OBJS-$(CONFIG_MPEG2_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_MPEG2_VAAPI_ENCODER) += vaapi_encode_mpeg2.o OBJS-$(CONFIG_MPEG2_V4L2M2M_DECODER) += v4l2_m2m_dec.o OBJS-$(CONFIG_MPEG4_DECODER) += xvididct.o +OBJS-$(CONFIG_MPEG4_CUVID_DECODER) += cuviddec.o OBJS-$(CONFIG_MPEG4_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_MPEG4_OMX_ENCODER) += omx.o OBJS-$(CONFIG_MPEG4_V4L2M2M_DECODER) += v4l2_m2m_dec.o @@ -469,7 +485,7 @@ OBJS-$(CONFIG_NUV_DECODER) += nuv.o rtjpeg.o OBJS-$(CONFIG_ON2AVC_DECODER) += on2avc.o on2avcdata.o OBJS-$(CONFIG_OPUS_DECODER) += opusdec.o opus.o opus_celt.o opus_rc.o \ opus_pvq.o opus_silk.o opustab.o vorbis_data.o -OBJS-$(CONFIG_OPUS_ENCODER) += opusenc.o opus_rc.o opustab.o opus_pvq.o \ +OBJS-$(CONFIG_OPUS_ENCODER) += opusenc.o opus.o opus_rc.o opustab.o opus_pvq.o \ opusenc_psy.o OBJS-$(CONFIG_PAF_AUDIO_DECODER) += pafaudio.o OBJS-$(CONFIG_PAF_VIDEO_DECODER) += pafvideo.o @@ -571,6 +587,8 @@ OBJS-$(CONFIG_SUBVIEWER_DECODER) += subviewerdec.o ass.o OBJS-$(CONFIG_SUNRAST_DECODER) += sunrast.o OBJS-$(CONFIG_SUNRAST_ENCODER) += sunrastenc.o OBJS-$(CONFIG_LIBRSVG_DECODER) += librsvgdec.o +OBJS-$(CONFIG_SBC_DECODER) += sbcdec.o sbcdec_data.o sbc.o +OBJS-$(CONFIG_SBC_ENCODER) += sbcenc.o sbc.o sbcdsp.o sbcdsp_data.o OBJS-$(CONFIG_SVQ1_DECODER) += svq1dec.o svq1.o svq13.o h263data.o OBJS-$(CONFIG_SVQ1_ENCODER) += svq1enc.o svq1.o h263data.o \ h263.o ituh263enc.o @@ -616,7 +634,7 @@ OBJS-$(CONFIG_VC1_DECODER) += vc1dec.o vc1_block.o vc1_loopfilter.o vc1_mc.o vc1_pred.o vc1.o vc1data.o \ msmpeg4dec.o msmpeg4.o msmpeg4data.o \ wmv2dsp.o wmv2data.o -OBJS-$(CONFIG_VC1_CUVID_DECODER) += cuvid.o +OBJS-$(CONFIG_VC1_CUVID_DECODER) += cuviddec.o OBJS-$(CONFIG_VC1_MMAL_DECODER) += mmaldec.o OBJS-$(CONFIG_VC1_QSV_DECODER) += qsvdec_other.o OBJS-$(CONFIG_VC1_V4L2M2M_DECODER) += v4l2_m2m_dec.o @@ -635,7 +653,7 @@ OBJS-$(CONFIG_VP6_DECODER) += vp6.o vp56.o vp56data.o \ vp6dsp.o vp56rac.o OBJS-$(CONFIG_VP7_DECODER) += vp8.o vp56rac.o OBJS-$(CONFIG_VP8_DECODER) += vp8.o vp56rac.o -OBJS-$(CONFIG_VP8_CUVID_DECODER) += cuvid.o +OBJS-$(CONFIG_VP8_CUVID_DECODER) += cuviddec.o OBJS-$(CONFIG_VP8_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_VP8_QSV_DECODER) += qsvdec_other.o OBJS-$(CONFIG_VP8_RKMPP_DECODER) += rkmppdec.o @@ -645,7 +663,7 @@ OBJS-$(CONFIG_VP8_V4L2M2M_ENCODER) += v4l2_m2m_enc.o OBJS-$(CONFIG_VP9_DECODER) += vp9.o vp9data.o vp9dsp.o vp9lpf.o vp9recon.o \ vp9block.o vp9prob.o vp9mvs.o vp56rac.o \ vp9dsp_8bpp.o vp9dsp_10bpp.o vp9dsp_12bpp.o -OBJS-$(CONFIG_VP9_CUVID_DECODER) += cuvid.o +OBJS-$(CONFIG_VP9_CUVID_DECODER) += cuviddec.o OBJS-$(CONFIG_VP9_MEDIACODEC_DECODER) += mediacodecdec.o OBJS-$(CONFIG_VP9_RKMPP_DECODER) += rkmppdec.o OBJS-$(CONFIG_VP9_VAAPI_ENCODER) += vaapi_encode_vp9.o @@ -822,8 +840,8 @@ OBJS-$(CONFIG_ADPCM_YAMAHA_ENCODER) += adpcmenc.o adpcm_data.o # hardware accelerators OBJS-$(CONFIG_D3D11VA) += dxva2.o OBJS-$(CONFIG_DXVA2) += dxva2.o +OBJS-$(CONFIG_NVDEC) += nvdec.o OBJS-$(CONFIG_VAAPI) += vaapi_decode.o -OBJS-$(CONFIG_VDA) += vda.o videotoolbox.o OBJS-$(CONFIG_VIDEOTOOLBOX) += videotoolbox.o OBJS-$(CONFIG_VDPAU) += vdpau.o @@ -831,36 +849,46 @@ OBJS-$(CONFIG_H263_VAAPI_HWACCEL) += vaapi_mpeg4.o OBJS-$(CONFIG_H263_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o OBJS-$(CONFIG_H264_D3D11VA_HWACCEL) += dxva2_h264.o OBJS-$(CONFIG_H264_DXVA2_HWACCEL) += dxva2_h264.o +OBJS-$(CONFIG_H264_NVDEC_HWACCEL) += nvdec_h264.o OBJS-$(CONFIG_H264_QSV_HWACCEL) += qsvdec_h2645.o OBJS-$(CONFIG_H264_VAAPI_HWACCEL) += vaapi_h264.o -OBJS-$(CONFIG_H264_VDA_HWACCEL) += vda_h264.o OBJS-$(CONFIG_H264_VDPAU_HWACCEL) += vdpau_h264.o OBJS-$(CONFIG_H264_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o OBJS-$(CONFIG_HEVC_D3D11VA_HWACCEL) += dxva2_hevc.o OBJS-$(CONFIG_HEVC_DXVA2_HWACCEL) += dxva2_hevc.o +OBJS-$(CONFIG_HEVC_NVDEC_HWACCEL) += nvdec_hevc.o OBJS-$(CONFIG_HEVC_QSV_HWACCEL) += qsvdec_h2645.o OBJS-$(CONFIG_HEVC_VAAPI_HWACCEL) += vaapi_hevc.o OBJS-$(CONFIG_HEVC_VDPAU_HWACCEL) += vdpau_hevc.o +OBJS-$(CONFIG_MJPEG_NVDEC_HWACCEL) += nvdec_mjpeg.o +OBJS-$(CONFIG_MJPEG_VAAPI_HWACCEL) += vaapi_mjpeg.o +OBJS-$(CONFIG_MPEG1_NVDEC_HWACCEL) += nvdec_mpeg12.o OBJS-$(CONFIG_MPEG1_VDPAU_HWACCEL) += vdpau_mpeg12.o OBJS-$(CONFIG_MPEG1_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o OBJS-$(CONFIG_MPEG1_XVMC_HWACCEL) += mpegvideo_xvmc.o OBJS-$(CONFIG_MPEG2_D3D11VA_HWACCEL) += dxva2_mpeg2.o OBJS-$(CONFIG_MPEG2_DXVA2_HWACCEL) += dxva2_mpeg2.o +OBJS-$(CONFIG_MPEG2_NVDEC_HWACCEL) += nvdec_mpeg12.o OBJS-$(CONFIG_MPEG2_QSV_HWACCEL) += qsvdec_other.o OBJS-$(CONFIG_MPEG2_VAAPI_HWACCEL) += vaapi_mpeg2.o OBJS-$(CONFIG_MPEG2_VDPAU_HWACCEL) += vdpau_mpeg12.o OBJS-$(CONFIG_MPEG2_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o OBJS-$(CONFIG_MPEG2_XVMC_HWACCEL) += mpegvideo_xvmc.o +OBJS-$(CONFIG_MPEG4_NVDEC_HWACCEL) += nvdec_mpeg4.o OBJS-$(CONFIG_MPEG4_VAAPI_HWACCEL) += vaapi_mpeg4.o OBJS-$(CONFIG_MPEG4_VDPAU_HWACCEL) += vdpau_mpeg4.o OBJS-$(CONFIG_MPEG4_VIDEOTOOLBOX_HWACCEL) += videotoolbox.o OBJS-$(CONFIG_VC1_D3D11VA_HWACCEL) += dxva2_vc1.o OBJS-$(CONFIG_VC1_DXVA2_HWACCEL) += dxva2_vc1.o +OBJS-$(CONFIG_VC1_NVDEC_HWACCEL) += nvdec_vc1.o OBJS-$(CONFIG_VC1_QSV_HWACCEL) += qsvdec_other.o OBJS-$(CONFIG_VC1_VAAPI_HWACCEL) += vaapi_vc1.o OBJS-$(CONFIG_VC1_VDPAU_HWACCEL) += vdpau_vc1.o +OBJS-$(CONFIG_VP8_NVDEC_HWACCEL) += nvdec_vp8.o +OBJS-$(CONFIG_VP8_VAAPI_HWACCEL) += vaapi_vp8.o OBJS-$(CONFIG_VP9_D3D11VA_HWACCEL) += dxva2_vp9.o OBJS-$(CONFIG_VP9_DXVA2_HWACCEL) += dxva2_vp9.o +OBJS-$(CONFIG_VP9_NVDEC_HWACCEL) += nvdec_vp9.o OBJS-$(CONFIG_VP9_VAAPI_HWACCEL) += vaapi_vp9.o OBJS-$(CONFIG_VP8_QSV_HWACCEL) += qsvdec_other.o @@ -869,6 +897,9 @@ OBJS-$(CONFIG_ISO_MEDIA) += mpeg4audio.o mpegaudiodata.o OBJS-$(CONFIG_ADTS_MUXER) += mpeg4audio.o OBJS-$(CONFIG_CAF_DEMUXER) += ac3tab.o +OBJS-$(CONFIG_CODEC2_DEMUXER) += codec2utils.o +OBJS-$(CONFIG_CODEC2_MUXER) += codec2utils.o +OBJS-$(CONFIG_CODEC2RAW_DEMUXER) += codec2utils.o OBJS-$(CONFIG_DNXHD_DEMUXER) += dnxhddata.o OBJS-$(CONFIG_FITS_DEMUXER) += fits.o OBJS-$(CONFIG_FLV_DEMUXER) += mpeg4audio.o @@ -880,7 +911,6 @@ OBJS-$(CONFIG_MXF_MUXER) += dnxhddata.o OBJS-$(CONFIG_NUT_MUXER) += mpegaudiodata.o OBJS-$(CONFIG_NUT_DEMUXER) += mpegaudiodata.o mpeg4audio.o OBJS-$(CONFIG_RTP_MUXER) += mpeg4audio.o -OBJS-$(CONFIG_SPDIF_DEMUXER) += aacadtsdec.o mpeg4audio.o OBJS-$(CONFIG_SPDIF_MUXER) += dca.o OBJS-$(CONFIG_TAK_DEMUXER) += tak.o OBJS-$(CONFIG_WEBM_MUXER) += mpeg4audio.o @@ -909,7 +939,11 @@ OBJS-$(CONFIG_ALAC_AT_ENCODER) += audiotoolboxenc.o OBJS-$(CONFIG_ILBC_AT_ENCODER) += audiotoolboxenc.o OBJS-$(CONFIG_PCM_ALAW_AT_ENCODER) += audiotoolboxenc.o OBJS-$(CONFIG_PCM_MULAW_AT_ENCODER) += audiotoolboxenc.o +OBJS-$(CONFIG_LIBAOM_AV1_DECODER) += libaomdec.o +OBJS-$(CONFIG_LIBAOM_AV1_ENCODER) += libaomenc.o OBJS-$(CONFIG_LIBCELT_DECODER) += libcelt_dec.o +OBJS-$(CONFIG_LIBCODEC2_DECODER) += libcodec2.o codec2utils.o +OBJS-$(CONFIG_LIBCODEC2_ENCODER) += libcodec2.o codec2utils.o OBJS-$(CONFIG_LIBFDK_AAC_DECODER) += libfdk-aacdec.o OBJS-$(CONFIG_LIBFDK_AAC_ENCODER) += libfdk-aacenc.o OBJS-$(CONFIG_LIBGSM_DECODER) += libgsmdec.o @@ -951,15 +985,14 @@ OBJS-$(CONFIG_LIBX262_ENCODER) += libx264.o OBJS-$(CONFIG_LIBX264_ENCODER) += libx264.o OBJS-$(CONFIG_LIBX265_ENCODER) += libx265.o OBJS-$(CONFIG_LIBXAVS_ENCODER) += libxavs.o -OBJS-$(CONFIG_LIBXVID_ENCODER) += libxvid.o +OBJS-$(CONFIG_LIBXVID_ENCODER) += libxvid.o libxvid_rc.o OBJS-$(CONFIG_LIBZVBI_TELETEXT_DECODER) += libzvbi-teletextdec.o ass.o # parsers OBJS-$(CONFIG_AAC_LATM_PARSER) += latm_parser.o OBJS-$(CONFIG_AAC_PARSER) += aac_parser.o aac_ac3_parser.o \ - aacadtsdec.o mpeg4audio.o -OBJS-$(CONFIG_AC3_PARSER) += ac3_parser.o ac3tab.o \ - aac_ac3_parser.o + mpeg4audio.o +OBJS-$(CONFIG_AC3_PARSER) += ac3tab.o aac_ac3_parser.o OBJS-$(CONFIG_ADX_PARSER) += adx_parser.o adx.o OBJS-$(CONFIG_BMP_PARSER) += bmp_parser.o OBJS-$(CONFIG_CAVSVIDEO_PARSER) += cavs_parser.o @@ -989,11 +1022,13 @@ OBJS-$(CONFIG_PNG_PARSER) += png_parser.o OBJS-$(CONFIG_MPEGAUDIO_PARSER) += mpegaudio_parser.o OBJS-$(CONFIG_MPEGVIDEO_PARSER) += mpegvideo_parser.o \ mpeg12.o mpeg12data.o -OBJS-$(CONFIG_OPUS_PARSER) += opus_parser.o opus.o vorbis_data.o +OBJS-$(CONFIG_OPUS_PARSER) += opus_parser.o opus.o opustab.o \ + opus_rc.o vorbis_data.o OBJS-$(CONFIG_PNG_PARSER) += png_parser.o OBJS-$(CONFIG_PNM_PARSER) += pnm_parser.o pnm.o OBJS-$(CONFIG_RV30_PARSER) += rv34_parser.o OBJS-$(CONFIG_RV40_PARSER) += rv34_parser.o +OBJS-$(CONFIG_SBC_PARSER) += sbc_parser.o OBJS-$(CONFIG_SIPR_PARSER) += sipr_parser.o OBJS-$(CONFIG_TAK_PARSER) += tak_parser.o tak.o OBJS-$(CONFIG_VC1_PARSER) += vc1_parser.o vc1.o vc1data.o \ @@ -1004,14 +1039,19 @@ OBJS-$(CONFIG_VP9_PARSER) += vp9_parser.o OBJS-$(CONFIG_XMA_PARSER) += xma_parser.o # bitstream filters -OBJS-$(CONFIG_AAC_ADTSTOASC_BSF) += aac_adtstoasc_bsf.o aacadtsdec.o \ - mpeg4audio.o +OBJS-$(CONFIG_AAC_ADTSTOASC_BSF) += aac_adtstoasc_bsf.o mpeg4audio.o OBJS-$(CONFIG_CHOMP_BSF) += chomp_bsf.o OBJS-$(CONFIG_DUMP_EXTRADATA_BSF) += dump_extradata_bsf.o OBJS-$(CONFIG_DCA_CORE_BSF) += dca_core_bsf.o +OBJS-$(CONFIG_EAC3_CORE_BSF) += eac3_core_bsf.o OBJS-$(CONFIG_EXTRACT_EXTRADATA_BSF) += extract_extradata_bsf.o \ h2645_parse.o +OBJS-$(CONFIG_FILTER_UNITS_BSF) += filter_units_bsf.o +OBJS-$(CONFIG_H264_METADATA_BSF) += h264_metadata_bsf.o OBJS-$(CONFIG_H264_MP4TOANNEXB_BSF) += h264_mp4toannexb_bsf.o +OBJS-$(CONFIG_H264_REDUNDANT_PPS_BSF) += h264_redundant_pps_bsf.o +OBJS-$(CONFIG_HAPQA_EXTRACT_BSF) += hapqa_extract_bsf.o hap.o +OBJS-$(CONFIG_HEVC_METADATA_BSF) += h265_metadata_bsf.o OBJS-$(CONFIG_HEVC_MP4TOANNEXB_BSF) += hevc_mp4toannexb_bsf.o OBJS-$(CONFIG_IMX_DUMP_HEADER_BSF) += imx_dump_header_bsf.o OBJS-$(CONFIG_MJPEG2JPEG_BSF) += mjpeg2jpeg_bsf.o @@ -1020,10 +1060,12 @@ OBJS-$(CONFIG_MPEG4_UNPACK_BFRAMES_BSF) += mpeg4_unpack_bframes_bsf.o OBJS-$(CONFIG_MOV2TEXTSUB_BSF) += movsub_bsf.o OBJS-$(CONFIG_MP3_HEADER_DECOMPRESS_BSF) += mp3_header_decompress_bsf.o \ mpegaudiodata.o +OBJS-$(CONFIG_MPEG2_METADATA_BSF) += mpeg2_metadata_bsf.o OBJS-$(CONFIG_NOISE_BSF) += noise_bsf.o OBJS-$(CONFIG_NULL_BSF) += null_bsf.o OBJS-$(CONFIG_REMOVE_EXTRADATA_BSF) += remove_extradata_bsf.o OBJS-$(CONFIG_TEXT2MOVSUB_BSF) += movsub_bsf.o +OBJS-$(CONFIG_TRACE_HEADERS_BSF) += trace_headers_bsf.o OBJS-$(CONFIG_VP9_RAW_REORDER_BSF) += vp9_raw_reorder_bsf.o OBJS-$(CONFIG_VP9_SUPERFRAME_BSF) += vp9_superframe_bsf.o OBJS-$(CONFIG_VP9_SUPERFRAME_SPLIT_BSF) += vp9_superframe_split_bsf.o @@ -1048,25 +1090,27 @@ SKIPHEADERS += %_tablegen.h \ aacenc_quantization_misc.h \ $(ARCH)/vp56_arith.h \ +SKIPHEADERS-$(CONFIG_AMF) += amfenc.h SKIPHEADERS-$(CONFIG_D3D11VA) += d3d11va.h dxva2_internal.h SKIPHEADERS-$(CONFIG_DXVA2) += dxva2.h dxva2_internal.h SKIPHEADERS-$(CONFIG_JNI) += ffjni.h SKIPHEADERS-$(CONFIG_LIBVPX) += libvpx.h SKIPHEADERS-$(CONFIG_LIBWEBP_ENCODER) += libwebpenc_common.h SKIPHEADERS-$(CONFIG_MEDIACODEC) += mediacodecdec_common.h mediacodec_surface.h mediacodec_wrapper.h mediacodec_sw_buffer.h +SKIPHEADERS-$(CONFIG_NVDEC) += nvdec.h SKIPHEADERS-$(CONFIG_NVENC) += nvenc.h SKIPHEADERS-$(CONFIG_QSV) += qsv.h qsv_internal.h SKIPHEADERS-$(CONFIG_QSVDEC) += qsvdec.h SKIPHEADERS-$(CONFIG_QSVENC) += qsvenc.h SKIPHEADERS-$(CONFIG_XVMC) += xvmc.h SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_decode.h vaapi_encode.h -SKIPHEADERS-$(CONFIG_VDA) += vda.h vda_vt_internal.h SKIPHEADERS-$(CONFIG_VDPAU) += vdpau.h vdpau_internal.h -SKIPHEADERS-$(CONFIG_VIDEOTOOLBOX) += videotoolbox.h vda_vt_internal.h +SKIPHEADERS-$(CONFIG_VIDEOTOOLBOX) += videotoolbox.h vt_internal.h SKIPHEADERS-$(CONFIG_V4L2_M2M) += v4l2_buffers.h v4l2_context.h v4l2_m2m.h TESTPROGS = avpacket \ celp_math \ + codec_desc \ htmlsubtitles \ imgconvert \ jpeg2000dwt \ @@ -1082,6 +1126,7 @@ TESTPROGS-$(CONFIG_GOLOMB) += golomb TESTPROGS-$(CONFIG_IDCTDSP) += dct TESTPROGS-$(CONFIG_IIRFILTER) += iirfilter TESTPROGS-$(HAVE_MMX) += motion +TESTPROGS-$(CONFIG_MPEGVIDEO) += mpeg12framerate TESTPROGS-$(CONFIG_RANGECODER) += rangecoder TESTPROGS-$(CONFIG_SNOW_ENCODER) += snowenc diff --git a/libavcodec/aac.h b/libavcodec/aac.h index 4910c661d6197..05bc95385f231 100644 --- a/libavcodec/aac.h +++ b/libavcodec/aac.h @@ -357,6 +357,8 @@ struct AACContext { int warned_num_aac_frames; int warned_960_sbr; + int warned_gain_control; + /* aacdec functions pointers */ void (*imdct_and_windowing)(AACContext *ac, SingleChannelElement *sce); void (*apply_ltp)(AACContext *ac, SingleChannelElement *sce); diff --git a/libavcodec/aac_ac3_parser.c b/libavcodec/aac_ac3_parser.c index c9ba6bf062cdf..54e459844f141 100644 --- a/libavcodec/aac_ac3_parser.c +++ b/libavcodec/aac_ac3_parser.c @@ -60,6 +60,9 @@ int ff_aac_ac3_parse(AVCodecParserContext *s1, s->remaining_size += i; goto get_next; } + else if (i < 0) { + s->remaining_size += i; + } } } } @@ -86,17 +89,7 @@ int ff_aac_ac3_parse(AVCodecParserContext *s1, the frame). */ if (avctx->codec_id != AV_CODEC_ID_AAC) { avctx->sample_rate = s->sample_rate; - - /* (E-)AC-3: allow downmixing to stereo or mono */ - if (s->channels > 1 && - avctx->request_channel_layout == AV_CH_LAYOUT_MONO) { - avctx->channels = 1; - avctx->channel_layout = AV_CH_LAYOUT_MONO; - } else if (s->channels > 2 && - avctx->request_channel_layout == AV_CH_LAYOUT_STEREO) { - avctx->channels = 2; - avctx->channel_layout = AV_CH_LAYOUT_STEREO; - } else { + if (avctx->codec_id != AV_CODEC_ID_EAC3) { avctx->channels = s->channels; avctx->channel_layout = s->channel_layout; } @@ -104,7 +97,8 @@ int ff_aac_ac3_parse(AVCodecParserContext *s1, avctx->audio_service_type = s->service_type; } - avctx->bit_rate = s->bit_rate; + if (avctx->codec_id != AV_CODEC_ID_EAC3) + avctx->bit_rate = s->bit_rate; } return i; diff --git a/libavcodec/aac_adtstoasc_bsf.c b/libavcodec/aac_adtstoasc_bsf.c index 4bcf55b193a48..6541b1189c21c 100644 --- a/libavcodec/aac_adtstoasc_bsf.c +++ b/libavcodec/aac_adtstoasc_bsf.c @@ -19,8 +19,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "adts_header.h" +#include "adts_parser.h" #include "avcodec.h" -#include "aacadtsdec.h" #include "bsf.h" #include "put_bits.h" #include "get_bits.h" @@ -35,29 +36,28 @@ typedef struct AACBSFContext { * This filter creates an MPEG-4 AudioSpecificConfig from an MPEG-2/4 * ADTS header and removes the ADTS header. */ -static int aac_adtstoasc_filter(AVBSFContext *bsfc, AVPacket *out) +static int aac_adtstoasc_filter(AVBSFContext *bsfc, AVPacket *pkt) { AACBSFContext *ctx = bsfc->priv_data; GetBitContext gb; PutBitContext pb; AACADTSHeaderInfo hdr; - AVPacket *in; int ret; - ret = ff_bsf_get_packet(bsfc, &in); + ret = ff_bsf_get_packet_ref(bsfc, pkt); if (ret < 0) return ret; - if (bsfc->par_in->extradata && in->size >= 2 && (AV_RB16(in->data) >> 4) != 0xfff) - goto finish; + if (bsfc->par_in->extradata && pkt->size >= 2 && (AV_RB16(pkt->data) >> 4) != 0xfff) + return 0; - if (in->size < AAC_ADTS_HEADER_SIZE) + if (pkt->size < AV_AAC_ADTS_HEADER_SIZE) goto packet_too_small; - init_get_bits(&gb, in->data, AAC_ADTS_HEADER_SIZE * 8); + init_get_bits(&gb, pkt->data, AV_AAC_ADTS_HEADER_SIZE * 8); - if (avpriv_aac_parse_header(&gb, &hdr) < 0) { + if (ff_adts_header_parse(&gb, &hdr) < 0) { av_log(bsfc, AV_LOG_ERROR, "Error parsing ADTS frame header!\n"); ret = AVERROR_INVALIDDATA; goto fail; @@ -70,10 +70,10 @@ static int aac_adtstoasc_filter(AVBSFContext *bsfc, AVPacket *out) goto fail; } - in->size -= AAC_ADTS_HEADER_SIZE + 2 * !hdr.crc_absent; - if (in->size <= 0) + pkt->size -= AV_AAC_ADTS_HEADER_SIZE + 2 * !hdr.crc_absent; + if (pkt->size <= 0) goto packet_too_small; - in->data += AAC_ADTS_HEADER_SIZE + 2 * !hdr.crc_absent; + pkt->data += AV_AAC_ADTS_HEADER_SIZE + 2 * !hdr.crc_absent; if (!ctx->first_frame_done) { int pce_size = 0; @@ -81,7 +81,7 @@ static int aac_adtstoasc_filter(AVBSFContext *bsfc, AVPacket *out) uint8_t *extradata; if (!hdr.chan_config) { - init_get_bits(&gb, in->data, in->size * 8); + init_get_bits(&gb, pkt->data, pkt->size * 8); if (get_bits(&gb, 3) != 5) { avpriv_report_missing_feature(bsfc, "PCE-based channel configuration " @@ -91,13 +91,13 @@ static int aac_adtstoasc_filter(AVBSFContext *bsfc, AVPacket *out) goto fail; } init_put_bits(&pb, pce_data, MAX_PCE_SIZE); - pce_size = avpriv_copy_pce_data(&pb, &gb)/8; + pce_size = ff_copy_pce_data(&pb, &gb) / 8; flush_put_bits(&pb); - in->size -= get_bits_count(&gb)/8; - in->data += get_bits_count(&gb)/8; + pkt->size -= get_bits_count(&gb)/8; + pkt->data += get_bits_count(&gb)/8; } - extradata = av_packet_new_side_data(in, AV_PKT_DATA_NEW_EXTRADATA, + extradata = av_packet_new_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, 2 + pce_size); if (!extradata) { ret = AVERROR(ENOMEM); @@ -119,17 +119,13 @@ static int aac_adtstoasc_filter(AVBSFContext *bsfc, AVPacket *out) ctx->first_frame_done = 1; } -finish: - av_packet_move_ref(out, in); - av_packet_free(&in); - return 0; packet_too_small: av_log(bsfc, AV_LOG_ERROR, "Input packet too small\n"); ret = AVERROR_INVALIDDATA; fail: - av_packet_free(&in); + av_packet_unref(pkt); return ret; } diff --git a/libavcodec/aac_parser.c b/libavcodec/aac_parser.c index 0b868edcb2521..b8692625f3f61 100644 --- a/libavcodec/aac_parser.c +++ b/libavcodec/aac_parser.c @@ -22,7 +22,8 @@ #include "parser.h" #include "aac_ac3_parser.h" -#include "aacadtsdec.h" +#include "adts_header.h" +#include "adts_parser.h" #include "get_bits.h" #include "mpeg4audio.h" @@ -38,9 +39,10 @@ static int aac_sync(uint64_t state, AACAC3ParseContext *hdr_info, } tmp; tmp.u64 = av_be2ne64(state); - init_get_bits(&bits, tmp.u8+8-AAC_ADTS_HEADER_SIZE, AAC_ADTS_HEADER_SIZE * 8); + init_get_bits(&bits, tmp.u8 + 8 - AV_AAC_ADTS_HEADER_SIZE, + AV_AAC_ADTS_HEADER_SIZE * 8); - if ((size = avpriv_aac_parse_header(&bits, &hdr)) < 0) + if ((size = ff_adts_header_parse(&bits, &hdr)) < 0) return 0; *need_next_header = 0; *new_frame_start = 1; @@ -54,7 +56,7 @@ static int aac_sync(uint64_t state, AACAC3ParseContext *hdr_info, static av_cold int aac_parse_init(AVCodecParserContext *s1) { AACAC3ParseContext *s = s1->priv_data; - s->header_size = AAC_ADTS_HEADER_SIZE; + s->header_size = AV_AAC_ADTS_HEADER_SIZE; s->sync = aac_sync; return 0; } diff --git a/libavcodec/aacdec.c b/libavcodec/aacdec.c index fe5087147682b..d394700cdc857 100644 --- a/libavcodec/aacdec.c +++ b/libavcodec/aacdec.c @@ -50,11 +50,11 @@ #include "aac.h" #include "aactab.h" #include "aacdectab.h" +#include "adts_header.h" #include "cbrt_data.h" #include "sbr.h" #include "aacsbr.h" #include "mpeg4audio.h" -#include "aacadtsdec.h" #include "profiles.h" #include "libavutil/intfloat.h" @@ -318,8 +318,8 @@ static int latm_decode_audio_specific_config(struct LATMContext *latmctx, ac->oc[1].m4ac.sample_rate != m4ac.sample_rate || ac->oc[1].m4ac.chan_config != m4ac.chan_config) { - if(latmctx->initialized) { - av_log(avctx, AV_LOG_INFO, "audio config changed\n"); + if (latmctx->initialized) { + av_log(avctx, AV_LOG_INFO, "audio config changed (sample_rate=%d, chan_config=%d)\n", m4ac.sample_rate, m4ac.chan_config); } else { av_log(avctx, AV_LOG_DEBUG, "initializing latmctx\n"); } diff --git a/libavcodec/aacdec_fixed.c b/libavcodec/aacdec_fixed.c index f6a533010f2ac..5c3613e06ce63 100644 --- a/libavcodec/aacdec_fixed.c +++ b/libavcodec/aacdec_fixed.c @@ -75,11 +75,11 @@ #include "aac.h" #include "aactab.h" #include "aacdectab.h" +#include "adts_header.h" #include "cbrt_data.h" #include "sbr.h" #include "aacsbr.h" #include "mpeg4audio.h" -#include "aacadtsdec.h" #include "profiles.h" #include "libavutil/intfloat.h" @@ -307,9 +307,9 @@ static av_always_inline void predict(PredictorState *ps, int *coef, if (shift < 31) { if (shift > 0) { - *coef += (pv.mant + (1 << (shift - 1))) >> shift; + *coef += (unsigned)((pv.mant + (1 << (shift - 1))) >> shift); } else - *coef += pv.mant << -shift; + *coef += (unsigned)pv.mant << -shift; } } @@ -394,7 +394,7 @@ static void apply_dependent_coupling_fixed(AACContext *ac, for (k = offsets[i]; k < offsets[i + 1]; k++) { tmp = (int)(((int64_t)src[group * 128 + k] * c + \ (int64_t)0x1000000000) >> 37); - dest[group * 128 + k] += tmp * (1 << shift); + dest[group * 128 + k] += tmp * (1U << shift); } } } @@ -417,7 +417,7 @@ static void apply_independent_coupling_fixed(AACContext *ac, int i, c, shift, round, tmp; const int gain = cce->coup.gain[index][0]; const int *src = cce->ch[0].ret; - int *dest = target->ret; + unsigned int *dest = target->ret; const int len = 1024 << (ac->oc[1].m4ac.sbr == 1); c = cce_scale_fixed[gain & 7]; diff --git a/libavcodec/aacdec_template.c b/libavcodec/aacdec_template.c index 082cc908d2bdf..cf971810926ed 100644 --- a/libavcodec/aacdec_template.c +++ b/libavcodec/aacdec_template.c @@ -997,6 +997,7 @@ static int decode_audio_specific_config_gb(AACContext *ac, switch (m4ac->object_type) { case AOT_AAC_MAIN: case AOT_AAC_LC: + case AOT_AAC_SSR: case AOT_AAC_LTP: case AOT_ER_AAC_LC: case AOT_ER_AAC_LD: @@ -1967,6 +1968,33 @@ static void apply_prediction(AACContext *ac, SingleChannelElement *sce) reset_all_predictors(sce->predictor_state); } +static void decode_gain_control(SingleChannelElement * sce, GetBitContext * gb) +{ + // wd_num, wd_test, aloc_size + static const uint8_t gain_mode[4][3] = { + {1, 0, 5}, // ONLY_LONG_SEQUENCE = 0, + {2, 1, 2}, // LONG_START_SEQUENCE, + {8, 0, 2}, // EIGHT_SHORT_SEQUENCE, + {2, 1, 5}, // LONG_STOP_SEQUENCE + }; + + const int mode = sce->ics.window_sequence[0]; + uint8_t bd, wd, ad; + + // FIXME: Store the gain control data on |sce| and do something with it. + uint8_t max_band = get_bits(gb, 2); + for (bd = 0; bd < max_band; bd++) { + for (wd = 0; wd < gain_mode[mode][0]; wd++) { + uint8_t adjust_num = get_bits(gb, 3); + for (ad = 0; ad < adjust_num; ad++) { + skip_bits(gb, 4 + ((wd == 0 && gain_mode[mode][1]) + ? 4 + : gain_mode[mode][2])); + } + } + } +} + /** * Decode an individual_channel_stream payload; reference: table 4.44. * @@ -2034,9 +2062,11 @@ static int decode_ics(AACContext *ac, SingleChannelElement *sce, goto fail; } if (!eld_syntax && get_bits1(gb)) { - avpriv_request_sample(ac->avctx, "SSR"); - ret = AVERROR_PATCHWELCOME; - goto fail; + decode_gain_control(sce, gb); + if (!ac->warned_gain_control) { + avpriv_report_missing_feature(ac->avctx, "Gain control"); + ac->warned_gain_control = 1; + } } // I see no textual basis in the spec for this occurring after SSR gain // control, but this is what both reference and real implmentations do @@ -2561,7 +2591,7 @@ static void apply_ltp(AACContext *ac, SingleChannelElement *sce) for (sfb = 0; sfb < FFMIN(sce->ics.max_sfb, MAX_LTP_LONG_SFB); sfb++) if (ltp->used[sfb]) for (i = offsets[sfb]; i < offsets[sfb + 1]; i++) - sce->coeffs[i] += predFreq[i]; + sce->coeffs[i] += (UINTFLOAT)predFreq[i]; } } @@ -2955,7 +2985,7 @@ static int parse_adts_frame_header(AACContext *ac, GetBitContext *gb) uint8_t layout_map[MAX_ELEM_ID*4][3]; int layout_map_tags, ret; - size = avpriv_aac_parse_header(gb, &hdr_info); + size = ff_adts_header_parse(gb, &hdr_info); if (size > 0) { if (!ac->warned_num_aac_frames && hdr_info.num_aac_frames != 1) { // This is 2 for "VLB " audio in NSV files. diff --git a/libavcodec/aacenc.c b/libavcodec/aacenc.c index 11da260742b09..6d94c76905994 100644 --- a/libavcodec/aacenc.c +++ b/libavcodec/aacenc.c @@ -50,17 +50,59 @@ static AVOnce aac_table_init = AV_ONCE_INIT; +static void put_pce(PutBitContext *pb, AVCodecContext *avctx) +{ + int i, j; + AACEncContext *s = avctx->priv_data; + AACPCEInfo *pce = &s->pce; + const int bitexact = avctx->flags & AV_CODEC_FLAG_BITEXACT; + const char *aux_data = bitexact ? "Lavc" : LIBAVCODEC_IDENT; + + put_bits(pb, 4, 0); + + put_bits(pb, 2, avctx->profile); + put_bits(pb, 4, s->samplerate_index); + + put_bits(pb, 4, pce->num_ele[0]); /* Front */ + put_bits(pb, 4, pce->num_ele[1]); /* Side */ + put_bits(pb, 4, pce->num_ele[2]); /* Back */ + put_bits(pb, 2, pce->num_ele[3]); /* LFE */ + put_bits(pb, 3, 0); /* Assoc data */ + put_bits(pb, 4, 0); /* CCs */ + + put_bits(pb, 1, 0); /* Stereo mixdown */ + put_bits(pb, 1, 0); /* Mono mixdown */ + put_bits(pb, 1, 0); /* Something else */ + + for (i = 0; i < 4; i++) { + for (j = 0; j < pce->num_ele[i]; j++) { + if (i < 3) + put_bits(pb, 1, pce->pairing[i][j]); + put_bits(pb, 4, pce->index[i][j]); + } + } + + avpriv_align_put_bits(pb); + put_bits(pb, 8, strlen(aux_data)); + avpriv_put_string(pb, aux_data, 0); +} + /** * Make AAC audio config object. * @see 1.6.2.1 "Syntax - AudioSpecificConfig" */ -static void put_audio_specific_config(AVCodecContext *avctx) +static int put_audio_specific_config(AVCodecContext *avctx) { PutBitContext pb; AACEncContext *s = avctx->priv_data; - int channels = s->channels - (s->channels == 8 ? 1 : 0); + int channels = (!s->needs_pce)*(s->channels - (s->channels == 8 ? 1 : 0)); + const int max_size = 32; + + avctx->extradata = av_mallocz(max_size); + if (!avctx->extradata) + return AVERROR(ENOMEM); - init_put_bits(&pb, avctx->extradata, avctx->extradata_size); + init_put_bits(&pb, avctx->extradata, max_size); put_bits(&pb, 5, s->profile+1); //profile put_bits(&pb, 4, s->samplerate_index); //sample rate index put_bits(&pb, 4, channels); @@ -68,12 +110,17 @@ static void put_audio_specific_config(AVCodecContext *avctx) put_bits(&pb, 1, 0); //frame length - 1024 samples put_bits(&pb, 1, 0); //does not depend on core coder put_bits(&pb, 1, 0); //is not extension + if (s->needs_pce) + put_pce(&pb, avctx); //Explicitly Mark SBR absent put_bits(&pb, 11, 0x2b7); //sync extension put_bits(&pb, 5, AOT_SBR); put_bits(&pb, 1, 0); flush_put_bits(&pb); + avctx->extradata_size = put_bits_count(&pb) >> 3; + + return 0; } void ff_quantize_band_cost_cache_init(struct AACEncContext *s) @@ -488,7 +535,7 @@ static void copy_input_samples(AACEncContext *s, const AVFrame *frame) { int ch; int end = 2048 + (frame ? frame->nb_samples : 0); - const uint8_t *channel_map = aac_chan_maps[s->channels - 1]; + const uint8_t *channel_map = s->reorder_map; /* copy and remap input samples */ for (ch = 0; ch < s->channels; ch++) { @@ -895,7 +942,6 @@ static av_cold int alloc_buffers(AVCodecContext *avctx, AACEncContext *s) int ch; FF_ALLOCZ_ARRAY_OR_GOTO(avctx, s->buffer.samples, s->channels, 3 * 1024 * sizeof(s->buffer.samples[0]), alloc_fail); FF_ALLOCZ_ARRAY_OR_GOTO(avctx, s->cpe, s->chan_map[0], sizeof(ChannelElement), alloc_fail); - FF_ALLOCZ_OR_GOTO(avctx, avctx->extradata, 5 + AV_INPUT_BUFFER_PADDING_SIZE, alloc_fail); for(ch = 0; ch < s->channels; ch++) s->planar_samples[ch] = s->buffer.samples + 3 * 1024 * ch; @@ -920,16 +966,35 @@ static av_cold int aac_encode_init(AVCodecContext *avctx) /* Constants */ s->last_frame_pb_count = 0; - avctx->extradata_size = 5; avctx->frame_size = 1024; avctx->initial_padding = 1024; s->lambda = avctx->global_quality > 0 ? avctx->global_quality : 120; /* Channel map and unspecified bitrate guessing */ s->channels = avctx->channels; - ERROR_IF(s->channels > AAC_MAX_CHANNELS || s->channels == 7, - "Unsupported number of channels: %d\n", s->channels); - s->chan_map = aac_chan_configs[s->channels-1]; + + s->needs_pce = 1; + for (i = 0; i < FF_ARRAY_ELEMS(aac_normal_chan_layouts); i++) { + if (avctx->channel_layout == aac_normal_chan_layouts[i]) { + s->needs_pce = s->options.pce; + break; + } + } + + if (s->needs_pce) { + for (i = 0; i < FF_ARRAY_ELEMS(aac_pce_configs); i++) + if (avctx->channel_layout == aac_pce_configs[i].layout) + break; + ERROR_IF(i == FF_ARRAY_ELEMS(aac_pce_configs), "Unsupported channel layout\n"); + av_log(avctx, AV_LOG_INFO, "Using a PCE to encode channel layout\n"); + s->pce = aac_pce_configs[i]; + s->reorder_map = s->pce.reorder_map; + s->chan_map = s->pce.config_map; + } else { + s->reorder_map = aac_chan_maps[s->channels - 1]; + s->chan_map = aac_chan_configs[s->channels - 1]; + } + if (!avctx->bit_rate) { for (i = 1; i <= s->chan_map[0]; i++) { avctx->bit_rate += s->chan_map[i] == TYPE_CPE ? 128000 : /* Pair */ @@ -1015,7 +1080,8 @@ static av_cold int aac_encode_init(AVCodecContext *avctx) if ((ret = alloc_buffers(avctx, s)) < 0) goto fail; - put_audio_specific_config(avctx); + if ((ret = put_audio_specific_config(avctx))) + goto fail; sizes[0] = ff_aac_swb_size_1024[s->samplerate_index]; sizes[1] = ff_aac_swb_size_128[s->samplerate_index]; @@ -1052,24 +1118,25 @@ static av_cold int aac_encode_init(AVCodecContext *avctx) #define AACENC_FLAGS AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM static const AVOption aacenc_options[] = { - {"aac_coder", "Coding algorithm", offsetof(AACEncContext, options.coder), AV_OPT_TYPE_INT, {.i64 = AAC_CODER_TWOLOOP}, 0, AAC_CODER_NB-1, AACENC_FLAGS, "coder"}, + {"aac_coder", "Coding algorithm", offsetof(AACEncContext, options.coder), AV_OPT_TYPE_INT, {.i64 = AAC_CODER_FAST}, 0, AAC_CODER_NB-1, AACENC_FLAGS, "coder"}, {"anmr", "ANMR method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_ANMR}, INT_MIN, INT_MAX, AACENC_FLAGS, "coder"}, {"twoloop", "Two loop searching method", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_TWOLOOP}, INT_MIN, INT_MAX, AACENC_FLAGS, "coder"}, - {"fast", "Constant quantizer", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_FAST}, INT_MIN, INT_MAX, AACENC_FLAGS, "coder"}, + {"fast", "Default fast search", 0, AV_OPT_TYPE_CONST, {.i64 = AAC_CODER_FAST}, INT_MIN, INT_MAX, AACENC_FLAGS, "coder"}, {"aac_ms", "Force M/S stereo coding", offsetof(AACEncContext, options.mid_side), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AACENC_FLAGS}, {"aac_is", "Intensity stereo coding", offsetof(AACEncContext, options.intensity_stereo), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS}, {"aac_pns", "Perceptual noise substitution", offsetof(AACEncContext, options.pns), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS}, {"aac_tns", "Temporal noise shaping", offsetof(AACEncContext, options.tns), AV_OPT_TYPE_BOOL, {.i64 = 1}, -1, 1, AACENC_FLAGS}, {"aac_ltp", "Long term prediction", offsetof(AACEncContext, options.ltp), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS}, {"aac_pred", "AAC-Main prediction", offsetof(AACEncContext, options.pred), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS}, + {"aac_pce", "Forces the use of PCEs", offsetof(AACEncContext, options.pce), AV_OPT_TYPE_BOOL, {.i64 = 0}, -1, 1, AACENC_FLAGS}, {NULL} }; static const AVClass aacenc_class = { - "AAC encoder", - av_default_item_name, - aacenc_options, - LIBAVUTIL_VERSION_INT, + .class_name = "AAC encoder", + .item_name = av_default_item_name, + .option = aacenc_options, + .version = LIBAVUTIL_VERSION_INT, }; static const AVCodecDefault aac_encode_defaults[] = { diff --git a/libavcodec/aacenc.h b/libavcodec/aacenc.h index ea2d3b9628c03..5a015ca92e307 100644 --- a/libavcodec/aacenc.h +++ b/libavcodec/aacenc.h @@ -45,6 +45,7 @@ typedef struct AACEncOptions { int pns; int tns; int ltp; + int pce; int pred; int mid_side; int intensity_stereo; @@ -89,6 +90,286 @@ typedef struct AACQuantizeBandCostCacheEntry { uint16_t generation; } AACQuantizeBandCostCacheEntry; +typedef struct AACPCEInfo { + int64_t layout; + int num_ele[4]; ///< front, side, back, lfe + int pairing[3][8]; ///< front, side, back + int index[4][8]; ///< front, side, back, lfe + uint8_t config_map[16]; ///< configs the encoder's channel specific settings + uint8_t reorder_map[16]; ///< maps channels from lavc to aac order +} AACPCEInfo; + +/** + * List of PCE (Program Configuration Element) for the channel layouts listed + * in channel_layout.h + * + * For those wishing in the future to add other layouts: + * + * - num_ele: number of elements in each group of front, side, back, lfe channels + * (an element is of type SCE (single channel), CPE (channel pair) for + * the first 3 groups; and is LFE for LFE group). + * + * - pairing: 0 for an SCE element or 1 for a CPE; does not apply to LFE group + * + * - index: there are three independent indices for SCE, CPE and LFE; + * they are incremented irrespective of the group to which the element belongs; + * they are not reset when going from one group to another + * + * Example: for 7.0 channel layout, + * .pairing = { { 1, 0 }, { 1 }, { 1 }, }, (3 CPE and 1 SCE in front group) + * .index = { { 0, 0 }, { 1 }, { 2 }, }, + * (index is 0 for the single SCE but goes from 0 to 2 for the CPEs) + * + * The index order impacts the channel ordering. But is otherwise arbitrary + * (the sequence could have been 2, 0, 1 instead of 0, 1, 2). + * + * Spec allows for discontinuous indices, e.g. if one has a total of two SCE, + * SCE.0 SCE.15 is OK per spec; BUT it won't be decoded by our AAC decoder + * which at this time requires that indices fully cover some range starting + * from 0 (SCE.1 SCE.0 is OK but not SCE.0 SCE.15). + * + * - config_map: total number of elements and their types. Beware, the way the + * types are ordered impacts the final channel ordering. + * + * - reorder_map: reorders the channels. + * + */ +static const AACPCEInfo aac_pce_configs[] = { + { + .layout = AV_CH_LAYOUT_MONO, + .num_ele = { 1, 0, 0, 0 }, + .pairing = { { 0 }, }, + .index = { { 0 }, }, + .config_map = { 1, TYPE_SCE, }, + .reorder_map = { 0 }, + }, + { + .layout = AV_CH_LAYOUT_STEREO, + .num_ele = { 1, 0, 0, 0 }, + .pairing = { { 1 }, }, + .index = { { 0 }, }, + .config_map = { 1, TYPE_CPE, }, + .reorder_map = { 0, 1 }, + }, + { + .layout = AV_CH_LAYOUT_2POINT1, + .num_ele = { 1, 0, 0, 1 }, + .pairing = { { 1 }, }, + .index = { { 0 },{ 0 },{ 0 },{ 0 } }, + .config_map = { 2, TYPE_CPE, TYPE_LFE }, + .reorder_map = { 0, 1, 2 }, + }, + { + .layout = AV_CH_LAYOUT_2_1, + .num_ele = { 1, 0, 1, 0 }, + .pairing = { { 1 },{ 0 },{ 0 } }, + .index = { { 0 },{ 0 },{ 0 }, }, + .config_map = { 2, TYPE_CPE, TYPE_SCE }, + .reorder_map = { 0, 1, 2 }, + }, + { + .layout = AV_CH_LAYOUT_SURROUND, + .num_ele = { 2, 0, 0, 0 }, + .pairing = { { 1, 0 }, }, + .index = { { 0, 0 }, }, + .config_map = { 2, TYPE_CPE, TYPE_SCE, }, + .reorder_map = { 0, 1, 2 }, + }, + { + .layout = AV_CH_LAYOUT_3POINT1, + .num_ele = { 2, 0, 0, 1 }, + .pairing = { { 1, 0 }, }, + .index = { { 0, 0 }, { 0 }, { 0 }, { 0 }, }, + .config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_LFE }, + .reorder_map = { 0, 1, 2, 3 }, + }, + { + .layout = AV_CH_LAYOUT_4POINT0, + .num_ele = { 2, 0, 1, 0 }, + .pairing = { { 1, 0 }, { 0 }, { 0 }, }, + .index = { { 0, 0 }, { 0 }, { 1 } }, + .config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_SCE }, + .reorder_map = { 0, 1, 2, 3 }, + }, + { + .layout = AV_CH_LAYOUT_4POINT1, + .num_ele = { 2, 1, 1, 0 }, + .pairing = { { 1, 0 }, { 0 }, { 0 }, }, + .index = { { 0, 0 }, { 1 }, { 2 }, { 0 } }, + .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_SCE }, + .reorder_map = { 0, 1, 2, 3, 4 }, + }, + { + .layout = AV_CH_LAYOUT_2_2, + .num_ele = { 1, 1, 0, 0 }, + .pairing = { { 1 }, { 1 }, }, + .index = { { 0 }, { 1 }, }, + .config_map = { 2, TYPE_CPE, TYPE_CPE }, + .reorder_map = { 0, 1, 2, 3 }, + }, + { + .layout = AV_CH_LAYOUT_QUAD, + .num_ele = { 1, 0, 1, 0 }, + .pairing = { { 1 }, { 0 }, { 1 }, }, + .index = { { 0 }, { 0 }, { 1 } }, + .config_map = { 2, TYPE_CPE, TYPE_CPE }, + .reorder_map = { 0, 1, 2, 3 }, + }, + { + .layout = AV_CH_LAYOUT_5POINT0, + .num_ele = { 2, 1, 0, 0 }, + .pairing = { { 1, 0 }, { 1 }, }, + .index = { { 0, 0 }, { 1 } }, + .config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_CPE }, + .reorder_map = { 0, 1, 2, 3, 4 }, + }, + { + .layout = AV_CH_LAYOUT_5POINT1, + .num_ele = { 2, 1, 1, 0 }, + .pairing = { { 1, 0 }, { 0 }, { 1 }, }, + .index = { { 0, 0 }, { 1 }, { 1 } }, + .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE }, + .reorder_map = { 0, 1, 2, 3, 4, 5 }, + }, + { + .layout = AV_CH_LAYOUT_5POINT0_BACK, + .num_ele = { 2, 0, 1, 0 }, + .pairing = { { 1, 0 }, { 0 }, { 1 } }, + .index = { { 0, 0 }, { 0 }, { 1 } }, + .config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_CPE }, + .reorder_map = { 0, 1, 2, 3, 4 }, + }, + { + .layout = AV_CH_LAYOUT_5POINT1_BACK, + .num_ele = { 2, 1, 1, 0 }, + .pairing = { { 1, 0 }, { 0 }, { 1 }, }, + .index = { { 0, 0 }, { 1 }, { 1 } }, + .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE }, + .reorder_map = { 0, 1, 2, 3, 4, 5 }, + }, + { + .layout = AV_CH_LAYOUT_6POINT0, + .num_ele = { 2, 1, 1, 0 }, + .pairing = { { 1, 0 }, { 1 }, { 0 }, }, + .index = { { 0, 0 }, { 1 }, { 1 } }, + .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, + .reorder_map = { 0, 1, 2, 3, 4, 5 }, + }, + { + .layout = AV_CH_LAYOUT_6POINT0_FRONT, + .num_ele = { 2, 1, 0, 0 }, + .pairing = { { 1, 1 }, { 1 } }, + .index = { { 1, 0 }, { 2 }, }, + .config_map = { 3, TYPE_CPE, TYPE_CPE, TYPE_CPE, }, + .reorder_map = { 0, 1, 2, 3, 4, 5 }, + }, + { + .layout = AV_CH_LAYOUT_HEXAGONAL, + .num_ele = { 2, 0, 2, 0 }, + .pairing = { { 1, 0 },{ 0 },{ 1, 0 }, }, + .index = { { 0, 0 },{ 0 },{ 1, 1 } }, + .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE, }, + .reorder_map = { 0, 1, 2, 3, 4, 5 }, + }, + { + .layout = AV_CH_LAYOUT_6POINT1, + .num_ele = { 2, 1, 2, 0 }, + .pairing = { { 1, 0 },{ 0 },{ 1, 0 }, }, + .index = { { 0, 0 },{ 1 },{ 1, 2 } }, + .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6 }, + }, + { + .layout = AV_CH_LAYOUT_6POINT1_BACK, + .num_ele = { 2, 1, 2, 0 }, + .pairing = { { 1, 0 }, { 0 }, { 1, 0 }, }, + .index = { { 0, 0 }, { 1 }, { 1, 2 } }, + .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6 }, + }, + { + .layout = AV_CH_LAYOUT_6POINT1_FRONT, + .num_ele = { 2, 1, 2, 0 }, + .pairing = { { 1, 0 }, { 0 }, { 1, 0 }, }, + .index = { { 0, 0 }, { 1 }, { 1, 2 } }, + .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6 }, + }, + { + .layout = AV_CH_LAYOUT_7POINT0, + .num_ele = { 2, 1, 1, 0 }, + .pairing = { { 1, 0 }, { 1 }, { 1 }, }, + .index = { { 0, 0 }, { 1 }, { 2 }, }, + .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6 }, + }, + { + .layout = AV_CH_LAYOUT_7POINT0_FRONT, + .num_ele = { 2, 1, 1, 0 }, + .pairing = { { 1, 0 }, { 1 }, { 1 }, }, + .index = { { 0, 0 }, { 1 }, { 2 }, }, + .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6 }, + }, + { + .layout = AV_CH_LAYOUT_7POINT1, + .num_ele = { 2, 1, 2, 0 }, + .pairing = { { 1, 0 }, { 0 }, { 1, 1 }, }, + .index = { { 0, 0 }, { 1 }, { 1, 2 }, { 0 } }, + .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_CPE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 }, + }, + { + .layout = AV_CH_LAYOUT_7POINT1_WIDE, + .num_ele = { 2, 1, 2, 0 }, + .pairing = { { 1, 0 }, { 0 },{ 1, 1 }, }, + .index = { { 0, 0 }, { 1 }, { 1, 2 }, { 0 } }, + .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_CPE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 }, + }, + { + .layout = AV_CH_LAYOUT_7POINT1_WIDE_BACK, + .num_ele = { 2, 1, 2, 0 }, + .pairing = { { 1, 0 }, { 0 }, { 1, 1 }, }, + .index = { { 0, 0 }, { 1 }, { 1, 2 }, { 0 } }, + .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_CPE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 }, + }, + { + .layout = AV_CH_LAYOUT_OCTAGONAL, + .num_ele = { 2, 1, 2, 0 }, + .pairing = { { 1, 0 }, { 1 }, { 1, 0 }, }, + .index = { { 0, 0 }, { 1 }, { 2, 1 } }, + .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_SCE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 }, + }, + { /* Meant for order 2/mixed ambisonics */ + .layout = AV_CH_LAYOUT_OCTAGONAL | AV_CH_TOP_CENTER, + .num_ele = { 2, 2, 2, 0 }, + .pairing = { { 1, 0 }, { 1, 0 }, { 1, 0 }, }, + .index = { { 0, 0 }, { 1, 1 }, { 2, 2 } }, + .config_map = { 6, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, + }, + { /* Meant for order 2/mixed ambisonics */ + .layout = AV_CH_LAYOUT_6POINT0_FRONT | AV_CH_BACK_CENTER | + AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT | AV_CH_TOP_CENTER, + .num_ele = { 2, 2, 2, 0 }, + .pairing = { { 1, 1 }, { 1, 0 }, { 1, 0 }, }, + .index = { { 0, 1 }, { 2, 0 }, { 3, 1 } }, + .config_map = { 6, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, + }, + { + .layout = AV_CH_LAYOUT_HEXADECAGONAL, + .num_ele = { 4, 2, 4, 0 }, + .pairing = { { 1, 0, 1, 0 }, { 1, 1 }, { 1, 0, 1, 0 }, }, + .index = { { 0, 0, 1, 1 }, { 2, 3 }, { 4, 2, 5, 3 } }, + .config_map = { 10, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, + .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, + }, +}; + /** * AAC encoder context */ @@ -99,12 +380,15 @@ typedef struct AACEncContext { FFTContext mdct1024; ///< long (1024 samples) frame transform context FFTContext mdct128; ///< short (128 samples) frame transform context AVFloatDSPContext *fdsp; - float *planar_samples[8]; ///< saved preprocessed input + AACPCEInfo pce; ///< PCE data, if needed + float *planar_samples[16]; ///< saved preprocessed input int profile; ///< copied from avctx + int needs_pce; ///< flag for non-standard layout LPCContext lpc; ///< used by TNS int samplerate_index; ///< MPEG-4 samplerate index int channels; ///< channel count + const uint8_t *reorder_map; ///< lavc to aac reorder map const uint8_t *chan_map; ///< channel configuration map ChannelElement *cpe; ///< channel elements diff --git a/libavcodec/aacenctab.h b/libavcodec/aacenctab.h index 5fc9411232742..64932d709f848 100644 --- a/libavcodec/aacenctab.h +++ b/libavcodec/aacenctab.h @@ -36,13 +36,24 @@ /** Total number of codebooks, including special ones **/ #define CB_TOT_ALL 15 -#define AAC_MAX_CHANNELS 8 +#define AAC_MAX_CHANNELS 16 extern const uint8_t *ff_aac_swb_size_1024[]; extern const int ff_aac_swb_size_1024_len; extern const uint8_t *ff_aac_swb_size_128[]; extern const int ff_aac_swb_size_128_len; +/* Supported layouts without using a PCE */ +static const int64_t aac_normal_chan_layouts[7] = { + AV_CH_LAYOUT_MONO, + AV_CH_LAYOUT_STEREO, + AV_CH_LAYOUT_SURROUND, + AV_CH_LAYOUT_4POINT0, + AV_CH_LAYOUT_5POINT0_BACK, + AV_CH_LAYOUT_5POINT1_BACK, + AV_CH_LAYOUT_7POINT1, +}; + /** default channel configurations */ static const uint8_t aac_chan_configs[AAC_MAX_CHANNELS][6] = { {1, TYPE_SCE}, // 1 channel - single channel element diff --git a/libavcodec/aacpsdsp_template.c b/libavcodec/aacpsdsp_template.c index e35e9699b0b5a..19be200653645 100644 --- a/libavcodec/aacpsdsp_template.c +++ b/libavcodec/aacpsdsp_template.c @@ -130,12 +130,12 @@ static void ps_decorrelate_c(INTFLOAT (*out)[2], INTFLOAT (*delay)[2], INTFLOAT apd_im = in_im; in_re = AAC_MSUB30(link_delay_re, fractional_delay_re, link_delay_im, fractional_delay_im); - in_re -= a_re; + in_re -= (UINTFLOAT)a_re; in_im = AAC_MADD30(link_delay_re, fractional_delay_im, link_delay_im, fractional_delay_re); - in_im -= a_im; - ap_delay[m][n+5][0] = apd_re + AAC_MUL31(ag[m], in_re); - ap_delay[m][n+5][1] = apd_im + AAC_MUL31(ag[m], in_im); + in_im -= (UINTFLOAT)a_im; + ap_delay[m][n+5][0] = apd_re + (UINTFLOAT)AAC_MUL31(ag[m], in_re); + ap_delay[m][n+5][1] = apd_im + (UINTFLOAT)AAC_MUL31(ag[m], in_im); } out[n][0] = AAC_MUL16(transient_gain[n], in_re); out[n][1] = AAC_MUL16(transient_gain[n], in_im); diff --git a/libavcodec/aacsbr_fixed.c b/libavcodec/aacsbr_fixed.c index 289bb86a810b8..59cbba10fffdf 100644 --- a/libavcodec/aacsbr_fixed.c +++ b/libavcodec/aacsbr_fixed.c @@ -433,6 +433,7 @@ static void sbr_gain_calc(AACContext *ac, SpectralBandReplication *sbr, av_add_sf(FLOAT_1, sbr->e_curr[e][m]), av_add_sf(FLOAT_1, sbr->q_mapped[e][m])))); } + sbr->gain[e][m] = av_add_sf(sbr->gain[e][m], FLOAT_MIN); } for (m = sbr->f_tablelim[k] - sbr->kx[1]; m < sbr->f_tablelim[k + 1] - sbr->kx[1]; m++) { sum[0] = av_add_sf(sum[0], sbr->e_origmapped[e][m]); @@ -566,8 +567,9 @@ static void sbr_hf_assemble(int Y1[38][64][2], int idx = indexsine&1; int A = (1-((indexsine+(kx & 1))&2)); int B = (A^(-idx)) + idx; - int *out = &Y1[i][kx][idx]; - int shift, round; + unsigned *out = &Y1[i][kx][idx]; + int shift; + unsigned round; SoftFloat *in = sbr->s_m[e]; for (m = 0; m+1 < m_max; m+=2) { @@ -580,12 +582,12 @@ static void sbr_hf_assemble(int Y1[38][64][2], } if (shift < 32) { round = 1 << (shift-1); - out[2*m ] += (in[m ].mant * A + round) >> shift; + out[2*m ] += (int)(in[m ].mant * A + round) >> shift; } if (shift2 < 32) { round = 1 << (shift2-1); - out[2*m+2] += (in[m+1].mant * B + round) >> shift2; + out[2*m+2] += (int)(in[m+1].mant * B + round) >> shift2; } } if(m_max&1) @@ -596,7 +598,7 @@ static void sbr_hf_assemble(int Y1[38][64][2], return; } else if (shift < 32) { round = 1 << (shift-1); - out[2*m ] += (in[m ].mant * A + round) >> shift; + out[2*m ] += (int)(in[m ].mant * A + round) >> shift; } } } diff --git a/libavcodec/aarch64/mpegaudiodsp_neon.S b/libavcodec/aarch64/mpegaudiodsp_neon.S index cc7d9b321c45f..b6ef131228ae5 100644 --- a/libavcodec/aarch64/mpegaudiodsp_neon.S +++ b/libavcodec/aarch64/mpegaudiodsp_neon.S @@ -24,7 +24,7 @@ #define WFRAC_BITS 16 // fractional bits for window #define OUT_SHIFT (WFRAC_BITS + FRAC_BITS - 15) -const tbl_rev128.s, align=4 +const tbl_rev128_s, align=4 .byte 12, 13, 14, 15 .byte 8, 9, 10, 11 .byte 4, 5, 6, 7 @@ -39,7 +39,7 @@ function ff_mpadsp_apply_window_\type\()_neon, export=1 ld1 {v4.4s,v5.4s,v6.4s,v7.4s}, [x7], #64 st1 {v0.4s,v1.4s,v2.4s,v3.4s}, [x8], #64 st1 {v4.4s,v5.4s,v6.4s,v7.4s}, [x8], #64 - movrel x15, tbl_rev128.s + movrel x15, tbl_rev128_s ld1 {v27.4s}, [x15] .ifc \type, fixed lsl x4, x4, #1 diff --git a/libavcodec/aarch64/sbrdsp_neon.S b/libavcodec/aarch64/sbrdsp_neon.S index d1d79b749c2fe..d23717e76055f 100644 --- a/libavcodec/aarch64/sbrdsp_neon.S +++ b/libavcodec/aarch64/sbrdsp_neon.S @@ -287,7 +287,7 @@ endfunc zip1 v4.4S, v4.4S, v4.4S fmla v6.4S, v1.4S, v3.4S fmla v2.4S, v5.4S, v4.4S - fcmeq v7.4S, v3.4S, #0.0 + fcmeq v7.4S, v3.4S, #0 bif v2.16B, v6.16B, v7.16B st1 {v2.4S}, [x0], #16 subs x5, x5, #2 diff --git a/libavcodec/ac3.h b/libavcodec/ac3.h index 5c9c37727e7df..f8f6a81f45105 100644 --- a/libavcodec/ac3.h +++ b/libavcodec/ac3.h @@ -28,6 +28,7 @@ #define AVCODEC_AC3_H #define AC3_MAX_CODED_FRAME_SIZE 3840 /* in bytes */ +#define EAC3_MAX_CHANNELS 16 /**< maximum number of channels in EAC3 */ #define AC3_MAX_CHANNELS 7 /**< maximum number of channels, including coupling channel */ #define CPL_CH 0 /**< coupling channel index */ diff --git a/libavcodec/ac3_parser.c b/libavcodec/ac3_parser.c index 83dd90ff67668..f4618bf215ee4 100644 --- a/libavcodec/ac3_parser.c +++ b/libavcodec/ac3_parser.c @@ -20,15 +20,19 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config.h" + #include "libavutil/channel_layout.h" #include "parser.h" #include "ac3_parser.h" +#include "ac3_parser_internal.h" #include "aac_ac3_parser.h" #include "get_bits.h" #define AC3_HEADER_SIZE 7 +#if CONFIG_AC3_PARSER static const uint8_t eac3_blocks[4] = { 1, 2, 3, 6 @@ -47,16 +51,9 @@ static const uint8_t center_levels[4] = { 4, 5, 6, 5 }; static const uint8_t surround_levels[4] = { 4, 6, 7, 6 }; -int avpriv_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo **phdr) +int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr) { int frame_size_code; - AC3HeaderInfo *hdr; - - if (!*phdr) - *phdr = av_mallocz(sizeof(AC3HeaderInfo)); - if (!*phdr) - return AVERROR(ENOMEM); - hdr = *phdr; memset(hdr, 0, sizeof(*hdr)); @@ -151,6 +148,46 @@ int avpriv_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo **phdr) return 0; } +// TODO: Better way to pass AC3HeaderInfo fields to mov muxer. +int avpriv_ac3_parse_header(AC3HeaderInfo **phdr, const uint8_t *buf, + size_t size) +{ + GetBitContext gb; + AC3HeaderInfo *hdr; + int err; + + if (!*phdr) + *phdr = av_mallocz(sizeof(AC3HeaderInfo)); + if (!*phdr) + return AVERROR(ENOMEM); + hdr = *phdr; + + init_get_bits8(&gb, buf, size); + err = ff_ac3_parse_header(&gb, hdr); + if (err < 0) + return AVERROR_INVALIDDATA; + + return get_bits_count(&gb); +} + +int av_ac3_parse_header(const uint8_t *buf, size_t size, + uint8_t *bitstream_id, uint16_t *frame_size) +{ + GetBitContext gb; + AC3HeaderInfo hdr; + int err; + + init_get_bits8(&gb, buf, size); + err = ff_ac3_parse_header(&gb, &hdr); + if (err < 0) + return AVERROR_INVALIDDATA; + + *bitstream_id = hdr.bitstream_id; + *frame_size = hdr.frame_size; + + return 0; +} + static int ac3_sync(uint64_t state, AACAC3ParseContext *hdr_info, int *need_next_header, int *new_frame_start) { @@ -159,11 +196,11 @@ static int ac3_sync(uint64_t state, AACAC3ParseContext *hdr_info, uint64_t u64; uint8_t u8[8 + AV_INPUT_BUFFER_PADDING_SIZE]; } tmp = { av_be2ne64(state) }; - AC3HeaderInfo hdr, *phdr = &hdr; + AC3HeaderInfo hdr; GetBitContext gbc; init_get_bits(&gbc, tmp.u8+8-AC3_HEADER_SIZE, 54); - err = avpriv_ac3_parse_header(&gbc, &phdr); + err = ff_ac3_parse_header(&gbc, &hdr); if(err < 0) return 0; @@ -181,8 +218,8 @@ static int ac3_sync(uint64_t state, AACAC3ParseContext *hdr_info, else if (hdr_info->codec_id == AV_CODEC_ID_NONE) hdr_info->codec_id = AV_CODEC_ID_AC3; - *need_next_header = (hdr.frame_type != EAC3_FRAME_TYPE_AC3_CONVERT); *new_frame_start = (hdr.frame_type != EAC3_FRAME_TYPE_DEPENDENT); + *need_next_header = *new_frame_start || (hdr.frame_type != EAC3_FRAME_TYPE_AC3_CONVERT); return hdr.frame_size; } @@ -202,3 +239,18 @@ AVCodecParser ff_ac3_parser = { .parser_parse = ff_aac_ac3_parse, .parser_close = ff_parse_close, }; + +#else + +int avpriv_ac3_parse_header(AC3HeaderInfo **phdr, const uint8_t *buf, + size_t size) +{ + return AVERROR(ENOSYS); +} + +int av_ac3_parse_header(const uint8_t *buf, size_t size, + uint8_t *bitstream_id, uint16_t *frame_size) +{ + return AVERROR(ENOSYS); +} +#endif diff --git a/libavcodec/ac3_parser.h b/libavcodec/ac3_parser.h index dc5d035e11a71..ff8cc4cf09311 100644 --- a/libavcodec/ac3_parser.h +++ b/libavcodec/ac3_parser.h @@ -23,20 +23,14 @@ #ifndef AVCODEC_AC3_PARSER_H #define AVCODEC_AC3_PARSER_H -#include "ac3.h" -#include "get_bits.h" +#include +#include /** - * Parse AC-3 frame header. - * Parse the header up to the lfeon element, which is the first 52 or 54 bits - * depending on the audio coding mode. - * @param[in] gbc BitContext containing the first 54 bits of the frame. - * @param[out] hdr Pointer to Pointer to struct where header info is written. - * will be allocated if NULL - * @return Returns 0 on success, -1 if there is a sync word mismatch, - * -2 if the bsid (version) element is invalid, -3 if the fscod (sample rate) - * element is invalid, or -4 if the frmsizecod (bit rate) element is invalid. + * Extract the bitstream ID and the frame size from AC-3 data. */ -int avpriv_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo **hdr); +int av_ac3_parse_header(const uint8_t *buf, size_t size, + uint8_t *bitstream_id, uint16_t *frame_size); + #endif /* AVCODEC_AC3_PARSER_H */ diff --git a/libavcodec/ac3_parser_internal.h b/libavcodec/ac3_parser_internal.h new file mode 100644 index 0000000000000..3648802a737d0 --- /dev/null +++ b/libavcodec/ac3_parser_internal.h @@ -0,0 +1,42 @@ +/* + * AC-3 parser internal code + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_AC3_PARSER_INTERNAL_H +#define AVCODEC_AC3_PARSER_INTERNAL_H + +#include "ac3.h" +#include "get_bits.h" + +/** + * Parse AC-3 frame header. + * Parse the header up to the lfeon element, which is the first 52 or 54 bits + * depending on the audio coding mode. + * @param[in] gbc BitContext containing the first 54 bits of the frame. + * @param[out] hdr Pointer to struct where header info is written. + * @return Returns 0 on success, -1 if there is a sync word mismatch, + * -2 if the bsid (version) element is invalid, -3 if the fscod (sample rate) + * element is invalid, or -4 if the frmsizecod (bit rate) element is invalid. + */ +int ff_ac3_parse_header(GetBitContext *gbc, AC3HeaderInfo *hdr); + +int avpriv_ac3_parse_header(AC3HeaderInfo **hdr, const uint8_t *buf, + size_t size); + +#endif /* AVCODEC_AC3_PARSER_INTERNAL_H */ diff --git a/libavcodec/ac3dec.c b/libavcodec/ac3dec.c index c393076aec2a8..b14d2e74ace8d 100644 --- a/libavcodec/ac3dec.c +++ b/libavcodec/ac3dec.c @@ -36,7 +36,7 @@ #include "bswapdsp.h" #include "internal.h" #include "aac_ac3_parser.h" -#include "ac3_parser.h" +#include "ac3_parser_internal.h" #include "ac3dec.h" #include "ac3dec_data.h" #include "kbdwin.h" @@ -106,6 +106,25 @@ static const uint8_t ac3_default_coeffs[8][5][2] = { { { 2, 7 }, { 5, 5 }, { 7, 2 }, { 6, 7 }, { 7, 6 }, }, }; +static const uint64_t custom_channel_map_locations[16][2] = { + { 1, AV_CH_FRONT_LEFT }, + { 1, AV_CH_FRONT_CENTER }, + { 1, AV_CH_FRONT_RIGHT }, + { 1, AV_CH_SIDE_LEFT }, + { 1, AV_CH_SIDE_RIGHT }, + { 0, AV_CH_FRONT_LEFT_OF_CENTER | AV_CH_FRONT_RIGHT_OF_CENTER }, + { 0, AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT }, + { 0, AV_CH_BACK_CENTER }, + { 0, AV_CH_TOP_CENTER }, + { 0, AV_CH_SURROUND_DIRECT_LEFT | AV_CH_SURROUND_DIRECT_RIGHT }, + { 0, AV_CH_WIDE_LEFT | AV_CH_WIDE_RIGHT }, + { 0, AV_CH_TOP_FRONT_LEFT | AV_CH_TOP_FRONT_RIGHT}, + { 0, AV_CH_TOP_FRONT_CENTER }, + { 0, AV_CH_TOP_BACK_LEFT | AV_CH_TOP_BACK_RIGHT }, + { 0, AV_CH_LOW_FREQUENCY_2 }, + { 1, AV_CH_LOW_FREQUENCY }, +}; + /** * Symmetrical Dequantization * reference: Section 7.3.3 Expansion of Mantissas for Symmetrical Quantization @@ -297,10 +316,10 @@ static int ac3_parse_header(AC3DecodeContext *s) */ static int parse_frame_header(AC3DecodeContext *s) { - AC3HeaderInfo hdr, *phdr=&hdr; + AC3HeaderInfo hdr; int err; - err = avpriv_ac3_parse_header(&s->gbc, &phdr); + err = ff_ac3_parse_header(&s->gbc, &hdr); if (err) return err; @@ -317,6 +336,7 @@ static int parse_frame_header(AC3DecodeContext *s) s->fbw_channels = s->channels - s->lfe_on; s->lfe_ch = s->fbw_channels + 1; s->frame_size = hdr.frame_size; + s->superframe_size += hdr.frame_size; s->preferred_downmix = AC3_DMIXMOD_NOTINDICATED; s->center_mix_level = hdr.center_mix_level; s->center_mix_level_ltrt = 4; // -3.0dB @@ -683,7 +703,7 @@ static void do_rematrixing(AC3DecodeContext *s) * Convert frequency domain coefficients to time-domain audio samples. * reference: Section 7.9.4 Transformation Equations */ -static inline void do_imdct(AC3DecodeContext *s, int channels) +static inline void do_imdct(AC3DecodeContext *s, int channels, int offset) { int ch; @@ -695,25 +715,25 @@ static inline void do_imdct(AC3DecodeContext *s, int channels) x[i] = s->transform_coeffs[ch][2 * i]; s->imdct_256.imdct_half(&s->imdct_256, s->tmp_output, x); #if USE_FIXED - s->fdsp->vector_fmul_window_scaled(s->outptr[ch - 1], s->delay[ch - 1], + s->fdsp->vector_fmul_window_scaled(s->outptr[ch - 1], s->delay[ch - 1 + offset], s->tmp_output, s->window, 128, 8); #else - s->fdsp->vector_fmul_window(s->outptr[ch - 1], s->delay[ch - 1], + s->fdsp->vector_fmul_window(s->outptr[ch - 1], s->delay[ch - 1 + offset], s->tmp_output, s->window, 128); #endif for (i = 0; i < 128; i++) x[i] = s->transform_coeffs[ch][2 * i + 1]; - s->imdct_256.imdct_half(&s->imdct_256, s->delay[ch - 1], x); + s->imdct_256.imdct_half(&s->imdct_256, s->delay[ch - 1 + offset], x); } else { s->imdct_512.imdct_half(&s->imdct_512, s->tmp_output, s->transform_coeffs[ch]); #if USE_FIXED - s->fdsp->vector_fmul_window_scaled(s->outptr[ch - 1], s->delay[ch - 1], + s->fdsp->vector_fmul_window_scaled(s->outptr[ch - 1], s->delay[ch - 1 + offset], s->tmp_output, s->window, 128, 8); #else - s->fdsp->vector_fmul_window(s->outptr[ch - 1], s->delay[ch - 1], + s->fdsp->vector_fmul_window(s->outptr[ch - 1], s->delay[ch - 1 + offset], s->tmp_output, s->window, 128); #endif - memcpy(s->delay[ch - 1], s->tmp_output + 128, 128 * sizeof(FFTSample)); + memcpy(s->delay[ch - 1 + offset], s->tmp_output + 128, 128 * sizeof(FFTSample)); } } } @@ -1063,7 +1083,7 @@ static inline int coupling_coordinates(AC3DecodeContext *s, int blk) /** * Decode a single audio block from the AC-3 bitstream. */ -static int decode_audio_block(AC3DecodeContext *s, int blk) +static int decode_audio_block(AC3DecodeContext *s, int blk, int offset) { int fbw_channels = s->fbw_channels; int channel_mode = s->channel_mode; @@ -1426,7 +1446,7 @@ static int decode_audio_block(AC3DecodeContext *s, int blk) ac3_upmix_delay(s); } - do_imdct(s, s->channels); + do_imdct(s, s->channels, offset); if (downmix_output) { #if USE_FIXED @@ -1449,7 +1469,7 @@ static int decode_audio_block(AC3DecodeContext *s, int blk) s->out_channels, s->fbw_channels, 128); } - do_imdct(s, s->out_channels); + do_imdct(s, s->out_channels, offset); } return 0; @@ -1463,14 +1483,19 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data, { AVFrame *frame = data; const uint8_t *buf = avpkt->data; - int buf_size = avpkt->size; + int buf_size, full_buf_size = avpkt->size; AC3DecodeContext *s = avctx->priv_data; - int blk, ch, err, ret; + int blk, ch, err, offset, ret; + int got_independent_frame = 0; const uint8_t *channel_map; + uint8_t extended_channel_map[EAC3_MAX_CHANNELS]; const SHORTFLOAT *output[AC3_MAX_CHANNELS]; enum AVMatrixEncoding matrix_encoding; AVDownmixInfo *downmix_info; + s->superframe_size = 0; + + buf_size = full_buf_size; /* copy input buffer to decoder context to avoid reading past the end of the buffer, which can be caused by a damaged input stream. */ if (buf_size >= 2 && AV_RB16(buf) == 0x770B) { @@ -1488,6 +1513,7 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data, av_lfg_init_from_data(&s->dith_state, s->input_buffer, FFMIN(buf_size, AC3_FRAME_BUFFER_SIZE)); buf = s->input_buffer; +dependent_frame: /* initialize the GetBitContext with the start of valid AC-3 Frame */ if ((ret = init_get_bits8(&s->gbc, buf, buf_size)) < 0) return ret; @@ -1511,11 +1537,11 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data, break; case AAC_AC3_PARSE_ERROR_FRAME_TYPE: /* skip frame if CRC is ok. otherwise use error concealment. */ - /* TODO: add support for substreams and dependent frames */ - if (s->frame_type == EAC3_FRAME_TYPE_DEPENDENT || s->substreamid) { + /* TODO: add support for substreams */ + if (s->substreamid) { av_log(avctx, AV_LOG_DEBUG, - "unsupported frame type %d: skipping frame\n", - s->frame_type); + "unsupported substream %d: skipping frame\n", + s->substreamid); *got_frame_ptr = 0; return buf_size; } else { @@ -1546,10 +1572,10 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data, } } - /* if frame is ok, set audio parameters */ - if (!err) { - avctx->sample_rate = s->sample_rate; - avctx->bit_rate = s->bit_rate; + if (s->frame_type == EAC3_FRAME_TYPE_DEPENDENT && !got_independent_frame) { + av_log(avctx, AV_LOG_WARNING, "Ignoring dependent frame without independent frame.\n"); + *got_frame_ptr = 0; + return FFMIN(full_buf_size, s->frame_size); } /* channel config */ @@ -1594,29 +1620,25 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data, if (s->bitstream_mode == 0x7 && s->channels > 1) avctx->audio_service_type = AV_AUDIO_SERVICE_TYPE_KARAOKE; - /* get output buffer */ - frame->nb_samples = s->num_blocks * AC3_BLOCK_SIZE; - if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) - return ret; - /* decode the audio blocks */ channel_map = ff_ac3_dec_channel_map[s->output_mode & ~AC3_OUTPUT_LFEON][s->lfe_on]; + offset = s->frame_type == EAC3_FRAME_TYPE_DEPENDENT ? AC3_MAX_CHANNELS : 0; for (ch = 0; ch < AC3_MAX_CHANNELS; ch++) { - output[ch] = s->output[ch]; - s->outptr[ch] = s->output[ch]; + output[ch] = s->output[ch + offset]; + s->outptr[ch] = s->output[ch + offset]; } for (ch = 0; ch < s->channels; ch++) { if (ch < s->out_channels) - s->outptr[channel_map[ch]] = (SHORTFLOAT *)frame->data[ch]; + s->outptr[channel_map[ch]] = s->output_buffer[ch + offset]; } for (blk = 0; blk < s->num_blocks; blk++) { - if (!err && decode_audio_block(s, blk)) { + if (!err && decode_audio_block(s, blk, offset)) { av_log(avctx, AV_LOG_ERROR, "error decoding the audio block\n"); err = 1; } if (err) for (ch = 0; ch < s->out_channels; ch++) - memcpy(((SHORTFLOAT*)frame->data[ch]) + AC3_BLOCK_SIZE*blk, output[ch], AC3_BLOCK_SIZE*sizeof(SHORTFLOAT)); + memcpy(s->output_buffer[ch + offset] + AC3_BLOCK_SIZE*blk, output[ch], AC3_BLOCK_SIZE*sizeof(SHORTFLOAT)); for (ch = 0; ch < s->out_channels; ch++) output[ch] = s->outptr[channel_map[ch]]; for (ch = 0; ch < s->out_channels; ch++) { @@ -1625,11 +1647,100 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data, } } - frame->decode_error_flags = err ? FF_DECODE_ERROR_INVALID_BITSTREAM : 0; - /* keep last block for error concealment in next frame */ for (ch = 0; ch < s->out_channels; ch++) - memcpy(s->output[ch], output[ch], AC3_BLOCK_SIZE*sizeof(SHORTFLOAT)); + memcpy(s->output[ch + offset], output[ch], AC3_BLOCK_SIZE*sizeof(SHORTFLOAT)); + + /* check if there is dependent frame */ + if (buf_size > s->frame_size) { + AC3HeaderInfo hdr; + int err; + + if ((ret = init_get_bits8(&s->gbc, buf + s->frame_size, buf_size - s->frame_size)) < 0) + return ret; + + err = ff_ac3_parse_header(&s->gbc, &hdr); + if (err) + return err; + + if (hdr.frame_type == EAC3_FRAME_TYPE_DEPENDENT) { + if (hdr.num_blocks != s->num_blocks || s->sample_rate != hdr.sample_rate) { + av_log(avctx, AV_LOG_WARNING, "Ignoring non-compatible dependent frame.\n"); + } else { + buf += s->frame_size; + buf_size -= s->frame_size; + s->prev_output_mode = s->output_mode; + s->prev_bit_rate = s->bit_rate; + got_independent_frame = 1; + goto dependent_frame; + } + } + } + + frame->decode_error_flags = err ? FF_DECODE_ERROR_INVALID_BITSTREAM : 0; + + /* if frame is ok, set audio parameters */ + if (!err) { + avctx->sample_rate = s->sample_rate; + avctx->bit_rate = s->bit_rate + s->prev_bit_rate; + } + + for (ch = 0; ch < EAC3_MAX_CHANNELS; ch++) + extended_channel_map[ch] = ch; + + if (s->frame_type == EAC3_FRAME_TYPE_DEPENDENT) { + uint64_t ich_layout = avpriv_ac3_channel_layout_tab[s->prev_output_mode & ~AC3_OUTPUT_LFEON]; + uint64_t channel_layout; + int extend = 0; + + if (s->prev_output_mode & AC3_OUTPUT_LFEON) + ich_layout |= AV_CH_LOW_FREQUENCY; + + channel_layout = ich_layout; + for (ch = 0; ch < 16; ch++) { + if (s->channel_map & (1 << (EAC3_MAX_CHANNELS - ch - 1))) { + channel_layout |= custom_channel_map_locations[ch][1]; + } + } + + avctx->channel_layout = channel_layout; + avctx->channels = av_get_channel_layout_nb_channels(channel_layout); + + for (ch = 0; ch < EAC3_MAX_CHANNELS; ch++) { + if (s->channel_map & (1 << (EAC3_MAX_CHANNELS - ch - 1))) { + if (custom_channel_map_locations[ch][0]) { + int index = av_get_channel_layout_channel_index(channel_layout, + custom_channel_map_locations[ch][1]); + if (index < 0) + return AVERROR_INVALIDDATA; + extended_channel_map[index] = offset + channel_map[extend++]; + } else { + int i; + + for (i = 0; i < 64; i++) { + if ((1LL << i) & custom_channel_map_locations[ch][1]) { + int index = av_get_channel_layout_channel_index(channel_layout, + 1LL << i); + if (index < 0) + return AVERROR_INVALIDDATA; + extended_channel_map[index] = offset + channel_map[extend++]; + } + } + } + } + } + } + + /* get output buffer */ + frame->nb_samples = s->num_blocks * AC3_BLOCK_SIZE; + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + + for (ch = 0; ch < avctx->channels; ch++) { + int map = extended_channel_map[ch]; + memcpy((SHORTFLOAT *)frame->data[ch], s->output_buffer[map], + s->num_blocks * AC3_BLOCK_SIZE * sizeof(SHORTFLOAT)); + } /* * AVMatrixEncoding @@ -1689,7 +1800,7 @@ static int ac3_decode_frame(AVCodecContext * avctx, void *data, *got_frame_ptr = 1; - return FFMIN(buf_size, s->frame_size); + return FFMIN(full_buf_size, s->superframe_size); } /** diff --git a/libavcodec/ac3dec.h b/libavcodec/ac3dec.h index aa4cf04f8a94e..ce1434b55c9d9 100644 --- a/libavcodec/ac3dec.h +++ b/libavcodec/ac3dec.h @@ -76,6 +76,7 @@ typedef struct AC3DecodeContext { ///@{ int frame_type; ///< frame type (strmtyp) int substreamid; ///< substream identification + int superframe_size; ///< current superframe size, in bytes int frame_size; ///< current frame size, in bytes int bit_rate; ///< stream bit rate, in bits-per-second int sample_rate; ///< sample frequency, in Hz @@ -87,7 +88,7 @@ typedef struct AC3DecodeContext { int dialog_normalization[2]; ///< dialog level in dBFS (dialnorm) int compression_exists[2]; ///< compression field is valid for frame (compre) int compression_gain[2]; ///< gain to apply for heavy compression (compr) - int channel_map; ///< custom channel map + int channel_map; ///< custom channel map (chanmap) int preferred_downmix; ///< Preferred 2-channel downmix mode (dmixmod) int center_mix_level; ///< Center mix level index int center_mix_level_ltrt; ///< Center mix level index for Lt/Rt (ltrtcmixlev) @@ -164,7 +165,9 @@ typedef struct AC3DecodeContext { SHORTFLOAT *downmix_coeffs[2]; ///< stereo downmix coefficients int downmixed; ///< indicates if coeffs are currently downmixed int output_mode; ///< output channel configuration + int prev_output_mode; ///< output channel configuration for previous frame int out_channels; ///< number of output channels + int prev_bit_rate; ///< stream bit rate, in bits-per-second for previous frame ///@} ///@name Dynamic range @@ -239,11 +242,12 @@ typedef struct AC3DecodeContext { ///@name Aligned arrays DECLARE_ALIGNED(16, int, fixed_coeffs)[AC3_MAX_CHANNELS][AC3_MAX_COEFS]; ///< fixed-point transform coefficients DECLARE_ALIGNED(32, INTFLOAT, transform_coeffs)[AC3_MAX_CHANNELS][AC3_MAX_COEFS]; ///< transform coefficients - DECLARE_ALIGNED(32, INTFLOAT, delay)[AC3_MAX_CHANNELS][AC3_BLOCK_SIZE]; ///< delay - added to the next block + DECLARE_ALIGNED(32, INTFLOAT, delay)[EAC3_MAX_CHANNELS][AC3_BLOCK_SIZE]; ///< delay - added to the next block DECLARE_ALIGNED(32, INTFLOAT, window)[AC3_BLOCK_SIZE]; ///< window coefficients DECLARE_ALIGNED(32, INTFLOAT, tmp_output)[AC3_BLOCK_SIZE]; ///< temporary storage for output before windowing - DECLARE_ALIGNED(32, SHORTFLOAT, output)[AC3_MAX_CHANNELS][AC3_BLOCK_SIZE]; ///< output after imdct transform and windowing + DECLARE_ALIGNED(32, SHORTFLOAT, output)[EAC3_MAX_CHANNELS][AC3_BLOCK_SIZE]; ///< output after imdct transform and windowing DECLARE_ALIGNED(32, uint8_t, input_buffer)[AC3_FRAME_BUFFER_SIZE + AV_INPUT_BUFFER_PADDING_SIZE]; ///< temp buffer to prevent overread + DECLARE_ALIGNED(32, SHORTFLOAT, output_buffer)[EAC3_MAX_CHANNELS][AC3_BLOCK_SIZE * 6]; ///< final output buffer ///@} } AC3DecodeContext; diff --git a/libavcodec/ac3dec_fixed.c b/libavcodec/ac3dec_fixed.c index 9a6d7a08b1c0a..bd66175d50f93 100644 --- a/libavcodec/ac3dec_fixed.c +++ b/libavcodec/ac3dec_fixed.c @@ -64,8 +64,8 @@ static void scale_coefs ( int dynrng, int len) { - int i, shift, round; - unsigned mul; + int i, shift; + unsigned mul, round; int temp, temp1, temp2, temp3, temp4, temp5, temp6, temp7; mul = (dynrng & 0x1f) + 0x20; diff --git a/libavcodec/ac3tab.h b/libavcodec/ac3tab.h index f529fc80774fd..ade6fb15e796f 100644 --- a/libavcodec/ac3tab.h +++ b/libavcodec/ac3tab.h @@ -26,10 +26,11 @@ #include "libavutil/internal.h" #include "ac3.h" +#include "internal.h" extern const uint16_t ff_ac3_frame_size_tab[38][3]; extern const uint8_t ff_ac3_channels_tab[8]; -extern av_export const uint16_t avpriv_ac3_channel_layout_tab[8]; +extern av_export_avcodec const uint16_t avpriv_ac3_channel_layout_tab[8]; extern const uint8_t ff_ac3_enc_channel_map[8][2][6]; extern const uint8_t ff_ac3_dec_channel_map[8][2][6]; extern const uint16_t ff_ac3_sample_rate_tab[3]; diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index be206c55ba439..cd3bbd33c2e44 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -1115,6 +1115,7 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data, int16_t *out1 = samples_p[1]; int samples_per_block = 28 * (3 - avctx->channels) * 4; int sample_offset = 0; + int bytes_remaining; while (bytestream2_get_bytes_left(&gb) >= 128) { if ((ret = xa_decode(avctx, out0, out1, buf + bytestream2_tell(&gb), &c->status[0], &c->status[1], @@ -1123,6 +1124,12 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data, bytestream2_skipu(&gb, 128); sample_offset += samples_per_block; } + /* Less than a full block of data left, e.g. when reading from + * 2324 byte per sector XA; the remainder is padding */ + bytes_remaining = bytestream2_get_bytes_left(&gb); + if (bytes_remaining > 0) { + bytestream2_skip(&gb, bytes_remaining); + } break; } case AV_CODEC_ID_ADPCM_IMA_EA_EACS: diff --git a/libavcodec/aacadtsdec.c b/libavcodec/adts_header.c similarity index 93% rename from libavcodec/aacadtsdec.c rename to libavcodec/adts_header.c index d0814ac27e149..0889820f8a25d 100644 --- a/libavcodec/aacadtsdec.c +++ b/libavcodec/adts_header.c @@ -22,11 +22,12 @@ */ #include "aac_ac3_parser.h" -#include "aacadtsdec.h" +#include "adts_header.h" +#include "adts_parser.h" #include "get_bits.h" #include "mpeg4audio.h" -int avpriv_aac_parse_header(GetBitContext *gbc, AACADTSHeaderInfo *hdr) +int ff_adts_header_parse(GetBitContext *gbc, AACADTSHeaderInfo *hdr) { int size, rdb, ch, sr; int aot, crc_abs; @@ -51,7 +52,7 @@ int avpriv_aac_parse_header(GetBitContext *gbc, AACADTSHeaderInfo *hdr) skip_bits1(gbc); /* copyright_identification_bit */ skip_bits1(gbc); /* copyright_identification_start */ size = get_bits(gbc, 13); /* aac_frame_length */ - if (size < AAC_ADTS_HEADER_SIZE) + if (size < AV_AAC_ADTS_HEADER_SIZE) return AAC_AC3_PARSE_ERROR_FRAME_SIZE; skip_bits(gbc, 11); /* adts_buffer_fullness */ diff --git a/libavcodec/aacadtsdec.h b/libavcodec/adts_header.h similarity index 86% rename from libavcodec/aacadtsdec.h rename to libavcodec/adts_header.h index d0584ef36a2ef..f615f6a9f90c9 100644 --- a/libavcodec/aacadtsdec.h +++ b/libavcodec/adts_header.h @@ -20,14 +20,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_AACADTSDEC_H -#define AVCODEC_AACADTSDEC_H +#ifndef AVCODEC_ADTS_HEADER_H +#define AVCODEC_ADTS_HEADER_H -#include #include "get_bits.h" -#define AAC_ADTS_HEADER_SIZE 7 - typedef struct AACADTSHeaderInfo { uint32_t sample_rate; uint32_t samples; @@ -40,7 +37,6 @@ typedef struct AACADTSHeaderInfo { } AACADTSHeaderInfo; /** - * Parse AAC frame header. * Parse the ADTS frame header to the end of the variable header, which is * the first 54 bits. * @param[in] gbc BitContext containing the first 54 bits of the frame. @@ -49,6 +45,6 @@ typedef struct AACADTSHeaderInfo { * -2 if the version element is invalid, -3 if the sample rate * element is invalid, or -4 if the bit rate element is invalid. */ -int avpriv_aac_parse_header(GetBitContext *gbc, AACADTSHeaderInfo *hdr); +int ff_adts_header_parse(GetBitContext *gbc, AACADTSHeaderInfo *hdr); -#endif /* AVCODEC_AACADTSDEC_H */ +#endif /* AVCODEC_ADTS_HEADER_H */ diff --git a/libavfilter/opencl_allkernels.h b/libavcodec/adts_parser.c similarity index 58% rename from libavfilter/opencl_allkernels.h rename to libavcodec/adts_parser.c index 57b650d27bec9..5c9f8ff6f207f 100644 --- a/libavfilter/opencl_allkernels.h +++ b/libavcodec/adts_parser.c @@ -1,6 +1,4 @@ /* - * Copyright (C) 2013 Wei Gao - * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -18,12 +16,29 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVFILTER_OPENCL_ALLKERNELS_H -#define AVFILTER_OPENCL_ALLKERNELS_H - -#include "avfilter.h" #include "config.h" -void ff_opencl_register_filter_kernel_code_all(void); +#include +#include + +#include "adts_header.h" +#include "adts_parser.h" -#endif /* AVFILTER_OPENCL_ALLKERNELS_H */ +int av_adts_header_parse(const uint8_t *buf, uint32_t *samples, uint8_t *frames) +{ +#if CONFIG_ADTS_HEADER + GetBitContext gb; + AACADTSHeaderInfo hdr; + int err = init_get_bits8(&gb, buf, AV_AAC_ADTS_HEADER_SIZE); + if (err < 0) + return err; + err = ff_adts_header_parse(&gb, &hdr); + if (err < 0) + return err; + *samples = hdr.samples; + *frames = hdr.num_aac_frames; + return 0; +#else + return AVERROR(ENOSYS); +#endif +} diff --git a/libavutil/opencl_internal.h b/libavcodec/adts_parser.h similarity index 56% rename from libavutil/opencl_internal.h rename to libavcodec/adts_parser.h index 5cabb7b3eea99..f85becd13138e 100644 --- a/libavutil/opencl_internal.h +++ b/libavcodec/adts_parser.h @@ -1,8 +1,4 @@ /* - * Copyright (C) 2012 Peng Gao - * Copyright (C) 2012 Li Cao - * Copyright (C) 2012 Wei Gao - * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -20,21 +16,22 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVUTIL_OPENCL_INTERNAL_H -#define AVUTIL_OPENCL_INTERNAL_H - -#include "attributes.h" -#include "opencl.h" +#ifndef AVCODEC_ADTS_PARSER_H +#define AVCODEC_ADTS_PARSER_H -#define FF_OPENCL_PARAM_INFO(a) ((void*)(&(a))), (sizeof(a)) +#include +#include -typedef struct { - cl_kernel kernel; - int param_num; - void *ctx; -} FFOpenclParam; +#define AV_AAC_ADTS_HEADER_SIZE 7 -av_warn_unused_result -int avpriv_opencl_set_parameter(FFOpenclParam *opencl_param, ...); +/** + * Extract the number of samples and frames from AAC data. + * @param[in] buf pointer to AAC data buffer + * @param[out] samples Pointer to where number of samples is written + * @param[out] frames Pointer to where number of frames is written + * @return Returns 0 on success, error code on failure. + */ +int av_adts_header_parse(const uint8_t *buf, uint32_t *samples, + uint8_t *frames); -#endif /* AVUTIL_OPENCL_INTERNAL_H */ +#endif /* AVCODEC_ADTS_PARSER_H */ diff --git a/libavcodec/aic.c b/libavcodec/aic.c index 67d78c5ddd260..9c6f806655e3e 100644 --- a/libavcodec/aic.c +++ b/libavcodec/aic.c @@ -308,6 +308,8 @@ static int aic_decode_slice(AICContext *ctx, int mb_x, int mb_y, GetBitContext gb; int ret, i, mb, blk; int slice_width = FFMIN(ctx->slice_width, ctx->mb_width - mb_x); + int last_row = mb_y && mb_y == ctx->mb_height - 1; + int y_pos, c_pos; uint8_t *Y, *C[2]; uint8_t *dst; int16_t *base_y = ctx->data_ptr[COEFF_LUMA]; @@ -316,10 +318,18 @@ static int aic_decode_slice(AICContext *ctx, int mb_x, int mb_y, int16_t *ext_c = ctx->data_ptr[COEFF_CHROMA_EXT]; const int ystride = ctx->frame->linesize[0]; - Y = ctx->frame->data[0] + mb_x * 16 + mb_y * 16 * ystride; + if (last_row) { + y_pos = (ctx->avctx->height - 16); + c_pos = ((ctx->avctx->height+1)/2 - 8); + } else { + y_pos = mb_y * 16; + c_pos = mb_y * 8; + } + + Y = ctx->frame->data[0] + mb_x * 16 + y_pos * ystride; for (i = 0; i < 2; i++) C[i] = ctx->frame->data[i + 1] + mb_x * 8 - + mb_y * 8 * ctx->frame->linesize[i + 1]; + + c_pos * ctx->frame->linesize[i + 1]; init_get_bits(&gb, src, src_size * 8); memset(ctx->slice_data, 0, diff --git a/libavcodec/alac.c b/libavcodec/alac.c index d6bd21ba1351a..93cf198eeafe5 100644 --- a/libavcodec/alac.c +++ b/libavcodec/alac.c @@ -524,7 +524,7 @@ static int alac_set_info(ALACContext *alac) alac->max_samples_per_frame = bytestream2_get_be32u(&gb); if (!alac->max_samples_per_frame || - alac->max_samples_per_frame > INT_MAX / sizeof(int32_t)) { + alac->max_samples_per_frame > 4096 * 4096) { av_log(alac->avctx, AV_LOG_ERROR, "max samples per frame invalid: %"PRIu32"\n", alac->max_samples_per_frame); diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 4f34312e67353..4d4ef530e4f3b 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -29,732 +29,865 @@ #include "avcodec.h" #include "version.h" -#define REGISTER_HWACCEL(X, x) \ - { \ - extern AVHWAccel ff_##x##_hwaccel; \ - if (CONFIG_##X##_HWACCEL) \ - av_register_hwaccel(&ff_##x##_hwaccel); \ +extern AVCodec ff_a64multi_encoder; +extern AVCodec ff_a64multi5_encoder; +extern AVCodec ff_aasc_decoder; +extern AVCodec ff_aic_decoder; +extern AVCodec ff_alias_pix_encoder; +extern AVCodec ff_alias_pix_decoder; +extern AVCodec ff_amv_encoder; +extern AVCodec ff_amv_decoder; +extern AVCodec ff_anm_decoder; +extern AVCodec ff_ansi_decoder; +extern AVCodec ff_apng_encoder; +extern AVCodec ff_apng_decoder; +extern AVCodec ff_asv1_encoder; +extern AVCodec ff_asv1_decoder; +extern AVCodec ff_asv2_encoder; +extern AVCodec ff_asv2_decoder; +extern AVCodec ff_aura_decoder; +extern AVCodec ff_aura2_decoder; +extern AVCodec ff_avrp_encoder; +extern AVCodec ff_avrp_decoder; +extern AVCodec ff_avrn_decoder; +extern AVCodec ff_avs_decoder; +extern AVCodec ff_avui_encoder; +extern AVCodec ff_avui_decoder; +extern AVCodec ff_ayuv_encoder; +extern AVCodec ff_ayuv_decoder; +extern AVCodec ff_bethsoftvid_decoder; +extern AVCodec ff_bfi_decoder; +extern AVCodec ff_bink_decoder; +extern AVCodec ff_bmp_encoder; +extern AVCodec ff_bmp_decoder; +extern AVCodec ff_bmv_video_decoder; +extern AVCodec ff_brender_pix_decoder; +extern AVCodec ff_c93_decoder; +extern AVCodec ff_cavs_decoder; +extern AVCodec ff_cdgraphics_decoder; +extern AVCodec ff_cdxl_decoder; +extern AVCodec ff_cfhd_decoder; +extern AVCodec ff_cinepak_encoder; +extern AVCodec ff_cinepak_decoder; +extern AVCodec ff_clearvideo_decoder; +extern AVCodec ff_cljr_encoder; +extern AVCodec ff_cljr_decoder; +extern AVCodec ff_cllc_decoder; +extern AVCodec ff_comfortnoise_encoder; +extern AVCodec ff_comfortnoise_decoder; +extern AVCodec ff_cpia_decoder; +extern AVCodec ff_cscd_decoder; +extern AVCodec ff_cyuv_decoder; +extern AVCodec ff_dds_decoder; +extern AVCodec ff_dfa_decoder; +extern AVCodec ff_dirac_decoder; +extern AVCodec ff_dnxhd_encoder; +extern AVCodec ff_dnxhd_decoder; +extern AVCodec ff_dpx_encoder; +extern AVCodec ff_dpx_decoder; +extern AVCodec ff_dsicinvideo_decoder; +extern AVCodec ff_dvaudio_decoder; +extern AVCodec ff_dvvideo_encoder; +extern AVCodec ff_dvvideo_decoder; +extern AVCodec ff_dxa_decoder; +extern AVCodec ff_dxtory_decoder; +extern AVCodec ff_dxv_decoder; +extern AVCodec ff_eacmv_decoder; +extern AVCodec ff_eamad_decoder; +extern AVCodec ff_eatgq_decoder; +extern AVCodec ff_eatgv_decoder; +extern AVCodec ff_eatqi_decoder; +extern AVCodec ff_eightbps_decoder; +extern AVCodec ff_eightsvx_exp_decoder; +extern AVCodec ff_eightsvx_fib_decoder; +extern AVCodec ff_escape124_decoder; +extern AVCodec ff_escape130_decoder; +extern AVCodec ff_exr_decoder; +extern AVCodec ff_ffv1_encoder; +extern AVCodec ff_ffv1_decoder; +extern AVCodec ff_ffvhuff_encoder; +extern AVCodec ff_ffvhuff_decoder; +extern AVCodec ff_fic_decoder; +extern AVCodec ff_fits_encoder; +extern AVCodec ff_fits_decoder; +extern AVCodec ff_flashsv_encoder; +extern AVCodec ff_flashsv_decoder; +extern AVCodec ff_flashsv2_encoder; +extern AVCodec ff_flashsv2_decoder; +extern AVCodec ff_flic_decoder; +extern AVCodec ff_flv_encoder; +extern AVCodec ff_flv_decoder; +extern AVCodec ff_fmvc_decoder; +extern AVCodec ff_fourxm_decoder; +extern AVCodec ff_fraps_decoder; +extern AVCodec ff_frwu_decoder; +extern AVCodec ff_g2m_decoder; +extern AVCodec ff_gdv_decoder; +extern AVCodec ff_gif_encoder; +extern AVCodec ff_gif_decoder; +extern AVCodec ff_h261_encoder; +extern AVCodec ff_h261_decoder; +extern AVCodec ff_h263_encoder; +extern AVCodec ff_h263_decoder; +extern AVCodec ff_h263i_decoder; +extern AVCodec ff_h263p_encoder; +extern AVCodec ff_h263p_decoder; +extern AVCodec ff_h263_v4l2m2m_decoder; +extern AVCodec ff_h264_decoder; +extern AVCodec ff_h264_crystalhd_decoder; +extern AVCodec ff_h264_v4l2m2m_decoder; +extern AVCodec ff_h264_mediacodec_decoder; +extern AVCodec ff_h264_mmal_decoder; +extern AVCodec ff_h264_qsv_decoder; +extern AVCodec ff_h264_rkmpp_decoder; +extern AVCodec ff_hap_encoder; +extern AVCodec ff_hap_decoder; +extern AVCodec ff_hevc_decoder; +extern AVCodec ff_hevc_qsv_decoder; +extern AVCodec ff_hevc_rkmpp_decoder; +extern AVCodec ff_hevc_v4l2m2m_decoder; +extern AVCodec ff_hnm4_video_decoder; +extern AVCodec ff_hq_hqa_decoder; +extern AVCodec ff_hqx_decoder; +extern AVCodec ff_huffyuv_encoder; +extern AVCodec ff_huffyuv_decoder; +extern AVCodec ff_idcin_decoder; +extern AVCodec ff_iff_ilbm_decoder; +extern AVCodec ff_indeo2_decoder; +extern AVCodec ff_indeo3_decoder; +extern AVCodec ff_indeo4_decoder; +extern AVCodec ff_indeo5_decoder; +extern AVCodec ff_interplay_video_decoder; +extern AVCodec ff_jpeg2000_encoder; +extern AVCodec ff_jpeg2000_decoder; +extern AVCodec ff_jpegls_encoder; +extern AVCodec ff_jpegls_decoder; +extern AVCodec ff_jv_decoder; +extern AVCodec ff_kgv1_decoder; +extern AVCodec ff_kmvc_decoder; +extern AVCodec ff_lagarith_decoder; +extern AVCodec ff_ljpeg_encoder; +extern AVCodec ff_loco_decoder; +extern AVCodec ff_m101_decoder; +extern AVCodec ff_magicyuv_encoder; +extern AVCodec ff_magicyuv_decoder; +extern AVCodec ff_mdec_decoder; +extern AVCodec ff_mimic_decoder; +extern AVCodec ff_mjpeg_encoder; +extern AVCodec ff_mjpeg_decoder; +extern AVCodec ff_mjpegb_decoder; +extern AVCodec ff_mmvideo_decoder; +extern AVCodec ff_motionpixels_decoder; +extern AVCodec ff_mpeg1video_encoder; +extern AVCodec ff_mpeg1video_decoder; +extern AVCodec ff_mpeg2video_encoder; +extern AVCodec ff_mpeg2video_decoder; +extern AVCodec ff_mpeg4_encoder; +extern AVCodec ff_mpeg4_decoder; +extern AVCodec ff_mpeg4_crystalhd_decoder; +extern AVCodec ff_mpeg4_v4l2m2m_decoder; +extern AVCodec ff_mpeg4_mmal_decoder; +extern AVCodec ff_mpegvideo_decoder; +extern AVCodec ff_mpeg1_v4l2m2m_decoder; +extern AVCodec ff_mpeg2_mmal_decoder; +extern AVCodec ff_mpeg2_crystalhd_decoder; +extern AVCodec ff_mpeg2_v4l2m2m_decoder; +extern AVCodec ff_mpeg2_qsv_decoder; +extern AVCodec ff_mpeg2_mediacodec_decoder; +extern AVCodec ff_msa1_decoder; +extern AVCodec ff_mscc_decoder; +extern AVCodec ff_msmpeg4v1_decoder; +extern AVCodec ff_msmpeg4v2_encoder; +extern AVCodec ff_msmpeg4v2_decoder; +extern AVCodec ff_msmpeg4v3_encoder; +extern AVCodec ff_msmpeg4v3_decoder; +extern AVCodec ff_msmpeg4_crystalhd_decoder; +extern AVCodec ff_msrle_decoder; +extern AVCodec ff_mss1_decoder; +extern AVCodec ff_mss2_decoder; +extern AVCodec ff_msvideo1_encoder; +extern AVCodec ff_msvideo1_decoder; +extern AVCodec ff_mszh_decoder; +extern AVCodec ff_mts2_decoder; +extern AVCodec ff_mvc1_decoder; +extern AVCodec ff_mvc2_decoder; +extern AVCodec ff_mxpeg_decoder; +extern AVCodec ff_nuv_decoder; +extern AVCodec ff_paf_video_decoder; +extern AVCodec ff_pam_encoder; +extern AVCodec ff_pam_decoder; +extern AVCodec ff_pbm_encoder; +extern AVCodec ff_pbm_decoder; +extern AVCodec ff_pcx_encoder; +extern AVCodec ff_pcx_decoder; +extern AVCodec ff_pgm_encoder; +extern AVCodec ff_pgm_decoder; +extern AVCodec ff_pgmyuv_encoder; +extern AVCodec ff_pgmyuv_decoder; +extern AVCodec ff_pictor_decoder; +extern AVCodec ff_pixlet_decoder; +extern AVCodec ff_png_encoder; +extern AVCodec ff_png_decoder; +extern AVCodec ff_ppm_encoder; +extern AVCodec ff_ppm_decoder; +extern AVCodec ff_prores_encoder; +extern AVCodec ff_prores_decoder; +extern AVCodec ff_prores_aw_encoder; +extern AVCodec ff_prores_ks_encoder; +extern AVCodec ff_prores_lgpl_decoder; +extern AVCodec ff_psd_decoder; +extern AVCodec ff_ptx_decoder; +extern AVCodec ff_qdraw_decoder; +extern AVCodec ff_qpeg_decoder; +extern AVCodec ff_qtrle_encoder; +extern AVCodec ff_qtrle_decoder; +extern AVCodec ff_r10k_encoder; +extern AVCodec ff_r10k_decoder; +extern AVCodec ff_r210_encoder; +extern AVCodec ff_r210_decoder; +extern AVCodec ff_rawvideo_encoder; +extern AVCodec ff_rawvideo_decoder; +extern AVCodec ff_rl2_decoder; +extern AVCodec ff_roq_encoder; +extern AVCodec ff_roq_decoder; +extern AVCodec ff_rpza_decoder; +extern AVCodec ff_rscc_decoder; +extern AVCodec ff_rv10_encoder; +extern AVCodec ff_rv10_decoder; +extern AVCodec ff_rv20_encoder; +extern AVCodec ff_rv20_decoder; +extern AVCodec ff_rv30_decoder; +extern AVCodec ff_rv40_decoder; +extern AVCodec ff_s302m_encoder; +extern AVCodec ff_s302m_decoder; +extern AVCodec ff_sanm_decoder; +extern AVCodec ff_scpr_decoder; +extern AVCodec ff_screenpresso_decoder; +extern AVCodec ff_sdx2_dpcm_decoder; +extern AVCodec ff_sgi_encoder; +extern AVCodec ff_sgi_decoder; +extern AVCodec ff_sgirle_decoder; +extern AVCodec ff_sheervideo_decoder; +extern AVCodec ff_smacker_decoder; +extern AVCodec ff_smc_decoder; +extern AVCodec ff_smvjpeg_decoder; +extern AVCodec ff_snow_encoder; +extern AVCodec ff_snow_decoder; +extern AVCodec ff_sp5x_decoder; +extern AVCodec ff_speedhq_decoder; +extern AVCodec ff_srgc_decoder; +extern AVCodec ff_sunrast_encoder; +extern AVCodec ff_sunrast_decoder; +extern AVCodec ff_svq1_encoder; +extern AVCodec ff_svq1_decoder; +extern AVCodec ff_svq3_decoder; +extern AVCodec ff_targa_encoder; +extern AVCodec ff_targa_decoder; +extern AVCodec ff_targa_y216_decoder; +extern AVCodec ff_tdsc_decoder; +extern AVCodec ff_theora_decoder; +extern AVCodec ff_thp_decoder; +extern AVCodec ff_tiertexseqvideo_decoder; +extern AVCodec ff_tiff_encoder; +extern AVCodec ff_tiff_decoder; +extern AVCodec ff_tmv_decoder; +extern AVCodec ff_truemotion1_decoder; +extern AVCodec ff_truemotion2_decoder; +extern AVCodec ff_truemotion2rt_decoder; +extern AVCodec ff_tscc_decoder; +extern AVCodec ff_tscc2_decoder; +extern AVCodec ff_txd_decoder; +extern AVCodec ff_ulti_decoder; +extern AVCodec ff_utvideo_encoder; +extern AVCodec ff_utvideo_decoder; +extern AVCodec ff_v210_encoder; +extern AVCodec ff_v210_decoder; +extern AVCodec ff_v210x_decoder; +extern AVCodec ff_v308_encoder; +extern AVCodec ff_v308_decoder; +extern AVCodec ff_v408_encoder; +extern AVCodec ff_v408_decoder; +extern AVCodec ff_v410_encoder; +extern AVCodec ff_v410_decoder; +extern AVCodec ff_vb_decoder; +extern AVCodec ff_vble_decoder; +extern AVCodec ff_vc1_decoder; +extern AVCodec ff_vc1_crystalhd_decoder; +extern AVCodec ff_vc1image_decoder; +extern AVCodec ff_vc1_mmal_decoder; +extern AVCodec ff_vc1_qsv_decoder; +extern AVCodec ff_vc1_v4l2m2m_decoder; +extern AVCodec ff_vc2_encoder; +extern AVCodec ff_vcr1_decoder; +extern AVCodec ff_vmdvideo_decoder; +extern AVCodec ff_vmnc_decoder; +extern AVCodec ff_vp3_decoder; +extern AVCodec ff_vp5_decoder; +extern AVCodec ff_vp6_decoder; +extern AVCodec ff_vp6a_decoder; +extern AVCodec ff_vp6f_decoder; +extern AVCodec ff_vp7_decoder; +extern AVCodec ff_vp8_decoder; +extern AVCodec ff_vp8_rkmpp_decoder; +extern AVCodec ff_vp8_v4l2m2m_decoder; +extern AVCodec ff_vp9_decoder; +extern AVCodec ff_vp9_rkmpp_decoder; +extern AVCodec ff_vp9_v4l2m2m_decoder; +extern AVCodec ff_vqa_decoder; +extern AVCodec ff_bitpacked_decoder; +extern AVCodec ff_webp_decoder; +extern AVCodec ff_wrapped_avframe_encoder; +extern AVCodec ff_wrapped_avframe_decoder; +extern AVCodec ff_wmv1_encoder; +extern AVCodec ff_wmv1_decoder; +extern AVCodec ff_wmv2_encoder; +extern AVCodec ff_wmv2_decoder; +extern AVCodec ff_wmv3_decoder; +extern AVCodec ff_wmv3_crystalhd_decoder; +extern AVCodec ff_wmv3image_decoder; +extern AVCodec ff_wnv1_decoder; +extern AVCodec ff_xan_wc3_decoder; +extern AVCodec ff_xan_wc4_decoder; +extern AVCodec ff_xbm_encoder; +extern AVCodec ff_xbm_decoder; +extern AVCodec ff_xface_encoder; +extern AVCodec ff_xface_decoder; +extern AVCodec ff_xl_decoder; +extern AVCodec ff_xpm_decoder; +extern AVCodec ff_xwd_encoder; +extern AVCodec ff_xwd_decoder; +extern AVCodec ff_y41p_encoder; +extern AVCodec ff_y41p_decoder; +extern AVCodec ff_ylc_decoder; +extern AVCodec ff_yop_decoder; +extern AVCodec ff_yuv4_encoder; +extern AVCodec ff_yuv4_decoder; +extern AVCodec ff_zero12v_decoder; +extern AVCodec ff_zerocodec_decoder; +extern AVCodec ff_zlib_encoder; +extern AVCodec ff_zlib_decoder; +extern AVCodec ff_zmbv_encoder; +extern AVCodec ff_zmbv_decoder; + +/* audio codecs */ +extern AVCodec ff_aac_encoder; +extern AVCodec ff_aac_decoder; +extern AVCodec ff_aac_fixed_decoder; +extern AVCodec ff_aac_latm_decoder; +extern AVCodec ff_ac3_encoder; +extern AVCodec ff_ac3_decoder; +extern AVCodec ff_ac3_fixed_encoder; +extern AVCodec ff_ac3_fixed_decoder; +extern AVCodec ff_alac_encoder; +extern AVCodec ff_alac_decoder; +extern AVCodec ff_als_decoder; +extern AVCodec ff_amrnb_decoder; +extern AVCodec ff_amrwb_decoder; +extern AVCodec ff_ape_decoder; +extern AVCodec ff_aptx_encoder; +extern AVCodec ff_aptx_decoder; +extern AVCodec ff_aptx_hd_encoder; +extern AVCodec ff_aptx_hd_decoder; +extern AVCodec ff_atrac1_decoder; +extern AVCodec ff_atrac3_decoder; +extern AVCodec ff_atrac3al_decoder; +extern AVCodec ff_atrac3p_decoder; +extern AVCodec ff_atrac3pal_decoder; +extern AVCodec ff_binkaudio_dct_decoder; +extern AVCodec ff_binkaudio_rdft_decoder; +extern AVCodec ff_bmv_audio_decoder; +extern AVCodec ff_cook_decoder; +extern AVCodec ff_dca_encoder; +extern AVCodec ff_dca_decoder; +extern AVCodec ff_dolby_e_decoder; +extern AVCodec ff_dsd_lsbf_decoder; +extern AVCodec ff_dsd_msbf_decoder; +extern AVCodec ff_dsd_lsbf_planar_decoder; +extern AVCodec ff_dsd_msbf_planar_decoder; +extern AVCodec ff_dsicinaudio_decoder; +extern AVCodec ff_dss_sp_decoder; +extern AVCodec ff_dst_decoder; +extern AVCodec ff_eac3_encoder; +extern AVCodec ff_eac3_decoder; +extern AVCodec ff_evrc_decoder; +extern AVCodec ff_ffwavesynth_decoder; +extern AVCodec ff_flac_encoder; +extern AVCodec ff_flac_decoder; +extern AVCodec ff_g723_1_encoder; +extern AVCodec ff_g723_1_decoder; +extern AVCodec ff_g729_decoder; +extern AVCodec ff_gsm_decoder; +extern AVCodec ff_gsm_ms_decoder; +extern AVCodec ff_iac_decoder; +extern AVCodec ff_imc_decoder; +extern AVCodec ff_interplay_acm_decoder; +extern AVCodec ff_mace3_decoder; +extern AVCodec ff_mace6_decoder; +extern AVCodec ff_metasound_decoder; +extern AVCodec ff_mlp_encoder; +extern AVCodec ff_mlp_decoder; +extern AVCodec ff_mp1_decoder; +extern AVCodec ff_mp1float_decoder; +extern AVCodec ff_mp2_encoder; +extern AVCodec ff_mp2_decoder; +extern AVCodec ff_mp2float_decoder; +extern AVCodec ff_mp2fixed_encoder; +extern AVCodec ff_mp3float_decoder; +extern AVCodec ff_mp3_decoder; +extern AVCodec ff_mp3adufloat_decoder; +extern AVCodec ff_mp3adu_decoder; +extern AVCodec ff_mp3on4float_decoder; +extern AVCodec ff_mp3on4_decoder; +extern AVCodec ff_mpc7_decoder; +extern AVCodec ff_mpc8_decoder; +extern AVCodec ff_nellymoser_encoder; +extern AVCodec ff_nellymoser_decoder; +extern AVCodec ff_on2avc_decoder; +extern AVCodec ff_opus_encoder; +extern AVCodec ff_opus_decoder; +extern AVCodec ff_paf_audio_decoder; +extern AVCodec ff_qcelp_decoder; +extern AVCodec ff_qdm2_decoder; +extern AVCodec ff_qdmc_decoder; +extern AVCodec ff_ra_144_encoder; +extern AVCodec ff_ra_144_decoder; +extern AVCodec ff_ra_288_decoder; +extern AVCodec ff_ralf_decoder; +extern AVCodec ff_sbc_encoder; +extern AVCodec ff_sbc_decoder; +extern AVCodec ff_shorten_decoder; +extern AVCodec ff_sipr_decoder; +extern AVCodec ff_smackaud_decoder; +extern AVCodec ff_sonic_encoder; +extern AVCodec ff_sonic_decoder; +extern AVCodec ff_sonic_ls_encoder; +extern AVCodec ff_tak_decoder; +extern AVCodec ff_truehd_encoder; +extern AVCodec ff_truehd_decoder; +extern AVCodec ff_truespeech_decoder; +extern AVCodec ff_tta_encoder; +extern AVCodec ff_tta_decoder; +extern AVCodec ff_twinvq_decoder; +extern AVCodec ff_vmdaudio_decoder; +extern AVCodec ff_vorbis_encoder; +extern AVCodec ff_vorbis_decoder; +extern AVCodec ff_wavpack_encoder; +extern AVCodec ff_wavpack_decoder; +extern AVCodec ff_wmalossless_decoder; +extern AVCodec ff_wmapro_decoder; +extern AVCodec ff_wmav1_encoder; +extern AVCodec ff_wmav1_decoder; +extern AVCodec ff_wmav2_encoder; +extern AVCodec ff_wmav2_decoder; +extern AVCodec ff_wmavoice_decoder; +extern AVCodec ff_ws_snd1_decoder; +extern AVCodec ff_xma1_decoder; +extern AVCodec ff_xma2_decoder; + +/* PCM codecs */ +extern AVCodec ff_pcm_alaw_encoder; +extern AVCodec ff_pcm_alaw_decoder; +extern AVCodec ff_pcm_bluray_decoder; +extern AVCodec ff_pcm_dvd_decoder; +extern AVCodec ff_pcm_f16le_decoder; +extern AVCodec ff_pcm_f24le_decoder; +extern AVCodec ff_pcm_f32be_encoder; +extern AVCodec ff_pcm_f32be_decoder; +extern AVCodec ff_pcm_f32le_encoder; +extern AVCodec ff_pcm_f32le_decoder; +extern AVCodec ff_pcm_f64be_encoder; +extern AVCodec ff_pcm_f64be_decoder; +extern AVCodec ff_pcm_f64le_encoder; +extern AVCodec ff_pcm_f64le_decoder; +extern AVCodec ff_pcm_lxf_decoder; +extern AVCodec ff_pcm_mulaw_encoder; +extern AVCodec ff_pcm_mulaw_decoder; +extern AVCodec ff_pcm_s8_encoder; +extern AVCodec ff_pcm_s8_decoder; +extern AVCodec ff_pcm_s8_planar_encoder; +extern AVCodec ff_pcm_s8_planar_decoder; +extern AVCodec ff_pcm_s16be_encoder; +extern AVCodec ff_pcm_s16be_decoder; +extern AVCodec ff_pcm_s16be_planar_encoder; +extern AVCodec ff_pcm_s16be_planar_decoder; +extern AVCodec ff_pcm_s16le_encoder; +extern AVCodec ff_pcm_s16le_decoder; +extern AVCodec ff_pcm_s16le_planar_encoder; +extern AVCodec ff_pcm_s16le_planar_decoder; +extern AVCodec ff_pcm_s24be_encoder; +extern AVCodec ff_pcm_s24be_decoder; +extern AVCodec ff_pcm_s24daud_encoder; +extern AVCodec ff_pcm_s24daud_decoder; +extern AVCodec ff_pcm_s24le_encoder; +extern AVCodec ff_pcm_s24le_decoder; +extern AVCodec ff_pcm_s24le_planar_encoder; +extern AVCodec ff_pcm_s24le_planar_decoder; +extern AVCodec ff_pcm_s32be_encoder; +extern AVCodec ff_pcm_s32be_decoder; +extern AVCodec ff_pcm_s32le_encoder; +extern AVCodec ff_pcm_s32le_decoder; +extern AVCodec ff_pcm_s32le_planar_encoder; +extern AVCodec ff_pcm_s32le_planar_decoder; +extern AVCodec ff_pcm_s64be_encoder; +extern AVCodec ff_pcm_s64be_decoder; +extern AVCodec ff_pcm_s64le_encoder; +extern AVCodec ff_pcm_s64le_decoder; +extern AVCodec ff_pcm_u8_encoder; +extern AVCodec ff_pcm_u8_decoder; +extern AVCodec ff_pcm_u16be_encoder; +extern AVCodec ff_pcm_u16be_decoder; +extern AVCodec ff_pcm_u16le_encoder; +extern AVCodec ff_pcm_u16le_decoder; +extern AVCodec ff_pcm_u24be_encoder; +extern AVCodec ff_pcm_u24be_decoder; +extern AVCodec ff_pcm_u24le_encoder; +extern AVCodec ff_pcm_u24le_decoder; +extern AVCodec ff_pcm_u32be_encoder; +extern AVCodec ff_pcm_u32be_decoder; +extern AVCodec ff_pcm_u32le_encoder; +extern AVCodec ff_pcm_u32le_decoder; +extern AVCodec ff_pcm_zork_decoder; + +/* DPCM codecs */ +extern AVCodec ff_gremlin_dpcm_decoder; +extern AVCodec ff_interplay_dpcm_decoder; +extern AVCodec ff_roq_dpcm_encoder; +extern AVCodec ff_roq_dpcm_decoder; +extern AVCodec ff_sol_dpcm_decoder; +extern AVCodec ff_xan_dpcm_decoder; + +/* ADPCM codecs */ +extern AVCodec ff_adpcm_4xm_decoder; +extern AVCodec ff_adpcm_adx_encoder; +extern AVCodec ff_adpcm_adx_decoder; +extern AVCodec ff_adpcm_afc_decoder; +extern AVCodec ff_adpcm_aica_decoder; +extern AVCodec ff_adpcm_ct_decoder; +extern AVCodec ff_adpcm_dtk_decoder; +extern AVCodec ff_adpcm_ea_decoder; +extern AVCodec ff_adpcm_ea_maxis_xa_decoder; +extern AVCodec ff_adpcm_ea_r1_decoder; +extern AVCodec ff_adpcm_ea_r2_decoder; +extern AVCodec ff_adpcm_ea_r3_decoder; +extern AVCodec ff_adpcm_ea_xas_decoder; +extern AVCodec ff_adpcm_g722_encoder; +extern AVCodec ff_adpcm_g722_decoder; +extern AVCodec ff_adpcm_g726_encoder; +extern AVCodec ff_adpcm_g726_decoder; +extern AVCodec ff_adpcm_g726le_encoder; +extern AVCodec ff_adpcm_g726le_decoder; +extern AVCodec ff_adpcm_ima_amv_decoder; +extern AVCodec ff_adpcm_ima_apc_decoder; +extern AVCodec ff_adpcm_ima_dat4_decoder; +extern AVCodec ff_adpcm_ima_dk3_decoder; +extern AVCodec ff_adpcm_ima_dk4_decoder; +extern AVCodec ff_adpcm_ima_ea_eacs_decoder; +extern AVCodec ff_adpcm_ima_ea_sead_decoder; +extern AVCodec ff_adpcm_ima_iss_decoder; +extern AVCodec ff_adpcm_ima_oki_decoder; +extern AVCodec ff_adpcm_ima_qt_encoder; +extern AVCodec ff_adpcm_ima_qt_decoder; +extern AVCodec ff_adpcm_ima_rad_decoder; +extern AVCodec ff_adpcm_ima_smjpeg_decoder; +extern AVCodec ff_adpcm_ima_wav_encoder; +extern AVCodec ff_adpcm_ima_wav_decoder; +extern AVCodec ff_adpcm_ima_ws_decoder; +extern AVCodec ff_adpcm_ms_encoder; +extern AVCodec ff_adpcm_ms_decoder; +extern AVCodec ff_adpcm_mtaf_decoder; +extern AVCodec ff_adpcm_psx_decoder; +extern AVCodec ff_adpcm_sbpro_2_decoder; +extern AVCodec ff_adpcm_sbpro_3_decoder; +extern AVCodec ff_adpcm_sbpro_4_decoder; +extern AVCodec ff_adpcm_swf_encoder; +extern AVCodec ff_adpcm_swf_decoder; +extern AVCodec ff_adpcm_thp_decoder; +extern AVCodec ff_adpcm_thp_le_decoder; +extern AVCodec ff_adpcm_vima_decoder; +extern AVCodec ff_adpcm_xa_decoder; +extern AVCodec ff_adpcm_yamaha_encoder; +extern AVCodec ff_adpcm_yamaha_decoder; + +/* subtitles */ +extern AVCodec ff_ssa_encoder; +extern AVCodec ff_ssa_decoder; +extern AVCodec ff_ass_encoder; +extern AVCodec ff_ass_decoder; +extern AVCodec ff_ccaption_decoder; +extern AVCodec ff_dvbsub_encoder; +extern AVCodec ff_dvbsub_decoder; +extern AVCodec ff_dvdsub_encoder; +extern AVCodec ff_dvdsub_decoder; +extern AVCodec ff_jacosub_decoder; +extern AVCodec ff_microdvd_decoder; +extern AVCodec ff_movtext_encoder; +extern AVCodec ff_movtext_decoder; +extern AVCodec ff_mpl2_decoder; +extern AVCodec ff_pgssub_decoder; +extern AVCodec ff_pjs_decoder; +extern AVCodec ff_realtext_decoder; +extern AVCodec ff_sami_decoder; +extern AVCodec ff_srt_encoder; +extern AVCodec ff_srt_decoder; +extern AVCodec ff_stl_decoder; +extern AVCodec ff_subrip_encoder; +extern AVCodec ff_subrip_decoder; +extern AVCodec ff_subviewer_decoder; +extern AVCodec ff_subviewer1_decoder; +extern AVCodec ff_text_encoder; +extern AVCodec ff_text_decoder; +extern AVCodec ff_vplayer_decoder; +extern AVCodec ff_webvtt_encoder; +extern AVCodec ff_webvtt_decoder; +extern AVCodec ff_xsub_encoder; +extern AVCodec ff_xsub_decoder; + +/* external libraries */ +extern AVCodec ff_aac_at_encoder; +extern AVCodec ff_aac_at_decoder; +extern AVCodec ff_ac3_at_decoder; +extern AVCodec ff_adpcm_ima_qt_at_decoder; +extern AVCodec ff_alac_at_encoder; +extern AVCodec ff_alac_at_decoder; +extern AVCodec ff_amr_nb_at_decoder; +extern AVCodec ff_eac3_at_decoder; +extern AVCodec ff_gsm_ms_at_decoder; +extern AVCodec ff_ilbc_at_encoder; +extern AVCodec ff_ilbc_at_decoder; +extern AVCodec ff_mp1_at_decoder; +extern AVCodec ff_mp2_at_decoder; +extern AVCodec ff_mp3_at_decoder; +extern AVCodec ff_pcm_alaw_at_encoder; +extern AVCodec ff_pcm_alaw_at_decoder; +extern AVCodec ff_pcm_mulaw_at_encoder; +extern AVCodec ff_pcm_mulaw_at_decoder; +extern AVCodec ff_qdmc_at_decoder; +extern AVCodec ff_qdm2_at_decoder; +extern AVCodec ff_libaom_av1_decoder; +extern AVCodec ff_libaom_av1_encoder; +extern AVCodec ff_libcelt_decoder; +extern AVCodec ff_libcodec2_encoder; +extern AVCodec ff_libcodec2_decoder; +extern AVCodec ff_libfdk_aac_encoder; +extern AVCodec ff_libfdk_aac_decoder; +extern AVCodec ff_libgsm_encoder; +extern AVCodec ff_libgsm_decoder; +extern AVCodec ff_libgsm_ms_encoder; +extern AVCodec ff_libgsm_ms_decoder; +extern AVCodec ff_libilbc_encoder; +extern AVCodec ff_libilbc_decoder; +extern AVCodec ff_libmp3lame_encoder; +extern AVCodec ff_libopencore_amrnb_encoder; +extern AVCodec ff_libopencore_amrnb_decoder; +extern AVCodec ff_libopencore_amrwb_decoder; +extern AVCodec ff_libopenjpeg_encoder; +extern AVCodec ff_libopenjpeg_decoder; +extern AVCodec ff_libopus_encoder; +extern AVCodec ff_libopus_decoder; +extern AVCodec ff_librsvg_decoder; +extern AVCodec ff_libshine_encoder; +extern AVCodec ff_libspeex_encoder; +extern AVCodec ff_libspeex_decoder; +extern AVCodec ff_libtheora_encoder; +extern AVCodec ff_libtwolame_encoder; +extern AVCodec ff_libvo_amrwbenc_encoder; +extern AVCodec ff_libvorbis_encoder; +extern AVCodec ff_libvorbis_decoder; +extern AVCodec ff_libvpx_vp8_encoder; +extern AVCodec ff_libvpx_vp8_decoder; +extern AVCodec ff_libvpx_vp9_encoder; +extern AVCodec ff_libvpx_vp9_decoder; +extern AVCodec ff_libwavpack_encoder; +/* preferred over libwebp */ +extern AVCodec ff_libwebp_anim_encoder; +extern AVCodec ff_libwebp_encoder; +extern AVCodec ff_libx262_encoder; +extern AVCodec ff_libx264_encoder; +extern AVCodec ff_libx264rgb_encoder; +extern AVCodec ff_libx265_encoder; +extern AVCodec ff_libxavs_encoder; +extern AVCodec ff_libxvid_encoder; +extern AVCodec ff_libzvbi_teletext_decoder; + +/* text */ +extern AVCodec ff_bintext_decoder; +extern AVCodec ff_xbin_decoder; +extern AVCodec ff_idf_decoder; + +/* external libraries, that shouldn't be used by default if one of the + * above is available */ +extern AVCodec ff_h263_v4l2m2m_encoder; +extern AVCodec ff_libopenh264_encoder; +extern AVCodec ff_libopenh264_decoder; +extern AVCodec ff_h264_amf_encoder; +extern AVCodec ff_h264_cuvid_decoder; +extern AVCodec ff_h264_nvenc_encoder; +extern AVCodec ff_h264_omx_encoder; +extern AVCodec ff_h264_qsv_encoder; +extern AVCodec ff_h264_v4l2m2m_encoder; +extern AVCodec ff_h264_vaapi_encoder; +extern AVCodec ff_h264_videotoolbox_encoder; +#if FF_API_NVENC_OLD_NAME +extern AVCodec ff_nvenc_encoder; +extern AVCodec ff_nvenc_h264_encoder; +extern AVCodec ff_nvenc_hevc_encoder; +#endif +extern AVCodec ff_hevc_amf_encoder; +extern AVCodec ff_hevc_cuvid_decoder; +extern AVCodec ff_hevc_mediacodec_decoder; +extern AVCodec ff_hevc_nvenc_encoder; +extern AVCodec ff_hevc_qsv_encoder; +extern AVCodec ff_hevc_v4l2m2m_encoder; +extern AVCodec ff_hevc_vaapi_encoder; +extern AVCodec ff_hevc_videotoolbox_encoder; +extern AVCodec ff_libkvazaar_encoder; +extern AVCodec ff_mjpeg_cuvid_decoder; +extern AVCodec ff_mjpeg_qsv_encoder; +extern AVCodec ff_mjpeg_vaapi_encoder; +extern AVCodec ff_mpeg1_cuvid_decoder; +extern AVCodec ff_mpeg2_cuvid_decoder; +extern AVCodec ff_mpeg2_qsv_encoder; +extern AVCodec ff_mpeg2_vaapi_encoder; +extern AVCodec ff_mpeg4_cuvid_decoder; +extern AVCodec ff_mpeg4_mediacodec_decoder; +extern AVCodec ff_mpeg4_v4l2m2m_encoder; +extern AVCodec ff_vc1_cuvid_decoder; +extern AVCodec ff_vp8_cuvid_decoder; +extern AVCodec ff_vp8_mediacodec_decoder; +extern AVCodec ff_vp8_qsv_decoder; +extern AVCodec ff_vp8_v4l2m2m_encoder; +extern AVCodec ff_vp8_vaapi_encoder; +extern AVCodec ff_vp9_cuvid_decoder; +extern AVCodec ff_vp9_mediacodec_decoder; +extern AVCodec ff_vp9_vaapi_encoder; + +#include "libavcodec/codec_list.c" + +static AVOnce av_codec_static_init = AV_ONCE_INIT; +static void av_codec_init_static(void) +{ + for (int i = 0; codec_list[i]; i++) { + if (codec_list[i]->init_static_data) + codec_list[i]->init_static_data((AVCodec*)codec_list[i]); } +} + +const AVCodec *av_codec_iterate(void **opaque) +{ + uintptr_t i = (uintptr_t)*opaque; + const AVCodec *c = codec_list[i]; -#define REGISTER_ENCODER(X, x) \ - { \ - extern AVCodec ff_##x##_encoder; \ - if (CONFIG_##X##_ENCODER) \ - avcodec_register(&ff_##x##_encoder); \ + ff_thread_once(&av_codec_static_init, av_codec_init_static); + + if (c) + *opaque = (void*)(i + 1); + + return c; +} + +#if FF_API_NEXT +FF_DISABLE_DEPRECATION_WARNINGS +static AVOnce av_codec_next_init = AV_ONCE_INIT; + +static void av_codec_init_next(void) +{ + AVCodec *prev = NULL, *p; + void *i = 0; + while ((p = (AVCodec*)av_codec_iterate(&i))) { + if (prev) + prev->next = p; + prev = p; } +} + + + +av_cold void avcodec_register(AVCodec *codec) +{ + ff_thread_once(&av_codec_next_init, av_codec_init_next); +} + +AVCodec *av_codec_next(const AVCodec *c) +{ + ff_thread_once(&av_codec_next_init, av_codec_init_next); + + if (c) + return c->next; + else + return (AVCodec*)codec_list[0]; +} -#define REGISTER_DECODER(X, x) \ - { \ - extern AVCodec ff_##x##_decoder; \ - if (CONFIG_##X##_DECODER) \ - avcodec_register(&ff_##x##_decoder); \ +void avcodec_register_all(void) +{ + ff_thread_once(&av_codec_next_init, av_codec_init_next); +} +FF_ENABLE_DEPRECATION_WARNINGS +#endif + +static enum AVCodecID remap_deprecated_codec_id(enum AVCodecID id) +{ + switch(id){ + //This is for future deprecatec codec ids, its empty since + //last major bump but will fill up again over time, please don't remove it + default : return id; } +} + +static AVCodec *find_codec(enum AVCodecID id, int (*x)(const AVCodec *)) +{ + const AVCodec *p, *experimental = NULL; + void *i = 0; -#define REGISTER_ENCDEC(X, x) REGISTER_ENCODER(X, x); REGISTER_DECODER(X, x) + id = remap_deprecated_codec_id(id); -#define REGISTER_PARSER(X, x) \ - { \ - extern AVCodecParser ff_##x##_parser; \ - if (CONFIG_##X##_PARSER) \ - av_register_codec_parser(&ff_##x##_parser); \ + while ((p = av_codec_iterate(&i))) { + if (!x(p)) + continue; + if (p->id == id) { + if (p->capabilities & AV_CODEC_CAP_EXPERIMENTAL && !experimental) { + experimental = p; + } else + return (AVCodec*)p; + } } -static void register_all(void) + return (AVCodec*)experimental; +} + +AVCodec *avcodec_find_encoder(enum AVCodecID id) { - /* hardware accelerators */ - REGISTER_HWACCEL(H263_VAAPI, h263_vaapi); - REGISTER_HWACCEL(H263_VIDEOTOOLBOX, h263_videotoolbox); - REGISTER_HWACCEL(H264_CUVID, h264_cuvid); - REGISTER_HWACCEL(H264_D3D11VA, h264_d3d11va); - REGISTER_HWACCEL(H264_D3D11VA2, h264_d3d11va2); - REGISTER_HWACCEL(H264_DXVA2, h264_dxva2); - REGISTER_HWACCEL(H264_MEDIACODEC, h264_mediacodec); - REGISTER_HWACCEL(H264_MMAL, h264_mmal); - REGISTER_HWACCEL(H264_QSV, h264_qsv); - REGISTER_HWACCEL(H264_VAAPI, h264_vaapi); - REGISTER_HWACCEL(H264_VDA, h264_vda); - REGISTER_HWACCEL(H264_VDA_OLD, h264_vda_old); - REGISTER_HWACCEL(H264_VDPAU, h264_vdpau); - REGISTER_HWACCEL(H264_VIDEOTOOLBOX, h264_videotoolbox); - REGISTER_HWACCEL(HEVC_CUVID, hevc_cuvid); - REGISTER_HWACCEL(HEVC_D3D11VA, hevc_d3d11va); - REGISTER_HWACCEL(HEVC_D3D11VA2, hevc_d3d11va2); - REGISTER_HWACCEL(HEVC_DXVA2, hevc_dxva2); - REGISTER_HWACCEL(HEVC_MEDIACODEC, hevc_mediacodec); - REGISTER_HWACCEL(HEVC_QSV, hevc_qsv); - REGISTER_HWACCEL(HEVC_VAAPI, hevc_vaapi); - REGISTER_HWACCEL(HEVC_VDPAU, hevc_vdpau); - REGISTER_HWACCEL(HEVC_VIDEOTOOLBOX, hevc_videotoolbox); - REGISTER_HWACCEL(MJPEG_CUVID, mjpeg_cuvid); - REGISTER_HWACCEL(MPEG1_CUVID, mpeg1_cuvid); - REGISTER_HWACCEL(MPEG1_XVMC, mpeg1_xvmc); - REGISTER_HWACCEL(MPEG1_VDPAU, mpeg1_vdpau); - REGISTER_HWACCEL(MPEG1_VIDEOTOOLBOX, mpeg1_videotoolbox); - REGISTER_HWACCEL(MPEG2_CUVID, mpeg2_cuvid); - REGISTER_HWACCEL(MPEG2_XVMC, mpeg2_xvmc); - REGISTER_HWACCEL(MPEG2_D3D11VA, mpeg2_d3d11va); - REGISTER_HWACCEL(MPEG2_D3D11VA2, mpeg2_d3d11va2); - REGISTER_HWACCEL(MPEG2_DXVA2, mpeg2_dxva2); - REGISTER_HWACCEL(MPEG2_MMAL, mpeg2_mmal); - REGISTER_HWACCEL(MPEG2_QSV, mpeg2_qsv); - REGISTER_HWACCEL(MPEG2_VAAPI, mpeg2_vaapi); - REGISTER_HWACCEL(MPEG2_VDPAU, mpeg2_vdpau); - REGISTER_HWACCEL(MPEG2_VIDEOTOOLBOX, mpeg2_videotoolbox); - REGISTER_HWACCEL(MPEG2_MEDIACODEC, mpeg2_mediacodec); - REGISTER_HWACCEL(MPEG4_CUVID, mpeg4_cuvid); - REGISTER_HWACCEL(MPEG4_MEDIACODEC, mpeg4_mediacodec); - REGISTER_HWACCEL(MPEG4_MMAL, mpeg4_mmal); - REGISTER_HWACCEL(MPEG4_VAAPI, mpeg4_vaapi); - REGISTER_HWACCEL(MPEG4_VDPAU, mpeg4_vdpau); - REGISTER_HWACCEL(MPEG4_VIDEOTOOLBOX, mpeg4_videotoolbox); - REGISTER_HWACCEL(VC1_CUVID, vc1_cuvid); - REGISTER_HWACCEL(VC1_D3D11VA, vc1_d3d11va); - REGISTER_HWACCEL(VC1_D3D11VA2, vc1_d3d11va2); - REGISTER_HWACCEL(VC1_DXVA2, vc1_dxva2); - REGISTER_HWACCEL(VC1_VAAPI, vc1_vaapi); - REGISTER_HWACCEL(VC1_VDPAU, vc1_vdpau); - REGISTER_HWACCEL(VC1_MMAL, vc1_mmal); - REGISTER_HWACCEL(VC1_QSV, vc1_qsv); - REGISTER_HWACCEL(VP8_CUVID, vp8_cuvid); - REGISTER_HWACCEL(VP8_MEDIACODEC, vp8_mediacodec); - REGISTER_HWACCEL(VP8_QSV, vp8_qsv); - REGISTER_HWACCEL(VP9_CUVID, vp9_cuvid); - REGISTER_HWACCEL(VP9_D3D11VA, vp9_d3d11va); - REGISTER_HWACCEL(VP9_D3D11VA2, vp9_d3d11va2); - REGISTER_HWACCEL(VP9_DXVA2, vp9_dxva2); - REGISTER_HWACCEL(VP9_MEDIACODEC, vp9_mediacodec); - REGISTER_HWACCEL(VP9_VAAPI, vp9_vaapi); - REGISTER_HWACCEL(WMV3_D3D11VA, wmv3_d3d11va); - REGISTER_HWACCEL(WMV3_D3D11VA2, wmv3_d3d11va2); - REGISTER_HWACCEL(WMV3_DXVA2, wmv3_dxva2); - REGISTER_HWACCEL(WMV3_VAAPI, wmv3_vaapi); - REGISTER_HWACCEL(WMV3_VDPAU, wmv3_vdpau); - - /* video codecs */ - REGISTER_ENCODER(A64MULTI, a64multi); - REGISTER_ENCODER(A64MULTI5, a64multi5); - REGISTER_DECODER(AASC, aasc); - REGISTER_DECODER(AIC, aic); - REGISTER_ENCDEC (ALIAS_PIX, alias_pix); - REGISTER_ENCDEC (AMV, amv); - REGISTER_DECODER(ANM, anm); - REGISTER_DECODER(ANSI, ansi); - REGISTER_ENCDEC (APNG, apng); - REGISTER_ENCDEC (ASV1, asv1); - REGISTER_ENCDEC (ASV2, asv2); - REGISTER_DECODER(AURA, aura); - REGISTER_DECODER(AURA2, aura2); - REGISTER_ENCDEC (AVRP, avrp); - REGISTER_DECODER(AVRN, avrn); - REGISTER_DECODER(AVS, avs); - REGISTER_ENCDEC (AVUI, avui); - REGISTER_ENCDEC (AYUV, ayuv); - REGISTER_DECODER(BETHSOFTVID, bethsoftvid); - REGISTER_DECODER(BFI, bfi); - REGISTER_DECODER(BINK, bink); - REGISTER_ENCDEC (BMP, bmp); - REGISTER_DECODER(BMV_VIDEO, bmv_video); - REGISTER_DECODER(BRENDER_PIX, brender_pix); - REGISTER_DECODER(C93, c93); - REGISTER_DECODER(CAVS, cavs); - REGISTER_DECODER(CDGRAPHICS, cdgraphics); - REGISTER_DECODER(CDXL, cdxl); - REGISTER_DECODER(CFHD, cfhd); - REGISTER_ENCDEC (CINEPAK, cinepak); - REGISTER_DECODER(CLEARVIDEO, clearvideo); - REGISTER_ENCDEC (CLJR, cljr); - REGISTER_DECODER(CLLC, cllc); - REGISTER_ENCDEC (COMFORTNOISE, comfortnoise); - REGISTER_DECODER(CPIA, cpia); - REGISTER_DECODER(CSCD, cscd); - REGISTER_DECODER(CYUV, cyuv); - REGISTER_DECODER(DDS, dds); - REGISTER_DECODER(DFA, dfa); - REGISTER_DECODER(DIRAC, dirac); - REGISTER_ENCDEC (DNXHD, dnxhd); - REGISTER_ENCDEC (DPX, dpx); - REGISTER_DECODER(DSICINVIDEO, dsicinvideo); - REGISTER_DECODER(DVAUDIO, dvaudio); - REGISTER_ENCDEC (DVVIDEO, dvvideo); - REGISTER_DECODER(DXA, dxa); - REGISTER_DECODER(DXTORY, dxtory); - REGISTER_DECODER(DXV, dxv); - REGISTER_DECODER(EACMV, eacmv); - REGISTER_DECODER(EAMAD, eamad); - REGISTER_DECODER(EATGQ, eatgq); - REGISTER_DECODER(EATGV, eatgv); - REGISTER_DECODER(EATQI, eatqi); - REGISTER_DECODER(EIGHTBPS, eightbps); - REGISTER_DECODER(EIGHTSVX_EXP, eightsvx_exp); - REGISTER_DECODER(EIGHTSVX_FIB, eightsvx_fib); - REGISTER_DECODER(ESCAPE124, escape124); - REGISTER_DECODER(ESCAPE130, escape130); - REGISTER_DECODER(EXR, exr); - REGISTER_ENCDEC (FFV1, ffv1); - REGISTER_ENCDEC (FFVHUFF, ffvhuff); - REGISTER_DECODER(FIC, fic); - REGISTER_ENCDEC (FITS, fits); - REGISTER_ENCDEC (FLASHSV, flashsv); - REGISTER_ENCDEC (FLASHSV2, flashsv2); - REGISTER_DECODER(FLIC, flic); - REGISTER_ENCDEC (FLV, flv); - REGISTER_DECODER(FMVC, fmvc); - REGISTER_DECODER(FOURXM, fourxm); - REGISTER_DECODER(FRAPS, fraps); - REGISTER_DECODER(FRWU, frwu); - REGISTER_DECODER(G2M, g2m); - REGISTER_DECODER(GDV, gdv); - REGISTER_ENCDEC (GIF, gif); - REGISTER_ENCDEC (H261, h261); - REGISTER_ENCDEC (H263, h263); - REGISTER_DECODER(H263I, h263i); - REGISTER_ENCDEC (H263P, h263p); - REGISTER_DECODER(H263_V4L2M2M, h263_v4l2m2m); - REGISTER_DECODER(H264, h264); - REGISTER_DECODER(H264_CRYSTALHD, h264_crystalhd); - REGISTER_DECODER(H264_V4L2M2M, h264_v4l2m2m); - REGISTER_DECODER(H264_MEDIACODEC, h264_mediacodec); - REGISTER_DECODER(H264_MMAL, h264_mmal); - REGISTER_DECODER(H264_QSV, h264_qsv); - REGISTER_DECODER(H264_RKMPP, h264_rkmpp); - REGISTER_DECODER(H264_VDA, h264_vda); -#if FF_API_VDPAU - REGISTER_DECODER(H264_VDPAU, h264_vdpau); -#endif - REGISTER_ENCDEC (HAP, hap); - REGISTER_DECODER(HEVC, hevc); - REGISTER_DECODER(HEVC_QSV, hevc_qsv); - REGISTER_DECODER(HEVC_RKMPP, hevc_rkmpp); - REGISTER_DECODER(HEVC_V4L2M2M, hevc_v4l2m2m); - REGISTER_DECODER(HNM4_VIDEO, hnm4_video); - REGISTER_DECODER(HQ_HQA, hq_hqa); - REGISTER_DECODER(HQX, hqx); - REGISTER_ENCDEC (HUFFYUV, huffyuv); - REGISTER_DECODER(IDCIN, idcin); - REGISTER_DECODER(IFF_ILBM, iff_ilbm); - REGISTER_DECODER(INDEO2, indeo2); - REGISTER_DECODER(INDEO3, indeo3); - REGISTER_DECODER(INDEO4, indeo4); - REGISTER_DECODER(INDEO5, indeo5); - REGISTER_DECODER(INTERPLAY_VIDEO, interplay_video); - REGISTER_ENCDEC (JPEG2000, jpeg2000); - REGISTER_ENCDEC (JPEGLS, jpegls); - REGISTER_DECODER(JV, jv); - REGISTER_DECODER(KGV1, kgv1); - REGISTER_DECODER(KMVC, kmvc); - REGISTER_DECODER(LAGARITH, lagarith); - REGISTER_ENCODER(LJPEG, ljpeg); - REGISTER_DECODER(LOCO, loco); - REGISTER_DECODER(M101, m101); - REGISTER_DECODER(MAGICYUV, magicyuv); - REGISTER_DECODER(MDEC, mdec); - REGISTER_DECODER(MIMIC, mimic); - REGISTER_ENCDEC (MJPEG, mjpeg); - REGISTER_DECODER(MJPEGB, mjpegb); - REGISTER_DECODER(MMVIDEO, mmvideo); - REGISTER_DECODER(MOTIONPIXELS, motionpixels); -#if FF_API_XVMC - REGISTER_DECODER(MPEG_XVMC, mpeg_xvmc); -#endif /* FF_API_XVMC */ - REGISTER_ENCDEC (MPEG1VIDEO, mpeg1video); - REGISTER_ENCDEC (MPEG2VIDEO, mpeg2video); - REGISTER_ENCDEC (MPEG4, mpeg4); - REGISTER_DECODER(MPEG4_CRYSTALHD, mpeg4_crystalhd); - REGISTER_DECODER(MPEG4_V4L2M2M, mpeg4_v4l2m2m); - REGISTER_DECODER(MPEG4_MMAL, mpeg4_mmal); -#if FF_API_VDPAU - REGISTER_DECODER(MPEG4_VDPAU, mpeg4_vdpau); -#endif - REGISTER_DECODER(MPEGVIDEO, mpegvideo); -#if FF_API_VDPAU - REGISTER_DECODER(MPEG_VDPAU, mpeg_vdpau); - REGISTER_DECODER(MPEG1_VDPAU, mpeg1_vdpau); -#endif - REGISTER_DECODER(MPEG1_V4L2M2M, mpeg1_v4l2m2m); - REGISTER_DECODER(MPEG2_MMAL, mpeg2_mmal); - REGISTER_DECODER(MPEG2_CRYSTALHD, mpeg2_crystalhd); - REGISTER_DECODER(MPEG2_V4L2M2M, mpeg2_v4l2m2m); - REGISTER_DECODER(MPEG2_QSV, mpeg2_qsv); - REGISTER_DECODER(MPEG2_MEDIACODEC, mpeg2_mediacodec); - REGISTER_DECODER(MSA1, msa1); - REGISTER_DECODER(MSCC, mscc); - REGISTER_DECODER(MSMPEG4V1, msmpeg4v1); - REGISTER_ENCDEC (MSMPEG4V2, msmpeg4v2); - REGISTER_ENCDEC (MSMPEG4V3, msmpeg4v3); - REGISTER_DECODER(MSMPEG4_CRYSTALHD, msmpeg4_crystalhd); - REGISTER_DECODER(MSRLE, msrle); - REGISTER_DECODER(MSS1, mss1); - REGISTER_DECODER(MSS2, mss2); - REGISTER_ENCDEC (MSVIDEO1, msvideo1); - REGISTER_DECODER(MSZH, mszh); - REGISTER_DECODER(MTS2, mts2); - REGISTER_DECODER(MVC1, mvc1); - REGISTER_DECODER(MVC2, mvc2); - REGISTER_DECODER(MXPEG, mxpeg); - REGISTER_DECODER(NUV, nuv); - REGISTER_DECODER(PAF_VIDEO, paf_video); - REGISTER_ENCDEC (PAM, pam); - REGISTER_ENCDEC (PBM, pbm); - REGISTER_ENCDEC (PCX, pcx); - REGISTER_ENCDEC (PGM, pgm); - REGISTER_ENCDEC (PGMYUV, pgmyuv); - REGISTER_DECODER(PICTOR, pictor); - REGISTER_DECODER(PIXLET, pixlet); - REGISTER_ENCDEC (PNG, png); - REGISTER_ENCDEC (PPM, ppm); - REGISTER_ENCDEC (PRORES, prores); - REGISTER_ENCODER(PRORES_AW, prores_aw); - REGISTER_ENCODER(PRORES_KS, prores_ks); - REGISTER_DECODER(PRORES_LGPL, prores_lgpl); - REGISTER_DECODER(PSD, psd); - REGISTER_DECODER(PTX, ptx); - REGISTER_DECODER(QDRAW, qdraw); - REGISTER_DECODER(QPEG, qpeg); - REGISTER_ENCDEC (QTRLE, qtrle); - REGISTER_ENCDEC (R10K, r10k); - REGISTER_ENCDEC (R210, r210); - REGISTER_ENCDEC (RAWVIDEO, rawvideo); - REGISTER_DECODER(RL2, rl2); - REGISTER_ENCDEC (ROQ, roq); - REGISTER_DECODER(RPZA, rpza); - REGISTER_DECODER(RSCC, rscc); - REGISTER_ENCDEC (RV10, rv10); - REGISTER_ENCDEC (RV20, rv20); - REGISTER_DECODER(RV30, rv30); - REGISTER_DECODER(RV40, rv40); - REGISTER_ENCDEC (S302M, s302m); - REGISTER_DECODER(SANM, sanm); - REGISTER_DECODER(SCPR, scpr); - REGISTER_DECODER(SCREENPRESSO, screenpresso); - REGISTER_DECODER(SDX2_DPCM, sdx2_dpcm); - REGISTER_ENCDEC (SGI, sgi); - REGISTER_DECODER(SGIRLE, sgirle); - REGISTER_DECODER(SHEERVIDEO, sheervideo); - REGISTER_DECODER(SMACKER, smacker); - REGISTER_DECODER(SMC, smc); - REGISTER_DECODER(SMVJPEG, smvjpeg); - REGISTER_ENCDEC (SNOW, snow); - REGISTER_DECODER(SP5X, sp5x); - REGISTER_DECODER(SPEEDHQ, speedhq); - REGISTER_DECODER(SRGC, srgc); - REGISTER_ENCDEC (SUNRAST, sunrast); - REGISTER_ENCDEC (SVQ1, svq1); - REGISTER_DECODER(SVQ3, svq3); - REGISTER_ENCDEC (TARGA, targa); - REGISTER_DECODER(TARGA_Y216, targa_y216); - REGISTER_DECODER(TDSC, tdsc); - REGISTER_DECODER(THEORA, theora); - REGISTER_DECODER(THP, thp); - REGISTER_DECODER(TIERTEXSEQVIDEO, tiertexseqvideo); - REGISTER_ENCDEC (TIFF, tiff); - REGISTER_DECODER(TMV, tmv); - REGISTER_DECODER(TRUEMOTION1, truemotion1); - REGISTER_DECODER(TRUEMOTION2, truemotion2); - REGISTER_DECODER(TRUEMOTION2RT, truemotion2rt); - REGISTER_DECODER(TSCC, tscc); - REGISTER_DECODER(TSCC2, tscc2); - REGISTER_DECODER(TXD, txd); - REGISTER_DECODER(ULTI, ulti); - REGISTER_ENCDEC (UTVIDEO, utvideo); - REGISTER_ENCDEC (V210, v210); - REGISTER_DECODER(V210X, v210x); - REGISTER_ENCDEC (V308, v308); - REGISTER_ENCDEC (V408, v408); - REGISTER_ENCDEC (V410, v410); - REGISTER_DECODER(VB, vb); - REGISTER_DECODER(VBLE, vble); - REGISTER_DECODER(VC1, vc1); - REGISTER_DECODER(VC1_CRYSTALHD, vc1_crystalhd); -#if FF_API_VDPAU - REGISTER_DECODER(VC1_VDPAU, vc1_vdpau); -#endif - REGISTER_DECODER(VC1IMAGE, vc1image); - REGISTER_DECODER(VC1_MMAL, vc1_mmal); - REGISTER_DECODER(VC1_QSV, vc1_qsv); - REGISTER_DECODER(VC1_V4L2M2M, vc1_v4l2m2m); - REGISTER_ENCODER(VC2, vc2); - REGISTER_DECODER(VCR1, vcr1); - REGISTER_DECODER(VMDVIDEO, vmdvideo); - REGISTER_DECODER(VMNC, vmnc); - REGISTER_DECODER(VP3, vp3); - REGISTER_DECODER(VP5, vp5); - REGISTER_DECODER(VP6, vp6); - REGISTER_DECODER(VP6A, vp6a); - REGISTER_DECODER(VP6F, vp6f); - REGISTER_DECODER(VP7, vp7); - REGISTER_DECODER(VP8, vp8); - REGISTER_DECODER(VP8_RKMPP, vp8_rkmpp); - REGISTER_DECODER(VP8_V4L2M2M, vp8_v4l2m2m); - REGISTER_DECODER(VP9, vp9); - REGISTER_DECODER(VP9_RKMPP, vp9_rkmpp); - REGISTER_DECODER(VP9_V4L2M2M, vp9_v4l2m2m); - REGISTER_DECODER(VQA, vqa); - REGISTER_DECODER(BITPACKED, bitpacked); - REGISTER_DECODER(WEBP, webp); - REGISTER_ENCDEC (WRAPPED_AVFRAME, wrapped_avframe); - REGISTER_ENCDEC (WMV1, wmv1); - REGISTER_ENCDEC (WMV2, wmv2); - REGISTER_DECODER(WMV3, wmv3); - REGISTER_DECODER(WMV3_CRYSTALHD, wmv3_crystalhd); -#if FF_API_VDPAU - REGISTER_DECODER(WMV3_VDPAU, wmv3_vdpau); -#endif - REGISTER_DECODER(WMV3IMAGE, wmv3image); - REGISTER_DECODER(WNV1, wnv1); - REGISTER_DECODER(XAN_WC3, xan_wc3); - REGISTER_DECODER(XAN_WC4, xan_wc4); - REGISTER_ENCDEC (XBM, xbm); - REGISTER_ENCDEC (XFACE, xface); - REGISTER_DECODER(XL, xl); - REGISTER_DECODER(XPM, xpm); - REGISTER_ENCDEC (XWD, xwd); - REGISTER_ENCDEC (Y41P, y41p); - REGISTER_DECODER(YLC, ylc); - REGISTER_DECODER(YOP, yop); - REGISTER_ENCDEC (YUV4, yuv4); - REGISTER_DECODER(ZERO12V, zero12v); - REGISTER_DECODER(ZEROCODEC, zerocodec); - REGISTER_ENCDEC (ZLIB, zlib); - REGISTER_ENCDEC (ZMBV, zmbv); - - /* audio codecs */ - REGISTER_ENCDEC (AAC, aac); - REGISTER_DECODER(AAC_FIXED, aac_fixed); - REGISTER_DECODER(AAC_LATM, aac_latm); - REGISTER_ENCDEC (AC3, ac3); - REGISTER_ENCDEC (AC3_FIXED, ac3_fixed); - REGISTER_ENCDEC (ALAC, alac); - REGISTER_DECODER(ALS, als); - REGISTER_DECODER(AMRNB, amrnb); - REGISTER_DECODER(AMRWB, amrwb); - REGISTER_DECODER(APE, ape); - REGISTER_DECODER(ATRAC1, atrac1); - REGISTER_DECODER(ATRAC3, atrac3); - REGISTER_DECODER(ATRAC3AL, atrac3al); - REGISTER_DECODER(ATRAC3P, atrac3p); - REGISTER_DECODER(ATRAC3PAL, atrac3pal); - REGISTER_DECODER(BINKAUDIO_DCT, binkaudio_dct); - REGISTER_DECODER(BINKAUDIO_RDFT, binkaudio_rdft); - REGISTER_DECODER(BMV_AUDIO, bmv_audio); - REGISTER_DECODER(COOK, cook); - REGISTER_ENCDEC (DCA, dca); - REGISTER_DECODER(DOLBY_E, dolby_e); - REGISTER_DECODER(DSD_LSBF, dsd_lsbf); - REGISTER_DECODER(DSD_MSBF, dsd_msbf); - REGISTER_DECODER(DSD_LSBF_PLANAR, dsd_lsbf_planar); - REGISTER_DECODER(DSD_MSBF_PLANAR, dsd_msbf_planar); - REGISTER_DECODER(DSICINAUDIO, dsicinaudio); - REGISTER_DECODER(DSS_SP, dss_sp); - REGISTER_DECODER(DST, dst); - REGISTER_ENCDEC (EAC3, eac3); - REGISTER_DECODER(EVRC, evrc); - REGISTER_DECODER(FFWAVESYNTH, ffwavesynth); - REGISTER_ENCDEC (FLAC, flac); - REGISTER_ENCDEC (G723_1, g723_1); - REGISTER_DECODER(G729, g729); - REGISTER_DECODER(GSM, gsm); - REGISTER_DECODER(GSM_MS, gsm_ms); - REGISTER_DECODER(IAC, iac); - REGISTER_DECODER(IMC, imc); - REGISTER_DECODER(INTERPLAY_ACM, interplay_acm); - REGISTER_DECODER(MACE3, mace3); - REGISTER_DECODER(MACE6, mace6); - REGISTER_DECODER(METASOUND, metasound); - REGISTER_ENCDEC (MLP, mlp); - REGISTER_DECODER(MP1, mp1); - REGISTER_DECODER(MP1FLOAT, mp1float); - REGISTER_ENCDEC (MP2, mp2); - REGISTER_DECODER(MP2FLOAT, mp2float); - REGISTER_ENCODER(MP2FIXED, mp2fixed); - REGISTER_DECODER(MP3, mp3); - REGISTER_DECODER(MP3FLOAT, mp3float); - REGISTER_DECODER(MP3ADU, mp3adu); - REGISTER_DECODER(MP3ADUFLOAT, mp3adufloat); - REGISTER_DECODER(MP3ON4, mp3on4); - REGISTER_DECODER(MP3ON4FLOAT, mp3on4float); - REGISTER_DECODER(MPC7, mpc7); - REGISTER_DECODER(MPC8, mpc8); - REGISTER_ENCDEC (NELLYMOSER, nellymoser); - REGISTER_DECODER(ON2AVC, on2avc); - REGISTER_ENCDEC (OPUS, opus); - REGISTER_DECODER(PAF_AUDIO, paf_audio); - REGISTER_DECODER(QCELP, qcelp); - REGISTER_DECODER(QDM2, qdm2); - REGISTER_DECODER(QDMC, qdmc); - REGISTER_ENCDEC (RA_144, ra_144); - REGISTER_DECODER(RA_288, ra_288); - REGISTER_DECODER(RALF, ralf); - REGISTER_DECODER(SHORTEN, shorten); - REGISTER_DECODER(SIPR, sipr); - REGISTER_DECODER(SMACKAUD, smackaud); - REGISTER_ENCDEC (SONIC, sonic); - REGISTER_ENCODER(SONIC_LS, sonic_ls); - REGISTER_DECODER(TAK, tak); - REGISTER_ENCDEC (TRUEHD, truehd); - REGISTER_DECODER(TRUESPEECH, truespeech); - REGISTER_ENCDEC (TTA, tta); - REGISTER_DECODER(TWINVQ, twinvq); - REGISTER_DECODER(VMDAUDIO, vmdaudio); - REGISTER_ENCDEC (VORBIS, vorbis); - REGISTER_ENCDEC (WAVPACK, wavpack); - REGISTER_DECODER(WMALOSSLESS, wmalossless); - REGISTER_DECODER(WMAPRO, wmapro); - REGISTER_ENCDEC (WMAV1, wmav1); - REGISTER_ENCDEC (WMAV2, wmav2); - REGISTER_DECODER(WMAVOICE, wmavoice); - REGISTER_DECODER(WS_SND1, ws_snd1); - REGISTER_DECODER(XMA1, xma1); - REGISTER_DECODER(XMA2, xma2); - - /* PCM codecs */ - REGISTER_ENCDEC (PCM_ALAW, pcm_alaw); - REGISTER_DECODER(PCM_BLURAY, pcm_bluray); - REGISTER_DECODER(PCM_DVD, pcm_dvd); - REGISTER_DECODER(PCM_F16LE, pcm_f16le); - REGISTER_DECODER(PCM_F24LE, pcm_f24le); - REGISTER_ENCDEC (PCM_F32BE, pcm_f32be); - REGISTER_ENCDEC (PCM_F32LE, pcm_f32le); - REGISTER_ENCDEC (PCM_F64BE, pcm_f64be); - REGISTER_ENCDEC (PCM_F64LE, pcm_f64le); - REGISTER_DECODER(PCM_LXF, pcm_lxf); - REGISTER_ENCDEC (PCM_MULAW, pcm_mulaw); - REGISTER_ENCDEC (PCM_S8, pcm_s8); - REGISTER_ENCDEC (PCM_S8_PLANAR, pcm_s8_planar); - REGISTER_ENCDEC (PCM_S16BE, pcm_s16be); - REGISTER_ENCDEC (PCM_S16BE_PLANAR, pcm_s16be_planar); - REGISTER_ENCDEC (PCM_S16LE, pcm_s16le); - REGISTER_ENCDEC (PCM_S16LE_PLANAR, pcm_s16le_planar); - REGISTER_ENCDEC (PCM_S24BE, pcm_s24be); - REGISTER_ENCDEC (PCM_S24DAUD, pcm_s24daud); - REGISTER_ENCDEC (PCM_S24LE, pcm_s24le); - REGISTER_ENCDEC (PCM_S24LE_PLANAR, pcm_s24le_planar); - REGISTER_ENCDEC (PCM_S32BE, pcm_s32be); - REGISTER_ENCDEC (PCM_S32LE, pcm_s32le); - REGISTER_ENCDEC (PCM_S32LE_PLANAR, pcm_s32le_planar); - REGISTER_ENCDEC (PCM_S64BE, pcm_s64be); - REGISTER_ENCDEC (PCM_S64LE, pcm_s64le); - REGISTER_ENCDEC (PCM_U8, pcm_u8); - REGISTER_ENCDEC (PCM_U16BE, pcm_u16be); - REGISTER_ENCDEC (PCM_U16LE, pcm_u16le); - REGISTER_ENCDEC (PCM_U24BE, pcm_u24be); - REGISTER_ENCDEC (PCM_U24LE, pcm_u24le); - REGISTER_ENCDEC (PCM_U32BE, pcm_u32be); - REGISTER_ENCDEC (PCM_U32LE, pcm_u32le); - REGISTER_DECODER(PCM_ZORK, pcm_zork); - - /* DPCM codecs */ - REGISTER_DECODER(GREMLIN_DPCM, gremlin_dpcm); - REGISTER_DECODER(INTERPLAY_DPCM, interplay_dpcm); - REGISTER_ENCDEC (ROQ_DPCM, roq_dpcm); - REGISTER_DECODER(SOL_DPCM, sol_dpcm); - REGISTER_DECODER(XAN_DPCM, xan_dpcm); - - /* ADPCM codecs */ - REGISTER_DECODER(ADPCM_4XM, adpcm_4xm); - REGISTER_ENCDEC (ADPCM_ADX, adpcm_adx); - REGISTER_DECODER(ADPCM_AFC, adpcm_afc); - REGISTER_DECODER(ADPCM_AICA, adpcm_aica); - REGISTER_DECODER(ADPCM_CT, adpcm_ct); - REGISTER_DECODER(ADPCM_DTK, adpcm_dtk); - REGISTER_DECODER(ADPCM_EA, adpcm_ea); - REGISTER_DECODER(ADPCM_EA_MAXIS_XA, adpcm_ea_maxis_xa); - REGISTER_DECODER(ADPCM_EA_R1, adpcm_ea_r1); - REGISTER_DECODER(ADPCM_EA_R2, adpcm_ea_r2); - REGISTER_DECODER(ADPCM_EA_R3, adpcm_ea_r3); - REGISTER_DECODER(ADPCM_EA_XAS, adpcm_ea_xas); - REGISTER_ENCDEC (ADPCM_G722, adpcm_g722); - REGISTER_ENCDEC (ADPCM_G726, adpcm_g726); - REGISTER_ENCDEC (ADPCM_G726LE, adpcm_g726le); - REGISTER_DECODER(ADPCM_IMA_AMV, adpcm_ima_amv); - REGISTER_DECODER(ADPCM_IMA_APC, adpcm_ima_apc); - REGISTER_DECODER(ADPCM_IMA_DAT4, adpcm_ima_dat4); - REGISTER_DECODER(ADPCM_IMA_DK3, adpcm_ima_dk3); - REGISTER_DECODER(ADPCM_IMA_DK4, adpcm_ima_dk4); - REGISTER_DECODER(ADPCM_IMA_EA_EACS, adpcm_ima_ea_eacs); - REGISTER_DECODER(ADPCM_IMA_EA_SEAD, adpcm_ima_ea_sead); - REGISTER_DECODER(ADPCM_IMA_ISS, adpcm_ima_iss); - REGISTER_DECODER(ADPCM_IMA_OKI, adpcm_ima_oki); - REGISTER_ENCDEC (ADPCM_IMA_QT, adpcm_ima_qt); - REGISTER_DECODER(ADPCM_IMA_RAD, adpcm_ima_rad); - REGISTER_DECODER(ADPCM_IMA_SMJPEG, adpcm_ima_smjpeg); - REGISTER_ENCDEC (ADPCM_IMA_WAV, adpcm_ima_wav); - REGISTER_DECODER(ADPCM_IMA_WS, adpcm_ima_ws); - REGISTER_ENCDEC (ADPCM_MS, adpcm_ms); - REGISTER_DECODER(ADPCM_MTAF, adpcm_mtaf); - REGISTER_DECODER(ADPCM_PSX, adpcm_psx); - REGISTER_DECODER(ADPCM_SBPRO_2, adpcm_sbpro_2); - REGISTER_DECODER(ADPCM_SBPRO_3, adpcm_sbpro_3); - REGISTER_DECODER(ADPCM_SBPRO_4, adpcm_sbpro_4); - REGISTER_ENCDEC (ADPCM_SWF, adpcm_swf); - REGISTER_DECODER(ADPCM_THP, adpcm_thp); - REGISTER_DECODER(ADPCM_THP_LE, adpcm_thp_le); - REGISTER_DECODER(ADPCM_VIMA, adpcm_vima); - REGISTER_DECODER(ADPCM_XA, adpcm_xa); - REGISTER_ENCDEC (ADPCM_YAMAHA, adpcm_yamaha); - - /* subtitles */ - REGISTER_ENCDEC (SSA, ssa); - REGISTER_ENCDEC (ASS, ass); - REGISTER_DECODER(CCAPTION, ccaption); - REGISTER_ENCDEC (DVBSUB, dvbsub); - REGISTER_ENCDEC (DVDSUB, dvdsub); - REGISTER_DECODER(JACOSUB, jacosub); - REGISTER_DECODER(MICRODVD, microdvd); - REGISTER_ENCDEC (MOVTEXT, movtext); - REGISTER_DECODER(MPL2, mpl2); - REGISTER_DECODER(PGSSUB, pgssub); - REGISTER_DECODER(PJS, pjs); - REGISTER_DECODER(REALTEXT, realtext); - REGISTER_DECODER(SAMI, sami); - REGISTER_ENCDEC (SRT, srt); - REGISTER_DECODER(STL, stl); - REGISTER_ENCDEC (SUBRIP, subrip); - REGISTER_DECODER(SUBVIEWER, subviewer); - REGISTER_DECODER(SUBVIEWER1, subviewer1); - REGISTER_ENCDEC (TEXT, text); - REGISTER_DECODER(VPLAYER, vplayer); - REGISTER_ENCDEC (WEBVTT, webvtt); - REGISTER_ENCDEC (XSUB, xsub); - - /* external libraries */ - REGISTER_ENCDEC (AAC_AT, aac_at); - REGISTER_DECODER(AC3_AT, ac3_at); - REGISTER_DECODER(ADPCM_IMA_QT_AT, adpcm_ima_qt_at); - REGISTER_ENCDEC (ALAC_AT, alac_at); - REGISTER_DECODER(AMR_NB_AT, amr_nb_at); - REGISTER_DECODER(EAC3_AT, eac3_at); - REGISTER_DECODER(GSM_MS_AT, gsm_ms_at); - REGISTER_ENCDEC (ILBC_AT, ilbc_at); - REGISTER_DECODER(MP1_AT, mp1_at); - REGISTER_DECODER(MP2_AT, mp2_at); - REGISTER_DECODER(MP3_AT, mp3_at); - REGISTER_ENCDEC (PCM_ALAW_AT, pcm_alaw_at); - REGISTER_ENCDEC (PCM_MULAW_AT, pcm_mulaw_at); - REGISTER_DECODER(QDMC_AT, qdmc_at); - REGISTER_DECODER(QDM2_AT, qdm2_at); - REGISTER_DECODER(LIBCELT, libcelt); - REGISTER_ENCDEC (LIBFDK_AAC, libfdk_aac); - REGISTER_ENCDEC (LIBGSM, libgsm); - REGISTER_ENCDEC (LIBGSM_MS, libgsm_ms); - REGISTER_ENCDEC (LIBILBC, libilbc); - REGISTER_ENCODER(LIBMP3LAME, libmp3lame); - REGISTER_ENCDEC (LIBOPENCORE_AMRNB, libopencore_amrnb); - REGISTER_DECODER(LIBOPENCORE_AMRWB, libopencore_amrwb); - REGISTER_ENCDEC (LIBOPENJPEG, libopenjpeg); - REGISTER_ENCDEC (LIBOPUS, libopus); - REGISTER_DECODER(LIBRSVG, librsvg); - REGISTER_ENCODER(LIBSHINE, libshine); - REGISTER_ENCDEC (LIBSPEEX, libspeex); - REGISTER_ENCODER(LIBTHEORA, libtheora); - REGISTER_ENCODER(LIBTWOLAME, libtwolame); - REGISTER_ENCODER(LIBVO_AMRWBENC, libvo_amrwbenc); - REGISTER_ENCDEC (LIBVORBIS, libvorbis); - REGISTER_ENCDEC (LIBVPX_VP8, libvpx_vp8); - REGISTER_ENCDEC (LIBVPX_VP9, libvpx_vp9); - REGISTER_ENCODER(LIBWAVPACK, libwavpack); - REGISTER_ENCODER(LIBWEBP_ANIM, libwebp_anim); /* preferred over libwebp */ - REGISTER_ENCODER(LIBWEBP, libwebp); - REGISTER_ENCODER(LIBX262, libx262); - REGISTER_ENCODER(LIBX264, libx264); - REGISTER_ENCODER(LIBX264RGB, libx264rgb); - REGISTER_ENCODER(LIBX265, libx265); - REGISTER_ENCODER(LIBXAVS, libxavs); - REGISTER_ENCODER(LIBXVID, libxvid); - REGISTER_DECODER(LIBZVBI_TELETEXT, libzvbi_teletext); - - /* text */ - REGISTER_DECODER(BINTEXT, bintext); - REGISTER_DECODER(XBIN, xbin); - REGISTER_DECODER(IDF, idf); - - /* external libraries, that shouldn't be used by default if one of the - * above is available */ - REGISTER_ENCODER(H263_V4L2M2M, h263_v4l2m2m); - REGISTER_ENCDEC (LIBOPENH264, libopenh264); - REGISTER_DECODER(H264_CUVID, h264_cuvid); - REGISTER_ENCODER(H264_NVENC, h264_nvenc); - REGISTER_ENCODER(H264_OMX, h264_omx); - REGISTER_ENCODER(H264_QSV, h264_qsv); - REGISTER_ENCODER(H264_V4L2M2M, h264_v4l2m2m); - REGISTER_ENCODER(H264_VAAPI, h264_vaapi); - REGISTER_ENCODER(H264_VIDEOTOOLBOX, h264_videotoolbox); -#if FF_API_NVENC_OLD_NAME - REGISTER_ENCODER(NVENC, nvenc); - REGISTER_ENCODER(NVENC_H264, nvenc_h264); - REGISTER_ENCODER(NVENC_HEVC, nvenc_hevc); -#endif - REGISTER_DECODER(HEVC_CUVID, hevc_cuvid); - REGISTER_DECODER(HEVC_MEDIACODEC, hevc_mediacodec); - REGISTER_ENCODER(HEVC_NVENC, hevc_nvenc); - REGISTER_ENCODER(HEVC_QSV, hevc_qsv); - REGISTER_ENCODER(HEVC_V4L2M2M, hevc_v4l2m2m); - REGISTER_ENCODER(HEVC_VAAPI, hevc_vaapi); - REGISTER_ENCODER(LIBKVAZAAR, libkvazaar); - REGISTER_DECODER(MJPEG_CUVID, mjpeg_cuvid); - REGISTER_ENCODER(MJPEG_VAAPI, mjpeg_vaapi); - REGISTER_DECODER(MPEG1_CUVID, mpeg1_cuvid); - REGISTER_DECODER(MPEG2_CUVID, mpeg2_cuvid); - REGISTER_ENCODER(MPEG2_QSV, mpeg2_qsv); - REGISTER_ENCODER(MPEG2_VAAPI, mpeg2_vaapi); - REGISTER_DECODER(MPEG4_CUVID, mpeg4_cuvid); - REGISTER_DECODER(MPEG4_MEDIACODEC, mpeg4_mediacodec); - REGISTER_ENCODER(MPEG4_V4L2M2M, mpeg4_v4l2m2m); - REGISTER_DECODER(VC1_CUVID, vc1_cuvid); - REGISTER_DECODER(VP8_CUVID, vp8_cuvid); - REGISTER_DECODER(VP8_MEDIACODEC, vp8_mediacodec); - REGISTER_DECODER(VP8_QSV, vp8_qsv); - REGISTER_ENCODER(VP8_V4L2M2M, vp8_v4l2m2m); - REGISTER_ENCODER(VP8_VAAPI, vp8_vaapi); - REGISTER_DECODER(VP9_CUVID, vp9_cuvid); - REGISTER_DECODER(VP9_MEDIACODEC, vp9_mediacodec); - REGISTER_ENCODER(VP9_VAAPI, vp9_vaapi); - - /* parsers */ - REGISTER_PARSER(AAC, aac); - REGISTER_PARSER(AAC_LATM, aac_latm); - REGISTER_PARSER(AC3, ac3); - REGISTER_PARSER(ADX, adx); - REGISTER_PARSER(BMP, bmp); - REGISTER_PARSER(CAVSVIDEO, cavsvideo); - REGISTER_PARSER(COOK, cook); - REGISTER_PARSER(DCA, dca); - REGISTER_PARSER(DIRAC, dirac); - REGISTER_PARSER(DNXHD, dnxhd); - REGISTER_PARSER(DPX, dpx); - REGISTER_PARSER(DVAUDIO, dvaudio); - REGISTER_PARSER(DVBSUB, dvbsub); - REGISTER_PARSER(DVDSUB, dvdsub); - REGISTER_PARSER(DVD_NAV, dvd_nav); - REGISTER_PARSER(FLAC, flac); - REGISTER_PARSER(G729, g729); - REGISTER_PARSER(GSM, gsm); - REGISTER_PARSER(H261, h261); - REGISTER_PARSER(H263, h263); - REGISTER_PARSER(H264, h264); - REGISTER_PARSER(HEVC, hevc); - REGISTER_PARSER(MJPEG, mjpeg); - REGISTER_PARSER(MLP, mlp); - REGISTER_PARSER(MPEG4VIDEO, mpeg4video); - REGISTER_PARSER(MPEGAUDIO, mpegaudio); - REGISTER_PARSER(MPEGVIDEO, mpegvideo); - REGISTER_PARSER(OPUS, opus); - REGISTER_PARSER(PNG, png); - REGISTER_PARSER(PNM, pnm); - REGISTER_PARSER(RV30, rv30); - REGISTER_PARSER(RV40, rv40); - REGISTER_PARSER(SIPR, sipr); - REGISTER_PARSER(TAK, tak); - REGISTER_PARSER(VC1, vc1); - REGISTER_PARSER(VORBIS, vorbis); - REGISTER_PARSER(VP3, vp3); - REGISTER_PARSER(VP8, vp8); - REGISTER_PARSER(VP9, vp9); - REGISTER_PARSER(XMA, xma); + return find_codec(id, av_codec_is_encoder); } -void avcodec_register_all(void) +AVCodec *avcodec_find_decoder(enum AVCodecID id) +{ + return find_codec(id, av_codec_is_decoder); +} + +static AVCodec *find_codec_by_name(const char *name, int (*x)(const AVCodec *)) { - static AVOnce control = AV_ONCE_INIT; + void *i = 0; + const AVCodec *p; - ff_thread_once(&control, register_all); + if (!name) + return NULL; + + while ((p = av_codec_iterate(&i))) { + if (!x(p)) + continue; + if (strcmp(name, p->name) == 0) + return (AVCodec*)p; + } + + return NULL; +} + +AVCodec *avcodec_find_encoder_by_name(const char *name) +{ + return find_codec_by_name(name, av_codec_is_encoder); +} + +AVCodec *avcodec_find_decoder_by_name(const char *name) +{ + return find_codec_by_name(name, av_codec_is_decoder); } diff --git a/libavcodec/alpha/asm.h b/libavcodec/alpha/asm.h index 827721e777fc1..6d850cecc640b 100644 --- a/libavcodec/alpha/asm.h +++ b/libavcodec/alpha/asm.h @@ -146,39 +146,6 @@ struct unaligned_long { uint64_t l; } __attribute__((packed)); #define unpkbw(a) ({ uint64_t __r; __asm__ (".arch ev6; unpkbw %r1,%0" : "=r" (__r) : "rJ" (a)); __r; }) #endif -#elif defined(__DECC) /* Digital/Compaq/hp "ccc" compiler */ - -#include -#define ldq(p) (*(const uint64_t *) (p)) -#define ldl(p) (*(const int32_t *) (p)) -#define stq(l, p) do { *(uint64_t *) (p) = (l); } while (0) -#define stl(l, p) do { *(int32_t *) (p) = (l); } while (0) -#define ldq_u(a) asm ("ldq_u %v0,0(%a0)", a) -#define uldq(a) (*(const __unaligned uint64_t *) (a)) -#define cmpbge(a, b) asm ("cmpbge %a0,%a1,%v0", a, b) -#define extql(a, b) asm ("extql %a0,%a1,%v0", a, b) -#define extwl(a, b) asm ("extwl %a0,%a1,%v0", a, b) -#define extqh(a, b) asm ("extqh %a0,%a1,%v0", a, b) -#define zap(a, b) asm ("zap %a0,%a1,%v0", a, b) -#define zapnot(a, b) asm ("zapnot %a0,%a1,%v0", a, b) -#define amask(a) asm ("amask %a0,%v0", a) -#define implver() asm ("implver %v0") -#define rpcc() asm ("rpcc %v0") -#define minub8(a, b) asm ("minub8 %a0,%a1,%v0", a, b) -#define minsb8(a, b) asm ("minsb8 %a0,%a1,%v0", a, b) -#define minuw4(a, b) asm ("minuw4 %a0,%a1,%v0", a, b) -#define minsw4(a, b) asm ("minsw4 %a0,%a1,%v0", a, b) -#define maxub8(a, b) asm ("maxub8 %a0,%a1,%v0", a, b) -#define maxsb8(a, b) asm ("maxsb8 %a0,%a1,%v0", a, b) -#define maxuw4(a, b) asm ("maxuw4 %a0,%a1,%v0", a, b) -#define maxsw4(a, b) asm ("maxsw4 %a0,%a1,%v0", a, b) -#define perr(a, b) asm ("perr %a0,%a1,%v0", a, b) -#define pklb(a) asm ("pklb %a0,%v0", a) -#define pkwb(a) asm ("pkwb %a0,%v0", a) -#define unpkbl(a) asm ("unpkbl %a0,%v0", a) -#define unpkbw(a) asm ("unpkbw %a0,%v0", a) -#define wh64(a) asm ("wh64 %a0", a) - #else #error "Unknown compiler!" #endif diff --git a/libavcodec/alpha/idctdsp_alpha.c b/libavcodec/alpha/idctdsp_alpha.c index 1923ebbc5fb16..bd43842535a94 100644 --- a/libavcodec/alpha/idctdsp_alpha.c +++ b/libavcodec/alpha/idctdsp_alpha.c @@ -118,8 +118,7 @@ av_cold void ff_idctdsp_init_alpha(IDCTDSPContext *c, AVCodecContext *avctx, add_pixels_clamped_axp_p = c->add_pixels_clamped; if (!high_bit_depth && !avctx->lowres && - (avctx->idct_algo == FF_IDCT_AUTO || - avctx->idct_algo == FF_IDCT_SIMPLEALPHA)) { + (avctx->idct_algo == FF_IDCT_AUTO)) { c->idct_put = ff_simple_idct_put_axp; c->idct_add = ff_simple_idct_add_axp; c->idct = ff_simple_idct_axp; diff --git a/libavcodec/alsdec.c b/libavcodec/alsdec.c index 13bd52f297ff1..ca8701e6d0d85 100644 --- a/libavcodec/alsdec.c +++ b/libavcodec/alsdec.c @@ -704,11 +704,6 @@ static int read_var_block_data(ALSDecContext *ctx, ALSBlockData *bd) } else { *bd->opt_order = sconf->max_order; } - if (*bd->opt_order > bd->block_length) { - *bd->opt_order = bd->block_length; - av_log(avctx, AV_LOG_ERROR, "Predictor order too large.\n"); - return AVERROR_INVALIDDATA; - } opt_order = *bd->opt_order; if (opt_order) { @@ -925,7 +920,7 @@ static int decode_var_block_data(ALSDecContext *ctx, ALSBlockData *bd) // reconstruct all samples from residuals if (bd->ra_block) { - for (smp = 0; smp < opt_order; smp++) { + for (smp = 0; smp < FFMIN(opt_order, block_length); smp++) { y = 1 << 19; for (sb = 0; sb < smp; sb++) diff --git a/libavcodec/amfenc.c b/libavcodec/amfenc.c new file mode 100644 index 0000000000000..384d8efc92cf8 --- /dev/null +++ b/libavcodec/amfenc.c @@ -0,0 +1,780 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/avassert.h" +#include "libavutil/imgutils.h" +#include "libavutil/hwcontext.h" +#if CONFIG_D3D11VA +#include "libavutil/hwcontext_d3d11va.h" +#endif +#if CONFIG_DXVA2 +#define COBJMACROS +#include "libavutil/hwcontext_dxva2.h" +#endif +#include "libavutil/mem.h" +#include "libavutil/pixdesc.h" +#include "libavutil/time.h" + +#include "amfenc.h" +#include "internal.h" + +#if CONFIG_D3D11VA +#include +#endif + +#ifdef _WIN32 +#include "compat/w32dlfcn.h" +#else +#include +#endif + +#define FFMPEG_AMF_WRITER_ID L"ffmpeg_amf" + +#define PTS_PROP L"PtsProp" + +const enum AVPixelFormat ff_amf_pix_fmts[] = { + AV_PIX_FMT_NV12, + AV_PIX_FMT_YUV420P, +#if CONFIG_D3D11VA + AV_PIX_FMT_D3D11, +#endif +#if CONFIG_DXVA2 + AV_PIX_FMT_DXVA2_VLD, +#endif + AV_PIX_FMT_NONE +}; + +typedef struct FormatMap { + enum AVPixelFormat av_format; + enum AMF_SURFACE_FORMAT amf_format; +} FormatMap; + +static const FormatMap format_map[] = +{ + { AV_PIX_FMT_NONE, AMF_SURFACE_UNKNOWN }, + { AV_PIX_FMT_NV12, AMF_SURFACE_NV12 }, + { AV_PIX_FMT_BGR0, AMF_SURFACE_BGRA }, + { AV_PIX_FMT_RGB0, AMF_SURFACE_RGBA }, + { AV_PIX_FMT_GRAY8, AMF_SURFACE_GRAY8 }, + { AV_PIX_FMT_YUV420P, AMF_SURFACE_YUV420P }, + { AV_PIX_FMT_YUYV422, AMF_SURFACE_YUY2 }, +}; + +static enum AMF_SURFACE_FORMAT amf_av_to_amf_format(enum AVPixelFormat fmt) +{ + int i; + for (i = 0; i < amf_countof(format_map); i++) { + if (format_map[i].av_format == fmt) { + return format_map[i].amf_format; + } + } + return AMF_SURFACE_UNKNOWN; +} + +static void AMF_CDECL_CALL AMFTraceWriter_Write(AMFTraceWriter *pThis, + const wchar_t *scope, const wchar_t *message) +{ + AmfTraceWriter *tracer = (AmfTraceWriter*)pThis; + av_log(tracer->avctx, AV_LOG_DEBUG, "%ls: %ls", scope, message); // \n is provided from AMF +} + +static void AMF_CDECL_CALL AMFTraceWriter_Flush(AMFTraceWriter *pThis) +{ +} + +static AMFTraceWriterVtbl tracer_vtbl = +{ + .Write = AMFTraceWriter_Write, + .Flush = AMFTraceWriter_Flush, +}; + +static int amf_load_library(AVCodecContext *avctx) +{ + AmfContext *ctx = avctx->priv_data; + AMFInit_Fn init_fun; + AMFQueryVersion_Fn version_fun; + AMF_RESULT res; + + ctx->delayed_frame = av_frame_alloc(); + if (!ctx->delayed_frame) { + return AVERROR(ENOMEM); + } + // hardcoded to current HW queue size - will realloc in timestamp_queue_enqueue() if too small + ctx->timestamp_list = av_fifo_alloc((avctx->max_b_frames + 16) * sizeof(int64_t)); + if (!ctx->timestamp_list) { + return AVERROR(ENOMEM); + } + ctx->dts_delay = 0; + + + ctx->library = dlopen(AMF_DLL_NAMEA, RTLD_NOW | RTLD_LOCAL); + AMF_RETURN_IF_FALSE(ctx, ctx->library != NULL, + AVERROR_UNKNOWN, "DLL %s failed to open\n", AMF_DLL_NAMEA); + + init_fun = (AMFInit_Fn)dlsym(ctx->library, AMF_INIT_FUNCTION_NAME); + AMF_RETURN_IF_FALSE(ctx, init_fun != NULL, AVERROR_UNKNOWN, "DLL %s failed to find function %s\n", AMF_DLL_NAMEA, AMF_INIT_FUNCTION_NAME); + + version_fun = (AMFQueryVersion_Fn)dlsym(ctx->library, AMF_QUERY_VERSION_FUNCTION_NAME); + AMF_RETURN_IF_FALSE(ctx, version_fun != NULL, AVERROR_UNKNOWN, "DLL %s failed to find function %s\n", AMF_DLL_NAMEA, AMF_QUERY_VERSION_FUNCTION_NAME); + + res = version_fun(&ctx->version); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_QUERY_VERSION_FUNCTION_NAME, res); + res = init_fun(AMF_FULL_VERSION, &ctx->factory); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "%s failed with error %d\n", AMF_INIT_FUNCTION_NAME, res); + res = ctx->factory->pVtbl->GetTrace(ctx->factory, &ctx->trace); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetTrace() failed with error %d\n", res); + res = ctx->factory->pVtbl->GetDebug(ctx->factory, &ctx->debug); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetDebug() failed with error %d\n", res); + return 0; +} + +#if CONFIG_D3D11VA +static int amf_init_from_d3d11_device(AVCodecContext *avctx, AVD3D11VADeviceContext *hwctx) +{ + AmfContext *ctx = avctx->priv_data; + AMF_RESULT res; + + res = ctx->context->pVtbl->InitDX11(ctx->context, hwctx->device, AMF_DX11_1); + if (res != AMF_OK) { + if (res == AMF_NOT_SUPPORTED) + av_log(avctx, AV_LOG_ERROR, "AMF via D3D11 is not supported on the given device.\n"); + else + av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on the given D3D11 device: %d.\n", res); + return AVERROR(ENODEV); + } + + return 0; +} +#endif + +#if CONFIG_DXVA2 +static int amf_init_from_dxva2_device(AVCodecContext *avctx, AVDXVA2DeviceContext *hwctx) +{ + AmfContext *ctx = avctx->priv_data; + HANDLE device_handle; + IDirect3DDevice9 *device; + HRESULT hr; + AMF_RESULT res; + int ret; + + hr = IDirect3DDeviceManager9_OpenDeviceHandle(hwctx->devmgr, &device_handle); + if (FAILED(hr)) { + av_log(avctx, AV_LOG_ERROR, "Failed to open device handle for Direct3D9 device: %lx.\n", (unsigned long)hr); + return AVERROR_EXTERNAL; + } + + hr = IDirect3DDeviceManager9_LockDevice(hwctx->devmgr, device_handle, &device, FALSE); + if (SUCCEEDED(hr)) { + IDirect3DDeviceManager9_UnlockDevice(hwctx->devmgr, device_handle, FALSE); + ret = 0; + } else { + av_log(avctx, AV_LOG_ERROR, "Failed to lock device handle for Direct3D9 device: %lx.\n", (unsigned long)hr); + ret = AVERROR_EXTERNAL; + } + + IDirect3DDeviceManager9_CloseDeviceHandle(hwctx->devmgr, device_handle); + + if (ret < 0) + return ret; + + res = ctx->context->pVtbl->InitDX9(ctx->context, device); + + IDirect3DDevice9_Release(device); + + if (res != AMF_OK) { + if (res == AMF_NOT_SUPPORTED) + av_log(avctx, AV_LOG_ERROR, "AMF via D3D9 is not supported on the given device.\n"); + else + av_log(avctx, AV_LOG_ERROR, "AMF failed to initialise on given D3D9 device: %d.\n", res); + return AVERROR(ENODEV); + } + + return 0; +} +#endif + +static int amf_init_context(AVCodecContext *avctx) +{ + AmfContext *ctx = avctx->priv_data; + AMF_RESULT res; + av_unused int ret; + + ctx->hwsurfaces_in_queue = 0; + ctx->hwsurfaces_in_queue_max = 16; + + // configure AMF logger + // the return of these functions indicates old state and do not affect behaviour + ctx->trace->pVtbl->EnableWriter(ctx->trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, ctx->log_to_dbg != 0 ); + if (ctx->log_to_dbg) + ctx->trace->pVtbl->SetWriterLevel(ctx->trace, AMF_TRACE_WRITER_DEBUG_OUTPUT, AMF_TRACE_TRACE); + ctx->trace->pVtbl->EnableWriter(ctx->trace, AMF_TRACE_WRITER_CONSOLE, 0); + ctx->trace->pVtbl->SetGlobalLevel(ctx->trace, AMF_TRACE_TRACE); + + // connect AMF logger to av_log + ctx->tracer.vtbl = &tracer_vtbl; + ctx->tracer.avctx = avctx; + ctx->trace->pVtbl->RegisterWriter(ctx->trace, FFMPEG_AMF_WRITER_ID,(AMFTraceWriter*)&ctx->tracer, 1); + ctx->trace->pVtbl->SetWriterLevel(ctx->trace, FFMPEG_AMF_WRITER_ID, AMF_TRACE_TRACE); + + res = ctx->factory->pVtbl->CreateContext(ctx->factory, &ctx->context); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "CreateContext() failed with error %d\n", res); + + // If a device was passed to the encoder, try to initialise from that. + if (avctx->hw_frames_ctx) { + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + + if (amf_av_to_amf_format(frames_ctx->sw_format) == AMF_SURFACE_UNKNOWN) { + av_log(avctx, AV_LOG_ERROR, "Format of input frames context (%s) is not supported by AMF.\n", + av_get_pix_fmt_name(frames_ctx->sw_format)); + return AVERROR(EINVAL); + } + + switch (frames_ctx->device_ctx->type) { +#if CONFIG_D3D11VA + case AV_HWDEVICE_TYPE_D3D11VA: + ret = amf_init_from_d3d11_device(avctx, frames_ctx->device_ctx->hwctx); + if (ret < 0) + return ret; + break; +#endif +#if CONFIG_DXVA2 + case AV_HWDEVICE_TYPE_DXVA2: + ret = amf_init_from_dxva2_device(avctx, frames_ctx->device_ctx->hwctx); + if (ret < 0) + return ret; + break; +#endif + default: + av_log(avctx, AV_LOG_ERROR, "AMF initialisation from a %s frames context is not supported.\n", + av_hwdevice_get_type_name(frames_ctx->device_ctx->type)); + return AVERROR(ENOSYS); + } + + ctx->hw_frames_ctx = av_buffer_ref(avctx->hw_frames_ctx); + if (!ctx->hw_frames_ctx) + return AVERROR(ENOMEM); + + if (frames_ctx->initial_pool_size > 0) + ctx->hwsurfaces_in_queue_max = frames_ctx->initial_pool_size - 1; + + } else if (avctx->hw_device_ctx) { + AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)avctx->hw_device_ctx->data; + + switch (device_ctx->type) { +#if CONFIG_D3D11VA + case AV_HWDEVICE_TYPE_D3D11VA: + ret = amf_init_from_d3d11_device(avctx, device_ctx->hwctx); + if (ret < 0) + return ret; + break; +#endif +#if CONFIG_DXVA2 + case AV_HWDEVICE_TYPE_DXVA2: + ret = amf_init_from_dxva2_device(avctx, device_ctx->hwctx); + if (ret < 0) + return ret; + break; +#endif + default: + av_log(avctx, AV_LOG_ERROR, "AMF initialisation from a %s device is not supported.\n", + av_hwdevice_get_type_name(device_ctx->type)); + return AVERROR(ENOSYS); + } + + ctx->hw_device_ctx = av_buffer_ref(avctx->hw_device_ctx); + if (!ctx->hw_device_ctx) + return AVERROR(ENOMEM); + + } else { + res = ctx->context->pVtbl->InitDX11(ctx->context, NULL, AMF_DX11_1); + if (res == AMF_OK) { + av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D11.\n"); + } else { + res = ctx->context->pVtbl->InitDX9(ctx->context, NULL); + if (res == AMF_OK) { + av_log(avctx, AV_LOG_VERBOSE, "AMF initialisation succeeded via D3D9.\n"); + } else { + av_log(avctx, AV_LOG_ERROR, "AMF initialisation failed via D3D9: error %d.\n", res); + return AVERROR(ENOSYS); + } + } + } + return 0; +} + +static int amf_init_encoder(AVCodecContext *avctx) +{ + AmfContext *ctx = avctx->priv_data; + const wchar_t *codec_id = NULL; + AMF_RESULT res; + enum AVPixelFormat pix_fmt; + + switch (avctx->codec->id) { + case AV_CODEC_ID_H264: + codec_id = AMFVideoEncoderVCE_AVC; + break; + case AV_CODEC_ID_HEVC: + codec_id = AMFVideoEncoder_HEVC; + break; + default: + break; + } + AMF_RETURN_IF_FALSE(ctx, codec_id != NULL, AVERROR(EINVAL), "Codec %d is not supported\n", avctx->codec->id); + + if (ctx->hw_frames_ctx) + pix_fmt = ((AVHWFramesContext*)ctx->hw_frames_ctx->data)->sw_format; + else + pix_fmt = avctx->pix_fmt; + + ctx->format = amf_av_to_amf_format(pix_fmt); + AMF_RETURN_IF_FALSE(ctx, ctx->format != AMF_SURFACE_UNKNOWN, AVERROR(EINVAL), + "Format %s is not supported\n", av_get_pix_fmt_name(pix_fmt)); + + res = ctx->factory->pVtbl->CreateComponent(ctx->factory, ctx->context, codec_id, &ctx->encoder); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_ENCODER_NOT_FOUND, "CreateComponent(%ls) failed with error %d\n", codec_id, res); + + return 0; +} + +int av_cold ff_amf_encode_close(AVCodecContext *avctx) +{ + AmfContext *ctx = avctx->priv_data; + + if (ctx->delayed_surface) { + ctx->delayed_surface->pVtbl->Release(ctx->delayed_surface); + ctx->delayed_surface = NULL; + } + + if (ctx->encoder) { + ctx->encoder->pVtbl->Terminate(ctx->encoder); + ctx->encoder->pVtbl->Release(ctx->encoder); + ctx->encoder = NULL; + } + + if (ctx->context) { + ctx->context->pVtbl->Terminate(ctx->context); + ctx->context->pVtbl->Release(ctx->context); + ctx->context = NULL; + } + av_buffer_unref(&ctx->hw_device_ctx); + av_buffer_unref(&ctx->hw_frames_ctx); + + if (ctx->trace) { + ctx->trace->pVtbl->UnregisterWriter(ctx->trace, FFMPEG_AMF_WRITER_ID); + } + if (ctx->library) { + dlclose(ctx->library); + ctx->library = NULL; + } + ctx->trace = NULL; + ctx->debug = NULL; + ctx->factory = NULL; + ctx->version = 0; + ctx->delayed_drain = 0; + av_frame_free(&ctx->delayed_frame); + av_fifo_freep(&ctx->timestamp_list); + + return 0; +} + +static int amf_copy_surface(AVCodecContext *avctx, const AVFrame *frame, + AMFSurface* surface) +{ + AMFPlane *plane; + uint8_t *dst_data[4]; + int dst_linesize[4]; + int planes; + int i; + + planes = surface->pVtbl->GetPlanesCount(surface); + av_assert0(planes < FF_ARRAY_ELEMS(dst_data)); + + for (i = 0; i < planes; i++) { + plane = surface->pVtbl->GetPlaneAt(surface, i); + dst_data[i] = plane->pVtbl->GetNative(plane); + dst_linesize[i] = plane->pVtbl->GetHPitch(plane); + } + av_image_copy(dst_data, dst_linesize, + (const uint8_t**)frame->data, frame->linesize, frame->format, + avctx->width, avctx->height); + + return 0; +} + +static inline int timestamp_queue_enqueue(AVCodecContext *avctx, int64_t timestamp) +{ + AmfContext *ctx = avctx->priv_data; + if (av_fifo_space(ctx->timestamp_list) < sizeof(timestamp)) { + if (av_fifo_grow(ctx->timestamp_list, sizeof(timestamp)) < 0) { + return AVERROR(ENOMEM); + } + } + av_fifo_generic_write(ctx->timestamp_list, ×tamp, sizeof(timestamp), NULL); + return 0; +} + +static int amf_copy_buffer(AVCodecContext *avctx, AVPacket *pkt, AMFBuffer *buffer) +{ + AmfContext *ctx = avctx->priv_data; + int ret; + AMFVariantStruct var = {0}; + int64_t timestamp = AV_NOPTS_VALUE; + int64_t size = buffer->pVtbl->GetSize(buffer); + + if ((ret = ff_alloc_packet2(avctx, pkt, size, 0)) < 0) { + return ret; + } + memcpy(pkt->data, buffer->pVtbl->GetNative(buffer), size); + + switch (avctx->codec->id) { + case AV_CODEC_ID_H264: + buffer->pVtbl->GetProperty(buffer, AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE, &var); + if(var.int64Value == AMF_VIDEO_ENCODER_OUTPUT_DATA_TYPE_IDR) { + pkt->flags = AV_PKT_FLAG_KEY; + } + break; + case AV_CODEC_ID_HEVC: + buffer->pVtbl->GetProperty(buffer, AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE, &var); + if (var.int64Value == AMF_VIDEO_ENCODER_HEVC_OUTPUT_DATA_TYPE_IDR) { + pkt->flags = AV_PKT_FLAG_KEY; + } + break; + default: + break; + } + + buffer->pVtbl->GetProperty(buffer, PTS_PROP, &var); + + pkt->pts = var.int64Value; // original pts + + + AMF_RETURN_IF_FALSE(ctx, av_fifo_size(ctx->timestamp_list) > 0, AVERROR_UNKNOWN, "timestamp_list is empty\n"); + + av_fifo_generic_read(ctx->timestamp_list, ×tamp, sizeof(timestamp), NULL); + + // calc dts shift if max_b_frames > 0 + if (avctx->max_b_frames > 0 && ctx->dts_delay == 0) { + int64_t timestamp_last = AV_NOPTS_VALUE; + AMF_RETURN_IF_FALSE(ctx, av_fifo_size(ctx->timestamp_list) > 0, AVERROR_UNKNOWN, + "timestamp_list is empty while max_b_frames = %d\n", avctx->max_b_frames); + av_fifo_generic_peek_at( + ctx->timestamp_list, + ×tamp_last, + (av_fifo_size(ctx->timestamp_list) / sizeof(timestamp) - 1) * sizeof(timestamp_last), + sizeof(timestamp_last), + NULL); + if (timestamp < 0 || timestamp_last < AV_NOPTS_VALUE) { + return AVERROR(ERANGE); + } + ctx->dts_delay = timestamp_last - timestamp; + } + pkt->dts = timestamp - ctx->dts_delay; + return 0; +} + +// amfenc API implementation +int ff_amf_encode_init(AVCodecContext *avctx) +{ + int ret; + + if ((ret = amf_load_library(avctx)) == 0) { + if ((ret = amf_init_context(avctx)) == 0) { + if ((ret = amf_init_encoder(avctx)) == 0) { + return 0; + } + } + } + ff_amf_encode_close(avctx); + return ret; +} + +static AMF_RESULT amf_set_property_buffer(AMFSurface *object, const wchar_t *name, AMFBuffer *val) +{ + AMF_RESULT res; + AMFVariantStruct var; + res = AMFVariantInit(&var); + if (res == AMF_OK) { + AMFGuid guid_AMFInterface = IID_AMFInterface(); + AMFInterface *amf_interface; + res = val->pVtbl->QueryInterface(val, &guid_AMFInterface, (void**)&amf_interface); + + if (res == AMF_OK) { + res = AMFVariantAssignInterface(&var, amf_interface); + amf_interface->pVtbl->Release(amf_interface); + } + if (res == AMF_OK) { + res = object->pVtbl->SetProperty(object, name, var); + } + AMFVariantClear(&var); + } + return res; +} + +static AMF_RESULT amf_get_property_buffer(AMFData *object, const wchar_t *name, AMFBuffer **val) +{ + AMF_RESULT res; + AMFVariantStruct var; + res = AMFVariantInit(&var); + if (res == AMF_OK) { + res = object->pVtbl->GetProperty(object, name, &var); + if (res == AMF_OK) { + if (var.type == AMF_VARIANT_INTERFACE) { + AMFGuid guid_AMFBuffer = IID_AMFBuffer(); + AMFInterface *amf_interface = AMFVariantInterface(&var); + res = amf_interface->pVtbl->QueryInterface(amf_interface, &guid_AMFBuffer, (void**)val); + } else { + res = AMF_INVALID_DATA_TYPE; + } + } + AMFVariantClear(&var); + } + return res; +} + +static AMFBuffer *amf_create_buffer_with_frame_ref(const AVFrame *frame, AMFContext *context) +{ + AVFrame *frame_ref; + AMFBuffer *frame_ref_storage_buffer = NULL; + AMF_RESULT res; + + res = context->pVtbl->AllocBuffer(context, AMF_MEMORY_HOST, sizeof(frame_ref), &frame_ref_storage_buffer); + if (res == AMF_OK) { + frame_ref = av_frame_clone(frame); + if (frame_ref) { + memcpy(frame_ref_storage_buffer->pVtbl->GetNative(frame_ref_storage_buffer), &frame_ref, sizeof(frame_ref)); + } else { + frame_ref_storage_buffer->pVtbl->Release(frame_ref_storage_buffer); + frame_ref_storage_buffer = NULL; + } + } + return frame_ref_storage_buffer; +} + +static void amf_release_buffer_with_frame_ref(AMFBuffer *frame_ref_storage_buffer) +{ + AVFrame *frame_ref; + memcpy(&frame_ref, frame_ref_storage_buffer->pVtbl->GetNative(frame_ref_storage_buffer), sizeof(frame_ref)); + av_frame_free(&frame_ref); + frame_ref_storage_buffer->pVtbl->Release(frame_ref_storage_buffer); +} + +int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame) +{ + AmfContext *ctx = avctx->priv_data; + AMFSurface *surface; + AMF_RESULT res; + int ret; + + if (!ctx->encoder) + return AVERROR(EINVAL); + + if (!frame) { // submit drain + if (!ctx->eof) { // submit drain one time only + if (ctx->delayed_surface != NULL) { + ctx->delayed_drain = 1; // input queue is full: resubmit Drain() in ff_amf_receive_packet + } else if(!ctx->delayed_drain) { + res = ctx->encoder->pVtbl->Drain(ctx->encoder); + if (res == AMF_INPUT_FULL) { + ctx->delayed_drain = 1; // input queue is full: resubmit Drain() in ff_amf_receive_packet + } else { + if (res == AMF_OK) { + ctx->eof = 1; // drain started + } + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Drain() failed with error %d\n", res); + } + } + } else{ + return AVERROR_EOF; + } + } else { // submit frame + int hw_surface = 0; + + if (ctx->delayed_surface != NULL) { + return AVERROR(EAGAIN); // should not happen when called from ffmpeg, other clients may resubmit + } + // prepare surface from frame + switch (frame->format) { +#if CONFIG_D3D11VA + case AV_PIX_FMT_D3D11: + { + static const GUID AMFTextureArrayIndexGUID = { 0x28115527, 0xe7c3, 0x4b66, { 0x99, 0xd3, 0x4f, 0x2a, 0xe6, 0xb4, 0x7f, 0xaf } }; + ID3D11Texture2D *texture = (ID3D11Texture2D*)frame->data[0]; // actual texture + int index = (intptr_t)frame->data[1]; // index is a slice in texture array is - set to tell AMF which slice to use + + av_assert0(frame->hw_frames_ctx && ctx->hw_frames_ctx && + frame->hw_frames_ctx->data == ctx->hw_frames_ctx->data); + + texture->lpVtbl->SetPrivateData(texture, &AMFTextureArrayIndexGUID, sizeof(index), &index); + + res = ctx->context->pVtbl->CreateSurfaceFromDX11Native(ctx->context, texture, &surface, NULL); // wrap to AMF surface + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "CreateSurfaceFromDX11Native() failed with error %d\n", res); + + hw_surface = 1; + } + break; +#endif +#if CONFIG_DXVA2 + case AV_PIX_FMT_DXVA2_VLD: + { + IDirect3DSurface9 *texture = (IDirect3DSurface9 *)frame->data[3]; // actual texture + + res = ctx->context->pVtbl->CreateSurfaceFromDX9Native(ctx->context, texture, &surface, NULL); // wrap to AMF surface + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "CreateSurfaceFromDX9Native() failed with error %d\n", res); + + hw_surface = 1; + } + break; +#endif + default: + { + res = ctx->context->pVtbl->AllocSurface(ctx->context, AMF_MEMORY_HOST, ctx->format, avctx->width, avctx->height, &surface); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR(ENOMEM), "AllocSurface() failed with error %d\n", res); + amf_copy_surface(avctx, frame, surface); + } + break; + } + + if (hw_surface) { + AMFBuffer *frame_ref_storage_buffer; + + // input HW surfaces can be vertically aligned by 16; tell AMF the real size + surface->pVtbl->SetCrop(surface, 0, 0, frame->width, frame->height); + + frame_ref_storage_buffer = amf_create_buffer_with_frame_ref(frame, ctx->context); + AMF_RETURN_IF_FALSE(ctx, frame_ref_storage_buffer != NULL, AVERROR(ENOMEM), "create_buffer_with_frame_ref() returned NULL\n"); + + res = amf_set_property_buffer(surface, L"av_frame_ref", frame_ref_storage_buffer); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SetProperty failed for \"av_frame_ref\" with error %d\n", res); + ctx->hwsurfaces_in_queue++; + frame_ref_storage_buffer->pVtbl->Release(frame_ref_storage_buffer); + } + + surface->pVtbl->SetPts(surface, frame->pts); + AMF_ASSIGN_PROPERTY_INT64(res, surface, PTS_PROP, frame->pts); + + switch (avctx->codec->id) { + case AV_CODEC_ID_H264: + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_INSERT_AUD, !!ctx->aud); + break; + case AV_CODEC_ID_HEVC: + AMF_ASSIGN_PROPERTY_INT64(res, surface, AMF_VIDEO_ENCODER_HEVC_INSERT_AUD, !!ctx->aud); + break; + default: + break; + } + + + // submit surface + res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)surface); + if (res == AMF_INPUT_FULL) { // handle full queue + //store surface for later submission + ctx->delayed_surface = surface; + if (surface->pVtbl->GetMemoryType(surface) == AMF_MEMORY_DX11) { + av_frame_ref(ctx->delayed_frame, frame); + } + } else { + surface->pVtbl->Release(surface); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "SubmitInput() failed with error %d\n", res); + + if ((ret = timestamp_queue_enqueue(avctx, frame->pts)) < 0) { + return ret; + } + + } + } + return 0; +} +int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) +{ + int ret; + AMF_RESULT res; + AMF_RESULT res_query; + AmfContext *ctx = avctx->priv_data; + AMFData *data = NULL; + int block_and_wait; + + if (!ctx->encoder) + return AVERROR(EINVAL); + + do { + block_and_wait = 0; + // poll data + res_query = ctx->encoder->pVtbl->QueryOutput(ctx->encoder, &data); + if (data) { + // copy data to packet + AMFBuffer* buffer; + AMFGuid guid = IID_AMFBuffer(); + data->pVtbl->QueryInterface(data, &guid, (void**)&buffer); // query for buffer interface + ret = amf_copy_buffer(avctx, avpkt, buffer); + + buffer->pVtbl->Release(buffer); + + if (data->pVtbl->HasProperty(data, L"av_frame_ref")) { + AMFBuffer *frame_ref_storage_buffer; + res = amf_get_property_buffer(data, L"av_frame_ref", &frame_ref_storage_buffer); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "GetProperty failed for \"av_frame_ref\" with error %d\n", res); + amf_release_buffer_with_frame_ref(frame_ref_storage_buffer); + ctx->hwsurfaces_in_queue--; + } + + data->pVtbl->Release(data); + + AMF_RETURN_IF_FALSE(ctx, ret >= 0, ret, "amf_copy_buffer() failed with error %d\n", ret); + + if (ctx->delayed_surface != NULL) { // try to resubmit frame + res = ctx->encoder->pVtbl->SubmitInput(ctx->encoder, (AMFData*)ctx->delayed_surface); + if (res != AMF_INPUT_FULL) { + int64_t pts = ctx->delayed_surface->pVtbl->GetPts(ctx->delayed_surface); + ctx->delayed_surface->pVtbl->Release(ctx->delayed_surface); + ctx->delayed_surface = NULL; + av_frame_unref(ctx->delayed_frame); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Repeated SubmitInput() failed with error %d\n", res); + + if ((ret = timestamp_queue_enqueue(avctx, pts)) < 0) { + return ret; + } + } else { + av_log(avctx, AV_LOG_WARNING, "Data acquired but delayed frame submission got AMF_INPUT_FULL- should not happen\n"); + } + } else if (ctx->delayed_drain) { // try to resubmit drain + res = ctx->encoder->pVtbl->Drain(ctx->encoder); + if (res != AMF_INPUT_FULL) { + ctx->delayed_drain = 0; + ctx->eof = 1; // drain started + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_UNKNOWN, "Repeated Drain() failed with error %d\n", res); + } else { + av_log(avctx, AV_LOG_WARNING, "Data acquired but delayed drain submission got AMF_INPUT_FULL- should not happen\n"); + } + } + } else if (ctx->delayed_surface != NULL || ctx->delayed_drain || (ctx->eof && res_query != AMF_EOF) || (ctx->hwsurfaces_in_queue >= ctx->hwsurfaces_in_queue_max)) { + block_and_wait = 1; + av_usleep(1000); // wait and poll again + } + } while (block_and_wait); + + if (res_query == AMF_EOF) { + ret = AVERROR_EOF; + } else if (data == NULL) { + ret = AVERROR(EAGAIN); + } else { + ret = 0; + } + return ret; +} diff --git a/libavcodec/amfenc.h b/libavcodec/amfenc.h new file mode 100644 index 0000000000000..b1361842bd655 --- /dev/null +++ b/libavcodec/amfenc.h @@ -0,0 +1,150 @@ +/* +* This file is part of FFmpeg. +* +* FFmpeg is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* FFmpeg is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with FFmpeg; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef AVCODEC_AMFENC_H +#define AVCODEC_AMFENC_H + +#include + +#include +#include + +#include "libavutil/fifo.h" + +#include "avcodec.h" + + +/** +* AMF trace writer callback class +* Used to capture all AMF logging +*/ + +typedef struct AmfTraceWriter { + AMFTraceWriterVtbl *vtbl; + AVCodecContext *avctx; +} AmfTraceWriter; + +/** +* AMF encoder context +*/ + +typedef struct AmfContext { + AVClass *avclass; + // access to AMF runtime + amf_handle library; ///< handle to DLL library + AMFFactory *factory; ///< pointer to AMF factory + AMFDebug *debug; ///< pointer to AMF debug interface + AMFTrace *trace; ///< pointer to AMF trace interface + + amf_uint64 version; ///< version of AMF runtime + AmfTraceWriter tracer; ///< AMF writer registered with AMF + AMFContext *context; ///< AMF context + //encoder + AMFComponent *encoder; ///< AMF encoder object + amf_bool eof; ///< flag indicating EOF happened + AMF_SURFACE_FORMAT format; ///< AMF surface format + + AVBufferRef *hw_device_ctx; ///< pointer to HW accelerator (decoder) + AVBufferRef *hw_frames_ctx; ///< pointer to HW accelerator (frame allocator) + + int hwsurfaces_in_queue; + int hwsurfaces_in_queue_max; + + // helpers to handle async calls + int delayed_drain; + AMFSurface *delayed_surface; + AVFrame *delayed_frame; + + // shift dts back by max_b_frames in timing + AVFifoBuffer *timestamp_list; + int64_t dts_delay; + + // common encoder option options + + int log_to_dbg; + + // Static options, have to be set before Init() call + int usage; + int profile; + int level; + int preanalysis; + int quality; + int b_frame_delta_qp; + int ref_b_frame_delta_qp; + + // Dynamic options, can be set after Init() call + + int rate_control_mode; + int enforce_hrd; + int filler_data; + int enable_vbaq; + int skip_frame; + int qp_i; + int qp_p; + int qp_b; + int max_au_size; + int header_spacing; + int b_frame_ref; + int intra_refresh_mb; + int coding_mode; + int me_half_pel; + int me_quarter_pel; + int aud; + + // HEVC - specific options + + int gops_per_idr; + int header_insertion_mode; + int min_qp_i; + int max_qp_i; + int min_qp_p; + int max_qp_p; + int tier; +} AmfContext; + +/** +* Common encoder initization function +*/ +int ff_amf_encode_init(AVCodecContext *avctx); +/** +* Common encoder termination function +*/ +int ff_amf_encode_close(AVCodecContext *avctx); + +/** +* Ecoding one frame - common function for all AMF encoders +*/ + +int ff_amf_send_frame(AVCodecContext *avctx, const AVFrame *frame); +int ff_amf_receive_packet(AVCodecContext *avctx, AVPacket *avpkt); + +/** +* Supported formats +*/ +extern const enum AVPixelFormat ff_amf_pix_fmts[]; + +/** +* Error handling helper +*/ +#define AMF_RETURN_IF_FALSE(avctx, exp, ret_value, /*message,*/ ...) \ + if (!(exp)) { \ + av_log(avctx, AV_LOG_ERROR, __VA_ARGS__); \ + return ret_value; \ + } + +#endif //AVCODEC_AMFENC_H diff --git a/libavcodec/amfenc_h264.c b/libavcodec/amfenc_h264.c new file mode 100644 index 0000000000000..2c082e93bd9b4 --- /dev/null +++ b/libavcodec/amfenc_h264.c @@ -0,0 +1,395 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include "libavutil/internal.h" +#include "libavutil/opt.h" +#include "amfenc.h" +#include "internal.h" + +#define OFFSET(x) offsetof(AmfContext, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM + +static const AVOption options[] = { + // Static + /// Usage + { "usage", "Encoder Usage", OFFSET(usage), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_USAGE_TRANSCONDING }, AMF_VIDEO_ENCODER_USAGE_TRANSCONDING, AMF_VIDEO_ENCODER_USAGE_WEBCAM, VE, "usage" }, + { "transcoding", "Generic Transcoding", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_USAGE_TRANSCONDING }, 0, 0, VE, "usage" }, + { "ultralowlatency","", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_USAGE_ULTRA_LOW_LATENCY }, 0, 0, VE, "usage" }, + { "lowlatency", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_USAGE_LOW_LATENCY }, 0, 0, VE, "usage" }, + { "webcam", "Webcam", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_USAGE_WEBCAM }, 0, 0, VE, "usage" }, + + /// Profile, + { "profile", "Profile", OFFSET(profile),AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_PROFILE_MAIN }, AMF_VIDEO_ENCODER_PROFILE_BASELINE, AMF_VIDEO_ENCODER_PROFILE_CONSTRAINED_HIGH, VE, "profile" }, + { "main", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_PROFILE_MAIN }, 0, 0, VE, "profile" }, + { "high", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_PROFILE_HIGH }, 0, 0, VE, "profile" }, + { "constrained_baseline", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_PROFILE_CONSTRAINED_BASELINE }, 0, 0, VE, "profile" }, + { "constrained_high", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_PROFILE_CONSTRAINED_HIGH }, 0, 0, VE, "profile" }, + + /// Profile Level + { "level", "Profile Level", OFFSET(level), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 62, VE, "level" }, + { "auto", "", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, VE, "level" }, + { "1.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 10 }, 0, 0, VE, "level" }, + { "1.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 11 }, 0, 0, VE, "level" }, + { "1.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 12 }, 0, 0, VE, "level" }, + { "1.3", "", 0, AV_OPT_TYPE_CONST, { .i64 = 13 }, 0, 0, VE, "level" }, + { "2.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 20 }, 0, 0, VE, "level" }, + { "2.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 21 }, 0, 0, VE, "level" }, + { "2.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 22 }, 0, 0, VE, "level" }, + { "3.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 30 }, 0, 0, VE, "level" }, + { "3.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 31 }, 0, 0, VE, "level" }, + { "3.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 32 }, 0, 0, VE, "level" }, + { "4.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 40 }, 0, 0, VE, "level" }, + { "4.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 41 }, 0, 0, VE, "level" }, + { "4.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 42 }, 0, 0, VE, "level" }, + { "5.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 50 }, 0, 0, VE, "level" }, + { "5.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 51 }, 0, 0, VE, "level" }, + { "5.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 52 }, 0, 0, VE, "level" }, + { "6.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = 60 }, 0, 0, VE, "level" }, + { "6.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = 61 }, 0, 0, VE, "level" }, + { "6.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = 62 }, 0, 0, VE, "level" }, + + + /// Quality Preset + { "quality", "Quality Preference", OFFSET(quality), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_QUALITY_PRESET_SPEED }, AMF_VIDEO_ENCODER_QUALITY_PRESET_BALANCED, AMF_VIDEO_ENCODER_QUALITY_PRESET_QUALITY, VE, "quality" }, + { "speed", "Prefer Speed", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_QUALITY_PRESET_SPEED }, 0, 0, VE, "quality" }, + { "balanced", "Balanced", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_QUALITY_PRESET_BALANCED }, 0, 0, VE, "quality" }, + { "quality", "Prefer Quality", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_QUALITY_PRESET_QUALITY }, 0, 0, VE, "quality" }, + + // Dynamic + /// Rate Control Method + { "rc", "Rate Control Method", OFFSET(rate_control_mode), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_UNKNOWN }, AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_UNKNOWN, AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR, VE, "rc" }, + { "cqp", "Constant Quantization Parameter", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP }, 0, 0, VE, "rc" }, + { "cbr", "Constant Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR }, 0, 0, VE, "rc" }, + { "vbr_peak", "Peak Contrained Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR }, 0, 0, VE, "rc" }, + { "vbr_latency", "Latency Constrained Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR }, 0, 0, VE, "rc" }, + + /// Enforce HRD, Filler Data, VBAQ, Frame Skipping + { "enforce_hrd", "Enforce HRD", OFFSET(enforce_hrd), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "filler_data", "Filler Data Enable", OFFSET(filler_data), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "vbaq", "Enable VBAQ", OFFSET(enable_vbaq), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "frame_skipping", "Rate Control Based Frame Skip", OFFSET(skip_frame), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + + /// QP Values + { "qp_i", "Quantization Parameter for I-Frame", OFFSET(qp_i), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, + { "qp_p", "Quantization Parameter for P-Frame", OFFSET(qp_p), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, + { "qp_b", "Quantization Parameter for B-Frame", OFFSET(qp_b), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, + + /// Pre-Pass, Pre-Analysis, Two-Pass + { "preanalysis", "Pre-Analysis Mode", OFFSET(preanalysis), AV_OPT_TYPE_BOOL,{ .i64 = 0 }, 0, 1, VE, NULL }, + + /// Maximum Access Unit Size + { "max_au_size", "Maximum Access Unit Size for rate control (in bits)", OFFSET(max_au_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, + + /// Header Insertion Spacing + { "header_spacing", "Header Insertion Spacing", OFFSET(header_spacing), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1000, VE }, + + /// B-Frames + // BPicturesPattern=bf + { "bf_delta_qp", "B-Picture Delta QP", OFFSET(b_frame_delta_qp), AV_OPT_TYPE_INT, { .i64 = 4 }, -10, 10, VE }, + { "bf_ref", "Enable Reference to B-Frames", OFFSET(b_frame_ref), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, + { "bf_ref_delta_qp","Reference B-Picture Delta QP", OFFSET(ref_b_frame_delta_qp), AV_OPT_TYPE_INT, { .i64 = 4 }, -10, 10, VE }, + + /// Intra-Refresh + { "intra_refresh_mb","Intra Refresh MBs Number Per Slot in Macroblocks", OFFSET(intra_refresh_mb), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, + + /// coder + { "coder", "Coding Type", OFFSET(coding_mode), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_UNDEFINED }, AMF_VIDEO_ENCODER_UNDEFINED, AMF_VIDEO_ENCODER_CALV, VE, "coder" }, + { "auto", "Automatic", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_UNDEFINED }, 0, 0, VE, "coder" }, + { "cavlc", "Context Adaptive Variable-Length Coding", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_CALV }, 0, 0, VE, "coder" }, + { "cabac", "Context Adaptive Binary Arithmetic Coding", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_CABAC }, 0, 0, VE, "coder" }, + + { "me_half_pel", "Enable ME Half Pixel", OFFSET(me_half_pel), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, + { "me_quarter_pel", "Enable ME Quarter Pixel", OFFSET(me_quarter_pel),AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, + + { "aud", "Inserts AU Delimiter NAL unit", OFFSET(aud) ,AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + + { "log_to_dbg", "Enable AMF logging to debug output", OFFSET(log_to_dbg) , AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + + { NULL } +}; + +static av_cold int amf_encode_init_h264(AVCodecContext *avctx) +{ + int ret = 0; + AMF_RESULT res = AMF_OK; + AmfContext *ctx = avctx->priv_data; + AMFVariantStruct var = { 0 }; + amf_int64 profile = 0; + amf_int64 profile_level = 0; + AMFBuffer *buffer; + AMFGuid guid; + AMFRate framerate; + AMFSize framesize = AMFConstructSize(avctx->width, avctx->height); + int deblocking_filter = (avctx->flags & AV_CODEC_FLAG_LOOP_FILTER) ? 1 : 0; + + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { + framerate = AMFConstructRate(avctx->framerate.num, avctx->framerate.den); + } else { + framerate = AMFConstructRate(avctx->time_base.den, avctx->time_base.num * avctx->ticks_per_frame); + } + + if ((ret = ff_amf_encode_init(avctx)) != 0) + return ret; + + // Static parameters + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_USAGE, ctx->usage); + + AMF_ASSIGN_PROPERTY_SIZE(res, ctx->encoder, AMF_VIDEO_ENCODER_FRAMESIZE, framesize); + + AMF_ASSIGN_PROPERTY_RATE(res, ctx->encoder, AMF_VIDEO_ENCODER_FRAMERATE, framerate); + + switch (avctx->profile) { + case FF_PROFILE_H264_BASELINE: + profile = AMF_VIDEO_ENCODER_PROFILE_BASELINE; + break; + case FF_PROFILE_H264_MAIN: + profile = AMF_VIDEO_ENCODER_PROFILE_MAIN; + break; + case FF_PROFILE_H264_HIGH: + profile = AMF_VIDEO_ENCODER_PROFILE_HIGH; + break; + case FF_PROFILE_H264_CONSTRAINED_BASELINE: + profile = AMF_VIDEO_ENCODER_PROFILE_CONSTRAINED_BASELINE; + break; + case (FF_PROFILE_H264_HIGH | FF_PROFILE_H264_CONSTRAINED): + profile = AMF_VIDEO_ENCODER_PROFILE_CONSTRAINED_HIGH; + break; + } + if (profile == 0) { + profile = ctx->profile; + } + + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_PROFILE, profile); + + profile_level = avctx->level; + if (profile_level == FF_LEVEL_UNKNOWN) { + profile_level = ctx->level; + } + if (profile_level != 0) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_PROFILE_LEVEL, profile_level); + } + + // Maximum Reference Frames + if (avctx->refs != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_MAX_NUM_REFRAMES, avctx->refs); + } + if (avctx->sample_aspect_ratio.den && avctx->sample_aspect_ratio.num) { + AMFRatio ratio = AMFConstructRatio(avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den); + AMF_ASSIGN_PROPERTY_RATIO(res, ctx->encoder, AMF_VIDEO_ENCODER_ASPECT_RATIO, ratio); + } + + /// Color Range (Partial/TV/MPEG or Full/PC/JPEG) + if (avctx->color_range == AVCOL_RANGE_JPEG) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_FULL_RANGE_COLOR, 1); + } + + // autodetect rate control method + if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_UNKNOWN) { + if (ctx->qp_i != -1 || ctx->qp_p != -1 || ctx->qp_b != -1) { + ctx->rate_control_mode = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP; + av_log(ctx, AV_LOG_DEBUG, "Rate control turned to CQP\n"); + } else if (avctx->rc_max_rate > 0 ) { + ctx->rate_control_mode = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR; + av_log(ctx, AV_LOG_DEBUG, "Rate control turned to Peak VBR\n"); + } else { + ctx->rate_control_mode = AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR; + av_log(ctx, AV_LOG_DEBUG, "Rate control turned to CBR\n"); + } + } + + if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_RATE_CONTROL_PREANALYSIS_ENABLE, AMF_VIDEO_ENCODER_PREENCODE_DISABLED); + if (ctx->preanalysis) + av_log(ctx, AV_LOG_WARNING, "Pre-Analysis is not supported by cqp Rate Control Method, automatically disabled\n"); + } else { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_RATE_CONTROL_PREANALYSIS_ENABLE, ctx->preanalysis); + } + + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_QUALITY_PRESET, ctx->quality); + + // Dynamic parmaters + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD, ctx->rate_control_mode); + + /// VBV Buffer + if (avctx->rc_buffer_size != 0) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_VBV_BUFFER_SIZE, avctx->rc_buffer_size); + if (avctx->rc_initial_buffer_occupancy != 0) { + int amf_buffer_fullness = avctx->rc_initial_buffer_occupancy * 64 / avctx->rc_buffer_size; + if (amf_buffer_fullness > 64) + amf_buffer_fullness = 64; + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_INITIAL_VBV_BUFFER_FULLNESS, amf_buffer_fullness); + } + } + /// Maximum Access Unit Size + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_MAX_AU_SIZE, ctx->max_au_size); + + if (ctx->max_au_size) + ctx->enforce_hrd = 1; + + // QP Minimum / Maximum + if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_MIN_QP, 0); + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_MAX_QP, 51); + } else { + if (avctx->qmin != -1) { + int qval = avctx->qmin > 51 ? 51 : avctx->qmin; + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_MIN_QP, qval); + } + if (avctx->qmax != -1) { + int qval = avctx->qmax > 51 ? 51 : avctx->qmax; + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_MAX_QP, qval); + } + } + // QP Values + if (ctx->qp_i != -1) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_QP_I, ctx->qp_i); + if (ctx->qp_p != -1) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_QP_P, ctx->qp_p); + if (ctx->qp_b != -1) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_QP_B, ctx->qp_b); + + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_TARGET_BITRATE, avctx->bit_rate); + + if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CBR) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_PEAK_BITRATE, avctx->bit_rate); + } + if (avctx->rc_max_rate) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_PEAK_BITRATE, avctx->rc_max_rate); + } else if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR) { + av_log(ctx, AV_LOG_WARNING, "rate control mode is PEAK_CONSTRAINED_VBR but rc_max_rate is not set\n"); + } + + // Initialize Encoder + res = ctx->encoder->pVtbl->Init(ctx->encoder, ctx->format, avctx->width, avctx->height); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "encoder->Init() failed with error %d\n", res); + + // Enforce HRD, Filler Data, VBAQ, Frame Skipping, Deblocking Filter + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_ENFORCE_HRD, !!ctx->enforce_hrd); + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_FILLER_DATA_ENABLE, !!ctx->filler_data); + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_RATE_CONTROL_SKIP_FRAME_ENABLE, !!ctx->skip_frame); + if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_RATE_CONTROL_METHOD_CONSTANT_QP) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_ENABLE_VBAQ, 0); + if (ctx->enable_vbaq) + av_log(ctx, AV_LOG_WARNING, "VBAQ is not supported by cqp Rate Control Method, automatically disabled\n"); + } else { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_ENABLE_VBAQ, !!ctx->enable_vbaq); + } + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_DE_BLOCKING_FILTER, !!deblocking_filter); + + // B-Frames + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_B_PIC_PATTERN, avctx->max_b_frames); + if (res != AMF_OK) { + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_B_PIC_PATTERN, &var); + av_log(ctx, AV_LOG_WARNING, "B-frames=%d is not supported by this GPU, switched to %d\n", + avctx->max_b_frames, (int)var.int64Value); + avctx->max_b_frames = (int)var.int64Value; + } + if (avctx->max_b_frames) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_B_PIC_DELTA_QP, ctx->b_frame_delta_qp); + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_B_REFERENCE_ENABLE, !!ctx->b_frame_ref); + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_REF_B_PIC_DELTA_QP, ctx->ref_b_frame_delta_qp); + } + + // Keyframe Interval + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_IDR_PERIOD, avctx->gop_size); + + // Header Insertion Spacing + if (ctx->header_spacing >= 0) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEADER_INSERTION_SPACING, ctx->header_spacing); + + // Intra-Refresh, Slicing + if (ctx->intra_refresh_mb > 0) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_INTRA_REFRESH_NUM_MBS_PER_SLOT, ctx->intra_refresh_mb); + if (avctx->slices > 1) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_SLICES_PER_FRAME, avctx->slices); + + // Coding + if (ctx->coding_mode != 0) + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_CABAC_ENABLE, ctx->coding_mode); + + // Motion Estimation + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_MOTION_HALF_PIXEL, !!ctx->me_half_pel); + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_MOTION_QUARTERPIXEL, !!ctx->me_quarter_pel); + + // fill extradata + res = AMFVariantInit(&var); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "AMFVariantInit() failed with error %d\n", res); + + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_EXTRADATA, &var); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "GetProperty(AMF_VIDEO_ENCODER_EXTRADATA) failed with error %d\n", res); + AMF_RETURN_IF_FALSE(ctx, var.pInterface != NULL, AVERROR_BUG, "GetProperty(AMF_VIDEO_ENCODER_EXTRADATA) returned NULL\n"); + + guid = IID_AMFBuffer(); + + res = var.pInterface->pVtbl->QueryInterface(var.pInterface, &guid, (void**)&buffer); // query for buffer interface + if (res != AMF_OK) { + var.pInterface->pVtbl->Release(var.pInterface); + } + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "QueryInterface(IID_AMFBuffer) failed with error %d\n", res); + + avctx->extradata_size = (int)buffer->pVtbl->GetSize(buffer); + avctx->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!avctx->extradata) { + buffer->pVtbl->Release(buffer); + var.pInterface->pVtbl->Release(var.pInterface); + return AVERROR(ENOMEM); + } + memcpy(avctx->extradata, buffer->pVtbl->GetNative(buffer), avctx->extradata_size); + + buffer->pVtbl->Release(buffer); + var.pInterface->pVtbl->Release(var.pInterface); + + return 0; +} + +static const AVCodecDefault defaults[] = { + { "refs", "-1" }, + { "aspect", "0" }, + { "qmin", "-1" }, + { "qmax", "-1" }, + { "b", "2M" }, + { "g", "250" }, + { "slices", "1" }, + { NULL }, +}; + +static const AVClass h264_amf_class = { + .class_name = "h264_amf", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_h264_amf_encoder = { + .name = "h264_amf", + .long_name = NULL_IF_CONFIG_SMALL("AMD AMF H.264 Encoder"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_H264, + .init = amf_encode_init_h264, + .send_frame = ff_amf_send_frame, + .receive_packet = ff_amf_receive_packet, + .close = ff_amf_encode_close, + .priv_data_size = sizeof(AmfContext), + .priv_class = &h264_amf_class, + .defaults = defaults, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .pix_fmts = ff_amf_pix_fmts, + .wrapper_name = "amf", +}; diff --git a/libavcodec/amfenc_hevc.c b/libavcodec/amfenc_hevc.c new file mode 100644 index 0000000000000..7c9a33ab335aa --- /dev/null +++ b/libavcodec/amfenc_hevc.c @@ -0,0 +1,326 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/internal.h" +#include "libavutil/opt.h" +#include "amfenc.h" +#include "internal.h" + +#define OFFSET(x) offsetof(AmfContext, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + { "usage", "Set the encoding usage", OFFSET(usage), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_TRANSCONDING }, AMF_VIDEO_ENCODER_HEVC_USAGE_TRANSCONDING, AMF_VIDEO_ENCODER_HEVC_USAGE_WEBCAM, VE, "usage" }, + { "transcoding", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_TRANSCONDING }, 0, 0, VE, "usage" }, + { "ultralowlatency","", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_ULTRA_LOW_LATENCY }, 0, 0, VE, "usage" }, + { "lowlatency", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_LOW_LATENCY }, 0, 0, VE, "usage" }, + { "webcam", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_USAGE_WEBCAM }, 0, 0, VE, "usage" }, + + { "profile", "Set the profile (default main)", OFFSET(profile), AV_OPT_TYPE_INT,{ .i64 = AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN }, AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN, AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN, VE, "profile" }, + { "main", "", 0, AV_OPT_TYPE_CONST,{ .i64 = AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN }, 0, 0, VE, "profile" }, + + { "profile_tier", "Set the profile tier (default main)", OFFSET(tier), AV_OPT_TYPE_INT,{ .i64 = AMF_VIDEO_ENCODER_HEVC_TIER_MAIN }, AMF_VIDEO_ENCODER_HEVC_TIER_MAIN, AMF_VIDEO_ENCODER_HEVC_TIER_HIGH, VE, "tier" }, + { "main", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_TIER_MAIN }, 0, 0, VE, "tier" }, + { "high", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_TIER_HIGH }, 0, 0, VE, "tier" }, + + { "level", "Set the encoding level (default auto)", OFFSET(level), AV_OPT_TYPE_INT,{ .i64 = 0 }, 0, AMF_LEVEL_6_2, VE, "level" }, + { "auto", "", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, VE, "level" }, + { "1.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_1 }, 0, 0, VE, "level" }, + { "2.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_2 }, 0, 0, VE, "level" }, + { "2.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_2_1 }, 0, 0, VE, "level" }, + { "3.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_3 }, 0, 0, VE, "level" }, + { "3.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_3_1 }, 0, 0, VE, "level" }, + { "4.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_4 }, 0, 0, VE, "level" }, + { "4.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_4_1 }, 0, 0, VE, "level" }, + { "5.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_5 }, 0, 0, VE, "level" }, + { "5.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_5_1 }, 0, 0, VE, "level" }, + { "5.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_5_2 }, 0, 0, VE, "level" }, + { "6.0", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_6 }, 0, 0, VE, "level" }, + { "6.1", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_6_1 }, 0, 0, VE, "level" }, + { "6.2", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_LEVEL_6_2 }, 0, 0, VE, "level" }, + + { "quality", "Set the encoding quality", OFFSET(quality), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_SPEED }, AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_QUALITY, AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_SPEED, VE, "quality" }, + { "balanced", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_BALANCED }, 0, 0, VE, "quality" }, + { "speed", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_SPEED }, 0, 0, VE, "quality" }, + { "quality", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET_QUALITY }, 0, 0, VE, "quality" }, + + { "rc", "Set the rate control mode", OFFSET(rate_control_mode), AV_OPT_TYPE_INT, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_UNKNOWN }, AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_UNKNOWN, AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR, VE, "rc" }, + { "cqp", "Constant Quantization Parameter", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CONSTANT_QP }, 0, 0, VE, "rc" }, + { "cbr", "Constant Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR }, 0, 0, VE, "rc" }, + { "vbr_peak", "Peak Contrained Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR }, 0, 0, VE, "rc" }, + { "vbr_latency", "Latency Constrained Variable Bitrate", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_LATENCY_CONSTRAINED_VBR }, 0, 0, VE, "rc" }, + + { "header_insertion_mode", "Set header insertion mode", OFFSET(header_insertion_mode), AV_OPT_TYPE_INT,{ .i64 = AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_NONE }, AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_NONE, AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_IDR_ALIGNED, VE, "hdrmode" }, + { "none", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_NONE }, 0, 0, VE, "hdrmode" }, + { "gop", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_GOP_ALIGNED }, 0, 0, VE, "hdrmode" }, + { "idr", "", 0, AV_OPT_TYPE_CONST, { .i64 = AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE_IDR_ALIGNED }, 0, 0, VE, "hdrmode" }, + + { "gops_per_idr", "GOPs per IDR 0-no IDR will be inserted", OFFSET(gops_per_idr), AV_OPT_TYPE_INT, { .i64 = 60 }, 0, INT_MAX, VE }, + { "preanalysis", "Enable preanalysis", OFFSET(preanalysis), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE}, + { "vbaq", "Enable VBAQ", OFFSET(enable_vbaq), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE}, + { "enforce_hrd", "Enforce HRD", OFFSET(enforce_hrd), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE}, + { "filler_data", "Filler Data Enable", OFFSET(filler_data), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE}, + { "max_au_size", "Maximum Access Unit Size for rate control (in bits)", OFFSET(max_au_size), AV_OPT_TYPE_INT,{ .i64 = 0 }, 0, INT_MAX, VE}, + { "min_qp_i", "min quantization parameter for I-frame", OFFSET(min_qp_i), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, + { "max_qp_i", "max quantization parameter for I-frame", OFFSET(max_qp_i), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, + { "min_qp_p", "min quantization parameter for P-frame", OFFSET(min_qp_p), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, + { "max_qp_p", "max quantization parameter for P-frame", OFFSET(max_qp_p), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, + { "qp_p", "quantization parameter for P-frame", OFFSET(qp_p), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, + { "qp_i", "quantization parameter for I-frame", OFFSET(qp_i), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 51, VE }, + { "skip_frame", "Rate Control Based Frame Skip", OFFSET(skip_frame), AV_OPT_TYPE_BOOL,{ .i64 = 0 }, 0, 1, VE }, + { "me_half_pel", "Enable ME Half Pixel", OFFSET(me_half_pel), AV_OPT_TYPE_BOOL,{ .i64 = 1 }, 0, 1, VE }, + { "me_quarter_pel", "Enable ME Quarter Pixel ", OFFSET(me_quarter_pel),AV_OPT_TYPE_BOOL,{ .i64 = 1 }, 0, 1, VE }, + + { "aud", "Inserts AU Delimiter NAL unit", OFFSET(aud) ,AV_OPT_TYPE_BOOL,{ .i64 = 0 }, 0, 1, VE }, + + { "log_to_dbg", "Enable AMF logging to debug output", OFFSET(log_to_dbg), AV_OPT_TYPE_BOOL,{ .i64 = 0 }, 0, 1, VE }, + { NULL } +}; + +static av_cold int amf_encode_init_hevc(AVCodecContext *avctx) +{ + int ret = 0; + AMF_RESULT res = AMF_OK; + AmfContext *ctx = avctx->priv_data; + AMFVariantStruct var = {0}; + amf_int64 profile = 0; + amf_int64 profile_level = 0; + AMFBuffer *buffer; + AMFGuid guid; + AMFRate framerate; + AMFSize framesize = AMFConstructSize(avctx->width, avctx->height); + int deblocking_filter = (avctx->flags & AV_CODEC_FLAG_LOOP_FILTER) ? 1 : 0; + + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { + framerate = AMFConstructRate(avctx->framerate.num, avctx->framerate.den); + } else { + framerate = AMFConstructRate(avctx->time_base.den, avctx->time_base.num * avctx->ticks_per_frame); + } + + if ((ret = ff_amf_encode_init(avctx)) < 0) + return ret; + + // init static parameters + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_USAGE, ctx->usage); + + AMF_ASSIGN_PROPERTY_SIZE(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_FRAMESIZE, framesize); + + AMF_ASSIGN_PROPERTY_RATE(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_FRAMERATE, framerate); + + switch (avctx->profile) { + case FF_PROFILE_HEVC_MAIN: + profile = AMF_VIDEO_ENCODER_HEVC_PROFILE_MAIN; + break; + default: + break; + } + if (profile == 0) { + profile = ctx->profile; + } + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_PROFILE, profile); + + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_TIER, ctx->tier); + + profile_level = avctx->level; + if (profile_level == 0) { + profile_level = ctx->level; + } + if (profile_level != 0) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_PROFILE_LEVEL, profile_level); + } + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_QUALITY_PRESET, ctx->quality); + // Maximum Reference Frames + if (avctx->refs != 0) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MAX_NUM_REFRAMES, avctx->refs); + } + // Aspect Ratio + if (avctx->sample_aspect_ratio.den && avctx->sample_aspect_ratio.num) { + AMFRatio ratio = AMFConstructRatio(avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den); + AMF_ASSIGN_PROPERTY_RATIO(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_ASPECT_RATIO, ratio); + } + + // Picture control properties + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_NUM_GOPS_PER_IDR, ctx->gops_per_idr); + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_GOP_SIZE, avctx->gop_size); + if (avctx->slices > 1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_SLICES_PER_FRAME, avctx->slices); + } + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_DE_BLOCKING_FILTER_DISABLE, deblocking_filter); + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_HEADER_INSERTION_MODE, ctx->header_insertion_mode); + + // Rate control + // autodetect rate control method + if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_UNKNOWN) { + if (ctx->min_qp_i != -1 || ctx->max_qp_i != -1 || + ctx->min_qp_p != -1 || ctx->max_qp_p != -1 || + ctx->qp_i !=-1 || ctx->qp_p != -1) { + ctx->rate_control_mode = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CONSTANT_QP; + av_log(ctx, AV_LOG_DEBUG, "Rate control turned to CQP\n"); + } else if (avctx->rc_max_rate > 0) { + ctx->rate_control_mode = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR; + av_log(ctx, AV_LOG_DEBUG, "Rate control turned to Peak VBR\n"); + } else { + ctx->rate_control_mode = AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR; + av_log(ctx, AV_LOG_DEBUG, "Rate control turned to CBR\n"); + } + } + + + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD, ctx->rate_control_mode); + if (avctx->rc_buffer_size) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_VBV_BUFFER_SIZE, avctx->rc_buffer_size); + + if (avctx->rc_initial_buffer_occupancy != 0) { + int amf_buffer_fullness = avctx->rc_initial_buffer_occupancy * 64 / avctx->rc_buffer_size; + if (amf_buffer_fullness > 64) + amf_buffer_fullness = 64; + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_INITIAL_VBV_BUFFER_FULLNESS, amf_buffer_fullness); + } + } + // Pre-Pass, Pre-Analysis, Two-Pass + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_PREANALYSIS_ENABLE, ctx->preanalysis); + + if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CONSTANT_QP) { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_ENABLE_VBAQ, false); + if (ctx->enable_vbaq) + av_log(ctx, AV_LOG_WARNING, "VBAQ is not supported by cqp Rate Control Method, automatically disabled\n"); + } else { + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_ENABLE_VBAQ, !!ctx->enable_vbaq); + } + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MOTION_HALF_PIXEL, ctx->me_half_pel); + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MOTION_QUARTERPIXEL, ctx->me_quarter_pel); + + // init dynamic rate control params + if (ctx->max_au_size) + ctx->enforce_hrd = 1; + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_ENFORCE_HRD, ctx->enforce_hrd); + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_FILLER_DATA_ENABLE, ctx->filler_data); + + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_TARGET_BITRATE, avctx->bit_rate); + + if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_CBR) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_PEAK_BITRATE, avctx->bit_rate); + } + if (avctx->rc_max_rate) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_PEAK_BITRATE, avctx->rc_max_rate); + } else if (ctx->rate_control_mode == AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_METHOD_PEAK_CONSTRAINED_VBR) { + av_log(ctx, AV_LOG_WARNING, "rate control mode is PEAK_CONSTRAINED_VBR but rc_max_rate is not set\n"); + } + + // init encoder + res = ctx->encoder->pVtbl->Init(ctx->encoder, ctx->format, avctx->width, avctx->height); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "encoder->Init() failed with error %d\n", res); + + // init dynamic picture control params + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MAX_AU_SIZE, ctx->max_au_size); + + if (ctx->min_qp_i != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MIN_QP_I, ctx->min_qp_i); + } else if (avctx->qmin != -1) { + int qval = avctx->qmin > 51 ? 51 : avctx->qmin; + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MIN_QP_I, qval); + } + if (ctx->max_qp_i != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MAX_QP_I, ctx->max_qp_i); + } else if (avctx->qmax != -1) { + int qval = avctx->qmax > 51 ? 51 : avctx->qmax; + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MAX_QP_I, qval); + } + if (ctx->min_qp_p != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MIN_QP_P, ctx->min_qp_p); + } else if (avctx->qmin != -1) { + int qval = avctx->qmin > 51 ? 51 : avctx->qmin; + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MIN_QP_P, qval); + } + if (ctx->max_qp_p != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MAX_QP_P, ctx->max_qp_p); + } else if (avctx->qmax != -1) { + int qval = avctx->qmax > 51 ? 51 : avctx->qmax; + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_MAX_QP_P, qval); + } + + if (ctx->qp_p != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_QP_I, ctx->qp_p); + } + if (ctx->qp_i != -1) { + AMF_ASSIGN_PROPERTY_INT64(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_QP_P, ctx->qp_i); + } + AMF_ASSIGN_PROPERTY_BOOL(res, ctx->encoder, AMF_VIDEO_ENCODER_HEVC_RATE_CONTROL_SKIP_FRAME_ENABLE, ctx->skip_frame); + + + // fill extradata + res = AMFVariantInit(&var); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "AMFVariantInit() failed with error %d\n", res); + + res = ctx->encoder->pVtbl->GetProperty(ctx->encoder, AMF_VIDEO_ENCODER_HEVC_EXTRADATA, &var); + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "GetProperty(AMF_VIDEO_ENCODER_EXTRADATA) failed with error %d\n", res); + AMF_RETURN_IF_FALSE(ctx, var.pInterface != NULL, AVERROR_BUG, "GetProperty(AMF_VIDEO_ENCODER_EXTRADATA) returned NULL\n"); + + guid = IID_AMFBuffer(); + + res = var.pInterface->pVtbl->QueryInterface(var.pInterface, &guid, (void**)&buffer); // query for buffer interface + if (res != AMF_OK) { + var.pInterface->pVtbl->Release(var.pInterface); + } + AMF_RETURN_IF_FALSE(ctx, res == AMF_OK, AVERROR_BUG, "QueryInterface(IID_AMFBuffer) failed with error %d\n", res); + + avctx->extradata_size = (int)buffer->pVtbl->GetSize(buffer); + avctx->extradata = av_mallocz(avctx->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!avctx->extradata) { + buffer->pVtbl->Release(buffer); + var.pInterface->pVtbl->Release(var.pInterface); + return AVERROR(ENOMEM); + } + memcpy(avctx->extradata, buffer->pVtbl->GetNative(buffer), avctx->extradata_size); + + buffer->pVtbl->Release(buffer); + var.pInterface->pVtbl->Release(var.pInterface); + + return 0; +} +static const AVCodecDefault defaults[] = { + { "refs", "-1" }, + { "aspect", "0" }, + { "b", "2M" }, + { "g", "250" }, + { "slices", "1" }, + { NULL }, +}; +static const AVClass hevc_amf_class = { + .class_name = "hevc_amf", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_hevc_amf_encoder = { + .name = "hevc_amf", + .long_name = NULL_IF_CONFIG_SMALL("AMD AMF HEVC encoder"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_HEVC, + .init = amf_encode_init_hevc, + .send_frame = ff_amf_send_frame, + .receive_packet = ff_amf_receive_packet, + .close = ff_amf_encode_close, + .priv_data_size = sizeof(AmfContext), + .priv_class = &hevc_amf_class, + .defaults = defaults, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .pix_fmts = ff_amf_pix_fmts, + .wrapper_name = "amf", +}; diff --git a/libavcodec/amrwbdec.c b/libavcodec/amrwbdec.c index 57aed874cc467..7f2874d35f39c 100644 --- a/libavcodec/amrwbdec.c +++ b/libavcodec/amrwbdec.c @@ -611,7 +611,7 @@ static float voice_factor(float *p_vector, float p_gain, AMRWB_SFR_SIZE) * f_gain * f_gain; - return (p_ener - f_ener) / (p_ener + f_ener); + return (p_ener - f_ener) / (p_ener + f_ener + 0.01); } /** diff --git a/libavcodec/aptx.c b/libavcodec/aptx.c new file mode 100644 index 0000000000000..8750d8421fb4e --- /dev/null +++ b/libavcodec/aptx.c @@ -0,0 +1,1162 @@ +/* + * Audio Processing Technology codec for Bluetooth (aptX) + * + * Copyright (C) 2017 Aurelien Jacobs + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/intreadwrite.h" +#include "avcodec.h" +#include "internal.h" +#include "mathops.h" +#include "audio_frame_queue.h" + + +enum channels { + LEFT, + RIGHT, + NB_CHANNELS +}; + +enum subbands { + LF, // Low Frequency (0-5.5 kHz) + MLF, // Medium-Low Frequency (5.5-11kHz) + MHF, // Medium-High Frequency (11-16.5kHz) + HF, // High Frequency (16.5-22kHz) + NB_SUBBANDS +}; + +#define NB_FILTERS 2 +#define FILTER_TAPS 16 + +typedef struct { + int pos; + int32_t buffer[2*FILTER_TAPS]; +} FilterSignal; + +typedef struct { + FilterSignal outer_filter_signal[NB_FILTERS]; + FilterSignal inner_filter_signal[NB_FILTERS][NB_FILTERS]; +} QMFAnalysis; + +typedef struct { + int32_t quantized_sample; + int32_t quantized_sample_parity_change; + int32_t error; +} Quantize; + +typedef struct { + int32_t quantization_factor; + int32_t factor_select; + int32_t reconstructed_difference; +} InvertQuantize; + +typedef struct { + int32_t prev_sign[2]; + int32_t s_weight[2]; + int32_t d_weight[24]; + int32_t pos; + int32_t reconstructed_differences[48]; + int32_t previous_reconstructed_sample; + int32_t predicted_difference; + int32_t predicted_sample; +} Prediction; + +typedef struct { + int32_t codeword_history; + int32_t dither_parity; + int32_t dither[NB_SUBBANDS]; + + QMFAnalysis qmf; + Quantize quantize[NB_SUBBANDS]; + InvertQuantize invert_quantize[NB_SUBBANDS]; + Prediction prediction[NB_SUBBANDS]; +} Channel; + +typedef struct { + int hd; + int block_size; + int32_t sync_idx; + Channel channels[NB_CHANNELS]; + AudioFrameQueue afq; +} AptXContext; + + +static const int32_t quantize_intervals_LF[65] = { + -9948, 9948, 29860, 49808, 69822, 89926, 110144, 130502, + 151026, 171738, 192666, 213832, 235264, 256982, 279014, 301384, + 324118, 347244, 370790, 394782, 419250, 444226, 469742, 495832, + 522536, 549890, 577936, 606720, 636290, 666700, 698006, 730270, + 763562, 797958, 833538, 870398, 908640, 948376, 989740, 1032874, + 1077948, 1125150, 1174700, 1226850, 1281900, 1340196, 1402156, 1468282, + 1539182, 1615610, 1698514, 1789098, 1888944, 2000168, 2125700, 2269750, + 2438670, 2642660, 2899462, 3243240, 3746078, 4535138, 5664098, 7102424, + 8897462, +}; +static const int32_t invert_quantize_dither_factors_LF[65] = { + 9948, 9948, 9962, 9988, 10026, 10078, 10142, 10218, + 10306, 10408, 10520, 10646, 10784, 10934, 11098, 11274, + 11462, 11664, 11880, 12112, 12358, 12618, 12898, 13194, + 13510, 13844, 14202, 14582, 14988, 15422, 15884, 16380, + 16912, 17484, 18098, 18762, 19480, 20258, 21106, 22030, + 23044, 24158, 25390, 26760, 28290, 30008, 31954, 34172, + 36728, 39700, 43202, 47382, 52462, 58762, 66770, 77280, + 91642, 112348, 144452, 199326, 303512, 485546, 643414, 794914, + 1000124, +}; +static const int32_t quantize_dither_factors_LF[65] = { + 0, 4, 7, 10, 13, 16, 19, 22, + 26, 28, 32, 35, 38, 41, 44, 47, + 51, 54, 58, 62, 65, 70, 74, 79, + 84, 90, 95, 102, 109, 116, 124, 133, + 143, 154, 166, 180, 195, 212, 231, 254, + 279, 308, 343, 383, 430, 487, 555, 639, + 743, 876, 1045, 1270, 1575, 2002, 2628, 3591, + 5177, 8026, 13719, 26047, 45509, 39467, 37875, 51303, + 0, +}; +static const int16_t quantize_factor_select_offset_LF[65] = { + 0, -21, -19, -17, -15, -12, -10, -8, + -6, -4, -1, 1, 3, 6, 8, 10, + 13, 15, 18, 20, 23, 26, 29, 31, + 34, 37, 40, 43, 47, 50, 53, 57, + 60, 64, 68, 72, 76, 80, 85, 89, + 94, 99, 105, 110, 116, 123, 129, 136, + 144, 152, 161, 171, 182, 194, 207, 223, + 241, 263, 291, 328, 382, 467, 522, 522, + 522, +}; + + +static const int32_t quantize_intervals_MLF[9] = { + -89806, 89806, 278502, 494338, 759442, 1113112, 1652322, 2720256, 5190186, +}; +static const int32_t invert_quantize_dither_factors_MLF[9] = { + 89806, 89806, 98890, 116946, 148158, 205512, 333698, 734236, 1735696, +}; +static const int32_t quantize_dither_factors_MLF[9] = { + 0, 2271, 4514, 7803, 14339, 32047, 100135, 250365, 0, +}; +static const int16_t quantize_factor_select_offset_MLF[9] = { + 0, -14, 6, 29, 58, 96, 154, 270, 521, +}; + + +static const int32_t quantize_intervals_MHF[3] = { + -194080, 194080, 890562, +}; +static const int32_t invert_quantize_dither_factors_MHF[3] = { + 194080, 194080, 502402, +}; +static const int32_t quantize_dither_factors_MHF[3] = { + 0, 77081, 0, +}; +static const int16_t quantize_factor_select_offset_MHF[3] = { + 0, -33, 136, +}; + + +static const int32_t quantize_intervals_HF[5] = { + -163006, 163006, 542708, 1120554, 2669238, +}; +static const int32_t invert_quantize_dither_factors_HF[5] = { + 163006, 163006, 216698, 361148, 1187538, +}; +static const int32_t quantize_dither_factors_HF[5] = { + 0, 13423, 36113, 206598, 0, +}; +static const int16_t quantize_factor_select_offset_HF[5] = { + 0, -8, 33, 95, 262, +}; + + +static const int32_t hd_quantize_intervals_LF[257] = { + -2436, 2436, 7308, 12180, 17054, 21930, 26806, 31686, + 36566, 41450, 46338, 51230, 56124, 61024, 65928, 70836, + 75750, 80670, 85598, 90530, 95470, 100418, 105372, 110336, + 115308, 120288, 125278, 130276, 135286, 140304, 145334, 150374, + 155426, 160490, 165566, 170654, 175756, 180870, 185998, 191138, + 196294, 201466, 206650, 211850, 217068, 222300, 227548, 232814, + 238096, 243396, 248714, 254050, 259406, 264778, 270172, 275584, + 281018, 286470, 291944, 297440, 302956, 308496, 314056, 319640, + 325248, 330878, 336532, 342212, 347916, 353644, 359398, 365178, + 370986, 376820, 382680, 388568, 394486, 400430, 406404, 412408, + 418442, 424506, 430600, 436726, 442884, 449074, 455298, 461554, + 467844, 474168, 480528, 486922, 493354, 499820, 506324, 512866, + 519446, 526064, 532722, 539420, 546160, 552940, 559760, 566624, + 573532, 580482, 587478, 594520, 601606, 608740, 615920, 623148, + 630426, 637754, 645132, 652560, 660042, 667576, 675164, 682808, + 690506, 698262, 706074, 713946, 721876, 729868, 737920, 746036, + 754216, 762460, 770770, 779148, 787594, 796108, 804694, 813354, + 822086, 830892, 839774, 848736, 857776, 866896, 876100, 885386, + 894758, 904218, 913766, 923406, 933138, 942964, 952886, 962908, + 973030, 983254, 993582, 1004020, 1014566, 1025224, 1035996, 1046886, + 1057894, 1069026, 1080284, 1091670, 1103186, 1114838, 1126628, 1138558, + 1150634, 1162858, 1175236, 1187768, 1200462, 1213320, 1226346, 1239548, + 1252928, 1266490, 1280242, 1294188, 1308334, 1322688, 1337252, 1352034, + 1367044, 1382284, 1397766, 1413494, 1429478, 1445728, 1462252, 1479058, + 1496158, 1513562, 1531280, 1549326, 1567710, 1586446, 1605550, 1625034, + 1644914, 1665208, 1685932, 1707108, 1728754, 1750890, 1773542, 1796732, + 1820488, 1844840, 1869816, 1895452, 1921780, 1948842, 1976680, 2005338, + 2034868, 2065322, 2096766, 2129260, 2162880, 2197708, 2233832, 2271352, + 2310384, 2351050, 2393498, 2437886, 2484404, 2533262, 2584710, 2639036, + 2696578, 2757738, 2822998, 2892940, 2968278, 3049896, 3138912, 3236760, + 3345312, 3467068, 3605434, 3765154, 3952904, 4177962, 4452178, 4787134, + 5187290, 5647128, 6159120, 6720518, 7332904, 8000032, 8726664, 9518152, + 10380372, +}; +static const int32_t hd_invert_quantize_dither_factors_LF[257] = { + 2436, 2436, 2436, 2436, 2438, 2438, 2438, 2440, + 2442, 2442, 2444, 2446, 2448, 2450, 2454, 2456, + 2458, 2462, 2464, 2468, 2472, 2476, 2480, 2484, + 2488, 2492, 2498, 2502, 2506, 2512, 2518, 2524, + 2528, 2534, 2540, 2548, 2554, 2560, 2568, 2574, + 2582, 2588, 2596, 2604, 2612, 2620, 2628, 2636, + 2646, 2654, 2664, 2672, 2682, 2692, 2702, 2712, + 2722, 2732, 2742, 2752, 2764, 2774, 2786, 2798, + 2810, 2822, 2834, 2846, 2858, 2870, 2884, 2896, + 2910, 2924, 2938, 2952, 2966, 2980, 2994, 3010, + 3024, 3040, 3056, 3070, 3086, 3104, 3120, 3136, + 3154, 3170, 3188, 3206, 3224, 3242, 3262, 3280, + 3300, 3320, 3338, 3360, 3380, 3400, 3422, 3442, + 3464, 3486, 3508, 3532, 3554, 3578, 3602, 3626, + 3652, 3676, 3702, 3728, 3754, 3780, 3808, 3836, + 3864, 3892, 3920, 3950, 3980, 4010, 4042, 4074, + 4106, 4138, 4172, 4206, 4240, 4276, 4312, 4348, + 4384, 4422, 4460, 4500, 4540, 4580, 4622, 4664, + 4708, 4752, 4796, 4842, 4890, 4938, 4986, 5036, + 5086, 5138, 5192, 5246, 5300, 5358, 5416, 5474, + 5534, 5596, 5660, 5726, 5792, 5860, 5930, 6002, + 6074, 6150, 6226, 6306, 6388, 6470, 6556, 6644, + 6736, 6828, 6924, 7022, 7124, 7228, 7336, 7448, + 7562, 7680, 7802, 7928, 8058, 8192, 8332, 8476, + 8624, 8780, 8940, 9106, 9278, 9458, 9644, 9840, + 10042, 10252, 10472, 10702, 10942, 11194, 11458, 11734, + 12024, 12328, 12648, 12986, 13342, 13720, 14118, 14540, + 14990, 15466, 15976, 16520, 17102, 17726, 18398, 19124, + 19908, 20760, 21688, 22702, 23816, 25044, 26404, 27922, + 29622, 31540, 33720, 36222, 39116, 42502, 46514, 51334, + 57218, 64536, 73830, 85890, 101860, 123198, 151020, 183936, + 216220, 243618, 268374, 293022, 319362, 347768, 378864, 412626, 449596, +}; +static const int32_t hd_quantize_dither_factors_LF[256] = { + 0, 0, 0, 1, 0, 0, 1, 1, + 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 1, 2, 2, 2, 1, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 3, + 2, 3, 2, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 4, 3, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 5, 4, 4, 5, + 4, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 6, 5, 5, 6, 5, 6, + 6, 6, 6, 6, 6, 6, 6, 7, + 6, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 8, 8, 8, 8, 8, 8, + 8, 9, 9, 9, 9, 9, 9, 9, + 10, 10, 10, 10, 10, 11, 11, 11, + 11, 11, 12, 12, 12, 12, 13, 13, + 13, 14, 14, 14, 15, 15, 15, 15, + 16, 16, 17, 17, 17, 18, 18, 18, + 19, 19, 20, 21, 21, 22, 22, 23, + 23, 24, 25, 26, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, + 39, 40, 42, 43, 45, 47, 49, 51, + 53, 55, 58, 60, 63, 66, 69, 73, + 76, 80, 85, 89, 95, 100, 106, 113, + 119, 128, 136, 146, 156, 168, 182, 196, + 213, 232, 254, 279, 307, 340, 380, 425, + 480, 545, 626, 724, 847, 1003, 1205, 1471, + 1830, 2324, 3015, 3993, 5335, 6956, 8229, 8071, + 6850, 6189, 6162, 6585, 7102, 7774, 8441, 9243, +}; +static const int16_t hd_quantize_factor_select_offset_LF[257] = { + 0, -22, -21, -21, -20, -20, -19, -19, + -18, -18, -17, -17, -16, -16, -15, -14, + -14, -13, -13, -12, -12, -11, -11, -10, + -10, -9, -9, -8, -7, -7, -6, -6, + -5, -5, -4, -4, -3, -3, -2, -1, + -1, 0, 0, 1, 1, 2, 2, 3, + 4, 4, 5, 5, 6, 6, 7, 8, + 8, 9, 9, 10, 11, 11, 12, 12, + 13, 14, 14, 15, 15, 16, 17, 17, + 18, 19, 19, 20, 20, 21, 22, 22, + 23, 24, 24, 25, 26, 26, 27, 28, + 28, 29, 30, 30, 31, 32, 33, 33, + 34, 35, 35, 36, 37, 38, 38, 39, + 40, 41, 41, 42, 43, 44, 44, 45, + 46, 47, 48, 48, 49, 50, 51, 52, + 52, 53, 54, 55, 56, 57, 58, 58, + 59, 60, 61, 62, 63, 64, 65, 66, + 67, 68, 69, 69, 70, 71, 72, 73, + 74, 75, 77, 78, 79, 80, 81, 82, + 83, 84, 85, 86, 87, 89, 90, 91, + 92, 93, 94, 96, 97, 98, 99, 101, + 102, 103, 105, 106, 107, 109, 110, 112, + 113, 115, 116, 118, 119, 121, 122, 124, + 125, 127, 129, 130, 132, 134, 136, 137, + 139, 141, 143, 145, 147, 149, 151, 153, + 155, 158, 160, 162, 164, 167, 169, 172, + 174, 177, 180, 182, 185, 188, 191, 194, + 197, 201, 204, 208, 211, 215, 219, 223, + 227, 232, 236, 241, 246, 251, 257, 263, + 269, 275, 283, 290, 298, 307, 317, 327, + 339, 352, 367, 384, 404, 429, 458, 494, + 522, 522, 522, 522, 522, 522, 522, 522, 522, +}; + + +static const int32_t hd_quantize_intervals_MLF[33] = { + -21236, 21236, 63830, 106798, 150386, 194832, 240376, 287258, + 335726, 386034, 438460, 493308, 550924, 611696, 676082, 744626, + 817986, 896968, 982580, 1076118, 1179278, 1294344, 1424504, 1574386, + 1751090, 1966260, 2240868, 2617662, 3196432, 4176450, 5658260, 7671068, + 10380372, +}; +static const int32_t hd_invert_quantize_dither_factors_MLF[33] = { + 21236, 21236, 21360, 21608, 21978, 22468, 23076, 23806, + 24660, 25648, 26778, 28070, 29544, 31228, 33158, 35386, + 37974, 41008, 44606, 48934, 54226, 60840, 69320, 80564, + 96140, 119032, 155576, 221218, 357552, 622468, 859344, 1153464, 1555840, +}; +static const int32_t hd_quantize_dither_factors_MLF[32] = { + 0, 31, 62, 93, 123, 152, 183, 214, + 247, 283, 323, 369, 421, 483, 557, 647, + 759, 900, 1082, 1323, 1654, 2120, 2811, 3894, + 5723, 9136, 16411, 34084, 66229, 59219, 73530, 100594, +}; +static const int16_t hd_quantize_factor_select_offset_MLF[33] = { + 0, -21, -16, -12, -7, -2, 3, 8, + 13, 19, 24, 30, 36, 43, 50, 57, + 65, 74, 83, 93, 104, 117, 131, 147, + 166, 189, 219, 259, 322, 427, 521, 521, 521, +}; + + +static const int32_t hd_quantize_intervals_MHF[9] = { + -95044, 95044, 295844, 528780, 821332, 1226438, 1890540, 3344850, 6450664, +}; +static const int32_t hd_invert_quantize_dither_factors_MHF[9] = { + 95044, 95044, 105754, 127180, 165372, 39736, 424366, 1029946, 2075866, +}; +static const int32_t hd_quantize_dither_factors_MHF[8] = { + 0, 2678, 5357, 9548, -31409, 96158, 151395, 261480, +}; +static const int16_t hd_quantize_factor_select_offset_MHF[9] = { + 0, -17, 5, 30, 62, 105, 177, 334, 518, +}; + + +static const int32_t hd_quantize_intervals_HF[17] = { + -45754, 45754, 138496, 234896, 337336, 448310, 570738, 708380, + 866534, 1053262, 1281958, 1577438, 1993050, 2665984, 3900982, 5902844, + 8897462, +}; +static const int32_t hd_invert_quantize_dither_factors_HF[17] = { + 45754, 45754, 46988, 49412, 53026, 57950, 64478, 73164, + 84988, 101740, 126958, 168522, 247092, 425842, 809154, 1192708, 1801910, +}; +static const int32_t hd_quantize_dither_factors_HF[16] = { + 0, 309, 606, 904, 1231, 1632, 2172, 2956, + 4188, 6305, 10391, 19643, 44688, 95828, 95889, 152301, +}; +static const int16_t hd_quantize_factor_select_offset_HF[17] = { + 0, -18, -8, 2, 13, 25, 38, 53, + 70, 90, 115, 147, 192, 264, 398, 521, 521, +}; + +typedef const struct { + const int32_t *quantize_intervals; + const int32_t *invert_quantize_dither_factors; + const int32_t *quantize_dither_factors; + const int16_t *quantize_factor_select_offset; + int tables_size; + int32_t factor_max; + int32_t prediction_order; +} ConstTables; + +static ConstTables tables[2][NB_SUBBANDS] = { + { + [LF] = { quantize_intervals_LF, + invert_quantize_dither_factors_LF, + quantize_dither_factors_LF, + quantize_factor_select_offset_LF, + FF_ARRAY_ELEMS(quantize_intervals_LF), + 0x11FF, 24 }, + [MLF] = { quantize_intervals_MLF, + invert_quantize_dither_factors_MLF, + quantize_dither_factors_MLF, + quantize_factor_select_offset_MLF, + FF_ARRAY_ELEMS(quantize_intervals_MLF), + 0x14FF, 12 }, + [MHF] = { quantize_intervals_MHF, + invert_quantize_dither_factors_MHF, + quantize_dither_factors_MHF, + quantize_factor_select_offset_MHF, + FF_ARRAY_ELEMS(quantize_intervals_MHF), + 0x16FF, 6 }, + [HF] = { quantize_intervals_HF, + invert_quantize_dither_factors_HF, + quantize_dither_factors_HF, + quantize_factor_select_offset_HF, + FF_ARRAY_ELEMS(quantize_intervals_HF), + 0x15FF, 12 }, + }, + { + [LF] = { hd_quantize_intervals_LF, + hd_invert_quantize_dither_factors_LF, + hd_quantize_dither_factors_LF, + hd_quantize_factor_select_offset_LF, + FF_ARRAY_ELEMS(hd_quantize_intervals_LF), + 0x11FF, 24 }, + [MLF] = { hd_quantize_intervals_MLF, + hd_invert_quantize_dither_factors_MLF, + hd_quantize_dither_factors_MLF, + hd_quantize_factor_select_offset_MLF, + FF_ARRAY_ELEMS(hd_quantize_intervals_MLF), + 0x14FF, 12 }, + [MHF] = { hd_quantize_intervals_MHF, + hd_invert_quantize_dither_factors_MHF, + hd_quantize_dither_factors_MHF, + hd_quantize_factor_select_offset_MHF, + FF_ARRAY_ELEMS(hd_quantize_intervals_MHF), + 0x16FF, 6 }, + [HF] = { hd_quantize_intervals_HF, + hd_invert_quantize_dither_factors_HF, + hd_quantize_dither_factors_HF, + hd_quantize_factor_select_offset_HF, + FF_ARRAY_ELEMS(hd_quantize_intervals_HF), + 0x15FF, 12 }, + } +}; + +static const int16_t quantization_factors[32] = { + 2048, 2093, 2139, 2186, 2233, 2282, 2332, 2383, + 2435, 2489, 2543, 2599, 2656, 2714, 2774, 2834, + 2896, 2960, 3025, 3091, 3158, 3228, 3298, 3371, + 3444, 3520, 3597, 3676, 3756, 3838, 3922, 4008, +}; + + +/* Rounded right shift with optionnal clipping */ +#define RSHIFT_SIZE(size) \ +av_always_inline \ +static int##size##_t rshift##size(int##size##_t value, int shift) \ +{ \ + int##size##_t rounding = (int##size##_t)1 << (shift - 1); \ + int##size##_t mask = ((int##size##_t)1 << (shift + 1)) - 1; \ + return ((value + rounding) >> shift) - ((value & mask) == rounding); \ +} \ +av_always_inline \ +static int##size##_t rshift##size##_clip24(int##size##_t value, int shift) \ +{ \ + return av_clip_intp2(rshift##size(value, shift), 23); \ +} +RSHIFT_SIZE(32) +RSHIFT_SIZE(64) + + +av_always_inline +static void aptx_update_codeword_history(Channel *channel) +{ + int32_t cw = ((channel->quantize[0].quantized_sample & 3) << 0) + + ((channel->quantize[1].quantized_sample & 2) << 1) + + ((channel->quantize[2].quantized_sample & 1) << 3); + channel->codeword_history = (cw << 8) + (channel->codeword_history << 4); +} + +static void aptx_generate_dither(Channel *channel) +{ + int subband; + int64_t m; + int32_t d; + + aptx_update_codeword_history(channel); + + m = (int64_t)5184443 * (channel->codeword_history >> 7); + d = (m << 2) + (m >> 22); + for (subband = 0; subband < NB_SUBBANDS; subband++) + channel->dither[subband] = d << (23 - 5*subband); + channel->dither_parity = (d >> 25) & 1; +} + +/* + * Convolution filter coefficients for the outer QMF of the QMF tree. + * The 2 sets are a mirror of each other. + */ +static const int32_t aptx_qmf_outer_coeffs[NB_FILTERS][FILTER_TAPS] = { + { + 730, -413, -9611, 43626, -121026, 269973, -585547, 2801966, + 697128, -160481, 27611, 8478, -10043, 3511, 688, -897, + }, + { + -897, 688, 3511, -10043, 8478, 27611, -160481, 697128, + 2801966, -585547, 269973, -121026, 43626, -9611, -413, 730, + }, +}; + +/* + * Convolution filter coefficients for the inner QMF of the QMF tree. + * The 2 sets are a mirror of each other. + */ +static const int32_t aptx_qmf_inner_coeffs[NB_FILTERS][FILTER_TAPS] = { + { + 1033, -584, -13592, 61697, -171156, 381799, -828088, 3962579, + 985888, -226954, 39048, 11990, -14203, 4966, 973, -1268, + }, + { + -1268, 973, 4966, -14203, 11990, 39048, -226954, 985888, + 3962579, -828088, 381799, -171156, 61697, -13592, -584, 1033, + }, +}; + +/* + * Push one sample into a circular signal buffer. + */ +av_always_inline +static void aptx_qmf_filter_signal_push(FilterSignal *signal, int32_t sample) +{ + signal->buffer[signal->pos ] = sample; + signal->buffer[signal->pos+FILTER_TAPS] = sample; + signal->pos = (signal->pos + 1) & (FILTER_TAPS - 1); +} + +/* + * Compute the convolution of the signal with the coefficients, and reduce + * to 24 bits by applying the specified right shifting. + */ +av_always_inline +static int32_t aptx_qmf_convolution(FilterSignal *signal, + const int32_t coeffs[FILTER_TAPS], + int shift) +{ + int32_t *sig = &signal->buffer[signal->pos]; + int64_t e = 0; + int i; + + for (i = 0; i < FILTER_TAPS; i++) + e += MUL64(sig[i], coeffs[i]); + + return rshift64_clip24(e, shift); +} + +/* + * Half-band QMF analysis filter realized with a polyphase FIR filter. + * Split into 2 subbands and downsample by 2. + * So for each pair of samples that goes in, one sample goes out, + * split into 2 separate subbands. + */ +av_always_inline +static void aptx_qmf_polyphase_analysis(FilterSignal signal[NB_FILTERS], + const int32_t coeffs[NB_FILTERS][FILTER_TAPS], + int shift, + int32_t samples[NB_FILTERS], + int32_t *low_subband_output, + int32_t *high_subband_output) +{ + int32_t subbands[NB_FILTERS]; + int i; + + for (i = 0; i < NB_FILTERS; i++) { + aptx_qmf_filter_signal_push(&signal[i], samples[NB_FILTERS-1-i]); + subbands[i] = aptx_qmf_convolution(&signal[i], coeffs[i], shift); + } + + *low_subband_output = av_clip_intp2(subbands[0] + subbands[1], 23); + *high_subband_output = av_clip_intp2(subbands[0] - subbands[1], 23); +} + +/* + * Two stage QMF analysis tree. + * Split 4 input samples into 4 subbands and downsample by 4. + * So for each group of 4 samples that goes in, one sample goes out, + * split into 4 separate subbands. + */ +static void aptx_qmf_tree_analysis(QMFAnalysis *qmf, + int32_t samples[4], + int32_t subband_samples[4]) +{ + int32_t intermediate_samples[4]; + int i; + + /* Split 4 input samples into 2 intermediate subbands downsampled to 2 samples */ + for (i = 0; i < 2; i++) + aptx_qmf_polyphase_analysis(qmf->outer_filter_signal, + aptx_qmf_outer_coeffs, 23, + &samples[2*i], + &intermediate_samples[0+i], + &intermediate_samples[2+i]); + + /* Split 2 intermediate subband samples into 4 final subbands downsampled to 1 sample */ + for (i = 0; i < 2; i++) + aptx_qmf_polyphase_analysis(qmf->inner_filter_signal[i], + aptx_qmf_inner_coeffs, 23, + &intermediate_samples[2*i], + &subband_samples[2*i+0], + &subband_samples[2*i+1]); +} + +/* + * Half-band QMF synthesis filter realized with a polyphase FIR filter. + * Join 2 subbands and upsample by 2. + * So for each 2 subbands sample that goes in, a pair of samples goes out. + */ +av_always_inline +static void aptx_qmf_polyphase_synthesis(FilterSignal signal[NB_FILTERS], + const int32_t coeffs[NB_FILTERS][FILTER_TAPS], + int shift, + int32_t low_subband_input, + int32_t high_subband_input, + int32_t samples[NB_FILTERS]) +{ + int32_t subbands[NB_FILTERS]; + int i; + + subbands[0] = low_subband_input + high_subband_input; + subbands[1] = low_subband_input - high_subband_input; + + for (i = 0; i < NB_FILTERS; i++) { + aptx_qmf_filter_signal_push(&signal[i], subbands[1-i]); + samples[i] = aptx_qmf_convolution(&signal[i], coeffs[i], shift); + } +} + +/* + * Two stage QMF synthesis tree. + * Join 4 subbands and upsample by 4. + * So for each 4 subbands sample that goes in, a group of 4 samples goes out. + */ +static void aptx_qmf_tree_synthesis(QMFAnalysis *qmf, + int32_t subband_samples[4], + int32_t samples[4]) +{ + int32_t intermediate_samples[4]; + int i; + + /* Join 4 subbands into 2 intermediate subbands upsampled to 2 samples. */ + for (i = 0; i < 2; i++) + aptx_qmf_polyphase_synthesis(qmf->inner_filter_signal[i], + aptx_qmf_inner_coeffs, 22, + subband_samples[2*i+0], + subband_samples[2*i+1], + &intermediate_samples[2*i]); + + /* Join 2 samples from intermediate subbands upsampled to 4 samples. */ + for (i = 0; i < 2; i++) + aptx_qmf_polyphase_synthesis(qmf->outer_filter_signal, + aptx_qmf_outer_coeffs, 21, + intermediate_samples[0+i], + intermediate_samples[2+i], + &samples[2*i]); +} + + +av_always_inline +static int32_t aptx_bin_search(int32_t value, int32_t factor, + const int32_t *intervals, int32_t nb_intervals) +{ + int32_t idx = 0; + int i; + + for (i = nb_intervals >> 1; i > 0; i >>= 1) + if (MUL64(factor, intervals[idx + i]) <= ((int64_t)value << 24)) + idx += i; + + return idx; +} + +static void aptx_quantize_difference(Quantize *quantize, + int32_t sample_difference, + int32_t dither, + int32_t quantization_factor, + ConstTables *tables) +{ + const int32_t *intervals = tables->quantize_intervals; + int32_t quantized_sample, dithered_sample, parity_change; + int32_t d, mean, interval, inv, sample_difference_abs; + int64_t error; + + sample_difference_abs = FFABS(sample_difference); + sample_difference_abs = FFMIN(sample_difference_abs, (1 << 23) - 1); + + quantized_sample = aptx_bin_search(sample_difference_abs >> 4, + quantization_factor, + intervals, tables->tables_size); + + d = rshift32_clip24(MULH(dither, dither), 7) - (1 << 23); + d = rshift64(MUL64(d, tables->quantize_dither_factors[quantized_sample]), 23); + + intervals += quantized_sample; + mean = (intervals[1] + intervals[0]) / 2; + interval = (intervals[1] - intervals[0]) * (-(sample_difference < 0) | 1); + + dithered_sample = rshift64_clip24(MUL64(dither, interval) + ((int64_t)av_clip_intp2(mean + d, 23) << 32), 32); + error = ((int64_t)sample_difference_abs << 20) - MUL64(dithered_sample, quantization_factor); + quantize->error = FFABS(rshift64(error, 23)); + + parity_change = quantized_sample; + if (error < 0) + quantized_sample--; + else + parity_change--; + + inv = -(sample_difference < 0); + quantize->quantized_sample = quantized_sample ^ inv; + quantize->quantized_sample_parity_change = parity_change ^ inv; +} + +static void aptx_encode_channel(Channel *channel, int32_t samples[4], int hd) +{ + int32_t subband_samples[4]; + int subband; + aptx_qmf_tree_analysis(&channel->qmf, samples, subband_samples); + aptx_generate_dither(channel); + for (subband = 0; subband < NB_SUBBANDS; subband++) { + int32_t diff = av_clip_intp2(subband_samples[subband] - channel->prediction[subband].predicted_sample, 23); + aptx_quantize_difference(&channel->quantize[subband], diff, + channel->dither[subband], + channel->invert_quantize[subband].quantization_factor, + &tables[hd][subband]); + } +} + +static void aptx_decode_channel(Channel *channel, int32_t samples[4]) +{ + int32_t subband_samples[4]; + int subband; + for (subband = 0; subband < NB_SUBBANDS; subband++) + subband_samples[subband] = channel->prediction[subband].previous_reconstructed_sample; + aptx_qmf_tree_synthesis(&channel->qmf, subband_samples, samples); +} + + +static void aptx_invert_quantization(InvertQuantize *invert_quantize, + int32_t quantized_sample, int32_t dither, + ConstTables *tables) +{ + int32_t qr, idx, shift, factor_select; + + idx = (quantized_sample ^ -(quantized_sample < 0)) + 1; + qr = tables->quantize_intervals[idx] / 2; + if (quantized_sample < 0) + qr = -qr; + + qr = rshift64_clip24(((int64_t)qr<<32) + MUL64(dither, tables->invert_quantize_dither_factors[idx]), 32); + invert_quantize->reconstructed_difference = MUL64(invert_quantize->quantization_factor, qr) >> 19; + + /* update factor_select */ + factor_select = 32620 * invert_quantize->factor_select; + factor_select = rshift32(factor_select + (tables->quantize_factor_select_offset[idx] << 15), 15); + invert_quantize->factor_select = av_clip(factor_select, 0, tables->factor_max); + + /* update quantization factor */ + idx = (invert_quantize->factor_select & 0xFF) >> 3; + shift = (tables->factor_max - invert_quantize->factor_select) >> 8; + invert_quantize->quantization_factor = (quantization_factors[idx] << 11) >> shift; +} + +static int32_t *aptx_reconstructed_differences_update(Prediction *prediction, + int32_t reconstructed_difference, + int order) +{ + int32_t *rd1 = prediction->reconstructed_differences, *rd2 = rd1 + order; + int p = prediction->pos; + + rd1[p] = rd2[p]; + prediction->pos = p = (p + 1) % order; + rd2[p] = reconstructed_difference; + return &rd2[p]; +} + +static void aptx_prediction_filtering(Prediction *prediction, + int32_t reconstructed_difference, + int order) +{ + int32_t reconstructed_sample, predictor, srd0; + int32_t *reconstructed_differences; + int64_t predicted_difference = 0; + int i; + + reconstructed_sample = av_clip_intp2(reconstructed_difference + prediction->predicted_sample, 23); + predictor = av_clip_intp2((MUL64(prediction->s_weight[0], prediction->previous_reconstructed_sample) + + MUL64(prediction->s_weight[1], reconstructed_sample)) >> 22, 23); + prediction->previous_reconstructed_sample = reconstructed_sample; + + reconstructed_differences = aptx_reconstructed_differences_update(prediction, reconstructed_difference, order); + srd0 = FFDIFFSIGN(reconstructed_difference, 0) << 23; + for (i = 0; i < order; i++) { + int32_t srd = FF_SIGNBIT(reconstructed_differences[-i-1]) | 1; + prediction->d_weight[i] -= rshift32(prediction->d_weight[i] - srd*srd0, 8); + predicted_difference += MUL64(reconstructed_differences[-i], prediction->d_weight[i]); + } + + prediction->predicted_difference = av_clip_intp2(predicted_difference >> 22, 23); + prediction->predicted_sample = av_clip_intp2(predictor + prediction->predicted_difference, 23); +} + +static void aptx_process_subband(InvertQuantize *invert_quantize, + Prediction *prediction, + int32_t quantized_sample, int32_t dither, + ConstTables *tables) +{ + int32_t sign, same_sign[2], weight[2], sw1, range; + + aptx_invert_quantization(invert_quantize, quantized_sample, dither, tables); + + sign = FFDIFFSIGN(invert_quantize->reconstructed_difference, + -prediction->predicted_difference); + same_sign[0] = sign * prediction->prev_sign[0]; + same_sign[1] = sign * prediction->prev_sign[1]; + prediction->prev_sign[0] = prediction->prev_sign[1]; + prediction->prev_sign[1] = sign | 1; + + range = 0x100000; + sw1 = rshift32(-same_sign[1] * prediction->s_weight[1], 1); + sw1 = (av_clip(sw1, -range, range) & ~0xF) << 4; + + range = 0x300000; + weight[0] = 254 * prediction->s_weight[0] + 0x800000*same_sign[0] + sw1; + prediction->s_weight[0] = av_clip(rshift32(weight[0], 8), -range, range); + + range = 0x3C0000 - prediction->s_weight[0]; + weight[1] = 255 * prediction->s_weight[1] + 0xC00000*same_sign[1]; + prediction->s_weight[1] = av_clip(rshift32(weight[1], 8), -range, range); + + aptx_prediction_filtering(prediction, + invert_quantize->reconstructed_difference, + tables->prediction_order); +} + +static void aptx_invert_quantize_and_prediction(Channel *channel, int hd) +{ + int subband; + for (subband = 0; subband < NB_SUBBANDS; subband++) + aptx_process_subband(&channel->invert_quantize[subband], + &channel->prediction[subband], + channel->quantize[subband].quantized_sample, + channel->dither[subband], + &tables[hd][subband]); +} + +static int32_t aptx_quantized_parity(Channel *channel) +{ + int32_t parity = channel->dither_parity; + int subband; + + for (subband = 0; subband < NB_SUBBANDS; subband++) + parity ^= channel->quantize[subband].quantized_sample; + + return parity & 1; +} + +/* For each sample, ensure that the parity of all subbands of all channels + * is 0 except once every 8 samples where the parity is forced to 1. */ +static int aptx_check_parity(Channel channels[NB_CHANNELS], int32_t *idx) +{ + int32_t parity = aptx_quantized_parity(&channels[LEFT]) + ^ aptx_quantized_parity(&channels[RIGHT]); + + int eighth = *idx == 7; + *idx = (*idx + 1) & 7; + + return parity ^ eighth; +} + +static void aptx_insert_sync(Channel channels[NB_CHANNELS], int32_t *idx) +{ + if (aptx_check_parity(channels, idx)) { + int i; + Channel *c; + static const int map[] = { 1, 2, 0, 3 }; + Quantize *min = &channels[NB_CHANNELS-1].quantize[map[0]]; + for (c = &channels[NB_CHANNELS-1]; c >= channels; c--) + for (i = 0; i < NB_SUBBANDS; i++) + if (c->quantize[map[i]].error < min->error) + min = &c->quantize[map[i]]; + + /* Forcing the desired parity is done by offsetting by 1 the quantized + * sample from the subband featuring the smallest quantization error. */ + min->quantized_sample = min->quantized_sample_parity_change; + } +} + +static uint16_t aptx_pack_codeword(Channel *channel) +{ + int32_t parity = aptx_quantized_parity(channel); + return (((channel->quantize[3].quantized_sample & 0x06) | parity) << 13) + | (((channel->quantize[2].quantized_sample & 0x03) ) << 11) + | (((channel->quantize[1].quantized_sample & 0x0F) ) << 7) + | (((channel->quantize[0].quantized_sample & 0x7F) ) << 0); +} + +static uint32_t aptxhd_pack_codeword(Channel *channel) +{ + int32_t parity = aptx_quantized_parity(channel); + return (((channel->quantize[3].quantized_sample & 0x01E) | parity) << 19) + | (((channel->quantize[2].quantized_sample & 0x00F) ) << 15) + | (((channel->quantize[1].quantized_sample & 0x03F) ) << 9) + | (((channel->quantize[0].quantized_sample & 0x1FF) ) << 0); +} + +static void aptx_unpack_codeword(Channel *channel, uint16_t codeword) +{ + channel->quantize[0].quantized_sample = sign_extend(codeword >> 0, 7); + channel->quantize[1].quantized_sample = sign_extend(codeword >> 7, 4); + channel->quantize[2].quantized_sample = sign_extend(codeword >> 11, 2); + channel->quantize[3].quantized_sample = sign_extend(codeword >> 13, 3); + channel->quantize[3].quantized_sample = (channel->quantize[3].quantized_sample & ~1) + | aptx_quantized_parity(channel); +} + +static void aptxhd_unpack_codeword(Channel *channel, uint32_t codeword) +{ + channel->quantize[0].quantized_sample = sign_extend(codeword >> 0, 9); + channel->quantize[1].quantized_sample = sign_extend(codeword >> 9, 6); + channel->quantize[2].quantized_sample = sign_extend(codeword >> 15, 4); + channel->quantize[3].quantized_sample = sign_extend(codeword >> 19, 5); + channel->quantize[3].quantized_sample = (channel->quantize[3].quantized_sample & ~1) + | aptx_quantized_parity(channel); +} + +static void aptx_encode_samples(AptXContext *ctx, + int32_t samples[NB_CHANNELS][4], + uint8_t *output) +{ + int channel; + for (channel = 0; channel < NB_CHANNELS; channel++) + aptx_encode_channel(&ctx->channels[channel], samples[channel], ctx->hd); + + aptx_insert_sync(ctx->channels, &ctx->sync_idx); + + for (channel = 0; channel < NB_CHANNELS; channel++) { + aptx_invert_quantize_and_prediction(&ctx->channels[channel], ctx->hd); + if (ctx->hd) + AV_WB24(output + 3*channel, + aptxhd_pack_codeword(&ctx->channels[channel])); + else + AV_WB16(output + 2*channel, + aptx_pack_codeword(&ctx->channels[channel])); + } +} + +static int aptx_decode_samples(AptXContext *ctx, + const uint8_t *input, + int32_t samples[NB_CHANNELS][4]) +{ + int channel, ret; + + for (channel = 0; channel < NB_CHANNELS; channel++) { + aptx_generate_dither(&ctx->channels[channel]); + + if (ctx->hd) + aptxhd_unpack_codeword(&ctx->channels[channel], + AV_RB24(input + 3*channel)); + else + aptx_unpack_codeword(&ctx->channels[channel], + AV_RB16(input + 2*channel)); + aptx_invert_quantize_and_prediction(&ctx->channels[channel], ctx->hd); + } + + ret = aptx_check_parity(ctx->channels, &ctx->sync_idx); + + for (channel = 0; channel < NB_CHANNELS; channel++) + aptx_decode_channel(&ctx->channels[channel], samples[channel]); + + return ret; +} + + +static av_cold int aptx_init(AVCodecContext *avctx) +{ + AptXContext *s = avctx->priv_data; + int chan, subband; + + s->hd = avctx->codec->id == AV_CODEC_ID_APTX_HD; + s->block_size = s->hd ? 6 : 4; + + if (avctx->frame_size == 0) + avctx->frame_size = 256 * s->block_size; + + if (avctx->frame_size % s->block_size) { + av_log(avctx, AV_LOG_ERROR, + "Frame size must be a multiple of %d samples\n", s->block_size); + return AVERROR(EINVAL); + } + + for (chan = 0; chan < NB_CHANNELS; chan++) { + Channel *channel = &s->channels[chan]; + for (subband = 0; subband < NB_SUBBANDS; subband++) { + Prediction *prediction = &channel->prediction[subband]; + prediction->prev_sign[0] = 1; + prediction->prev_sign[1] = 1; + } + } + + ff_af_queue_init(avctx, &s->afq); + return 0; +} + +static int aptx_decode_frame(AVCodecContext *avctx, void *data, + int *got_frame_ptr, AVPacket *avpkt) +{ + AptXContext *s = avctx->priv_data; + AVFrame *frame = data; + int pos, opos, channel, sample, ret; + + if (avpkt->size < s->block_size) { + av_log(avctx, AV_LOG_ERROR, "Packet is too small\n"); + return AVERROR_INVALIDDATA; + } + + /* get output buffer */ + frame->channels = NB_CHANNELS; + frame->format = AV_SAMPLE_FMT_S32P; + frame->nb_samples = 4 * avpkt->size / s->block_size; + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + + for (pos = 0, opos = 0; opos < frame->nb_samples; pos += s->block_size, opos += 4) { + int32_t samples[NB_CHANNELS][4]; + + if (aptx_decode_samples(s, &avpkt->data[pos], samples)) { + av_log(avctx, AV_LOG_ERROR, "Synchronization error\n"); + return AVERROR_INVALIDDATA; + } + + for (channel = 0; channel < NB_CHANNELS; channel++) + for (sample = 0; sample < 4; sample++) + AV_WN32A(&frame->data[channel][4*(opos+sample)], + samples[channel][sample] << 8); + } + + *got_frame_ptr = 1; + return s->block_size * frame->nb_samples / 4; +} + +static int aptx_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr) +{ + AptXContext *s = avctx->priv_data; + int pos, ipos, channel, sample, output_size, ret; + + if ((ret = ff_af_queue_add(&s->afq, frame)) < 0) + return ret; + + output_size = s->block_size * frame->nb_samples/4; + if ((ret = ff_alloc_packet2(avctx, avpkt, output_size, 0)) < 0) + return ret; + + for (pos = 0, ipos = 0; pos < output_size; pos += s->block_size, ipos += 4) { + int32_t samples[NB_CHANNELS][4]; + + for (channel = 0; channel < NB_CHANNELS; channel++) + for (sample = 0; sample < 4; sample++) + samples[channel][sample] = (int32_t)AV_RN32A(&frame->data[channel][4*(ipos+sample)]) >> 8; + + aptx_encode_samples(s, samples, avpkt->data + pos); + } + + ff_af_queue_remove(&s->afq, frame->nb_samples, &avpkt->pts, &avpkt->duration); + *got_packet_ptr = 1; + return 0; +} + +static av_cold int aptx_close(AVCodecContext *avctx) +{ + AptXContext *s = avctx->priv_data; + ff_af_queue_close(&s->afq); + return 0; +} + + +#if CONFIG_APTX_DECODER +AVCodec ff_aptx_decoder = { + .name = "aptx", + .long_name = NULL_IF_CONFIG_SMALL("aptX (Audio Processing Technology for Bluetooth)"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_APTX, + .priv_data_size = sizeof(AptXContext), + .init = aptx_init, + .decode = aptx_decode_frame, + .close = aptx_close, + .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, + .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_STEREO, 0}, + .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32P, + AV_SAMPLE_FMT_NONE }, +}; +#endif + +#if CONFIG_APTX_HD_DECODER +AVCodec ff_aptx_hd_decoder = { + .name = "aptx_hd", + .long_name = NULL_IF_CONFIG_SMALL("aptX HD (Audio Processing Technology for Bluetooth)"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_APTX_HD, + .priv_data_size = sizeof(AptXContext), + .init = aptx_init, + .decode = aptx_decode_frame, + .close = aptx_close, + .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, + .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_STEREO, 0}, + .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32P, + AV_SAMPLE_FMT_NONE }, +}; +#endif + +#if CONFIG_APTX_ENCODER +AVCodec ff_aptx_encoder = { + .name = "aptx", + .long_name = NULL_IF_CONFIG_SMALL("aptX (Audio Processing Technology for Bluetooth)"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_APTX, + .priv_data_size = sizeof(AptXContext), + .init = aptx_init, + .encode2 = aptx_encode_frame, + .close = aptx_close, + .capabilities = AV_CODEC_CAP_SMALL_LAST_FRAME, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, + .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_STEREO, 0}, + .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32P, + AV_SAMPLE_FMT_NONE }, + .supported_samplerates = (const int[]) {8000, 16000, 24000, 32000, 44100, 48000, 0}, +}; +#endif + +#if CONFIG_APTX_HD_ENCODER +AVCodec ff_aptx_hd_encoder = { + .name = "aptx_hd", + .long_name = NULL_IF_CONFIG_SMALL("aptX HD (Audio Processing Technology for Bluetooth)"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_APTX_HD, + .priv_data_size = sizeof(AptXContext), + .init = aptx_init, + .encode2 = aptx_encode_frame, + .close = aptx_close, + .capabilities = AV_CODEC_CAP_SMALL_LAST_FRAME, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, + .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_STEREO, 0}, + .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S32P, + AV_SAMPLE_FMT_NONE }, + .supported_samplerates = (const int[]) {8000, 16000, 24000, 32000, 44100, 48000, 0}, +}; +#endif diff --git a/libavcodec/arm/Makefile b/libavcodec/arm/Makefile index 1eeac5449eeac..e656011c3c52f 100644 --- a/libavcodec/arm/Makefile +++ b/libavcodec/arm/Makefile @@ -42,6 +42,7 @@ OBJS-$(CONFIG_DCA_DECODER) += arm/synth_filter_init_arm.o OBJS-$(CONFIG_HEVC_DECODER) += arm/hevcdsp_init_arm.o OBJS-$(CONFIG_MLP_DECODER) += arm/mlpdsp_init_arm.o OBJS-$(CONFIG_RV40_DECODER) += arm/rv40dsp_init_arm.o +OBJS-$(CONFIG_SBC_ENCODER) += arm/sbcdsp_init_arm.o OBJS-$(CONFIG_VORBIS_DECODER) += arm/vorbisdsp_init_arm.o OBJS-$(CONFIG_VP6_DECODER) += arm/vp6dsp_init_arm.o OBJS-$(CONFIG_VP9_DECODER) += arm/vp9dsp_init_10bpp_arm.o \ @@ -81,6 +82,7 @@ ARMV6-OBJS-$(CONFIG_VP8DSP) += arm/vp8_armv6.o \ # decoders/encoders ARMV6-OBJS-$(CONFIG_MLP_DECODER) += arm/mlpdsp_armv6.o +ARMV6-OBJS-$(CONFIG_SBC_ENCODER) += arm/sbcdsp_armv6.o # VFP optimizations @@ -136,10 +138,12 @@ NEON-OBJS-$(CONFIG_DCA_DECODER) += arm/synth_filter_neon.o NEON-OBJS-$(CONFIG_HEVC_DECODER) += arm/hevcdsp_init_neon.o \ arm/hevcdsp_deblock_neon.o \ arm/hevcdsp_idct_neon.o \ - arm/hevcdsp_qpel_neon.o + arm/hevcdsp_qpel_neon.o \ + arm/hevcdsp_sao_neon.o NEON-OBJS-$(CONFIG_RV30_DECODER) += arm/rv34dsp_neon.o NEON-OBJS-$(CONFIG_RV40_DECODER) += arm/rv34dsp_neon.o \ arm/rv40dsp_neon.o +NEON-OBJS-$(CONFIG_SBC_ENCODER) += arm/sbcdsp_neon.o NEON-OBJS-$(CONFIG_VORBIS_DECODER) += arm/vorbisdsp_neon.o NEON-OBJS-$(CONFIG_VP6_DECODER) += arm/vp6dsp_neon.o NEON-OBJS-$(CONFIG_VP9_DECODER) += arm/vp9itxfm_16bpp_neon.o \ diff --git a/libavcodec/arm/fmtconvert_init_arm.c b/libavcodec/arm/fmtconvert_init_arm.c index a734decec01dd..e88255d61905a 100644 --- a/libavcodec/arm/fmtconvert_init_arm.c +++ b/libavcodec/arm/fmtconvert_init_arm.c @@ -42,10 +42,8 @@ av_cold void ff_fmt_convert_init_arm(FmtConvertContext *c, AVCodecContext *avctx int cpu_flags = av_get_cpu_flags(); if (have_vfp_vm(cpu_flags)) { - if (!have_vfpv3(cpu_flags)) { - c->int32_to_float_fmul_scalar = ff_int32_to_float_fmul_scalar_vfp; - c->int32_to_float_fmul_array8 = ff_int32_to_float_fmul_array8_vfp; - } + c->int32_to_float_fmul_scalar = ff_int32_to_float_fmul_scalar_vfp; + c->int32_to_float_fmul_array8 = ff_int32_to_float_fmul_array8_vfp; } if (have_neon(cpu_flags)) { diff --git a/libavcodec/arm/h264idct_neon.S b/libavcodec/arm/h264idct_neon.S index 4f68bdb9f55e9..93859db8809cb 100644 --- a/libavcodec/arm/h264idct_neon.S +++ b/libavcodec/arm/h264idct_neon.S @@ -21,6 +21,7 @@ #include "libavutil/arm/asm.S" function ff_h264_idct_add_neon, export=1 +h264_idct_add_neon_nothumb: vld1.64 {d0-d3}, [r1,:128] vmov.i16 q15, #0 @@ -73,6 +74,7 @@ function ff_h264_idct_add_neon, export=1 endfunc function ff_h264_idct_dc_add_neon, export=1 +h264_idct_dc_add_neon_nothumb: mov r3, #0 vld1.16 {d2[],d3[]}, [r1,:16] strh r3, [r1] @@ -113,8 +115,8 @@ function ff_h264_idct_add16_neon, export=1 movne lr, #0 cmp lr, #0 ite ne - adrne lr, X(ff_h264_idct_dc_add_neon) + CONFIG_THUMB - adreq lr, X(ff_h264_idct_add_neon) + CONFIG_THUMB + adrne lr, h264_idct_dc_add_neon_nothumb + CONFIG_THUMB + adreq lr, h264_idct_add_neon_nothumb + CONFIG_THUMB blx lr 2: subs ip, ip, #1 add r1, r1, #32 @@ -138,8 +140,8 @@ function ff_h264_idct_add16intra_neon, export=1 cmp r8, #0 ldrsh r8, [r1] iteet ne - adrne lr, X(ff_h264_idct_add_neon) + CONFIG_THUMB - adreq lr, X(ff_h264_idct_dc_add_neon) + CONFIG_THUMB + adrne lr, h264_idct_add_neon_nothumb + CONFIG_THUMB + adreq lr, h264_idct_dc_add_neon_nothumb + CONFIG_THUMB cmpeq r8, #0 blxne lr subs ip, ip, #1 @@ -166,8 +168,8 @@ function ff_h264_idct_add8_neon, export=1 cmp r8, #0 ldrsh r8, [r1] iteet ne - adrne lr, X(ff_h264_idct_add_neon) + CONFIG_THUMB - adreq lr, X(ff_h264_idct_dc_add_neon) + CONFIG_THUMB + adrne lr, h264_idct_add_neon_nothumb + CONFIG_THUMB + adreq lr, h264_idct_dc_add_neon_nothumb + CONFIG_THUMB cmpeq r8, #0 blxne lr add r12, r12, #1 @@ -267,6 +269,7 @@ endfunc .endm function ff_h264_idct8_add_neon, export=1 +h264_idct8_add_neon_nothumb: vmov.i16 q3, #0 vld1.16 {q8-q9}, [r1,:128] vst1.16 {q3}, [r1,:128]! @@ -328,6 +331,7 @@ function ff_h264_idct8_add_neon, export=1 endfunc function ff_h264_idct8_dc_add_neon, export=1 +h264_idct8_dc_add_neon_nothumb: mov r3, #0 vld1.16 {d30[],d31[]},[r1,:16] strh r3, [r1] @@ -388,8 +392,8 @@ function ff_h264_idct8_add4_neon, export=1 movne lr, #0 cmp lr, #0 ite ne - adrne lr, X(ff_h264_idct8_dc_add_neon) + CONFIG_THUMB - adreq lr, X(ff_h264_idct8_add_neon) + CONFIG_THUMB + adrne lr, h264_idct8_dc_add_neon_nothumb + CONFIG_THUMB + adreq lr, h264_idct8_add_neon_nothumb + CONFIG_THUMB blx lr 2: subs r12, r12, #4 add r1, r1, #128 diff --git a/libavcodec/arm/hevcdsp_arm.h b/libavcodec/arm/hevcdsp_arm.h index 7735df9cd2307..47cdfa574d062 100644 --- a/libavcodec/arm/hevcdsp_arm.h +++ b/libavcodec/arm/hevcdsp_arm.h @@ -21,6 +21,6 @@ #include "libavcodec/hevcdsp.h" -void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth); +void ff_hevc_dsp_init_neon(HEVCDSPContext *c, const int bit_depth); #endif /* AVCODEC_ARM_HEVCDSP_ARM_H */ diff --git a/libavcodec/arm/hevcdsp_deblock_neon.S b/libavcodec/arm/hevcdsp_deblock_neon.S index 166bddb104f18..7cb7487ef6105 100644 --- a/libavcodec/arm/hevcdsp_deblock_neon.S +++ b/libavcodec/arm/hevcdsp_deblock_neon.S @@ -152,7 +152,7 @@ and r9, r8, r7 cmp r9, #0 - beq weakfilter_\@ + beq 1f vadd.i16 q2, q11, q12 vadd.i16 q4, q9, q8 @@ -210,11 +210,11 @@ vbit q13, q3, q5 vbit q14, q2, q5 -weakfilter_\@: +1: mvn r8, r8 and r9, r8, r7 cmp r9, #0 - beq ready_\@ + beq 2f vdup.16 q4, r2 @@ -275,7 +275,7 @@ weakfilter_\@: vbit q11, q0, q5 vbit q12, q4, q5 -ready_\@: +2: vqmovun.s16 d16, q8 vqmovun.s16 d18, q9 vqmovun.s16 d20, q10 diff --git a/libavcodec/arm/hevcdsp_idct_neon.S b/libavcodec/arm/hevcdsp_idct_neon.S index e39d00634b63f..75795e6a6ae22 100644 --- a/libavcodec/arm/hevcdsp_idct_neon.S +++ b/libavcodec/arm/hevcdsp_idct_neon.S @@ -1,5 +1,7 @@ /* + * ARM NEON optimised IDCT functions for HEVC decoding * Copyright (c) 2014 Seppo Tomperi + * Copyright (c) 2017 Alexandra Hájková * * This file is part of FFmpeg. * @@ -19,179 +21,967 @@ */ #include "libavutil/arm/asm.S" -#include "neon.S" - -function ff_hevc_idct_4x4_dc_neon_8, export=1 - ldrsh r1, [r0] - ldr r2, =0x20 - add r1, #1 - asr r1, #1 - add r1, r2 - asr r1, #6 - vdup.16 q0, r1 - vdup.16 q1, r1 - vst1.16 {q0, q1}, [r0] - bx lr + +const trans, align=4 + .short 64, 83, 64, 36 + .short 89, 75, 50, 18 + .short 90, 87, 80, 70 + .short 57, 43, 25, 9 + .short 90, 90, 88, 85 + .short 82, 78, 73, 67 + .short 61, 54, 46, 38 + .short 31, 22, 13, 4 +endconst + +.macro clip10 in1, in2, c1, c2 + vmax.s16 \in1, \in1, \c1 + vmax.s16 \in2, \in2, \c1 + vmin.s16 \in1, \in1, \c2 + vmin.s16 \in2, \in2, \c2 +.endm + +function ff_hevc_add_residual_4x4_8_neon, export=1 + vld1.16 {q0-q1}, [r1, :128] + vld1.32 d4[0], [r0, :32], r2 + vld1.32 d4[1], [r0, :32], r2 + vld1.32 d5[0], [r0, :32], r2 + vld1.32 d5[1], [r0, :32], r2 + sub r0, r0, r2, lsl #2 + vmovl.u8 q8, d4 + vmovl.u8 q9, d5 + vqadd.s16 q0, q0, q8 + vqadd.s16 q1, q1, q9 + vqmovun.s16 d0, q0 + vqmovun.s16 d1, q1 + vst1.32 d0[0], [r0, :32], r2 + vst1.32 d0[1], [r0, :32], r2 + vst1.32 d1[0], [r0, :32], r2 + vst1.32 d1[1], [r0, :32], r2 + bx lr endfunc -function ff_hevc_idct_8x8_dc_neon_8, export=1 - ldrsh r1, [r0] - ldr r2, =0x20 - add r1, #1 - asr r1, #1 - add r1, r2 - asr r1, #6 - vdup.16 q8, r1 - vdup.16 q9, r1 - vmov.16 q10, q8 - vmov.16 q11, q8 - vmov.16 q12, q8 - vmov.16 q13, q8 - vmov.16 q14, q8 - vmov.16 q15, q8 - vstm r0, {q8-q15} - bx lr +function ff_hevc_add_residual_4x4_10_neon, export=1 + mov r12, r0 + vld1.16 {q0-q1}, [r1, :128] + vld1.16 d4, [r12, :64], r2 + vld1.16 d5, [r12, :64], r2 + vld1.16 d6, [r12, :64], r2 + vqadd.s16 q0, q2 + vld1.16 d7, [r12, :64], r2 + vmov.s16 q12, #0 + vqadd.s16 q1, q3 + vmvn.s16 q13, #0xFC00 @ vmov.s16 #0x3FF + clip10 q0, q1, q12, q13 + vst1.16 d0, [r0, :64], r2 + vst1.16 d1, [r0, :64], r2 + vst1.16 d2, [r0, :64], r2 + vst1.16 d3, [r0, :64], r2 + bx lr endfunc -function ff_hevc_idct_16x16_dc_neon_8, export=1 - ldrsh r1, [r0] - ldr r2, =0x20 - add r1, #1 - asr r1, #1 - add r1, r2 - asr r1, #6 - vdup.16 q8, r1 - vdup.16 q9, r1 - vmov.16 q10, q8 - vmov.16 q11, q8 - vmov.16 q12, q8 - vmov.16 q13, q8 - vmov.16 q14, q8 - vmov.16 q15, q8 - vstm r0!, {q8-q15} - vstm r0!, {q8-q15} - vstm r0!, {q8-q15} - vstm r0, {q8-q15} - bx lr +function ff_hevc_add_residual_8x8_8_neon, export=1 + add r12, r0, r2 + add r2, r2, r2 + mov r3, #8 +1: subs r3, #2 + vld1.8 {d16}, [r0, :64] + vld1.8 {d17}, [r12, :64] + vmovl.u8 q9, d16 + vld1.16 {q0-q1}, [r1, :128]! + vmovl.u8 q8, d17 + vqadd.s16 q0, q9 + vqadd.s16 q1, q8 + vqmovun.s16 d0, q0 + vqmovun.s16 d1, q1 + vst1.8 d0, [r0, :64], r2 + vst1.8 d1, [r12, :64], r2 + bne 1b + bx lr +endfunc + +function ff_hevc_add_residual_8x8_10_neon, export=1 + add r12, r0, r2 + add r2, r2, r2 + mov r3, #8 + vmov.s16 q12, #0 + vmvn.s16 q13, #0xFC00 @ vmov.s16 #0x3FF +1: subs r3, #2 + vld1.16 {q0-q1}, [r1, :128]! + vld1.16 {q8}, [r0, :128] + vqadd.s16 q0, q8 + vld1.16 {q9}, [r12, :128] + vqadd.s16 q1, q9 + clip10 q0, q1, q12, q13 + vst1.16 {q0}, [r0, :128], r2 + vst1.16 {q1}, [r12, :128], r2 + bne 1b + bx lr +endfunc + +function ff_hevc_add_residual_16x16_8_neon, export=1 + mov r3, #16 + add r12, r0, r2 + add r2, r2, r2 +1: subs r3, #2 + vld1.8 {q8}, [r0, :128] + vld1.16 {q0, q1}, [r1, :128]! + vld1.8 {q11}, [r12, :128] + vld1.16 {q2, q3}, [r1, :128]! + vmovl.u8 q9, d16 + vmovl.u8 q10, d17 + vmovl.u8 q12, d22 + vmovl.u8 q13, d23 + vqadd.s16 q0, q9 + vqadd.s16 q1, q10 + vqadd.s16 q2, q12 + vqadd.s16 q3, q13 + vqmovun.s16 d0, q0 + vqmovun.s16 d1, q1 + vqmovun.s16 d2, q2 + vqmovun.s16 d3, q3 + vst1.8 {q0}, [r0, :128], r2 + vst1.8 {q1}, [r12, :128], r2 + bne 1b + bx lr +endfunc + +function ff_hevc_add_residual_16x16_10_neon, export=1 + mov r3, #16 + vmov.s16 q12, #0 + vmvn.s16 q13, #0xFC00 @ vmov.s16 #0x3FF + add r12, r0, r2 + add r2, r2, r2 +1: subs r3, #2 + vld1.16 {q8-q9}, [r0, :128] + vld1.16 {q0, q1}, [r1, :128]! + vqadd.s16 q0, q8 + vld1.16 {q10-q11}, [r12, :128] + vqadd.s16 q1, q9 + vld1.16 {q2, q3}, [r1, :128]! + vqadd.s16 q2, q10 + vqadd.s16 q3, q11 + clip10 q0, q1, q12, q13 + clip10 q2, q3, q12, q13 + vst1.16 {q0-q1}, [r0, :128], r2 + vst1.16 {q2-q3}, [r12, :128], r2 + bne 1b + bx lr +endfunc + +function ff_hevc_add_residual_32x32_8_neon, export=1 + vpush {q4-q7} + add r12, r0, r2 + add r2, r2, r2 + mov r3, #32 +1: subs r3, #2 + vld1.8 {q12, q13}, [r0, :128] + vmovl.u8 q8, d24 + vmovl.u8 q9, d25 + vld1.8 {q14, q15}, [r12, :128] + vmovl.u8 q10, d26 + vmovl.u8 q11, d27 + vmovl.u8 q12, d28 + vldm r1!, {q0-q7} + vmovl.u8 q13, d29 + vmovl.u8 q14, d30 + vmovl.u8 q15, d31 + vqadd.s16 q0, q8 + vqadd.s16 q1, q9 + vqadd.s16 q2, q10 + vqadd.s16 q3, q11 + vqadd.s16 q4, q12 + vqadd.s16 q5, q13 + vqadd.s16 q6, q14 + vqadd.s16 q7, q15 + vqmovun.s16 d0, q0 + vqmovun.s16 d1, q1 + vqmovun.s16 d2, q2 + vqmovun.s16 d3, q3 + vqmovun.s16 d4, q4 + vqmovun.s16 d5, q5 + vst1.8 {q0, q1}, [r0, :128], r2 + vqmovun.s16 d6, q6 + vqmovun.s16 d7, q7 + vst1.8 {q2, q3}, [r12, :128], r2 + bne 1b + vpop {q4-q7} + bx lr +endfunc + +function ff_hevc_add_residual_32x32_10_neon, export=1 + mov r3, #32 + add r12, r0, #32 + vmov.s16 q12, #0 + vmvn.s16 q13, #0xFC00 @ vmov.s16 #0x3FF +1: subs r3, #1 + vldm r1!, {q0-q3} + vld1.16 {q8, q9}, [r0, :128] + vld1.16 {q10, q11}, [r12, :128] + vqadd.s16 q0, q8 + vqadd.s16 q1, q9 + vqadd.s16 q2, q10 + vqadd.s16 q3, q11 + clip10 q0, q1, q12, q13 + clip10 q2, q3, q12, q13 + vst1.16 {q0-q1}, [r0, :128], r2 + vst1.16 {q2-q3}, [r12, :128], r2 + bne 1b + bx lr +endfunc + +.macro idct_4x4_dc bitdepth +function ff_hevc_idct_4x4_dc_\bitdepth\()_neon, export=1 + ldrsh r1, [r0] + ldr r2, =(1 << (13 - \bitdepth)) + add r1, #1 + asr r1, #1 + add r1, r2 + asr r1, #(14 - \bitdepth) + vdup.16 q0, r1 + vdup.16 q1, r1 + vst1.16 {q0, q1}, [r0, :128] + bx lr +endfunc +.endm + +.macro idct_8x8_dc bitdepth +function ff_hevc_idct_8x8_dc_\bitdepth\()_neon, export=1 + ldrsh r1, [r0] + ldr r2, =(1 << (13 - \bitdepth)) + add r1, #1 + asr r1, #1 + add r1, r2 + asr r1, #(14 - \bitdepth) + vdup.16 q8, r1 + vdup.16 q9, r1 + vmov.16 q10, q8 + vmov.16 q11, q8 + vmov.16 q12, q8 + vmov.16 q13, q8 + vmov.16 q14, q8 + vmov.16 q15, q8 + vstm r0, {q8-q15} + bx lr +endfunc +.endm + +.macro idct_16x16_dc bitdepth +function ff_hevc_idct_16x16_dc_\bitdepth\()_neon, export=1 + ldrsh r1, [r0] + ldr r2, =(1 << (13 - \bitdepth)) + add r1, #1 + asr r1, #1 + add r1, r2 + asr r1, #(14 - \bitdepth) + vdup.16 q8, r1 + vdup.16 q9, r1 + vmov.16 q10, q8 + vmov.16 q11, q8 + vmov.16 q12, q8 + vmov.16 q13, q8 + vmov.16 q14, q8 + vmov.16 q15, q8 + vstm r0!, {q8-q15} + vstm r0!, {q8-q15} + vstm r0!, {q8-q15} + vstm r0, {q8-q15} + bx lr endfunc +.endm + +.macro idct_32x32_dc bitdepth +function ff_hevc_idct_32x32_dc_\bitdepth\()_neon, export=1 + ldrsh r1, [r0] + ldr r2, =(1 << (13 - \bitdepth)) + add r1, #1 + asr r1, #1 + add r1, r2 + asr r1, #(14 - \bitdepth) + mov r3, #16 + vdup.16 q8, r1 + vdup.16 q9, r1 + vmov.16 q10, q8 + vmov.16 q11, q8 + vmov.16 q12, q8 + vmov.16 q13, q8 + vmov.16 q14, q8 + vmov.16 q15, q8 +1: subs r3, #1 + vstm r0!, {q8-q15} + bne 1b + bx lr +endfunc +.endm + +.macro sum_sub out, in, c, op + .ifc \op, + + vmlal.s16 \out, \in, \c + .else + vmlsl.s16 \out, \in, \c + .endif +.endm + +.macro tr_4x4 in0, in1, in2, in3, out0, out1, out2, out3, shift, tmp0, tmp1, tmp2, tmp3, tmp4 + vshll.s16 \tmp0, \in0, #6 + vmull.s16 \tmp2, \in1, d4[1] + vmov \tmp1, \tmp0 + vmull.s16 \tmp3, \in1, d4[3] + vmlal.s16 \tmp0, \in2, d4[0] @e0 + vmlsl.s16 \tmp1, \in2, d4[0] @e1 + vmlal.s16 \tmp2, \in3, d4[3] @o0 + vmlsl.s16 \tmp3, \in3, d4[1] @o1 + + vadd.s32 \tmp4, \tmp0, \tmp2 + vsub.s32 \tmp0, \tmp0, \tmp2 + vadd.s32 \tmp2, \tmp1, \tmp3 + vsub.s32 \tmp1, \tmp1, \tmp3 + vqrshrn.s32 \out0, \tmp4, #\shift + vqrshrn.s32 \out3, \tmp0, #\shift + vqrshrn.s32 \out1, \tmp2, #\shift + vqrshrn.s32 \out2, \tmp1, #\shift +.endm + +.macro tr_4x4_8 in0, in1, in2, in3, out0, out1, out2, out3, tmp0, tmp1, tmp2, tmp3 + vshll.s16 \tmp0, \in0, #6 + vld1.s16 {\in0}, [r1, :64]! + vmov \tmp1, \tmp0 + vmull.s16 \tmp2, \in1, \in0[1] + vmull.s16 \tmp3, \in1, \in0[3] + vmlal.s16 \tmp0, \in2, \in0[0] @e0 + vmlsl.s16 \tmp1, \in2, \in0[0] @e1 + vmlal.s16 \tmp2, \in3, \in0[3] @o0 + vmlsl.s16 \tmp3, \in3, \in0[1] @o1 + + vld1.s16 {\in0}, [r1, :64] + + vadd.s32 \out0, \tmp0, \tmp2 + vadd.s32 \out1, \tmp1, \tmp3 + vsub.s32 \out2, \tmp1, \tmp3 + vsub.s32 \out3, \tmp0, \tmp2 + + sub r1, r1, #8 +.endm + +@ Do a 4x4 transpose, using q registers for the subtransposes that don't +@ need to address the indiviudal d registers. +@ r0,r1 == rq0, r2,r3 == rq1 +.macro transpose_4x4 rq0, rq1, r0, r1, r2, r3 + vtrn.32 \rq0, \rq1 + vtrn.16 \r0, \r1 + vtrn.16 \r2, \r3 +.endm + +.macro idct_4x4 bitdepth +function ff_hevc_idct_4x4_\bitdepth\()_neon, export=1 +@r0 - coeffs + vld1.s16 {q0-q1}, [r0, :128] -function ff_hevc_idct_32x32_dc_neon_8, export=1 - ldrsh r1, [r0] - ldr r2, =0x20 - add r1, #1 - asr r1, #1 - add r1, r2 - asr r1, #6 - mov r3, #16 - vdup.16 q8, r1 - vdup.16 q9, r1 - vmov.16 q10, q8 - vmov.16 q11, q8 - vmov.16 q12, q8 - vmov.16 q13, q8 - vmov.16 q14, q8 - vmov.16 q15, q8 -1: subs r3, #1 - vstm r0!, {q8-q15} - bne 1b + movrel r1, trans + vld1.s16 {d4}, [r1, :64] + + tr_4x4 d0, d1, d2, d3, d16, d17, d18, d19, 7, q10, q11, q12, q13, q0 + transpose_4x4 q8, q9, d16, d17, d18, d19 + + tr_4x4 d16, d17, d18, d19, d0, d1, d2, d3, 20 - \bitdepth, q10, q11, q12, q13, q0 + transpose_4x4 q0, q1, d0, d1, d2, d3 + vst1.s16 {d0-d3}, [r0, :128] bx lr endfunc +.endm + +.macro transpose8_4x4 r0, r1, r2, r3 + vtrn.16 \r0, \r1 + vtrn.16 \r2, \r3 + vtrn.32 \r0, \r2 + vtrn.32 \r1, \r3 +.endm + +.macro transpose_8x8 r0, r1, r2, r3, r4, r5, r6, r7, l0, l1, l2, l3, l4, l5, l6, l7 + transpose8_4x4 \r0, \r1, \r2, \r3 + transpose8_4x4 \r4, \r5, \r6, \r7 + + transpose8_4x4 \l0, \l1, \l2, \l3 + transpose8_4x4 \l4, \l5, \l6, \l7 +.endm + +.macro tr_8x4 shift, in0, in1, in2, in3, in4, in5, in6, in7 + tr_4x4_8 \in0, \in2, \in4, \in6, q8, q9, q10, q11, q12, q13, q14, q15 + + vmull.s16 q14, \in1, \in0[2] + vmull.s16 q12, \in1, \in0[0] + vmull.s16 q13, \in1, \in0[1] + sum_sub q14, \in3, \in0[0], - + sum_sub q12, \in3, \in0[1], + + sum_sub q13, \in3, \in0[3], - + + sum_sub q14, \in5, \in0[3], + + sum_sub q12, \in5, \in0[2], + + sum_sub q13, \in5, \in0[0], - + + sum_sub q14, \in7, \in0[1], + + sum_sub q12, \in7, \in0[3], + + sum_sub q13, \in7, \in0[2], - + + vadd.s32 q15, q10, q14 + vsub.s32 q10, q10, q14 + vqrshrn.s32 \in2, q15, \shift + + vmull.s16 q15, \in1, \in0[3] + sum_sub q15, \in3, \in0[2], - + sum_sub q15, \in5, \in0[1], + + sum_sub q15, \in7, \in0[0], - + + vqrshrn.s32 \in5, q10, \shift + + vadd.s32 q10, q8, q12 + vsub.s32 q8, q8, q12 + vadd.s32 q12, q9, q13 + vsub.s32 q9, q9, q13 + vadd.s32 q14, q11, q15 + vsub.s32 q11, q11, q15 + + vqrshrn.s32 \in0, q10, \shift + vqrshrn.s32 \in7, q8, \shift + vqrshrn.s32 \in1, q12, \shift + vqrshrn.s32 \in6, q9, \shift + vqrshrn.s32 \in3, q14, \shift + vqrshrn.s32 \in4, q11, \shift +.endm + +.macro idct_8x8 bitdepth +function ff_hevc_idct_8x8_\bitdepth\()_neon, export=1 +@r0 - coeffs + vpush {q4-q7} + + mov r1, r0 + mov r2, #64 + add r3, r0, #32 + vld1.s16 {q0-q1}, [r1,:128], r2 + vld1.s16 {q2-q3}, [r3,:128], r2 + vld1.s16 {q4-q5}, [r1,:128], r2 + vld1.s16 {q6-q7}, [r3,:128], r2 + + movrel r1, trans -function ff_hevc_add_residual_4x4_neon_8, export=1 - vldm r1, {q0-q1} - vld1.32 d4[0], [r0], r2 - vld1.32 d4[1], [r0], r2 - vld1.32 d5[0], [r0], r2 - vld1.32 d5[1], [r0], r2 - sub r0, r0, r2, lsl #2 - vmovl.u8 q8, d4 - vmovl.u8 q9, d5 - vqadd.s16 q0, q0, q8 - vqadd.s16 q1, q1, q9 - vqmovun.s16 d0, q0 - vqmovun.s16 d1, q1 - vst1.32 d0[0], [r0], r2 - vst1.32 d0[1], [r0], r2 - vst1.32 d1[0], [r0], r2 - vst1.32 d1[1], [r0], r2 - bx lr + tr_8x4 7, d0, d2, d4, d6, d8, d10, d12, d14 + tr_8x4 7, d1, d3, d5, d7, d9, d11, d13, d15 + + @ Transpose each 4x4 block, and swap how d4-d7 and d8-d11 are used. + @ Layout before: + @ d0 d1 + @ d2 d3 + @ d4 d5 + @ d6 d7 + @ d8 d9 + @ d10 d11 + @ d12 d13 + @ d14 d15 + transpose_8x8 d0, d2, d4, d6, d8, d10, d12, d14, d1, d3, d5, d7, d9, d11, d13, d15 + @ Now the layout is: + @ d0 d8 + @ d2 d10 + @ d4 d12 + @ d6 d14 + @ d1 d9 + @ d3 d11 + @ d5 d13 + @ d7 d15 + + tr_8x4 20 - \bitdepth, d0, d2, d4, d6, d1, d3, d5, d7 + vswp d0, d8 + tr_8x4 20 - \bitdepth, d0, d10, d12, d14, d9, d11, d13, d15 + vswp d0, d8 + + transpose_8x8 d0, d2, d4, d6, d8, d10, d12, d14, d1, d3, d5, d7, d9, d11, d13, d15 + + mov r1, r0 + mov r2, #64 + add r3, r0, #32 + vst1.s16 {q0-q1}, [r1,:128], r2 + vst1.s16 {q2-q3}, [r3,:128], r2 + vst1.s16 {q4-q5}, [r1,:128], r2 + vst1.s16 {q6-q7}, [r3,:128], r2 + + vpop {q4-q7} + bx lr endfunc +.endm + +.macro butterfly e, o, tmp_p, tmp_m + vadd.s32 \tmp_p, \e, \o + vsub.s32 \tmp_m, \e, \o +.endm + +.macro tr16_8x4 in0, in1, in2, in3, in4, in5, in6, in7, offset + tr_4x4_8 \in0, \in2, \in4, \in6, q8, q9, q10, q11, q12, q13, q14, q15 + + vmull.s16 q12, \in1, \in0[0] + vmull.s16 q13, \in1, \in0[1] + vmull.s16 q14, \in1, \in0[2] + vmull.s16 q15, \in1, \in0[3] + sum_sub q12, \in3, \in0[1], + + sum_sub q13, \in3, \in0[3], - + sum_sub q14, \in3, \in0[0], - + sum_sub q15, \in3, \in0[2], - + + sum_sub q12, \in5, \in0[2], + + sum_sub q13, \in5, \in0[0], - + sum_sub q14, \in5, \in0[3], + + sum_sub q15, \in5, \in0[1], + -function ff_hevc_add_residual_8x8_neon_8, export=1 - mov r3, #8 -1: subs r3, #1 - vld1.16 {q0}, [r1]! - vld1.8 d16, [r0] - vmovl.u8 q8, d16 - vqadd.s16 q0, q8 - vqmovun.s16 d0, q0 - vst1.32 d0, [r0], r2 - bne 1b - bx lr + sum_sub q12, \in7, \in0[3], + + sum_sub q13, \in7, \in0[2], - + sum_sub q14, \in7, \in0[1], + + sum_sub q15, \in7, \in0[0], - + + butterfly q8, q12, q0, q7 + butterfly q9, q13, q1, q6 + butterfly q10, q14, q2, q5 + butterfly q11, q15, q3, q4 + add r4, sp, #\offset + vst1.s32 {q0-q1}, [r4, :128]! + vst1.s32 {q2-q3}, [r4, :128]! + vst1.s32 {q4-q5}, [r4, :128]! + vst1.s32 {q6-q7}, [r4, :128] +.endm + +.macro load16 in0, in1, in2, in3, in4, in5, in6, in7 + vld1.s16 {\in0}, [r1, :64], r2 + vld1.s16 {\in1}, [r3, :64], r2 + vld1.s16 {\in2}, [r1, :64], r2 + vld1.s16 {\in3}, [r3, :64], r2 + vld1.s16 {\in4}, [r1, :64], r2 + vld1.s16 {\in5}, [r3, :64], r2 + vld1.s16 {\in6}, [r1, :64], r2 + vld1.s16 {\in7}, [r3, :64], r2 +.endm + +.macro add_member in, t0, t1, t2, t3, t4, t5, t6, t7, op0, op1, op2, op3, op4, op5, op6, op7 + sum_sub q5, \in, \t0, \op0 + sum_sub q6, \in, \t1, \op1 + sum_sub q7, \in, \t2, \op2 + sum_sub q8, \in, \t3, \op3 + sum_sub q9, \in, \t4, \op4 + sum_sub q10, \in, \t5, \op5 + sum_sub q11, \in, \t6, \op6 + sum_sub q12, \in, \t7, \op7 +.endm + +.macro butterfly16 in0, in1, in2, in3, in4, in5, in6, in7 + vadd.s32 q4, \in0, \in1 + vsub.s32 \in0, \in0, \in1 + vadd.s32 \in1, \in2, \in3 + vsub.s32 \in2, \in2, \in3 + vadd.s32 \in3, \in4, \in5 + vsub.s32 \in4, \in4, \in5 + vadd.s32 \in5, \in6, \in7 + vsub.s32 \in6, \in6, \in7 +.endm + +.macro store16 in0, in1, in2, in3, in4, in5, in6, in7, rx + vst1.s16 \in0, [r1, :64], r2 + vst1.s16 \in1, [r3, :64], \rx + vst1.s16 \in2, [r1, :64], r2 + vst1.s16 \in3, [r3, :64], \rx + vst1.s16 \in4, [r1, :64], r2 + vst1.s16 \in5, [r3, :64], \rx + vst1.s16 \in6, [r1, :64], r2 + vst1.s16 \in7, [r3, :64], \rx +.endm + +.macro scale out0, out1, out2, out3, out4, out5, out6, out7, in0, in1, in2, in3, in4, in5, in6, in7, shift + vqrshrn.s32 \out0, \in0, \shift + vqrshrn.s32 \out1, \in1, \shift + vqrshrn.s32 \out2, \in2, \shift + vqrshrn.s32 \out3, \in3, \shift + vqrshrn.s32 \out4, \in4, \shift + vqrshrn.s32 \out5, \in5, \shift + vqrshrn.s32 \out6, \in6, \shift + vqrshrn.s32 \out7, \in7, \shift +.endm + +@stores in1, in2, in4, in6 ascending from off1 and +@stores in1, in3, in5, in7 descending from off2 +.macro store_to_stack off1, off2, in0, in2, in4, in6, in7, in5, in3, in1 + add r1, sp, #\off1 + add r3, sp, #\off2 + mov r2, #-16 + vst1.s32 {\in0}, [r1, :128]! + vst1.s32 {\in1}, [r3, :128], r2 + vst1.s32 {\in2}, [r1, :128]! + vst1.s32 {\in3}, [r3, :128], r2 + vst1.s32 {\in4}, [r1, :128]! + vst1.s32 {\in5}, [r3, :128], r2 + vst1.s32 {\in6}, [r1, :128] + vst1.s32 {\in7}, [r3, :128] +.endm + +.macro tr_16x4 name, shift, offset, step +function func_tr_16x4_\name + mov r1, r5 + add r3, r5, #(\step * 64) + mov r2, #(\step * 128) + load16 d0, d1, d2, d3, d4, d5, d6, d7 + movrel r1, trans + + tr16_8x4 d0, d1, d2, d3, d4, d5, d6, d7, \offset + + add r1, r5, #(\step * 32) + add r3, r5, #(\step * 3 *32) + mov r2, #(\step * 128) + load16 d8, d9, d2, d3, d4, d5, d6, d7 + movrel r1, trans + 16 + vld1.s16 {q0}, [r1, :128] + vmull.s16 q5, d8, d0[0] + vmull.s16 q6, d8, d0[1] + vmull.s16 q7, d8, d0[2] + vmull.s16 q8, d8, d0[3] + vmull.s16 q9, d8, d1[0] + vmull.s16 q10, d8, d1[1] + vmull.s16 q11, d8, d1[2] + vmull.s16 q12, d8, d1[3] + + add_member d9, d0[1], d1[0], d1[3], d1[1], d0[2], d0[0], d0[3], d1[2], +, +, +, -, -, -, -, - + add_member d2, d0[2], d1[3], d0[3], d0[1], d1[2], d1[0], d0[0], d1[1], +, +, -, -, -, +, +, + + add_member d3, d0[3], d1[1], d0[1], d1[3], d0[0], d1[2], d0[2], d1[0], +, -, -, +, +, +, -, - + add_member d4, d1[0], d0[2], d1[2], d0[0], d1[3], d0[1], d1[1], d0[3], +, -, -, +, -, -, +, + + add_member d5, d1[1], d0[0], d1[0], d1[2], d0[1], d0[3], d1[3], d0[2], +, -, +, +, -, +, +, - + add_member d6, d1[2], d0[3], d0[0], d0[2], d1[1], d1[3], d1[0], d0[1], +, -, +, -, +, +, -, + + add_member d7, d1[3], d1[2], d1[1], d1[0], d0[3], d0[2], d0[1], d0[0], +, -, +, -, +, -, +, - + + add r4, sp, #\offset + vld1.s32 {q0-q1}, [r4, :128]! + vld1.s32 {q2-q3}, [r4, :128]! + + butterfly16 q0, q5, q1, q6, q2, q7, q3, q8 + .if \shift > 0 + scale d26, d27, d28, d29, d30, d31, d16, d17, q4, q0, q5, q1, q6, q2, q7, q3, \shift + transpose8_4x4 d26, d28, d30, d16 + transpose8_4x4 d17, d31, d29, d27 + mov r1, r6 + add r3, r6, #(24 +3*32) + mov r2, #32 + mov r4, #-32 + store16 d26, d27, d28, d29, d30, d31, d16, d17, r4 + .else + store_to_stack \offset, (\offset + 240), q4, q5, q6, q7, q3, q2, q1, q0 + .endif + + add r4, sp, #(\offset + 64) + vld1.s32 {q0-q1}, [r4, :128]! + vld1.s32 {q2-q3}, [r4, :128] + butterfly16 q0, q9, q1, q10, q2, q11, q3, q12 + .if \shift > 0 + scale d26, d27, d28, d29, d30, d31, d8, d9, q4, q0, q9, q1, q10, q2, q11, q3, \shift + transpose8_4x4 d26, d28, d30, d8 + transpose8_4x4 d9, d31, d29, d27 + + add r1, r6, #8 + add r3, r6, #(16 + 3 * 32) + mov r2, #32 + mov r4, #-32 + store16 d26, d27, d28, d29, d30, d31, d8, d9, r4 + .else + store_to_stack (\offset + 64), (\offset + 176), q4, q9, q10, q11, q3, q2, q1, q0 + .endif + + bx lr +endfunc +.endm + +.macro idct_16x16 bitdepth +function ff_hevc_idct_16x16_\bitdepth\()_neon, export=1 +@r0 - coeffs + push {r4-r7, lr} + vpush {q4-q7} + + @ Align the stack, allocate a temp buffer +T mov r7, sp +T and r7, r7, #15 +A and r7, sp, #15 + add r7, r7, #640 + sub sp, sp, r7 + +.irp i, 0, 1, 2, 3 + add r5, r0, #(8 * \i) + add r6, sp, #(8 * \i * 16) + bl func_tr_16x4_firstpass +.endr + +.irp i, 0, 1, 2, 3 + add r5, sp, #(8 * \i) + add r6, r0, #(8 * \i * 16) + bl func_tr_16x4_secondpass_\bitdepth +.endr + + add sp, sp, r7 + + vpop {q4-q7} + pop {r4-r7, pc} endfunc +.endm + +.macro load32 + add r1, r5, #64 + add r3, r1, #128 + mov r2, #256 + vld1.s16 {d4}, [r1, :64], r2 + vld1.s16 {d5}, [r3, :64], r2 + vld1.s16 {d6}, [r1, :64], r2 + vld1.s16 {d7}, [r3, :64], r2 + vld1.s16 {d8}, [r1, :64], r2 + vld1.s16 {d9}, [r3, :64], r2 + vld1.s16 {d10}, [r1, :64], r2 + vld1.s16 {d11}, [r3, :64], r2 + vld1.s16 {d12}, [r1, :64], r2 + vld1.s16 {d13}, [r3, :64], r2 + vld1.s16 {d14}, [r1, :64], r2 + vld1.s16 {d15}, [r3, :64], r2 + vld1.s16 {d16}, [r1, :64], r2 + vld1.s16 {d17}, [r3, :64], r2 + vld1.s16 {d18}, [r1, :64], r2 + vld1.s16 {d19}, [r3, :64], r2 +.endm + +.macro add_member32 in, t0, t1, t2, t3, op0, op1, op2, op3 + sum_sub q10, \in, \t0, \op0 + sum_sub q11, \in, \t1, \op1 + sum_sub q12, \in, \t2, \op2 + sum_sub q13, \in, \t3, \op3 +.endm + +.macro butterfly32 in0, in1, in2, in3 + vadd.s32 q1, \in0, \in1 + vsub.s32 \in0, \in0, \in1 + vadd.s32 \in1, \in2, \in3 + vsub.s32 \in2, \in2, \in3 +.endm + +.macro scale32 out0, out1, out2, out3, in0, in1, in2, in3, shift + vqrshrn.s32 \out0, \in0, \shift + vqrshrn.s32 \out1, \in1, \shift + vqrshrn.s32 \out2, \in2, \shift + vqrshrn.s32 \out3, \in3, \shift +.endm + +.macro multiply in + vmull.s16 q10, d4, \in[0] + vmull.s16 q11, d4, \in[1] + vmull.s16 q12, d4, \in[2] + vmull.s16 q13, d4, \in[3] +.endm -function ff_hevc_add_residual_16x16_neon_8, export=1 - mov r3, #16 -1: subs r3, #1 - vld1.16 {q0, q1}, [r1]! - vld1.8 {q8}, [r0] - vmovl.u8 q9, d16 - vmovl.u8 q10, d17 - vqadd.s16 q0, q9 - vqadd.s16 q1, q10 - vqmovun.s16 d0, q0 - vqmovun.s16 d1, q1 - vst1.8 {q0}, [r0], r2 - bne 1b - bx lr +.macro scale_store shift + vld1.s16 {q14-q15}, [r4, :128]! + butterfly32 q14, q10, q15, q11 + scale32 d22, d23, d20, d21, q1, q14, q10, q15, \shift + + vld1.s16 {q14-q15}, [r4, :128]! + butterfly32 q14, q12, q15, q13 + scale32 d2, d3, d28, d29, q1, q14, q12, q15, \shift + transpose8_4x4 d22, d20, d2, d28 + transpose8_4x4 d29, d3, d21, d23 + store16 d22, d23, d20, d21, d2, d3, d28, d29, r8 + + @ reload multiplication coefficiens to q1 + vld1.s16 {q1}, [r9, :128] +.endm + +function tr_block1 + multiply d0 + add_member32 d5, d0[1], d1[0], d1[3], d2[2], +, +, +, + + add_member32 d6, d0[2], d1[3], d3[0], d3[2], +, +, +, - + add_member32 d7, d0[3], d2[2], d3[2], d1[3], +, +, -, - + add_member32 d8, d1[0], d3[1], d2[1], d0[0], +, +, -, - + add_member32 d9, d1[1], d3[3], d1[0], d1[2], +, -, -, - + add_member32 d10, d1[2], d3[0], d0[0], d3[1], +, -, -, - + add_member32 d11, d1[3], d2[1], d1[1], d2[3], +, -, -, + + add_member32 d12, d2[0], d1[2], d2[2], d1[0], +, -, -, + + add_member32 d13, d2[1], d0[3], d3[3], d0[2], +, -, -, + + add_member32 d14, d2[2], d0[1], d2[3], d2[1], +, -, +, + + add_member32 d15, d2[3], d0[2], d1[2], d3[3], +, -, +, - + add_member32 d16, d3[0], d1[1], d0[1], d2[0], +, -, +, - + add_member32 d17, d3[1], d2[0], d0[3], d0[1], +, -, +, - + add_member32 d18, d3[2], d2[3], d2[0], d1[1], +, -, +, - + add_member32 d19, d3[3], d3[2], d3[1], d3[0], +, -, +, - + bx lr +endfunc + +function tr_block2 + multiply d1 + add_member32 d5, d3[1], d3[3], d3[0], d2[1], +, -, -, - + add_member32 d6, d2[1], d1[0], d0[0], d1[1], -, -, -, - + add_member32 d7, d0[0], d1[2], d3[1], d2[3], -, -, -, + + add_member32 d8, d2[0], d3[2], d1[1], d0[3], -, +, +, + + add_member32 d9, d3[2], d0[3], d1[3], d3[1], +, +, +, - + add_member32 d10, d1[1], d1[3], d2[3], d0[0], +, +, -, - + add_member32 d11, d0[3], d3[1], d0[1], d3[3], +, -, -, + + add_member32 d12, d3[0], d0[2], d3[2], d0[1], +, -, -, + + add_member32 d13, d2[2], d2[0], d1[0], d3[2], -, -, +, + + add_member32 d14, d0[1], d3[0], d2[0], d0[2], -, +, +, - + add_member32 d15, d1[3], d0[1], d2[2], d3[0], -, +, -, - + add_member32 d16, d3[3], d2[1], d0[2], d1[0], +, +, -, + + add_member32 d17, d1[2], d2[3], d3[3], d2[2], +, -, -, + + add_member32 d18, d0[2], d0[1], d0[3], d1[2], +, -, +, - + add_member32 d19, d2[3], d2[2], d2[1], d2[0], +, -, +, - + bx lr +endfunc + +function tr_block3 + multiply d2 + add_member32 d5, d1[2], d0[3], d0[0], d0[2], -, -, -, - + add_member32 d6, d2[2], d3[3], d2[3], d1[2], -, -, +, + + add_member32 d7, d1[0], d0[2], d2[1], d3[3], +, +, +, - + add_member32 d8, d3[0], d2[2], d0[1], d1[3], +, -, -, - + add_member32 d9, d0[2], d2[0], d3[0], d0[0], -, -, +, + + add_member32 d10, d3[2], d1[0], d2[0], d2[2], -, +, +, - + add_member32 d11, d0[0], d3[2], d0[2], d3[0], +, +, -, - + add_member32 d12, d3[3], d0[1], d3[1], d0[3], -, -, +, + + add_member32 d13, d0[1], d2[3], d1[3], d1[1], -, +, +, - + add_member32 d14, d3[1], d1[3], d0[3], d3[2], +, +, -, + + add_member32 d15, d0[3], d1[1], d3[2], d2[0], +, -, +, + + add_member32 d16, d2[3], d3[1], d1[2], d0[1], -, -, +, - + add_member32 d17, d1[1], d0[0], d1[0], d2[1], -, +, -, + + add_member32 d18, d2[1], d3[0], d3[3], d3[1], +, -, +, + + add_member32 d19, d1[3], d1[2], d1[1], d1[0], +, -, +, - + bx lr endfunc -function ff_hevc_add_residual_32x32_neon_8, export=1 - mov r3, #32 -1: subs r3, #1 - vldm r1!, {q0-q3} - vld1.8 {q8, q9}, [r0] - vmovl.u8 q10, d16 - vmovl.u8 q11, d17 - vmovl.u8 q12, d18 - vmovl.u8 q13, d19 - vqadd.s16 q0, q10 - vqadd.s16 q1, q11 - vqadd.s16 q2, q12 - vqadd.s16 q3, q13 - vqmovun.s16 d0, q0 - vqmovun.s16 d1, q1 - vqmovun.s16 d2, q2 - vqmovun.s16 d3, q3 - vst1.8 {q0, q1}, [r0], r2 - bne 1b - bx lr +function tr_block4 + multiply d3 + add_member32 d5, d1[1], d2[0], d2[3], d3[2], -, -, -, - + add_member32 d6, d0[0], d0[3], d2[0], d3[1], +, +, +, + + add_member32 d7, d2[0], d0[0], d1[1], d3[0], -, -, -, - + add_member32 d8, d3[3], d1[2], d0[2], d2[3], +, +, +, + + add_member32 d9, d2[1], d2[3], d0[0], d2[2], +, -, -, - + add_member32 d10, d0[2], d3[3], d0[3], d2[1], -, -, +, + + add_member32 d11, d1[0], d2[2], d1[2], d2[0], +, +, -, - + add_member32 d12, d2[3], d1[1], d2[1], d1[3], -, -, +, + + add_member32 d13, d3[1], d0[1], d3[0], d1[2], -, +, -, - + add_member32 d14, d1[2], d1[0], d3[3], d1[1], +, -, +, + + add_member32 d15, d0[1], d2[1], d3[1], d1[0], -, +, +, - + add_member32 d16, d1[3], d3[2], d2[2], d0[3], +, -, -, + + add_member32 d17, d3[2], d3[0], d1[3], d0[2], -, -, +, - + add_member32 d18, d2[2], d1[3], d1[0], d0[1], -, +, -, + + add_member32 d19, d0[3], d0[2], d0[1], d0[0], +, -, +, - + bx lr endfunc -.macro transpose_16b_8x8 r0, r1, r2, r3, r4, r5, r6, r7 - vtrn.64 \r0, \r4 - vtrn.64 \r1, \r5 - vtrn.64 \r2, \r6 - vtrn.64 \r3, \r7 - vtrn.32 \r0, \r2 - vtrn.32 \r1, \r3 - vtrn.32 \r4, \r6 - vtrn.32 \r5, \r7 - vtrn.16 \r0, \r1 - vtrn.16 \r2, \r3 - vtrn.16 \r4, \r5 - vtrn.16 \r6, \r7 -.endm - -// in 4 q regs -// output 8 d regs -.macro transpose_16b_4x4 r0, r1, r2, r3 - vtrn.32 \r0, \r2 - vtrn.32 \r1, \r3 - vtrn.16 \r0, \r1 - vtrn.16 \r2, \r3 +.macro tr_32x4 name, shift +function func_tr_32x4_\name + mov r10, lr + bl func_tr_16x4_noscale + + load32 + movrel r9, trans + 32 + vld1.s16 {q0}, [r9, :128]! + vld1.s16 {q1}, [r9, :128] + + bl tr_block1 + + add r4, sp, #2048 + vld1.s16 {q14-q15}, [r4, :128]! + butterfly32 q14, q10, q15, q11 + scale32 d22, d23, d20, d21, q1, q14, q10, q15, \shift + + vld1.s16 {q14-q15}, [r4, :128]! + butterfly32 q14, q12, q15, q13 + scale32 d2, d3, d28, d29, q1, q14, q12, q15, \shift + + transpose8_4x4 d22, d20, d2, d28 + transpose8_4x4 d29, d3, d21, d23 + mov r1, r11 + mov r2, #64 + mov r8, #-64 + add r3, r11, #(56 + 3 * 64) + store16 d22, d23, d20, d21, d2, d3, d28, d29, r8 + + @ reload multiplication coefficiens to q1 + vld1.s16 {q1}, [r9, :128] + + bl tr_block2 + add r1, r11, #8 + add r3, r11, #(48 + 3 * 64) + mov r2, #64 + mov r8, #-64 + scale_store \shift + + bl tr_block3 + add r1, r11, #16 + add r3, r11, #(40 + 3 * 64) + mov r2, #64 + mov r8, #-64 + scale_store \shift + + bl tr_block4 + add r1, r11, #24 + add r3, r11, #(32 + 3 * 64) + mov r2, #64 + mov r8, #-64 + scale_store \shift + + bx r10 +endfunc .endm +.macro idct_32x32 bitdepth +function ff_hevc_idct_32x32_\bitdepth\()_neon, export=1 +@r0 - coeffs + push {r4-r11, lr} + vpush {q4-q7} + + @ Align the stack, allocate a temp buffer +T mov r7, sp +T and r7, r7, #15 +A and r7, sp, #15 + add r7, r7, #2432 + sub sp, sp, r7 + +.irp i, 0, 1, 2, 3, 4, 5, 6, 7 + add r5, r0, #(8 * \i) + add r11, sp, #(8 * \i * 32) + bl func_tr_32x4_firstpass +.endr + +.irp i, 0, 1, 2, 3, 4, 5, 6, 7 + add r5, sp, #(8 * \i) + add r11, r0, #(8 * \i * 32) + bl func_tr_32x4_secondpass_\bitdepth +.endr + + add sp, sp, r7 + vpop {q4-q7} + pop {r4-r11, pc} +endfunc +.endm + +tr_16x4 firstpass, 7, 512, 1 +tr_16x4 secondpass_8, 20 - 8, 512, 1 +tr_16x4 secondpass_10, 20 - 10, 512, 1 +tr_16x4 noscale, 0, 2048, 4 +.ltorg +tr_32x4 firstpass, 7 +tr_32x4 secondpass_8, 20 - 8 +tr_32x4 secondpass_10, 20 - 10 +.ltorg + +idct_4x4 8 +idct_4x4_dc 8 +idct_4x4 10 +idct_4x4_dc 10 +idct_8x8 8 +idct_8x8_dc 8 +idct_8x8 10 +idct_8x8_dc 10 +idct_16x16 8 +idct_16x16_dc 8 +idct_16x16 10 +idct_16x16_dc 10 +idct_32x32 8 +idct_32x32_dc 8 +idct_32x32 10 +idct_32x32_dc 10 + /* uses registers q2 - q9 for temp values */ /* TODO: reorder */ .macro tr4_luma_shift r0, r1, r2, r3, shift @@ -225,67 +1015,7 @@ endfunc vqrshrn.s32 \r3, q5, \shift .endm -/* uses registers q2 - q6 for temp values */ -.macro tr4 r0, r1, r2, r3 - vmull.s16 q4, \r1, d0[0] // 83 * src1 - vmull.s16 q6, \r1, d0[1] // 36 * src1 - vshll.s16 q2, \r0, #6 // 64 * src0 - vshll.s16 q3, \r2, #6 // 64 * src2 - vadd.s32 q5, q2, q3 // 64 * (src0 + src2) e0 - vsub.s32 q2, q2, q3 // 64 * (src0 - src2) e1 - vmlal.s16 q4, \r3, d0[1] // 83 * src1 + 36 * src3 o0 - vmlsl.s16 q6, \r3, d0[0] // 36 * src1 - 83 * src3 o1 - - vsub.s32 q3, q5, q4 // e0 - o0 - vadd.s32 q4, q5, q4 // e0 + o0 - vadd.s32 q5, q2, q6 // e1 + o1 - vsub.s32 q6, q2, q6 // e1 - o1 -.endm - -.macro tr4_shift r0, r1, r2, r3, shift - vmull.s16 q4, \r1, d0[0] // 83 * src1 - vmull.s16 q6, \r1, d0[1] // 36 * src1 - vshll.s16 q2, \r0, #6 // 64 * src0 - vshll.s16 q3, \r2, #6 // 64 * src2 - vadd.s32 q5, q2, q3 // 64 * (src0 + src2) e0 - vsub.s32 q2, q2, q3 // 64 * (src0 - src2) e1 - vmlal.s16 q4, \r3, d0[1] // 83 * src1 + 36 * src3 o0 - vmlsl.s16 q6, \r3, d0[0] // 36 * src1 - 83 * src3 o1 - - vsub.s32 q3, q5, q4 // e0 - o0 - vadd.s32 q4, q5, q4 // e0 + o0 - vadd.s32 q5, q2, q6 // e1 + o1 - vsub.s32 q6, q2, q6 // e1 - o1 - - vqrshrn.s32 \r0, q4, \shift - vqrshrn.s32 \r1, q5, \shift - vqrshrn.s32 \r2, q6, \shift - vqrshrn.s32 \r3, q3, \shift -.endm - -function ff_hevc_transform_4x4_neon_8, export=1 - vpush {d8-d15} - vld1.16 {q14, q15}, [r0] // coeffs - ldr r3, =0x00240053 // 36 and 83 - vmov.32 d0[0], r3 - - tr4_shift d28, d29, d30, d31, #7 - - vtrn.16 d28, d29 - vtrn.16 d30, d31 - vtrn.32 q14, q15 - - tr4_shift d28, d29, d30, d31, #12 - - vtrn.16 d28, d29 - vtrn.16 d30, d31 - vtrn.32 q14, q15 - - vst1.16 {q14, q15}, [r0] - vpop {d8-d15} - bx lr -endfunc - +.ltorg function ff_hevc_transform_luma_4x4_neon_8, export=1 vpush {d8-d15} vld1.16 {q14, q15}, [r0] // coeffs @@ -311,155 +1041,3 @@ function ff_hevc_transform_luma_4x4_neon_8, export=1 vpop {d8-d15} bx lr endfunc - -.macro tr8_begin in0, in1, in2, in3 - vmull.s16 q7, \in0, d1[1] // 89 * src1 - vmull.s16 q8, \in0, d1[0] // 75 * src1 - vmull.s16 q9, \in0, d1[3] // 50 * src1 - vmull.s16 q10, \in0, d1[2] // 18 * src1 - - vmlal.s16 q7, \in1, d1[0] // 75 * src3 - vmlsl.s16 q8, \in1, d1[2] //-18 * src3 - vmlsl.s16 q9, \in1, d1[1] //-89 * src3 - vmlsl.s16 q10, \in1, d1[3] //-50 * src3 - - vmlal.s16 q7, \in2, d1[3] // 50 * src5 - vmlsl.s16 q8, \in2, d1[1] //-89 * src5 - vmlal.s16 q9, \in2, d1[2] // 18 * src5 - vmlal.s16 q10, \in2, d1[0] // 75 * src5 - - vmlal.s16 q7, \in3, d1[2] // 18 * src7 - vmlsl.s16 q8, \in3, d1[3] //-50 * src7 - vmlal.s16 q9, \in3, d1[0] // 75 * src7 - vmlsl.s16 q10, \in3, d1[1] //-89 * src7 -.endm - -.macro tr8_end shift - vadd.s32 q1, q4, q7 // e_8[0] + o_8[0], dst[0] - vsub.s32 q4, q4, q7 // e_8[0] - o_8[0], dst[7] - - vadd.s32 q2, q5, q8 // e_8[1] + o_8[1], dst[1] - vsub.s32 q5, q5, q8 // e_8[1] - o_8[1], dst[6] - - vadd.s32 q11, q6, q9 // e_8[2] + o_8[2], dst[2] - vsub.s32 q6, q6, q9 // e_8[2] - o_8[2], dst[5] - - vadd.s32 q12, q3, q10 // e_8[3] + o_8[3], dst[3] - vsub.s32 q3, q3, q10 // e_8[3] - o_8[3], dst[4] - vqrshrn.s32 d2, q1, \shift - vqrshrn.s32 d3, q2, \shift - vqrshrn.s32 d4, q11, \shift - vqrshrn.s32 d5, q12, \shift - vqrshrn.s32 d6, q3, \shift - vqrshrn.s32 d7, q6, \shift - vqrshrn.s32 d9, q4, \shift - vqrshrn.s32 d8, q5, \shift -.endm - -function ff_hevc_transform_8x8_neon_8, export=1 - push {r4-r8} - vpush {d8-d15} - mov r5, #16 - - adr r3, tr4f - vld1.16 {d0, d1}, [r3] - - // left half - vld1.16 {d24}, [r0], r5 - vld1.16 {d25}, [r0], r5 - vld1.16 {d26}, [r0], r5 - vld1.16 {d27}, [r0], r5 - vld1.16 {d28}, [r0], r5 - vld1.16 {d29}, [r0], r5 - vld1.16 {d30}, [r0], r5 - vld1.16 {d31}, [r0], r5 - sub r0, #128 - tr8_begin d25, d27, d29, d31 - tr4 d24, d26, d28, d30 - tr8_end #7 - vst1.16 {d2}, [r0], r5 - vst1.16 {d3}, [r0], r5 - vst1.16 {d4}, [r0], r5 - vst1.16 {d5}, [r0], r5 - vst1.16 {d6}, [r0], r5 - vst1.16 {d7}, [r0], r5 - vst1.16 {d8}, [r0], r5 - vst1.16 {d9}, [r0], r5 - sub r0, #128 - //skip right half if col_limit in r1 is less than 4 - cmp r1, #4 - blt 1f - //right half - add r0, #8 - vld1.16 {d24}, [r0], r5 - vld1.16 {d25}, [r0], r5 - vld1.16 {d26}, [r0], r5 - vld1.16 {d27}, [r0], r5 - vld1.16 {d28}, [r0], r5 - vld1.16 {d29}, [r0], r5 - vld1.16 {d30}, [r0], r5 - vld1.16 {d31}, [r0], r5 - sub r0, #128 - tr8_begin d25, d27, d29, d31 - tr4 d24, d26, d28, d30 - tr8_end #7 - vst1.16 {d2}, [r0], r5 - vst1.16 {d3}, [r0], r5 - vst1.16 {d4}, [r0], r5 - vst1.16 {d5}, [r0], r5 - vst1.16 {d6}, [r0], r5 - vst1.16 {d7}, [r0], r5 - vst1.16 {d8}, [r0], r5 - vst1.16 {d9}, [r0], r5 - sub r0, #136 -1: - // top half - vldm r0, {q12-q15} // coeffs - transpose_16b_4x4 d24, d26, d28, d30 - transpose_16b_4x4 d25, d27, d29, d31 - tr8_begin d26, d30, d27, d31 - tr4 d24, d28, d25, d29 - tr8_end #12 - transpose_16b_4x4 d2, d3, d4, d5 - transpose_16b_4x4 d6, d7, d8, d9 - vswp d7, d5 - vswp d7, d8 - vswp d3, d6 - vswp d6, d4 - vstm r0!, {q1-q4} - - // bottom half - vldm r0, {q12-q15} // coeffs - transpose_16b_4x4 d24, d26, d28, d30 - transpose_16b_4x4 d25, d27, d29, d31 - tr8_begin d26, d30, d27, d31 - tr4 d24, d28, d25, d29 - tr8_end #12 - transpose_16b_4x4 d2, d3, d4, d5 - transpose_16b_4x4 d6, d7, d8, d9 - vswp d7, d5 - vswp d7, d8 - vswp d3, d6 - vswp d6, d4 - //vstm r0, {q1-q4} - vst1.16 {q1-q2}, [r0] - add r0, #32 - vst1.16 {q3-q4}, [r0] - sub r0, #32 - vpop {d8-d15} - pop {r4-r8} - bx lr -endfunc - -.align 4 -tr4f: -.word 0x00240053 // 36 and d1[0] = 83 -.word 0x00000000 -tr8f: -.word 0x0059004b // 89, d0[0] = 75 -.word 0x00320012 // 50, d0[2] = 18 -tr16: -.word 0x005a0057 // 90, d2[0] = 87 -.word 0x00500046 // 80, d2[2] = 70 -.word 0x0039002b // 57, d2[0] = 43 -.word 0x00190009 // 25, d2[2] = 9 diff --git a/libavcodec/arm/hevcdsp_init_arm.c b/libavcodec/arm/hevcdsp_init_arm.c index adcc454511169..e8fa1f79acbc0 100644 --- a/libavcodec/arm/hevcdsp_init_arm.c +++ b/libavcodec/arm/hevcdsp_init_arm.c @@ -19,14 +19,16 @@ */ #include "libavutil/attributes.h" +#include "libavutil/cpu.h" #include "libavutil/arm/cpu.h" + #include "libavcodec/hevcdsp.h" #include "hevcdsp_arm.h" -av_cold void ff_hevcdsp_init_arm(HEVCDSPContext *c, const int bit_depth) +av_cold void ff_hevc_dsp_init_arm(HEVCDSPContext *c, const int bit_depth) { int cpu_flags = av_get_cpu_flags(); if (have_neon(cpu_flags)) - ff_hevcdsp_init_neon(c, bit_depth); + ff_hevc_dsp_init_neon(c, bit_depth); } diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c index 1a3912c60979b..201a088dac056 100644 --- a/libavcodec/arm/hevcdsp_init_neon.c +++ b/libavcodec/arm/hevcdsp_init_neon.c @@ -21,27 +21,53 @@ #include "libavutil/attributes.h" #include "libavutil/arm/cpu.h" #include "libavcodec/hevcdsp.h" +#include "libavcodec/avcodec.h" #include "hevcdsp_arm.h" +void ff_hevc_sao_band_filter_neon_8_wrapper(uint8_t *_dst, uint8_t *_src, + ptrdiff_t stride_dst, ptrdiff_t stride_src, + int16_t *sao_offset_val, int sao_left_class, + int width, int height); +void ff_hevc_sao_edge_filter_neon_8_wrapper(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val, + int eo, int width, int height); + void ff_hevc_v_loop_filter_luma_neon(uint8_t *_pix, ptrdiff_t _stride, int _beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q); void ff_hevc_h_loop_filter_luma_neon(uint8_t *_pix, ptrdiff_t _stride, int _beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q); void ff_hevc_v_loop_filter_chroma_neon(uint8_t *_pix, ptrdiff_t _stride, int *_tc, uint8_t *_no_p, uint8_t *_no_q); void ff_hevc_h_loop_filter_chroma_neon(uint8_t *_pix, ptrdiff_t _stride, int *_tc, uint8_t *_no_p, uint8_t *_no_q); -void ff_hevc_transform_4x4_neon_8(int16_t *coeffs, int col_limit); -void ff_hevc_transform_8x8_neon_8(int16_t *coeffs, int col_limit); -void ff_hevc_idct_4x4_dc_neon_8(int16_t *coeffs); -void ff_hevc_idct_8x8_dc_neon_8(int16_t *coeffs); -void ff_hevc_idct_16x16_dc_neon_8(int16_t *coeffs); -void ff_hevc_idct_32x32_dc_neon_8(int16_t *coeffs); -void ff_hevc_transform_luma_4x4_neon_8(int16_t *coeffs); -void ff_hevc_add_residual_4x4_neon_8(uint8_t *_dst, int16_t *coeffs, +void ff_hevc_add_residual_4x4_8_neon(uint8_t *_dst, int16_t *coeffs, ptrdiff_t stride); -void ff_hevc_add_residual_8x8_neon_8(uint8_t *_dst, int16_t *coeffs, +void ff_hevc_add_residual_4x4_10_neon(uint8_t *_dst, int16_t *coeffs, + ptrdiff_t stride); +void ff_hevc_add_residual_8x8_8_neon(uint8_t *_dst, int16_t *coeffs, ptrdiff_t stride); -void ff_hevc_add_residual_16x16_neon_8(uint8_t *_dst, int16_t *coeffs, +void ff_hevc_add_residual_8x8_10_neon(uint8_t *_dst, int16_t *coeffs, + ptrdiff_t stride); +void ff_hevc_add_residual_16x16_8_neon(uint8_t *_dst, int16_t *coeffs, ptrdiff_t stride); -void ff_hevc_add_residual_32x32_neon_8(uint8_t *_dst, int16_t *coeffs, +void ff_hevc_add_residual_16x16_10_neon(uint8_t *_dst, int16_t *coeffs, + ptrdiff_t stride); +void ff_hevc_add_residual_32x32_8_neon(uint8_t *_dst, int16_t *coeffs, ptrdiff_t stride); +void ff_hevc_add_residual_32x32_10_neon(uint8_t *_dst, int16_t *coeffs, + ptrdiff_t stride); +void ff_hevc_idct_4x4_dc_8_neon(int16_t *coeffs); +void ff_hevc_idct_8x8_dc_8_neon(int16_t *coeffs); +void ff_hevc_idct_16x16_dc_8_neon(int16_t *coeffs); +void ff_hevc_idct_32x32_dc_8_neon(int16_t *coeffs); +void ff_hevc_idct_4x4_dc_10_neon(int16_t *coeffs); +void ff_hevc_idct_8x8_dc_10_neon(int16_t *coeffs); +void ff_hevc_idct_16x16_dc_10_neon(int16_t *coeffs); +void ff_hevc_idct_32x32_dc_10_neon(int16_t *coeffs); +void ff_hevc_idct_4x4_8_neon(int16_t *coeffs, int col_limit); +void ff_hevc_idct_8x8_8_neon(int16_t *coeffs, int col_limit); +void ff_hevc_idct_16x16_8_neon(int16_t *coeffs, int col_limit); +void ff_hevc_idct_32x32_8_neon(int16_t *coeffs, int col_limit); +void ff_hevc_idct_4x4_10_neon(int16_t *coeffs, int col_limit); +void ff_hevc_idct_8x8_10_neon(int16_t *coeffs, int col_limit); +void ff_hevc_idct_16x16_10_neon(int16_t *coeffs, int col_limit); +void ff_hevc_idct_32x32_10_neon(int16_t *coeffs, int col_limit); +void ff_hevc_transform_luma_4x4_neon_8(int16_t *coeffs); #define PUT_PIXELS(name) \ void name(int16_t *dst, uint8_t *src, \ @@ -124,6 +150,47 @@ QPEL_FUNC_UW(ff_hevc_put_qpel_uw_h3v2_neon_8); QPEL_FUNC_UW(ff_hevc_put_qpel_uw_h3v3_neon_8); #undef QPEL_FUNC_UW +void ff_hevc_sao_band_filter_neon_8(uint8_t *dst, uint8_t *src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int width, int height, int16_t *offset_table); + +void ff_hevc_sao_band_filter_neon_8_wrapper(uint8_t *_dst, uint8_t *_src, + ptrdiff_t stride_dst, ptrdiff_t stride_src, + int16_t *sao_offset_val, int sao_left_class, + int width, int height) { + uint8_t *dst = _dst; + uint8_t *src = _src; + int16_t offset_table[32] = {0}; + int k; + + for (k = 0; k < 4; k++) { + offset_table[(k + sao_left_class) & 31] = sao_offset_val[k + 1]; + } + + ff_hevc_sao_band_filter_neon_8(dst, src, stride_dst, stride_src, width, height, offset_table); +} + +void ff_hevc_sao_edge_filter_neon_8(uint8_t *dst, uint8_t *src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int width, int height, + int a_stride, int b_stride, int16_t *sao_offset_val, uint8_t *edge_idx); + +void ff_hevc_sao_edge_filter_neon_8_wrapper(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, int16_t *sao_offset_val, + int eo, int width, int height) { + static uint8_t edge_idx[] = { 1, 2, 0, 3, 4 }; + static const int8_t pos[4][2][2] = { + { { -1, 0 }, { 1, 0 } }, // horizontal + { { 0, -1 }, { 0, 1 } }, // vertical + { { -1, -1 }, { 1, 1 } }, // 45 degree + { { 1, -1 }, { -1, 1 } }, // 135 degree + }; + uint8_t *dst = _dst; + uint8_t *src = _src; + int a_stride, b_stride; + ptrdiff_t stride_src = (2*MAX_PB_SIZE + AV_INPUT_BUFFER_PADDING_SIZE); + + a_stride = pos[eo][0][0] + pos[eo][0][1] * stride_src; + b_stride = pos[eo][1][0] + pos[eo][1][1] * stride_src; + + ff_hevc_sao_edge_filter_neon_8(dst, src, stride_dst, stride_src, width, height, a_stride, b_stride, sao_offset_val, edge_idx); +} + void ff_hevc_put_qpel_neon_wrapper(int16_t *dst, uint8_t *src, ptrdiff_t srcstride, int height, intptr_t mx, intptr_t my, int width) { @@ -142,7 +209,7 @@ void ff_hevc_put_qpel_bi_neon_wrapper(uint8_t *dst, ptrdiff_t dststride, uint8_t put_hevc_qpel_uw_neon[my][mx](dst, dststride, src, srcstride, width, height, src2, MAX_PB_SIZE); } -av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth) +av_cold void ff_hevc_dsp_init_neon(HEVCDSPContext *c, const int bit_depth) { if (bit_depth == 8) { int x; @@ -150,16 +217,28 @@ av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth) c->hevc_h_loop_filter_luma = ff_hevc_h_loop_filter_luma_neon; c->hevc_v_loop_filter_chroma = ff_hevc_v_loop_filter_chroma_neon; c->hevc_h_loop_filter_chroma = ff_hevc_h_loop_filter_chroma_neon; - c->idct[0] = ff_hevc_transform_4x4_neon_8; - c->idct[1] = ff_hevc_transform_8x8_neon_8; - c->idct_dc[0] = ff_hevc_idct_4x4_dc_neon_8; - c->idct_dc[1] = ff_hevc_idct_8x8_dc_neon_8; - c->idct_dc[2] = ff_hevc_idct_16x16_dc_neon_8; - c->idct_dc[3] = ff_hevc_idct_32x32_dc_neon_8; - c->add_residual[0] = ff_hevc_add_residual_4x4_neon_8; - c->add_residual[1] = ff_hevc_add_residual_8x8_neon_8; - c->add_residual[2] = ff_hevc_add_residual_16x16_neon_8; - c->add_residual[3] = ff_hevc_add_residual_32x32_neon_8; + c->sao_band_filter[0] = ff_hevc_sao_band_filter_neon_8_wrapper; + c->sao_band_filter[1] = ff_hevc_sao_band_filter_neon_8_wrapper; + c->sao_band_filter[2] = ff_hevc_sao_band_filter_neon_8_wrapper; + c->sao_band_filter[3] = ff_hevc_sao_band_filter_neon_8_wrapper; + c->sao_band_filter[4] = ff_hevc_sao_band_filter_neon_8_wrapper; + c->sao_edge_filter[0] = ff_hevc_sao_edge_filter_neon_8_wrapper; + c->sao_edge_filter[1] = ff_hevc_sao_edge_filter_neon_8_wrapper; + c->sao_edge_filter[2] = ff_hevc_sao_edge_filter_neon_8_wrapper; + c->sao_edge_filter[3] = ff_hevc_sao_edge_filter_neon_8_wrapper; + c->sao_edge_filter[4] = ff_hevc_sao_edge_filter_neon_8_wrapper; + c->add_residual[0] = ff_hevc_add_residual_4x4_8_neon; + c->add_residual[1] = ff_hevc_add_residual_8x8_8_neon; + c->add_residual[2] = ff_hevc_add_residual_16x16_8_neon; + c->add_residual[3] = ff_hevc_add_residual_32x32_8_neon; + c->idct_dc[0] = ff_hevc_idct_4x4_dc_8_neon; + c->idct_dc[1] = ff_hevc_idct_8x8_dc_8_neon; + c->idct_dc[2] = ff_hevc_idct_16x16_dc_8_neon; + c->idct_dc[3] = ff_hevc_idct_32x32_dc_8_neon; + c->idct[0] = ff_hevc_idct_4x4_8_neon; + c->idct[1] = ff_hevc_idct_8x8_8_neon; + c->idct[2] = ff_hevc_idct_16x16_8_neon; + c->idct[3] = ff_hevc_idct_32x32_8_neon; c->transform_4x4_luma = ff_hevc_transform_luma_4x4_neon_8; put_hevc_qpel_neon[1][0] = ff_hevc_put_qpel_v1_neon_8; put_hevc_qpel_neon[2][0] = ff_hevc_put_qpel_v2_neon_8; @@ -221,4 +300,21 @@ av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth) c->put_hevc_qpel_uni[8][0][0] = ff_hevc_put_qpel_uw_pixels_w48_neon_8; c->put_hevc_qpel_uni[9][0][0] = ff_hevc_put_qpel_uw_pixels_w64_neon_8; } + + if (bit_depth == 10) { + c->add_residual[0] = ff_hevc_add_residual_4x4_10_neon; + c->add_residual[1] = ff_hevc_add_residual_8x8_10_neon; + c->add_residual[2] = ff_hevc_add_residual_16x16_10_neon; + c->add_residual[3] = ff_hevc_add_residual_32x32_10_neon; + + c->idct_dc[0] = ff_hevc_idct_4x4_dc_10_neon; + c->idct_dc[1] = ff_hevc_idct_8x8_dc_10_neon; + c->idct_dc[2] = ff_hevc_idct_16x16_dc_10_neon; + c->idct_dc[3] = ff_hevc_idct_32x32_dc_10_neon; + + c->idct[0] = ff_hevc_idct_4x4_10_neon; + c->idct[1] = ff_hevc_idct_8x8_10_neon; + c->idct[2] = ff_hevc_idct_16x16_10_neon; + c->idct[3] = ff_hevc_idct_32x32_10_neon; + } } diff --git a/libavcodec/arm/hevcdsp_qpel_neon.S b/libavcodec/arm/hevcdsp_qpel_neon.S index 86f92cf75a31a..caa6efa7664b1 100644 --- a/libavcodec/arm/hevcdsp_qpel_neon.S +++ b/libavcodec/arm/hevcdsp_qpel_neon.S @@ -667,76 +667,76 @@ endfunc function ff_hevc_put_qpel_h1v1_neon_8, export=1 - hevc_put_qpel_hXvY_neon_8 qpel_filter_1 qpel_filter_1_32b + hevc_put_qpel_hXvY_neon_8 qpel_filter_1, qpel_filter_1_32b endfunc function ff_hevc_put_qpel_h2v1_neon_8, export=1 - hevc_put_qpel_hXvY_neon_8 qpel_filter_2 qpel_filter_1_32b + hevc_put_qpel_hXvY_neon_8 qpel_filter_2, qpel_filter_1_32b endfunc function ff_hevc_put_qpel_h3v1_neon_8, export=1 - hevc_put_qpel_hXvY_neon_8 qpel_filter_3 qpel_filter_1_32b + hevc_put_qpel_hXvY_neon_8 qpel_filter_3, qpel_filter_1_32b endfunc function ff_hevc_put_qpel_h1v2_neon_8, export=1 - hevc_put_qpel_hXvY_neon_8 qpel_filter_1 qpel_filter_2_32b + hevc_put_qpel_hXvY_neon_8 qpel_filter_1, qpel_filter_2_32b endfunc function ff_hevc_put_qpel_h2v2_neon_8, export=1 - hevc_put_qpel_hXvY_neon_8 qpel_filter_2 qpel_filter_2_32b + hevc_put_qpel_hXvY_neon_8 qpel_filter_2, qpel_filter_2_32b endfunc function ff_hevc_put_qpel_h3v2_neon_8, export=1 - hevc_put_qpel_hXvY_neon_8 qpel_filter_3 qpel_filter_2_32b + hevc_put_qpel_hXvY_neon_8 qpel_filter_3, qpel_filter_2_32b endfunc function ff_hevc_put_qpel_h1v3_neon_8, export=1 - hevc_put_qpel_hXvY_neon_8 qpel_filter_1 qpel_filter_3_32b + hevc_put_qpel_hXvY_neon_8 qpel_filter_1, qpel_filter_3_32b endfunc function ff_hevc_put_qpel_h2v3_neon_8, export=1 - hevc_put_qpel_hXvY_neon_8 qpel_filter_2 qpel_filter_3_32b + hevc_put_qpel_hXvY_neon_8 qpel_filter_2, qpel_filter_3_32b endfunc function ff_hevc_put_qpel_h3v3_neon_8, export=1 - hevc_put_qpel_hXvY_neon_8 qpel_filter_3 qpel_filter_3_32b + hevc_put_qpel_hXvY_neon_8 qpel_filter_3, qpel_filter_3_32b endfunc function ff_hevc_put_qpel_uw_h1v1_neon_8, export=1 - hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_1 qpel_filter_1_32b + hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_1, qpel_filter_1_32b endfunc function ff_hevc_put_qpel_uw_h2v1_neon_8, export=1 - hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_2 qpel_filter_1_32b + hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_2, qpel_filter_1_32b endfunc function ff_hevc_put_qpel_uw_h3v1_neon_8, export=1 - hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_3 qpel_filter_1_32b + hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_3, qpel_filter_1_32b endfunc function ff_hevc_put_qpel_uw_h1v2_neon_8, export=1 - hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_1 qpel_filter_2_32b + hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_1, qpel_filter_2_32b endfunc function ff_hevc_put_qpel_uw_h2v2_neon_8, export=1 - hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_2 qpel_filter_2_32b + hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_2, qpel_filter_2_32b endfunc function ff_hevc_put_qpel_uw_h3v2_neon_8, export=1 - hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_3 qpel_filter_2_32b + hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_3, qpel_filter_2_32b endfunc function ff_hevc_put_qpel_uw_h1v3_neon_8, export=1 - hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_1 qpel_filter_3_32b + hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_1, qpel_filter_3_32b endfunc function ff_hevc_put_qpel_uw_h2v3_neon_8, export=1 - hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_2 qpel_filter_3_32b + hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_2, qpel_filter_3_32b endfunc function ff_hevc_put_qpel_uw_h3v3_neon_8, export=1 - hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_3 qpel_filter_3_32b + hevc_put_qpel_uw_hXvY_neon_8 qpel_filter_3, qpel_filter_3_32b endfunc .macro init_put_pixels diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S new file mode 100644 index 0000000000000..347167951b7ec --- /dev/null +++ b/libavcodec/arm/hevcdsp_sao_neon.S @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2017 Meng Wang + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include "libavutil/arm/asm.S" +#include "neon.S" + +function ff_hevc_sao_band_filter_neon_8, export=1 + push {r4-r10} + ldr r5, [sp, #28] // width + ldr r4, [sp, #32] // height + ldr r8, [sp, #36] // offset_table + vpush {d8-d15} + mov r12, r4 // r12 = height + mov r6, r0 // r6 = r0 = dst + mov r7, r1 // r7 = r1 = src + vldm r8, {q0-q3} + vmov.u16 q15, #1 + vmov.u8 q14, #32 +0: pld [r1] + vld1.8 {d16}, [r1], r3 + cmp r5, #4 + beq 4f +8: subs r4, #1 + vshr.u8 d17, d16, #3 // index = [src>>3] + vshll.u8 q9, d17, #1 // lowIndex = 2*index + vadd.u16 q11, q9, q15 // highIndex = (2*index+1) << 8 + vshl.u16 q10, q11, #8 // q10: highIndex; q9: lowIndex; + vadd.u16 q10, q9 // combine high and low index; + // Look-up Table Round 1; index range: 0-15 + vtbx.8 d24, {q0-q1}, d20 + vtbx.8 d25, {q0-q1}, d21 + // Look-up Table Round 2; index range: 16-31 + vsub.u8 q10, q14 // Look-up with 8bit + vtbx.8 d24, {q2-q3}, d20 + vtbx.8 d25, {q2-q3}, d21 + vaddw.u8 q13, q12, d16 + vqmovun.s16 d8, q13 + vst1.8 d8, [r0], r2 + vld1.8 {d16}, [r1], r3 + bne 8b + subs r5, #8 + beq 99f + mov r4, r12 + add r6, #8 + mov r0, r6 + add r7, #8 + mov r1, r7 + b 0b +4: subs r4, #1 + vshr.u8 d17, d16, #3 // src>>3 + vshll.u8 q9, d17, #1 // lowIndex = 2*index + vadd.u16 q11, q9, q15 // highIndex = (2*index+1) << 8 + vshl.u16 q10, q11, #8 // q10: highIndex; q9: lowIndex; + vadd.u16 q10, q9 // combine high and low index; + // Look-up Table Round 1; index range: 0-15 + vtbx.8 d24, {q0-q1}, d20 + vtbx.8 d25, {q0-q1}, d21 + // Look-up Table Round 2; index range: 16-32 + vsub.u8 q10, q14 // Look-up with 8bit + vtbx.8 d24, {q2-q3}, d20 + vtbx.8 d25, {q2-q3}, d21 + vaddw.u8 q13, q12, d16 + vqmovun.s16 d14, q13 + vst1.32 d14[0], [r0], r2 + vld1.32 {d16[0]}, [r1], r3 + bne 4b + b 99f +99: + vpop {d8-d15} + pop {r4-r10} + bx lr +endfunc + +function ff_hevc_sao_edge_filter_neon_8, export=1 + push {r4-r11} + ldr r5, [sp, #32] // width + ldr r4, [sp, #36] // height + ldr r8, [sp, #40] // a_stride + ldr r9, [sp, #44] // b_stride + ldr r10, [sp, #48] // sao_offset_val + ldr r11, [sp, #52] // edge_idx + vpush {d8-d15} + mov r12, r4 // r12 = height + mov r6, r0 // r6 = r0 = dst + mov r7, r1 // r7 = r1 = src + vld1.8 {d0}, [r11] // edge_idx tabel load in d0 5x8bit + vld1.16 {q1}, [r10] // sao_offset_val table load in q1, 5x16bit + vmov.u8 d1, #2 + vmov.u16 q2, #1 +0: mov r10, r1 + add r10, r8 // src[x + a_stride] + mov r11, r1 + add r11, r9 // src[x + b_stride] + pld [r1] + vld1.8 {d16}, [r1], r3 // src[x] 8x8bit + vld1.8 {d17}, [r10], r3 // src[x + a_stride] + vld1.8 {d18}, [r11], r3 // src[x + b_stride] + cmp r5, #4 + beq 4f +8: subs r4, #1 + vcgt.u8 d8, d16, d17 + vshr.u8 d9, d8, #7 + vclt.u8 d8, d16, d17 + vadd.u8 d8, d9 // diff0 + vcgt.u8 d10, d16, d18 + vshr.u8 d11, d10, #7 + vclt.u8 d10, d16, d18 + vadd.u8 d10, d11 // diff1 + vadd.s8 d8, d10 + vadd.s8 d8, d1 + vtbx.8 d9, {d0}, d8 // offset_val + vshll.u8 q6, d9, #1 // lowIndex + vadd.u16 q7, q6, q2 + vshl.u16 q10, q7, #8 // highIndex + vadd.u16 q10, q6 // combine lowIndex and highIndex, offset_val + vtbx.8 d22, {q1}, d20 + vtbx.8 d23, {q1}, d21 + vaddw.u8 q12, q11, d16 + vqmovun.s16 d26, q12 + vst1.8 d26, [r0], r2 + vld1.8 {d16}, [r1], r3 // src[x] 8x8bit + vld1.8 {d17}, [r10], r3 // src[x + a_stride] + vld1.8 {d18}, [r11], r3 // src[x + b_stride] + bne 8b + subs r5, #8 + beq 99f + mov r4, r12 + add r6, #8 + mov r0, r6 + add r7, #8 + mov r1, r7 + b 0b +4: subs r4, #1 + vcgt.u8 d8, d16, d17 + vshr.u8 d9, d8, #7 + vclt.u8 d8, d16, d17 + vadd.u8 d8, d9 // diff0 + vcgt.u8 d10, d16, d18 + vshr.u8 d11, d10, #7 + vclt.u8 d10, d16, d18 + vadd.u8 d10, d11 // diff1 + vadd.s8 d8, d10 + vadd.s8 d8, d1 + vtbx.8 d9, {d0}, d8 // offset_val + vshll.u8 q6, d9, #1 // lowIndex + vadd.u16 q7, q6, q2 + vshl.u16 q10, q7, #8 // highIndex + vadd.u16 q10, q6 // combine lowIndex and highIndex, offset_val + vtbx.8 d22, {q1}, d20 + vtbx.8 d23, {q1}, d21 + vaddw.u8 q12, q11, d16 + vqmovun.s16 d26, q12 + vst1.32 d26[0], [r0], r2 + vld1.32 {d16[0]}, [r1], r3 + vld1.32 {d17[0]}, [r10], r3 // src[x + a_stride] + vld1.32 {d18[0]}, [r11], r3 // src[x + b_stride] + bne 4b + b 99f +99: + vpop {d8-d15} + pop {r4-r11} + bx lr +endfunc diff --git a/libavcodec/arm/sbcdsp_armv6.S b/libavcodec/arm/sbcdsp_armv6.S new file mode 100644 index 0000000000000..f1ff845798843 --- /dev/null +++ b/libavcodec/arm/sbcdsp_armv6.S @@ -0,0 +1,245 @@ +/* + * Bluetooth low-complexity, subband codec (SBC) + * + * Copyright (C) 2017 Aurelien Jacobs + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2006 Brad Midgley + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * SBC ARMv6 optimizations. The instructions are scheduled for ARM11 pipeline. + */ + +#include "libavutil/arm/asm.S" + +function ff_sbc_analyze_4_armv6, export=1 + @ r0 = in, r1 = out, r2 = consts + push {r1, r3-r7, lr} + push {r8-r12, r14} + ldrd r4, r5, [r0, #0] + ldrd r6, r7, [r2, #0] + ldrd r8, r9, [r0, #16] + ldrd r10, r11, [r2, #16] + mov r14, #0x8000 + smlad r3, r4, r6, r14 + smlad r12, r5, r7, r14 + ldrd r4, r5, [r0, #32] + ldrd r6, r7, [r2, #32] + smlad r3, r8, r10, r3 + smlad r12, r9, r11, r12 + ldrd r8, r9, [r0, #48] + ldrd r10, r11, [r2, #48] + smlad r3, r4, r6, r3 + smlad r12, r5, r7, r12 + ldrd r4, r5, [r0, #64] + ldrd r6, r7, [r2, #64] + smlad r3, r8, r10, r3 + smlad r12, r9, r11, r12 + ldrd r8, r9, [r0, #8] + ldrd r10, r11, [r2, #8] + smlad r3, r4, r6, r3 @ t1[0] is done + smlad r12, r5, r7, r12 @ t1[1] is done + ldrd r4, r5, [r0, #24] + ldrd r6, r7, [r2, #24] + pkhtb r3, r12, r3, asr #16 @ combine t1[0] and t1[1] + smlad r12, r8, r10, r14 + smlad r14, r9, r11, r14 + ldrd r8, r9, [r0, #40] + ldrd r10, r11, [r2, #40] + smlad r12, r4, r6, r12 + smlad r14, r5, r7, r14 + ldrd r4, r5, [r0, #56] + ldrd r6, r7, [r2, #56] + smlad r12, r8, r10, r12 + smlad r14, r9, r11, r14 + ldrd r8, r9, [r0, #72] + ldrd r10, r11, [r2, #72] + smlad r12, r4, r6, r12 + smlad r14, r5, r7, r14 + ldrd r4, r5, [r2, #80] @ start loading cos table + smlad r12, r8, r10, r12 @ t1[2] is done + smlad r14, r9, r11, r14 @ t1[3] is done + ldrd r6, r7, [r2, #88] + ldrd r8, r9, [r2, #96] + ldrd r10, r11, [r2, #104] @ cos table fully loaded + pkhtb r12, r14, r12, asr #16 @ combine t1[2] and t1[3] + smuad r4, r3, r4 + smuad r5, r3, r5 + smlad r4, r12, r8, r4 + smlad r5, r12, r9, r5 + smuad r6, r3, r6 + smuad r7, r3, r7 + smlad r6, r12, r10, r6 + smlad r7, r12, r11, r7 + pop {r8-r12, r14} + stmia r1, {r4, r5, r6, r7} + pop {r1, r3-r7, pc} +endfunc + +function ff_sbc_analyze_8_armv6, export=1 + @ r0 = in, r1 = out, r2 = consts + push {r1, r3-r7, lr} + push {r8-r12, r14} + ldrd r4, r5, [r0, #24] + ldrd r6, r7, [r2, #24] + ldrd r8, r9, [r0, #56] + ldrd r10, r11, [r2, #56] + mov r14, #0x8000 + smlad r3, r4, r6, r14 + smlad r12, r5, r7, r14 + ldrd r4, r5, [r0, #88] + ldrd r6, r7, [r2, #88] + smlad r3, r8, r10, r3 + smlad r12, r9, r11, r12 + ldrd r8, r9, [r0, #120] + ldrd r10, r11, [r2, #120] + smlad r3, r4, r6, r3 + smlad r12, r5, r7, r12 + ldrd r4, r5, [r0, #152] + ldrd r6, r7, [r2, #152] + smlad r3, r8, r10, r3 + smlad r12, r9, r11, r12 + ldrd r8, r9, [r0, #16] + ldrd r10, r11, [r2, #16] + smlad r3, r4, r6, r3 @ t1[6] is done + smlad r12, r5, r7, r12 @ t1[7] is done + ldrd r4, r5, [r0, #48] + ldrd r6, r7, [r2, #48] + pkhtb r3, r12, r3, asr #16 @ combine t1[6] and t1[7] + str r3, [sp, #-4]! @ save to stack + smlad r3, r8, r10, r14 + smlad r12, r9, r11, r14 + ldrd r8, r9, [r0, #80] + ldrd r10, r11, [r2, #80] + smlad r3, r4, r6, r3 + smlad r12, r5, r7, r12 + ldrd r4, r5, [r0, #112] + ldrd r6, r7, [r2, #112] + smlad r3, r8, r10, r3 + smlad r12, r9, r11, r12 + ldrd r8, r9, [r0, #144] + ldrd r10, r11, [r2, #144] + smlad r3, r4, r6, r3 + smlad r12, r5, r7, r12 + ldrd r4, r5, [r0, #0] + ldrd r6, r7, [r2, #0] + smlad r3, r8, r10, r3 @ t1[4] is done + smlad r12, r9, r11, r12 @ t1[5] is done + ldrd r8, r9, [r0, #32] + ldrd r10, r11, [r2, #32] + pkhtb r3, r12, r3, asr #16 @ combine t1[4] and t1[5] + str r3, [sp, #-4]! @ save to stack + smlad r3, r4, r6, r14 + smlad r12, r5, r7, r14 + ldrd r4, r5, [r0, #64] + ldrd r6, r7, [r2, #64] + smlad r3, r8, r10, r3 + smlad r12, r9, r11, r12 + ldrd r8, r9, [r0, #96] + ldrd r10, r11, [r2, #96] + smlad r3, r4, r6, r3 + smlad r12, r5, r7, r12 + ldrd r4, r5, [r0, #128] + ldrd r6, r7, [r2, #128] + smlad r3, r8, r10, r3 + smlad r12, r9, r11, r12 + ldrd r8, r9, [r0, #8] + ldrd r10, r11, [r2, #8] + smlad r3, r4, r6, r3 @ t1[0] is done + smlad r12, r5, r7, r12 @ t1[1] is done + ldrd r4, r5, [r0, #40] + ldrd r6, r7, [r2, #40] + pkhtb r3, r12, r3, asr #16 @ combine t1[0] and t1[1] + smlad r12, r8, r10, r14 + smlad r14, r9, r11, r14 + ldrd r8, r9, [r0, #72] + ldrd r10, r11, [r2, #72] + smlad r12, r4, r6, r12 + smlad r14, r5, r7, r14 + ldrd r4, r5, [r0, #104] + ldrd r6, r7, [r2, #104] + smlad r12, r8, r10, r12 + smlad r14, r9, r11, r14 + ldrd r8, r9, [r0, #136] + ldrd r10, r11, [r2, #136]! + smlad r12, r4, r6, r12 + smlad r14, r5, r7, r14 + ldrd r4, r5, [r2, #(160 - 136 + 0)] + smlad r12, r8, r10, r12 @ t1[2] is done + smlad r14, r9, r11, r14 @ t1[3] is done + ldrd r6, r7, [r2, #(160 - 136 + 8)] + smuad r4, r3, r4 + smuad r5, r3, r5 + pkhtb r12, r14, r12, asr #16 @ combine t1[2] and t1[3] + @ r3 = t2[0:1] + @ r12 = t2[2:3] + pop {r0, r14} @ t2[4:5], t2[6:7] + ldrd r8, r9, [r2, #(160 - 136 + 32)] + smuad r6, r3, r6 + smuad r7, r3, r7 + ldrd r10, r11, [r2, #(160 - 136 + 40)] + smlad r4, r12, r8, r4 + smlad r5, r12, r9, r5 + ldrd r8, r9, [r2, #(160 - 136 + 64)] + smlad r6, r12, r10, r6 + smlad r7, r12, r11, r7 + ldrd r10, r11, [r2, #(160 - 136 + 72)] + smlad r4, r0, r8, r4 + smlad r5, r0, r9, r5 + ldrd r8, r9, [r2, #(160 - 136 + 96)] + smlad r6, r0, r10, r6 + smlad r7, r0, r11, r7 + ldrd r10, r11, [r2, #(160 - 136 + 104)] + smlad r4, r14, r8, r4 + smlad r5, r14, r9, r5 + ldrd r8, r9, [r2, #(160 - 136 + 16 + 0)] + smlad r6, r14, r10, r6 + smlad r7, r14, r11, r7 + ldrd r10, r11, [r2, #(160 - 136 + 16 + 8)] + stmia r1!, {r4, r5} + smuad r4, r3, r8 + smuad r5, r3, r9 + ldrd r8, r9, [r2, #(160 - 136 + 16 + 32)] + stmia r1!, {r6, r7} + smuad r6, r3, r10 + smuad r7, r3, r11 + ldrd r10, r11, [r2, #(160 - 136 + 16 + 40)] + smlad r4, r12, r8, r4 + smlad r5, r12, r9, r5 + ldrd r8, r9, [r2, #(160 - 136 + 16 + 64)] + smlad r6, r12, r10, r6 + smlad r7, r12, r11, r7 + ldrd r10, r11, [r2, #(160 - 136 + 16 + 72)] + smlad r4, r0, r8, r4 + smlad r5, r0, r9, r5 + ldrd r8, r9, [r2, #(160 - 136 + 16 + 96)] + smlad r6, r0, r10, r6 + smlad r7, r0, r11, r7 + ldrd r10, r11, [r2, #(160 - 136 + 16 + 104)] + smlad r4, r14, r8, r4 + smlad r5, r14, r9, r5 + smlad r6, r14, r10, r6 + smlad r7, r14, r11, r7 + pop {r8-r12, r14} + stmia r1!, {r4, r5, r6, r7} + pop {r1, r3-r7, pc} +endfunc diff --git a/libavcodec/arm/sbcdsp_init_arm.c b/libavcodec/arm/sbcdsp_init_arm.c new file mode 100644 index 0000000000000..6bf7e729ef118 --- /dev/null +++ b/libavcodec/arm/sbcdsp_init_arm.c @@ -0,0 +1,105 @@ +/* + * Bluetooth low-complexity, subband codec (SBC) + * + * Copyright (C) 2017 Aurelien Jacobs + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2006 Brad Midgley + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * SBC ARMv6 optimization for some basic "building bricks" + */ + +#include "libavutil/cpu.h" +#include "libavutil/arm/cpu.h" +#include "libavcodec/sbcdsp.h" + +void ff_sbc_analyze_4_armv6(const int16_t *in, int32_t *out, const int16_t *consts); +void ff_sbc_analyze_8_armv6(const int16_t *in, int32_t *out, const int16_t *consts); + +void ff_sbc_analyze_4_neon(const int16_t *in, int32_t *out, const int16_t *consts); +void ff_sbc_analyze_8_neon(const int16_t *in, int32_t *out, const int16_t *consts); +void ff_sbc_calc_scalefactors_neon(int32_t sb_sample_f[16][2][8], + uint32_t scale_factor[2][8], + int blocks, int channels, int subbands); +int ff_sbc_calc_scalefactors_j_neon(int32_t sb_sample_f[16][2][8], + uint32_t scale_factor[2][8], + int blocks, int subbands); +int ff_sbc_enc_process_input_4s_neon(int position, const uint8_t *pcm, + int16_t X[2][SBC_X_BUFFER_SIZE], + int nsamples, int nchannels); +int ff_sbc_enc_process_input_8s_neon(int position, const uint8_t *pcm, + int16_t X[2][SBC_X_BUFFER_SIZE], + int nsamples, int nchannels); + +DECLARE_ALIGNED(SBC_ALIGN, int32_t, ff_sbcdsp_joint_bits_mask)[8] = { + 8, 4, 2, 1, 128, 64, 32, 16 +}; + +#if HAVE_BIGENDIAN +#define PERM(a, b, c, d) { \ + (a * 2) + 1, (a * 2) + 0, \ + (b * 2) + 1, (b * 2) + 0, \ + (c * 2) + 1, (c * 2) + 0, \ + (d * 2) + 1, (d * 2) + 0 \ + } +#else +#define PERM(a, b, c, d) { \ + (a * 2) + 0, (a * 2) + 1, \ + (b * 2) + 0, (b * 2) + 1, \ + (c * 2) + 0, (c * 2) + 1, \ + (d * 2) + 0, (d * 2) + 1 \ + } +#endif + +DECLARE_ALIGNED(SBC_ALIGN, uint8_t, ff_sbc_input_perm_4)[2][8] = { + PERM(7, 3, 6, 4), + PERM(0, 2, 1, 5) +}; + +DECLARE_ALIGNED(SBC_ALIGN, uint8_t, ff_sbc_input_perm_8)[4][8] = { + PERM(15, 7, 14, 8), + PERM(13, 9, 12, 10), + PERM(11, 3, 6, 0), + PERM( 5, 1, 4, 2) +}; + +av_cold void ff_sbcdsp_init_arm(SBCDSPContext *s) +{ + int cpu_flags = av_get_cpu_flags(); + + if (have_armv6(cpu_flags)) { + s->sbc_analyze_4 = ff_sbc_analyze_4_armv6; + s->sbc_analyze_8 = ff_sbc_analyze_8_armv6; + } + + if (have_neon(cpu_flags)) { + s->sbc_analyze_4 = ff_sbc_analyze_4_neon; + s->sbc_analyze_8 = ff_sbc_analyze_8_neon; + s->sbc_calc_scalefactors = ff_sbc_calc_scalefactors_neon; + s->sbc_calc_scalefactors_j = ff_sbc_calc_scalefactors_j_neon; + if (s->increment != 1) { + s->sbc_enc_process_input_4s = ff_sbc_enc_process_input_4s_neon; + s->sbc_enc_process_input_8s = ff_sbc_enc_process_input_8s_neon; + } + } +} diff --git a/libavcodec/arm/sbcdsp_neon.S b/libavcodec/arm/sbcdsp_neon.S new file mode 100644 index 0000000000000..d83d21d20202d --- /dev/null +++ b/libavcodec/arm/sbcdsp_neon.S @@ -0,0 +1,714 @@ +/* + * Bluetooth low-complexity, subband codec (SBC) + * + * Copyright (C) 2017 Aurelien Jacobs + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2006 Brad Midgley + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * SBC ARM NEON optimizations + */ + +#include "libavutil/arm/asm.S" +#include "neon.S" + +#define SBC_PROTO_FIXED_SCALE 16 + +function ff_sbc_analyze_4_neon, export=1 + /* TODO: merge even and odd cases (or even merge all four calls to this + * function) in order to have only aligned reads from 'in' array + * and reduce number of load instructions */ + vld1.16 {d4, d5}, [r0, :64]! + vld1.16 {d8, d9}, [r2, :128]! + + vmull.s16 q0, d4, d8 + vld1.16 {d6, d7}, [r0, :64]! + vmull.s16 q1, d5, d9 + vld1.16 {d10, d11}, [r2, :128]! + + vmlal.s16 q0, d6, d10 + vld1.16 {d4, d5}, [r0, :64]! + vmlal.s16 q1, d7, d11 + vld1.16 {d8, d9}, [r2, :128]! + + vmlal.s16 q0, d4, d8 + vld1.16 {d6, d7}, [r0, :64]! + vmlal.s16 q1, d5, d9 + vld1.16 {d10, d11}, [r2, :128]! + + vmlal.s16 q0, d6, d10 + vld1.16 {d4, d5}, [r0, :64]! + vmlal.s16 q1, d7, d11 + vld1.16 {d8, d9}, [r2, :128]! + + vmlal.s16 q0, d4, d8 + vmlal.s16 q1, d5, d9 + + vpadd.s32 d0, d0, d1 + vpadd.s32 d1, d2, d3 + + vrshrn.s32 d0, q0, SBC_PROTO_FIXED_SCALE + + vld1.16 {d2, d3, d4, d5}, [r2, :128]! + + vdup.i32 d1, d0[1] /* TODO: can be eliminated */ + vdup.i32 d0, d0[0] /* TODO: can be eliminated */ + + vmull.s16 q3, d2, d0 + vmull.s16 q4, d3, d0 + vmlal.s16 q3, d4, d1 + vmlal.s16 q4, d5, d1 + + vpadd.s32 d0, d6, d7 /* TODO: can be eliminated */ + vpadd.s32 d1, d8, d9 /* TODO: can be eliminated */ + + vst1.32 {d0, d1}, [r1, :128] + + bx lr +endfunc + +function ff_sbc_analyze_8_neon, export=1 + /* TODO: merge even and odd cases (or even merge all four calls to this + * function) in order to have only aligned reads from 'in' array + * and reduce number of load instructions */ + vld1.16 {d4, d5}, [r0, :64]! + vld1.16 {d8, d9}, [r2, :128]! + + vmull.s16 q6, d4, d8 + vld1.16 {d6, d7}, [r0, :64]! + vmull.s16 q7, d5, d9 + vld1.16 {d10, d11}, [r2, :128]! + vmull.s16 q8, d6, d10 + vld1.16 {d4, d5}, [r0, :64]! + vmull.s16 q9, d7, d11 + vld1.16 {d8, d9}, [r2, :128]! + + vmlal.s16 q6, d4, d8 + vld1.16 {d6, d7}, [r0, :64]! + vmlal.s16 q7, d5, d9 + vld1.16 {d10, d11}, [r2, :128]! + vmlal.s16 q8, d6, d10 + vld1.16 {d4, d5}, [r0, :64]! + vmlal.s16 q9, d7, d11 + vld1.16 {d8, d9}, [r2, :128]! + + vmlal.s16 q6, d4, d8 + vld1.16 {d6, d7}, [r0, :64]! + vmlal.s16 q7, d5, d9 + vld1.16 {d10, d11}, [r2, :128]! + vmlal.s16 q8, d6, d10 + vld1.16 {d4, d5}, [r0, :64]! + vmlal.s16 q9, d7, d11 + vld1.16 {d8, d9}, [r2, :128]! + + vmlal.s16 q6, d4, d8 + vld1.16 {d6, d7}, [r0, :64]! + vmlal.s16 q7, d5, d9 + vld1.16 {d10, d11}, [r2, :128]! + vmlal.s16 q8, d6, d10 + vld1.16 {d4, d5}, [r0, :64]! + vmlal.s16 q9, d7, d11 + vld1.16 {d8, d9}, [r2, :128]! + + vmlal.s16 q6, d4, d8 + vld1.16 {d6, d7}, [r0, :64]! + vmlal.s16 q7, d5, d9 + vld1.16 {d10, d11}, [r2, :128]! + + vmlal.s16 q8, d6, d10 + vmlal.s16 q9, d7, d11 + + vpadd.s32 d0, d12, d13 + vpadd.s32 d1, d14, d15 + vpadd.s32 d2, d16, d17 + vpadd.s32 d3, d18, d19 + + vrshr.s32 q0, q0, SBC_PROTO_FIXED_SCALE + vrshr.s32 q1, q1, SBC_PROTO_FIXED_SCALE + vmovn.s32 d0, q0 + vmovn.s32 d1, q1 + + vdup.i32 d3, d1[1] /* TODO: can be eliminated */ + vdup.i32 d2, d1[0] /* TODO: can be eliminated */ + vdup.i32 d1, d0[1] /* TODO: can be eliminated */ + vdup.i32 d0, d0[0] /* TODO: can be eliminated */ + + vld1.16 {d4, d5}, [r2, :128]! + vmull.s16 q6, d4, d0 + vld1.16 {d6, d7}, [r2, :128]! + vmull.s16 q7, d5, d0 + vmull.s16 q8, d6, d0 + vmull.s16 q9, d7, d0 + + vld1.16 {d4, d5}, [r2, :128]! + vmlal.s16 q6, d4, d1 + vld1.16 {d6, d7}, [r2, :128]! + vmlal.s16 q7, d5, d1 + vmlal.s16 q8, d6, d1 + vmlal.s16 q9, d7, d1 + + vld1.16 {d4, d5}, [r2, :128]! + vmlal.s16 q6, d4, d2 + vld1.16 {d6, d7}, [r2, :128]! + vmlal.s16 q7, d5, d2 + vmlal.s16 q8, d6, d2 + vmlal.s16 q9, d7, d2 + + vld1.16 {d4, d5}, [r2, :128]! + vmlal.s16 q6, d4, d3 + vld1.16 {d6, d7}, [r2, :128]! + vmlal.s16 q7, d5, d3 + vmlal.s16 q8, d6, d3 + vmlal.s16 q9, d7, d3 + + vpadd.s32 d0, d12, d13 /* TODO: can be eliminated */ + vpadd.s32 d1, d14, d15 /* TODO: can be eliminated */ + vpadd.s32 d2, d16, d17 /* TODO: can be eliminated */ + vpadd.s32 d3, d18, d19 /* TODO: can be eliminated */ + + vst1.32 {d0, d1, d2, d3}, [r1, :128] + + bx lr +endfunc + +function ff_sbc_calc_scalefactors_neon, export=1 + @ parameters + @ r0 = sb_sample_f + @ r1 = scale_factor + @ r2 = blocks + @ r3 = channels + @ r4 = subbands + @ local variables + @ r5 = in_loop_1 + @ r6 = in + @ r7 = out_loop_1 + @ r8 = out + @ r9 = ch + @ r10 = sb + @ r11 = inc + @ r12 = blk + + push {r1-r2, r4-r12} + ldr r4, [sp, #44] + mov r11, #64 + + mov r9, #0 +1: + add r5, r0, r9, lsl#5 + add r7, r1, r9, lsl#5 + + mov r10, #0 +2: + add r6, r5, r10, lsl#2 + add r8, r7, r10, lsl#2 + mov r12, r2 + + vmov.s32 q0, #0 + vmov.s32 q1, #0x8000 @ 1 << SCALE_OUT_BITS + vmov.s32 q14, #1 + vmov.s32 q15, #16 @ 31 - SCALE_OUT_BITS + vadd.s32 q1, q1, q14 +3: + vld1.32 {d16, d17}, [r6, :128], r11 + vabs.s32 q8, q8 + vld1.32 {d18, d19}, [r6, :128], r11 + vabs.s32 q9, q9 + vld1.32 {d20, d21}, [r6, :128], r11 + vabs.s32 q10, q10 + vld1.32 {d22, d23}, [r6, :128], r11 + vabs.s32 q11, q11 + vmax.s32 q0, q0, q8 + vmax.s32 q1, q1, q9 + vmax.s32 q0, q0, q10 + vmax.s32 q1, q1, q11 + subs r12, r12, #4 + bgt 3b + vmax.s32 q0, q0, q1 + vsub.s32 q0, q0, q14 + vclz.s32 q0, q0 + vsub.s32 q0, q15, q0 + vst1.32 {d0, d1}, [r8, :128] + + add r10, r10, #4 + cmp r10, r4 + blt 2b + + add r9, r9, #1 + cmp r9, r3 + blt 1b + + pop {r1-r2, r4-r12} + bx lr +endfunc + +/* + * constants: q13 = (31 - SCALE_OUT_BITS) + * q14 = 1 + * input: q0 - ((1 << SCALE_OUT_BITS) + 1) + * r5 - samples for channel 0 + * r6 - samples for shannel 1 + * output: q0, q1 - scale factors without joint stereo + * q2, q3 - scale factors with joint stereo + * q15 - joint stereo selection mask + */ +.macro calc_scalefactors + vmov.s32 q1, q0 + vmov.s32 q2, q0 + vmov.s32 q3, q0 + mov r3, r2 +1: + vld1.32 {d18, d19}, [r6, :128], r11 + vbic.s32 q11, q9, q14 + vld1.32 {d16, d17}, [r5, :128], r11 + vhadd.s32 q10, q8, q11 + vhsub.s32 q11, q8, q11 + vabs.s32 q8, q8 + vabs.s32 q9, q9 + vabs.s32 q10, q10 + vabs.s32 q11, q11 + vmax.s32 q0, q0, q8 + vmax.s32 q1, q1, q9 + vmax.s32 q2, q2, q10 + vmax.s32 q3, q3, q11 + subs r3, r3, #1 + bgt 1b + vsub.s32 q0, q0, q14 + vsub.s32 q1, q1, q14 + vsub.s32 q2, q2, q14 + vsub.s32 q3, q3, q14 + vclz.s32 q0, q0 + vclz.s32 q1, q1 + vclz.s32 q2, q2 + vclz.s32 q3, q3 + vsub.s32 q0, q13, q0 + vsub.s32 q1, q13, q1 + vsub.s32 q2, q13, q2 + vsub.s32 q3, q13, q3 +.endm + +/* + * constants: q14 = 1 + * input: q15 - joint stereo selection mask + * r5 - value set by calc_scalefactors macro + * r6 - value set by calc_scalefactors macro + */ +.macro update_joint_stereo_samples + sub r8, r6, r11 + sub r7, r5, r11 + sub r6, r6, r11, asl #1 + sub r5, r5, r11, asl #1 + vld1.32 {d18, d19}, [r6, :128] + vbic.s32 q11, q9, q14 + vld1.32 {d16, d17}, [r5, :128] + vld1.32 {d2, d3}, [r8, :128] + vbic.s32 q3, q1, q14 + vld1.32 {d0, d1}, [r7, :128] + vhsub.s32 q10, q8, q11 + vhadd.s32 q11, q8, q11 + vhsub.s32 q2, q0, q3 + vhadd.s32 q3, q0, q3 + vbif.s32 q10, q9, q15 + vbif.s32 d22, d16, d30 + sub r11, r10, r11, asl #1 + sub r3, r2, #2 +2: + vbif.s32 d23, d17, d31 + vst1.32 {d20, d21}, [r6, :128], r11 + vbif.s32 d4, d2, d30 + vld1.32 {d18, d19}, [r6, :128] + vbif.s32 d5, d3, d31 + vst1.32 {d22, d23}, [r5, :128], r11 + vbif.s32 d6, d0, d30 + vld1.32 {d16, d17}, [r5, :128] + vbif.s32 d7, d1, d31 + vst1.32 {d4, d5}, [r8, :128], r11 + vbic.s32 q11, q9, q14 + vld1.32 {d2, d3}, [r8, :128] + vst1.32 {d6, d7}, [r7, :128], r11 + vbic.s32 q3, q1, q14 + vld1.32 {d0, d1}, [r7, :128] + vhsub.s32 q10, q8, q11 + vhadd.s32 q11, q8, q11 + vhsub.s32 q2, q0, q3 + vhadd.s32 q3, q0, q3 + vbif.s32 q10, q9, q15 + vbif.s32 d22, d16, d30 + subs r3, r3, #2 + bgt 2b + sub r11, r10, r11, asr #1 + vbif.s32 d23, d17, d31 + vst1.32 {d20, d21}, [r6, :128] + vbif.s32 q2, q1, q15 + vst1.32 {d22, d23}, [r5, :128] + vbif.s32 q3, q0, q15 + vst1.32 {d4, d5}, [r8, :128] + vst1.32 {d6, d7}, [r7, :128] +.endm + +function ff_sbc_calc_scalefactors_j_neon, export=1 + @ parameters + @ r0 = in = sb_sample_f + @ r1 = out = scale_factor + @ r2 = blocks + @ r3 = subbands + @ local variables + @ r4 = consts = ff_sbcdsp_joint_bits_mask + @ r5 = in0 + @ r6 = in1 + @ r7 = out0 + @ r8 = out1 + @ r10 = zero + @ r11 = inc + @ return r0 = joint + + push {r3-r11} + movrelx r4, X(ff_sbcdsp_joint_bits_mask) + mov r10, #0 + mov r11, #64 + + vmov.s32 q14, #1 + vmov.s32 q13, #16 @ 31 - SCALE_OUT_BITS + + cmp r3, #4 + bne 8f + +4: @ 4 subbands + add r5, r0, #0 + add r6, r0, #32 + add r7, r1, #0 + add r8, r1, #32 + vmov.s32 q0, #0x8000 @ 1 << SCALE_OUT_BITS + vadd.s32 q0, q0, q14 + + calc_scalefactors + + @ check whether to use joint stereo for subbands 0, 1, 2 + vadd.s32 q15, q0, q1 + vadd.s32 q9, q2, q3 + vmov.s32 d31[1], r10 @ last subband -> no joint + vld1.32 {d16, d17}, [r4, :128]! + vcgt.s32 q15, q15, q9 + + @ calculate and save to memory 'joint' variable + @ update and save scale factors to memory + vand.s32 q8, q8, q15 + vbit.s32 q0, q2, q15 + vpadd.s32 d16, d16, d17 + vbit.s32 q1, q3, q15 + vpadd.s32 d16, d16, d16 + vst1.32 {d0, d1}, [r7, :128] + vst1.32 {d2, d3}, [r8, :128] + vmov.32 r0, d16[0] + + update_joint_stereo_samples + b 9f + +8: @ 8 subbands + add r5, r0, #16 + add r6, r0, #48 + add r7, r1, #16 + add r8, r1, #48 + vmov.s32 q0, #0x8000 @ 1 << SCALE_OUT_BITS + vadd.s32 q0, q0, q14 + + calc_scalefactors + + @ check whether to use joint stereo for subbands 4, 5, 6 + vadd.s32 q15, q0, q1 + vadd.s32 q9, q2, q3 + vmov.s32 d31[1], r10 @ last subband -> no joint + vld1.32 {d16, d17}, [r4, :128]! + vcgt.s32 q15, q15, q9 + + @ calculate part of 'joint' variable and save it to d24 + @ update and save scale factors to memory + vand.s32 q8, q8, q15 + vbit.s32 q0, q2, q15 + vpadd.s32 d16, d16, d17 + vbit.s32 q1, q3, q15 + vst1.32 {d0, d1}, [r7, :128] + vst1.32 {d2, d3}, [r8, :128] + vpadd.s32 d24, d16, d16 + + update_joint_stereo_samples + + add r5, r0, #0 + add r6, r0, #32 + add r7, r1, #0 + add r8, r1, #32 + vmov.s32 q0, #0x8000 @ 1 << SCALE_OUT_BITS + vadd.s32 q0, q0, q14 + + calc_scalefactors + + @ check whether to use joint stereo for subbands 0, 1, 2, 3 + vadd.s32 q15, q0, q1 + vadd.s32 q9, q2, q3 + vld1.32 {d16, d17}, [r4, :128]! + vcgt.s32 q15, q15, q9 + + @ combine last part of 'joint' with d24 and save to memory + @ update and save scale factors to memory + vand.s32 q8, q8, q15 + vbit.s32 q0, q2, q15 + vpadd.s32 d16, d16, d17 + vbit.s32 q1, q3, q15 + vpadd.s32 d16, d16, d16 + vst1.32 {d0, d1}, [r7, :128] + vadd.s32 d16, d16, d24 + vst1.32 {d2, d3}, [r8, :128] + vmov.32 r0, d16[0] + + update_joint_stereo_samples +9: + pop {r3-r11} + bx lr +endfunc + +function ff_sbc_enc_process_input_4s_neon, export=1 + @ parameters + @ r0 = positioin + @ r1 = pcm + @ r2 = X + @ r3 = nsamples + @ r4 = nchannels + @ local variables + @ r5 = ff_sbc_input_perm_4 + @ r6 = src / x + @ r7 = dst / y + + push {r1, r3-r7} + ldr r4, [sp, #24] + movrelx r5, X(ff_sbc_input_perm_4) + + @ handle X buffer wraparound + cmp r0, r3 + bge 1f @ if (position < nsamples) + add r7, r2, #576 @ &X[0][SBC_X_BUFFER_SIZE - 40] + add r6, r2, r0, lsl#1 @ &X[0][position] + vld1.16 {d0, d1, d2, d3}, [r6, :128]! + vst1.16 {d0, d1, d2, d3}, [r7, :128]! + vld1.16 {d0, d1, d2, d3}, [r6, :128]! + vst1.16 {d0, d1, d2, d3}, [r7, :128]! + vld1.16 {d0}, [r6, :64]! + vst1.16 {d0}, [r7, :64]! + cmp r4, #1 + ble 2f @ if (nchannels > 1) + add r7, r2, #1232 @ &X[1][SBC_X_BUFFER_SIZE - 40] + add r6, r2, #656 + add r6, r6, r0, lsl#1 @ &X[1][position] + vld1.16 {d0, d1, d2, d3}, [r6, :128]! + vst1.16 {d0, d1, d2, d3}, [r7, :128]! + vld1.16 {d0, d1, d2, d3}, [r6, :128]! + vst1.16 {d0, d1, d2, d3}, [r7, :128]! + vld1.16 {d0}, [r6, :64]! + vst1.16 {d0}, [r7, :64]! +2: + mov r0, #288 @ SBC_X_BUFFER_SIZE - 40 +1: + + add r6, r2, r0, lsl#1 @ &X[0][position] + add r7, r6, #656 @ &X[1][position] + + cmp r4, #1 + ble 8f @ if (nchannels > 1) + tst r1, #1 + beq 7f @ if (pcm & 1) + @ poor 'pcm' alignment + vld1.8 {d0, d1}, [r5, :128] +1: + sub r6, r6, #16 + sub r7, r7, #16 + sub r0, r0, #8 + vld1.8 {d4, d5}, [r1]! + vuzp.16 d4, d5 + vld1.8 {d20, d21}, [r1]! + vuzp.16 d20, d21 + vswp d5, d20 + vtbl.8 d16, {d4, d5}, d0 + vtbl.8 d17, {d4, d5}, d1 + vtbl.8 d18, {d20, d21}, d0 + vtbl.8 d19, {d20, d21}, d1 + vst1.16 {d16, d17}, [r6, :128] + vst1.16 {d18, d19}, [r7, :128] + subs r3, r3, #8 + bgt 1b + b 9f +7: + @ proper 'pcm' alignment + vld1.8 {d0, d1}, [r5, :128] +1: + sub r6, r6, #16 + sub r7, r7, #16 + sub r0, r0, #8 + vld2.16 {d4, d5}, [r1]! + vld2.16 {d20, d21}, [r1]! + vswp d5, d20 + vtbl.8 d16, {d4, d5}, d0 + vtbl.8 d17, {d4, d5}, d1 + vtbl.8 d18, {d20, d21}, d0 + vtbl.8 d19, {d20, d21}, d1 + vst1.16 {d16, d17}, [r6, :128] + vst1.16 {d18, d19}, [r7, :128] + subs r3, r3, #8 + bgt 1b + b 9f +8: + @ mono + vld1.8 {d0, d1}, [r5, :128] +1: + sub r6, r6, #16 + sub r0, r0, #8 + vld1.8 {d4, d5}, [r1]! + vtbl.8 d16, {d4, d5}, d0 + vtbl.8 d17, {d4, d5}, d1 + vst1.16 {d16, d17}, [r6, :128] + subs r3, r3, #8 + bgt 1b +9: + pop {r1, r3-r7} + bx lr +endfunc + +function ff_sbc_enc_process_input_8s_neon, export=1 + @ parameters + @ r0 = positioin + @ r1 = pcm + @ r2 = X + @ r3 = nsamples + @ r4 = nchannels + @ local variables + @ r5 = ff_sbc_input_perm_8 + @ r6 = src + @ r7 = dst + + push {r1, r3-r7} + ldr r4, [sp, #24] + movrelx r5, X(ff_sbc_input_perm_8) + + @ handle X buffer wraparound + cmp r0, r3 + bge 1f @ if (position < nsamples) + add r7, r2, #512 @ &X[0][SBC_X_BUFFER_SIZE - 72] + add r6, r2, r0, lsl#1 @ &X[0][position] + vld1.16 {d0, d1, d2, d3}, [r6, :128]! + vst1.16 {d0, d1, d2, d3}, [r7, :128]! + vld1.16 {d0, d1, d2, d3}, [r6, :128]! + vst1.16 {d0, d1, d2, d3}, [r7, :128]! + vld1.16 {d0, d1, d2, d3}, [r6, :128]! + vst1.16 {d0, d1, d2, d3}, [r7, :128]! + vld1.16 {d0, d1, d2, d3}, [r6, :128]! + vst1.16 {d0, d1, d2, d3}, [r7, :128]! + vld1.16 {d0, d1}, [r6, :128]! + vst1.16 {d0, d1}, [r7, :128]! + cmp r4, #1 + ble 2f @ if (nchannels > 1) + add r7, r2, #1168 @ &X[1][SBC_X_BUFFER_SIZE - 72] + add r6, r2, #656 + add r6, r6, r0, lsl#1 @ &X[1][position] + vld1.16 {d0, d1, d2, d3}, [r6, :128]! + vst1.16 {d0, d1, d2, d3}, [r7, :128]! + vld1.16 {d0, d1, d2, d3}, [r6, :128]! + vst1.16 {d0, d1, d2, d3}, [r7, :128]! + vld1.16 {d0, d1, d2, d3}, [r6, :128]! + vst1.16 {d0, d1, d2, d3}, [r7, :128]! + vld1.16 {d0, d1, d2, d3}, [r6, :128]! + vst1.16 {d0, d1, d2, d3}, [r7, :128]! + vld1.16 {d0, d1}, [r6, :128]! + vst1.16 {d0, d1}, [r7, :128]! +2: + mov r0, #256 @ SBC_X_BUFFER_SIZE - 72 +1: + + add r6, r2, r0, lsl#1 @ &X[0][position] + add r7, r6, #656 @ &X[1][position] + + cmp r4, #1 + ble 8f @ if (nchannels > 1) + tst r1, #1 + beq 7f @ if (pcm & 1) + @ poor 'pcm' alignment + vld1.8 {d0, d1, d2, d3}, [r5, :128] +1: + sub r6, r6, #32 + sub r7, r7, #32 + sub r0, r0, #16 + vld1.8 {d4, d5, d6, d7}, [r1]! + vuzp.16 q2, q3 + vld1.8 {d20, d21, d22, d23}, [r1]! + vuzp.16 q10, q11 + vswp q3, q10 + vtbl.8 d16, {d4, d5, d6, d7}, d0 + vtbl.8 d17, {d4, d5, d6, d7}, d1 + vtbl.8 d18, {d4, d5, d6, d7}, d2 + vtbl.8 d19, {d4, d5, d6, d7}, d3 + vst1.16 {d16, d17, d18, d19}, [r6, :128] + vtbl.8 d16, {d20, d21, d22, d23}, d0 + vtbl.8 d17, {d20, d21, d22, d23}, d1 + vtbl.8 d18, {d20, d21, d22, d23}, d2 + vtbl.8 d19, {d20, d21, d22, d23}, d3 + vst1.16 {d16, d17, d18, d19}, [r7, :128] + subs r3, r3, #16 + bgt 1b + b 9f +7: + @ proper 'pcm' alignment + vld1.8 {d0, d1, d2, d3}, [r5, :128] +1: + sub r6, r6, #32 + sub r7, r7, #32 + sub r0, r0, #16 + vld2.16 {d4, d5, d6, d7}, [r1]! + vld2.16 {d20, d21, d22, d23}, [r1]! + vswp q3, q10 + vtbl.8 d16, {d4, d5, d6, d7}, d0 + vtbl.8 d17, {d4, d5, d6, d7}, d1 + vtbl.8 d18, {d4, d5, d6, d7}, d2 + vtbl.8 d19, {d4, d5, d6, d7}, d3 + vst1.16 {d16, d17, d18, d19}, [r6, :128] + vtbl.8 d16, {d20, d21, d22, d23}, d0 + vtbl.8 d17, {d20, d21, d22, d23}, d1 + vtbl.8 d18, {d20, d21, d22, d23}, d2 + vtbl.8 d19, {d20, d21, d22, d23}, d3 + vst1.16 {d16, d17, d18, d19}, [r7, :128] + subs r3, r3, #16 + bgt 1b + b 9f +8: + @ mono + vld1.8 {d0, d1, d2, d3}, [r5, :128] +1: + sub r6, r6, #32 + sub r0, r0, #16 + vld1.8 {d4, d5, d6, d7}, [r1]! + vtbl.8 d16, {d4, d5, d6, d7}, d0 + vtbl.8 d17, {d4, d5, d6, d7}, d1 + vtbl.8 d18, {d4, d5, d6, d7}, d2 + vtbl.8 d19, {d4, d5, d6, d7}, d3 + vst1.16 {d16, d17, d18, d19}, [r6, :128] + subs r3, r3, #16 + bgt 1b +9: + pop {r1, r3-r7} + bx lr +endfunc diff --git a/libavcodec/arm/sbrdsp_neon.S b/libavcodec/arm/sbrdsp_neon.S index e66abd682a8fe..003b04ea05653 100644 --- a/libavcodec/arm/sbrdsp_neon.S +++ b/libavcodec/arm/sbrdsp_neon.S @@ -336,11 +336,11 @@ function ff_sbr_hf_apply_noise_0_neon, export=1 vld1.32 {d0}, [r0,:64] vld1.32 {d6}, [lr,:64] vld1.32 {d2[]}, [r1,:32]! - vld1.32 {d3[]}, [r2,:32]! + vld1.32 {d18[]}, [r2,:32]! vceq.f32 d4, d2, #0 veor d2, d2, d3 vmov d1, d0 - vmla.f32 d0, d6, d3 + vmla.f32 d0, d6, d18 vadd.f32 s2, s2, s4 vbif d0, d1, d4 vst1.32 {d0}, [r0,:64]! diff --git a/libavcodec/arm/vc1dsp_init_neon.c b/libavcodec/arm/vc1dsp_init_neon.c index 005d45ce8f246..2cca784f5ac34 100644 --- a/libavcodec/arm/vc1dsp_init_neon.c +++ b/libavcodec/arm/vc1dsp_init_neon.c @@ -22,8 +22,6 @@ #include "libavcodec/vc1dsp.h" #include "vc1dsp.h" -#include "config.h" - void ff_vc1_inv_trans_8x8_neon(int16_t *block); void ff_vc1_inv_trans_4x8_neon(uint8_t *dest, ptrdiff_t stride, int16_t *block); void ff_vc1_inv_trans_8x4_neon(uint8_t *dest, ptrdiff_t stride, int16_t *block); @@ -95,7 +93,6 @@ av_cold void ff_vc1dsp_init_neon(VC1DSPContext *dsp) dsp->vc1_inv_trans_4x4_dc = ff_vc1_inv_trans_4x4_dc_neon; dsp->put_vc1_mspel_pixels_tab[1][ 0] = ff_put_pixels8x8_neon; - if (HAVE_AS_DN_DIRECTIVE) { FN_ASSIGN(1, 0); FN_ASSIGN(2, 0); FN_ASSIGN(3, 0); @@ -114,7 +111,6 @@ av_cold void ff_vc1dsp_init_neon(VC1DSPContext *dsp) FN_ASSIGN(1, 3); FN_ASSIGN(2, 3); FN_ASSIGN(3, 3); - } dsp->put_no_rnd_vc1_chroma_pixels_tab[0] = ff_put_vc1_chroma_mc8_neon; dsp->avg_no_rnd_vc1_chroma_pixels_tab[0] = ff_avg_vc1_chroma_mc8_neon; diff --git a/libavcodec/arm/vc1dsp_neon.S b/libavcodec/arm/vc1dsp_neon.S index 611cbf2234f15..93f043bf08c41 100644 --- a/libavcodec/arm/vc1dsp_neon.S +++ b/libavcodec/arm/vc1dsp_neon.S @@ -410,13 +410,13 @@ function ff_vc1_inv_trans_8x8_neon, export=1 @ src[48] q14 @ src[56] q15 - vc1_inv_trans_8x8_helper add=4 add1beforeshift=0 rshift=3 + vc1_inv_trans_8x8_helper add=4, add1beforeshift=0, rshift=3 @ Transpose result matrix of 8x8 swap4 d17, d19, d21, d23, d24, d26, d28, d30 transpose16_4x4 q8, q9, q10, q11, q12, q13, q14, q15 - vc1_inv_trans_8x8_helper add=64 add1beforeshift=1 rshift=7 + vc1_inv_trans_8x8_helper add=64, add1beforeshift=1, rshift=7 vst1.64 {q8-q9}, [r0,:128]! vst1.64 {q10-q11}, [r0,:128]! @@ -431,7 +431,7 @@ function ff_vc1_inv_trans_8x4_neon, export=1 vld1.64 {q0-q1}, [r2,:128]! @ load 8 * 4 * 2 = 64 bytes / 16 bytes per quad = 4 quad registers vld1.64 {q2-q3}, [r2,:128] - transpose16 q0 q1 q2 q3 @ transpose rows to columns + transpose16 q0, q1, q2, q3 @ transpose rows to columns @ At this point: @ src[0] d0 @@ -443,7 +443,7 @@ function ff_vc1_inv_trans_8x4_neon, export=1 @ src[6] d5 @ src[7] d7 - vc1_inv_trans_8x4_helper add=4 add1beforeshift=0 rshift=3 + vc1_inv_trans_8x4_helper add=4, add1beforeshift=0, rshift=3 @ Move output to more standardized registers vmov d0, d16 @@ -465,7 +465,7 @@ function ff_vc1_inv_trans_8x4_neon, export=1 @ dst[6] d5 @ dst[7] d7 - transpose16 q0 q1 q2 q3 @ turn columns into rows + transpose16 q0, q1, q2, q3 @ turn columns into rows @ At this point: @ row[0] q0 @@ -473,7 +473,7 @@ function ff_vc1_inv_trans_8x4_neon, export=1 @ row[2] q2 @ row[3] q3 - vc1_inv_trans_4x8_helper add=64 rshift=7 + vc1_inv_trans_4x8_helper add=64, rshift=7 @ At this point: @ line[0].l d0 @@ -523,7 +523,7 @@ function ff_vc1_inv_trans_4x8_neon, export=1 vld4.16 {d1[2], d3[2], d5[2], d7[2]}, [r2,:64], r12 vld4.16 {d1[3], d3[3], d5[3], d7[3]}, [r2,:64] - vc1_inv_trans_4x8_helper add=4 rshift=3 + vc1_inv_trans_4x8_helper add=4, rshift=3 @ At this point: @ dst[0] = q0 @@ -531,9 +531,9 @@ function ff_vc1_inv_trans_4x8_neon, export=1 @ dst[2] = q2 @ dst[3] = q3 - transpose16 q0 q1 q2 q3 @ Transpose rows (registers) into columns + transpose16 q0, q1, q2, q3 @ Transpose rows (registers) into columns - vc1_inv_trans_8x4_helper add=64 add1beforeshift=1 rshift=7 + vc1_inv_trans_8x4_helper add=64, add1beforeshift=1, rshift=7 vld1.32 {d28[]}, [r0,:32], r1 @ read dest vld1.32 {d28[1]}, [r0,:32], r1 @@ -611,7 +611,7 @@ function ff_vc1_inv_trans_4x4_neon, export=1 @ src[2] = d1 @ src[3] = d3 - vc1_inv_trans_4x4_helper add=4 rshift=3 @ compute t1, t2, t3, t4 and combine them into dst[0-3] + vc1_inv_trans_4x4_helper add=4, rshift=3 @ compute t1, t2, t3, t4 and combine them into dst[0-3] @ At this point: @ dst[0] = d0 @@ -619,7 +619,7 @@ function ff_vc1_inv_trans_4x4_neon, export=1 @ dst[2] = d1 @ dst[3] = d2 - transpose16 d0 d3 d1 d2 @ Transpose rows (registers) into columns + transpose16 d0, d3, d1, d2 @ Transpose rows (registers) into columns @ At this point: @ src[0] = d0 @@ -635,7 +635,7 @@ function ff_vc1_inv_trans_4x4_neon, export=1 @ src[16] = d1 @ src[24] = d3 - vc1_inv_trans_4x4_helper add=64 rshift=7 @ compute t1, t2, t3, t4 and combine them into dst[0-3] + vc1_inv_trans_4x4_helper add=64, rshift=7 @ compute t1, t2, t3, t4 and combine them into dst[0-3] @ At this point: @ line[0] = d0 @@ -663,48 +663,43 @@ function ff_vc1_inv_trans_4x4_neon, export=1 bx lr endfunc -#if HAVE_AS_DN_DIRECTIVE @ The absolute value of multiplication constants from vc1_mspel_filter and vc1_mspel_{ver,hor}_filter_16bits. @ The sign is embedded in the code below that carries out the multiplication (mspel_filter{,.16}). -#define MSPEL_MODE_1_MUL_CONSTANTS 4 53 18 3 -#define MSPEL_MODE_2_MUL_CONSTANTS 1 9 9 1 -#define MSPEL_MODE_3_MUL_CONSTANTS 3 18 53 4 +#define MSPEL_MODE_1_MUL_CONSTANTS 4, 53, 18, 3 +#define MSPEL_MODE_2_MUL_CONSTANTS 1, 9, 9, 1 +#define MSPEL_MODE_3_MUL_CONSTANTS 3, 18, 53, 4 @ These constants are from reading the source code of vc1_mspel_mc and determining the value that @ is added to `rnd` to result in the variable `r`, and the value of the variable `shift`. -#define MSPEL_MODES_11_ADDSHIFT_CONSTANTS 15 5 -#define MSPEL_MODES_12_ADDSHIFT_CONSTANTS 3 3 -#define MSPEL_MODES_13_ADDSHIFT_CONSTANTS 15 5 +#define MSPEL_MODES_11_ADDSHIFT_CONSTANTS 15, 5 +#define MSPEL_MODES_12_ADDSHIFT_CONSTANTS 3, 3 +#define MSPEL_MODES_13_ADDSHIFT_CONSTANTS 15, 5 #define MSPEL_MODES_21_ADDSHIFT_CONSTANTS MSPEL_MODES_12_ADDSHIFT_CONSTANTS -#define MSPEL_MODES_22_ADDSHIFT_CONSTANTS 0 1 -#define MSPEL_MODES_23_ADDSHIFT_CONSTANTS 3 3 +#define MSPEL_MODES_22_ADDSHIFT_CONSTANTS 0, 1 +#define MSPEL_MODES_23_ADDSHIFT_CONSTANTS 3, 3 #define MSPEL_MODES_31_ADDSHIFT_CONSTANTS MSPEL_MODES_13_ADDSHIFT_CONSTANTS #define MSPEL_MODES_32_ADDSHIFT_CONSTANTS MSPEL_MODES_23_ADDSHIFT_CONSTANTS -#define MSPEL_MODES_33_ADDSHIFT_CONSTANTS 15 5 +#define MSPEL_MODES_33_ADDSHIFT_CONSTANTS 15, 5 @ The addition and shift constants from vc1_mspel_filter. -#define MSPEL_MODE_1_ADDSHIFT_CONSTANTS 32 6 -#define MSPEL_MODE_2_ADDSHIFT_CONSTANTS 8 4 -#define MSPEL_MODE_3_ADDSHIFT_CONSTANTS 32 6 +#define MSPEL_MODE_1_ADDSHIFT_CONSTANTS 32, 6 +#define MSPEL_MODE_2_ADDSHIFT_CONSTANTS 8, 4 +#define MSPEL_MODE_3_ADDSHIFT_CONSTANTS 32, 6 @ Setup constants in registers for a subsequent use of mspel_filter{,.16}. .macro mspel_constants typesize reg_a reg_b reg_c reg_d filter_a filter_b filter_c filter_d reg_add filter_add_register - @ Define double-word register aliases. Typesize should be i8 or i16. - ra .dn \reg_a\().\typesize - rb .dn \reg_b\().\typesize - rc .dn \reg_c\().\typesize - rd .dn \reg_d\().\typesize + @ Typesize should be i8 or i16. @ Only set the register if the value is not 1 and unique .if \filter_a != 1 - vmov ra, #\filter_a @ ra = filter_a + vmov.\typesize \reg_a, #\filter_a @ reg_a = filter_a .endif - vmov rb, #\filter_b @ rb = filter_b + vmov.\typesize \reg_b, #\filter_b @ reg_b = filter_b .if \filter_b != \filter_c - vmov rc, #\filter_c @ rc = filter_c + vmov.\typesize \reg_c, #\filter_c @ reg_c = filter_c .endif .if \filter_d != 1 - vmov rd, #\filter_d @ rd = filter_d + vmov.\typesize \reg_d, #\filter_d @ reg_d = filter_d .endif @ vdup to double the size of typesize .ifc \typesize,i8 @@ -712,11 +707,6 @@ endfunc .else vdup.32 \reg_add, \filter_add_register @ reg_add = filter_add_register .endif - - .unreq ra - .unreq rb - .unreq rc - .unreq rd .endm @ After mspel_constants has been used, do the filtering. @@ -828,7 +818,7 @@ T mov sp, r4 sub r1, r1, r2 @ r1 = &src[-stride] @ slide back @ Do vertical filtering from src into tmp - mspel_constants i8 d28 d29 d30 d31 \filter_v_a \filter_v_b \filter_v_c \filter_v_d q13 r3 + mspel_constants i8, d28, d29, d30, d31, \filter_v_a, \filter_v_b, \filter_v_c, \filter_v_d, q13, r3 vld1.64 {d0,d1}, [r1], r2 vld1.64 {d2,d3}, [r1], r2 @@ -838,23 +828,23 @@ T mov sp, r4 subs r12, r12, #4 vld1.64 {d6,d7}, [r1], r2 - mspel_filter q11 q11 d0 d2 d4 d6 \filter_v_a \filter_v_b \filter_v_c \filter_v_d d28 d29 d30 d31 q13 \filter_shift narrow=0 - mspel_filter q12 q12 d1 d3 d5 d7 \filter_v_a \filter_v_b \filter_v_c \filter_v_d d28 d29 d30 d31 q13 \filter_shift narrow=0 + mspel_filter q11, q11, d0, d2, d4, d6, \filter_v_a, \filter_v_b, \filter_v_c, \filter_v_d, d28, d29, d30, d31, q13, \filter_shift, narrow=0 + mspel_filter q12, q12, d1, d3, d5, d7, \filter_v_a, \filter_v_b, \filter_v_c, \filter_v_d, d28, d29, d30, d31, q13, \filter_shift, narrow=0 vst1.64 {q11,q12}, [r4,:128]! @ store and increment vld1.64 {d0,d1}, [r1], r2 - mspel_filter q11 q11 d2 d4 d6 d0 \filter_v_a \filter_v_b \filter_v_c \filter_v_d d28 d29 d30 d31 q13 \filter_shift narrow=0 - mspel_filter q12 q12 d3 d5 d7 d1 \filter_v_a \filter_v_b \filter_v_c \filter_v_d d28 d29 d30 d31 q13 \filter_shift narrow=0 + mspel_filter q11, q11, d2, d4, d6, d0, \filter_v_a, \filter_v_b, \filter_v_c, \filter_v_d, d28, d29, d30, d31, q13, \filter_shift, narrow=0 + mspel_filter q12, q12, d3, d5, d7, d1, \filter_v_a, \filter_v_b, \filter_v_c, \filter_v_d, d28, d29, d30, d31, q13, \filter_shift, narrow=0 vst1.64 {q11,q12}, [r4,:128]! @ store and increment vld1.64 {d2,d3}, [r1], r2 - mspel_filter q11 q11 d4 d6 d0 d2 \filter_v_a \filter_v_b \filter_v_c \filter_v_d d28 d29 d30 d31 q13 \filter_shift narrow=0 - mspel_filter q12 q12 d5 d7 d1 d3 \filter_v_a \filter_v_b \filter_v_c \filter_v_d d28 d29 d30 d31 q13 \filter_shift narrow=0 + mspel_filter q11, q11, d4, d6, d0, d2, \filter_v_a, \filter_v_b, \filter_v_c, \filter_v_d, d28, d29, d30, d31, q13, \filter_shift, narrow=0 + mspel_filter q12, q12, d5, d7, d1, d3, \filter_v_a, \filter_v_b, \filter_v_c, \filter_v_d, d28, d29, d30, d31, q13, \filter_shift, narrow=0 vst1.64 {q11,q12}, [r4,:128]! @ store and increment vld1.64 {d4,d5}, [r1], r2 - mspel_filter q11 q11 d6 d0 d2 d4 \filter_v_a \filter_v_b \filter_v_c \filter_v_d d28 d29 d30 d31 q13 \filter_shift narrow=0 - mspel_filter q12 q12 d7 d1 d3 d5 \filter_v_a \filter_v_b \filter_v_c \filter_v_d d28 d29 d30 d31 q13 \filter_shift narrow=0 + mspel_filter q11, q11, d6, d0, d2, d4, \filter_v_a, \filter_v_b, \filter_v_c, \filter_v_d, d28, d29, d30, d31, q13, \filter_shift, narrow=0 + mspel_filter q12, q12, d7, d1, d3, d5, \filter_v_a, \filter_v_b, \filter_v_c, \filter_v_d, d28, d29, d30, d31, q13, \filter_shift, narrow=0 vst1.64 {q11,q12}, [r4,:128]! @ store and increment bne 1b @@ -864,7 +854,7 @@ T mov sp, r4 mov r4, sp @ r4 = tmp @ Do horizontal filtering from temp to dst - mspel_constants i16 d28 d29 d30 d31 \filter_h_a \filter_h_b \filter_h_c \filter_h_d q13 r3 + mspel_constants i16, d28, d29, d30, d31, \filter_h_a, \filter_h_b, \filter_h_c, \filter_h_d, q13, r3 2: subs r12, r12, #1 @@ -874,7 +864,7 @@ T mov sp, r4 vext.16 q3, q0, q1, #3 vext.16 q1, q0, q1, #1 @ do last because it writes to q1 which is read by the other vext instructions - mspel_filter.16 q11 q12 d22 d23 d21 d0 d1 d2 d3 d4 d5 d6 d7 \filter_h_a \filter_h_b \filter_h_c \filter_h_d d28 d29 d30 d31 q13 7 + mspel_filter.16 q11, q12, d22, d23, d21, d0, d1, d2, d3, d4, d5, d6, d7, \filter_h_a, \filter_h_b, \filter_h_c, \filter_h_d, d28, d29, d30, d31, q13, 7 vst1.64 {d21}, [r0,:64], r2 @ store and increment dst @@ -887,9 +877,9 @@ endfunc @ Use C preprocessor and assembler macros to expand to functions for horizontal and vertical filtering. #define PUT_VC1_MSPEL_MC_HV(hmode, vmode) \ - put_vc1_mspel_mc_hv hmode vmode \ - MSPEL_MODE_ ## hmode ## _MUL_CONSTANTS \ - MSPEL_MODE_ ## vmode ## _MUL_CONSTANTS \ + put_vc1_mspel_mc_hv hmode, vmode, \ + MSPEL_MODE_ ## hmode ## _MUL_CONSTANTS, \ + MSPEL_MODE_ ## vmode ## _MUL_CONSTANTS, \ MSPEL_MODES_ ## hmode ## vmode ## _ADDSHIFT_CONSTANTS PUT_VC1_MSPEL_MC_HV(1, 1) @@ -910,7 +900,7 @@ function ff_put_vc1_mspel_mc\hmode\()0_neon, export=1 mov r12, #8 @ loop counter sub r1, r1, #1 @ slide back, using immediate - mspel_constants i8 d28 d29 d30 d31 \filter_a \filter_b \filter_c \filter_d q13 r3 + mspel_constants i8, d28, d29, d30, d31, \filter_a, \filter_b, \filter_c, \filter_d, q13, r3 1: subs r12, r12, #1 @@ -920,7 +910,7 @@ function ff_put_vc1_mspel_mc\hmode\()0_neon, export=1 vext.8 d3, d0, d1, #3 vext.8 d1, d0, d1, #1 @ do last because it writes to d1 which is read by the other vext instructions - mspel_filter q11 d21 d0 d1 d2 d3 \filter_a \filter_b \filter_c \filter_d d28 d29 d30 d31 q13 \filter_shift + mspel_filter q11, d21, d0, d1, d2, d3, \filter_a, \filter_b, \filter_c, \filter_d, d28, d29, d30, d31, q13, \filter_shift vst1.64 {d21}, [r0,:64], r2 @ store and increment dst @@ -932,7 +922,7 @@ endfunc @ Use C preprocessor and assembler macros to expand to functions for horizontal only filtering. #define PUT_VC1_MSPEL_MC_H_ONLY(hmode) \ - put_vc1_mspel_mc_h_only hmode MSPEL_MODE_ ## hmode ## _MUL_CONSTANTS MSPEL_MODE_ ## hmode ## _ADDSHIFT_CONSTANTS + put_vc1_mspel_mc_h_only hmode, MSPEL_MODE_ ## hmode ## _MUL_CONSTANTS, MSPEL_MODE_ ## hmode ## _ADDSHIFT_CONSTANTS PUT_VC1_MSPEL_MC_H_ONLY(1) PUT_VC1_MSPEL_MC_H_ONLY(2) @@ -947,7 +937,7 @@ function ff_put_vc1_mspel_mc0\vmode\()_neon, export=1 mov r12, #8 @ loop counter sub r1, r1, r2 @ r1 = &src[-stride] @ slide back - mspel_constants i8 d28 d29 d30 d31 \filter_a \filter_b \filter_c \filter_d q13 r3 + mspel_constants i8, d28, d29, d30, d31, \filter_a, \filter_b, \filter_c, \filter_d, q13, r3 vld1.64 {d0}, [r1], r2 @ d0 = src[-stride] vld1.64 {d1}, [r1], r2 @ d1 = src[0] @@ -957,19 +947,19 @@ function ff_put_vc1_mspel_mc0\vmode\()_neon, export=1 subs r12, r12, #4 vld1.64 {d3}, [r1], r2 @ d3 = src[stride * 2] - mspel_filter q11 d21 d0 d1 d2 d3 \filter_a \filter_b \filter_c \filter_d d28 d29 d30 d31 q13 \filter_shift + mspel_filter q11, d21, d0, d1, d2, d3, \filter_a, \filter_b, \filter_c, \filter_d, d28, d29, d30, d31, q13, \filter_shift vst1.64 {d21}, [r0,:64], r2 @ store and increment dst vld1.64 {d0}, [r1], r2 @ d0 = next line - mspel_filter q11 d21 d1 d2 d3 d0 \filter_a \filter_b \filter_c \filter_d d28 d29 d30 d31 q13 \filter_shift + mspel_filter q11, d21, d1, d2, d3, d0, \filter_a, \filter_b, \filter_c, \filter_d, d28, d29, d30, d31, q13, \filter_shift vst1.64 {d21}, [r0,:64], r2 @ store and increment dst vld1.64 {d1}, [r1], r2 @ d1 = next line - mspel_filter q11 d21 d2 d3 d0 d1 \filter_a \filter_b \filter_c \filter_d d28 d29 d30 d31 q13 \filter_shift + mspel_filter q11, d21, d2, d3, d0, d1, \filter_a, \filter_b, \filter_c, \filter_d, d28, d29, d30, d31, q13, \filter_shift vst1.64 {d21}, [r0,:64], r2 @ store and increment dst vld1.64 {d2}, [r1], r2 @ d2 = next line - mspel_filter q11 d21 d3 d0 d1 d2 \filter_a \filter_b \filter_c \filter_d d28 d29 d30 d31 q13 \filter_shift + mspel_filter q11, d21, d3, d0, d1, d2, \filter_a, \filter_b, \filter_c, \filter_d, d28, d29, d30, d31, q13, \filter_shift vst1.64 {d21}, [r0,:64], r2 @ store and increment dst bne 1b @@ -980,14 +970,13 @@ endfunc @ Use C preprocessor and assembler macros to expand to functions for vertical only filtering. #define PUT_VC1_MSPEL_MC_V_ONLY(vmode) \ - put_vc1_mspel_mc_v_only vmode MSPEL_MODE_ ## vmode ## _MUL_CONSTANTS MSPEL_MODE_ ## vmode ## _ADDSHIFT_CONSTANTS + put_vc1_mspel_mc_v_only vmode, MSPEL_MODE_ ## vmode ## _MUL_CONSTANTS, MSPEL_MODE_ ## vmode ## _ADDSHIFT_CONSTANTS PUT_VC1_MSPEL_MC_V_ONLY(1) PUT_VC1_MSPEL_MC_V_ONLY(2) PUT_VC1_MSPEL_MC_V_ONLY(3) #undef PUT_VC1_MSPEL_MC_V_ONLY -#endif function ff_put_pixels8x8_neon, export=1 vld1.64 {d0}, [r1], r2 diff --git a/libavcodec/audioconvert.c b/libavcodec/audioconvert.c deleted file mode 100644 index 5e46fae2df5f3..0000000000000 --- a/libavcodec/audioconvert.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * audio conversion - * Copyright (c) 2006 Michael Niedermayer - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file - * audio conversion - * @author Michael Niedermayer - */ - -#include "libavutil/avstring.h" -#include "libavutil/common.h" -#include "libavutil/libm.h" -#include "libavutil/samplefmt.h" -#include "avcodec.h" -#include "audioconvert.h" - -#if FF_API_AUDIO_CONVERT - -struct AVAudioConvert { - int in_channels, out_channels; - int fmt_pair; -}; - -AVAudioConvert *av_audio_convert_alloc(enum AVSampleFormat out_fmt, int out_channels, - enum AVSampleFormat in_fmt, int in_channels, - const float *matrix, int flags) -{ - AVAudioConvert *ctx; - if (in_channels!=out_channels) - return NULL; /* FIXME: not supported */ - ctx = av_malloc(sizeof(AVAudioConvert)); - if (!ctx) - return NULL; - ctx->in_channels = in_channels; - ctx->out_channels = out_channels; - ctx->fmt_pair = out_fmt + AV_SAMPLE_FMT_NB*in_fmt; - return ctx; -} - -void av_audio_convert_free(AVAudioConvert *ctx) -{ - av_free(ctx); -} - -int av_audio_convert(AVAudioConvert *ctx, - void * const out[6], const int out_stride[6], - const void * const in[6], const int in_stride[6], int len) -{ - int ch; - - //FIXME optimize common cases - - for(ch=0; chout_channels; ch++){ - const int is= in_stride[ch]; - const int os= out_stride[ch]; - const uint8_t *pi= in[ch]; - uint8_t *po= out[ch]; - uint8_t *end= po + os*len; - if(!out[ch]) - continue; - -#define CONV(ofmt, otype, ifmt, expr)\ -if(ctx->fmt_pair == ofmt + AV_SAMPLE_FMT_NB*ifmt){\ - do{\ - *(otype*)po = expr; pi += is; po += os;\ - }while(po < end);\ -} - -//FIXME put things below under ifdefs so we do not waste space for cases no codec will need -//FIXME rounding ? - - CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_U8 , *(const uint8_t*)pi) - else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)<<8) - else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)<<24) - else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0 / (1<<7))) - else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_U8 , (*(const uint8_t*)pi - 0x80)*(1.0 / (1<<7))) - else CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_S16, (*(const int16_t*)pi>>8) + 0x80) - else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S16, *(const int16_t*)pi) - else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S16, *(const int16_t*)pi<<16) - else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_S16, *(const int16_t*)pi*(1.0 / (1<<15))) - else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_S16, *(const int16_t*)pi*(1.0 / (1<<15))) - else CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_S32, (*(const int32_t*)pi>>24) + 0x80) - else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_S32, *(const int32_t*)pi>>16) - else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_S32, *(const int32_t*)pi) - else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_S32, *(const int32_t*)pi*(1.0 / (1U<<31))) - else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_S32, *(const int32_t*)pi*(1.0 / (1U<<31))) - else CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_FLT, av_clip_uint8( lrintf(*(const float*)pi * (1<<7)) + 0x80)) - else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_FLT, av_clip_int16( lrintf(*(const float*)pi * (1<<15)))) - else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_FLT, av_clipl_int32(llrintf(*(const float*)pi * (1U<<31)))) - else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_FLT, *(const float*)pi) - else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_FLT, *(const float*)pi) - else CONV(AV_SAMPLE_FMT_U8 , uint8_t, AV_SAMPLE_FMT_DBL, av_clip_uint8( lrint(*(const double*)pi * (1<<7)) + 0x80)) - else CONV(AV_SAMPLE_FMT_S16, int16_t, AV_SAMPLE_FMT_DBL, av_clip_int16( lrint(*(const double*)pi * (1<<15)))) - else CONV(AV_SAMPLE_FMT_S32, int32_t, AV_SAMPLE_FMT_DBL, av_clipl_int32(llrint(*(const double*)pi * (1U<<31)))) - else CONV(AV_SAMPLE_FMT_FLT, float , AV_SAMPLE_FMT_DBL, *(const double*)pi) - else CONV(AV_SAMPLE_FMT_DBL, double , AV_SAMPLE_FMT_DBL, *(const double*)pi) - else return -1; - } - return 0; -} - -#endif /* FF_API_AUDIO_CONVERT */ diff --git a/libavcodec/audioconvert.h b/libavcodec/audioconvert.h deleted file mode 100644 index 996c3f37adc08..0000000000000 --- a/libavcodec/audioconvert.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * audio conversion - * Copyright (c) 2006 Michael Niedermayer - * Copyright (c) 2008 Peter Ross - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVCODEC_AUDIOCONVERT_H -#define AVCODEC_AUDIOCONVERT_H - -#include "version.h" - -/** - * @file - * Audio format conversion routines - * This interface is deprecated and will be dropped in a future - * version. You should use the libswresample library instead. - */ - -#if FF_API_AUDIO_CONVERT - -#include "libavutil/cpu.h" -#include "avcodec.h" -#include "libavutil/channel_layout.h" - -struct AVAudioConvert; -typedef struct AVAudioConvert AVAudioConvert; - -/** - * Create an audio sample format converter context - * @param out_fmt Output sample format - * @param out_channels Number of output channels - * @param in_fmt Input sample format - * @param in_channels Number of input channels - * @param[in] matrix Channel mixing matrix (of dimension in_channel*out_channels). Set to NULL to ignore. - * @param flags See AV_CPU_FLAG_xx - * @return NULL on error - * @deprecated See libswresample - */ - -attribute_deprecated -AVAudioConvert *av_audio_convert_alloc(enum AVSampleFormat out_fmt, int out_channels, - enum AVSampleFormat in_fmt, int in_channels, - const float *matrix, int flags); - -/** - * Free audio sample format converter context - * @deprecated See libswresample - */ - -attribute_deprecated -void av_audio_convert_free(AVAudioConvert *ctx); - -/** - * Convert between audio sample formats - * @param[in] out array of output buffers for each channel. set to NULL to ignore processing of the given channel. - * @param[in] out_stride distance between consecutive output samples (measured in bytes) - * @param[in] in array of input buffers for each channel - * @param[in] in_stride distance between consecutive input samples (measured in bytes) - * @param len length of audio frame size (measured in samples) - * @deprecated See libswresample - */ - -attribute_deprecated -int av_audio_convert(AVAudioConvert *ctx, - void * const out[6], const int out_stride[6], - const void * const in[6], const int in_stride[6], int len); - -#endif /* FF_API_AUDIO_CONVERT */ - -#endif /* AVCODEC_AUDIOCONVERT_H */ diff --git a/libavcodec/audiotoolboxdec.c b/libavcodec/audiotoolboxdec.c index 607d3ba4d4803..5c0a9de8f636f 100644 --- a/libavcodec/audiotoolboxdec.c +++ b/libavcodec/audiotoolboxdec.c @@ -24,7 +24,7 @@ #include "config.h" #include "avcodec.h" -#include "ac3_parser.h" +#include "ac3_parser_internal.h" #include "bytestream.h" #include "internal.h" #include "mpegaudiodecheader.h" @@ -350,10 +350,10 @@ static av_cold int ffat_create_decoder(AVCodecContext *avctx, AVPacket *pkt) } else if (pkt && pkt->size >= 7 && (avctx->codec_id == AV_CODEC_ID_AC3 || avctx->codec_id == AV_CODEC_ID_EAC3)) { - AC3HeaderInfo hdr, *phdr = &hdr; + AC3HeaderInfo hdr; GetBitContext gbc; init_get_bits(&gbc, pkt->data, pkt->size); - if (avpriv_ac3_parse_header(&gbc, &phdr) < 0) + if (ff_ac3_parse_header(&gbc, &hdr) < 0) return AVERROR_INVALIDDATA; in_format.mSampleRate = hdr.sample_rate; in_format.mChannelsPerFrame = hdr.channels; @@ -597,6 +597,7 @@ static av_cold int ffat_close_decoder(AVCodecContext *avctx) .bsfs = bsf_name, \ .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, \ .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, \ + .wrapper_name = "at", \ }; FFAT_DEC(aac, AV_CODEC_ID_AAC, "aac_adtstoasc") diff --git a/libavcodec/audiotoolboxenc.c b/libavcodec/audiotoolboxenc.c index c47fbd1b2d264..2c1891693e21c 100644 --- a/libavcodec/audiotoolboxenc.c +++ b/libavcodec/audiotoolboxenc.c @@ -48,6 +48,8 @@ typedef struct ATDecodeContext { AudioFrameQueue afq; int eof; int frame_size; + + AVFrame* encoding_frame; } ATDecodeContext; static UInt32 ffat_get_format_id(enum AVCodecID codec, int profile) @@ -442,6 +444,10 @@ static av_cold int ffat_init_encoder(AVCodecContext *avctx) ff_af_queue_init(avctx, &at->afq); + at->encoding_frame = av_frame_alloc(); + if (!at->encoding_frame) + return AVERROR(ENOMEM); + return 0; } @@ -453,6 +459,7 @@ static OSStatus ffat_encode_callback(AudioConverterRef converter, UInt32 *nb_pac AVCodecContext *avctx = inctx; ATDecodeContext *at = avctx->priv_data; AVFrame *frame; + int ret; if (!at->frame_queue.available) { if (at->eof) { @@ -475,6 +482,13 @@ static OSStatus ffat_encode_callback(AudioConverterRef converter, UInt32 *nb_pac if (*nb_packets > frame->nb_samples) *nb_packets = frame->nb_samples; + av_frame_unref(at->encoding_frame); + ret = av_frame_ref(at->encoding_frame, frame); + if (ret < 0) { + *nb_packets = 0; + return ret; + } + ff_bufqueue_add(avctx, &at->used_frame_queue, frame); return 0; @@ -565,6 +579,7 @@ static av_cold int ffat_close_encoder(AVCodecContext *avctx) ff_bufqueue_discard_all(&at->frame_queue); ff_bufqueue_discard_all(&at->used_frame_queue); ff_af_queue_close(&at->afq); + av_frame_free(&at->encoding_frame); return 0; } @@ -619,6 +634,7 @@ static const AVOption options[] = { }, \ .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, \ .profiles = PROFILES, \ + .wrapper_name = "at", \ }; static const uint64_t aac_at_channel_layouts[] = { diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 52cc5b0ca08ad..0c1eefe6ba99a 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -36,6 +36,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/dict.h" #include "libavutil/frame.h" +#include "libavutil/hwcontext.h" #include "libavutil/log.h" #include "libavutil/pixfmt.h" #include "libavutil/rational.h" @@ -217,9 +218,6 @@ enum AVCodecID { /* video codecs */ AV_CODEC_ID_MPEG1VIDEO, AV_CODEC_ID_MPEG2VIDEO, ///< preferred ID for MPEG-1/2 video decoding -#if FF_API_XVMC - AV_CODEC_ID_MPEG2VIDEO_XVMC, -#endif /* FF_API_XVMC */ AV_CODEC_ID_H261, AV_CODEC_ID_H263, AV_CODEC_ID_RV10, @@ -520,9 +518,6 @@ enum AVCodecID { AV_CODEC_ID_ADPCM_G722, AV_CODEC_ID_ADPCM_IMA_APC, AV_CODEC_ID_ADPCM_VIMA, -#if FF_API_VIMA_DECODER - AV_CODEC_ID_VIMA = AV_CODEC_ID_ADPCM_VIMA, -#endif AV_CODEC_ID_ADPCM_AFC = 0x11800, AV_CODEC_ID_ADPCM_IMA_OKI, @@ -585,9 +580,6 @@ enum AVCodecID { AV_CODEC_ID_MLP, AV_CODEC_ID_GSM_MS, /* as found in WAV */ AV_CODEC_ID_ATRAC3, -#if FF_API_VOXWARE - AV_CODEC_ID_VOXWARE, -#endif AV_CODEC_ID_APE, AV_CODEC_ID_NELLYMOSER, AV_CODEC_ID_MUSEPACK8, @@ -623,6 +615,7 @@ enum AVCodecID { AV_CODEC_ID_PAF_AUDIO, AV_CODEC_ID_ON2AVC, AV_CODEC_ID_DSS_SP, + AV_CODEC_ID_CODEC2, AV_CODEC_ID_FFWAVESYNTH = 0x15800, AV_CODEC_ID_SONIC, @@ -641,6 +634,9 @@ enum AVCodecID { AV_CODEC_ID_ATRAC3AL, AV_CODEC_ID_ATRAC3PAL, AV_CODEC_ID_DOLBY_E, + AV_CODEC_ID_APTX, + AV_CODEC_ID_APTX_HD, + AV_CODEC_ID_SBC, /* subtitle codecs */ AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. @@ -774,7 +770,7 @@ typedef struct AVCodecDescriptor { * Note: If the first 23 bits of the additional bytes are not 0, then damaged * MPEG bitstreams could cause overread and segfault. */ -#define AV_INPUT_BUFFER_PADDING_SIZE 32 +#define AV_INPUT_BUFFER_PADDING_SIZE 64 /** * @ingroup lavc_encoding @@ -783,38 +779,6 @@ typedef struct AVCodecDescriptor { */ #define AV_INPUT_BUFFER_MIN_SIZE 16384 -#if FF_API_WITHOUT_PREFIX -/** - * @deprecated use AV_INPUT_BUFFER_PADDING_SIZE instead - */ -#define FF_INPUT_BUFFER_PADDING_SIZE 32 - -/** - * @deprecated use AV_INPUT_BUFFER_MIN_SIZE instead - */ -#define FF_MIN_BUFFER_SIZE 16384 -#endif /* FF_API_WITHOUT_PREFIX */ - -/** - * @ingroup lavc_encoding - * motion estimation type. - * @deprecated use codec private option instead - */ -#if FF_API_MOTION_EST -enum Motion_Est_ID { - ME_ZERO = 1, ///< no search, that is use 0,0 vector whenever one is needed - ME_FULL, - ME_LOG, - ME_PHODS, - ME_EPZS, ///< enhanced predictive zonal search - ME_X1, ///< reserved for experiments - ME_HEX, ///< hexagon based search - ME_UMH, ///< uneven multi-hexagon search - ME_TESA, ///< transformed exhaustive search algorithm - ME_ITER=50, ///< iterative search -}; -#endif - /** * @ingroup lavc_decoding */ @@ -853,13 +817,6 @@ typedef struct RcOverride{ float quality_factor; } RcOverride; -#if FF_API_MAX_BFRAMES -/** - * @deprecated there is no libavcodec-wide limit on the number of B-frames - */ -#define FF_MAX_B_FRAMES 16 -#endif - /* encoding support These flags can be passed in AVCodecContext.flags before initialization. Note: Not everything is supported yet. @@ -1031,13 +988,6 @@ typedef struct RcOverride{ */ #define AV_CODEC_CAP_SMALL_LAST_FRAME (1 << 6) -#if FF_API_CAP_VDPAU -/** - * Codec can export data for HW decoding (VDPAU). - */ -#define AV_CODEC_CAP_HWACCEL_VDPAU (1 << 7) -#endif - /** * Codec can output multiple frames per AVPacket * Normally demuxers return one frame at a time, demuxers which do not do @@ -1098,231 +1048,26 @@ typedef struct RcOverride{ */ #define AV_CODEC_CAP_LOSSLESS 0x80000000 - -#if FF_API_WITHOUT_PREFIX /** - * Allow decoders to produce frames with data planes that are not aligned - * to CPU requirements (e.g. due to cropping). + * Codec is backed by a hardware implementation. Typically used to + * identify a non-hwaccel hardware decoder. For information about hwaccels, use + * avcodec_get_hw_config() instead. */ -#define CODEC_FLAG_UNALIGNED AV_CODEC_FLAG_UNALIGNED -#define CODEC_FLAG_QSCALE AV_CODEC_FLAG_QSCALE -#define CODEC_FLAG_4MV AV_CODEC_FLAG_4MV -#define CODEC_FLAG_OUTPUT_CORRUPT AV_CODEC_FLAG_OUTPUT_CORRUPT -#define CODEC_FLAG_QPEL AV_CODEC_FLAG_QPEL -#if FF_API_GMC -/** - * @deprecated use the "gmc" private option of the libxvid encoder - */ -#define CODEC_FLAG_GMC 0x0020 ///< Use GMC. -#endif -#if FF_API_MV0 -/** - * @deprecated use the flag "mv0" in the "mpv_flags" private option of the - * mpegvideo encoders - */ -#define CODEC_FLAG_MV0 0x0040 -#endif -#if FF_API_INPUT_PRESERVED -/** - * @deprecated passing reference-counted frames to the encoders replaces this - * flag - */ -#define CODEC_FLAG_INPUT_PRESERVED 0x0100 -#endif -#define CODEC_FLAG_PASS1 AV_CODEC_FLAG_PASS1 -#define CODEC_FLAG_PASS2 AV_CODEC_FLAG_PASS2 -#define CODEC_FLAG_GRAY AV_CODEC_FLAG_GRAY -#if FF_API_EMU_EDGE -/** - * @deprecated edges are not used/required anymore. I.e. this flag is now always - * set. - */ -#define CODEC_FLAG_EMU_EDGE 0x4000 -#endif -#define CODEC_FLAG_PSNR AV_CODEC_FLAG_PSNR -#define CODEC_FLAG_TRUNCATED AV_CODEC_FLAG_TRUNCATED +#define AV_CODEC_CAP_HARDWARE (1 << 18) -#if FF_API_NORMALIZE_AQP /** - * @deprecated use the flag "naq" in the "mpv_flags" private option of the - * mpegvideo encoders + * Codec is potentially backed by a hardware implementation, but not + * necessarily. This is used instead of AV_CODEC_CAP_HARDWARE, if the + * implementation provides some sort of internal fallback. */ -#define CODEC_FLAG_NORMALIZE_AQP 0x00020000 -#endif -#define CODEC_FLAG_INTERLACED_DCT AV_CODEC_FLAG_INTERLACED_DCT -#define CODEC_FLAG_LOW_DELAY AV_CODEC_FLAG_LOW_DELAY -#define CODEC_FLAG_GLOBAL_HEADER AV_CODEC_FLAG_GLOBAL_HEADER -#define CODEC_FLAG_BITEXACT AV_CODEC_FLAG_BITEXACT -#define CODEC_FLAG_AC_PRED AV_CODEC_FLAG_AC_PRED -#define CODEC_FLAG_LOOP_FILTER AV_CODEC_FLAG_LOOP_FILTER -#define CODEC_FLAG_INTERLACED_ME AV_CODEC_FLAG_INTERLACED_ME -#define CODEC_FLAG_CLOSED_GOP AV_CODEC_FLAG_CLOSED_GOP -#define CODEC_FLAG2_FAST AV_CODEC_FLAG2_FAST -#define CODEC_FLAG2_NO_OUTPUT AV_CODEC_FLAG2_NO_OUTPUT -#define CODEC_FLAG2_LOCAL_HEADER AV_CODEC_FLAG2_LOCAL_HEADER -#define CODEC_FLAG2_DROP_FRAME_TIMECODE AV_CODEC_FLAG2_DROP_FRAME_TIMECODE -#define CODEC_FLAG2_IGNORE_CROP AV_CODEC_FLAG2_IGNORE_CROP - -#define CODEC_FLAG2_CHUNKS AV_CODEC_FLAG2_CHUNKS -#define CODEC_FLAG2_SHOW_ALL AV_CODEC_FLAG2_SHOW_ALL -#define CODEC_FLAG2_EXPORT_MVS AV_CODEC_FLAG2_EXPORT_MVS -#define CODEC_FLAG2_SKIP_MANUAL AV_CODEC_FLAG2_SKIP_MANUAL - -/* Unsupported options : - * Syntax Arithmetic coding (SAC) - * Reference Picture Selection - * Independent Segment Decoding */ -/* /Fx */ -/* codec capabilities */ - -#define CODEC_CAP_DRAW_HORIZ_BAND AV_CODEC_CAP_DRAW_HORIZ_BAND ///< Decoder can use draw_horiz_band callback. -/** - * Codec uses get_buffer() for allocating buffers and supports custom allocators. - * If not set, it might not use get_buffer() at all or use operations that - * assume the buffer was allocated by avcodec_default_get_buffer. - */ -#define CODEC_CAP_DR1 AV_CODEC_CAP_DR1 -#define CODEC_CAP_TRUNCATED AV_CODEC_CAP_TRUNCATED -#if FF_API_XVMC -/* Codec can export data for HW decoding. This flag indicates that - * the codec would call get_format() with list that might contain HW accelerated - * pixel formats (XvMC, VDPAU, VAAPI, etc). The application can pick any of them - * including raw image format. - * The application can use the passed context to determine bitstream version, - * chroma format, resolution etc. - */ -#define CODEC_CAP_HWACCEL 0x0010 -#endif /* FF_API_XVMC */ -/** - * Encoder or decoder requires flushing with NULL input at the end in order to - * give the complete and correct output. - * - * NOTE: If this flag is not set, the codec is guaranteed to never be fed with - * with NULL data. The user can still send NULL data to the public encode - * or decode function, but libavcodec will not pass it along to the codec - * unless this flag is set. - * - * Decoders: - * The decoder has a non-zero delay and needs to be fed with avpkt->data=NULL, - * avpkt->size=0 at the end to get the delayed data until the decoder no longer - * returns frames. - * - * Encoders: - * The encoder needs to be fed with NULL data at the end of encoding until the - * encoder no longer returns data. - * - * NOTE: For encoders implementing the AVCodec.encode2() function, setting this - * flag also means that the encoder must set the pts and duration for - * each output packet. If this flag is not set, the pts and duration will - * be determined by libavcodec from the input frame. - */ -#define CODEC_CAP_DELAY AV_CODEC_CAP_DELAY -/** - * Codec can be fed a final frame with a smaller size. - * This can be used to prevent truncation of the last audio samples. - */ -#define CODEC_CAP_SMALL_LAST_FRAME AV_CODEC_CAP_SMALL_LAST_FRAME -#if FF_API_CAP_VDPAU -/** - * Codec can export data for HW decoding (VDPAU). - */ -#define CODEC_CAP_HWACCEL_VDPAU AV_CODEC_CAP_HWACCEL_VDPAU -#endif -/** - * Codec can output multiple frames per AVPacket - * Normally demuxers return one frame at a time, demuxers which do not do - * are connected to a parser to split what they return into proper frames. - * This flag is reserved to the very rare category of codecs which have a - * bitstream that cannot be split into frames without timeconsuming - * operations like full decoding. Demuxers carrying such bitstreams thus - * may return multiple frames in a packet. This has many disadvantages like - * prohibiting stream copy in many cases thus it should only be considered - * as a last resort. - */ -#define CODEC_CAP_SUBFRAMES AV_CODEC_CAP_SUBFRAMES -/** - * Codec is experimental and is thus avoided in favor of non experimental - * encoders - */ -#define CODEC_CAP_EXPERIMENTAL AV_CODEC_CAP_EXPERIMENTAL -/** - * Codec should fill in channel configuration and samplerate instead of container - */ -#define CODEC_CAP_CHANNEL_CONF AV_CODEC_CAP_CHANNEL_CONF -#if FF_API_NEG_LINESIZES -/** - * @deprecated no codecs use this capability - */ -#define CODEC_CAP_NEG_LINESIZES 0x0800 -#endif -/** - * Codec supports frame-level multithreading. - */ -#define CODEC_CAP_FRAME_THREADS AV_CODEC_CAP_FRAME_THREADS -/** - * Codec supports slice-based (or partition-based) multithreading. - */ -#define CODEC_CAP_SLICE_THREADS AV_CODEC_CAP_SLICE_THREADS -/** - * Codec supports changed parameters at any point. - */ -#define CODEC_CAP_PARAM_CHANGE AV_CODEC_CAP_PARAM_CHANGE -/** - * Codec supports avctx->thread_count == 0 (auto). - */ -#define CODEC_CAP_AUTO_THREADS AV_CODEC_CAP_AUTO_THREADS -/** - * Audio encoder supports receiving a different number of samples in each call. - */ -#define CODEC_CAP_VARIABLE_FRAME_SIZE AV_CODEC_CAP_VARIABLE_FRAME_SIZE -/** - * Codec is intra only. - */ -#define CODEC_CAP_INTRA_ONLY AV_CODEC_CAP_INTRA_ONLY -/** - * Codec is lossless. - */ -#define CODEC_CAP_LOSSLESS AV_CODEC_CAP_LOSSLESS - -/** - * HWAccel is experimental and is thus avoided in favor of non experimental - * codecs - */ -#define HWACCEL_CODEC_CAP_EXPERIMENTAL 0x0200 -#endif /* FF_API_WITHOUT_PREFIX */ - -#if FF_API_MB_TYPE -//The following defines may change, don't expect compatibility if you use them. -#define MB_TYPE_INTRA4x4 0x0001 -#define MB_TYPE_INTRA16x16 0x0002 //FIXME H.264-specific -#define MB_TYPE_INTRA_PCM 0x0004 //FIXME H.264-specific -#define MB_TYPE_16x16 0x0008 -#define MB_TYPE_16x8 0x0010 -#define MB_TYPE_8x16 0x0020 -#define MB_TYPE_8x8 0x0040 -#define MB_TYPE_INTERLACED 0x0080 -#define MB_TYPE_DIRECT2 0x0100 //FIXME -#define MB_TYPE_ACPRED 0x0200 -#define MB_TYPE_GMC 0x0400 -#define MB_TYPE_SKIP 0x0800 -#define MB_TYPE_P0L0 0x1000 -#define MB_TYPE_P1L0 0x2000 -#define MB_TYPE_P0L1 0x4000 -#define MB_TYPE_P1L1 0x8000 -#define MB_TYPE_L0 (MB_TYPE_P0L0 | MB_TYPE_P1L0) -#define MB_TYPE_L1 (MB_TYPE_P0L1 | MB_TYPE_P1L1) -#define MB_TYPE_L0L1 (MB_TYPE_L0 | MB_TYPE_L1) -#define MB_TYPE_QUANT 0x00010000 -#define MB_TYPE_CBP 0x00020000 -// Note bits 24-31 are reserved for codec specific use (H.264 ref0, MPEG-1 0mv, ...) -#endif +#define AV_CODEC_CAP_HYBRID (1 << 19) /** * Pan Scan area. * This specifies the area which should be displayed. * Note there may be multiple such areas for one frame. */ -typedef struct AVPanScan{ +typedef struct AVPanScan { /** * id * - encoding: Set by user. @@ -1344,7 +1089,7 @@ typedef struct AVPanScan{ * - decoding: Set by libavcodec. */ int16_t position[3][2]; -}AVPanScan; +} AVPanScan; /** * This structure describes the bitrate properties of an encoded bitstream. It @@ -1384,13 +1129,6 @@ typedef struct AVCPBProperties { uint64_t vbv_delay; } AVCPBProperties; -#if FF_API_QSCALE_TYPE -#define FF_QSCALE_TYPE_MPEG1 0 -#define FF_QSCALE_TYPE_MPEG2 1 -#define FF_QSCALE_TYPE_H264 2 -#define FF_QSCALE_TYPE_VP56 3 -#endif - /** * The decoder will keep a reference to the frame and may reuse it later. */ @@ -1518,7 +1256,7 @@ enum AVPacketSideDataType { * u8 reason for end skip (0=padding silence, 1=convergence) * @endcode */ - AV_PKT_DATA_SKIP_SAMPLES=70, + AV_PKT_DATA_SKIP_SAMPLES, /** * An AV_PKT_DATA_JP_DUALMONO side data packet indicates that @@ -1607,7 +1345,20 @@ enum AVPacketSideDataType { AV_PKT_DATA_A53_CC, /** - * The number of side data elements (in fact a bit more than it). + * This side data is encryption initialization data. + * The format is not part of ABI, use av_encryption_init_info_* methods to + * access. + */ + AV_PKT_DATA_ENCRYPTION_INIT_INFO, + + /** + * This side data contains encryption info for how to decrypt the packet. + * The format is not part of ABI, use av_encryption_info_* methods to access. + */ + AV_PKT_DATA_ENCRYPTION_INFO, + + /** + * The number of side data types. * This is not part of the public API/ABI in the sense that it may * change when new side data types are added. * This must stay the last enum value. @@ -1723,6 +1474,13 @@ typedef struct AVPacket { * outside the packet may be followed. */ #define AV_PKT_FLAG_TRUSTED 0x0008 +/** + * Flag is used to indicate packets that contain frames that can + * be discarded by the decoder. I.e. Non-reference frames. + */ +#define AV_PKT_FLAG_DISPOSABLE 0x0010 + +#define AV_PKT_FLAG_NEW_SEG 0x8000 ///< The packet is the first packet from a source in concat enum AVSideDataParamChangeFlags { AV_SIDE_DATA_PARAM_CHANGE_CHANNEL_COUNT = 0x0001, @@ -1768,13 +1526,6 @@ typedef struct AVCodecContext { enum AVMediaType codec_type; /* see AVMEDIA_TYPE_xxx */ const struct AVCodec *codec; -#if FF_API_CODEC_NAME - /** - * @deprecated this field is not used for anything in libavcodec - */ - attribute_deprecated - char codec_name[32]; -#endif enum AVCodecID codec_id; /* see AV_CODEC_ID_xxx */ /** @@ -1792,14 +1543,6 @@ typedef struct AVCodecContext { */ unsigned int codec_tag; -#if FF_API_STREAM_CODEC_TAG - /** - * @deprecated this field is unused - */ - attribute_deprecated - unsigned int stream_codec_tag; -#endif - void *priv_data; /** @@ -1962,10 +1705,6 @@ typedef struct AVCodecContext { */ int coded_width, coded_height; -#if FF_API_ASPECT_EXTENDED -#define FF_ASPECT_EXTENDED 15 -#endif - /** * the number of pictures in a group of pictures, or 0 for intra_only * - encoding: Set by user. @@ -1988,14 +1727,6 @@ typedef struct AVCodecContext { */ enum AVPixelFormat pix_fmt; -#if FF_API_MOTION_EST - /** - * This option does nothing - * @deprecated use codec private options instead - */ - attribute_deprecated int me_method; -#endif - /** * If non NULL, 'draw_horiz_band' is called by the libavcodec * decoder to draw a horizontal band. It improves cache usage. Not @@ -2055,12 +1786,6 @@ typedef struct AVCodecContext { */ float b_quant_factor; -#if FF_API_RC_STRATEGY - /** @deprecated use codec private option instead */ - attribute_deprecated int rc_strategy; -#define FF_RC_STRATEGY_XVID 1 -#endif - #if FF_API_PRIVATE_OPT /** @deprecated use encoder private options instead */ attribute_deprecated @@ -2254,26 +1979,6 @@ typedef struct AVCodecContext { */ int me_subpel_quality; -#if FF_API_AFD - /** - * DTG active format information (additional aspect ratio - * information only used in DVB MPEG-2 transport streams) - * 0 if not set. - * - * - encoding: unused - * - decoding: Set by decoder. - * @deprecated Deprecated in favor of AVSideData - */ - attribute_deprecated int dtg_active_format; -#define FF_DTG_AFD_SAME 8 -#define FF_DTG_AFD_4_3 9 -#define FF_DTG_AFD_16_9 10 -#define FF_DTG_AFD_14_9 11 -#define FF_DTG_AFD_4_3_SP_14_9 13 -#define FF_DTG_AFD_16_9_SP_14_9 14 -#define FF_DTG_AFD_SP_4_3 15 -#endif /* FF_API_AFD */ - /** * maximum motion estimation search range in subpel units * If 0 then no limit. @@ -2283,19 +1988,6 @@ typedef struct AVCodecContext { */ int me_range; -#if FF_API_QUANT_BIAS - /** - * @deprecated use encoder private option instead - */ - attribute_deprecated int intra_quant_bias; -#define FF_DEFAULT_QUANT_BIAS 999999 - - /** - * @deprecated use encoder private option instead - */ - attribute_deprecated int inter_quant_bias; -#endif - /** * slice flags * - encoding: unused @@ -2306,16 +1998,6 @@ typedef struct AVCodecContext { #define SLICE_FLAG_ALLOW_FIELD 0x0002 ///< allow draw_horiz_band() with field slices (MPEG-2 field pics) #define SLICE_FLAG_ALLOW_PLANE 0x0004 ///< allow draw_horiz_band() with 1 component at a time (SVQ1) -#if FF_API_XVMC - /** - * XVideo Motion Acceleration - * - encoding: forbidden - * - decoding: set by decoder - * @deprecated XvMC doesn't need it anymore. - */ - attribute_deprecated int xvmc_acceleration; -#endif /* FF_API_XVMC */ - /** * macroblock decision mode * - encoding: Set by user. @@ -2350,20 +2032,6 @@ typedef struct AVCodecContext { int noise_reduction; #endif -#if FF_API_MPV_OPT - /** - * @deprecated this field is unused - */ - attribute_deprecated - int me_threshold; - - /** - * @deprecated this field is unused - */ - attribute_deprecated - int mb_threshold; -#endif - /** * precision of the intra DC coefficient - 8 * - encoding: Set by user. @@ -2385,14 +2053,6 @@ typedef struct AVCodecContext { */ int skip_bottom; -#if FF_API_MPV_OPT - /** - * @deprecated use encoder private options instead - */ - attribute_deprecated - float border_masking; -#endif - /** * minimum MB Lagrange multiplier * - encoding: Set by user. @@ -2447,15 +2107,6 @@ typedef struct AVCodecContext { int chromaoffset; #endif -#if FF_API_UNUSED_MEMBERS - /** - * Multiplied by qscale for each frame and added to scene_change_score. - * - encoding: Set by user. - * - decoding: unused - */ - attribute_deprecated int scenechange_factor; -#endif - /** * Note: Value depends upon the compare function used for fullpel ME. * - encoding: Set by user. @@ -2718,19 +2369,6 @@ typedef struct AVCodecContext { */ int max_qdiff; -#if FF_API_MPV_OPT - /** - * @deprecated use encoder private options instead - */ - attribute_deprecated - float rc_qsquish; - - attribute_deprecated - float rc_qmod_amp; - attribute_deprecated - int rc_qmod_freq; -#endif - /** * decoder bitstream buffer size * - encoding: Set by user. @@ -2746,14 +2384,6 @@ typedef struct AVCodecContext { int rc_override_count; RcOverride *rc_override; -#if FF_API_MPV_OPT - /** - * @deprecated use encoder private options instead - */ - attribute_deprecated - const char *rc_eq; -#endif - /** * maximum bitrate * - encoding: Set by user. @@ -2768,17 +2398,6 @@ typedef struct AVCodecContext { */ int64_t rc_min_rate; -#if FF_API_MPV_OPT - /** - * @deprecated use encoder private options instead - */ - attribute_deprecated - float rc_buffer_aggressivity; - - attribute_deprecated - float rc_initial_cplx; -#endif - /** * Ratecontrol attempt to use, at maximum, of what can be used without an underflow. * - encoding: Set by user. @@ -2805,9 +2424,6 @@ typedef struct AVCodecContext { #define FF_CODER_TYPE_AC 1 #define FF_CODER_TYPE_RAW 2 #define FF_CODER_TYPE_RLE 3 -#if FF_API_UNUSED_MEMBERS -#define FF_CODER_TYPE_DEFLATE 4 -#endif /* FF_API_UNUSED_MEMBERS */ /** * @deprecated use encoder private options instead */ @@ -2821,20 +2437,6 @@ typedef struct AVCodecContext { int context_model; #endif -#if FF_API_MPV_OPT - /** - * @deprecated use encoder private options instead - */ - attribute_deprecated - int lmin; - - /** - * @deprecated use encoder private options instead - */ - attribute_deprecated - int lmax; -#endif - #if FF_API_PRIVATE_OPT /** @deprecated use encoder private options instead */ attribute_deprecated @@ -2945,16 +2547,10 @@ typedef struct AVCodecContext { */ int workaround_bugs; #define FF_BUG_AUTODETECT 1 ///< autodetection -#if FF_API_OLD_MSMPEG4 -#define FF_BUG_OLD_MSMPEG4 2 -#endif #define FF_BUG_XVID_ILACE 4 #define FF_BUG_UMP4 8 #define FF_BUG_NO_PADDING 16 #define FF_BUG_AMV 32 -#if FF_API_AC_VLC -#define FF_BUG_AC_VLC 0 ///< Will be removed, libavcodec can now handle these non-compliant files by default. -#endif #define FF_BUG_QPEL_CHROMA 64 #define FF_BUG_STD_QPEL 128 #define FF_BUG_QPEL_CHROMA2 256 @@ -3015,9 +2611,6 @@ typedef struct AVCodecContext { #define FF_DEBUG_DCT_COEFF 0x00000040 #define FF_DEBUG_SKIP 0x00000080 #define FF_DEBUG_STARTCODE 0x00000100 -#if FF_API_UNUSED_MEMBERS -#define FF_DEBUG_PTS 0x00000200 -#endif /* FF_API_UNUSED_MEMBERS */ #define FF_DEBUG_ER 0x00000400 #define FF_DEBUG_MMCO 0x00000800 #define FF_DEBUG_BUGS 0x00001000 @@ -3079,7 +2672,7 @@ typedef struct AVCodecContext { * - encoding: unused. * - decoding: Set by libavcodec */ - struct AVHWAccel *hwaccel; + const struct AVHWAccel *hwaccel; /** * Hardware accelerator context. @@ -3125,27 +2718,13 @@ typedef struct AVCodecContext { #define FF_IDCT_SIMPLEMMX 3 #define FF_IDCT_ARM 7 #define FF_IDCT_ALTIVEC 8 -#if FF_API_ARCH_SH4 -#define FF_IDCT_SH4 9 -#endif #define FF_IDCT_SIMPLEARM 10 -#if FF_API_UNUSED_MEMBERS -#define FF_IDCT_IPP 13 -#endif /* FF_API_UNUSED_MEMBERS */ #define FF_IDCT_XVID 14 -#if FF_API_IDCT_XVIDMMX -#define FF_IDCT_XVIDMMX 14 -#endif /* FF_API_IDCT_XVIDMMX */ #define FF_IDCT_SIMPLEARMV5TE 16 #define FF_IDCT_SIMPLEARMV6 17 -#if FF_API_ARCH_SPARC -#define FF_IDCT_SIMPLEVIS 18 -#endif #define FF_IDCT_FAAN 20 #define FF_IDCT_SIMPLENEON 22 -#if FF_API_ARCH_ALPHA -#define FF_IDCT_SIMPLEALPHA 23 -#endif +#define FF_IDCT_NONE 24 /* Used by XvMC to extract IDCT coefficients with FF_IDCT_PERM_NONE */ #define FF_IDCT_SIMPLEAUTO 128 /** @@ -3355,6 +2934,18 @@ typedef struct AVCodecContext { #define FF_PROFILE_HEVC_MAIN_STILL_PICTURE 3 #define FF_PROFILE_HEVC_REXT 4 +#define FF_PROFILE_AV1_MAIN 0 +#define FF_PROFILE_AV1_HIGH 1 +#define FF_PROFILE_AV1_PROFESSIONAL 2 + +#define FF_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT 0xc0 +#define FF_PROFILE_MJPEG_HUFFMAN_EXTENDED_SEQUENTIAL_DCT 0xc1 +#define FF_PROFILE_MJPEG_HUFFMAN_PROGRESSIVE_DCT 0xc2 +#define FF_PROFILE_MJPEG_HUFFMAN_LOSSLESS 0xc3 +#define FF_PROFILE_MJPEG_JPEG_LS 0xf7 + +#define FF_PROFILE_SBC_MSBC 1 + /** * level * - encoding: Set by user. @@ -3395,15 +2986,6 @@ typedef struct AVCodecContext { uint8_t *subtitle_header; int subtitle_header_size; -#if FF_API_ERROR_RATE - /** - * @deprecated use the 'error_rate' private AVOption of the mpegvideo - * encoders - */ - attribute_deprecated - int error_rate; -#endif - #if FF_API_VBV_DELAY /** * VBV delay coded in the last frame (in periods of a 27 MHz clock). @@ -3515,6 +3097,7 @@ typedef struct AVCodecContext { #define FF_SUB_CHARENC_MODE_DO_NOTHING -1 ///< do nothing (demuxer outputs a stream supposed to be already in UTF-8, or the codec is bitmap for instance) #define FF_SUB_CHARENC_MODE_AUTOMATIC 0 ///< libavcodec will select the mode itself #define FF_SUB_CHARENC_MODE_PRE_DECODER 1 ///< the AVPacket data needs to be recoded to UTF-8 before being fed to the decoder, requires iconv +#define FF_SUB_CHARENC_MODE_IGNORE 2 ///< neither convert the subtitles, nor check them for valid UTF-8 /** * Skip processing alpha if supported by codec. @@ -3701,24 +3284,57 @@ typedef struct AVCodecContext { * (with the display dimensions being determined by the crop_* fields). */ int apply_cropping; + + /* + * Video decoding only. Sets the number of extra hardware frames which + * the decoder will allocate for use by the caller. This must be set + * before avcodec_open2() is called. + * + * Some hardware decoders require all frames that they will use for + * output to be defined in advance before decoding starts. For such + * decoders, the hardware frame pool must therefore be of a fixed size. + * The extra frames set here are on top of any number that the decoder + * needs internally in order to operate normally (for example, frames + * used as reference pictures). + */ + int extra_hw_frames; } AVCodecContext; +#if FF_API_CODEC_GET_SET +/** + * Accessors for some AVCodecContext fields. These used to be provided for ABI + * compatibility, and do not need to be used anymore. + */ +attribute_deprecated AVRational av_codec_get_pkt_timebase (const AVCodecContext *avctx); +attribute_deprecated void av_codec_set_pkt_timebase (AVCodecContext *avctx, AVRational val); +attribute_deprecated const AVCodecDescriptor *av_codec_get_codec_descriptor(const AVCodecContext *avctx); +attribute_deprecated void av_codec_set_codec_descriptor(AVCodecContext *avctx, const AVCodecDescriptor *desc); +attribute_deprecated unsigned av_codec_get_codec_properties(const AVCodecContext *avctx); +#if FF_API_LOWRES +attribute_deprecated int av_codec_get_lowres(const AVCodecContext *avctx); +attribute_deprecated void av_codec_set_lowres(AVCodecContext *avctx, int val); +#endif +attribute_deprecated int av_codec_get_seek_preroll(const AVCodecContext *avctx); +attribute_deprecated void av_codec_set_seek_preroll(AVCodecContext *avctx, int val); +attribute_deprecated uint16_t *av_codec_get_chroma_intra_matrix(const AVCodecContext *avctx); +attribute_deprecated void av_codec_set_chroma_intra_matrix(AVCodecContext *avctx, uint16_t *val); +#endif /** * AVProfile. @@ -3728,6 +3344,61 @@ typedef struct AVProfile { const char *name; ///< short name for the profile } AVProfile; +enum { + /** + * The codec supports this format via the hw_device_ctx interface. + * + * When selecting this format, AVCodecContext.hw_device_ctx should + * have been set to a device of the specified type before calling + * avcodec_open2(). + */ + AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX = 0x01, + /** + * The codec supports this format via the hw_frames_ctx interface. + * + * When selecting this format for a decoder, + * AVCodecContext.hw_frames_ctx should be set to a suitable frames + * context inside the get_format() callback. The frames context + * must have been created on a device of the specified type. + */ + AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX = 0x02, + /** + * The codec supports this format by some internal method. + * + * This format can be selected without any additional configuration - + * no device or frames context is required. + */ + AV_CODEC_HW_CONFIG_METHOD_INTERNAL = 0x04, + /** + * The codec supports this format by some ad-hoc method. + * + * Additional settings and/or function calls are required. See the + * codec-specific documentation for details. (Methods requiring + * this sort of configuration are deprecated and others should be + * used in preference.) + */ + AV_CODEC_HW_CONFIG_METHOD_AD_HOC = 0x08, +}; + +typedef struct AVCodecHWConfig { + /** + * A hardware pixel format which the codec can use. + */ + enum AVPixelFormat pix_fmt; + /** + * Bit set of AV_CODEC_HW_CONFIG_METHOD_* flags, describing the possible + * setup methods which can be used with this configuration. + */ + int methods; + /** + * The device type associated with the configuration. + * + * Must be set for AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX and + * AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX, otherwise unused. + */ + enum AVHWDeviceType device_type; +} AVCodecHWConfig; + typedef struct AVCodecDefault AVCodecDefault; struct AVSubtitle; @@ -3764,6 +3435,18 @@ typedef struct AVCodec { const AVClass *priv_class; ///< AVClass for the private context const AVProfile *profiles; ///< array of recognized profiles, or NULL if unknown, array is terminated by {FF_PROFILE_UNKNOWN} + /** + * Group name of the codec implementation. + * This is a short symbolic name of the wrapper backing this codec. A + * wrapper uses some kind of external implementation for the codec, such + * as an external library, or a codec implementation provided by the OS or + * the hardware. + * If this field is NULL, this is a builtin, libavcodec native codec. + * If non-NULL, this will be the suffix in AVCodec.name in most cases + * (usually AVCodec.name will be of the form "_"). + */ + const char *wrapper_name; + /***************************************************************** * No fields below this line are part of the public API. They * may not be used outside of libavcodec and can be changed and @@ -3800,6 +3483,9 @@ typedef struct AVCodec { /** * Initialize codec static data, called from avcodec_register(). + * + * This is not intended for time consuming operations as it is + * run for every codec regardless of that codec being used. */ void (*init_static_data)(struct AVCodec *codec); @@ -3853,14 +3539,39 @@ typedef struct AVCodec { * packets before decoding. */ const char *bsfs; + + /** + * Array of pointers to hardware configurations supported by the codec, + * or NULL if no hardware supported. The array is terminated by a NULL + * pointer. + * + * The user can only access this field via avcodec_get_hw_config(). + */ + const struct AVCodecHWConfigInternal **hw_configs; } AVCodec; +#if FF_API_CODEC_GET_SET +attribute_deprecated int av_codec_get_max_lowres(const AVCodec *codec); +#endif struct MpegEncContext; +/** + * Retrieve supported hardware configurations for a codec. + * + * Values of index from zero to some maximum return the indexed configuration + * descriptor; all other values return NULL. If the codec does not support + * any hardware configurations then it will always return NULL. + */ +const AVCodecHWConfig *avcodec_get_hw_config(const AVCodec *codec, int index); + /** * @defgroup lavc_hwaccel AVHWAccel + * + * @note Nothing in this structure should be accessed by the user. At some + * point in future it will not be externally visible at all. + * * @{ */ typedef struct AVHWAccel { @@ -3905,7 +3616,6 @@ typedef struct AVHWAccel { * New public fields should be added right above. ***************************************************************** */ - struct AVHWAccel *next; /** * Allocate a custom buffer @@ -3928,6 +3638,20 @@ typedef struct AVHWAccel { */ int (*start_frame)(AVCodecContext *avctx, const uint8_t *buf, uint32_t buf_size); + /** + * Callback for parameter data (SPS/PPS/VPS etc). + * + * Useful for hardware decoders which keep persistent state about the + * video parameters, and need to receive any changes to update that state. + * + * @param avctx the codec context + * @param type the nal unit type + * @param buf the nal unit data buffer + * @param buf_size the size of the nal unit in bytes + * @return zero if successful, a negative value otherwise + */ + int (*decode_params)(AVCodecContext *avctx, int type, const uint8_t *buf, uint32_t buf_size); + /** * Callback for each slice. * @@ -4000,6 +3724,16 @@ typedef struct AVHWAccel { * Internal hwaccel capabilities. */ int caps_internal; + + /** + * Fill the given hw_frames context with current codec parameters. Called + * from get_format. Refer to avcodec_get_hw_frames_parameters() for + * details. + * + * This CAN be called before AVHWAccel.init is called, and you must assume + * that avctx->hwaccel_priv_data is invalid. + */ + int (*frame_params)(AVCodecContext *avctx, AVBufferRef *hw_frames_ctx); } AVHWAccel; /** @@ -4291,12 +4025,26 @@ typedef struct AVCodecParameters { int seek_preroll; } AVCodecParameters; +/** + * Iterate over all registered codecs. + * + * @param opaque a pointer where libavcodec will store the iteration state. Must + * point to NULL to start the iteration. + * + * @return the next registered codec or NULL when the iteration is + * finished + */ +const AVCodec *av_codec_iterate(void **opaque); + +#if FF_API_NEXT /** * If c is NULL, returns the first registered codec, * if c is non-NULL, returns the next registered codec after c, * or NULL if c is the last one. */ +attribute_deprecated AVCodec *av_codec_next(const AVCodec *c); +#endif /** * Return the LIBAVCODEC_VERSION_INT constant. @@ -4313,6 +4061,7 @@ const char *avcodec_configuration(void); */ const char *avcodec_license(void); +#if FF_API_NEXT /** * Register the codec codec and initialize libavcodec. * @@ -4321,6 +4070,7 @@ const char *avcodec_license(void); * * @see avcodec_register_all() */ +attribute_deprecated void avcodec_register(AVCodec *codec); /** @@ -4333,7 +4083,9 @@ void avcodec_register(AVCodec *codec); * @see av_register_codec_parser * @see av_register_bitstream_filter */ +attribute_deprecated void avcodec_register_all(void); +#endif /** * Allocate an AVCodecContext and set its fields to default values. The @@ -4614,7 +4366,7 @@ int av_packet_from_data(AVPacket *pkt, uint8_t *data, int size); * @warning This is a hack - the packet memory allocation stuff is broken. The * packet is allocated if it was not really allocated. * - * @deprecated Use av_packet_ref + * @deprecated Use av_packet_ref or av_packet_make_refcounted */ attribute_deprecated int av_dup_packet(AVPacket *pkt); @@ -4785,6 +4537,33 @@ void av_packet_move_ref(AVPacket *dst, AVPacket *src); */ int av_packet_copy_props(AVPacket *dst, const AVPacket *src); +/** + * Ensure the data described by a given packet is reference counted. + * + * @note This function does not ensure that the reference will be writable. + * Use av_packet_make_writable instead for that purpose. + * + * @see av_packet_ref + * @see av_packet_make_writable + * + * @param pkt packet whose data should be made reference counted. + * + * @return 0 on success, a negative AVERROR on error. On failure, the + * packet is unchanged. + */ +int av_packet_make_refcounted(AVPacket *pkt); + +/** + * Create a writable reference for the data described by a given packet, + * avoiding data copy if possible. + * + * @param pkt Packet whose data should be made writable. + * + * @return 0 on success, a negative AVERROR on failure. On failure, the + * packet is unchanged. + */ +int av_packet_make_writable(AVPacket *pkt); + /** * Convert valid timing fields (timestamps / durations) in a packet from one * timebase to another. Timestamps with unknown values (AV_NOPTS_VALUE) will be @@ -4830,21 +4609,6 @@ AVCodec *avcodec_find_decoder_by_name(const char *name); */ int avcodec_default_get_buffer2(AVCodecContext *s, AVFrame *frame, int flags); -#if FF_API_EMU_EDGE -/** - * Return the amount of padding in pixels which the get_buffer callback must - * provide around the edge of the image for codecs which do not have the - * CODEC_FLAG_EMU_EDGE flag. - * - * @return Required padding in pixels. - * - * @deprecated CODEC_FLAG_EMU_EDGE is deprecated, so this function is no longer - * needed - */ -attribute_deprecated -unsigned avcodec_get_edge_width(void); -#endif - /** * Modify width and height values so that they will result in a memory * buffer that is acceptable for the codec if you do not use any horizontal @@ -5150,6 +4914,109 @@ int avcodec_send_frame(AVCodecContext *avctx, const AVFrame *frame); */ int avcodec_receive_packet(AVCodecContext *avctx, AVPacket *avpkt); +/** + * Create and return a AVHWFramesContext with values adequate for hardware + * decoding. This is meant to get called from the get_format callback, and is + * a helper for preparing a AVHWFramesContext for AVCodecContext.hw_frames_ctx. + * This API is for decoding with certain hardware acceleration modes/APIs only. + * + * The returned AVHWFramesContext is not initialized. The caller must do this + * with av_hwframe_ctx_init(). + * + * Calling this function is not a requirement, but makes it simpler to avoid + * codec or hardware API specific details when manually allocating frames. + * + * Alternatively to this, an API user can set AVCodecContext.hw_device_ctx, + * which sets up AVCodecContext.hw_frames_ctx fully automatically, and makes + * it unnecessary to call this function or having to care about + * AVHWFramesContext initialization at all. + * + * There are a number of requirements for calling this function: + * + * - It must be called from get_format with the same avctx parameter that was + * passed to get_format. Calling it outside of get_format is not allowed, and + * can trigger undefined behavior. + * - The function is not always supported (see description of return values). + * Even if this function returns successfully, hwaccel initialization could + * fail later. (The degree to which implementations check whether the stream + * is actually supported varies. Some do this check only after the user's + * get_format callback returns.) + * - The hw_pix_fmt must be one of the choices suggested by get_format. If the + * user decides to use a AVHWFramesContext prepared with this API function, + * the user must return the same hw_pix_fmt from get_format. + * - The device_ref passed to this function must support the given hw_pix_fmt. + * - After calling this API function, it is the user's responsibility to + * initialize the AVHWFramesContext (returned by the out_frames_ref parameter), + * and to set AVCodecContext.hw_frames_ctx to it. If done, this must be done + * before returning from get_format (this is implied by the normal + * AVCodecContext.hw_frames_ctx API rules). + * - The AVHWFramesContext parameters may change every time time get_format is + * called. Also, AVCodecContext.hw_frames_ctx is reset before get_format. So + * you are inherently required to go through this process again on every + * get_format call. + * - It is perfectly possible to call this function without actually using + * the resulting AVHWFramesContext. One use-case might be trying to reuse a + * previously initialized AVHWFramesContext, and calling this API function + * only to test whether the required frame parameters have changed. + * - Fields that use dynamically allocated values of any kind must not be set + * by the user unless setting them is explicitly allowed by the documentation. + * If the user sets AVHWFramesContext.free and AVHWFramesContext.user_opaque, + * the new free callback must call the potentially set previous free callback. + * This API call may set any dynamically allocated fields, including the free + * callback. + * + * The function will set at least the following fields on AVHWFramesContext + * (potentially more, depending on hwaccel API): + * + * - All fields set by av_hwframe_ctx_alloc(). + * - Set the format field to hw_pix_fmt. + * - Set the sw_format field to the most suited and most versatile format. (An + * implication is that this will prefer generic formats over opaque formats + * with arbitrary restrictions, if possible.) + * - Set the width/height fields to the coded frame size, rounded up to the + * API-specific minimum alignment. + * - Only _if_ the hwaccel requires a pre-allocated pool: set the initial_pool_size + * field to the number of maximum reference surfaces possible with the codec, + * plus 1 surface for the user to work (meaning the user can safely reference + * at most 1 decoded surface at a time), plus additional buffering introduced + * by frame threading. If the hwaccel does not require pre-allocation, the + * field is left to 0, and the decoder will allocate new surfaces on demand + * during decoding. + * - Possibly AVHWFramesContext.hwctx fields, depending on the underlying + * hardware API. + * + * Essentially, out_frames_ref returns the same as av_hwframe_ctx_alloc(), but + * with basic frame parameters set. + * + * The function is stateless, and does not change the AVCodecContext or the + * device_ref AVHWDeviceContext. + * + * @param avctx The context which is currently calling get_format, and which + * implicitly contains all state needed for filling the returned + * AVHWFramesContext properly. + * @param device_ref A reference to the AVHWDeviceContext describing the device + * which will be used by the hardware decoder. + * @param hw_pix_fmt The hwaccel format you are going to return from get_format. + * @param out_frames_ref On success, set to a reference to an _uninitialized_ + * AVHWFramesContext, created from the given device_ref. + * Fields will be set to values required for decoding. + * Not changed if an error is returned. + * @return zero on success, a negative value on error. The following error codes + * have special semantics: + * AVERROR(ENOENT): the decoder does not support this functionality. Setup + * is always manual, or it is a decoder which does not + * support setting AVCodecContext.hw_frames_ctx at all, + * or it is a software format. + * AVERROR(EINVAL): it is known that hardware decoding is not supported for + * this configuration, or the device_ref is not supported + * for the hwaccel referenced by hw_pix_fmt. + */ +int avcodec_get_hw_frames_parameters(AVCodecContext *avctx, + AVBufferRef *device_ref, + enum AVPixelFormat hw_pix_fmt, + AVBufferRef **out_frames_ref); + + /** * @defgroup lavc_parsing Frame parsing @@ -5345,8 +5212,21 @@ typedef struct AVCodecParser { struct AVCodecParser *next; } AVCodecParser; +/** + * Iterate over all registered codec parsers. + * + * @param opaque a pointer where libavcodec will store the iteration state. Must + * point to NULL to start the iteration. + * + * @return the next registered codec parser or NULL when the iteration is + * finished + */ +const AVCodecParser *av_parser_iterate(void **opaque); + +attribute_deprecated AVCodecParser *av_parser_next(const AVCodecParser *c); +attribute_deprecated void av_register_codec_parser(AVCodecParser *parser); AVCodecParserContext *av_parser_init(int codec_id); @@ -5515,103 +5395,6 @@ int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size, * @} */ -#if FF_API_AVCODEC_RESAMPLE -/** - * @defgroup lavc_resample Audio resampling - * @ingroup libavc - * @deprecated use libswresample instead - * - * @{ - */ -struct ReSampleContext; -struct AVResampleContext; - -typedef struct ReSampleContext ReSampleContext; - -/** - * Initialize audio resampling context. - * - * @param output_channels number of output channels - * @param input_channels number of input channels - * @param output_rate output sample rate - * @param input_rate input sample rate - * @param sample_fmt_out requested output sample format - * @param sample_fmt_in input sample format - * @param filter_length length of each FIR filter in the filterbank relative to the cutoff frequency - * @param log2_phase_count log2 of the number of entries in the polyphase filterbank - * @param linear if 1 then the used FIR filter will be linearly interpolated - between the 2 closest, if 0 the closest will be used - * @param cutoff cutoff frequency, 1.0 corresponds to half the output sampling rate - * @return allocated ReSampleContext, NULL if error occurred - */ -attribute_deprecated -ReSampleContext *av_audio_resample_init(int output_channels, int input_channels, - int output_rate, int input_rate, - enum AVSampleFormat sample_fmt_out, - enum AVSampleFormat sample_fmt_in, - int filter_length, int log2_phase_count, - int linear, double cutoff); - -attribute_deprecated -int audio_resample(ReSampleContext *s, short *output, short *input, int nb_samples); - -/** - * Free resample context. - * - * @param s a non-NULL pointer to a resample context previously - * created with av_audio_resample_init() - */ -attribute_deprecated -void audio_resample_close(ReSampleContext *s); - - -/** - * Initialize an audio resampler. - * Note, if either rate is not an integer then simply scale both rates up so they are. - * @param filter_length length of each FIR filter in the filterbank relative to the cutoff freq - * @param log2_phase_count log2 of the number of entries in the polyphase filterbank - * @param linear If 1 then the used FIR filter will be linearly interpolated - between the 2 closest, if 0 the closest will be used - * @param cutoff cutoff frequency, 1.0 corresponds to half the output sampling rate - */ -attribute_deprecated -struct AVResampleContext *av_resample_init(int out_rate, int in_rate, int filter_length, int log2_phase_count, int linear, double cutoff); - -/** - * Resample an array of samples using a previously configured context. - * @param src an array of unconsumed samples - * @param consumed the number of samples of src which have been consumed are returned here - * @param src_size the number of unconsumed samples available - * @param dst_size the amount of space in samples available in dst - * @param update_ctx If this is 0 then the context will not be modified, that way several channels can be resampled with the same context. - * @return the number of samples written in dst or -1 if an error occurred - */ -attribute_deprecated -int av_resample(struct AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx); - - -/** - * Compensate samplerate/timestamp drift. The compensation is done by changing - * the resampler parameters, so no audible clicks or similar distortions occur - * @param compensation_distance distance in output samples over which the compensation should be performed - * @param sample_delta number of output samples which should be output less - * - * example: av_resample_compensate(c, 10, 500) - * here instead of 510 samples only 500 samples would be output - * - * note, due to rounding the actual compensation might be slightly different, - * especially if the compensation_distance is large and the in_rate used during init is small - */ -attribute_deprecated -void av_resample_compensate(struct AVResampleContext *c, int sample_delta, int compensation_distance); -attribute_deprecated -void av_resample_close(struct AVResampleContext *c); - -/** - * @} - */ -#endif - #if FF_API_AVPICTURE /** * @addtogroup lavc_picture @@ -5752,14 +5535,6 @@ enum AVPixelFormat avcodec_default_get_format(struct AVCodecContext *s, const en * @} */ -#if FF_API_SET_DIMENSIONS -/** - * @deprecated this function is not supposed to be used from outside of lavc - */ -attribute_deprecated -void avcodec_set_dimensions(AVCodecContext *s, int width, int height); -#endif - #if FF_API_TAG_STRING /** * Put a string representing the codec tag codec_tag in buf. @@ -5996,84 +5771,42 @@ typedef struct AVBitStreamFilter { #if FF_API_OLD_BSF /** - * Register a bitstream filter. - * - * The filter will be accessible to the application code through - * av_bitstream_filter_next() or can be directly initialized with - * av_bitstream_filter_init(). - * - * @see avcodec_register_all() + * @deprecated the old bitstream filtering API (using AVBitStreamFilterContext) + * is deprecated. Use the new bitstream filtering API (using AVBSFContext). */ attribute_deprecated void av_register_bitstream_filter(AVBitStreamFilter *bsf); - /** - * Create and initialize a bitstream filter context given a bitstream - * filter name. - * - * The returned context must be freed with av_bitstream_filter_close(). - * - * @param name the name of the bitstream filter - * @return a bitstream filter context if a matching filter was found - * and successfully initialized, NULL otherwise + * @deprecated the old bitstream filtering API (using AVBitStreamFilterContext) + * is deprecated. Use av_bsf_get_by_name(), av_bsf_alloc(), and av_bsf_init() + * from the new bitstream filtering API (using AVBSFContext). */ attribute_deprecated AVBitStreamFilterContext *av_bitstream_filter_init(const char *name); - /** - * Filter bitstream. - * - * This function filters the buffer buf with size buf_size, and places the - * filtered buffer in the buffer pointed to by poutbuf. - * - * The output buffer must be freed by the caller. - * - * @param bsfc bitstream filter context created by av_bitstream_filter_init() - * @param avctx AVCodecContext accessed by the filter, may be NULL. - * If specified, this must point to the encoder context of the - * output stream the packet is sent to. - * @param args arguments which specify the filter configuration, may be NULL - * @param poutbuf pointer which is updated to point to the filtered buffer - * @param poutbuf_size pointer which is updated to the filtered buffer size in bytes - * @param buf buffer containing the data to filter - * @param buf_size size in bytes of buf - * @param keyframe set to non-zero if the buffer to filter corresponds to a key-frame packet data - * @return >= 0 in case of success, or a negative error code in case of failure - * - * If the return value is positive, an output buffer is allocated and - * is available in *poutbuf, and is distinct from the input buffer. - * - * If the return value is 0, the output buffer is not allocated and - * should be considered identical to the input buffer, or in case - * *poutbuf was set it points to the input buffer (not necessarily to - * its starting address). A special case is if *poutbuf was set to NULL and - * *poutbuf_size was set to 0, which indicates the packet should be dropped. + * @deprecated the old bitstream filtering API (using AVBitStreamFilterContext) + * is deprecated. Use av_bsf_send_packet() and av_bsf_receive_packet() from the + * new bitstream filtering API (using AVBSFContext). */ attribute_deprecated int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc, AVCodecContext *avctx, const char *args, uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size, int keyframe); - /** - * Release bitstream filter context. - * - * @param bsf the bitstream filter context created with - * av_bitstream_filter_init(), can be NULL + * @deprecated the old bitstream filtering API (using AVBitStreamFilterContext) + * is deprecated. Use av_bsf_free() from the new bitstream filtering API (using + * AVBSFContext). */ attribute_deprecated void av_bitstream_filter_close(AVBitStreamFilterContext *bsf); - /** - * If f is NULL, return the first registered bitstream filter, - * if f is non-NULL, return the next registered bitstream filter - * after f, or NULL if f is the last one. - * - * This function can be used to iterate over all registered bitstream - * filters. + * @deprecated the old bitstream filtering API (using AVBitStreamFilterContext) + * is deprecated. Use av_bsf_iterate() from the new bitstream filtering API (using + * AVBSFContext). */ attribute_deprecated -AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f); +const AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f); #endif /** @@ -6091,7 +5824,11 @@ const AVBitStreamFilter *av_bsf_get_by_name(const char *name); * @return the next registered bitstream filter or NULL when the iteration is * finished */ +const AVBitStreamFilter *av_bsf_iterate(void **opaque); +#if FF_API_NEXT +attribute_deprecated const AVBitStreamFilter *av_bsf_next(void **opaque); +#endif /** * Allocate a context for a given bitstream filter. The caller must fill in the @@ -6281,51 +6018,32 @@ void av_fast_padded_mallocz(void *ptr, unsigned int *size, size_t min_size); */ unsigned int av_xiphlacing(unsigned char *s, unsigned int v); -#if FF_API_MISSING_SAMPLE -/** - * Log a generic warning message about a missing feature. This function is - * intended to be used internally by FFmpeg (libavcodec, libavformat, etc.) - * only, and would normally not be used by applications. - * @param[in] avc a pointer to an arbitrary struct of which the first field is - * a pointer to an AVClass struct - * @param[in] feature string containing the name of the missing feature - * @param[in] want_sample indicates if samples are wanted which exhibit this feature. - * If want_sample is non-zero, additional verbiage will be added to the log - * message which tells the user how to report samples to the development - * mailing list. - * @deprecated Use avpriv_report_missing_feature() instead. - */ -attribute_deprecated -void av_log_missing_feature(void *avc, const char *feature, int want_sample); - -/** - * Log a generic warning message asking for a sample. This function is - * intended to be used internally by FFmpeg (libavcodec, libavformat, etc.) - * only, and would normally not be used by applications. - * @param[in] avc a pointer to an arbitrary struct of which the first field is - * a pointer to an AVClass struct - * @param[in] msg string containing an optional message, or NULL if no message - * @deprecated Use avpriv_request_sample() instead. - */ -attribute_deprecated -void av_log_ask_for_sample(void *avc, const char *msg, ...) av_printf_format(2, 3); -#endif /* FF_API_MISSING_SAMPLE */ - +#if FF_API_USER_VISIBLE_AVHWACCEL /** * Register the hardware accelerator hwaccel. + * + * @deprecated This function doesn't do anything. */ +attribute_deprecated void av_register_hwaccel(AVHWAccel *hwaccel); /** * If hwaccel is NULL, returns the first registered hardware accelerator, * if hwaccel is non-NULL, returns the next registered hardware accelerator * after hwaccel, or NULL if hwaccel is the last one. + * + * @deprecated AVHWaccel structures contain no user-serviceable parts, so + * this function should not be used. */ +attribute_deprecated AVHWAccel *av_hwaccel_next(const AVHWAccel *hwaccel); +#endif - +#if FF_API_LOCKMGR /** * Lock operation used by lockmgr + * + * @deprecated Deprecated together with av_lockmgr_register(). */ enum AVLockOp { AV_LOCK_CREATE, ///< Create a mutex @@ -6356,8 +6074,13 @@ enum AVLockOp { * mechanism (i.e. do not use a single static object to * implement your lock manager). If cb is set to NULL the * lockmgr will be unregistered. + * + * @deprecated This function does nothing, and always returns 0. Be sure to + * build with thread support to get basic thread safety. */ +attribute_deprecated int av_lockmgr_register(int (*cb)(void **mutex, enum AVLockOp op)); +#endif /** * Get the type of the given codec. diff --git a/libavcodec/avdct.c b/libavcodec/avdct.c index 80aca8872bbf8..47e5f7134ea26 100644 --- a/libavcodec/avdct.c +++ b/libavcodec/avdct.c @@ -48,19 +48,10 @@ static const AVOption avdct_options[] = { {"simplemmx", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEMMX }, INT_MIN, INT_MAX, V|E|D, "idct"}, {"arm", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_ARM }, INT_MIN, INT_MAX, V|E|D, "idct"}, {"altivec", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_ALTIVEC }, INT_MIN, INT_MAX, V|E|D, "idct"}, -#if FF_API_ARCH_SH4 -{"sh4", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SH4 }, INT_MIN, INT_MAX, V|E|D, "idct"}, -#endif {"simplearm", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEARM }, INT_MIN, INT_MAX, V|E|D, "idct"}, {"simplearmv5te", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEARMV5TE }, INT_MIN, INT_MAX, V|E|D, "idct"}, {"simplearmv6", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEARMV6 }, INT_MIN, INT_MAX, V|E|D, "idct"}, {"simpleneon", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLENEON }, INT_MIN, INT_MAX, V|E|D, "idct"}, -#if FF_API_ARCH_ALPHA -{"simplealpha", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEALPHA }, INT_MIN, INT_MAX, V|E|D, "idct"}, -#endif -#if FF_API_UNUSED_MEMBERS -{"ipp", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_IPP }, INT_MIN, INT_MAX, V|E|D, "idct"}, -#endif {"xvid", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_XVID }, INT_MIN, INT_MAX, V|E|D, "idct"}, {"xvidmmx", "experimental / for debugging", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_XVID }, INT_MIN, INT_MAX, V|E|D, "idct"}, {"faani", "floating point AAN IDCT (experimental / for debugging)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_FAAN }, INT_MIN, INT_MAX, V|D|E, "idct"}, @@ -132,8 +123,7 @@ int avcodec_dct_init(AVDCT *dsp) } #endif - avcodec_close(avctx); - av_free(avctx); + avcodec_free_context(&avctx); return 0; } diff --git a/libavcodec/avpacket.c b/libavcodec/avpacket.c index d1f4ea9eb3feb..99a0c1383bd1b 100644 --- a/libavcodec/avpacket.c +++ b/libavcodec/avpacket.c @@ -479,34 +479,6 @@ int av_packet_split_side_data(AVPacket *pkt){ } #endif -#if FF_API_MERGE_SD -int ff_packet_split_and_drop_side_data(AVPacket *pkt){ - if (!pkt->side_data_elems && pkt->size >12 && AV_RB64(pkt->data + pkt->size - 8) == FF_MERGE_MARKER){ - int i; - unsigned int size; - uint8_t *p; - - p = pkt->data + pkt->size - 8 - 5; - for (i=1; ; i++){ - size = AV_RB32(p); - if (size>INT_MAX - 5 || p - pkt->data < size) - return 0; - if (p[4]&128) - break; - if (p - pkt->data < size + 5) - return 0; - p-= size+5; - if (i > AV_PKT_DATA_NB) - return 0; - } - pkt->size = p - pkt->data - size; - av_assert0(pkt->size >= 0); - return 1; - } - return 0; -} -#endif - uint8_t *av_packet_pack_dictionary(AVDictionary *dict, int *size) { AVDictionaryEntry *t = NULL; @@ -599,6 +571,8 @@ FF_ENABLE_DEPRECATION_WARNINGS dst->flags = src->flags; dst->stream_index = src->stream_index; + dst->side_data = NULL; + dst->side_data_elems = 0; for (i = 0; i < src->side_data_elems; i++) { enum AVPacketSideDataType type = src->side_data[i].type; int size = src->side_data[i].size; @@ -678,6 +652,45 @@ void av_packet_move_ref(AVPacket *dst, AVPacket *src) src->size = 0; } +int av_packet_make_refcounted(AVPacket *pkt) +{ + int ret; + + if (pkt->buf) + return 0; + + ret = packet_alloc(&pkt->buf, pkt->size); + if (ret < 0) + return ret; + if (pkt->size) + memcpy(pkt->buf->data, pkt->data, pkt->size); + + pkt->data = pkt->buf->data; + + return 0; +} + +int av_packet_make_writable(AVPacket *pkt) +{ + AVBufferRef *buf = NULL; + int ret; + + if (pkt->buf && av_buffer_is_writable(pkt->buf)) + return 0; + + ret = packet_alloc(&buf, pkt->size); + if (ret < 0) + return ret; + if (pkt->size) + memcpy(buf->data, pkt->data, pkt->size); + + av_buffer_unref(&pkt->buf); + pkt->buf = buf; + pkt->data = buf->data; + + return 0; +} + void av_packet_rescale_ts(AVPacket *pkt, AVRational src_tb, AVRational dst_tb) { if (pkt->pts != AV_NOPTS_VALUE) diff --git a/libavcodec/avrndec.c b/libavcodec/avrndec.c index c37f99661b5dc..104ff2d9048ee 100644 --- a/libavcodec/avrndec.c +++ b/libavcodec/avrndec.c @@ -168,7 +168,6 @@ AVCodec ff_avrn_decoder = { .init = init, .close = end, .decode = decode_frame, - .capabilities = AV_CODEC_CAP_DR1, .max_lowres = 3, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, }; diff --git a/libavcodec/bink.c b/libavcodec/bink.c index 346b6cda9dfb6..c4cf617a8bc80 100644 --- a/libavcodec/bink.c +++ b/libavcodec/bink.c @@ -601,17 +601,16 @@ static inline int binkb_get_value(BinkContext *c, int bundle_num) * @param quant_matrices quantization matrices * @return 0 for success, negative value in other cases */ -static int read_dct_coeffs(GetBitContext *gb, int32_t block[64], const uint8_t *scan, - const int32_t quant_matrices[16][64], int q) +static int read_dct_coeffs(GetBitContext *gb, int32_t block[64], + const uint8_t *scan, int *coef_count_, + int coef_idx[64], int q) { int coef_list[128]; int mode_list[128]; int i, t, bits, ccoef, mode, sign; int list_start = 64, list_end = 64, list_pos; int coef_count = 0; - int coef_idx[64]; int quant_idx; - const int32_t *quant; coef_list[list_end] = 4; mode_list[list_end++] = 0; coef_list[list_end] = 24; mode_list[list_end++] = 0; @@ -690,15 +689,21 @@ static int read_dct_coeffs(GetBitContext *gb, int32_t block[64], const uint8_t * } } - quant = quant_matrices[quant_idx]; + *coef_count_ = coef_count; + return quant_idx; +} + +static void unquantize_dct_coeffs(int32_t block[64], const int32_t quant[64], + int coef_count, int coef_idx[64], + const uint8_t *scan) +{ + int i; block[0] = (block[0] * quant[0]) >> 11; for (i = 0; i < coef_count; i++) { int idx = coef_idx[i]; block[scan[idx]] = (block[scan[idx]] * quant[idx]) >> 11; } - - return 0; } /** @@ -817,7 +822,7 @@ static int binkb_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb, LOCAL_ALIGNED_16(int32_t, dctblock, [64]); int coordmap[64]; int ybias = is_key ? -15 : 0; - int qp; + int qp, quant_idx, coef_count, coef_idx[64]; const int stride = frame->linesize[plane_idx]; int bw = is_chroma ? (c->avctx->width + 15) >> 4 : (c->avctx->width + 7) >> 3; @@ -872,7 +877,9 @@ static int binkb_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb, memset(dctblock, 0, sizeof(*dctblock) * 64); dctblock[0] = binkb_get_value(c, BINKB_SRC_INTRA_DC); qp = binkb_get_value(c, BINKB_SRC_INTRA_Q); - read_dct_coeffs(gb, dctblock, bink_scan, (const int32_t (*)[64])binkb_intra_quant, qp); + if ((quant_idx = read_dct_coeffs(gb, dctblock, bink_scan, &coef_count, coef_idx, qp)) < 0) + return quant_idx; + unquantize_dct_coeffs(dctblock, binkb_intra_quant[quant_idx], coef_count, coef_idx, bink_scan); c->binkdsp.idct_put(dst, stride, dctblock); break; case 3: @@ -905,7 +912,9 @@ static int binkb_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb, memset(dctblock, 0, sizeof(*dctblock) * 64); dctblock[0] = binkb_get_value(c, BINKB_SRC_INTER_DC); qp = binkb_get_value(c, BINKB_SRC_INTER_Q); - read_dct_coeffs(gb, dctblock, bink_scan, (const int32_t (*)[64])binkb_inter_quant, qp); + if ((quant_idx = read_dct_coeffs(gb, dctblock, bink_scan, &coef_count, coef_idx, qp)) < 0) + return quant_idx; + unquantize_dct_coeffs(dctblock, binkb_inter_quant[quant_idx], coef_count, coef_idx, bink_scan); c->binkdsp.idct_add(dst, stride, dctblock); break; case 5: @@ -979,7 +988,7 @@ static int bink_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb, LOCAL_ALIGNED_32(int16_t, block, [64]); LOCAL_ALIGNED_16(uint8_t, ublock, [64]); LOCAL_ALIGNED_16(int32_t, dctblock, [64]); - int coordmap[64]; + int coordmap[64], quant_idx, coef_count, coef_idx[64]; const int stride = frame->linesize[plane_idx]; int bw = is_chroma ? (c->avctx->width + 15) >> 4 : (c->avctx->width + 7) >> 3; @@ -1065,7 +1074,9 @@ static int bink_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb, case INTRA_BLOCK: memset(dctblock, 0, sizeof(*dctblock) * 64); dctblock[0] = get_value(c, BINK_SRC_INTRA_DC); - read_dct_coeffs(gb, dctblock, bink_scan, bink_intra_quant, -1); + if ((quant_idx = read_dct_coeffs(gb, dctblock, bink_scan, &coef_count, coef_idx, -1)) < 0) + return quant_idx; + unquantize_dct_coeffs(dctblock, bink_intra_quant[quant_idx], coef_count, coef_idx, bink_scan); c->binkdsp.idct_put(ublock, 8, dctblock); break; case FILL_BLOCK: @@ -1138,7 +1149,9 @@ static int bink_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb, case INTRA_BLOCK: memset(dctblock, 0, sizeof(*dctblock) * 64); dctblock[0] = get_value(c, BINK_SRC_INTRA_DC); - read_dct_coeffs(gb, dctblock, bink_scan, bink_intra_quant, -1); + if ((quant_idx = read_dct_coeffs(gb, dctblock, bink_scan, &coef_count, coef_idx, -1)) < 0) + return quant_idx; + unquantize_dct_coeffs(dctblock, bink_intra_quant[quant_idx], coef_count, coef_idx, bink_scan); c->binkdsp.idct_put(dst, stride, dctblock); break; case FILL_BLOCK: @@ -1152,7 +1165,9 @@ static int bink_decode_plane(BinkContext *c, AVFrame *frame, GetBitContext *gb, return ret; memset(dctblock, 0, sizeof(*dctblock) * 64); dctblock[0] = get_value(c, BINK_SRC_INTER_DC); - read_dct_coeffs(gb, dctblock, bink_scan, bink_inter_quant, -1); + if ((quant_idx = read_dct_coeffs(gb, dctblock, bink_scan, &coef_count, coef_idx, -1)) < 0) + return quant_idx; + unquantize_dct_coeffs(dctblock, bink_inter_quant[quant_idx], coef_count, coef_idx, bink_scan); c->binkdsp.idct_add(dst, stride, dctblock); break; case PATTERN_BLOCK: diff --git a/libavcodec/bintext.c b/libavcodec/bintext.c index 90bbe67b59b69..d967317671b89 100644 --- a/libavcodec/bintext.c +++ b/libavcodec/bintext.c @@ -35,6 +35,8 @@ #include "bintext.h" #include "internal.h" +#define FONT_WIDTH 8 + typedef struct XbinContext { AVFrame *frame; int palette[16]; @@ -91,6 +93,9 @@ static av_cold int decode_init(AVCodecContext *avctx) break; } } + if (avctx->width < FONT_WIDTH || avctx->height < s->font_height) + return AVERROR_INVALIDDATA; + s->frame = av_frame_alloc(); if (!s->frame) @@ -113,8 +118,6 @@ av_unused static void hscroll(AVCodecContext *avctx) } } -#define FONT_WIDTH 8 - /** * Draw character to screen */ diff --git a/libavcodec/bit_depth_template.c b/libavcodec/bit_depth_template.c index 80184892f5a64..d44d47ea456be 100644 --- a/libavcodec/bit_depth_template.c +++ b/libavcodec/bit_depth_template.c @@ -29,6 +29,7 @@ # undef pixel2 # undef pixel4 # undef dctcoef +# undef idctin # undef INIT_CLIP # undef no_rnd_avg_pixel4 # undef rnd_avg_pixel4 @@ -53,6 +54,16 @@ # define pixel4 uint64_t # define dctcoef int32_t +#ifdef IN_IDCT_DEPTH +#if IN_IDCT_DEPTH == 32 +# define idctin int32_t +#else +# define idctin int16_t +#endif +#else +# define idctin int16_t +#endif + # define INIT_CLIP # define no_rnd_avg_pixel4 no_rnd_avg64 # define rnd_avg_pixel4 rnd_avg64 @@ -71,6 +82,7 @@ # define pixel2 uint16_t # define pixel4 uint32_t # define dctcoef int16_t +# define idctin int16_t # define INIT_CLIP # define no_rnd_avg_pixel4 no_rnd_avg32 @@ -87,7 +99,10 @@ # define CLIP(a) av_clip_uint8(a) #endif -#define FUNC3(a, b, c) a ## _ ## b ## c +#define FUNC3(a, b, c) a ## _ ## b ## c #define FUNC2(a, b, c) FUNC3(a, b, c) #define FUNC(a) FUNC2(a, BIT_DEPTH,) #define FUNCC(a) FUNC2(a, BIT_DEPTH, _c) +#define FUNC4(a, b, c) a ## _int ## b ## _ ## c ## bit +#define FUNC5(a, b, c) FUNC4(a, b, c) +#define FUNC6(a) FUNC5(a, IN_IDCT_DEPTH, BIT_DEPTH) diff --git a/libavcodec/bitstream_filter.c b/libavcodec/bitstream_filter.c index 8599b90d4a2a9..ca11ed371e37c 100644 --- a/libavcodec/bitstream_filter.c +++ b/libavcodec/bitstream_filter.c @@ -28,15 +28,15 @@ #if FF_API_OLD_BSF FF_DISABLE_DEPRECATION_WARNINGS -AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f) +const AVBitStreamFilter *av_bitstream_filter_next(const AVBitStreamFilter *f) { const AVBitStreamFilter *filter = NULL; void *opaque = NULL; while (filter != f) - filter = av_bsf_next(&opaque); + filter = av_bsf_iterate(&opaque); - return av_bsf_next(&opaque); + return av_bsf_iterate(&opaque); } void av_register_bitstream_filter(AVBitStreamFilter *bsf) @@ -131,7 +131,7 @@ int av_bitstream_filter_filter(AVBitStreamFilterContext *bsfc, return ret; } - pkt.data = buf; + pkt.data = (uint8_t *)buf; pkt.size = buf_size; ret = av_bsf_send_packet(priv->ctx, &pkt); diff --git a/libavcodec/bitstream_filters.c b/libavcodec/bitstream_filters.c index ce34de640d30b..18b698a85fc4a 100644 --- a/libavcodec/bitstream_filters.c +++ b/libavcodec/bitstream_filters.c @@ -28,26 +28,34 @@ extern const AVBitStreamFilter ff_aac_adtstoasc_bsf; extern const AVBitStreamFilter ff_chomp_bsf; extern const AVBitStreamFilter ff_dump_extradata_bsf; extern const AVBitStreamFilter ff_dca_core_bsf; +extern const AVBitStreamFilter ff_eac3_core_bsf; extern const AVBitStreamFilter ff_extract_extradata_bsf; +extern const AVBitStreamFilter ff_filter_units_bsf; +extern const AVBitStreamFilter ff_h264_metadata_bsf; extern const AVBitStreamFilter ff_h264_mp4toannexb_bsf; +extern const AVBitStreamFilter ff_h264_redundant_pps_bsf; +extern const AVBitStreamFilter ff_hapqa_extract_bsf; +extern const AVBitStreamFilter ff_hevc_metadata_bsf; extern const AVBitStreamFilter ff_hevc_mp4toannexb_bsf; extern const AVBitStreamFilter ff_imx_dump_header_bsf; extern const AVBitStreamFilter ff_mjpeg2jpeg_bsf; extern const AVBitStreamFilter ff_mjpega_dump_header_bsf; extern const AVBitStreamFilter ff_mp3_header_decompress_bsf; +extern const AVBitStreamFilter ff_mpeg2_metadata_bsf; extern const AVBitStreamFilter ff_mpeg4_unpack_bframes_bsf; extern const AVBitStreamFilter ff_mov2textsub_bsf; extern const AVBitStreamFilter ff_noise_bsf; extern const AVBitStreamFilter ff_null_bsf; extern const AVBitStreamFilter ff_remove_extradata_bsf; extern const AVBitStreamFilter ff_text2movsub_bsf; +extern const AVBitStreamFilter ff_trace_headers_bsf; extern const AVBitStreamFilter ff_vp9_raw_reorder_bsf; extern const AVBitStreamFilter ff_vp9_superframe_bsf; extern const AVBitStreamFilter ff_vp9_superframe_split_bsf; #include "libavcodec/bsf_list.c" -const AVBitStreamFilter *av_bsf_next(void **opaque) +const AVBitStreamFilter *av_bsf_iterate(void **opaque) { uintptr_t i = (uintptr_t)*opaque; const AVBitStreamFilter *f = bitstream_filters[i]; @@ -58,12 +66,18 @@ const AVBitStreamFilter *av_bsf_next(void **opaque) return f; } +#if FF_API_NEXT +const AVBitStreamFilter *av_bsf_next(void **opaque) { + return av_bsf_iterate(opaque); +} +#endif + const AVBitStreamFilter *av_bsf_get_by_name(const char *name) { - int i; + const AVBitStreamFilter *f = NULL; + void *i = 0; - for (i = 0; bitstream_filters[i]; i++) { - const AVBitStreamFilter *f = bitstream_filters[i]; + while ((f = av_bsf_iterate(&i))) { if (!strcmp(f->name, name)) return f; } @@ -73,19 +87,20 @@ const AVBitStreamFilter *av_bsf_get_by_name(const char *name) const AVClass *ff_bsf_child_class_next(const AVClass *prev) { - int i; + const AVBitStreamFilter *f = NULL; + void *i = 0; /* find the filter that corresponds to prev */ - for (i = 0; prev && bitstream_filters[i]; i++) { - if (bitstream_filters[i]->priv_class == prev) { - i++; + while (prev && (f = av_bsf_iterate(&i))) { + if (f->priv_class == prev) { break; } } /* find next filter with priv options */ - for (; bitstream_filters[i]; i++) - if (bitstream_filters[i]->priv_class) - return bitstream_filters[i]->priv_class; + while ((f = av_bsf_iterate(&i))) { + if (f->priv_class) + return f->priv_class; + } return NULL; } diff --git a/libavcodec/blockdsp.h b/libavcodec/blockdsp.h index 6e27a02ba52d8..26fc2ea13b6ad 100644 --- a/libavcodec/blockdsp.h +++ b/libavcodec/blockdsp.h @@ -33,8 +33,8 @@ typedef void (*op_fill_func)(uint8_t *block /* align width (8 or 16) */, uint8_t value, ptrdiff_t line_size, int h); typedef struct BlockDSPContext { - void (*clear_block)(int16_t *block /* align 16 */); - void (*clear_blocks)(int16_t *blocks /* align 16 */); + void (*clear_block)(int16_t *block /* align 32 */); + void (*clear_blocks)(int16_t *blocks /* align 32 */); op_fill_func fill_block_tab[2]; } BlockDSPContext; diff --git a/libavcodec/bsf.c b/libavcodec/bsf.c index 38b423101c361..bd611ea16b0e7 100644 --- a/libavcodec/bsf.c +++ b/libavcodec/bsf.c @@ -174,6 +174,8 @@ int av_bsf_init(AVBSFContext *ctx) int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt) { + int ret; + if (!pkt || (!pkt->data && !pkt->side_data_elems)) { ctx->internal->eof = 1; return 0; @@ -188,6 +190,9 @@ int av_bsf_send_packet(AVBSFContext *ctx, AVPacket *pkt) ctx->internal->buffer_pkt->side_data_elems) return AVERROR(EAGAIN); + ret = av_packet_make_refcounted(pkt); + if (ret < 0) + return ret; av_packet_move_ref(ctx->internal->buffer_pkt, pkt); return 0; diff --git a/libavcodec/cabac.c b/libavcodec/cabac.c index dd2b057c6dd83..e51139de3bb72 100644 --- a/libavcodec/cabac.c +++ b/libavcodec/cabac.c @@ -32,7 +32,7 @@ #include "cabac.h" #include "cabac_functions.h" -const uint8_t ff_h264_cabac_tables[512 + 4*2*64 + 4*64 + 63] = { +DECLARE_ASM_ALIGNED(1, const uint8_t, ff_h264_cabac_tables)[512 + 4*2*64 + 4*64 + 63] = { 9,8,7,7,6,6,6,6,5,5,5,5,5,5,5,5, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, diff --git a/libavcodec/cavsdec.c b/libavcodec/cavsdec.c index 06c752735ecef..c7fff67c06c66 100644 --- a/libavcodec/cavsdec.c +++ b/libavcodec/cavsdec.c @@ -1067,6 +1067,11 @@ static int decode_pic(AVSContext *h) if (!h->loop_filter_disable && get_bits1(&h->gb)) { h->alpha_offset = get_se_golomb(&h->gb); h->beta_offset = get_se_golomb(&h->gb); + if ( h->alpha_offset < -64 || h->alpha_offset > 64 + || h-> beta_offset < -64 || h-> beta_offset > 64) { + h->alpha_offset = h->beta_offset = 0; + return AVERROR_INVALIDDATA; + } } else { h->alpha_offset = h->beta_offset = 0; } diff --git a/libavcodec/cbs.c b/libavcodec/cbs.c new file mode 100644 index 0000000000000..897e0bb28e34c --- /dev/null +++ b/libavcodec/cbs.c @@ -0,0 +1,615 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "config.h" + +#include "libavutil/avassert.h" +#include "libavutil/buffer.h" +#include "libavutil/common.h" + +#include "cbs.h" +#include "cbs_internal.h" + + +static const CodedBitstreamType *cbs_type_table[] = { +#if CONFIG_CBS_H264 + &ff_cbs_type_h264, +#endif +#if CONFIG_CBS_H265 + &ff_cbs_type_h265, +#endif +#if CONFIG_CBS_MPEG2 + &ff_cbs_type_mpeg2, +#endif +}; + +const enum AVCodecID ff_cbs_all_codec_ids[] = { +#if CONFIG_CBS_H264 + AV_CODEC_ID_H264, +#endif +#if CONFIG_CBS_H265 + AV_CODEC_ID_H265, +#endif +#if CONFIG_CBS_MPEG2 + AV_CODEC_ID_MPEG2VIDEO, +#endif + AV_CODEC_ID_NONE +}; + +int ff_cbs_init(CodedBitstreamContext **ctx_ptr, + enum AVCodecID codec_id, void *log_ctx) +{ + CodedBitstreamContext *ctx; + const CodedBitstreamType *type; + int i; + + type = NULL; + for (i = 0; i < FF_ARRAY_ELEMS(cbs_type_table); i++) { + if (cbs_type_table[i]->codec_id == codec_id) { + type = cbs_type_table[i]; + break; + } + } + if (!type) + return AVERROR(EINVAL); + + ctx = av_mallocz(sizeof(*ctx)); + if (!ctx) + return AVERROR(ENOMEM); + + ctx->log_ctx = log_ctx; + ctx->codec = type; + + ctx->priv_data = av_mallocz(ctx->codec->priv_data_size); + if (!ctx->priv_data) { + av_freep(&ctx); + return AVERROR(ENOMEM); + } + + ctx->decompose_unit_types = NULL; + + ctx->trace_enable = 0; + ctx->trace_level = AV_LOG_TRACE; + + *ctx_ptr = ctx; + return 0; +} + +void ff_cbs_close(CodedBitstreamContext **ctx_ptr) +{ + CodedBitstreamContext *ctx = *ctx_ptr; + + if (!ctx) + return; + + if (ctx->codec && ctx->codec->close) + ctx->codec->close(ctx); + + av_freep(&ctx->priv_data); + av_freep(ctx_ptr); +} + +static void cbs_unit_uninit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + av_buffer_unref(&unit->content_ref); + unit->content = NULL; + + av_buffer_unref(&unit->data_ref); + unit->data = NULL; + unit->data_size = 0; + unit->data_bit_padding = 0; +} + +void ff_cbs_fragment_uninit(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) +{ + int i; + + for (i = 0; i < frag->nb_units; i++) + cbs_unit_uninit(ctx, &frag->units[i]); + av_freep(&frag->units); + frag->nb_units = 0; + + av_buffer_unref(&frag->data_ref); + frag->data = NULL; + frag->data_size = 0; + frag->data_bit_padding = 0; +} + +static int cbs_read_fragment_content(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) +{ + int err, i, j; + + for (i = 0; i < frag->nb_units; i++) { + if (ctx->decompose_unit_types) { + for (j = 0; j < ctx->nb_decompose_unit_types; j++) { + if (ctx->decompose_unit_types[j] == frag->units[i].type) + break; + } + if (j >= ctx->nb_decompose_unit_types) + continue; + } + + av_buffer_unref(&frag->units[i].content_ref); + frag->units[i].content = NULL; + + err = ctx->codec->read_unit(ctx, &frag->units[i]); + if (err == AVERROR(ENOSYS)) { + av_log(ctx->log_ctx, AV_LOG_VERBOSE, + "Decomposition unimplemented for unit %d " + "(type %"PRIu32").\n", i, frag->units[i].type); + } else if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to read unit %d " + "(type %"PRIu32").\n", i, frag->units[i].type); + return err; + } + } + + return 0; +} + +int ff_cbs_read_extradata(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const AVCodecParameters *par) +{ + int err; + + memset(frag, 0, sizeof(*frag)); + + frag->data = par->extradata; + frag->data_size = par->extradata_size; + + err = ctx->codec->split_fragment(ctx, frag, 1); + if (err < 0) + return err; + + frag->data = NULL; + frag->data_size = 0; + + return cbs_read_fragment_content(ctx, frag); +} + +static int cbs_fill_fragment_data(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const uint8_t *data, size_t size) +{ + av_assert0(!frag->data && !frag->data_ref); + + frag->data_ref = + av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!frag->data_ref) + return AVERROR(ENOMEM); + + frag->data = frag->data_ref->data; + frag->data_size = size; + + memcpy(frag->data, data, size); + memset(frag->data + size, 0, + AV_INPUT_BUFFER_PADDING_SIZE); + + return 0; +} + +int ff_cbs_read_packet(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const AVPacket *pkt) +{ + int err; + + memset(frag, 0, sizeof(*frag)); + + if (pkt->buf) { + frag->data_ref = av_buffer_ref(pkt->buf); + if (!frag->data_ref) + return AVERROR(ENOMEM); + + frag->data = pkt->data; + frag->data_size = pkt->size; + + } else { + err = cbs_fill_fragment_data(ctx, frag, pkt->data, pkt->size); + if (err < 0) + return err; + } + + err = ctx->codec->split_fragment(ctx, frag, 0); + if (err < 0) + return err; + + return cbs_read_fragment_content(ctx, frag); +} + +int ff_cbs_read(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const uint8_t *data, size_t size) +{ + int err; + + memset(frag, 0, sizeof(*frag)); + + err = cbs_fill_fragment_data(ctx, frag, data, size); + if (err < 0) + return err; + + err = ctx->codec->split_fragment(ctx, frag, 0); + if (err < 0) + return err; + + return cbs_read_fragment_content(ctx, frag); +} + + +int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) +{ + int err, i; + + for (i = 0; i < frag->nb_units; i++) { + CodedBitstreamUnit *unit = &frag->units[i]; + + if (!unit->content) + continue; + + av_buffer_unref(&unit->data_ref); + unit->data = NULL; + + err = ctx->codec->write_unit(ctx, unit); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to write unit %d " + "(type %"PRIu32").\n", i, unit->type); + return err; + } + } + + av_buffer_unref(&frag->data_ref); + frag->data = NULL; + + err = ctx->codec->assemble_fragment(ctx, frag); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to assemble fragment.\n"); + return err; + } + + return 0; +} + +int ff_cbs_write_extradata(CodedBitstreamContext *ctx, + AVCodecParameters *par, + CodedBitstreamFragment *frag) +{ + int err; + + err = ff_cbs_write_fragment_data(ctx, frag); + if (err < 0) + return err; + + av_freep(&par->extradata); + + par->extradata = av_malloc(frag->data_size + + AV_INPUT_BUFFER_PADDING_SIZE); + if (!par->extradata) + return AVERROR(ENOMEM); + + memcpy(par->extradata, frag->data, frag->data_size); + memset(par->extradata + frag->data_size, 0, + AV_INPUT_BUFFER_PADDING_SIZE); + par->extradata_size = frag->data_size; + + return 0; +} + +int ff_cbs_write_packet(CodedBitstreamContext *ctx, + AVPacket *pkt, + CodedBitstreamFragment *frag) +{ + AVBufferRef *buf; + int err; + + err = ff_cbs_write_fragment_data(ctx, frag); + if (err < 0) + return err; + + av_assert0(frag->data_ref); + buf = av_buffer_ref(frag->data_ref); + if (!buf) + return AVERROR(ENOMEM); + + av_init_packet(pkt); + pkt->buf = buf; + pkt->data = frag->data; + pkt->size = frag->data_size; + + return 0; +} + + +void ff_cbs_trace_header(CodedBitstreamContext *ctx, + const char *name) +{ + if (!ctx->trace_enable) + return; + + av_log(ctx->log_ctx, ctx->trace_level, "%s\n", name); +} + +void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, int position, + const char *name, const char *bits, + int64_t value) +{ + size_t name_len, bits_len; + int pad; + + if (!ctx->trace_enable) + return; + + av_assert0(value >= INT_MIN && value <= UINT32_MAX); + + name_len = strlen(name); + bits_len = strlen(bits); + + if (name_len + bits_len > 60) + pad = bits_len + 2; + else + pad = 61 - name_len; + + av_log(ctx->log_ctx, ctx->trace_level, "%-10d %s%*s = %"PRId64"\n", + position, name, pad, bits, value); +} + +int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, + int width, const char *name, uint32_t *write_to, + uint32_t range_min, uint32_t range_max) +{ + uint32_t value; + int position; + + av_assert0(width > 0 && width <= 32); + + if (get_bits_left(gbc) < width) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid value at " + "%s: bitstream ended.\n", name); + return AVERROR_INVALIDDATA; + } + + if (ctx->trace_enable) + position = get_bits_count(gbc); + + value = get_bits_long(gbc, width); + + if (ctx->trace_enable) { + char bits[33]; + int i; + for (i = 0; i < width; i++) + bits[i] = value >> (width - i - 1) & 1 ? '1' : '0'; + bits[i] = 0; + + ff_cbs_trace_syntax_element(ctx, position, name, bits, value); + } + + if (value < range_min || value > range_max) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%"PRIu32", but must be in [%"PRIu32",%"PRIu32"].\n", + name, value, range_min, range_max); + return AVERROR_INVALIDDATA; + } + + *write_to = value; + return 0; +} + +int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, + int width, const char *name, uint32_t value, + uint32_t range_min, uint32_t range_max) +{ + av_assert0(width > 0 && width <= 32); + + if (value < range_min || value > range_max) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%"PRIu32", but must be in [%"PRIu32",%"PRIu32"].\n", + name, value, range_min, range_max); + return AVERROR_INVALIDDATA; + } + + if (put_bits_left(pbc) < width) + return AVERROR(ENOSPC); + + if (ctx->trace_enable) { + char bits[33]; + int i; + for (i = 0; i < width; i++) + bits[i] = value >> (width - i - 1) & 1 ? '1' : '0'; + bits[i] = 0; + + ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), name, bits, value); + } + + if (width < 32) + put_bits(pbc, width, value); + else + put_bits32(pbc, value); + + return 0; +} + + +int ff_cbs_alloc_unit_content(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + size_t size, + void (*free)(void *opaque, uint8_t *data)) +{ + av_assert0(!unit->content && !unit->content_ref); + + unit->content = av_mallocz(size); + if (!unit->content) + return AVERROR(ENOMEM); + + unit->content_ref = av_buffer_create(unit->content, size, + free, ctx, 0); + if (!unit->content_ref) { + av_freep(&unit->content); + return AVERROR(ENOMEM); + } + + return 0; +} + +int ff_cbs_alloc_unit_data(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + size_t size) +{ + av_assert0(!unit->data && !unit->data_ref); + + unit->data_ref = av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!unit->data_ref) + return AVERROR(ENOMEM); + + unit->data = unit->data_ref->data; + unit->data_size = size; + + memset(unit->data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + return 0; +} + +static int cbs_insert_unit(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int position) +{ + CodedBitstreamUnit *units; + + units = av_malloc_array(frag->nb_units + 1, sizeof(*units)); + if (!units) + return AVERROR(ENOMEM); + + if (position > 0) + memcpy(units, frag->units, position * sizeof(*units)); + if (position < frag->nb_units) + memcpy(units + position + 1, frag->units + position, + (frag->nb_units - position) * sizeof(*units)); + + memset(units + position, 0, sizeof(*units)); + + av_freep(&frag->units); + frag->units = units; + ++frag->nb_units; + + return 0; +} + +int ff_cbs_insert_unit_content(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int position, + CodedBitstreamUnitType type, + void *content, + AVBufferRef *content_buf) +{ + CodedBitstreamUnit *unit; + AVBufferRef *content_ref; + int err; + + if (position == -1) + position = frag->nb_units; + av_assert0(position >= 0 && position <= frag->nb_units); + + if (content_buf) { + content_ref = av_buffer_ref(content_buf); + if (!content_ref) + return AVERROR(ENOMEM); + } else { + content_ref = NULL; + } + + err = cbs_insert_unit(ctx, frag, position); + if (err < 0) { + av_buffer_unref(&content_ref); + return err; + } + + unit = &frag->units[position]; + unit->type = type; + unit->content = content; + unit->content_ref = content_ref; + + return 0; +} + +int ff_cbs_insert_unit_data(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int position, + CodedBitstreamUnitType type, + uint8_t *data, size_t data_size, + AVBufferRef *data_buf) +{ + CodedBitstreamUnit *unit; + AVBufferRef *data_ref; + int err; + + if (position == -1) + position = frag->nb_units; + av_assert0(position >= 0 && position <= frag->nb_units); + + if (data_buf) + data_ref = av_buffer_ref(data_buf); + else + data_ref = av_buffer_create(data, data_size, NULL, NULL, 0); + if (!data_ref) + return AVERROR(ENOMEM); + + err = cbs_insert_unit(ctx, frag, position); + if (err < 0) { + av_buffer_unref(&data_ref); + return err; + } + + unit = &frag->units[position]; + unit->type = type; + unit->data = data; + unit->data_size = data_size; + unit->data_ref = data_ref; + + return 0; +} + +int ff_cbs_delete_unit(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int position) +{ + if (position < 0 || position >= frag->nb_units) + return AVERROR(EINVAL); + + cbs_unit_uninit(ctx, &frag->units[position]); + + --frag->nb_units; + + if (frag->nb_units == 0) { + av_freep(&frag->units); + + } else { + memmove(frag->units + position, + frag->units + position + 1, + (frag->nb_units - position) * sizeof(*frag->units)); + + // Don't bother reallocating the unit array. + } + + return 0; +} diff --git a/libavcodec/cbs.h b/libavcodec/cbs.h new file mode 100644 index 0000000000000..402eb39e00aef --- /dev/null +++ b/libavcodec/cbs.h @@ -0,0 +1,353 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_CBS_H +#define AVCODEC_CBS_H + +#include +#include + +#include "libavutil/buffer.h" + +#include "avcodec.h" + + +/* + * This defines a framework for converting between a coded bitstream + * and structures defining all individual syntax elements found in + * such a stream. + * + * Conversion in both directions is possible. Given a coded bitstream + * (any meaningful fragment), it can be parsed and decomposed into + * syntax elements stored in a set of codec-specific structures. + * Similarly, given a set of those same codec-specific structures the + * syntax elements can be serialised and combined to create a coded + * bitstream. + */ + +struct CodedBitstreamType; + +/** + * The codec-specific type of a bitstream unit. + * + * H.264 / AVC: nal_unit_type + * H.265 / HEVC: nal_unit_type + * MPEG-2: start code value (without prefix) + */ +typedef uint32_t CodedBitstreamUnitType; + +/** + * Coded bitstream unit structure. + * + * A bitstream unit the smallest element of a bitstream which + * is meaningful on its own. For example, an H.264 NAL unit. + * + * See the codec-specific header for the meaning of this for any + * particular codec. + */ +typedef struct CodedBitstreamUnit { + /** + * Codec-specific type of this unit. + */ + CodedBitstreamUnitType type; + + /** + * Pointer to the directly-parsable bitstream form of this unit. + * + * May be NULL if the unit currently only exists in decomposed form. + */ + uint8_t *data; + /** + * The number of bytes in the bitstream (including any padding bits + * in the final byte). + */ + size_t data_size; + /** + * The number of bits which should be ignored in the final byte. + * + * This supports non-byte-aligned bitstreams. + */ + size_t data_bit_padding; + /** + * If data is reference counted, a reference to the buffer containing + * data. Null if data is not reference counted. + */ + AVBufferRef *data_ref; + + /** + * Pointer to the decomposed form of this unit. + * + * The type of this structure depends on both the codec and the + * type of this unit. May be NULL if the unit only exists in + * bitstream form. + */ + void *content; + /** + * If content is reference counted, a reference to the buffer containing + * content. Null if content is not reference counted. + */ + AVBufferRef *content_ref; +} CodedBitstreamUnit; + +/** + * Coded bitstream fragment structure, combining one or more units. + * + * This is any sequence of units. It need not form some greater whole, + * though in many cases it will. For example, an H.264 access unit, + * which is composed of a sequence of H.264 NAL units. + */ +typedef struct CodedBitstreamFragment { + /** + * Pointer to the bitstream form of this fragment. + * + * May be NULL if the fragment only exists as component units. + */ + uint8_t *data; + /** + * The number of bytes in the bitstream. + * + * The number of bytes in the bitstream (including any padding bits + * in the final byte). + */ + size_t data_size; + /** + * The number of bits which should be ignored in the final byte. + */ + size_t data_bit_padding; + /** + * If data is reference counted, a reference to the buffer containing + * data. Null if data is not reference counted. + */ + AVBufferRef *data_ref; + + /** + * Number of units in this fragment. + * + * This may be zero if the fragment only exists in bitstream form + * and has not been decomposed. + */ + int nb_units; + /** + * Pointer to an array of units of length nb_units. + * + * Must be NULL if nb_units is zero. + */ + CodedBitstreamUnit *units; +} CodedBitstreamFragment; + +/** + * Context structure for coded bitstream operations. + */ +typedef struct CodedBitstreamContext { + /** + * Logging context to be passed to all av_log() calls associated + * with this context. + */ + void *log_ctx; + + /** + * Internal codec-specific hooks. + */ + const struct CodedBitstreamType *codec; + + /** + * Internal codec-specific data. + * + * This contains any information needed when reading/writing + * bitsteams which will not necessarily be present in a fragment. + * For example, for H.264 it contains all currently visible + * parameter sets - they are required to determine the bitstream + * syntax but need not be present in every access unit. + */ + void *priv_data; + + /** + * Array of unit types which should be decomposed when reading. + * + * Types not in this list will be available in bitstream form only. + * If NULL, all supported types will be decomposed. + */ + CodedBitstreamUnitType *decompose_unit_types; + /** + * Length of the decompose_unit_types array. + */ + int nb_decompose_unit_types; + + /** + * Enable trace output during read/write operations. + */ + int trace_enable; + /** + * Log level to use for trace output. + * + * From AV_LOG_*; defaults to AV_LOG_TRACE. + */ + int trace_level; +} CodedBitstreamContext; + + +/** + * Table of all supported codec IDs. + * + * Terminated by AV_CODEC_ID_NONE. + */ +extern const enum AVCodecID ff_cbs_all_codec_ids[]; + + +/** + * Create and initialise a new context for the given codec. + */ +int ff_cbs_init(CodedBitstreamContext **ctx, + enum AVCodecID codec_id, void *log_ctx); + +/** + * Close a context and free all internal state. + */ +void ff_cbs_close(CodedBitstreamContext **ctx); + + +/** + * Read the extradata bitstream found in codec parameters into a + * fragment, then split into units and decompose. + * + * This also updates the internal state, so will need to be called for + * codecs with extradata to read parameter sets necessary for further + * parsing even if the fragment itself is not desired. + */ +int ff_cbs_read_extradata(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const AVCodecParameters *par); + +/** + * Read the data bitstream from a packet into a fragment, then + * split into units and decompose. + * + * This also updates the internal state of the coded bitstream context + * with any persistent data from the fragment which may be required to + * read following fragments (e.g. parameter sets). + */ +int ff_cbs_read_packet(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const AVPacket *pkt); + +/** + * Read a bitstream from a memory region into a fragment, then + * split into units and decompose. + * + * This also updates the internal state of the coded bitstream context + * with any persistent data from the fragment which may be required to + * read following fragments (e.g. parameter sets). + */ +int ff_cbs_read(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const uint8_t *data, size_t size); + + +/** + * Write the content of the fragment to its own internal buffer. + * + * Writes the content of all units and then assembles them into a new + * data buffer. When modifying the content of decomposed units, this + * can be used to regenerate the bitstream form of units or the whole + * fragment so that it can be extracted for other use. + * + * This also updates the internal state of the coded bitstream context + * with any persistent data from the fragment which may be required to + * write following fragments (e.g. parameter sets). + */ +int ff_cbs_write_fragment_data(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag); + +/** + * Write the bitstream of a fragment to the extradata in codec parameters. + * + * This replaces any existing extradata in the structure. + */ +int ff_cbs_write_extradata(CodedBitstreamContext *ctx, + AVCodecParameters *par, + CodedBitstreamFragment *frag); + +/** + * Write the bitstream of a fragment to a packet. + */ +int ff_cbs_write_packet(CodedBitstreamContext *ctx, + AVPacket *pkt, + CodedBitstreamFragment *frag); + + +/** + * Free all allocated memory in a fragment. + */ +void ff_cbs_fragment_uninit(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag); + + +/** + * Allocate a new internal content buffer of the given size in the unit. + * + * The content will be zeroed. + */ +int ff_cbs_alloc_unit_content(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + size_t size, + void (*free)(void *unit, uint8_t *content)); + +/** + * Allocate a new internal data buffer of the given size in the unit. + * + * The data buffer will have input padding. + */ +int ff_cbs_alloc_unit_data(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + size_t size); + +/** + * Insert a new unit into a fragment with the given content. + * + * The content structure continues to be owned by the caller if + * content_buf is not supplied. + */ +int ff_cbs_insert_unit_content(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int position, + CodedBitstreamUnitType type, + void *content, + AVBufferRef *content_buf); + +/** + * Insert a new unit into a fragment with the given data bitstream. + * + * If data_buf is not supplied then data must have been allocated with + * av_malloc() and will become owned by the unit after this call. + */ +int ff_cbs_insert_unit_data(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int position, + CodedBitstreamUnitType type, + uint8_t *data, size_t data_size, + AVBufferRef *data_buf); + +/** + * Delete a unit from a fragment and free all memory it uses. + */ +int ff_cbs_delete_unit(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int position); + + +#endif /* AVCODEC_CBS_H */ diff --git a/libavcodec/cbs_h264.h b/libavcodec/cbs_h264.h new file mode 100644 index 0000000000000..2219d9da8d7a4 --- /dev/null +++ b/libavcodec/cbs_h264.h @@ -0,0 +1,458 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_CBS_H264_H +#define AVCODEC_CBS_H264_H + +#include +#include + +#include "cbs.h" +#include "cbs_h2645.h" +#include "h264.h" + + +enum { + // This limit is arbitrary - it is sufficient for one message of each + // type plus some repeats, and will therefore easily cover all sane + // streams. However, it is possible to make technically-valid streams + // for which it will fail (for example, by including a large number of + // user-data-unregistered messages). + H264_MAX_SEI_PAYLOADS = 64, +}; + + +typedef struct H264RawNALUnitHeader { + uint8_t forbidden_zero_bit; + uint8_t nal_ref_idc; + uint8_t nal_unit_type; + + uint8_t svc_extension_flag; + uint8_t avc_3d_extension_flag; +} H264RawNALUnitHeader; + +typedef struct H264RawScalingList { + int8_t delta_scale[64]; +} H264RawScalingList; + +typedef struct H264RawHRD { + uint8_t cpb_cnt_minus1; + uint8_t bit_rate_scale; + uint8_t cpb_size_scale; + + uint32_t bit_rate_value_minus1[H264_MAX_CPB_CNT]; + uint32_t cpb_size_value_minus1[H264_MAX_CPB_CNT]; + uint8_t cbr_flag[H264_MAX_CPB_CNT]; + + uint8_t initial_cpb_removal_delay_length_minus1; + uint8_t cpb_removal_delay_length_minus1; + uint8_t dpb_output_delay_length_minus1; + uint8_t time_offset_length; +} H264RawHRD; + +typedef struct H264RawVUI { + uint8_t aspect_ratio_info_present_flag; + uint8_t aspect_ratio_idc; + uint16_t sar_width; + uint16_t sar_height; + + uint8_t overscan_info_present_flag; + uint8_t overscan_appropriate_flag; + + uint8_t video_signal_type_present_flag; + uint8_t video_format; + uint8_t video_full_range_flag; + uint8_t colour_description_present_flag; + uint8_t colour_primaries; + uint8_t transfer_characteristics; + uint8_t matrix_coefficients; + + uint8_t chroma_loc_info_present_flag; + uint8_t chroma_sample_loc_type_top_field; + uint8_t chroma_sample_loc_type_bottom_field; + + uint8_t timing_info_present_flag; + uint32_t num_units_in_tick; + uint32_t time_scale; + uint8_t fixed_frame_rate_flag; + + uint8_t nal_hrd_parameters_present_flag; + H264RawHRD nal_hrd_parameters; + uint8_t vcl_hrd_parameters_present_flag; + H264RawHRD vcl_hrd_parameters; + uint8_t low_delay_hrd_flag; + + uint8_t pic_struct_present_flag; + + uint8_t bitstream_restriction_flag; + uint8_t motion_vectors_over_pic_boundaries_flag; + uint8_t max_bytes_per_pic_denom; + uint8_t max_bits_per_mb_denom; + uint8_t log2_max_mv_length_horizontal; + uint8_t log2_max_mv_length_vertical; + uint8_t max_num_reorder_frames; + uint8_t max_dec_frame_buffering; +} H264RawVUI; + +typedef struct H264RawSPS { + H264RawNALUnitHeader nal_unit_header; + + uint8_t profile_idc; + uint8_t constraint_set0_flag; + uint8_t constraint_set1_flag; + uint8_t constraint_set2_flag; + uint8_t constraint_set3_flag; + uint8_t constraint_set4_flag; + uint8_t constraint_set5_flag; + uint8_t reserved_zero_2bits; + uint8_t level_idc; + + uint8_t seq_parameter_set_id; + + uint8_t chroma_format_idc; + uint8_t separate_colour_plane_flag; + uint8_t bit_depth_luma_minus8; + uint8_t bit_depth_chroma_minus8; + uint8_t qpprime_y_zero_transform_bypass_flag; + + uint8_t seq_scaling_matrix_present_flag; + uint8_t seq_scaling_list_present_flag[12]; + H264RawScalingList scaling_list_4x4[6]; + H264RawScalingList scaling_list_8x8[6]; + + uint8_t log2_max_frame_num_minus4; + uint8_t pic_order_cnt_type; + uint8_t log2_max_pic_order_cnt_lsb_minus4; + uint8_t delta_pic_order_always_zero_flag; + int32_t offset_for_non_ref_pic; + int32_t offset_for_top_to_bottom_field; + uint8_t num_ref_frames_in_pic_order_cnt_cycle; + int32_t offset_for_ref_frame[256]; + + uint8_t max_num_ref_frames; + uint8_t gaps_in_frame_num_allowed_flag; + + uint16_t pic_width_in_mbs_minus1; + uint16_t pic_height_in_map_units_minus1; + + uint8_t frame_mbs_only_flag; + uint8_t mb_adaptive_frame_field_flag; + uint8_t direct_8x8_inference_flag; + + uint8_t frame_cropping_flag; + uint16_t frame_crop_left_offset; + uint16_t frame_crop_right_offset; + uint16_t frame_crop_top_offset; + uint16_t frame_crop_bottom_offset; + + uint8_t vui_parameters_present_flag; + H264RawVUI vui; +} H264RawSPS; + +typedef struct H264RawSPSExtension { + H264RawNALUnitHeader nal_unit_header; + + uint8_t seq_parameter_set_id; + + uint8_t aux_format_idc; + uint8_t bit_depth_aux_minus8; + uint8_t alpha_incr_flag; + uint16_t alpha_opaque_value; + uint16_t alpha_transparent_value; + + uint8_t additional_extension_flag; +} H264RawSPSExtension; + +typedef struct H264RawPPS { + H264RawNALUnitHeader nal_unit_header; + + uint8_t pic_parameter_set_id; + uint8_t seq_parameter_set_id; + + uint8_t entropy_coding_mode_flag; + uint8_t bottom_field_pic_order_in_frame_present_flag; + + uint8_t num_slice_groups_minus1; + uint8_t slice_group_map_type; + uint16_t run_length_minus1[H264_MAX_SLICE_GROUPS]; + uint16_t top_left[H264_MAX_SLICE_GROUPS]; + uint16_t bottom_right[H264_MAX_SLICE_GROUPS]; + uint8_t slice_group_change_direction_flag; + uint16_t slice_group_change_rate_minus1; + uint16_t pic_size_in_map_units_minus1; + + uint8_t *slice_group_id; + AVBufferRef *slice_group_id_ref; + + uint8_t num_ref_idx_l0_default_active_minus1; + uint8_t num_ref_idx_l1_default_active_minus1; + + uint8_t weighted_pred_flag; + uint8_t weighted_bipred_idc; + + int8_t pic_init_qp_minus26; + int8_t pic_init_qs_minus26; + int8_t chroma_qp_index_offset; + + uint8_t deblocking_filter_control_present_flag; + uint8_t constrained_intra_pred_flag; + + uint8_t more_rbsp_data; + + uint8_t redundant_pic_cnt_present_flag; + uint8_t transform_8x8_mode_flag; + + uint8_t pic_scaling_matrix_present_flag; + uint8_t pic_scaling_list_present_flag[12]; + H264RawScalingList scaling_list_4x4[6]; + H264RawScalingList scaling_list_8x8[6]; + + int8_t second_chroma_qp_index_offset; +} H264RawPPS; + +typedef struct H264RawAUD { + H264RawNALUnitHeader nal_unit_header; + + uint8_t primary_pic_type; +} H264RawAUD; + +typedef struct H264RawSEIBufferingPeriod { + uint8_t seq_parameter_set_id; + struct { + uint32_t initial_cpb_removal_delay[H264_MAX_CPB_CNT]; + uint32_t initial_cpb_removal_delay_offset[H264_MAX_CPB_CNT]; + } nal, vcl; +} H264RawSEIBufferingPeriod; + +typedef struct H264RawSEIPicTimestamp { + uint8_t ct_type; + uint8_t nuit_field_based_flag; + uint8_t counting_type; + uint8_t full_timestamp_flag; + uint8_t discontinuity_flag; + uint8_t cnt_dropped_flag; + uint8_t n_frames; + uint8_t seconds_flag; + uint8_t seconds_value; + uint8_t minutes_flag; + uint8_t minutes_value; + uint8_t hours_flag; + uint8_t hours_value; + uint32_t time_offset; +} H264RawSEIPicTimestamp; + +typedef struct H264RawSEIPicTiming { + uint32_t cpb_removal_delay; + uint32_t dpb_output_delay; + uint8_t pic_struct; + uint8_t clock_timestamp_flag[3]; + H264RawSEIPicTimestamp timestamp[3]; +} H264RawSEIPicTiming; + +typedef struct H264RawSEIUserDataRegistered { + uint8_t itu_t_t35_country_code; + uint8_t itu_t_t35_country_code_extension_byte; + uint8_t *data; + size_t data_length; + AVBufferRef *data_ref; +} H264RawSEIUserDataRegistered; + +typedef struct H264RawSEIUserDataUnregistered { + uint8_t uuid_iso_iec_11578[16]; + uint8_t *data; + size_t data_length; + AVBufferRef *data_ref; +} H264RawSEIUserDataUnregistered; + +typedef struct H264RawSEIRecoveryPoint { + uint16_t recovery_frame_cnt; + uint8_t exact_match_flag; + uint8_t broken_link_flag; + uint8_t changing_slice_group_idc; +} H264RawSEIRecoveryPoint; + +typedef struct H264RawSEIDisplayOrientation { + uint8_t display_orientation_cancel_flag; + uint8_t hor_flip; + uint8_t ver_flip; + uint16_t anticlockwise_rotation; + uint16_t display_orientation_repetition_period; + uint8_t display_orientation_extension_flag; +} H264RawSEIDisplayOrientation; + +typedef struct H264RawSEIPayload { + uint32_t payload_type; + uint32_t payload_size; + union { + H264RawSEIBufferingPeriod buffering_period; + H264RawSEIPicTiming pic_timing; + // H264RawSEIFiller filler -> no fields. + H264RawSEIUserDataRegistered user_data_registered; + H264RawSEIUserDataUnregistered user_data_unregistered; + H264RawSEIRecoveryPoint recovery_point; + H264RawSEIDisplayOrientation display_orientation; + struct { + uint8_t *data; + size_t data_length; + AVBufferRef *data_ref; + } other; + } payload; +} H264RawSEIPayload; + +typedef struct H264RawSEI { + H264RawNALUnitHeader nal_unit_header; + + H264RawSEIPayload payload[H264_MAX_SEI_PAYLOADS]; + uint8_t payload_count; +} H264RawSEI; + +typedef struct H264RawSliceHeader { + H264RawNALUnitHeader nal_unit_header; + + uint32_t first_mb_in_slice; + uint8_t slice_type; + + uint8_t pic_parameter_set_id; + + uint8_t colour_plane_id; + + uint16_t frame_num; + uint8_t field_pic_flag; + uint8_t bottom_field_flag; + + uint16_t idr_pic_id; + + uint16_t pic_order_cnt_lsb; + int32_t delta_pic_order_cnt_bottom; + int32_t delta_pic_order_cnt[2]; + + uint8_t redundant_pic_cnt; + uint8_t direct_spatial_mv_pred_flag; + + uint8_t num_ref_idx_active_override_flag; + uint8_t num_ref_idx_l0_active_minus1; + uint8_t num_ref_idx_l1_active_minus1; + + uint8_t ref_pic_list_modification_flag_l0; + uint8_t ref_pic_list_modification_flag_l1; + struct { + uint8_t modification_of_pic_nums_idc; + int32_t abs_diff_pic_num_minus1; + uint8_t long_term_pic_num; + } rplm_l0[H264_MAX_RPLM_COUNT], rplm_l1[H264_MAX_RPLM_COUNT]; + + uint8_t luma_log2_weight_denom; + uint8_t chroma_log2_weight_denom; + + uint8_t luma_weight_l0_flag[H264_MAX_REFS]; + int8_t luma_weight_l0[H264_MAX_REFS]; + int8_t luma_offset_l0[H264_MAX_REFS]; + uint8_t chroma_weight_l0_flag[H264_MAX_REFS]; + int8_t chroma_weight_l0[H264_MAX_REFS][2]; + int8_t chroma_offset_l0[H264_MAX_REFS][2]; + + uint8_t luma_weight_l1_flag[H264_MAX_REFS]; + int8_t luma_weight_l1[H264_MAX_REFS]; + int8_t luma_offset_l1[H264_MAX_REFS]; + uint8_t chroma_weight_l1_flag[H264_MAX_REFS]; + int8_t chroma_weight_l1[H264_MAX_REFS][2]; + int8_t chroma_offset_l1[H264_MAX_REFS][2]; + + uint8_t no_output_of_prior_pics_flag; + uint8_t long_term_reference_flag; + + uint8_t adaptive_ref_pic_marking_mode_flag; + struct { + uint8_t memory_management_control_operation; + int32_t difference_of_pic_nums_minus1; + uint8_t long_term_pic_num; + uint8_t long_term_frame_idx; + uint8_t max_long_term_frame_idx_plus1; + } mmco[H264_MAX_MMCO_COUNT]; + + uint8_t cabac_init_idc; + + int8_t slice_qp_delta; + + uint8_t sp_for_switch_flag; + int8_t slice_qs_delta; + + uint8_t disable_deblocking_filter_idc; + int8_t slice_alpha_c0_offset_div2; + int8_t slice_beta_offset_div2; + + uint16_t slice_group_change_cycle; +} H264RawSliceHeader; + +typedef struct H264RawSlice { + H264RawSliceHeader header; + + uint8_t *data; + size_t data_size; + int data_bit_start; + AVBufferRef *data_ref; +} H264RawSlice; + +typedef struct H264RawFiller { + H264RawNALUnitHeader nal_unit_header; + + uint32_t filler_size; +} H264RawFiller; + + +typedef struct CodedBitstreamH264Context { + // Reader/writer context in common with the H.265 implementation. + CodedBitstreamH2645Context common; + + // All currently available parameter sets. These are updated when + // any parameter set NAL unit is read/written with this context. + H264RawSPS *sps[H264_MAX_SPS_COUNT]; + H264RawPPS *pps[H264_MAX_PPS_COUNT]; + + // The currently active parameter sets. These are updated when any + // NAL unit refers to the relevant parameter set. These pointers + // must also be present in the arrays above. + const H264RawSPS *active_sps; + const H264RawPPS *active_pps; + + // The NAL unit type of the most recent normal slice. This is required + // to be able to read/write auxiliary slices, because IdrPicFlag is + // otherwise unknown. + uint8_t last_slice_nal_unit_type; +} CodedBitstreamH264Context; + + +/** + * Add an SEI message to an access unit. + */ +int ff_cbs_h264_add_sei_message(CodedBitstreamContext *ctx, + CodedBitstreamFragment *access_unit, + const H264RawSEIPayload *payload); + +/** + * Delete an SEI message from an access unit. + * + * Deletes from nal_unit, which must be an SEI NAL unit. If this is the + * last message in nal_unit, also deletes it from access_unit. + */ +int ff_cbs_h264_delete_sei_message(CodedBitstreamContext *ctx, + CodedBitstreamFragment *access_unit, + CodedBitstreamUnit *nal_unit, + int position); + +#endif /* AVCODEC_CBS_H264_H */ diff --git a/libavcodec/cbs_h2645.c b/libavcodec/cbs_h2645.c new file mode 100644 index 0000000000000..5585831cf61b1 --- /dev/null +++ b/libavcodec/cbs_h2645.c @@ -0,0 +1,1521 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/avassert.h" + +#include "bytestream.h" +#include "cbs.h" +#include "cbs_internal.h" +#include "cbs_h264.h" +#include "cbs_h265.h" +#include "golomb.h" +#include "h264.h" +#include "h264_sei.h" +#include "h2645_parse.h" +#include "hevc.h" + + +static int cbs_read_ue_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc, + const char *name, uint32_t *write_to, + uint32_t range_min, uint32_t range_max) +{ + uint32_t value; + int position, i, j; + unsigned int k; + char bits[65]; + + position = get_bits_count(gbc); + + for (i = 0; i < 32; i++) { + if (get_bits_left(gbc) < i + 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid ue-golomb code at " + "%s: bitstream ended.\n", name); + return AVERROR_INVALIDDATA; + } + k = get_bits1(gbc); + bits[i] = k ? '1' : '0'; + if (k) + break; + } + if (i >= 32) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid ue-golomb code at " + "%s: more than 31 zeroes.\n", name); + return AVERROR_INVALIDDATA; + } + value = 1; + for (j = 0; j < i; j++) { + k = get_bits1(gbc); + bits[i + j + 1] = k ? '1' : '0'; + value = value << 1 | k; + } + bits[i + j + 1] = 0; + --value; + + if (ctx->trace_enable) + ff_cbs_trace_syntax_element(ctx, position, name, bits, value); + + if (value < range_min || value > range_max) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%"PRIu32", but must be in [%"PRIu32",%"PRIu32"].\n", + name, value, range_min, range_max); + return AVERROR_INVALIDDATA; + } + + *write_to = value; + return 0; +} + +static int cbs_read_se_golomb(CodedBitstreamContext *ctx, GetBitContext *gbc, + const char *name, int32_t *write_to, + int32_t range_min, int32_t range_max) +{ + int32_t value; + int position, i, j; + unsigned int k; + uint32_t v; + char bits[65]; + + position = get_bits_count(gbc); + + for (i = 0; i < 32; i++) { + if (get_bits_left(gbc) < i + 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid se-golomb code at " + "%s: bitstream ended.\n", name); + return AVERROR_INVALIDDATA; + } + k = get_bits1(gbc); + bits[i] = k ? '1' : '0'; + if (k) + break; + } + if (i >= 32) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid se-golomb code at " + "%s: more than 31 zeroes.\n", name); + return AVERROR_INVALIDDATA; + } + v = 1; + for (j = 0; j < i; j++) { + k = get_bits1(gbc); + bits[i + j + 1] = k ? '1' : '0'; + v = v << 1 | k; + } + bits[i + j + 1] = 0; + if (v & 1) + value = -(int32_t)(v / 2); + else + value = v / 2; + + if (ctx->trace_enable) + ff_cbs_trace_syntax_element(ctx, position, name, bits, value); + + if (value < range_min || value > range_max) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%"PRId32", but must be in [%"PRId32",%"PRId32"].\n", + name, value, range_min, range_max); + return AVERROR_INVALIDDATA; + } + + *write_to = value; + return 0; +} + +static int cbs_write_ue_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc, + const char *name, uint32_t value, + uint32_t range_min, uint32_t range_max) +{ + int len; + + if (value < range_min || value > range_max) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%"PRIu32", but must be in [%"PRIu32",%"PRIu32"].\n", + name, value, range_min, range_max); + return AVERROR_INVALIDDATA; + } + av_assert0(value != UINT32_MAX); + + len = av_log2(value + 1); + if (put_bits_left(pbc) < 2 * len + 1) + return AVERROR(ENOSPC); + + if (ctx->trace_enable) { + char bits[65]; + int i; + + for (i = 0; i < len; i++) + bits[i] = '0'; + bits[len] = '1'; + for (i = 0; i < len; i++) + bits[len + i + 1] = (value + 1) >> (len - i - 1) & 1 ? '1' : '0'; + bits[len + len + 1] = 0; + + ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), name, bits, value); + } + + put_bits(pbc, len, 0); + if (len + 1 < 32) + put_bits(pbc, len + 1, value + 1); + else + put_bits32(pbc, value + 1); + + return 0; +} + +static int cbs_write_se_golomb(CodedBitstreamContext *ctx, PutBitContext *pbc, + const char *name, int32_t value, + int32_t range_min, int32_t range_max) +{ + int len; + uint32_t uvalue; + + if (value < range_min || value > range_max) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s out of range: " + "%"PRId32", but must be in [%"PRId32",%"PRId32"].\n", + name, value, range_min, range_max); + return AVERROR_INVALIDDATA; + } + av_assert0(value != INT32_MIN); + + if (value == 0) + uvalue = 0; + else if (value > 0) + uvalue = 2 * (uint32_t)value - 1; + else + uvalue = 2 * (uint32_t)-value; + + len = av_log2(uvalue + 1); + if (put_bits_left(pbc) < 2 * len + 1) + return AVERROR(ENOSPC); + + if (ctx->trace_enable) { + char bits[65]; + int i; + + for (i = 0; i < len; i++) + bits[i] = '0'; + bits[len] = '1'; + for (i = 0; i < len; i++) + bits[len + i + 1] = (uvalue + 1) >> (len - i - 1) & 1 ? '1' : '0'; + bits[len + len + 1] = 0; + + ff_cbs_trace_syntax_element(ctx, put_bits_count(pbc), name, bits, value); + } + + put_bits(pbc, len, 0); + if (len + 1 < 32) + put_bits(pbc, len + 1, uvalue + 1); + else + put_bits32(pbc, uvalue + 1); + + return 0; +} + +#define HEADER(name) do { \ + ff_cbs_trace_header(ctx, name); \ + } while (0) + +#define CHECK(call) do { \ + err = (call); \ + if (err < 0) \ + return err; \ + } while (0) + +#define FUNC_NAME(rw, codec, name) cbs_ ## codec ## _ ## rw ## _ ## name +#define FUNC_H264(rw, name) FUNC_NAME(rw, h264, name) +#define FUNC_H265(rw, name) FUNC_NAME(rw, h265, name) + + +#define READ +#define READWRITE read +#define RWContext GetBitContext + +#define xu(width, name, var, range_min, range_max) do { \ + uint32_t value = range_min; \ + CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) +#define xue(name, var, range_min, range_max) do { \ + uint32_t value = range_min; \ + CHECK(cbs_read_ue_golomb(ctx, rw, #name, \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) +#define xse(name, var, range_min, range_max) do { \ + int32_t value = range_min; \ + CHECK(cbs_read_se_golomb(ctx, rw, #name, \ + &value, range_min, range_max)); \ + var = value; \ + } while (0) + + +#define u(width, name, range_min, range_max) \ + xu(width, name, current->name, range_min, range_max) +#define flag(name) u(1, name, 0, 1) +#define ue(name, range_min, range_max) \ + xue(name, current->name, range_min, range_max) +#define se(name, range_min, range_max) \ + xse(name, current->name, range_min, range_max) + +#define infer(name, value) do { \ + current->name = value; \ + } while (0) + +static int cbs_h2645_read_more_rbsp_data(GetBitContext *gbc) +{ + int bits_left = get_bits_left(gbc); + if (bits_left > 8) + return 1; + if (show_bits(gbc, bits_left) == 1 << (bits_left - 1)) + return 0; + return 1; +} + +#define more_rbsp_data(var) ((var) = cbs_h2645_read_more_rbsp_data(rw)) + +#define byte_alignment(rw) (get_bits_count(rw) % 8) + +#define allocate(name, size) do { \ + name ## _ref = av_buffer_allocz(size); \ + if (!name ## _ref) \ + return AVERROR(ENOMEM); \ + name = name ## _ref->data; \ + } while (0) + +#define FUNC(name) FUNC_H264(READWRITE, name) +#include "cbs_h264_syntax_template.c" +#undef FUNC + +#define FUNC(name) FUNC_H265(READWRITE, name) +#include "cbs_h265_syntax_template.c" +#undef FUNC + +#undef READ +#undef READWRITE +#undef RWContext +#undef xu +#undef xue +#undef xse +#undef u +#undef flag +#undef ue +#undef se +#undef infer +#undef more_rbsp_data +#undef byte_alignment +#undef allocate + + +#define WRITE +#define READWRITE write +#define RWContext PutBitContext + +#define xu(width, name, var, range_min, range_max) do { \ + uint32_t value = var; \ + CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ + value, range_min, range_max)); \ + } while (0) +#define xue(name, var, range_min, range_max) do { \ + uint32_t value = var; \ + CHECK(cbs_write_ue_golomb(ctx, rw, #name, \ + value, range_min, range_max)); \ + } while (0) +#define xse(name, var, range_min, range_max) do { \ + int32_t value = var; \ + CHECK(cbs_write_se_golomb(ctx, rw, #name, \ + value, range_min, range_max)); \ + } while (0) + +#define u(width, name, range_min, range_max) \ + xu(width, name, current->name, range_min, range_max) +#define flag(name) u(1, name, 0, 1) +#define ue(name, range_min, range_max) \ + xue(name, current->name, range_min, range_max) +#define se(name, range_min, range_max) \ + xse(name, current->name, range_min, range_max) + +#define infer(name, value) do { \ + if (current->name != (value)) { \ + av_log(ctx->log_ctx, AV_LOG_WARNING, "Warning: " \ + "%s does not match inferred value: " \ + "%"PRId64", but should be %"PRId64".\n", \ + #name, (int64_t)current->name, (int64_t)(value)); \ + } \ + } while (0) + +#define more_rbsp_data(var) (var) + +#define byte_alignment(rw) (put_bits_count(rw) % 8) + +#define allocate(name, size) do { \ + if (!name) { \ + av_log(ctx->log_ctx, AV_LOG_ERROR, "%s must be set " \ + "for writing.\n", #name); \ + return AVERROR_INVALIDDATA; \ + } \ + } while (0) + +#define FUNC(name) FUNC_H264(READWRITE, name) +#include "cbs_h264_syntax_template.c" +#undef FUNC + +#define FUNC(name) FUNC_H265(READWRITE, name) +#include "cbs_h265_syntax_template.c" +#undef FUNC + +#undef WRITE +#undef READWRITE +#undef RWContext +#undef xu +#undef xue +#undef xse +#undef u +#undef flag +#undef ue +#undef se +#undef infer +#undef more_rbsp_data +#undef byte_alignment +#undef allocate + + +static void cbs_h264_free_pps(void *unit, uint8_t *content) +{ + H264RawPPS *pps = (H264RawPPS*)content; + av_buffer_unref(&pps->slice_group_id_ref); + av_freep(&content); +} + +static void cbs_h264_free_sei_payload(H264RawSEIPayload *payload) +{ + switch (payload->payload_type) { + case H264_SEI_TYPE_BUFFERING_PERIOD: + case H264_SEI_TYPE_PIC_TIMING: + case H264_SEI_TYPE_RECOVERY_POINT: + case H264_SEI_TYPE_DISPLAY_ORIENTATION: + break; + case H264_SEI_TYPE_USER_DATA_REGISTERED: + av_buffer_unref(&payload->payload.user_data_registered.data_ref); + break; + case H264_SEI_TYPE_USER_DATA_UNREGISTERED: + av_buffer_unref(&payload->payload.user_data_unregistered.data_ref); + break; + default: + av_buffer_unref(&payload->payload.other.data_ref); + break; + } +} + +static void cbs_h264_free_sei(void *unit, uint8_t *content) +{ + H264RawSEI *sei = (H264RawSEI*)content; + int i; + for (i = 0; i < sei->payload_count; i++) + cbs_h264_free_sei_payload(&sei->payload[i]); + av_freep(&content); +} + +static void cbs_h264_free_slice(void *unit, uint8_t *content) +{ + H264RawSlice *slice = (H264RawSlice*)content; + av_buffer_unref(&slice->data_ref); + av_freep(&content); +} + +static void cbs_h265_free_vps(void *unit, uint8_t *content) +{ + H265RawVPS *vps = (H265RawVPS*)content; + av_buffer_unref(&vps->extension_data.data_ref); + av_freep(&content); +} + +static void cbs_h265_free_sps(void *unit, uint8_t *content) +{ + H265RawSPS *sps = (H265RawSPS*)content; + av_buffer_unref(&sps->extension_data.data_ref); + av_freep(&content); +} + +static void cbs_h265_free_pps(void *unit, uint8_t *content) +{ + H265RawPPS *pps = (H265RawPPS*)content; + av_buffer_unref(&pps->extension_data.data_ref); + av_freep(&content); +} + +static void cbs_h265_free_slice(void *unit, uint8_t *content) +{ + H265RawSlice *slice = (H265RawSlice*)content; + av_buffer_unref(&slice->data_ref); + av_freep(&content); +} + +static int cbs_h2645_fragment_add_nals(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + const H2645Packet *packet) +{ + int err, i; + + for (i = 0; i < packet->nb_nals; i++) { + const H2645NAL *nal = &packet->nals[i]; + size_t size = nal->size; + uint8_t *data; + + // Remove trailing zeroes. + while (size > 0 && nal->data[size - 1] == 0) + --size; + av_assert0(size > 0); + + data = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!data) + return AVERROR(ENOMEM); + memcpy(data, nal->data, size); + memset(data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + err = ff_cbs_insert_unit_data(ctx, frag, -1, nal->type, + data, size, NULL); + if (err < 0) { + av_freep(&data); + return err; + } + } + + return 0; +} + +static int cbs_h2645_split_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int header) +{ + enum AVCodecID codec_id = ctx->codec->codec_id; + CodedBitstreamH2645Context *priv = ctx->priv_data; + GetByteContext gbc; + int err; + + av_assert0(frag->data && frag->nb_units == 0); + if (frag->data_size == 0) + return 0; + + if (header && frag->data[0] && codec_id == AV_CODEC_ID_H264) { + // AVCC header. + size_t size, start, end; + int i, count, version; + + priv->mp4 = 1; + + bytestream2_init(&gbc, frag->data, frag->data_size); + + if (bytestream2_get_bytes_left(&gbc) < 6) + return AVERROR_INVALIDDATA; + + version = bytestream2_get_byte(&gbc); + if (version != 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid AVCC header: " + "first byte %u.", version); + return AVERROR_INVALIDDATA; + } + + bytestream2_skip(&gbc, 3); + priv->nal_length_size = (bytestream2_get_byte(&gbc) & 3) + 1; + + // SPS array. + count = bytestream2_get_byte(&gbc) & 0x1f; + start = bytestream2_tell(&gbc); + for (i = 0; i < count; i++) { + if (bytestream2_get_bytes_left(&gbc) < 2 * (count - i)) + return AVERROR_INVALIDDATA; + size = bytestream2_get_be16(&gbc); + if (bytestream2_get_bytes_left(&gbc) < size) + return AVERROR_INVALIDDATA; + bytestream2_skip(&gbc, size); + } + end = bytestream2_tell(&gbc); + + err = ff_h2645_packet_split(&priv->read_packet, + frag->data + start, end - start, + ctx->log_ctx, 1, 2, AV_CODEC_ID_H264, 1); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to split AVCC SPS array.\n"); + return err; + } + err = cbs_h2645_fragment_add_nals(ctx, frag, &priv->read_packet); + if (err < 0) + return err; + + // PPS array. + count = bytestream2_get_byte(&gbc); + start = bytestream2_tell(&gbc); + for (i = 0; i < count; i++) { + if (bytestream2_get_bytes_left(&gbc) < 2 * (count - i)) + return AVERROR_INVALIDDATA; + size = bytestream2_get_be16(&gbc); + if (bytestream2_get_bytes_left(&gbc) < size) + return AVERROR_INVALIDDATA; + bytestream2_skip(&gbc, size); + } + end = bytestream2_tell(&gbc); + + err = ff_h2645_packet_split(&priv->read_packet, + frag->data + start, end - start, + ctx->log_ctx, 1, 2, AV_CODEC_ID_H264, 1); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to split AVCC PPS array.\n"); + return err; + } + err = cbs_h2645_fragment_add_nals(ctx, frag, &priv->read_packet); + if (err < 0) + return err; + + if (bytestream2_get_bytes_left(&gbc) > 0) { + av_log(ctx->log_ctx, AV_LOG_WARNING, "%u bytes left at end of AVCC " + "header.\n", bytestream2_get_bytes_left(&gbc)); + } + + } else if (header && frag->data[0] && codec_id == AV_CODEC_ID_HEVC) { + // HVCC header. + size_t size, start, end; + int i, j, nb_arrays, nal_unit_type, nb_nals, version; + + priv->mp4 = 1; + + bytestream2_init(&gbc, frag->data, frag->data_size); + + if (bytestream2_get_bytes_left(&gbc) < 23) + return AVERROR_INVALIDDATA; + + version = bytestream2_get_byte(&gbc); + if (version != 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid HVCC header: " + "first byte %u.", version); + return AVERROR_INVALIDDATA; + } + + bytestream2_skip(&gbc, 20); + priv->nal_length_size = (bytestream2_get_byte(&gbc) & 3) + 1; + + nb_arrays = bytestream2_get_byte(&gbc); + for (i = 0; i < nb_arrays; i++) { + nal_unit_type = bytestream2_get_byte(&gbc) & 0x3f; + nb_nals = bytestream2_get_be16(&gbc); + + start = bytestream2_tell(&gbc); + for (j = 0; j < nb_nals; j++) { + if (bytestream2_get_bytes_left(&gbc) < 2) + return AVERROR_INVALIDDATA; + size = bytestream2_get_be16(&gbc); + if (bytestream2_get_bytes_left(&gbc) < size) + return AVERROR_INVALIDDATA; + bytestream2_skip(&gbc, size); + } + end = bytestream2_tell(&gbc); + + err = ff_h2645_packet_split(&priv->read_packet, + frag->data + start, end - start, + ctx->log_ctx, 1, 2, AV_CODEC_ID_HEVC, 1); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Failed to split " + "HVCC array %d (%d NAL units of type %d).\n", + i, nb_nals, nal_unit_type); + return err; + } + err = cbs_h2645_fragment_add_nals(ctx, frag, &priv->read_packet); + if (err < 0) + return err; + } + + } else { + // Annex B, or later MP4 with already-known parameters. + + err = ff_h2645_packet_split(&priv->read_packet, + frag->data, frag->data_size, + ctx->log_ctx, + priv->mp4, priv->nal_length_size, + codec_id, 1); + if (err < 0) + return err; + + err = cbs_h2645_fragment_add_nals(ctx, frag, &priv->read_packet); + if (err < 0) + return err; + } + + return 0; +} + +#define cbs_h2645_replace_ps(h26n, ps_name, ps_var, id_element) \ +static int cbs_h26 ## h26n ## _replace_ ## ps_var(CodedBitstreamContext *ctx, \ + const H26 ## h26n ## Raw ## ps_name *ps_var) \ +{ \ + CodedBitstreamH26 ## h26n ## Context *priv = ctx->priv_data; \ + unsigned int id = ps_var->id_element; \ + if (id > FF_ARRAY_ELEMS(priv->ps_var)) { \ + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid " #ps_name \ + " id : %d.\n", id); \ + return AVERROR_INVALIDDATA; \ + } \ + if (priv->ps_var[id] == priv->active_ ## ps_var) \ + priv->active_ ## ps_var = NULL ; \ + av_freep(&priv->ps_var[id]); \ + priv->ps_var[id] = av_malloc(sizeof(*ps_var)); \ + if (!priv->ps_var[id]) \ + return AVERROR(ENOMEM); \ + memcpy(priv->ps_var[id], ps_var, sizeof(*ps_var)); \ + return 0; \ +} + +cbs_h2645_replace_ps(4, SPS, sps, seq_parameter_set_id) +cbs_h2645_replace_ps(4, PPS, pps, pic_parameter_set_id) +cbs_h2645_replace_ps(5, VPS, vps, vps_video_parameter_set_id) +cbs_h2645_replace_ps(5, SPS, sps, sps_seq_parameter_set_id) +cbs_h2645_replace_ps(5, PPS, pps, pps_pic_parameter_set_id) + +static int cbs_h264_read_nal_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + GetBitContext gbc; + int err; + + err = init_get_bits(&gbc, unit->data, 8 * unit->data_size); + if (err < 0) + return err; + + switch (unit->type) { + case H264_NAL_SPS: + { + H264RawSPS *sps; + + err = ff_cbs_alloc_unit_content(ctx, unit, sizeof(*sps), NULL); + if (err < 0) + return err; + sps = unit->content; + + err = cbs_h264_read_sps(ctx, &gbc, sps); + if (err < 0) + return err; + + err = cbs_h264_replace_sps(ctx, sps); + if (err < 0) + return err; + } + break; + + case H264_NAL_SPS_EXT: + { + err = ff_cbs_alloc_unit_content(ctx, unit, + sizeof(H264RawSPSExtension), + NULL); + if (err < 0) + return err; + + err = cbs_h264_read_sps_extension(ctx, &gbc, unit->content); + if (err < 0) + return err; + } + break; + + case H264_NAL_PPS: + { + H264RawPPS *pps; + + err = ff_cbs_alloc_unit_content(ctx, unit, sizeof(*pps), + &cbs_h264_free_pps); + if (err < 0) + return err; + pps = unit->content; + + err = cbs_h264_read_pps(ctx, &gbc, pps); + if (err < 0) + return err; + + err = cbs_h264_replace_pps(ctx, pps); + if (err < 0) + return err; + } + break; + + case H264_NAL_SLICE: + case H264_NAL_IDR_SLICE: + case H264_NAL_AUXILIARY_SLICE: + { + H264RawSlice *slice; + int pos, len; + + err = ff_cbs_alloc_unit_content(ctx, unit, sizeof(*slice), + &cbs_h264_free_slice); + if (err < 0) + return err; + slice = unit->content; + + err = cbs_h264_read_slice_header(ctx, &gbc, &slice->header); + if (err < 0) + return err; + + pos = get_bits_count(&gbc); + len = unit->data_size; + if (!unit->data[len - 1]) { + int z; + for (z = 0; z < len && !unit->data[len - z - 1]; z++); + av_log(ctx->log_ctx, AV_LOG_DEBUG, "Deleted %d trailing zeroes " + "from slice data.\n", z); + len -= z; + } + + slice->data_size = len - pos / 8; + slice->data_ref = av_buffer_alloc(slice->data_size + + AV_INPUT_BUFFER_PADDING_SIZE); + if (!slice->data_ref) + return AVERROR(ENOMEM); + slice->data = slice->data_ref->data; + memcpy(slice->data, + unit->data + pos / 8, slice->data_size); + memset(slice->data + slice->data_size, 0, + AV_INPUT_BUFFER_PADDING_SIZE); + slice->data_bit_start = pos % 8; + } + break; + + case H264_NAL_AUD: + { + err = ff_cbs_alloc_unit_content(ctx, unit, + sizeof(H264RawAUD), NULL); + if (err < 0) + return err; + + err = cbs_h264_read_aud(ctx, &gbc, unit->content); + if (err < 0) + return err; + } + break; + + case H264_NAL_SEI: + { + err = ff_cbs_alloc_unit_content(ctx, unit, sizeof(H264RawSEI), + &cbs_h264_free_sei); + if (err < 0) + return err; + + err = cbs_h264_read_sei(ctx, &gbc, unit->content); + if (err < 0) + return err; + } + break; + + case H264_NAL_FILLER_DATA: + { + err = ff_cbs_alloc_unit_content(ctx, unit, + sizeof(H264RawFiller), NULL); + if (err < 0) + return err; + + err = cbs_h264_read_filler(ctx, &gbc, unit->content); + if (err < 0) + return err; + } + break; + + default: + return AVERROR(ENOSYS); + } + + return 0; +} + +static int cbs_h265_read_nal_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + GetBitContext gbc; + int err; + + err = init_get_bits(&gbc, unit->data, 8 * unit->data_size); + if (err < 0) + return err; + + switch (unit->type) { + case HEVC_NAL_VPS: + { + H265RawVPS *vps; + + err = ff_cbs_alloc_unit_content(ctx, unit, sizeof(*vps), + &cbs_h265_free_vps); + if (err < 0) + return err; + vps = unit->content; + + err = cbs_h265_read_vps(ctx, &gbc, vps); + if (err < 0) + return err; + + err = cbs_h265_replace_vps(ctx, vps); + if (err < 0) + return err; + } + break; + case HEVC_NAL_SPS: + { + H265RawSPS *sps; + + err = ff_cbs_alloc_unit_content(ctx, unit, sizeof(*sps), + &cbs_h265_free_sps); + if (err < 0) + return err; + sps = unit->content; + + err = cbs_h265_read_sps(ctx, &gbc, sps); + if (err < 0) + return err; + + err = cbs_h265_replace_sps(ctx, sps); + if (err < 0) + return err; + } + break; + + case HEVC_NAL_PPS: + { + H265RawPPS *pps; + + err = ff_cbs_alloc_unit_content(ctx, unit, sizeof(*pps), + &cbs_h265_free_pps); + if (err < 0) + return err; + pps = unit->content; + + err = cbs_h265_read_pps(ctx, &gbc, pps); + if (err < 0) + return err; + + err = cbs_h265_replace_pps(ctx, pps); + if (err < 0) + return err; + } + break; + + case HEVC_NAL_TRAIL_N: + case HEVC_NAL_TRAIL_R: + case HEVC_NAL_TSA_N: + case HEVC_NAL_TSA_R: + case HEVC_NAL_STSA_N: + case HEVC_NAL_STSA_R: + case HEVC_NAL_RADL_N: + case HEVC_NAL_RADL_R: + case HEVC_NAL_RASL_N: + case HEVC_NAL_RASL_R: + case HEVC_NAL_BLA_W_LP: + case HEVC_NAL_BLA_W_RADL: + case HEVC_NAL_BLA_N_LP: + case HEVC_NAL_IDR_W_RADL: + case HEVC_NAL_IDR_N_LP: + case HEVC_NAL_CRA_NUT: + { + H265RawSlice *slice; + int pos, len; + + err = ff_cbs_alloc_unit_content(ctx, unit, sizeof(*slice), + &cbs_h265_free_slice); + if (err < 0) + return err; + slice = unit->content; + + err = cbs_h265_read_slice_segment_header(ctx, &gbc, &slice->header); + if (err < 0) + return err; + + pos = get_bits_count(&gbc); + len = unit->data_size; + if (!unit->data[len - 1]) { + int z; + for (z = 0; z < len && !unit->data[len - z - 1]; z++); + av_log(ctx->log_ctx, AV_LOG_DEBUG, "Deleted %d trailing zeroes " + "from slice data.\n", z); + len -= z; + } + + slice->data_size = len - pos / 8; + slice->data_ref = av_buffer_alloc(slice->data_size + + AV_INPUT_BUFFER_PADDING_SIZE); + if (!slice->data_ref) + return AVERROR(ENOMEM); + slice->data = slice->data_ref->data; + memcpy(slice->data, + unit->data + pos / 8, slice->data_size); + memset(slice->data + slice->data_size, 0, + AV_INPUT_BUFFER_PADDING_SIZE); + slice->data_bit_start = pos % 8; + } + break; + + case HEVC_NAL_AUD: + { + err = ff_cbs_alloc_unit_content(ctx, unit, + sizeof(H265RawAUD), NULL); + if (err < 0) + return err; + + err = cbs_h265_read_aud(ctx, &gbc, unit->content); + if (err < 0) + return err; + } + break; + + default: + return AVERROR(ENOSYS); + } + + return 0; +} + +static int cbs_h264_write_nal_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) +{ + int err; + + switch (unit->type) { + case H264_NAL_SPS: + { + H264RawSPS *sps = unit->content; + + err = cbs_h264_write_sps(ctx, pbc, sps); + if (err < 0) + return err; + + err = cbs_h264_replace_sps(ctx, sps); + if (err < 0) + return err; + } + break; + + case H264_NAL_SPS_EXT: + { + H264RawSPSExtension *sps_ext = unit->content; + + err = cbs_h264_write_sps_extension(ctx, pbc, sps_ext); + if (err < 0) + return err; + } + break; + + case H264_NAL_PPS: + { + H264RawPPS *pps = unit->content; + + err = cbs_h264_write_pps(ctx, pbc, pps); + if (err < 0) + return err; + + err = cbs_h264_replace_pps(ctx, pps); + if (err < 0) + return err; + } + break; + + case H264_NAL_SLICE: + case H264_NAL_IDR_SLICE: + case H264_NAL_AUXILIARY_SLICE: + { + H264RawSlice *slice = unit->content; + GetBitContext gbc; + int bits_left, end, zeroes; + + err = cbs_h264_write_slice_header(ctx, pbc, &slice->header); + if (err < 0) + return err; + + if (slice->data) { + if (slice->data_size * 8 + 8 > put_bits_left(pbc)) + return AVERROR(ENOSPC); + + init_get_bits(&gbc, slice->data, slice->data_size * 8); + skip_bits_long(&gbc, slice->data_bit_start); + + // Copy in two-byte blocks, but stop before copying the + // rbsp_stop_one_bit in the final byte. + while (get_bits_left(&gbc) > 23) + put_bits(pbc, 16, get_bits(&gbc, 16)); + + bits_left = get_bits_left(&gbc); + end = get_bits(&gbc, bits_left); + + // rbsp_stop_one_bit must be present here. + av_assert0(end); + zeroes = ff_ctz(end); + if (bits_left > zeroes + 1) + put_bits(pbc, bits_left - zeroes - 1, + end >> (zeroes + 1)); + put_bits(pbc, 1, 1); + while (put_bits_count(pbc) % 8 != 0) + put_bits(pbc, 1, 0); + } else { + // No slice data - that was just the header. + // (Bitstream may be unaligned!) + } + } + break; + + case H264_NAL_AUD: + { + err = cbs_h264_write_aud(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + + case H264_NAL_SEI: + { + err = cbs_h264_write_sei(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + + case H264_NAL_FILLER_DATA: + { + err = cbs_h264_write_filler(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + + default: + av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for " + "NAL unit type %"PRIu32".\n", unit->type); + return AVERROR_PATCHWELCOME; + } + + return 0; +} + +static int cbs_h265_write_nal_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) +{ + int err; + + switch (unit->type) { + case HEVC_NAL_VPS: + { + H265RawVPS *vps = unit->content; + + err = cbs_h265_write_vps(ctx, pbc, vps); + if (err < 0) + return err; + + err = cbs_h265_replace_vps(ctx, vps); + if (err < 0) + return err; + } + break; + + case HEVC_NAL_SPS: + { + H265RawSPS *sps = unit->content; + + err = cbs_h265_write_sps(ctx, pbc, sps); + if (err < 0) + return err; + + err = cbs_h265_replace_sps(ctx, sps); + if (err < 0) + return err; + } + break; + + case HEVC_NAL_PPS: + { + H265RawPPS *pps = unit->content; + + err = cbs_h265_write_pps(ctx, pbc, pps); + if (err < 0) + return err; + + err = cbs_h265_replace_pps(ctx, pps); + if (err < 0) + return err; + } + break; + + case HEVC_NAL_TRAIL_N: + case HEVC_NAL_TRAIL_R: + case HEVC_NAL_TSA_N: + case HEVC_NAL_TSA_R: + case HEVC_NAL_STSA_N: + case HEVC_NAL_STSA_R: + case HEVC_NAL_RADL_N: + case HEVC_NAL_RADL_R: + case HEVC_NAL_RASL_N: + case HEVC_NAL_RASL_R: + case HEVC_NAL_BLA_W_LP: + case HEVC_NAL_BLA_W_RADL: + case HEVC_NAL_BLA_N_LP: + case HEVC_NAL_IDR_W_RADL: + case HEVC_NAL_IDR_N_LP: + case HEVC_NAL_CRA_NUT: + { + H265RawSlice *slice = unit->content; + GetBitContext gbc; + int bits_left, end, zeroes; + + err = cbs_h265_write_slice_segment_header(ctx, pbc, &slice->header); + if (err < 0) + return err; + + if (slice->data) { + if (slice->data_size * 8 + 8 > put_bits_left(pbc)) + return AVERROR(ENOSPC); + + init_get_bits(&gbc, slice->data, slice->data_size * 8); + skip_bits_long(&gbc, slice->data_bit_start); + + // Copy in two-byte blocks, but stop before copying the + // rbsp_stop_one_bit in the final byte. + while (get_bits_left(&gbc) > 23) + put_bits(pbc, 16, get_bits(&gbc, 16)); + + bits_left = get_bits_left(&gbc); + end = get_bits(&gbc, bits_left); + + // rbsp_stop_one_bit must be present here. + av_assert0(end); + zeroes = ff_ctz(end); + if (bits_left > zeroes + 1) + put_bits(pbc, bits_left - zeroes - 1, + end >> (zeroes + 1)); + put_bits(pbc, 1, 1); + while (put_bits_count(pbc) % 8 != 0) + put_bits(pbc, 1, 0); + } else { + // No slice data - that was just the header. + } + } + break; + + case HEVC_NAL_AUD: + { + err = cbs_h265_write_aud(ctx, pbc, unit->content); + if (err < 0) + return err; + } + break; + + default: + av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for " + "NAL unit type %"PRIu32".\n", unit->type); + return AVERROR_PATCHWELCOME; + } + + return 0; +} + +static int cbs_h2645_write_nal_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + CodedBitstreamH2645Context *priv = ctx->priv_data; + enum AVCodecID codec_id = ctx->codec->codec_id; + PutBitContext pbc; + int err; + + if (!priv->write_buffer) { + // Initial write buffer size is 1MB. + priv->write_buffer_size = 1024 * 1024; + + reallocate_and_try_again: + err = av_reallocp(&priv->write_buffer, priv->write_buffer_size); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Unable to allocate a " + "sufficiently large write buffer (last attempt " + "%"SIZE_SPECIFIER" bytes).\n", priv->write_buffer_size); + return err; + } + } + + init_put_bits(&pbc, priv->write_buffer, priv->write_buffer_size); + + if (codec_id == AV_CODEC_ID_H264) + err = cbs_h264_write_nal_unit(ctx, unit, &pbc); + else + err = cbs_h265_write_nal_unit(ctx, unit, &pbc); + + if (err == AVERROR(ENOSPC)) { + // Overflow. + priv->write_buffer_size *= 2; + goto reallocate_and_try_again; + } + // Overflow but we didn't notice. + av_assert0(put_bits_count(&pbc) <= 8 * priv->write_buffer_size); + + if (err < 0) { + // Write failed for some other reason. + return err; + } + + if (put_bits_count(&pbc) % 8) + unit->data_bit_padding = 8 - put_bits_count(&pbc) % 8; + else + unit->data_bit_padding = 0; + + unit->data_size = (put_bits_count(&pbc) + 7) / 8; + flush_put_bits(&pbc); + + err = ff_cbs_alloc_unit_data(ctx, unit, unit->data_size); + if (err < 0) + return err; + + memcpy(unit->data, priv->write_buffer, unit->data_size); + + return 0; +} + +static int cbs_h2645_assemble_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) +{ + uint8_t *data; + size_t max_size, dp, sp; + int err, i, zero_run; + + for (i = 0; i < frag->nb_units; i++) { + // Data should already all have been written when we get here. + av_assert0(frag->units[i].data); + } + + max_size = 0; + for (i = 0; i < frag->nb_units; i++) { + // Start code + content with worst-case emulation prevention. + max_size += 3 + frag->units[i].data_size * 3 / 2; + } + + data = av_malloc(max_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!data) + return AVERROR(ENOMEM); + + dp = 0; + for (i = 0; i < frag->nb_units; i++) { + CodedBitstreamUnit *unit = &frag->units[i]; + + if (unit->data_bit_padding > 0) { + if (i < frag->nb_units - 1) + av_log(ctx->log_ctx, AV_LOG_WARNING, "Probably invalid " + "unaligned padding on non-final NAL unit.\n"); + else + frag->data_bit_padding = unit->data_bit_padding; + } + + if ((ctx->codec->codec_id == AV_CODEC_ID_H264 && + (unit->type == H264_NAL_SPS || + unit->type == H264_NAL_PPS)) || + (ctx->codec->codec_id == AV_CODEC_ID_HEVC && + (unit->type == HEVC_NAL_VPS || + unit->type == HEVC_NAL_SPS || + unit->type == HEVC_NAL_PPS)) || + i == 0 /* (Assume this is the start of an access unit.) */) { + // zero_byte + data[dp++] = 0; + } + // start_code_prefix_one_3bytes + data[dp++] = 0; + data[dp++] = 0; + data[dp++] = 1; + + zero_run = 0; + for (sp = 0; sp < unit->data_size; sp++) { + if (zero_run < 2) { + if (unit->data[sp] == 0) + ++zero_run; + else + zero_run = 0; + } else { + if ((unit->data[sp] & ~3) == 0) { + // emulation_prevention_three_byte + data[dp++] = 3; + } + zero_run = unit->data[sp] == 0; + } + data[dp++] = unit->data[sp]; + } + } + + av_assert0(dp <= max_size); + err = av_reallocp(&data, dp + AV_INPUT_BUFFER_PADDING_SIZE); + if (err) + return err; + memset(data + dp, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + frag->data_ref = av_buffer_create(data, dp + AV_INPUT_BUFFER_PADDING_SIZE, + NULL, NULL, 0); + if (!frag->data_ref) { + av_freep(&data); + return AVERROR(ENOMEM); + } + + frag->data = data; + frag->data_size = dp; + + return 0; +} + +static void cbs_h264_close(CodedBitstreamContext *ctx) +{ + CodedBitstreamH264Context *h264 = ctx->priv_data; + int i; + + ff_h2645_packet_uninit(&h264->common.read_packet); + + av_freep(&h264->common.write_buffer); + + for (i = 0; i < FF_ARRAY_ELEMS(h264->sps); i++) + av_freep(&h264->sps[i]); + for (i = 0; i < FF_ARRAY_ELEMS(h264->pps); i++) + av_freep(&h264->pps[i]); +} + +static void cbs_h265_close(CodedBitstreamContext *ctx) +{ + CodedBitstreamH265Context *h265 = ctx->priv_data; + int i; + + ff_h2645_packet_uninit(&h265->common.read_packet); + + av_freep(&h265->common.write_buffer); + + for (i = 0; i < FF_ARRAY_ELEMS(h265->vps); i++) + av_freep(&h265->vps[i]); + for (i = 0; i < FF_ARRAY_ELEMS(h265->sps); i++) + av_freep(&h265->sps[i]); + for (i = 0; i < FF_ARRAY_ELEMS(h265->pps); i++) + av_freep(&h265->pps[i]); +} + +const CodedBitstreamType ff_cbs_type_h264 = { + .codec_id = AV_CODEC_ID_H264, + + .priv_data_size = sizeof(CodedBitstreamH264Context), + + .split_fragment = &cbs_h2645_split_fragment, + .read_unit = &cbs_h264_read_nal_unit, + .write_unit = &cbs_h2645_write_nal_unit, + .assemble_fragment = &cbs_h2645_assemble_fragment, + + .close = &cbs_h264_close, +}; + +const CodedBitstreamType ff_cbs_type_h265 = { + .codec_id = AV_CODEC_ID_HEVC, + + .priv_data_size = sizeof(CodedBitstreamH265Context), + + .split_fragment = &cbs_h2645_split_fragment, + .read_unit = &cbs_h265_read_nal_unit, + .write_unit = &cbs_h2645_write_nal_unit, + .assemble_fragment = &cbs_h2645_assemble_fragment, + + .close = &cbs_h265_close, +}; + +int ff_cbs_h264_add_sei_message(CodedBitstreamContext *ctx, + CodedBitstreamFragment *au, + const H264RawSEIPayload *payload) +{ + H264RawSEI *sei; + CodedBitstreamUnit *nal = NULL; + int err, i; + + // Find an existing SEI NAL unit to add to. + for (i = 0; i < au->nb_units; i++) { + if (au->units[i].type == H264_NAL_SEI) { + nal = &au->units[i]; + break; + } + } + if (nal) { + sei = nal->content; + + } else { + // Need to make a new SEI NAL unit. Insert it before the first + // slice data NAL unit; if no slice data, add at the end. + AVBufferRef *sei_ref; + + sei = av_mallocz(sizeof(*sei)); + if (!sei) + return AVERROR(ENOMEM); + + sei->nal_unit_header.nal_unit_type = H264_NAL_SEI; + sei->nal_unit_header.nal_ref_idc = 0; + + sei_ref = av_buffer_create((uint8_t*)sei, sizeof(*sei), + &cbs_h264_free_sei, ctx, 0); + if (!sei_ref) { + av_freep(&sei); + return AVERROR(ENOMEM); + } + + for (i = 0; i < au->nb_units; i++) { + if (au->units[i].type == H264_NAL_SLICE || + au->units[i].type == H264_NAL_IDR_SLICE) + break; + } + + err = ff_cbs_insert_unit_content(ctx, au, i, H264_NAL_SEI, + sei, sei_ref); + av_buffer_unref(&sei_ref); + if (err < 0) + return err; + } + + if (sei->payload_count >= H264_MAX_SEI_PAYLOADS) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Too many payloads in " + "SEI NAL unit.\n"); + return AVERROR(EINVAL); + } + + memcpy(&sei->payload[sei->payload_count], payload, sizeof(*payload)); + ++sei->payload_count; + + return 0; +} + +int ff_cbs_h264_delete_sei_message(CodedBitstreamContext *ctx, + CodedBitstreamFragment *au, + CodedBitstreamUnit *nal, + int position) +{ + H264RawSEI *sei = nal->content; + + av_assert0(nal->type == H264_NAL_SEI); + av_assert0(position >= 0 && position < sei->payload_count); + + if (position == 0 && sei->payload_count == 1) { + // Deleting NAL unit entirely. + int i; + + for (i = 0; i < au->nb_units; i++) { + if (&au->units[i] == nal) + break; + } + av_assert0(i < au->nb_units && "NAL unit not in access unit."); + + return ff_cbs_delete_unit(ctx, au, i); + } else { + cbs_h264_free_sei_payload(&sei->payload[position]); + + --sei->payload_count; + memmove(sei->payload + position, + sei->payload + position + 1, + (sei->payload_count - position) * sizeof(*sei->payload)); + + return 0; + } +} diff --git a/libavcodec/cbs_h2645.h b/libavcodec/cbs_h2645.h new file mode 100644 index 0000000000000..f4cf65bdde500 --- /dev/null +++ b/libavcodec/cbs_h2645.h @@ -0,0 +1,43 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_CBS_H2645_H +#define AVCODEC_CBS_H2645_H + +#include +#include + +#include "h2645_parse.h" + + +typedef struct CodedBitstreamH2645Context { + // If set, the stream being read is in MP4 (AVCC/HVCC) format. If not + // set, the stream is assumed to be in annex B format. + int mp4; + // Size in bytes of the NAL length field for MP4 format. + int nal_length_size; + // Packet reader. + H2645Packet read_packet; + + // Write buffer + uint8_t *write_buffer; + size_t write_buffer_size; +} CodedBitstreamH2645Context; + + +#endif /* AVCODEC_CBS_H2645_H */ diff --git a/libavcodec/cbs_h264_syntax_template.c b/libavcodec/cbs_h264_syntax_template.c new file mode 100644 index 0000000000000..b5cd0b2310b48 --- /dev/null +++ b/libavcodec/cbs_h264_syntax_template.c @@ -0,0 +1,1278 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +static int FUNC(rbsp_trailing_bits)(CodedBitstreamContext *ctx, RWContext *rw) +{ + int err; + av_unused int one = 1, zero = 0; + xu(1, rbsp_stop_one_bit, one, 1, 1); + while (byte_alignment(rw) != 0) + xu(1, rbsp_alignment_zero_bit, zero, 0, 0); + + return 0; +} + +static int FUNC(nal_unit_header)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawNALUnitHeader *current, + uint32_t valid_type_mask) +{ + int err; + + u(1, forbidden_zero_bit, 0, 0); + u(2, nal_ref_idc, 0, 3); + u(5, nal_unit_type, 0, 31); + + if (!(1 << current->nal_unit_type & valid_type_mask)) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid NAL unit type %d.\n", + current->nal_unit_type); + return AVERROR_INVALIDDATA; + } + + if (current->nal_unit_type == 14 || + current->nal_unit_type == 20 || + current->nal_unit_type == 21) { + if (current->nal_unit_type != 21) + flag(svc_extension_flag); + else + flag(avc_3d_extension_flag); + + if (current->svc_extension_flag) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "SVC not supported.\n"); + return AVERROR_PATCHWELCOME; + + } else if (current->avc_3d_extension_flag) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "3DAVC not supported.\n"); + return AVERROR_PATCHWELCOME; + + } else { + av_log(ctx->log_ctx, AV_LOG_ERROR, "MVC not supported.\n"); + return AVERROR_PATCHWELCOME; + } + } + + return 0; +} + +static int FUNC(scaling_list)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawScalingList *current, + int size_of_scaling_list) +{ + int err, i, scale; + + scale = 8; + for (i = 0; i < size_of_scaling_list; i++) { + xse(delta_scale, current->delta_scale[i], -128, +127); + scale = (scale + current->delta_scale[i] + 256) % 256; + if (scale == 0) + break; + } + + return 0; +} + +static int FUNC(hrd_parameters)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawHRD *current) +{ + int err, i; + + ue(cpb_cnt_minus1, 0, 31); + u(4, bit_rate_scale, 0, 15); + u(4, cpb_size_scale, 0, 15); + + for (i = 0; i <= current->cpb_cnt_minus1; i++) { + ue(bit_rate_value_minus1[i], 0, UINT32_MAX - 1); + ue(cpb_size_value_minus1[i], 0, UINT32_MAX - 1); + flag(cbr_flag[i]); + } + + u(5, initial_cpb_removal_delay_length_minus1, 0, 31); + u(5, cpb_removal_delay_length_minus1, 0, 31); + u(5, dpb_output_delay_length_minus1, 0, 31); + u(5, time_offset_length, 0, 31); + + return 0; +} + +static int FUNC(vui_parameters)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawVUI *current, H264RawSPS *sps) +{ + int err; + + flag(aspect_ratio_info_present_flag); + if (current->aspect_ratio_info_present_flag) { + u(8, aspect_ratio_idc, 0, 255); + if (current->aspect_ratio_idc == 255) { + u(16, sar_width, 0, 65535); + u(16, sar_height, 0, 65535); + } + } else { + infer(aspect_ratio_idc, 0); + } + + flag(overscan_info_present_flag); + if (current->overscan_info_present_flag) + flag(overscan_appropriate_flag); + + flag(video_signal_type_present_flag); + if (current->video_signal_type_present_flag) { + u(3, video_format, 0, 7); + flag(video_full_range_flag); + flag(colour_description_present_flag); + if (current->colour_description_present_flag) { + u(8, colour_primaries, 0, 255); + u(8, transfer_characteristics, 0, 255); + u(8, matrix_coefficients, 0, 255); + } + } else { + infer(video_format, 5); + infer(video_full_range_flag, 0); + infer(colour_primaries, 2); + infer(transfer_characteristics, 2); + infer(matrix_coefficients, 2); + } + + flag(chroma_loc_info_present_flag); + if (current->chroma_loc_info_present_flag) { + ue(chroma_sample_loc_type_top_field, 0, 5); + ue(chroma_sample_loc_type_bottom_field, 0, 5); + } else { + infer(chroma_sample_loc_type_top_field, 0); + infer(chroma_sample_loc_type_bottom_field, 0); + } + + flag(timing_info_present_flag); + if (current->timing_info_present_flag) { + u(32, num_units_in_tick, 1, UINT32_MAX); + u(32, time_scale, 1, UINT32_MAX); + flag(fixed_frame_rate_flag); + } else { + infer(fixed_frame_rate_flag, 0); + } + + flag(nal_hrd_parameters_present_flag); + if (current->nal_hrd_parameters_present_flag) + CHECK(FUNC(hrd_parameters)(ctx, rw, ¤t->nal_hrd_parameters)); + + flag(vcl_hrd_parameters_present_flag); + if (current->vcl_hrd_parameters_present_flag) + CHECK(FUNC(hrd_parameters)(ctx, rw, ¤t->vcl_hrd_parameters)); + + if (current->nal_hrd_parameters_present_flag || + current->vcl_hrd_parameters_present_flag) + flag(low_delay_hrd_flag); + else + infer(low_delay_hrd_flag, 1 - current->fixed_frame_rate_flag); + + flag(pic_struct_present_flag); + + flag(bitstream_restriction_flag); + if (current->bitstream_restriction_flag) { + flag(motion_vectors_over_pic_boundaries_flag); + ue(max_bytes_per_pic_denom, 0, 16); + ue(max_bits_per_mb_denom, 0, 16); + ue(log2_max_mv_length_horizontal, 0, 16); + ue(log2_max_mv_length_vertical, 0, 16); + ue(max_num_reorder_frames, 0, H264_MAX_DPB_FRAMES); + ue(max_dec_frame_buffering, 0, H264_MAX_DPB_FRAMES); + } else { + infer(motion_vectors_over_pic_boundaries_flag, 1); + infer(max_bytes_per_pic_denom, 2); + infer(max_bits_per_mb_denom, 1); + infer(log2_max_mv_length_horizontal, 16); + infer(log2_max_mv_length_vertical, 16); + + if ((sps->profile_idc == 44 || sps->profile_idc == 86 || + sps->profile_idc == 110 || sps->profile_idc == 110 || + sps->profile_idc == 122 || sps->profile_idc == 244) && + sps->constraint_set3_flag) { + infer(max_num_reorder_frames, 0); + infer(max_dec_frame_buffering, 0); + } else { + infer(max_num_reorder_frames, H264_MAX_DPB_FRAMES); + infer(max_dec_frame_buffering, H264_MAX_DPB_FRAMES); + } + } + + return 0; +} + +static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSPS *current) +{ + int err, i; + + HEADER("Sequence Parameter Set"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + 1 << H264_NAL_SPS)); + + u(8, profile_idc, 0, 255); + + flag(constraint_set0_flag); + flag(constraint_set1_flag); + flag(constraint_set2_flag); + flag(constraint_set3_flag); + flag(constraint_set4_flag); + flag(constraint_set5_flag); + + u(2, reserved_zero_2bits, 0, 0); + + u(8, level_idc, 0, 255); + + ue(seq_parameter_set_id, 0, 31); + + if (current->profile_idc == 100 || current->profile_idc == 110 || + current->profile_idc == 122 || current->profile_idc == 244 || + current->profile_idc == 44 || current->profile_idc == 83 || + current->profile_idc == 86 || current->profile_idc == 118 || + current->profile_idc == 128 || current->profile_idc == 138) { + ue(chroma_format_idc, 0, 3); + + if (current->chroma_format_idc == 3) + flag(separate_colour_plane_flag); + else + infer(separate_colour_plane_flag, 0); + + ue(bit_depth_luma_minus8, 0, 6); + ue(bit_depth_chroma_minus8, 0, 6); + + flag(qpprime_y_zero_transform_bypass_flag); + + flag(seq_scaling_matrix_present_flag); + if (current->seq_scaling_matrix_present_flag) { + for (i = 0; i < ((current->chroma_format_idc != 3) ? 8 : 12); i++) { + flag(seq_scaling_list_present_flag[i]); + if (current->seq_scaling_list_present_flag[i]) { + if (i < 6) + CHECK(FUNC(scaling_list)(ctx, rw, + ¤t->scaling_list_4x4[i], + 16)); + else + CHECK(FUNC(scaling_list)(ctx, rw, + ¤t->scaling_list_8x8[i - 6], + 64)); + } + } + } + } else { + infer(chroma_format_idc, current->profile_idc == 183 ? 0 : 1); + + infer(separate_colour_plane_flag, 0); + infer(bit_depth_luma_minus8, 0); + infer(bit_depth_chroma_minus8, 0); + } + + ue(log2_max_frame_num_minus4, 0, 12); + ue(pic_order_cnt_type, 0, 2); + + if (current->pic_order_cnt_type == 0) { + ue(log2_max_pic_order_cnt_lsb_minus4, 0, 12); + } else if (current->pic_order_cnt_type == 1) { + flag(delta_pic_order_always_zero_flag); + se(offset_for_non_ref_pic, INT32_MIN + 1, INT32_MAX); + se(offset_for_top_to_bottom_field, INT32_MIN + 1, INT32_MAX); + ue(num_ref_frames_in_pic_order_cnt_cycle, 0, 255); + + for (i = 0; i < current->num_ref_frames_in_pic_order_cnt_cycle; i++) + se(offset_for_ref_frame[i], INT32_MIN + 1, INT32_MAX); + } + + ue(max_num_ref_frames, 0, H264_MAX_DPB_FRAMES); + flag(gaps_in_frame_num_allowed_flag); + + ue(pic_width_in_mbs_minus1, 0, H264_MAX_MB_WIDTH); + ue(pic_height_in_map_units_minus1, 0, H264_MAX_MB_HEIGHT); + + flag(frame_mbs_only_flag); + if (!current->frame_mbs_only_flag) + flag(mb_adaptive_frame_field_flag); + + flag(direct_8x8_inference_flag); + + flag(frame_cropping_flag); + if (current->frame_cropping_flag) { + ue(frame_crop_left_offset, 0, H264_MAX_WIDTH); + ue(frame_crop_right_offset, 0, H264_MAX_WIDTH); + ue(frame_crop_top_offset, 0, H264_MAX_HEIGHT); + ue(frame_crop_bottom_offset, 0, H264_MAX_HEIGHT); + } + + flag(vui_parameters_present_flag); + if (current->vui_parameters_present_flag) + CHECK(FUNC(vui_parameters)(ctx, rw, ¤t->vui, current)); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(sps_extension)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSPSExtension *current) +{ + int err; + + HEADER("Sequence Parameter Set Extension"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + 1 << H264_NAL_SPS_EXT)); + + ue(seq_parameter_set_id, 0, 31); + + ue(aux_format_idc, 0, 3); + + if (current->aux_format_idc != 0) { + int bits; + + ue(bit_depth_aux_minus8, 0, 4); + flag(alpha_incr_flag); + + bits = current->bit_depth_aux_minus8 + 9; + u(bits, alpha_opaque_value, 0, MAX_UINT_BITS(bits)); + u(bits, alpha_transparent_value, 0, MAX_UINT_BITS(bits)); + } + + flag(additional_extension_flag); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(pps)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawPPS *current) +{ + CodedBitstreamH264Context *h264 = ctx->priv_data; + const H264RawSPS *sps; + int err, i; + + HEADER("Picture Parameter Set"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + 1 << H264_NAL_PPS)); + + ue(pic_parameter_set_id, 0, 255); + ue(seq_parameter_set_id, 0, 31); + + sps = h264->sps[current->seq_parameter_set_id]; + if (!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "SPS id %d not available.\n", + current->seq_parameter_set_id); + return AVERROR_INVALIDDATA; + } + + flag(entropy_coding_mode_flag); + flag(bottom_field_pic_order_in_frame_present_flag); + + ue(num_slice_groups_minus1, 0, 7); + if (current->num_slice_groups_minus1 > 0) { + unsigned int pic_size; + int iGroup; + + pic_size = (sps->pic_width_in_mbs_minus1 + 1) * + (sps->pic_height_in_map_units_minus1 + 1); + + ue(slice_group_map_type, 0, 6); + + if (current->slice_group_map_type == 0) { + for (iGroup = 0; iGroup <= current->num_slice_groups_minus1; iGroup++) + ue(run_length_minus1[iGroup], 0, pic_size - 1); + + } else if (current->slice_group_map_type == 2) { + for (iGroup = 0; iGroup < current->num_slice_groups_minus1; iGroup++) { + ue(top_left[iGroup], 0, pic_size - 1); + ue(bottom_right[iGroup], current->top_left[iGroup], pic_size - 1); + } + } else if (current->slice_group_map_type == 3 || + current->slice_group_map_type == 4 || + current->slice_group_map_type == 5) { + flag(slice_group_change_direction_flag); + ue(slice_group_change_rate_minus1, 0, pic_size - 1); + } else if (current->slice_group_map_type == 6) { + ue(pic_size_in_map_units_minus1, pic_size - 1, pic_size - 1); + + allocate(current->slice_group_id, + current->pic_size_in_map_units_minus1 + 1); + for (i = 0; i <= current->pic_size_in_map_units_minus1; i++) + u(av_log2(2 * current->num_slice_groups_minus1 + 1), + slice_group_id[i], 0, current->num_slice_groups_minus1); + } + } + + ue(num_ref_idx_l0_default_active_minus1, 0, 31); + ue(num_ref_idx_l1_default_active_minus1, 0, 31); + + flag(weighted_pred_flag); + u(2, weighted_bipred_idc, 0, 2); + + se(pic_init_qp_minus26, -26 - 6 * sps->bit_depth_luma_minus8, +25); + se(pic_init_qs_minus26, -26, +25); + se(chroma_qp_index_offset, -12, +12); + + flag(deblocking_filter_control_present_flag); + flag(constrained_intra_pred_flag); + flag(redundant_pic_cnt_present_flag); + + if (more_rbsp_data(current->more_rbsp_data)) + { + flag(transform_8x8_mode_flag); + + flag(pic_scaling_matrix_present_flag); + if (current->pic_scaling_matrix_present_flag) { + for (i = 0; i < 6 + (((sps->chroma_format_idc != 3) ? 2 : 6) * + current->transform_8x8_mode_flag); i++) { + flag(pic_scaling_list_present_flag[i]); + if (current->pic_scaling_list_present_flag[i]) { + if (i < 6) + CHECK(FUNC(scaling_list)(ctx, rw, + ¤t->scaling_list_4x4[i], + 16)); + else + CHECK(FUNC(scaling_list)(ctx, rw, + ¤t->scaling_list_8x8[i - 6], + 64)); + } + } + } + + se(second_chroma_qp_index_offset, -12, +12); + } else { + infer(transform_8x8_mode_flag, 0); + infer(pic_scaling_matrix_present_flag, 0); + infer(second_chroma_qp_index_offset, current->chroma_qp_index_offset); + } + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(sei_buffering_period)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIBufferingPeriod *current) +{ + CodedBitstreamH264Context *h264 = ctx->priv_data; + const H264RawSPS *sps; + int err, i, length; + + ue(seq_parameter_set_id, 0, 31); + + sps = h264->sps[current->seq_parameter_set_id]; + if (!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "SPS id %d not available.\n", + current->seq_parameter_set_id); + return AVERROR_INVALIDDATA; + } + h264->active_sps = sps; + + if (sps->vui.nal_hrd_parameters_present_flag) { + for (i = 0; i <= sps->vui.nal_hrd_parameters.cpb_cnt_minus1; i++) { + length = sps->vui.nal_hrd_parameters.initial_cpb_removal_delay_length_minus1 + 1; + xu(length, initial_cpb_removal_delay[SchedSelIdx], + current->nal.initial_cpb_removal_delay[i], + 1, MAX_UINT_BITS(length)); + xu(length, initial_cpb_removal_delay_offset[SchedSelIdx], + current->nal.initial_cpb_removal_delay_offset[i], + 0, MAX_UINT_BITS(length)); + } + } + + if (sps->vui.vcl_hrd_parameters_present_flag) { + for (i = 0; i <= sps->vui.vcl_hrd_parameters.cpb_cnt_minus1; i++) { + length = sps->vui.vcl_hrd_parameters.initial_cpb_removal_delay_length_minus1 + 1; + xu(length, initial_cpb_removal_delay[SchedSelIdx], + current->vcl.initial_cpb_removal_delay[i], + 1, MAX_UINT_BITS(length)); + xu(length, initial_cpb_removal_delay_offset[SchedSelIdx], + current->vcl.initial_cpb_removal_delay_offset[i], + 0, MAX_UINT_BITS(length)); + } + } + + return 0; +} + +static int FUNC(sei_pic_timestamp)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIPicTimestamp *current) +{ + CodedBitstreamH264Context *h264 = ctx->priv_data; + const H264RawSPS *sps; + uint8_t time_offset_length; + int err; + + u(2, ct_type, 0, 2); + flag(nuit_field_based_flag); + u(5, counting_type, 0, 6); + flag(full_timestamp_flag); + flag(discontinuity_flag); + flag(cnt_dropped_flag); + u(8, n_frames, 0, 255); + if (current->full_timestamp_flag) { + u(6, seconds_value, 0, 59); + u(6, minutes_value, 0, 59); + u(5, hours_value, 0, 23); + } else { + flag(seconds_flag); + if (current->seconds_flag) { + u(6, seconds_value, 0, 59); + flag(minutes_flag); + if (current->minutes_flag) { + u(6, minutes_value, 0, 59); + flag(hours_flag); + if (current->hours_flag) + u(5, hours_value, 0, 23); + } + } + } + + sps = h264->active_sps; + if (sps->vui.nal_hrd_parameters_present_flag) + time_offset_length = sps->vui.nal_hrd_parameters.time_offset_length; + else if (sps->vui.vcl_hrd_parameters_present_flag) + time_offset_length = sps->vui.vcl_hrd_parameters.time_offset_length; + else + time_offset_length = 24; + + if (time_offset_length > 0) + u(time_offset_length, time_offset, + 0, MAX_UINT_BITS(time_offset_length)); + else + infer(time_offset, 0); + + return 0; +} + +static int FUNC(sei_pic_timing)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIPicTiming *current) +{ + CodedBitstreamH264Context *h264 = ctx->priv_data; + const H264RawSPS *sps; + int err; + + sps = h264->active_sps; + if (!sps) { + // If there is exactly one possible SPS but it is not yet active + // then just assume that it should be the active one. + int i, k = -1; + for (i = 0; i < H264_MAX_SPS_COUNT; i++) { + if (h264->sps[i]) { + if (k >= 0) { + k = -1; + break; + } + k = i; + } + } + if (k >= 0) + sps = h264->sps[k]; + } + if (!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "No active SPS for pic_timing.\n"); + return AVERROR_INVALIDDATA; + } + + if (sps->vui.nal_hrd_parameters_present_flag || + sps->vui.vcl_hrd_parameters_present_flag) { + const H264RawHRD *hrd; + + if (sps->vui.nal_hrd_parameters_present_flag) + hrd = &sps->vui.nal_hrd_parameters; + else if (sps->vui.vcl_hrd_parameters_present_flag) + hrd = &sps->vui.vcl_hrd_parameters; + else { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "No HRD parameters for pic_timing.\n"); + return AVERROR_INVALIDDATA; + } + + u(hrd->cpb_removal_delay_length_minus1 + 1, cpb_removal_delay, + 0, MAX_UINT_BITS(hrd->cpb_removal_delay_length_minus1 + 1)); + u(hrd->dpb_output_delay_length_minus1 + 1, dpb_output_delay, + 0, MAX_UINT_BITS(hrd->dpb_output_delay_length_minus1 + 1)); + } + + if (sps->vui.pic_struct_present_flag) { + static const int num_clock_ts[9] = { + 1, 1, 1, 2, 2, 3, 3, 2, 3 + }; + int i; + + u(4, pic_struct, 0, 8); + if (current->pic_struct > 8) + return AVERROR_INVALIDDATA; + + for (i = 0; i < num_clock_ts[current->pic_struct]; i++) { + flag(clock_timestamp_flag[i]); + if (current->clock_timestamp_flag[i]) + CHECK(FUNC(sei_pic_timestamp)(ctx, rw, ¤t->timestamp[i])); + } + } + + return 0; +} + +static int FUNC(sei_user_data_registered)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIUserDataRegistered *current, + uint32_t *payload_size) +{ + int err, i, j; + + u(8, itu_t_t35_country_code, 0x00, 0xff); + if (current->itu_t_t35_country_code != 0xff) + i = 1; + else { + u(8, itu_t_t35_country_code_extension_byte, 0x00, 0xff); + i = 2; + } + +#ifdef READ + if (*payload_size < i) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "Invalid SEI user data registered payload.\n"); + return AVERROR_INVALIDDATA; + } + current->data_length = *payload_size - i; +#else + *payload_size = i + current->data_length; +#endif + + allocate(current->data, current->data_length); + for (j = 0; j < current->data_length; j++) + xu(8, itu_t_t35_payload_byte, current->data[j], 0x00, 0xff); + + return 0; +} + +static int FUNC(sei_user_data_unregistered)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIUserDataUnregistered *current, + uint32_t *payload_size) +{ + int err, i; + +#ifdef READ + if (*payload_size < 16) { + av_log(ctx->log_ctx, AV_LOG_ERROR, + "Invalid SEI user data unregistered payload.\n"); + return AVERROR_INVALIDDATA; + } + current->data_length = *payload_size - 16; +#else + *payload_size = 16 + current->data_length; +#endif + + for (i = 0; i < 16; i++) { + xu(8, uuid_iso_iec_11578, + current->uuid_iso_iec_11578[i], 0x00, 0xff); + } + + allocate(current->data, current->data_length); + + for (i = 0; i < current->data_length; i++) + xu(8, user_data_payload_byte, current->data[i], 0x00, 0xff); + + return 0; +} + +static int FUNC(sei_recovery_point)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIRecoveryPoint *current) +{ + int err; + + ue(recovery_frame_cnt, 0, 65535); + flag(exact_match_flag); + flag(broken_link_flag); + u(2, changing_slice_group_idc, 0, 2); + + return 0; +} + +static int FUNC(sei_display_orientation)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIDisplayOrientation *current) +{ + int err; + + flag(display_orientation_cancel_flag); + if (!current->display_orientation_cancel_flag) { + flag(hor_flip); + flag(ver_flip); + u(16, anticlockwise_rotation, 0, 65535); + ue(display_orientation_repetition_period, 0, 16384); + flag(display_orientation_extension_flag); + } + + return 0; +} + +static int FUNC(sei_payload)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEIPayload *current) +{ + int err, i; + int start_position, end_position; + +#ifdef READ + start_position = get_bits_count(rw); +#else + start_position = put_bits_count(rw); +#endif + + switch (current->payload_type) { + case H264_SEI_TYPE_BUFFERING_PERIOD: + CHECK(FUNC(sei_buffering_period) + (ctx, rw, ¤t->payload.buffering_period)); + break; + case H264_SEI_TYPE_PIC_TIMING: + CHECK(FUNC(sei_pic_timing) + (ctx, rw, ¤t->payload.pic_timing)); + break; + case H264_SEI_TYPE_FILLER_PAYLOAD: + { + av_unused int ff_byte = 0xff; + for (i = 0; i < current->payload_size; i++) + xu(8, ff_byte, ff_byte, 0xff, 0xff); + } + break; + case H264_SEI_TYPE_USER_DATA_REGISTERED: + CHECK(FUNC(sei_user_data_registered) + (ctx, rw, ¤t->payload.user_data_registered, ¤t->payload_size)); + break; + case H264_SEI_TYPE_USER_DATA_UNREGISTERED: + CHECK(FUNC(sei_user_data_unregistered) + (ctx, rw, ¤t->payload.user_data_unregistered, ¤t->payload_size)); + break; + case H264_SEI_TYPE_RECOVERY_POINT: + CHECK(FUNC(sei_recovery_point) + (ctx, rw, ¤t->payload.recovery_point)); + break; + case H264_SEI_TYPE_DISPLAY_ORIENTATION: + CHECK(FUNC(sei_display_orientation) + (ctx, rw, ¤t->payload.display_orientation)); + break; + default: + { + allocate(current->payload.other.data, current->payload_size); + for (i = 0; i < current->payload_size; i++) + xu(8, payload_byte, current->payload.other.data[i], 0, 255); + } + } + + if (byte_alignment(rw)) { + av_unused int one = 1, zero = 0; + xu(1, bit_equal_to_one, one, 1, 1); + while (byte_alignment(rw)) + xu(1, bit_equal_to_zero, zero, 0, 0); + } + +#ifdef READ + end_position = get_bits_count(rw); + if (end_position < start_position + 8 * current->payload_size) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Incorrect SEI payload length: " + "header %"PRIu32" bits, actually %d bits.\n", + 8 * current->payload_size, + end_position - start_position); + return AVERROR_INVALIDDATA; + } +#else + end_position = put_bits_count(rw); + current->payload_size = (end_position - start_position) / 8; +#endif + + return 0; +} + +static int FUNC(sei)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSEI *current) +{ + int err, k; + + HEADER("Supplemental Enhancement Information"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + 1 << H264_NAL_SEI)); + +#ifdef READ + for (k = 0; k < H264_MAX_SEI_PAYLOADS; k++) { + uint32_t payload_type = 0; + uint32_t payload_size = 0; + uint32_t tmp; + + while (show_bits(rw, 8) == 0xff) { + xu(8, ff_byte, tmp, 0xff, 0xff); + payload_type += 255; + } + xu(8, last_payload_type_byte, tmp, 0, 254); + payload_type += tmp; + + while (show_bits(rw, 8) == 0xff) { + xu(8, ff_byte, tmp, 0xff, 0xff); + payload_size += 255; + } + xu(8, last_payload_size_byte, tmp, 0, 254); + payload_size += tmp; + + current->payload[k].payload_type = payload_type; + current->payload[k].payload_size = payload_size; + + CHECK(FUNC(sei_payload)(ctx, rw, ¤t->payload[k])); + + if (!cbs_h2645_read_more_rbsp_data(rw)) + break; + } + if (k >= H264_MAX_SEI_PAYLOADS) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Too many payloads in " + "SEI message: found %d.\n", k); + return AVERROR_INVALIDDATA; + } + current->payload_count = k + 1; +#else + for (k = 0; k < current->payload_count; k++) { + PutBitContext start_state; + uint32_t tmp; + int need_size, i; + + // Somewhat clumsy: we write the payload twice when + // we don't know the size in advance. This will mess + // with trace output, but is otherwise harmless. + start_state = *rw; + need_size = !current->payload[k].payload_size; + for (i = 0; i < 1 + need_size; i++) { + *rw = start_state; + + tmp = current->payload[k].payload_type; + while (tmp >= 255) { + xu(8, ff_byte, 0xff, 0xff, 0xff); + tmp -= 255; + } + xu(8, last_payload_type_byte, tmp, 0, 254); + + tmp = current->payload[k].payload_size; + while (tmp >= 255) { + xu(8, ff_byte, 0xff, 0xff, 0xff); + tmp -= 255; + } + xu(8, last_payload_size_byte, tmp, 0, 254); + + CHECK(FUNC(sei_payload)(ctx, rw, ¤t->payload[k])); + } + } +#endif + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(aud)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawAUD *current) +{ + int err; + + HEADER("Access Unit Delimiter"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + 1 << H264_NAL_AUD)); + + u(3, primary_pic_type, 0, 7); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(ref_pic_list_modification)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSliceHeader *current) +{ + CodedBitstreamH264Context *h264 = ctx->priv_data; + const H264RawSPS *sps = h264->active_sps; + int err, i, mopn; + + if (current->slice_type % 5 != 2 && + current->slice_type % 5 != 4) { + flag(ref_pic_list_modification_flag_l0); + if (current->ref_pic_list_modification_flag_l0) { + for (i = 0; i < H264_MAX_RPLM_COUNT; i++) { + xue(modification_of_pic_nums_idc, + current->rplm_l0[i].modification_of_pic_nums_idc, 0, 3); + + mopn = current->rplm_l0[i].modification_of_pic_nums_idc; + if (mopn == 3) + break; + + if (mopn == 0 || mopn == 1) + xue(abs_diff_pic_num_minus1, + current->rplm_l0[i].abs_diff_pic_num_minus1, + 0, (1 + current->field_pic_flag) * + (1 << (sps->log2_max_frame_num_minus4 + 4))); + else if (mopn == 2) + xue(long_term_pic_num, + current->rplm_l0[i].long_term_pic_num, + 0, sps->max_num_ref_frames - 1); + } + } + } + + if (current->slice_type % 5 == 1) { + flag(ref_pic_list_modification_flag_l1); + if (current->ref_pic_list_modification_flag_l1) { + for (i = 0; i < H264_MAX_RPLM_COUNT; i++) { + xue(modification_of_pic_nums_idc, + current->rplm_l1[i].modification_of_pic_nums_idc, 0, 3); + + mopn = current->rplm_l1[i].modification_of_pic_nums_idc; + if (mopn == 3) + break; + + if (mopn == 0 || mopn == 1) + xue(abs_diff_pic_num_minus1, + current->rplm_l1[i].abs_diff_pic_num_minus1, + 0, (1 + current->field_pic_flag) * + (1 << (sps->log2_max_frame_num_minus4 + 4))); + else if (mopn == 2) + xue(long_term_pic_num, + current->rplm_l1[i].long_term_pic_num, + 0, sps->max_num_ref_frames - 1); + } + } + } + + return 0; +} + +static int FUNC(pred_weight_table)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSliceHeader *current) +{ + CodedBitstreamH264Context *h264 = ctx->priv_data; + const H264RawSPS *sps = h264->active_sps; + int chroma; + int err, i, j; + + ue(luma_log2_weight_denom, 0, 7); + + chroma = !sps->separate_colour_plane_flag && sps->chroma_format_idc != 0; + if (chroma) + ue(chroma_log2_weight_denom, 0, 7); + + for (i = 0; i <= current->num_ref_idx_l0_active_minus1; i++) { + flag(luma_weight_l0_flag[i]); + if (current->luma_weight_l0_flag[i]) { + se(luma_weight_l0[i], -128, +127); + se(luma_offset_l0[i], -128, +127); + } + if (chroma) { + flag(chroma_weight_l0_flag[i]); + if (current->chroma_weight_l0_flag[i]) { + for (j = 0; j < 2; j++) { + se(chroma_weight_l0[i][j], -128, +127); + se(chroma_offset_l0[i][j], -128, +127); + } + } + } + } + + if (current->slice_type % 5 == 1) { + for (i = 0; i <= current->num_ref_idx_l1_active_minus1; i++) { + flag(luma_weight_l1_flag[i]); + if (current->luma_weight_l1_flag[i]) { + se(luma_weight_l1[i], -128, +127); + se(luma_offset_l1[i], -128, +127); + } + if (chroma) { + flag(chroma_weight_l1_flag[i]); + if (current->chroma_weight_l1_flag[i]) { + for (j = 0; j < 2; j++) { + se(chroma_weight_l1[i][j], -128, +127); + se(chroma_offset_l1[i][j], -128, +127); + } + } + } + } + } + + return 0; +} + +static int FUNC(dec_ref_pic_marking)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSliceHeader *current, int idr_pic_flag) +{ + CodedBitstreamH264Context *h264 = ctx->priv_data; + const H264RawSPS *sps = h264->active_sps; + int err, i; + uint32_t mmco; + + if (idr_pic_flag) { + flag(no_output_of_prior_pics_flag); + flag(long_term_reference_flag); + } else { + flag(adaptive_ref_pic_marking_mode_flag); + if (current->adaptive_ref_pic_marking_mode_flag) { + for (i = 0; i < H264_MAX_MMCO_COUNT; i++) { + xue(memory_management_control_operation, + current->mmco[i].memory_management_control_operation, + 0, 6); + + mmco = current->mmco[i].memory_management_control_operation; + if (mmco == 0) + break; + + if (mmco == 1 || mmco == 3) + xue(difference_of_pic_nums_minus1, + current->mmco[i].difference_of_pic_nums_minus1, + 0, INT32_MAX); + if (mmco == 2) + xue(long_term_pic_num, + current->mmco[i].long_term_pic_num, + 0, sps->max_num_ref_frames - 1); + if (mmco == 3 || mmco == 6) + xue(long_term_frame_idx, + current->mmco[i].long_term_frame_idx, + 0, sps->max_num_ref_frames - 1); + if (mmco == 4) + xue(max_long_term_frame_idx_plus1, + current->mmco[i].max_long_term_frame_idx_plus1, + 0, sps->max_num_ref_frames); + } + if (i == H264_MAX_MMCO_COUNT) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Too many " + "memory management control operations.\n"); + return AVERROR_INVALIDDATA; + } + } + } + + return 0; +} + +static int FUNC(slice_header)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawSliceHeader *current) +{ + CodedBitstreamH264Context *h264 = ctx->priv_data; + const H264RawSPS *sps; + const H264RawPPS *pps; + int err; + int idr_pic_flag; + int slice_type_i, slice_type_p, slice_type_b; + int slice_type_si, slice_type_sp; + + HEADER("Slice Header"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + 1 << H264_NAL_SLICE | + 1 << H264_NAL_IDR_SLICE | + 1 << H264_NAL_AUXILIARY_SLICE)); + + if (current->nal_unit_header.nal_unit_type == H264_NAL_AUXILIARY_SLICE) { + if (!h264->last_slice_nal_unit_type) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Auxiliary slice " + "is not decodable without the main picture " + "in the same access unit.\n"); + return AVERROR_INVALIDDATA; + } + } else { + h264->last_slice_nal_unit_type = + current->nal_unit_header.nal_unit_type; + } + idr_pic_flag = h264->last_slice_nal_unit_type == H264_NAL_IDR_SLICE; + + ue(first_mb_in_slice, 0, H264_MAX_MB_PIC_SIZE - 1); + ue(slice_type, 0, 9); + + slice_type_i = current->slice_type % 5 == 2; + slice_type_p = current->slice_type % 5 == 0; + slice_type_b = current->slice_type % 5 == 1; + slice_type_si = current->slice_type % 5 == 4; + slice_type_sp = current->slice_type % 5 == 3; + + if (idr_pic_flag && !(slice_type_i || slice_type_si)) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid slice type %d " + "for IDR picture.\n", current->slice_type); + return AVERROR_INVALIDDATA; + } + + ue(pic_parameter_set_id, 0, 255); + + pps = h264->pps[current->pic_parameter_set_id]; + if (!pps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "PPS id %d not available.\n", + current->pic_parameter_set_id); + return AVERROR_INVALIDDATA; + } + h264->active_pps = pps; + + sps = h264->sps[pps->seq_parameter_set_id]; + if (!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "SPS id %d not available.\n", + pps->seq_parameter_set_id); + return AVERROR_INVALIDDATA; + } + h264->active_sps = sps; + + if (sps->separate_colour_plane_flag) + u(2, colour_plane_id, 0, 2); + + u(sps->log2_max_frame_num_minus4 + 4, frame_num, + 0, MAX_UINT_BITS(sps->log2_max_frame_num_minus4 + 4)); + + if (!sps->frame_mbs_only_flag) { + flag(field_pic_flag); + if (current->field_pic_flag) + flag(bottom_field_flag); + else + infer(bottom_field_flag, 0); + } else { + infer(field_pic_flag, 0); + infer(bottom_field_flag, 0); + } + + if (idr_pic_flag) + ue(idr_pic_id, 0, 65535); + + if (sps->pic_order_cnt_type == 0) { + u(sps->log2_max_pic_order_cnt_lsb_minus4 + 4, pic_order_cnt_lsb, + 0, MAX_UINT_BITS(sps->log2_max_pic_order_cnt_lsb_minus4 + 4)); + if (pps->bottom_field_pic_order_in_frame_present_flag && + !current->field_pic_flag) + se(delta_pic_order_cnt_bottom, INT32_MIN + 1, INT32_MAX); + + } else if (sps->pic_order_cnt_type == 1) { + if (!sps->delta_pic_order_always_zero_flag) { + se(delta_pic_order_cnt[0], INT32_MIN + 1, INT32_MAX); + if (pps->bottom_field_pic_order_in_frame_present_flag && + !current->field_pic_flag) + se(delta_pic_order_cnt[1], INT32_MIN + 1, INT32_MAX); + else + infer(delta_pic_order_cnt[1], 0); + } else { + infer(delta_pic_order_cnt[0], 0); + infer(delta_pic_order_cnt[1], 0); + } + } + + if (pps->redundant_pic_cnt_present_flag) + ue(redundant_pic_cnt, 0, 127); + + if (slice_type_b) + flag(direct_spatial_mv_pred_flag); + + if (slice_type_p || slice_type_sp || slice_type_b) { + flag(num_ref_idx_active_override_flag); + if (current->num_ref_idx_active_override_flag) { + ue(num_ref_idx_l0_active_minus1, 0, 31); + if (slice_type_b) + ue(num_ref_idx_l1_active_minus1, 0, 31); + } else { + infer(num_ref_idx_l0_active_minus1, + pps->num_ref_idx_l0_default_active_minus1); + infer(num_ref_idx_l1_active_minus1, + pps->num_ref_idx_l1_default_active_minus1); + } + } + + if (current->nal_unit_header.nal_unit_type == 20 || + current->nal_unit_header.nal_unit_type == 21) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "MVC / 3DAVC not supported.\n"); + return AVERROR_PATCHWELCOME; + } else { + CHECK(FUNC(ref_pic_list_modification)(ctx, rw, current)); + } + + if ((pps->weighted_pred_flag && (slice_type_p || slice_type_sp)) || + (pps->weighted_bipred_idc == 1 && slice_type_b)) { + CHECK(FUNC(pred_weight_table)(ctx, rw, current)); + } + + if (current->nal_unit_header.nal_ref_idc != 0) { + CHECK(FUNC(dec_ref_pic_marking)(ctx, rw, current, idr_pic_flag)); + } + + if (pps->entropy_coding_mode_flag && + !slice_type_i && !slice_type_si) { + ue(cabac_init_idc, 0, 2); + } + + se(slice_qp_delta, - 51 - 6 * sps->bit_depth_luma_minus8, + + 51 + 6 * sps->bit_depth_luma_minus8); + if (slice_type_sp || slice_type_si) { + if (slice_type_sp) + flag(sp_for_switch_flag); + se(slice_qs_delta, -51, +51); + } + + if (pps->deblocking_filter_control_present_flag) { + ue(disable_deblocking_filter_idc, 0, 2); + if (current->disable_deblocking_filter_idc != 1) { + se(slice_alpha_c0_offset_div2, -6, +6); + se(slice_beta_offset_div2, -6, +6); + } else { + infer(slice_alpha_c0_offset_div2, 0); + infer(slice_beta_offset_div2, 0); + } + } else { + infer(disable_deblocking_filter_idc, 0); + infer(slice_alpha_c0_offset_div2, 0); + infer(slice_beta_offset_div2, 0); + } + + if (pps->num_slice_groups_minus1 > 0 && + pps->slice_group_map_type >= 3 && + pps->slice_group_map_type <= 5) { + unsigned int pic_size, max, bits; + + pic_size = (sps->pic_width_in_mbs_minus1 + 1) * + (sps->pic_height_in_map_units_minus1 + 1); + max = (pic_size + pps->slice_group_change_rate_minus1) / + (pps->slice_group_change_rate_minus1 + 1); + bits = av_log2(2 * max - 1); + + u(bits, slice_group_change_cycle, 0, max); + } + + if (pps->entropy_coding_mode_flag) { + av_unused int one = 1; + while (byte_alignment(rw)) + xu(1, cabac_alignment_one_bit, one, 1, 1); + } + + return 0; +} + +static int FUNC(filler)(CodedBitstreamContext *ctx, RWContext *rw, + H264RawFiller *current) +{ + av_unused int ff_byte = 0xff; + int err; + + HEADER("Filler Data"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, + 1 << H264_NAL_FILLER_DATA)); + +#ifdef READ + while (show_bits(rw, 8) == 0xff) { + xu(8, ff_byte, ff_byte, 0xff, 0xff); + ++current->filler_size; + } +#else + { + uint32_t i; + for (i = 0; i < current->filler_size; i++) + xu(8, ff_byte, ff_byte, 0xff, 0xff); + } +#endif + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} diff --git a/libavcodec/cbs_h265.h b/libavcodec/cbs_h265.h new file mode 100644 index 0000000000000..33e71fc234e1d --- /dev/null +++ b/libavcodec/cbs_h265.h @@ -0,0 +1,539 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_CBS_H265_H +#define AVCODEC_CBS_H265_H + +#include +#include + +#include "cbs_h2645.h" +#include "hevc.h" + + +typedef struct H265RawNALUnitHeader { + uint8_t forbidden_zero_bit; + uint8_t nal_unit_type; + uint8_t nuh_layer_id; + uint8_t nuh_temporal_id_plus1; +} H265RawNALUnitHeader; + +typedef struct H265RawProfileTierLevel { + uint8_t general_profile_space; + uint8_t general_tier_flag; + uint8_t general_profile_idc; + + uint8_t general_profile_compatibility_flag[32]; + + uint8_t general_progressive_source_flag; + uint8_t general_interlaced_source_flag; + uint8_t general_non_packed_constraint_flag; + uint8_t general_frame_only_constraint_flag; + + uint8_t general_max_12bit_constraint_flag; + uint8_t general_max_10bit_constraint_flag; + uint8_t general_max_8bit_constraint_flag; + uint8_t general_max_422chroma_constraint_flag; + uint8_t general_max_420chroma_constraint_flag; + uint8_t general_max_monochrome_constraint_flag; + uint8_t general_intra_constraint_flag; + uint8_t general_one_picture_only_constraint_flag; + uint8_t general_lower_bit_rate_constraint_flag; + uint8_t general_max_14bit_constraint_flag; + + uint8_t general_inbld_flag; + + uint8_t general_level_idc; + + uint8_t sub_layer_profile_present_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t sub_layer_level_present_flag[HEVC_MAX_SUB_LAYERS]; + + // TODO: much of that again for each sub-layer. +} H265RawProfileTierLevel; + +typedef struct H265RawSubLayerHRDParameters { + uint32_t bit_rate_value_minus1[HEVC_MAX_CPB_CNT]; + uint32_t cpb_size_value_minus1[HEVC_MAX_CPB_CNT]; + uint32_t cpb_size_du_value_minus1[HEVC_MAX_CPB_CNT]; + uint32_t bit_rate_du_value_minus1[HEVC_MAX_CPB_CNT]; + uint8_t cbr_flag[HEVC_MAX_CPB_CNT]; +} H265RawSubLayerHRDParameters; + +typedef struct H265RawHRDParameters { + uint8_t nal_hrd_parameters_present_flag; + uint8_t vcl_hrd_parameters_present_flag; + + uint8_t sub_pic_hrd_params_present_flag; + uint8_t tick_divisor_minus2; + uint8_t du_cpb_removal_delay_increment_length_minus1; + uint8_t sub_pic_cpb_params_in_pic_timing_sei_flag; + uint8_t dpb_output_delay_du_length_minus1; + + uint8_t bit_rate_scale; + uint8_t cpb_size_scale; + uint8_t cpb_size_du_scale; + + uint8_t initial_cpb_removal_delay_length_minus1; + uint8_t au_cpb_removal_delay_length_minus1; + uint8_t dpb_output_delay_length_minus1; + + uint8_t fixed_pic_rate_general_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t fixed_pic_rate_within_cvs_flag[HEVC_MAX_SUB_LAYERS]; + uint16_t elemental_duration_in_tc_minus1[HEVC_MAX_SUB_LAYERS]; + uint8_t low_delay_hrd_flag[HEVC_MAX_SUB_LAYERS]; + uint8_t cpb_cnt_minus1[HEVC_MAX_SUB_LAYERS]; + H265RawSubLayerHRDParameters nal_sub_layer_hrd_parameters[HEVC_MAX_SUB_LAYERS]; + H265RawSubLayerHRDParameters vcl_sub_layer_hrd_parameters[HEVC_MAX_SUB_LAYERS]; +} H265RawHRDParameters; + +typedef struct H265RawVUI { + uint8_t aspect_ratio_info_present_flag; + uint8_t aspect_ratio_idc; + uint16_t sar_width; + uint16_t sar_height; + + uint8_t overscan_info_present_flag; + uint8_t overscan_appropriate_flag; + + uint8_t video_signal_type_present_flag; + uint8_t video_format; + uint8_t video_full_range_flag; + uint8_t colour_description_present_flag; + uint8_t colour_primaries; + uint8_t transfer_characteristics; + uint8_t matrix_coefficients; + + uint8_t chroma_loc_info_present_flag; + uint8_t chroma_sample_loc_type_top_field; + uint8_t chroma_sample_loc_type_bottom_field; + + uint8_t neutral_chroma_indication_flag; + uint8_t field_seq_flag; + uint8_t frame_field_info_present_flag; + + uint8_t default_display_window_flag; + uint16_t def_disp_win_left_offset; + uint16_t def_disp_win_right_offset; + uint16_t def_disp_win_top_offset; + uint16_t def_disp_win_bottom_offset; + + uint8_t vui_timing_info_present_flag; + uint32_t vui_num_units_in_tick; + uint32_t vui_time_scale; + uint8_t vui_poc_proportional_to_timing_flag; + uint32_t vui_num_ticks_poc_diff_one_minus1; + uint8_t vui_hrd_parameters_present_flag; + H265RawHRDParameters hrd_parameters; + + uint8_t bitstream_restriction_flag; + uint8_t tiles_fixed_structure_flag; + uint8_t motion_vectors_over_pic_boundaries_flag; + uint8_t restricted_ref_pic_lists_flag; + uint16_t min_spatial_segmentation_idc; + uint8_t max_bytes_per_pic_denom; + uint8_t max_bits_per_min_cu_denom; + uint8_t log2_max_mv_length_horizontal; + uint8_t log2_max_mv_length_vertical; +} H265RawVUI; + +typedef struct H265RawPSExtensionData { + uint8_t *data; + size_t bit_length; + AVBufferRef *data_ref; +} H265RawPSExtensionData; + +typedef struct H265RawVPS { + H265RawNALUnitHeader nal_unit_header; + + uint8_t vps_video_parameter_set_id; + + uint8_t vps_base_layer_internal_flag; + uint8_t vps_base_layer_available_flag; + uint8_t vps_max_layers_minus1; + uint8_t vps_max_sub_layers_minus1; + uint8_t vps_temporal_id_nesting_flag; + + H265RawProfileTierLevel profile_tier_level; + + uint8_t vps_sub_layer_ordering_info_present_flag; + uint8_t vps_max_dec_pic_buffering_minus1[HEVC_MAX_SUB_LAYERS]; + uint8_t vps_max_num_reorder_pics[HEVC_MAX_SUB_LAYERS]; + uint32_t vps_max_latency_increase_plus1[HEVC_MAX_SUB_LAYERS]; + + uint8_t vps_max_layer_id; + uint16_t vps_num_layer_sets_minus1; + uint8_t layer_id_included_flag[HEVC_MAX_LAYER_SETS][HEVC_MAX_LAYERS]; + + uint8_t vps_timing_info_present_flag; + uint32_t vps_num_units_in_tick; + uint32_t vps_time_scale; + uint8_t vps_poc_proportional_to_timing_flag; + uint32_t vps_num_ticks_poc_diff_one_minus1; + uint16_t vps_num_hrd_parameters; + uint16_t hrd_layer_set_idx[HEVC_MAX_LAYER_SETS]; + uint8_t cprms_present_flag[HEVC_MAX_LAYER_SETS]; + H265RawHRDParameters hrd_parameters[HEVC_MAX_LAYER_SETS]; + + uint8_t vps_extension_flag; + H265RawPSExtensionData extension_data; +} H265RawVPS; + +typedef struct H265RawSTRefPicSet { + uint8_t inter_ref_pic_set_prediction_flag; + + uint8_t delta_idx_minus1; + uint8_t delta_rps_sign; + uint16_t abs_delta_rps_minus1; + + uint8_t used_by_curr_pic_flag[HEVC_MAX_REFS]; + uint8_t use_delta_flag[HEVC_MAX_REFS]; + + uint8_t num_negative_pics; + uint8_t num_positive_pics; + uint16_t delta_poc_s0_minus1[HEVC_MAX_REFS]; + uint8_t used_by_curr_pic_s0_flag[HEVC_MAX_REFS]; + uint16_t delta_poc_s1_minus1[HEVC_MAX_REFS]; + uint8_t used_by_curr_pic_s1_flag[HEVC_MAX_REFS]; +} H265RawSTRefPicSet; + +typedef struct H265RawScalingList { + uint8_t scaling_list_pred_mode_flag[4][6]; + uint8_t scaling_list_pred_matrix_id_delta[4][6]; + int16_t scaling_list_dc_coef_minus8[4][6]; + int8_t scaling_list_delta_coeff[4][6][64]; +} H265RawScalingList; + +typedef struct H265RawSPS { + H265RawNALUnitHeader nal_unit_header; + + uint8_t sps_video_parameter_set_id; + + uint8_t sps_max_sub_layers_minus1; + uint8_t sps_temporal_id_nesting_flag; + + H265RawProfileTierLevel profile_tier_level; + + uint8_t sps_seq_parameter_set_id; + + uint8_t chroma_format_idc; + uint8_t separate_colour_plane_flag; + + uint16_t pic_width_in_luma_samples; + uint16_t pic_height_in_luma_samples; + + uint8_t conformance_window_flag; + uint16_t conf_win_left_offset; + uint16_t conf_win_right_offset; + uint16_t conf_win_top_offset; + uint16_t conf_win_bottom_offset; + + uint8_t bit_depth_luma_minus8; + uint8_t bit_depth_chroma_minus8; + + uint8_t log2_max_pic_order_cnt_lsb_minus4; + + uint8_t sps_sub_layer_ordering_info_present_flag; + uint8_t sps_max_dec_pic_buffering_minus1[HEVC_MAX_SUB_LAYERS]; + uint8_t sps_max_num_reorder_pics[HEVC_MAX_SUB_LAYERS]; + uint32_t sps_max_latency_increase_plus1[HEVC_MAX_SUB_LAYERS]; + + uint8_t log2_min_luma_coding_block_size_minus3; + uint8_t log2_diff_max_min_luma_coding_block_size; + uint8_t log2_min_luma_transform_block_size_minus2; + uint8_t log2_diff_max_min_luma_transform_block_size; + uint8_t max_transform_hierarchy_depth_inter; + uint8_t max_transform_hierarchy_depth_intra; + + uint8_t scaling_list_enabled_flag; + uint8_t sps_scaling_list_data_present_flag; + H265RawScalingList scaling_list; + + uint8_t amp_enabled_flag; + uint8_t sample_adaptive_offset_enabled_flag; + + uint8_t pcm_enabled_flag; + uint8_t pcm_sample_bit_depth_luma_minus1; + uint8_t pcm_sample_bit_depth_chroma_minus1; + uint8_t log2_min_pcm_luma_coding_block_size_minus3; + uint8_t log2_diff_max_min_pcm_luma_coding_block_size; + uint8_t pcm_loop_filter_disabled_flag; + + uint8_t num_short_term_ref_pic_sets; + H265RawSTRefPicSet st_ref_pic_set[HEVC_MAX_SHORT_TERM_REF_PIC_SETS]; + + uint8_t long_term_ref_pics_present_flag; + uint8_t num_long_term_ref_pics_sps; + uint16_t lt_ref_pic_poc_lsb_sps[HEVC_MAX_LONG_TERM_REF_PICS]; + uint8_t used_by_curr_pic_lt_sps_flag[HEVC_MAX_LONG_TERM_REF_PICS]; + + uint8_t sps_temporal_mvp_enabled_flag; + uint8_t strong_intra_smoothing_enabled_flag; + + uint8_t vui_parameters_present_flag; + H265RawVUI vui; + + uint8_t sps_extension_present_flag; + uint8_t sps_range_extension_flag; + uint8_t sps_multilayer_extension_flag; + uint8_t sps_3d_extension_flag; + uint8_t sps_scc_extension_flag; + uint8_t sps_extension_4bits; + + H265RawPSExtensionData extension_data; + + // Range extension. + uint8_t transform_skip_rotation_enabled_flag; + uint8_t transform_skip_context_enabled_flag; + uint8_t implicit_rdpcm_enabled_flag; + uint8_t explicit_rdpcm_enabled_flag; + uint8_t extended_precision_processing_flag; + uint8_t intra_smoothing_disabled_flag; + uint8_t high_precision_offsets_enabled_flag; + uint8_t persistent_rice_adaptation_enabled_flag; + uint8_t cabac_bypass_alignment_enabled_flag; + + // Screen content coding extension. + uint8_t sps_curr_pic_ref_enabled_flag; + uint8_t palette_mode_enabled_flag; + uint8_t palette_max_size; + uint8_t delta_palette_max_predictor_size; + uint8_t sps_palette_predictor_initializer_present_flag; + uint8_t sps_num_palette_predictor_initializer_minus1; + uint16_t sps_palette_predictor_initializers[3][128]; + + uint8_t motion_vector_resolution_control_idc; + uint8_t intra_boundary_filtering_disable_flag; +} H265RawSPS; + +typedef struct H265RawPPS { + H265RawNALUnitHeader nal_unit_header; + + uint8_t pps_pic_parameter_set_id; + uint8_t pps_seq_parameter_set_id; + + uint8_t dependent_slice_segments_enabled_flag; + uint8_t output_flag_present_flag; + uint8_t num_extra_slice_header_bits; + uint8_t sign_data_hiding_enabled_flag; + uint8_t cabac_init_present_flag; + + uint8_t num_ref_idx_l0_default_active_minus1; + uint8_t num_ref_idx_l1_default_active_minus1; + + int8_t init_qp_minus26; + + uint8_t constrained_intra_pred_flag; + uint8_t transform_skip_enabled_flag; + uint8_t cu_qp_delta_enabled_flag; + uint8_t diff_cu_qp_delta_depth; + + int8_t pps_cb_qp_offset; + int8_t pps_cr_qp_offset; + uint8_t pps_slice_chroma_qp_offsets_present_flag; + + uint8_t weighted_pred_flag; + uint8_t weighted_bipred_flag; + + uint8_t transquant_bypass_enabled_flag; + uint8_t tiles_enabled_flag; + uint8_t entropy_coding_sync_enabled_flag; + + uint8_t num_tile_columns_minus1; + uint8_t num_tile_rows_minus1; + uint8_t uniform_spacing_flag; + uint16_t column_width_minus1[HEVC_MAX_TILE_COLUMNS]; + uint16_t row_height_minus1[HEVC_MAX_TILE_ROWS]; + uint8_t loop_filter_across_tiles_enabled_flag; + + uint8_t pps_loop_filter_across_slices_enabled_flag; + uint8_t deblocking_filter_control_present_flag; + uint8_t deblocking_filter_override_enabled_flag; + uint8_t pps_deblocking_filter_disabled_flag; + int8_t pps_beta_offset_div2; + int8_t pps_tc_offset_div2; + + uint8_t pps_scaling_list_data_present_flag; + H265RawScalingList scaling_list; + + uint8_t lists_modification_present_flag; + uint8_t log2_parallel_merge_level_minus2; + + uint8_t slice_segment_header_extension_present_flag; + + uint8_t pps_extension_present_flag; + uint8_t pps_range_extension_flag; + uint8_t pps_multilayer_extension_flag; + uint8_t pps_3d_extension_flag; + uint8_t pps_scc_extension_flag; + uint8_t pps_extension_4bits; + + H265RawPSExtensionData extension_data; + + // Range extension. + uint8_t log2_max_transform_skip_block_size_minus2; + uint8_t cross_component_prediction_enabled_flag; + uint8_t chroma_qp_offset_list_enabled_flag; + uint8_t diff_cu_chroma_qp_offset_depth; + uint8_t chroma_qp_offset_list_len_minus1; + int8_t cb_qp_offset_list[6]; + int8_t cr_qp_offset_list[6]; + uint8_t log2_sao_offset_scale_luma; + uint8_t log2_sao_offset_scale_chroma; + + // Screen content coding extension. + uint8_t pps_curr_pic_ref_enabled_flag; + uint8_t residual_adaptive_colour_transform_enabled_flag; + uint8_t pps_slice_act_qp_offsets_present_flag; + int8_t pps_act_y_qp_offset_plus5; + int8_t pps_act_cb_qp_offset_plus5; + int8_t pps_act_cr_qp_offset_plus3; + + uint8_t pps_palette_predictor_initializer_present_flag; + uint8_t pps_num_palette_predictor_initializer; + uint8_t monochrome_palette_flag; + uint8_t luma_bit_depth_entry_minus8; + uint8_t chroma_bit_depth_entry_minus8; + uint16_t pps_palette_predictor_initializers[3][128]; +} H265RawPPS; + +typedef struct H265RawAUD { + H265RawNALUnitHeader nal_unit_header; + + uint8_t pic_type; +} H265RawAUD; + +typedef struct H265RawSliceHeader { + H265RawNALUnitHeader nal_unit_header; + + uint8_t first_slice_segment_in_pic_flag; + uint8_t no_output_of_prior_pics_flag; + uint8_t slice_pic_parameter_set_id; + + uint8_t dependent_slice_segment_flag; + uint16_t slice_segment_address; + + uint8_t slice_reserved_flag[8]; + uint8_t slice_type; + + uint8_t pic_output_flag; + uint8_t colour_plane_id; + + uint16_t slice_pic_order_cnt_lsb; + + uint8_t short_term_ref_pic_set_sps_flag; + H265RawSTRefPicSet short_term_ref_pic_set; + uint8_t short_term_ref_pic_set_idx; + + uint8_t num_long_term_sps; + uint8_t num_long_term_pics; + uint8_t lt_idx_sps[HEVC_MAX_REFS]; + uint8_t poc_lsb_lt[HEVC_MAX_REFS]; + uint8_t used_by_curr_pic_lt_flag[HEVC_MAX_REFS]; + uint8_t delta_poc_msb_present_flag[HEVC_MAX_REFS]; + uint32_t delta_poc_msb_cycle_lt[HEVC_MAX_REFS]; + + uint8_t slice_temporal_mvp_enabled_flag; + + uint8_t slice_sao_luma_flag; + uint8_t slice_sao_chroma_flag; + + uint8_t num_ref_idx_active_override_flag; + uint8_t num_ref_idx_l0_active_minus1; + uint8_t num_ref_idx_l1_active_minus1; + + uint8_t ref_pic_list_modification_flag_l0; + uint8_t list_entry_l0[HEVC_MAX_REFS]; + uint8_t ref_pic_list_modification_flag_l1; + uint8_t list_entry_l1[HEVC_MAX_REFS]; + + uint8_t mvd_l1_zero_flag; + uint8_t cabac_init_flag; + uint8_t collocated_from_l0_flag; + uint8_t collocated_ref_idx; + + uint8_t luma_log2_weight_denom; + int8_t delta_chroma_log2_weight_denom; + uint8_t luma_weight_l0_flag[HEVC_MAX_REFS]; + uint8_t chroma_weight_l0_flag[HEVC_MAX_REFS]; + int8_t delta_luma_weight_l0[HEVC_MAX_REFS]; + int16_t luma_offset_l0[HEVC_MAX_REFS]; + int8_t delta_chroma_weight_l0[HEVC_MAX_REFS][2]; + int16_t chroma_offset_l0[HEVC_MAX_REFS][2]; + uint8_t luma_weight_l1_flag[HEVC_MAX_REFS]; + uint8_t chroma_weight_l1_flag[HEVC_MAX_REFS]; + int8_t delta_luma_weight_l1[HEVC_MAX_REFS]; + int16_t luma_offset_l1[HEVC_MAX_REFS]; + int8_t delta_chroma_weight_l1[HEVC_MAX_REFS][2]; + int16_t chroma_offset_l1[HEVC_MAX_REFS][2]; + + uint8_t five_minus_max_num_merge_cand; + uint8_t use_integer_mv_flag; + + int8_t slice_qp_delta; + int8_t slice_cb_qp_offset; + int8_t slice_cr_qp_offset; + int8_t slice_act_y_qp_offset; + int8_t slice_act_cb_qp_offset; + int8_t slice_act_cr_qp_offset; + uint8_t cu_chroma_qp_offset_enabled_flag; + + uint8_t deblocking_filter_override_flag; + uint8_t slice_deblocking_filter_disabled_flag; + int8_t slice_beta_offset_div2; + int8_t slice_tc_offset_div2; + uint8_t slice_loop_filter_across_slices_enabled_flag; + + uint16_t num_entry_point_offsets; + uint8_t offset_len_minus1; + uint32_t entry_point_offset_minus1[HEVC_MAX_ENTRY_POINT_OFFSETS]; + + uint16_t slice_segment_header_extension_length; + uint8_t slice_segment_header_extension_data_byte[256]; +} H265RawSliceHeader; + + +typedef struct H265RawSlice { + H265RawSliceHeader header; + + uint8_t *data; + size_t data_size; + int data_bit_start; + AVBufferRef *data_ref; +} H265RawSlice; + + +typedef struct CodedBitstreamH265Context { + // Reader/writer context in common with the H.264 implementation. + CodedBitstreamH2645Context common; + + // All currently available parameter sets. These are updated when + // any parameter set NAL unit is read/written with this context. + H265RawVPS *vps[HEVC_MAX_VPS_COUNT]; + H265RawSPS *sps[HEVC_MAX_SPS_COUNT]; + H265RawPPS *pps[HEVC_MAX_PPS_COUNT]; + + // The currently active parameter sets. These are updated when any + // NAL unit refers to the relevant parameter set. These pointers + // must also be present in the arrays above. + const H265RawVPS *active_vps; + const H265RawSPS *active_sps; + const H265RawPPS *active_pps; +} CodedBitstreamH265Context; + + +#endif /* AVCODEC_CBS_H265_H */ diff --git a/libavcodec/cbs_h265_syntax_template.c b/libavcodec/cbs_h265_syntax_template.c new file mode 100644 index 0000000000000..140c827c9dd2f --- /dev/null +++ b/libavcodec/cbs_h265_syntax_template.c @@ -0,0 +1,1503 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +static int FUNC(rbsp_trailing_bits)(CodedBitstreamContext *ctx, RWContext *rw) +{ + int err; + av_unused int one = 1, zero = 0; + xu(1, rbsp_stop_one_bit, one, 1, 1); + while (byte_alignment(rw) != 0) + xu(1, rbsp_alignment_zero_bit, zero, 0, 0); + + return 0; +} + +static int FUNC(nal_unit_header)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawNALUnitHeader *current, + int expected_nal_unit_type) +{ + int err; + + u(1, forbidden_zero_bit, 0, 0); + + if (expected_nal_unit_type >= 0) + u(6, nal_unit_type, expected_nal_unit_type, + expected_nal_unit_type); + else + u(6, nal_unit_type, 0, 63); + + u(6, nuh_layer_id, 0, 62); + u(3, nuh_temporal_id_plus1, 1, 7); + + return 0; +} + +static int FUNC(byte_alignment)(CodedBitstreamContext *ctx, RWContext *rw) +{ + int err; + av_unused int one = 1, zero = 0; + xu(1, alignment_bit_equal_to_one, one, 1, 1); + while (byte_alignment(rw) != 0) + xu(1, alignment_bit_equal_to_zero, zero, 0, 0); + + return 0; +} + +static int FUNC(extension_data)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawPSExtensionData *current) +{ + int err; + size_t k; +#ifdef READ + GetBitContext start; + uint8_t bit; + start = *rw; + for (k = 0; cbs_h2645_read_more_rbsp_data(rw); k++) + skip_bits(rw, 1); + current->bit_length = k; + if (k > 0) { + *rw = start; + allocate(current->data, (current->bit_length + 7) / 8); + for (k = 0; k < current->bit_length; k++) { + xu(1, extension_data, bit, 0, 1); + current->data[k / 8] |= bit << (7 - k % 8); + } + } +#else + for (k = 0; k < current->bit_length; k++) + xu(1, extension_data, current->data[k / 8] >> (7 - k % 8), 0, 1); +#endif + return 0; +} + +static int FUNC(profile_tier_level)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawProfileTierLevel *current, + int profile_present_flag, + int max_num_sub_layers_minus1) +{ + av_unused unsigned int zero = 0; + int err, i, j; + + if (profile_present_flag) { + u(2, general_profile_space, 0, 0); + flag(general_tier_flag); + u(5, general_profile_idc, 0, 31); + + for (j = 0; j < 32; j++) + flag(general_profile_compatibility_flag[j]); + + flag(general_progressive_source_flag); + flag(general_interlaced_source_flag); + flag(general_non_packed_constraint_flag); + flag(general_frame_only_constraint_flag); + +#define profile_compatible(x) (current->general_profile_idc == (x) || \ + current->general_profile_compatibility_flag[x]) + if (profile_compatible(4) || profile_compatible(5) || + profile_compatible(6) || profile_compatible(7) || + profile_compatible(8) || profile_compatible(9) || + profile_compatible(10)) { + flag(general_max_12bit_constraint_flag); + flag(general_max_10bit_constraint_flag); + flag(general_max_8bit_constraint_flag); + flag(general_max_422chroma_constraint_flag); + flag(general_max_420chroma_constraint_flag); + flag(general_max_monochrome_constraint_flag); + flag(general_intra_constraint_flag); + flag(general_one_picture_only_constraint_flag); + flag(general_lower_bit_rate_constraint_flag); + + if (profile_compatible(5) || profile_compatible(9) || + profile_compatible(10)) { + flag(general_max_14bit_constraint_flag); + xu(24, general_reserved_zero_33bits, zero, 0, 0); + xu(9, general_reserved_zero_33bits, zero, 0, 0); + } else { + xu(24, general_reserved_zero_34bits, zero, 0, 0); + xu(10, general_reserved_zero_34bits, zero, 0, 0); + } + } else { + xu(24, general_reserved_zero_43bits, zero, 0, 0); + xu(19, general_reserved_zero_43bits, zero, 0, 0); + } + + if (profile_compatible(1) || profile_compatible(2) || + profile_compatible(3) || profile_compatible(4) || + profile_compatible(5) || profile_compatible(9)) { + flag(general_inbld_flag); + } else { + xu(1, general_reserved_zero_bit, zero, 0, 0); + } +#undef profile_compatible + } + + u(8, general_level_idc, 0, 255); + + for (i = 0; i < max_num_sub_layers_minus1; i++) { + flag(sub_layer_profile_present_flag[i]); + flag(sub_layer_level_present_flag[i]); + } + + if (max_num_sub_layers_minus1 > 0) { + for (i = max_num_sub_layers_minus1; i < 8; i++) { + av_unused int zero = 0; + xu(2, reserved_zero_2bits, zero, 0, 0); + } + } + + for (i = 0; i < max_num_sub_layers_minus1; i++) { + if (current->sub_layer_profile_present_flag[i]) + return AVERROR_PATCHWELCOME; + if (current->sub_layer_level_present_flag[i]) + return AVERROR_PATCHWELCOME; + } + + return 0; +} + +static int FUNC(sub_layer_hrd_parameters)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawHRDParameters *hrd, + int nal, int sub_layer_id) +{ + H265RawSubLayerHRDParameters *current; + int err, i; + + if (nal) + current = &hrd->nal_sub_layer_hrd_parameters[sub_layer_id]; + else + current = &hrd->vcl_sub_layer_hrd_parameters[sub_layer_id]; + + for (i = 0; i <= hrd->cpb_cnt_minus1[sub_layer_id]; i++) { + ue(bit_rate_value_minus1[i], 0, UINT32_MAX - 1); + ue(cpb_size_value_minus1[i], 0, UINT32_MAX - 1); + if (hrd->sub_pic_hrd_params_present_flag) { + ue(cpb_size_du_value_minus1[i], 0, UINT32_MAX - 1); + ue(bit_rate_du_value_minus1[i], 0, UINT32_MAX - 1); + } + flag(cbr_flag[i]); + } + + return 0; +} + +static int FUNC(hrd_parameters)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawHRDParameters *current, int common_inf_present_flag, + int max_num_sub_layers_minus1) +{ + int err, i; + + if (common_inf_present_flag) { + flag(nal_hrd_parameters_present_flag); + flag(vcl_hrd_parameters_present_flag); + + if (current->nal_hrd_parameters_present_flag || + current->vcl_hrd_parameters_present_flag) { + flag(sub_pic_hrd_params_present_flag); + if (current->sub_pic_hrd_params_present_flag) { + u(8, tick_divisor_minus2, 0, 255); + u(5, du_cpb_removal_delay_increment_length_minus1, 0, 31); + flag(sub_pic_cpb_params_in_pic_timing_sei_flag); + u(5, dpb_output_delay_du_length_minus1, 0, 31); + } + + u(4, bit_rate_scale, 0, 15); + u(4, cpb_size_scale, 0, 15); + if (current->sub_pic_hrd_params_present_flag) + u(4, cpb_size_du_scale, 0, 15); + + u(5, initial_cpb_removal_delay_length_minus1, 0, 31); + u(5, au_cpb_removal_delay_length_minus1, 0, 31); + u(5, dpb_output_delay_length_minus1, 0, 31); + } else { + infer(sub_pic_hrd_params_present_flag, 0); + + infer(initial_cpb_removal_delay_length_minus1, 23); + infer(au_cpb_removal_delay_length_minus1, 23); + infer(dpb_output_delay_length_minus1, 23); + } + } + + for (i = 0; i <= max_num_sub_layers_minus1; i++) { + flag(fixed_pic_rate_general_flag[i]); + + if (!current->fixed_pic_rate_general_flag[i]) + flag(fixed_pic_rate_within_cvs_flag[i]); + else + infer(fixed_pic_rate_within_cvs_flag[i], 1); + + if (current->fixed_pic_rate_within_cvs_flag[i]) { + ue(elemental_duration_in_tc_minus1[i], 0, 2047); + infer(low_delay_hrd_flag[i], 0); + } else + flag(low_delay_hrd_flag[i]); + + if (!current->low_delay_hrd_flag[i]) + ue(cpb_cnt_minus1[i], 0, 31); + else + infer(cpb_cnt_minus1[i], 0); + + if (current->nal_hrd_parameters_present_flag) + CHECK(FUNC(sub_layer_hrd_parameters)(ctx, rw, current, 0, i)); + if (current->vcl_hrd_parameters_present_flag) + CHECK(FUNC(sub_layer_hrd_parameters)(ctx, rw, current, 1, i)); + } + + return 0; +} + +static int FUNC(vui_parameters)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawVUI *current, const H265RawSPS *sps) +{ + int err; + + flag(aspect_ratio_info_present_flag); + if (current->aspect_ratio_info_present_flag) { + u(8, aspect_ratio_idc, 0, 255); + if (current->aspect_ratio_idc == 255) { + u(16, sar_width, 0, 65535); + u(16, sar_height, 0, 65535); + } + } else { + infer(aspect_ratio_idc, 0); + } + + flag(overscan_info_present_flag); + if (current->overscan_info_present_flag) + flag(overscan_appropriate_flag); + + flag(video_signal_type_present_flag); + if (current->video_signal_type_present_flag) { + u(3, video_format, 0, 7); + flag(video_full_range_flag); + flag(colour_description_present_flag); + if (current->colour_description_present_flag) { + u(8, colour_primaries, 0, 255); + u(8, transfer_characteristics, 0, 255); + u(8, matrix_coefficients, 0, 255); + } else { + infer(colour_primaries, 2); + infer(transfer_characteristics, 2); + infer(matrix_coefficients, 2); + } + } else { + infer(video_format, 5); + infer(video_full_range_flag, 0); + infer(colour_primaries, 2); + infer(transfer_characteristics, 2); + infer(matrix_coefficients, 2); + } + + flag(chroma_loc_info_present_flag); + if (current->chroma_loc_info_present_flag) { + ue(chroma_sample_loc_type_top_field, 0, 5); + ue(chroma_sample_loc_type_bottom_field, 0, 5); + } else { + infer(chroma_sample_loc_type_top_field, 0); + infer(chroma_sample_loc_type_bottom_field, 0); + } + + flag(neutral_chroma_indication_flag); + flag(field_seq_flag); + flag(frame_field_info_present_flag); + + flag(default_display_window_flag); + if (current->default_display_window_flag) { + ue(def_disp_win_left_offset, 0, 16384); + ue(def_disp_win_right_offset, 0, 16384); + ue(def_disp_win_top_offset, 0, 16384); + ue(def_disp_win_bottom_offset, 0, 16384); + } + + flag(vui_timing_info_present_flag); + if (current->vui_timing_info_present_flag) { + u(32, vui_num_units_in_tick, 1, UINT32_MAX); + u(32, vui_time_scale, 1, UINT32_MAX); + flag(vui_poc_proportional_to_timing_flag); + if (current->vui_poc_proportional_to_timing_flag) + ue(vui_num_ticks_poc_diff_one_minus1, 0, UINT32_MAX - 1); + + flag(vui_hrd_parameters_present_flag); + if (current->vui_hrd_parameters_present_flag) { + CHECK(FUNC(hrd_parameters)(ctx, rw, ¤t->hrd_parameters, + 1, sps->sps_max_sub_layers_minus1)); + } + } + + flag(bitstream_restriction_flag); + if (current->bitstream_restriction_flag) { + flag(tiles_fixed_structure_flag); + flag(motion_vectors_over_pic_boundaries_flag); + flag(restricted_ref_pic_lists_flag); + ue(min_spatial_segmentation_idc, 0, 4095); + ue(max_bytes_per_pic_denom, 0, 16); + ue(max_bits_per_min_cu_denom, 0, 16); + ue(log2_max_mv_length_horizontal, 0, 16); + ue(log2_max_mv_length_vertical, 0, 16); + } else { + infer(tiles_fixed_structure_flag, 0); + infer(motion_vectors_over_pic_boundaries_flag, 1); + infer(min_spatial_segmentation_idc, 0); + infer(max_bytes_per_pic_denom, 2); + infer(max_bits_per_min_cu_denom, 1); + infer(log2_max_mv_length_horizontal, 15); + infer(log2_max_mv_length_vertical, 15); + } + + return 0; +} + +static int FUNC(vps)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawVPS *current) +{ + int err, i, j; + + HEADER("Video Parameter Set"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, HEVC_NAL_VPS)); + + u(4, vps_video_parameter_set_id, 0, 15); + + flag(vps_base_layer_internal_flag); + flag(vps_base_layer_available_flag); + u(6, vps_max_layers_minus1, 0, HEVC_MAX_LAYERS - 1); + u(3, vps_max_sub_layers_minus1, 0, HEVC_MAX_SUB_LAYERS - 1); + flag(vps_temporal_id_nesting_flag); + + if (current->vps_max_sub_layers_minus1 == 0 && + current->vps_temporal_id_nesting_flag != 1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid stream: " + "vps_temporal_id_nesting_flag must be 1 if " + "vps_max_sub_layers_minus1 is 0.\n"); + return AVERROR_INVALIDDATA; + } + + { + av_unused uint16_t ffff = 0xffff; + xu(16, vps_reserved_0xffff_16bits, ffff, 0xffff, 0xffff); + } + + CHECK(FUNC(profile_tier_level)(ctx, rw, ¤t->profile_tier_level, + 1, current->vps_max_sub_layers_minus1)); + + flag(vps_sub_layer_ordering_info_present_flag); + for (i = (current->vps_sub_layer_ordering_info_present_flag ? + 0 : current->vps_max_sub_layers_minus1); + i <= current->vps_max_sub_layers_minus1; i++) { + ue(vps_max_dec_pic_buffering_minus1[i], 0, HEVC_MAX_DPB_SIZE - 1); + ue(vps_max_num_reorder_pics[i], 0, current->vps_max_dec_pic_buffering_minus1[i]); + ue(vps_max_latency_increase_plus1[i], 0, UINT32_MAX - 1); + } + if (!current->vps_sub_layer_ordering_info_present_flag) { + for (i = 0; i < current->vps_max_sub_layers_minus1; i++) { + infer(vps_max_dec_pic_buffering_minus1[i], + current->vps_max_dec_pic_buffering_minus1[current->vps_max_sub_layers_minus1]); + infer(vps_max_num_reorder_pics[i], + current->vps_max_num_reorder_pics[current->vps_max_sub_layers_minus1]); + infer(vps_max_latency_increase_plus1[i], + current->vps_max_latency_increase_plus1[current->vps_max_sub_layers_minus1]); + } + } + + u(6, vps_max_layer_id, 0, HEVC_MAX_LAYERS - 1); + ue(vps_num_layer_sets_minus1, 0, HEVC_MAX_LAYER_SETS - 1); + for (i = 1; i <= current->vps_num_layer_sets_minus1; i++) { + for (j = 0; j <= current->vps_max_layer_id; j++) + flag(layer_id_included_flag[i][j]); + } + for (j = 0; j <= current->vps_max_layer_id; j++) + infer(layer_id_included_flag[0][j], j == 0); + + flag(vps_timing_info_present_flag); + if (current->vps_timing_info_present_flag) { + u(32, vps_num_units_in_tick, 1, UINT32_MAX); + u(32, vps_time_scale, 1, UINT32_MAX); + flag(vps_poc_proportional_to_timing_flag); + if (current->vps_poc_proportional_to_timing_flag) + ue(vps_num_ticks_poc_diff_one_minus1, 0, UINT32_MAX - 1); + ue(vps_num_hrd_parameters, 0, current->vps_num_layer_sets_minus1 + 1); + for (i = 0; i < current->vps_num_hrd_parameters; i++) { + ue(hrd_layer_set_idx[i], + current->vps_base_layer_internal_flag ? 0 : 1, + current->vps_num_layer_sets_minus1); + if (i > 0) + flag(cprms_present_flag[i]); + else + infer(cprms_present_flag[0], 1); + + CHECK(FUNC(hrd_parameters)(ctx, rw, ¤t->hrd_parameters[i], + current->cprms_present_flag[i], + current->vps_max_sub_layers_minus1)); + } + } + + flag(vps_extension_flag); + if (current->vps_extension_flag) + CHECK(FUNC(extension_data)(ctx, rw, ¤t->extension_data)); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(st_ref_pic_set)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSTRefPicSet *current, int st_rps_idx, + const H265RawSPS *sps) +{ + int err, i, j; + + if (st_rps_idx != 0) + flag(inter_ref_pic_set_prediction_flag); + else + infer(inter_ref_pic_set_prediction_flag, 0); + + if (current->inter_ref_pic_set_prediction_flag) { + unsigned int ref_rps_idx, num_delta_pocs; + const H265RawSTRefPicSet *ref; + int delta_rps, d_poc; + int ref_delta_poc_s0[HEVC_MAX_REFS], ref_delta_poc_s1[HEVC_MAX_REFS]; + int delta_poc_s0[HEVC_MAX_REFS], delta_poc_s1[HEVC_MAX_REFS]; + uint8_t used_by_curr_pic_s0[HEVC_MAX_REFS], + used_by_curr_pic_s1[HEVC_MAX_REFS]; + + if (st_rps_idx == sps->num_short_term_ref_pic_sets) + ue(delta_idx_minus1, 0, st_rps_idx - 1); + else + infer(delta_idx_minus1, 0); + + ref_rps_idx = st_rps_idx - (current->delta_idx_minus1 + 1); + ref = &sps->st_ref_pic_set[ref_rps_idx]; + num_delta_pocs = ref->num_negative_pics + ref->num_positive_pics; + + flag(delta_rps_sign); + ue(abs_delta_rps_minus1, 0, INT16_MAX); + delta_rps = (1 - 2 * current->delta_rps_sign) * + (current->abs_delta_rps_minus1 + 1); + + for (j = 0; j <= num_delta_pocs; j++) { + flag(used_by_curr_pic_flag[j]); + if (!current->used_by_curr_pic_flag[j]) + flag(use_delta_flag[j]); + else + infer(use_delta_flag[j], 1); + } + + // Since the stored form of an RPS here is actually the delta-step + // form used when inter_ref_pic_set_prediction_flag is not set, we + // need to reconstruct that here in order to be able to refer to + // the RPS later (which is required for parsing, because we don't + // even know what syntax elements appear without it). Therefore, + // this code takes the delta-step form of the reference set, turns + // it into the delta-array form, applies the prediction process of + // 7.4.8, converts the result back to the delta-step form, and + // stores that as the current set for future use. Note that the + // inferences here mean that writers using prediction will need + // to fill in the delta-step values correctly as well - since the + // whole RPS prediction process is somewhat overly sophisticated, + // this hopefully forms a useful check for them to ensure their + // predicted form actually matches what was intended rather than + // an onerous additional requirement. + + d_poc = 0; + for (i = 0; i < ref->num_negative_pics; i++) { + d_poc -= ref->delta_poc_s0_minus1[i] + 1; + ref_delta_poc_s0[i] = d_poc; + } + d_poc = 0; + for (i = 0; i < ref->num_positive_pics; i++) { + d_poc += ref->delta_poc_s1_minus1[i] + 1; + ref_delta_poc_s1[i] = d_poc; + } + + i = 0; + for (j = ref->num_positive_pics - 1; j >= 0; j--) { + d_poc = ref_delta_poc_s1[j] + delta_rps; + if (d_poc < 0 && current->use_delta_flag[ref->num_negative_pics + j]) { + delta_poc_s0[i] = d_poc; + used_by_curr_pic_s0[i++] = + current->used_by_curr_pic_flag[ref->num_negative_pics + j]; + } + } + if (delta_rps < 0 && current->use_delta_flag[num_delta_pocs]) { + delta_poc_s0[i] = delta_rps; + used_by_curr_pic_s0[i++] = + current->used_by_curr_pic_flag[num_delta_pocs]; + } + for (j = 0; j < ref->num_negative_pics; j++) { + d_poc = ref_delta_poc_s0[j] + delta_rps; + if (d_poc < 0 && current->use_delta_flag[j]) { + delta_poc_s0[i] = d_poc; + used_by_curr_pic_s0[i++] = current->used_by_curr_pic_flag[j]; + } + } + + infer(num_negative_pics, i); + for (i = 0; i < current->num_negative_pics; i++) { + infer(delta_poc_s0_minus1[i], + -(delta_poc_s0[i] - (i == 0 ? 0 : delta_poc_s0[i - 1])) - 1); + infer(used_by_curr_pic_s0_flag[i], used_by_curr_pic_s0[i]); + } + + i = 0; + for (j = ref->num_negative_pics - 1; j >= 0; j--) { + d_poc = ref_delta_poc_s0[j] + delta_rps; + if (d_poc > 0 && current->use_delta_flag[j]) { + delta_poc_s1[i] = d_poc; + used_by_curr_pic_s1[i++] = current->used_by_curr_pic_flag[j]; + } + } + if (delta_rps > 0 && current->use_delta_flag[num_delta_pocs]) { + delta_poc_s1[i] = delta_rps; + used_by_curr_pic_s1[i++] = + current->used_by_curr_pic_flag[num_delta_pocs]; + } + for (j = 0; j < ref->num_positive_pics; j++) { + d_poc = ref_delta_poc_s1[j] + delta_rps; + if (d_poc > 0 && current->use_delta_flag[ref->num_negative_pics + j]) { + delta_poc_s1[i] = d_poc; + used_by_curr_pic_s1[i++] = + current->used_by_curr_pic_flag[ref->num_negative_pics + j]; + } + } + + infer(num_positive_pics, i); + for (i = 0; i < current->num_positive_pics; i++) { + infer(delta_poc_s1_minus1[i], + delta_poc_s1[i] - (i == 0 ? 0 : delta_poc_s1[i - 1]) - 1); + infer(used_by_curr_pic_s1_flag[i], used_by_curr_pic_s1[i]); + } + + } else { + ue(num_negative_pics, 0, 15); + ue(num_positive_pics, 0, 15 - current->num_negative_pics); + + for (i = 0; i < current->num_negative_pics; i++) { + ue(delta_poc_s0_minus1[i], 0, INT16_MAX); + flag(used_by_curr_pic_s0_flag[i]); + } + + for (i = 0; i < current->num_positive_pics; i++) { + ue(delta_poc_s1_minus1[i], 0, INT16_MAX); + flag(used_by_curr_pic_s1_flag[i]); + } + } + + return 0; +} + +static int FUNC(scaling_list_data)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawScalingList *current) +{ + int sizeId, matrixId; + int err, n, i; + + for (sizeId = 0; sizeId < 4; sizeId++) { + for (matrixId = 0; matrixId < 6; matrixId += (sizeId == 3 ? 3 : 1)) { + flag(scaling_list_pred_mode_flag[sizeId][matrixId]); + if (!current->scaling_list_pred_mode_flag[sizeId][matrixId]) { + ue(scaling_list_pred_matrix_id_delta[sizeId][matrixId], + 0, sizeId == 3 ? matrixId / 3 : matrixId); + } else { + n = FFMIN(64, 1 << (4 + (sizeId << 1))); + if (sizeId > 1) + se(scaling_list_dc_coef_minus8[sizeId - 2][matrixId], -7, +247); + for (i = 0; i < n; i++) { + xse(scaling_list_delta_coeff, + current->scaling_list_delta_coeff[sizeId][matrixId][i], + -128, +127); + } + } + } + } + + return 0; +} + +static int FUNC(sps_range_extension)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSPS *current) +{ + int err; + + flag(transform_skip_rotation_enabled_flag); + flag(transform_skip_context_enabled_flag); + flag(implicit_rdpcm_enabled_flag); + flag(explicit_rdpcm_enabled_flag); + flag(extended_precision_processing_flag); + flag(intra_smoothing_disabled_flag); + flag(high_precision_offsets_enabled_flag); + flag(persistent_rice_adaptation_enabled_flag); + flag(cabac_bypass_alignment_enabled_flag); + + return 0; +} + +static int FUNC(sps_scc_extension)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSPS *current) +{ + int err, comp, i; + + flag(sps_curr_pic_ref_enabled_flag); + + flag(palette_mode_enabled_flag); + if (current->palette_mode_enabled_flag) { + ue(palette_max_size, 0, 64); + ue(delta_palette_max_predictor_size, 0, 128); + + flag(sps_palette_predictor_initializer_present_flag); + if (current->sps_palette_predictor_initializer_present_flag) { + ue(sps_num_palette_predictor_initializer_minus1, 0, 128); + for (comp = 0; comp < (current->chroma_format_idc ? 3 : 1); comp++) { + int bit_depth = comp == 0 ? current->bit_depth_luma_minus8 + 8 + : current->bit_depth_chroma_minus8 + 8; + for (i = 0; i <= current->sps_num_palette_predictor_initializer_minus1; i++) + u(bit_depth, sps_palette_predictor_initializers[comp][i], + 0, MAX_UINT_BITS(bit_depth)); + } + } + } + + u(2, motion_vector_resolution_control_idc, 0, 2); + flag(intra_boundary_filtering_disable_flag); + + return 0; +} + +static int FUNC(sps)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSPS *current) +{ + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawVPS *vps; + int err, i; + unsigned int min_cb_log2_size_y, ctb_log2_size_y, + min_cb_size_y, min_tb_log2_size_y; + + HEADER("Sequence Parameter Set"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, HEVC_NAL_SPS)); + + u(4, sps_video_parameter_set_id, 0, 15); + h265->active_vps = vps = h265->vps[current->sps_video_parameter_set_id]; + + u(3, sps_max_sub_layers_minus1, 0, HEVC_MAX_SUB_LAYERS - 1); + flag(sps_temporal_id_nesting_flag); + if (vps) { + if (vps->vps_max_sub_layers_minus1 > current->sps_max_sub_layers_minus1) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid stream: " + "sps_max_sub_layers_minus1 (%d) must be less than or equal to " + "vps_max_sub_layers_minus1 (%d).\n", + vps->vps_max_sub_layers_minus1, + current->sps_max_sub_layers_minus1); + return AVERROR_INVALIDDATA; + } + if (vps->vps_temporal_id_nesting_flag && + !current->sps_temporal_id_nesting_flag) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid stream: " + "sps_temporal_id_nesting_flag must be 1 if " + "vps_temporal_id_nesting_flag is 1.\n"); + return AVERROR_INVALIDDATA; + } + } + + CHECK(FUNC(profile_tier_level)(ctx, rw, ¤t->profile_tier_level, + 1, current->sps_max_sub_layers_minus1)); + + ue(sps_seq_parameter_set_id, 0, 15); + + ue(chroma_format_idc, 0, 3); + if (current->chroma_format_idc == 3) + flag(separate_colour_plane_flag); + else + infer(separate_colour_plane_flag, 0); + + ue(pic_width_in_luma_samples, 1, HEVC_MAX_WIDTH); + ue(pic_height_in_luma_samples, 1, HEVC_MAX_HEIGHT); + + flag(conformance_window_flag); + if (current->conformance_window_flag) { + ue(conf_win_left_offset, 0, current->pic_width_in_luma_samples); + ue(conf_win_right_offset, 0, current->pic_width_in_luma_samples); + ue(conf_win_top_offset, 0, current->pic_height_in_luma_samples); + ue(conf_win_bottom_offset, 0, current->pic_height_in_luma_samples); + } else { + infer(conf_win_left_offset, 0); + infer(conf_win_right_offset, 0); + infer(conf_win_top_offset, 0); + infer(conf_win_bottom_offset, 0); + } + + ue(bit_depth_luma_minus8, 0, 8); + ue(bit_depth_chroma_minus8, 0, 8); + + ue(log2_max_pic_order_cnt_lsb_minus4, 0, 12); + + flag(sps_sub_layer_ordering_info_present_flag); + for (i = (current->sps_sub_layer_ordering_info_present_flag ? + 0 : current->sps_max_sub_layers_minus1); + i <= current->sps_max_sub_layers_minus1; i++) { + ue(sps_max_dec_pic_buffering_minus1[i], 0, HEVC_MAX_DPB_SIZE - 1); + ue(sps_max_num_reorder_pics[i], 0, current->sps_max_dec_pic_buffering_minus1[i]); + ue(sps_max_latency_increase_plus1[i], 0, UINT32_MAX - 1); + } + if (!current->sps_sub_layer_ordering_info_present_flag) { + for (i = 0; i < current->sps_max_sub_layers_minus1; i++) { + infer(sps_max_dec_pic_buffering_minus1[i], + current->sps_max_dec_pic_buffering_minus1[current->sps_max_sub_layers_minus1]); + infer(sps_max_num_reorder_pics[i], + current->sps_max_num_reorder_pics[current->sps_max_sub_layers_minus1]); + infer(sps_max_latency_increase_plus1[i], + current->sps_max_latency_increase_plus1[current->sps_max_sub_layers_minus1]); + } + } + + ue(log2_min_luma_coding_block_size_minus3, 0, 3); + min_cb_log2_size_y = current->log2_min_luma_coding_block_size_minus3 + 3; + + ue(log2_diff_max_min_luma_coding_block_size, 0, 3); + ctb_log2_size_y = min_cb_log2_size_y + + current->log2_diff_max_min_luma_coding_block_size; + + min_cb_size_y = 1 << min_cb_log2_size_y; + if (current->pic_width_in_luma_samples % min_cb_size_y || + current->pic_height_in_luma_samples % min_cb_size_y) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid dimensions: %ux%u not divisible " + "by MinCbSizeY = %u.\n", current->pic_width_in_luma_samples, + current->pic_height_in_luma_samples, min_cb_size_y); + return AVERROR_INVALIDDATA; + } + + ue(log2_min_luma_transform_block_size_minus2, 0, min_cb_log2_size_y - 3); + min_tb_log2_size_y = current->log2_min_luma_transform_block_size_minus2 + 2; + + ue(log2_diff_max_min_luma_transform_block_size, + 0, FFMIN(ctb_log2_size_y, 5) - min_tb_log2_size_y); + + ue(max_transform_hierarchy_depth_inter, + 0, ctb_log2_size_y - min_tb_log2_size_y); + ue(max_transform_hierarchy_depth_intra, + 0, ctb_log2_size_y - min_tb_log2_size_y); + + flag(scaling_list_enabled_flag); + if (current->scaling_list_enabled_flag) { + flag(sps_scaling_list_data_present_flag); + if (current->sps_scaling_list_data_present_flag) + CHECK(FUNC(scaling_list_data)(ctx, rw, ¤t->scaling_list)); + } else { + infer(sps_scaling_list_data_present_flag, 0); + } + + flag(amp_enabled_flag); + flag(sample_adaptive_offset_enabled_flag); + + flag(pcm_enabled_flag); + if (current->pcm_enabled_flag) { + u(4, pcm_sample_bit_depth_luma_minus1, + 0, current->bit_depth_luma_minus8 + 8 - 1); + u(4, pcm_sample_bit_depth_chroma_minus1, + 0, current->bit_depth_chroma_minus8 + 8 - 1); + + ue(log2_min_pcm_luma_coding_block_size_minus3, + FFMIN(min_cb_log2_size_y, 5) - 3, FFMIN(ctb_log2_size_y, 5) - 3); + ue(log2_diff_max_min_pcm_luma_coding_block_size, + 0, FFMIN(ctb_log2_size_y, 5) - (current->log2_min_pcm_luma_coding_block_size_minus3 + 3)); + + flag(pcm_loop_filter_disabled_flag); + } + + ue(num_short_term_ref_pic_sets, 0, HEVC_MAX_SHORT_TERM_REF_PIC_SETS); + for (i = 0; i < current->num_short_term_ref_pic_sets; i++) + CHECK(FUNC(st_ref_pic_set)(ctx, rw, ¤t->st_ref_pic_set[i], i, current)); + + flag(long_term_ref_pics_present_flag); + if (current->long_term_ref_pics_present_flag) { + ue(num_long_term_ref_pics_sps, 0, HEVC_MAX_LONG_TERM_REF_PICS); + for (i = 0; i < current->num_long_term_ref_pics_sps; i++) { + u(current->log2_max_pic_order_cnt_lsb_minus4 + 4, + lt_ref_pic_poc_lsb_sps[i], + 0, MAX_UINT_BITS(current->log2_max_pic_order_cnt_lsb_minus4 + 4)); + flag(used_by_curr_pic_lt_sps_flag[i]); + } + } + + flag(sps_temporal_mvp_enabled_flag); + flag(strong_intra_smoothing_enabled_flag); + + flag(vui_parameters_present_flag); + if (current->vui_parameters_present_flag) + CHECK(FUNC(vui_parameters)(ctx, rw, ¤t->vui, current)); + + flag(sps_extension_present_flag); + if (current->sps_extension_present_flag) { + flag(sps_range_extension_flag); + flag(sps_multilayer_extension_flag); + flag(sps_3d_extension_flag); + flag(sps_scc_extension_flag); + u(4, sps_extension_4bits, 0, MAX_UINT_BITS(4)); + } + + if (current->sps_range_extension_flag) + CHECK(FUNC(sps_range_extension)(ctx, rw, current)); + if (current->sps_multilayer_extension_flag) + return AVERROR_PATCHWELCOME; + if (current->sps_3d_extension_flag) + return AVERROR_PATCHWELCOME; + if (current->sps_scc_extension_flag) + CHECK(FUNC(sps_scc_extension)(ctx, rw, current)); + if (current->sps_extension_4bits) + CHECK(FUNC(extension_data)(ctx, rw, ¤t->extension_data)); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(pps_range_extension)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawPPS *current) +{ + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawSPS *sps = h265->active_sps; + int err, i; + + if (current->transform_skip_enabled_flag) + ue(log2_max_transform_skip_block_size_minus2, 0, 3); + flag(cross_component_prediction_enabled_flag); + + flag(chroma_qp_offset_list_enabled_flag); + if (current->chroma_qp_offset_list_enabled_flag) { + ue(diff_cu_chroma_qp_offset_depth, + 0, sps->log2_diff_max_min_luma_coding_block_size); + ue(chroma_qp_offset_list_len_minus1, 0, 5); + for (i = 0; i <= current->chroma_qp_offset_list_len_minus1; i++) { + se(cb_qp_offset_list[i], -12, +12); + se(cr_qp_offset_list[i], -12, +12); + } + } + + ue(log2_sao_offset_scale_luma, 0, FFMAX(0, sps->bit_depth_luma_minus8 - 2)); + ue(log2_sao_offset_scale_chroma, 0, FFMAX(0, sps->bit_depth_chroma_minus8 - 2)); + + return 0; +} + +static int FUNC(pps_scc_extension)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawPPS *current) +{ + int err, comp, i; + + flag(pps_curr_pic_ref_enabled_flag); + + flag(residual_adaptive_colour_transform_enabled_flag); + if (current->residual_adaptive_colour_transform_enabled_flag) { + flag(pps_slice_act_qp_offsets_present_flag); + se(pps_act_y_qp_offset_plus5, -7, +17); + se(pps_act_cb_qp_offset_plus5, -7, +17); + se(pps_act_cr_qp_offset_plus3, -9, +15); + } else { + infer(pps_slice_act_qp_offsets_present_flag, 0); + infer(pps_act_y_qp_offset_plus5, 0); + infer(pps_act_cb_qp_offset_plus5, 0); + infer(pps_act_cr_qp_offset_plus3, 0); + } + + flag(pps_palette_predictor_initializer_present_flag); + if (current->pps_palette_predictor_initializer_present_flag) { + ue(pps_num_palette_predictor_initializer, 0, 128); + if (current->pps_num_palette_predictor_initializer > 0) { + flag(monochrome_palette_flag); + ue(luma_bit_depth_entry_minus8, 0, 8); + if (!current->monochrome_palette_flag) + ue(chroma_bit_depth_entry_minus8, 0, 8); + for (comp = 0; comp < (current->monochrome_palette_flag ? 1 : 3); comp++) { + int bit_depth = comp == 0 ? current->luma_bit_depth_entry_minus8 + 8 + : current->chroma_bit_depth_entry_minus8 + 8; + for (i = 0; i < current->pps_num_palette_predictor_initializer; i++) + u(bit_depth, pps_palette_predictor_initializers[comp][i], + 0, MAX_UINT_BITS(bit_depth)); + } + } + } + + return 0; +} + +static int FUNC(pps)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawPPS *current) +{ + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawSPS *sps; + int err, i; + + HEADER("Picture Parameter Set"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, HEVC_NAL_PPS)); + + ue(pps_pic_parameter_set_id, 0, 63); + ue(pps_seq_parameter_set_id, 0, 15); + sps = h265->sps[current->pps_seq_parameter_set_id]; + if (!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "SPS id %d not available.\n", + current->pps_seq_parameter_set_id); + return AVERROR_INVALIDDATA; + } + h265->active_sps = sps; + + flag(dependent_slice_segments_enabled_flag); + flag(output_flag_present_flag); + u(3, num_extra_slice_header_bits, 0, 7); + flag(sign_data_hiding_enabled_flag); + flag(cabac_init_present_flag); + + ue(num_ref_idx_l0_default_active_minus1, 0, 14); + ue(num_ref_idx_l1_default_active_minus1, 0, 14); + + se(init_qp_minus26, -(26 + 6 * sps->bit_depth_luma_minus8), +25); + + flag(constrained_intra_pred_flag); + flag(transform_skip_enabled_flag); + flag(cu_qp_delta_enabled_flag); + if (current->cu_qp_delta_enabled_flag) + ue(diff_cu_qp_delta_depth, + 0, sps->log2_diff_max_min_luma_coding_block_size); + else + infer(diff_cu_qp_delta_depth, 0); + + se(pps_cb_qp_offset, -12, +12); + se(pps_cr_qp_offset, -12, +12); + flag(pps_slice_chroma_qp_offsets_present_flag); + + flag(weighted_pred_flag); + flag(weighted_bipred_flag); + + flag(transquant_bypass_enabled_flag); + flag(tiles_enabled_flag); + flag(entropy_coding_sync_enabled_flag); + + if (current->tiles_enabled_flag) { + ue(num_tile_columns_minus1, 0, HEVC_MAX_TILE_COLUMNS); + ue(num_tile_rows_minus1, 0, HEVC_MAX_TILE_ROWS); + flag(uniform_spacing_flag); + if (!current->uniform_spacing_flag) { + for (i = 0; i < current->num_tile_columns_minus1; i++) + ue(column_width_minus1[i], 0, sps->pic_width_in_luma_samples); + for (i = 0; i < current->num_tile_rows_minus1; i++) + ue(row_height_minus1[i], 0, sps->pic_height_in_luma_samples); + } + flag(loop_filter_across_tiles_enabled_flag); + } else { + infer(num_tile_columns_minus1, 0); + infer(num_tile_rows_minus1, 0); + } + + flag(pps_loop_filter_across_slices_enabled_flag); + flag(deblocking_filter_control_present_flag); + if (current->deblocking_filter_control_present_flag) { + flag(deblocking_filter_override_enabled_flag); + flag(pps_deblocking_filter_disabled_flag); + if (!current->pps_deblocking_filter_disabled_flag) { + se(pps_beta_offset_div2, -6, +6); + se(pps_tc_offset_div2, -6, +6); + } else { + infer(pps_beta_offset_div2, 0); + infer(pps_tc_offset_div2, 0); + } + } else { + infer(deblocking_filter_override_enabled_flag, 0); + infer(pps_deblocking_filter_disabled_flag, 0); + infer(pps_beta_offset_div2, 0); + infer(pps_tc_offset_div2, 0); + } + + flag(pps_scaling_list_data_present_flag); + if (current->pps_scaling_list_data_present_flag) + CHECK(FUNC(scaling_list_data)(ctx, rw, ¤t->scaling_list)); + + flag(lists_modification_present_flag); + + ue(log2_parallel_merge_level_minus2, + 0, (sps->log2_min_luma_coding_block_size_minus3 + 3 + + sps->log2_diff_max_min_luma_coding_block_size - 2)); + + flag(slice_segment_header_extension_present_flag); + + flag(pps_extension_present_flag); + if (current->pps_extension_present_flag) { + flag(pps_range_extension_flag); + flag(pps_multilayer_extension_flag); + flag(pps_3d_extension_flag); + flag(pps_scc_extension_flag); + u(4, pps_extension_4bits, 0, MAX_UINT_BITS(4)); + } + if (current->pps_range_extension_flag) + CHECK(FUNC(pps_range_extension)(ctx, rw, current)); + if (current->pps_multilayer_extension_flag) + return AVERROR_PATCHWELCOME; + if (current->pps_3d_extension_flag) + return AVERROR_PATCHWELCOME; + if (current->pps_scc_extension_flag) + CHECK(FUNC(pps_scc_extension)(ctx, rw, current)); + if (current->pps_extension_4bits) + CHECK(FUNC(extension_data)(ctx, rw, ¤t->extension_data)); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(aud)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawAUD *current) +{ + int err; + + HEADER("Access Unit Delimiter"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, HEVC_NAL_AUD)); + + u(3, pic_type, 0, 2); + + CHECK(FUNC(rbsp_trailing_bits)(ctx, rw)); + + return 0; +} + +static int FUNC(ref_pic_lists_modification)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSliceHeader *current, + unsigned int num_pic_total_curr) +{ + unsigned int entry_size; + int err, i; + + entry_size = av_log2(num_pic_total_curr - 1) + 1; + + flag(ref_pic_list_modification_flag_l0); + if (current->ref_pic_list_modification_flag_l0) { + for (i = 0; i <= current->num_ref_idx_l0_active_minus1; i++) + u(entry_size, list_entry_l0[i], 0, num_pic_total_curr - 1); + } + + if (current->slice_type == HEVC_SLICE_B) { + flag(ref_pic_list_modification_flag_l1); + if (current->ref_pic_list_modification_flag_l1) { + for (i = 0; i <= current->num_ref_idx_l1_active_minus1; i++) + u(entry_size, list_entry_l1[i], 0, num_pic_total_curr - 1); + } + } + + return 0; +} + +static int FUNC(pred_weight_table)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSliceHeader *current) +{ + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawSPS *sps = h265->active_sps; + int err, i, j; + int chroma = !sps->separate_colour_plane_flag && + sps->chroma_format_idc != 0; + + ue(luma_log2_weight_denom, 0, 7); + if (chroma) + se(delta_chroma_log2_weight_denom, -7, 7); + else + infer(delta_chroma_log2_weight_denom, 0); + + for (i = 0; i <= current->num_ref_idx_l0_active_minus1; i++) { + if (1 /* is not same POC and same layer_id */) + flag(luma_weight_l0_flag[i]); + else + infer(luma_weight_l0_flag[i], 0); + } + if (chroma) { + for (i = 0; i <= current->num_ref_idx_l0_active_minus1; i++) { + if (1 /* is not same POC and same layer_id */) + flag(chroma_weight_l0_flag[i]); + else + infer(chroma_weight_l0_flag[i], 0); + } + } + + for (i = 0; i <= current->num_ref_idx_l0_active_minus1; i++) { + if (current->luma_weight_l0_flag[i]) { + se(delta_luma_weight_l0[i], -128, +127); + se(luma_offset_l0[i], + -(1 << (sps->bit_depth_luma_minus8 + 8 - 1)), + ((1 << (sps->bit_depth_luma_minus8 + 8 - 1)) - 1)); + } else { + infer(delta_luma_weight_l0[i], 0); + infer(luma_offset_l0[i], 0); + } + if (current->chroma_weight_l0_flag[i]) { + for (j = 0; j < 2; j++) { + se(delta_chroma_weight_l0[i][j], -128, +127); + se(chroma_offset_l0[i][j], + -(4 << (sps->bit_depth_chroma_minus8 + 8 - 1)), + ((4 << (sps->bit_depth_chroma_minus8 + 8 - 1)) - 1)); + } + } else { + for (j = 0; j < 2; j++) { + infer(delta_chroma_weight_l0[i][j], 0); + infer(chroma_offset_l0[i][j], 0); + } + } + } + + if (current->slice_type == HEVC_SLICE_B) { + for (i = 0; i <= current->num_ref_idx_l1_active_minus1; i++) { + if (1 /* RefPicList1[i] is not CurrPic, nor is it in a different layer */) + flag(luma_weight_l1_flag[i]); + else + infer(luma_weight_l1_flag[i], 0); + } + if (chroma) { + for (i = 0; i <= current->num_ref_idx_l1_active_minus1; i++) { + if (1 /* RefPicList1[i] is not CurrPic, nor is it in a different layer */) + flag(chroma_weight_l1_flag[i]); + else + infer(chroma_weight_l1_flag[i], 0); + } + } + + for (i = 0; i <= current->num_ref_idx_l1_active_minus1; i++) { + if (current->luma_weight_l1_flag[i]) { + se(delta_luma_weight_l1[i], -128, +127); + se(luma_offset_l1[i], + -(1 << (sps->bit_depth_luma_minus8 + 8 - 1)), + ((1 << (sps->bit_depth_luma_minus8 + 8 - 1)) - 1)); + } else { + infer(delta_luma_weight_l1[i], 0); + infer(luma_offset_l1[i], 0); + } + if (current->chroma_weight_l1_flag[i]) { + for (j = 0; j < 2; j++) { + se(delta_chroma_weight_l1[i][j], -128, +127); + se(chroma_offset_l1[i][j], + -(4 << (sps->bit_depth_chroma_minus8 + 8 - 1)), + ((4 << (sps->bit_depth_chroma_minus8 + 8 - 1)) - 1)); + } + } else { + for (j = 0; j < 2; j++) { + infer(delta_chroma_weight_l1[i][j], 0); + infer(chroma_offset_l1[i][j], 0); + } + } + } + } + + return 0; +} + +static int FUNC(slice_segment_header)(CodedBitstreamContext *ctx, RWContext *rw, + H265RawSliceHeader *current) +{ + CodedBitstreamH265Context *h265 = ctx->priv_data; + const H265RawSPS *sps; + const H265RawPPS *pps; + unsigned int min_cb_log2_size_y, ctb_log2_size_y, ctb_size_y; + unsigned int pic_width_in_ctbs_y, pic_height_in_ctbs_y, pic_size_in_ctbs_y; + unsigned int num_pic_total_curr = 0; + int err, i; + + HEADER("Slice Segment Header"); + + CHECK(FUNC(nal_unit_header)(ctx, rw, ¤t->nal_unit_header, -1)); + + flag(first_slice_segment_in_pic_flag); + + if (current->nal_unit_header.nal_unit_type >= HEVC_NAL_BLA_W_LP && + current->nal_unit_header.nal_unit_type <= HEVC_NAL_IRAP_VCL23) + flag(no_output_of_prior_pics_flag); + + ue(slice_pic_parameter_set_id, 0, 63); + + pps = h265->pps[current->slice_pic_parameter_set_id]; + if (!pps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "PPS id %d not available.\n", + current->slice_pic_parameter_set_id); + return AVERROR_INVALIDDATA; + } + h265->active_pps = pps; + + sps = h265->sps[pps->pps_seq_parameter_set_id]; + if (!sps) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "SPS id %d not available.\n", + pps->pps_seq_parameter_set_id); + return AVERROR_INVALIDDATA; + } + h265->active_sps = sps; + + min_cb_log2_size_y = sps->log2_min_luma_coding_block_size_minus3 + 3; + ctb_log2_size_y = min_cb_log2_size_y + sps->log2_diff_max_min_luma_coding_block_size; + ctb_size_y = 1 << ctb_log2_size_y; + pic_width_in_ctbs_y = + (sps->pic_width_in_luma_samples + ctb_size_y - 1) / ctb_size_y; + pic_height_in_ctbs_y = + (sps->pic_height_in_luma_samples + ctb_size_y - 1) / ctb_size_y; + pic_size_in_ctbs_y = pic_width_in_ctbs_y * pic_height_in_ctbs_y; + + if (!current->first_slice_segment_in_pic_flag) { + unsigned int address_size = av_log2(pic_size_in_ctbs_y - 1) + 1; + if (pps->dependent_slice_segments_enabled_flag) + flag(dependent_slice_segment_flag); + else + infer(dependent_slice_segment_flag, 0); + u(address_size, slice_segment_address, 0, pic_size_in_ctbs_y - 1); + } else { + infer(dependent_slice_segment_flag, 0); + } + + if (!current->dependent_slice_segment_flag) { + for (i = 0; i < pps->num_extra_slice_header_bits; i++) + flag(slice_reserved_flag[i]); + + ue(slice_type, 0, 2); + + if (pps->output_flag_present_flag) + flag(pic_output_flag); + + if (sps->separate_colour_plane_flag) + u(2, colour_plane_id, 0, 2); + + if (current->nal_unit_header.nal_unit_type != HEVC_NAL_IDR_W_RADL && + current->nal_unit_header.nal_unit_type != HEVC_NAL_IDR_N_LP) { + const H265RawSTRefPicSet *rps; + + u(sps->log2_max_pic_order_cnt_lsb_minus4 + 4, slice_pic_order_cnt_lsb, + 0, MAX_UINT_BITS(sps->log2_max_pic_order_cnt_lsb_minus4 + 4)); + + flag(short_term_ref_pic_set_sps_flag); + if (!current->short_term_ref_pic_set_sps_flag) { + CHECK(FUNC(st_ref_pic_set)(ctx, rw, ¤t->short_term_ref_pic_set, + sps->num_short_term_ref_pic_sets, sps)); + rps = ¤t->short_term_ref_pic_set; + } else if (sps->num_short_term_ref_pic_sets > 1) { + unsigned int idx_size = av_log2(sps->num_short_term_ref_pic_sets - 1) + 1; + u(idx_size, short_term_ref_pic_set_idx, + 0, sps->num_short_term_ref_pic_sets - 1); + rps = &sps->st_ref_pic_set[current->short_term_ref_pic_set_idx]; + } else { + infer(short_term_ref_pic_set_idx, 0); + rps = &sps->st_ref_pic_set[0]; + } + + num_pic_total_curr = 0; + for (i = 0; i < rps->num_negative_pics; i++) + if (rps->used_by_curr_pic_s0_flag[i]) + ++num_pic_total_curr; + for (i = 0; i < rps->num_positive_pics; i++) + if (rps->used_by_curr_pic_s1_flag[i]) + ++num_pic_total_curr; + + if (sps->long_term_ref_pics_present_flag) { + unsigned int idx_size; + + if (sps->num_long_term_ref_pics_sps > 0) { + ue(num_long_term_sps, 0, sps->num_long_term_ref_pics_sps); + idx_size = av_log2(sps->num_long_term_ref_pics_sps - 1) + 1; + } else { + infer(num_long_term_sps, 0); + idx_size = 0; + } + ue(num_long_term_pics, 0, HEVC_MAX_LONG_TERM_REF_PICS); + + for (i = 0; i < current->num_long_term_sps + + current->num_long_term_pics; i++) { + if (i < current->num_long_term_sps) { + if (sps->num_long_term_ref_pics_sps > 1) + u(idx_size, lt_idx_sps[i], + 0, sps->num_long_term_ref_pics_sps - 1); + if (sps->used_by_curr_pic_lt_sps_flag[current->lt_idx_sps[i]]) + ++num_pic_total_curr; + } else { + u(sps->log2_max_pic_order_cnt_lsb_minus4 + 4, poc_lsb_lt[i], + 0, MAX_UINT_BITS(sps->log2_max_pic_order_cnt_lsb_minus4 + 4)); + flag(used_by_curr_pic_lt_flag[i]); + if (current->used_by_curr_pic_lt_flag[i]) + ++num_pic_total_curr; + } + flag(delta_poc_msb_present_flag[i]); + if (current->delta_poc_msb_present_flag[i]) + ue(delta_poc_msb_cycle_lt[i], 0, UINT32_MAX - 1); + else + infer(delta_poc_msb_cycle_lt[i], 0); + } + } + + if (sps->sps_temporal_mvp_enabled_flag) + flag(slice_temporal_mvp_enabled_flag); + else + infer(slice_temporal_mvp_enabled_flag, 0); + + if (pps->pps_curr_pic_ref_enabled_flag) + ++num_pic_total_curr; + } + + if (sps->sample_adaptive_offset_enabled_flag) { + flag(slice_sao_luma_flag); + if (!sps->separate_colour_plane_flag && sps->chroma_format_idc != 0) + flag(slice_sao_chroma_flag); + else + infer(slice_sao_chroma_flag, 0); + } else { + infer(slice_sao_luma_flag, 0); + infer(slice_sao_chroma_flag, 0); + } + + if (current->slice_type == HEVC_SLICE_P || + current->slice_type == HEVC_SLICE_B) { + flag(num_ref_idx_active_override_flag); + if (current->num_ref_idx_active_override_flag) { + ue(num_ref_idx_l0_active_minus1, 0, 14); + if (current->slice_type == HEVC_SLICE_B) + ue(num_ref_idx_l1_active_minus1, 0, 14); + else + infer(num_ref_idx_l1_active_minus1, pps->num_ref_idx_l1_default_active_minus1); + } else { + infer(num_ref_idx_l0_active_minus1, pps->num_ref_idx_l0_default_active_minus1); + infer(num_ref_idx_l1_active_minus1, pps->num_ref_idx_l1_default_active_minus1); + } + + if (pps->lists_modification_present_flag && num_pic_total_curr > 1) + CHECK(FUNC(ref_pic_lists_modification)(ctx, rw, current, + num_pic_total_curr)); + + if (current->slice_type == HEVC_SLICE_B) + flag(mvd_l1_zero_flag); + if (pps->cabac_init_present_flag) + flag(cabac_init_flag); + else + infer(cabac_init_flag, 0); + if (current->slice_temporal_mvp_enabled_flag) { + if (current->slice_type == HEVC_SLICE_B) + flag(collocated_from_l0_flag); + else + infer(collocated_from_l0_flag, 1); + if (current->collocated_from_l0_flag) { + if (current->num_ref_idx_l0_active_minus1 > 0) + ue(collocated_ref_idx, 0, current->num_ref_idx_l0_active_minus1); + else + infer(collocated_ref_idx, 0); + } else { + if (current->num_ref_idx_l1_active_minus1 > 0) + ue(collocated_ref_idx, 0, current->num_ref_idx_l1_active_minus1); + else + infer(collocated_ref_idx, 0); + } + } + + if ((pps->weighted_pred_flag && current->slice_type == HEVC_SLICE_P) || + (pps->weighted_bipred_flag && current->slice_type == HEVC_SLICE_B)) + CHECK(FUNC(pred_weight_table)(ctx, rw, current)); + + ue(five_minus_max_num_merge_cand, 0, 4); + if (sps->motion_vector_resolution_control_idc == 2) + flag(use_integer_mv_flag); + else + infer(use_integer_mv_flag, sps->motion_vector_resolution_control_idc); + } + + se(slice_qp_delta, + - 6 * sps->bit_depth_luma_minus8 - (pps->init_qp_minus26 + 26), + + 51 - (pps->init_qp_minus26 + 26)); + if (pps->pps_slice_chroma_qp_offsets_present_flag) { + se(slice_cb_qp_offset, -12, +12); + se(slice_cr_qp_offset, -12, +12); + } else { + infer(slice_cb_qp_offset, 0); + infer(slice_cr_qp_offset, 0); + } + if (pps->pps_slice_act_qp_offsets_present_flag) { + se(slice_act_y_qp_offset, + -12 - (pps->pps_act_y_qp_offset_plus5 - 5), + +12 - (pps->pps_act_y_qp_offset_plus5 - 5)); + se(slice_act_cb_qp_offset, + -12 - (pps->pps_act_cb_qp_offset_plus5 - 5), + +12 - (pps->pps_act_cb_qp_offset_plus5 - 5)); + se(slice_act_cr_qp_offset, + -12 - (pps->pps_act_cr_qp_offset_plus3 - 3), + +12 - (pps->pps_act_cr_qp_offset_plus3 - 3)); + } else { + infer(slice_act_y_qp_offset, 0); + infer(slice_act_cb_qp_offset, 0); + infer(slice_act_cr_qp_offset, 0); + } + if (pps->chroma_qp_offset_list_enabled_flag) + flag(cu_chroma_qp_offset_enabled_flag); + else + infer(cu_chroma_qp_offset_enabled_flag, 0); + + if (pps->deblocking_filter_override_enabled_flag) + flag(deblocking_filter_override_flag); + else + infer(deblocking_filter_override_flag, 0); + if (current->deblocking_filter_override_flag) { + flag(slice_deblocking_filter_disabled_flag); + if (!current->slice_deblocking_filter_disabled_flag) { + se(slice_beta_offset_div2, -6, +6); + se(slice_tc_offset_div2, -6, +6); + } else { + infer(slice_beta_offset_div2, pps->pps_beta_offset_div2); + infer(slice_tc_offset_div2, pps->pps_tc_offset_div2); + } + } else { + infer(slice_deblocking_filter_disabled_flag, + pps->pps_deblocking_filter_disabled_flag); + infer(slice_beta_offset_div2, pps->pps_beta_offset_div2); + infer(slice_tc_offset_div2, pps->pps_tc_offset_div2); + } + if (pps->pps_loop_filter_across_slices_enabled_flag && + (current->slice_sao_luma_flag || current->slice_sao_chroma_flag || + !current->slice_deblocking_filter_disabled_flag)) + flag(slice_loop_filter_across_slices_enabled_flag); + else + infer(slice_loop_filter_across_slices_enabled_flag, + pps->pps_loop_filter_across_slices_enabled_flag); + } + + if (pps->tiles_enabled_flag || pps->entropy_coding_sync_enabled_flag) { + unsigned int num_entry_point_offsets_limit; + if (!pps->tiles_enabled_flag && pps->entropy_coding_sync_enabled_flag) + num_entry_point_offsets_limit = pic_height_in_ctbs_y - 1; + else if (pps->tiles_enabled_flag && !pps->entropy_coding_sync_enabled_flag) + num_entry_point_offsets_limit = + (pps->num_tile_columns_minus1 + 1) * (pps->num_tile_rows_minus1 + 1); + else + num_entry_point_offsets_limit = + (pps->num_tile_columns_minus1 + 1) * pic_height_in_ctbs_y - 1; + ue(num_entry_point_offsets, 0, num_entry_point_offsets_limit); + + if (current->num_entry_point_offsets > HEVC_MAX_ENTRY_POINT_OFFSETS) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Too many entry points: " + "%"PRIu16".\n", current->num_entry_point_offsets); + return AVERROR_PATCHWELCOME; + } + + if (current->num_entry_point_offsets > 0) { + ue(offset_len_minus1, 0, 31); + for (i = 0; i < current->num_entry_point_offsets; i++) + u(current->offset_len_minus1 + 1, entry_point_offset_minus1[i], + 0, MAX_UINT_BITS(current->offset_len_minus1 + 1)); + } + } + + if (pps->slice_segment_header_extension_present_flag) { + ue(slice_segment_header_extension_length, 0, 256); + for (i = 0; i < current->slice_segment_header_extension_length; i++) + u(8, slice_segment_header_extension_data_byte[i], 0x00, 0xff); + } + + CHECK(FUNC(byte_alignment)(ctx, rw)); + + return 0; +} diff --git a/libavcodec/cbs_internal.h b/libavcodec/cbs_internal.h new file mode 100644 index 0000000000000..be540e2a44d3d --- /dev/null +++ b/libavcodec/cbs_internal.h @@ -0,0 +1,92 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_CBS_INTERNAL_H +#define AVCODEC_CBS_INTERNAL_H + +#include "avcodec.h" +#include "cbs.h" +#include "get_bits.h" +#include "put_bits.h" + + +typedef struct CodedBitstreamType { + enum AVCodecID codec_id; + + size_t priv_data_size; + + // Split frag->data into coded bitstream units, creating the + // frag->units array. Fill data but not content on each unit. + // The header argument should be set if the fragment came from + // a header block, which may require different parsing for some + // codecs (e.g. the AVCC header in H.264). + int (*split_fragment)(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int header); + + // Read the unit->data bitstream and decompose it, creating + // unit->content. + int (*read_unit)(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit); + + // Write the unit->data bitstream from unit->content. + int (*write_unit)(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit); + + // Read the data from all of frag->units and assemble it into + // a bitstream for the whole fragment. + int (*assemble_fragment)(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag); + + // Free the codec internal state. + void (*close)(CodedBitstreamContext *ctx); +} CodedBitstreamType; + + +// Helper functions for trace output. + +void ff_cbs_trace_header(CodedBitstreamContext *ctx, + const char *name); + +void ff_cbs_trace_syntax_element(CodedBitstreamContext *ctx, + int position, const char *name, + const char *bitstring, int64_t value); + + +// Helper functions for read/write of common bitstream elements, including +// generation of trace output. + +int ff_cbs_read_unsigned(CodedBitstreamContext *ctx, GetBitContext *gbc, + int width, const char *name, uint32_t *write_to, + uint32_t range_min, uint32_t range_max); + +int ff_cbs_write_unsigned(CodedBitstreamContext *ctx, PutBitContext *pbc, + int width, const char *name, uint32_t value, + uint32_t range_min, uint32_t range_max); + +// The largest value representable in N bits, suitable for use as +// range_max in the above functions. +#define MAX_UINT_BITS(length) ((UINT64_C(1) << (length)) - 1) + + +extern const CodedBitstreamType ff_cbs_type_h264; +extern const CodedBitstreamType ff_cbs_type_h265; +extern const CodedBitstreamType ff_cbs_type_mpeg2; + + +#endif /* AVCODEC_CBS_INTERNAL_H */ diff --git a/libavcodec/cbs_mpeg2.c b/libavcodec/cbs_mpeg2.c new file mode 100644 index 0000000000000..bfb64a0851192 --- /dev/null +++ b/libavcodec/cbs_mpeg2.c @@ -0,0 +1,416 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" + +#include "cbs.h" +#include "cbs_internal.h" +#include "cbs_mpeg2.h" +#include "internal.h" + + +#define HEADER(name) do { \ + ff_cbs_trace_header(ctx, name); \ + } while (0) + +#define CHECK(call) do { \ + err = (call); \ + if (err < 0) \ + return err; \ + } while (0) + +#define FUNC_NAME(rw, codec, name) cbs_ ## codec ## _ ## rw ## _ ## name +#define FUNC_MPEG2(rw, name) FUNC_NAME(rw, mpeg2, name) +#define FUNC(name) FUNC_MPEG2(READWRITE, name) + + +#define READ +#define READWRITE read +#define RWContext GetBitContext + +#define xui(width, name, var) do { \ + uint32_t value = 0; \ + CHECK(ff_cbs_read_unsigned(ctx, rw, width, #name, \ + &value, 0, (1 << width) - 1)); \ + var = value; \ + } while (0) + +#define ui(width, name) \ + xui(width, name, current->name) + +#define marker_bit() do { \ + av_unused uint32_t one; \ + CHECK(ff_cbs_read_unsigned(ctx, rw, 1, "marker_bit", &one, 1, 1)); \ + } while (0) + +#define nextbits(width, compare, var) \ + (get_bits_left(rw) >= width && \ + (var = show_bits(rw, width)) == (compare)) + +#include "cbs_mpeg2_syntax_template.c" + +#undef READ +#undef READWRITE +#undef RWContext +#undef xui +#undef ui +#undef marker_bit +#undef nextbits + + +#define WRITE +#define READWRITE write +#define RWContext PutBitContext + +#define xui(width, name, var) do { \ + CHECK(ff_cbs_write_unsigned(ctx, rw, width, #name, \ + var, 0, (1 << width) - 1)); \ + } while (0) + +#define ui(width, name) \ + xui(width, name, current->name) + +#define marker_bit() do { \ + CHECK(ff_cbs_write_unsigned(ctx, rw, 1, "marker_bit", 1, 1, 1)); \ + } while (0) + +#define nextbits(width, compare, var) (var) + +#include "cbs_mpeg2_syntax_template.c" + +#undef READ +#undef READWRITE +#undef RWContext +#undef xui +#undef ui +#undef marker_bit +#undef nextbits + + +static void cbs_mpeg2_free_user_data(void *unit, uint8_t *content) +{ + MPEG2RawUserData *user = (MPEG2RawUserData*)content; + av_buffer_unref(&user->user_data_ref); + av_freep(&content); +} + +static void cbs_mpeg2_free_slice(void *unit, uint8_t *content) +{ + MPEG2RawSlice *slice = (MPEG2RawSlice*)content; + av_buffer_unref(&slice->header.extra_information_ref); + av_buffer_unref(&slice->data_ref); + av_freep(&content); +} + +static int cbs_mpeg2_split_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag, + int header) +{ + const uint8_t *start, *end; + uint8_t *unit_data; + uint32_t start_code = -1, next_start_code = -1; + size_t unit_size; + int err, i, unit_type; + + start = avpriv_find_start_code(frag->data, frag->data + frag->data_size, + &start_code); + for (i = 0;; i++) { + end = avpriv_find_start_code(start, frag->data + frag->data_size, + &next_start_code); + + unit_type = start_code & 0xff; + + // The start and end pointers point at to the byte following the + // start_code_identifier in the start code that they found. + if (end == frag->data + frag->data_size) { + // We didn't find a start code, so this is the final unit. + unit_size = end - (start - 1); + } else { + // Unit runs from start to the beginning of the start code + // pointed to by end (including any padding zeroes). + unit_size = (end - 4) - (start - 1); + } + + unit_data = av_malloc(unit_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!unit_data) + return AVERROR(ENOMEM); + memcpy(unit_data, start - 1, unit_size); + memset(unit_data + unit_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + + err = ff_cbs_insert_unit_data(ctx, frag, i, unit_type, + unit_data, unit_size, NULL); + if (err < 0) { + av_freep(&unit_data); + return err; + } + + if (end == frag->data + frag->data_size) + break; + + start_code = next_start_code; + start = end; + } + + return 0; +} + +static int cbs_mpeg2_read_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + GetBitContext gbc; + int err; + + err = init_get_bits(&gbc, unit->data, 8 * unit->data_size); + if (err < 0) + return err; + + if (MPEG2_START_IS_SLICE(unit->type)) { + MPEG2RawSlice *slice; + int pos, len; + + err = ff_cbs_alloc_unit_content(ctx, unit, sizeof(*slice), + &cbs_mpeg2_free_slice); + if (err < 0) + return err; + slice = unit->content; + + err = cbs_mpeg2_read_slice_header(ctx, &gbc, &slice->header); + if (err < 0) + return err; + + pos = get_bits_count(&gbc); + len = unit->data_size; + + slice->data_size = len - pos / 8; + slice->data_ref = av_buffer_alloc(slice->data_size + + AV_INPUT_BUFFER_PADDING_SIZE); + if (!slice->data_ref) + return AVERROR(ENOMEM); + slice->data = slice->data_ref->data; + + memcpy(slice->data, + unit->data + pos / 8, slice->data_size); + memset(slice->data + slice->data_size, 0, + AV_INPUT_BUFFER_PADDING_SIZE); + slice->data_bit_start = pos % 8; + + } else { + switch (unit->type) { +#define START(start_code, type, read_func, free_func) \ + case start_code: \ + { \ + type *header; \ + err = ff_cbs_alloc_unit_content(ctx, unit, \ + sizeof(*header), free_func); \ + if (err < 0) \ + return err; \ + header = unit->content; \ + err = cbs_mpeg2_read_ ## read_func(ctx, &gbc, header); \ + if (err < 0) \ + return err; \ + } \ + break; + START(0x00, MPEG2RawPictureHeader, picture_header, NULL); + START(0xb2, MPEG2RawUserData, user_data, + &cbs_mpeg2_free_user_data); + START(0xb3, MPEG2RawSequenceHeader, sequence_header, NULL); + START(0xb5, MPEG2RawExtensionData, extension_data, NULL); + START(0xb8, MPEG2RawGroupOfPicturesHeader, + group_of_pictures_header, NULL); +#undef START + default: + av_log(ctx->log_ctx, AV_LOG_ERROR, "Unknown start code %02"PRIx32".\n", + unit->type); + return AVERROR_INVALIDDATA; + } + } + + return 0; +} + +static int cbs_mpeg2_write_header(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) +{ + int err; + + switch (unit->type) { +#define START(start_code, type, func) \ + case start_code: \ + err = cbs_mpeg2_write_ ## func(ctx, pbc, unit->content); \ + break; + START(0x00, MPEG2RawPictureHeader, picture_header); + START(0xb2, MPEG2RawUserData, user_data); + START(0xb3, MPEG2RawSequenceHeader, sequence_header); + START(0xb5, MPEG2RawExtensionData, extension_data); + START(0xb8, MPEG2RawGroupOfPicturesHeader, group_of_pictures_header); +#undef START + default: + av_log(ctx->log_ctx, AV_LOG_ERROR, "Write unimplemented for start " + "code %02"PRIx32".\n", unit->type); + return AVERROR_PATCHWELCOME; + } + + return err; +} + +static int cbs_mpeg2_write_slice(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit, + PutBitContext *pbc) +{ + MPEG2RawSlice *slice = unit->content; + GetBitContext gbc; + size_t bits_left; + int err; + + err = cbs_mpeg2_write_slice_header(ctx, pbc, &slice->header); + if (err < 0) + return err; + + if (slice->data) { + if (slice->data_size * 8 + 8 > put_bits_left(pbc)) + return AVERROR(ENOSPC); + + init_get_bits(&gbc, slice->data, slice->data_size * 8); + skip_bits_long(&gbc, slice->data_bit_start); + + while (get_bits_left(&gbc) > 15) + put_bits(pbc, 16, get_bits(&gbc, 16)); + + bits_left = get_bits_left(&gbc); + put_bits(pbc, bits_left, get_bits(&gbc, bits_left)); + + // Align with zeroes. + while (put_bits_count(pbc) % 8 != 0) + put_bits(pbc, 1, 0); + } + + return 0; +} + +static int cbs_mpeg2_write_unit(CodedBitstreamContext *ctx, + CodedBitstreamUnit *unit) +{ + CodedBitstreamMPEG2Context *priv = ctx->priv_data; + PutBitContext pbc; + int err; + + if (!priv->write_buffer) { + // Initial write buffer size is 1MB. + priv->write_buffer_size = 1024 * 1024; + + reallocate_and_try_again: + err = av_reallocp(&priv->write_buffer, priv->write_buffer_size); + if (err < 0) { + av_log(ctx->log_ctx, AV_LOG_ERROR, "Unable to allocate a " + "sufficiently large write buffer (last attempt " + "%"SIZE_SPECIFIER" bytes).\n", priv->write_buffer_size); + return err; + } + } + + init_put_bits(&pbc, priv->write_buffer, priv->write_buffer_size); + + if (unit->type >= 0x01 && unit->type <= 0xaf) + err = cbs_mpeg2_write_slice(ctx, unit, &pbc); + else + err = cbs_mpeg2_write_header(ctx, unit, &pbc); + + if (err == AVERROR(ENOSPC)) { + // Overflow. + priv->write_buffer_size *= 2; + goto reallocate_and_try_again; + } + if (err < 0) { + // Write failed for some other reason. + return err; + } + + if (put_bits_count(&pbc) % 8) + unit->data_bit_padding = 8 - put_bits_count(&pbc) % 8; + else + unit->data_bit_padding = 0; + + unit->data_size = (put_bits_count(&pbc) + 7) / 8; + flush_put_bits(&pbc); + + err = ff_cbs_alloc_unit_data(ctx, unit, unit->data_size); + if (err < 0) + return err; + + memcpy(unit->data, priv->write_buffer, unit->data_size); + + return 0; +} + +static int cbs_mpeg2_assemble_fragment(CodedBitstreamContext *ctx, + CodedBitstreamFragment *frag) +{ + uint8_t *data; + size_t size, dp, sp; + int i; + + size = 0; + for (i = 0; i < frag->nb_units; i++) + size += 3 + frag->units[i].data_size; + + frag->data_ref = av_buffer_alloc(size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!frag->data_ref) + return AVERROR(ENOMEM); + data = frag->data_ref->data; + + dp = 0; + for (i = 0; i < frag->nb_units; i++) { + CodedBitstreamUnit *unit = &frag->units[i]; + + data[dp++] = 0; + data[dp++] = 0; + data[dp++] = 1; + + for (sp = 0; sp < unit->data_size; sp++) + data[dp++] = unit->data[sp]; + } + + av_assert0(dp == size); + + memset(data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + frag->data = data; + frag->data_size = size; + + return 0; +} + +static void cbs_mpeg2_close(CodedBitstreamContext *ctx) +{ + CodedBitstreamMPEG2Context *priv = ctx->priv_data; + + av_freep(&priv->write_buffer); +} + +const CodedBitstreamType ff_cbs_type_mpeg2 = { + .codec_id = AV_CODEC_ID_MPEG2VIDEO, + + .priv_data_size = sizeof(CodedBitstreamMPEG2Context), + + .split_fragment = &cbs_mpeg2_split_fragment, + .read_unit = &cbs_mpeg2_read_unit, + .write_unit = &cbs_mpeg2_write_unit, + .assemble_fragment = &cbs_mpeg2_assemble_fragment, + + .close = &cbs_mpeg2_close, +}; diff --git a/libavcodec/cbs_mpeg2.h b/libavcodec/cbs_mpeg2.h new file mode 100644 index 0000000000000..92caa99dc1d95 --- /dev/null +++ b/libavcodec/cbs_mpeg2.h @@ -0,0 +1,229 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_CBS_MPEG2_H +#define AVCODEC_CBS_MPEG2_H + +#include +#include + +#include "libavutil/buffer.h" + + +enum { + MPEG2_START_PICTURE = 0x00, + MPEG2_START_SLICE_MIN = 0x01, + MPEG2_START_SLICE_MAX = 0xaf, + MPEG2_START_USER_DATA = 0xb2, + MPEG2_START_SEQUENCE_HEADER = 0xb3, + MPEG2_START_SEQUENCE_ERROR = 0xb4, + MPEG2_START_EXTENSION = 0xb5, + MPEG2_START_SEQUENCE_END = 0xb7, + MPEG2_START_GROUP = 0xb8, +}; + +#define MPEG2_START_IS_SLICE(type) \ + ((type) >= MPEG2_START_SLICE_MIN && \ + (type) <= MPEG2_START_SLICE_MAX) + +enum { + MPEG2_EXTENSION_SEQUENCE = 0x1, + MPEG2_EXTENSION_SEQUENCE_DISPLAY = 0x2, + MPEG2_EXTENSION_QUANT_MATRIX = 0x3, + MPEG2_EXTENSION_COPYRIGHT = 0x4, + MPEG2_EXTENSION_SEQUENCE_SCALABLE = 0x5, + MPEG2_EXTENSION_PICTURE_DISPLAY = 0x7, + MPEG2_EXTENSION_PICTURE_CODING = 0x8, + MPEG2_EXTENSION_PICTURE_SPATIAL_SCALABLE = 0x9, + MPEG2_EXTENSION_PICTURE_TEMPORAL_SCALABLE = 0xa, + MPEG2_EXTENSION_CAMAERA_PARAMETERS = 0xb, + MPEG2_EXTENSION_ITU_T = 0xc, +}; + + +typedef struct MPEG2RawSequenceHeader { + uint8_t sequence_header_code; + + uint16_t horizontal_size_value; + uint16_t vertical_size_value; + uint8_t aspect_ratio_information; + uint8_t frame_rate_code; + uint32_t bit_rate_value; + uint16_t vbv_buffer_size_value; + uint8_t constrained_parameters_flag; + + uint8_t load_intra_quantiser_matrix; + uint8_t intra_quantiser_matrix[64]; + uint8_t load_non_intra_quantiser_matrix; + uint8_t non_intra_quantiser_matrix[64]; +} MPEG2RawSequenceHeader; + +typedef struct MPEG2RawUserData { + uint8_t user_data_start_code; + + uint8_t *user_data; + size_t user_data_length; + AVBufferRef *user_data_ref; +} MPEG2RawUserData; + +typedef struct MPEG2RawSequenceExtension { + uint8_t profile_and_level_indication; + uint8_t progressive_sequence; + uint8_t chroma_format; + uint8_t horizontal_size_extension; + uint8_t vertical_size_extension; + uint16_t bit_rate_extension; + uint8_t vbv_buffer_size_extension; + uint8_t low_delay; + uint8_t frame_rate_extension_n; + uint8_t frame_rate_extension_d; +} MPEG2RawSequenceExtension; + +typedef struct MPEG2RawSequenceDisplayExtension { + uint8_t video_format; + + uint8_t colour_description; + uint8_t colour_primaries; + uint8_t transfer_characteristics; + uint8_t matrix_coefficients; + + uint16_t display_horizontal_size; + uint16_t display_vertical_size; +} MPEG2RawSequenceDisplayExtension; + +typedef struct MPEG2RawGroupOfPicturesHeader { + uint8_t group_start_code; + + uint32_t time_code; + uint8_t closed_gop; + uint8_t broken_link; +} MPEG2RawGroupOfPicturesHeader; + +typedef struct MPEG2RawPictureHeader { + uint8_t picture_start_code; + + uint16_t temporal_reference; + uint8_t picture_coding_type; + uint16_t vbv_delay; + + uint8_t full_pel_forward_vector; + uint8_t forward_f_code; + uint8_t full_pel_backward_vector; + uint8_t backward_f_code; + + uint8_t extra_bit_picture; +} MPEG2RawPictureHeader; + +typedef struct MPEG2RawPictureCodingExtension { + uint8_t f_code[2][2]; + + uint8_t intra_dc_precision; + uint8_t picture_structure; + uint8_t top_field_first; + uint8_t frame_pred_frame_dct; + uint8_t concealment_motion_vectors; + uint8_t q_scale_type; + uint8_t intra_vlc_format; + uint8_t alternate_scan; + uint8_t repeat_first_field; + uint8_t chroma_420_type; + uint8_t progressive_frame; + + uint8_t composite_display_flag; + uint8_t v_axis; + uint8_t field_sequence; + uint8_t sub_carrier; + uint8_t burst_amplitude; + uint8_t sub_carrier_phase; +} MPEG2RawPictureCodingExtension; + +typedef struct MPEG2RawQuantMatrixExtension { + uint8_t load_intra_quantiser_matrix; + uint8_t intra_quantiser_matrix[64]; + uint8_t load_non_intra_quantiser_matrix; + uint8_t non_intra_quantiser_matrix[64]; + uint8_t load_chroma_intra_quantiser_matrix; + uint8_t chroma_intra_quantiser_matrix[64]; + uint8_t load_chroma_non_intra_quantiser_matrix; + uint8_t chroma_non_intra_quantiser_matrix[64]; +} MPEG2RawQuantMatrixExtension; + +typedef struct MPEG2RawPictureDisplayExtension { + uint16_t frame_centre_horizontal_offset[3]; + uint16_t frame_centre_vertical_offset[3]; +} MPEG2RawPictureDisplayExtension; + +typedef struct MPEG2RawExtensionData { + uint8_t extension_start_code; + uint8_t extension_start_code_identifier; + + union { + MPEG2RawSequenceExtension sequence; + MPEG2RawSequenceDisplayExtension sequence_display; + MPEG2RawQuantMatrixExtension quant_matrix; + MPEG2RawPictureCodingExtension picture_coding; + MPEG2RawPictureDisplayExtension picture_display; + } data; +} MPEG2RawExtensionData; + +typedef struct MPEG2RawSliceHeader { + uint8_t slice_vertical_position; + + uint8_t slice_vertical_position_extension; + uint8_t priority_breakpoint; + + uint8_t quantiser_scale_code; + + uint8_t slice_extension_flag; + uint8_t intra_slice; + uint8_t slice_picture_id_enable; + uint8_t slice_picture_id; + + uint8_t extra_bit_slice; + + size_t extra_information_length; + uint8_t *extra_information; + AVBufferRef *extra_information_ref; +} MPEG2RawSliceHeader; + +typedef struct MPEG2RawSlice { + MPEG2RawSliceHeader header; + + uint8_t *data; + size_t data_size; + int data_bit_start; + AVBufferRef *data_ref; +} MPEG2RawSlice; + + +typedef struct CodedBitstreamMPEG2Context { + // Elements stored in headers which are required for other decoding. + uint16_t horizontal_size; + uint16_t vertical_size; + uint8_t scalable; + uint8_t scalable_mode; + uint8_t progressive_sequence; + uint8_t number_of_frame_centre_offsets; + + // Write buffer. + uint8_t *write_buffer; + size_t write_buffer_size; +} CodedBitstreamMPEG2Context; + + +#endif /* AVCODEC_CBS_MPEG2_H */ diff --git a/libavcodec/cbs_mpeg2_syntax_template.c b/libavcodec/cbs_mpeg2_syntax_template.c new file mode 100644 index 0000000000000..51c32cb58d6ba --- /dev/null +++ b/libavcodec/cbs_mpeg2_syntax_template.c @@ -0,0 +1,385 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +static int FUNC(sequence_header)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawSequenceHeader *current) +{ + CodedBitstreamMPEG2Context *mpeg2 = ctx->priv_data; + int err, i; + + HEADER("Sequence Header"); + + ui(8, sequence_header_code); + + ui(12, horizontal_size_value); + ui(12, vertical_size_value); + + mpeg2->horizontal_size = current->horizontal_size_value; + mpeg2->vertical_size = current->vertical_size_value; + + ui(4, aspect_ratio_information); + ui(4, frame_rate_code); + ui(18, bit_rate_value); + + marker_bit(); + + ui(10, vbv_buffer_size_value); + ui(1, constrained_parameters_flag); + + ui(1, load_intra_quantiser_matrix); + if (current->load_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) + ui(8, intra_quantiser_matrix[i]); + } + + ui(1, load_non_intra_quantiser_matrix); + if (current->load_non_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) + ui(8, non_intra_quantiser_matrix[i]); + } + + return 0; +} + +static int FUNC(user_data)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawUserData *current) +{ + size_t k; + int err; + + HEADER("User Data"); + + ui(8, user_data_start_code); + +#ifdef READ + k = get_bits_left(rw); + av_assert0(k % 8 == 0); + current->user_data_length = k /= 8; + if (k > 0) { + current->user_data_ref = av_buffer_alloc(k); + if (!current->user_data_ref) + return AVERROR(ENOMEM); + current->user_data = current->user_data_ref->data; + } +#endif + + for (k = 0; k < current->user_data_length; k++) + xui(8, user_data, current->user_data[k]); + + return 0; +} + +static int FUNC(sequence_extension)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawSequenceExtension *current) +{ + CodedBitstreamMPEG2Context *mpeg2 = ctx->priv_data; + int err; + + HEADER("Sequence Extension"); + + ui(8, profile_and_level_indication); + ui(1, progressive_sequence); + ui(2, chroma_format); + ui(2, horizontal_size_extension); + ui(2, vertical_size_extension); + + mpeg2->horizontal_size = (mpeg2->horizontal_size & 0xfff) | + current->horizontal_size_extension << 12; + mpeg2->vertical_size = (mpeg2->vertical_size & 0xfff) | + current->vertical_size_extension << 12; + mpeg2->progressive_sequence = current->progressive_sequence; + + ui(12, bit_rate_extension); + marker_bit(); + ui(8, vbv_buffer_size_extension); + ui(1, low_delay); + ui(2, frame_rate_extension_n); + ui(5, frame_rate_extension_d); + + return 0; +} + +static int FUNC(sequence_display_extension)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawSequenceDisplayExtension *current) +{ + int err; + + HEADER("Sequence Display Extension"); + + ui(3, video_format); + + ui(1, colour_description); + if (current->colour_description) { + ui(8, colour_primaries); + ui(8, transfer_characteristics); + ui(8, matrix_coefficients); + } + + ui(14, display_horizontal_size); + marker_bit(); + ui(14, display_vertical_size); + + return 0; +} + +static int FUNC(group_of_pictures_header)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawGroupOfPicturesHeader *current) +{ + int err; + + HEADER("Group of Pictures Header"); + + ui(8, group_start_code); + + ui(25, time_code); + ui(1, closed_gop); + ui(1, broken_link); + + return 0; +} + +static int FUNC(picture_header)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawPictureHeader *current) +{ + int err; + + HEADER("Picture Header"); + + ui(8, picture_start_code); + + ui(10, temporal_reference); + ui(3, picture_coding_type); + ui(16, vbv_delay); + + if (current->picture_coding_type == 2 || + current->picture_coding_type == 3) { + ui(1, full_pel_forward_vector); + ui(3, forward_f_code); + } + + if (current->picture_coding_type == 3) { + ui(1, full_pel_backward_vector); + ui(3, backward_f_code); + } + + ui(1, extra_bit_picture); + + return 0; +} + +static int FUNC(picture_coding_extension)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawPictureCodingExtension *current) +{ + CodedBitstreamMPEG2Context *mpeg2 = ctx->priv_data; + int err; + + HEADER("Picture Coding Extension"); + + ui(4, f_code[0][0]); + ui(4, f_code[0][1]); + ui(4, f_code[1][0]); + ui(4, f_code[1][1]); + + ui(2, intra_dc_precision); + ui(2, picture_structure); + ui(1, top_field_first); + ui(1, frame_pred_frame_dct); + ui(1, concealment_motion_vectors); + ui(1, q_scale_type); + ui(1, intra_vlc_format); + ui(1, alternate_scan); + ui(1, repeat_first_field); + ui(1, chroma_420_type); + ui(1, progressive_frame); + + if (mpeg2->progressive_sequence) { + if (current->repeat_first_field) { + if (current->top_field_first) + mpeg2->number_of_frame_centre_offsets = 3; + else + mpeg2->number_of_frame_centre_offsets = 2; + } else { + mpeg2->number_of_frame_centre_offsets = 1; + } + } else { + if (current->picture_structure == 1 || // Top field. + current->picture_structure == 2) { // Bottom field. + mpeg2->number_of_frame_centre_offsets = 1; + } else { + if (current->repeat_first_field) + mpeg2->number_of_frame_centre_offsets = 3; + else + mpeg2->number_of_frame_centre_offsets = 2; + } + } + + ui(1, composite_display_flag); + if (current->composite_display_flag) { + ui(1, v_axis); + ui(3, field_sequence); + ui(1, sub_carrier); + ui(7, burst_amplitude); + ui(8, sub_carrier_phase); + } + + return 0; +} + +static int FUNC(quant_matrix_extension)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawQuantMatrixExtension *current) +{ + int err, i; + + HEADER("Quant Matrix Extension"); + + ui(1, load_intra_quantiser_matrix); + if (current->load_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) + ui(8, intra_quantiser_matrix[i]); + } + + ui(1, load_non_intra_quantiser_matrix); + if (current->load_non_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) + ui(8, non_intra_quantiser_matrix[i]); + } + + ui(1, load_chroma_intra_quantiser_matrix); + if (current->load_chroma_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) + ui(8, intra_quantiser_matrix[i]); + } + + ui(1, load_chroma_non_intra_quantiser_matrix); + if (current->load_chroma_non_intra_quantiser_matrix) { + for (i = 0; i < 64; i++) + ui(8, chroma_non_intra_quantiser_matrix[i]); + } + + return 0; +} + +static int FUNC(picture_display_extension)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawPictureDisplayExtension *current) +{ + CodedBitstreamMPEG2Context *mpeg2 = ctx->priv_data; + int err, i; + + HEADER("Picture Display Extension"); + + for (i = 0; i < mpeg2->number_of_frame_centre_offsets; i++) { + ui(16, frame_centre_horizontal_offset[i]); + marker_bit(); + ui(16, frame_centre_vertical_offset[i]); + marker_bit(); + } + + return 0; +} + +static int FUNC(extension_data)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawExtensionData *current) +{ + int err; + + HEADER("Extension Data"); + + ui(8, extension_start_code); + ui(4, extension_start_code_identifier); + + switch (current->extension_start_code_identifier) { + case 1: + return FUNC(sequence_extension) + (ctx, rw, ¤t->data.sequence); + case 2: + return FUNC(sequence_display_extension) + (ctx, rw, ¤t->data.sequence_display); + case 3: + return FUNC(quant_matrix_extension) + (ctx, rw, ¤t->data.quant_matrix); + case 7: + return FUNC(picture_display_extension) + (ctx, rw, ¤t->data.picture_display); + case 8: + return FUNC(picture_coding_extension) + (ctx, rw, ¤t->data.picture_coding); + default: + av_log(ctx->log_ctx, AV_LOG_ERROR, "Invalid extension ID %d.\n", + current->extension_start_code_identifier); + return AVERROR_INVALIDDATA; + } +} + +static int FUNC(slice_header)(CodedBitstreamContext *ctx, RWContext *rw, + MPEG2RawSliceHeader *current) +{ + CodedBitstreamMPEG2Context *mpeg2 = ctx->priv_data; + int err; + + HEADER("Slice Header"); + + ui(8, slice_vertical_position); + + if (mpeg2->vertical_size > 2800) + ui(3, slice_vertical_position_extension); + if (mpeg2->scalable) { + if (mpeg2->scalable_mode == 0) + ui(7, priority_breakpoint); + } + + ui(5, quantiser_scale_code); + + if (nextbits(1, 1, current->slice_extension_flag)) { + ui(1, slice_extension_flag); + ui(1, intra_slice); + ui(1, slice_picture_id_enable); + ui(6, slice_picture_id); + + { + size_t k; +#ifdef READ + GetBitContext start; + uint8_t bit; + start = *rw; + for (k = 0; nextbits(1, 1, bit); k++) + skip_bits(rw, 8); + current->extra_information_length = k; + if (k > 0) { + *rw = start; + current->extra_information = + av_malloc(current->extra_information_length); + if (!current->extra_information) + return AVERROR(ENOMEM); + for (k = 0; k < current->extra_information_length; k++) { + xui(1, extra_bit_slice, bit); + xui(8, extra_information_slice, + current->extra_information[k]); + } + } +#else + for (k = 0; k < current->extra_information_length; k++) { + xui(1, extra_bit_slice, 1); + xui(8, extra_information_slice, current->extra_information[k]); + } +#endif + } + } + ui(1, extra_bit_slice); + + return 0; +} diff --git a/libavcodec/cfhd.c b/libavcodec/cfhd.c index 5ea8f24821a77..f10742f4fac44 100644 --- a/libavcodec/cfhd.c +++ b/libavcodec/cfhd.c @@ -20,24 +20,42 @@ /** * @file - * CFHD Video Decoder + * Cineform HD video decoder */ +#include "libavutil/attributes.h" #include "libavutil/buffer.h" #include "libavutil/common.h" -#include "libavutil/intreadwrite.h" #include "libavutil/imgutils.h" +#include "libavutil/intreadwrite.h" #include "libavutil/opt.h" #include "avcodec.h" -#include "internal.h" #include "bytestream.h" +#include "get_bits.h" +#include "internal.h" #include "thread.h" #include "cfhd.h" -#define SUBBAND_COUNT 10 +#define ALPHA_COMPAND_DC_OFFSET 256 +#define ALPHA_COMPAND_GAIN 9400 + +enum CFHDParam { + ChannelCount = 12, + SubbandCount = 14, + ImageWidth = 20, + ImageHeight = 21, + LowpassPrecision = 35, + SubbandNumber = 48, + Quantization = 53, + ChannelNumber = 62, + BitsPerComponent = 101, + ChannelWidth = 104, + ChannelHeight = 105, + PrescaleShift = 109, +}; -static av_cold int cfhd_decode_init(AVCodecContext *avctx) +static av_cold int cfhd_init(AVCodecContext *avctx) { CFHDContext *s = avctx->priv_data; @@ -58,9 +76,10 @@ static void init_frame_defaults(CFHDContext *s) { s->coded_width = 0; s->coded_height = 0; + s->cropped_height = 0; s->bpc = 10; s->channel_cnt = 4; - s->subband_cnt = 10; + s->subband_cnt = SUBBAND_COUNT; s->channel_num = 0; s->lowpass_precision = 16; s->quantisation = 1; @@ -74,15 +93,32 @@ static void init_frame_defaults(CFHDContext *s) static inline int dequant_and_decompand(int level, int quantisation) { int64_t abslevel = abs(level); - return (abslevel + ((768 * abslevel * abslevel * abslevel) / (255 * 255 * 255))) * FFSIGN(level) * quantisation; + return (abslevel + ((768 * abslevel * abslevel * abslevel) / (255 * 255 * 255))) * + FFSIGN(level) * quantisation; } -static inline void filter(int16_t *output, ptrdiff_t out_stride, int16_t *low, ptrdiff_t low_stride, - int16_t *high, ptrdiff_t high_stride, int len, uint8_t clip) +static inline void process_alpha(int16_t *alpha, int width) { - int16_t tmp; + int i, channel; + for (i = 0; i < width; i++) { + channel = alpha[i]; + channel -= ALPHA_COMPAND_DC_OFFSET; + channel <<= 3; + channel *= ALPHA_COMPAND_GAIN; + channel >>= 16; + channel = av_clip_uintp2(channel, 12); + alpha[i] = channel; + } +} +static inline void filter(int16_t *output, ptrdiff_t out_stride, + int16_t *low, ptrdiff_t low_stride, + int16_t *high, ptrdiff_t high_stride, + int len, int clip) +{ + int16_t tmp; int i; + for (i = 0; i < len; i++) { if (i == 0) { tmp = (11*low[0*low_stride] - 4*low[1*low_stride] + low[2*low_stride] + 4) >> 3; @@ -118,28 +154,30 @@ static inline void filter(int16_t *output, ptrdiff_t out_stride, int16_t *low, p } } -static void horiz_filter(int16_t *output, int16_t *low, int16_t *high, int width) +static void horiz_filter(int16_t *output, int16_t *low, int16_t *high, + int width) { filter(output, 1, low, 1, high, 1, width, 0); } -static void horiz_filter_clip(int16_t *output, int16_t *low, int16_t *high, int width, uint8_t clip) +static void horiz_filter_clip(int16_t *output, int16_t *low, int16_t *high, + int width, int clip) { filter(output, 1, low, 1, high, 1, width, clip); } -static void vert_filter(int16_t *output, int out_stride, int16_t *low, int low_stride, - int16_t *high, int high_stride, int len) +static void vert_filter(int16_t *output, ptrdiff_t out_stride, + int16_t *low, ptrdiff_t low_stride, + int16_t *high, ptrdiff_t high_stride, int len) { filter(output, out_stride, low, low_stride, high, high_stride, len, 0); } -static void free_buffers(AVCodecContext *avctx) +static void free_buffers(CFHDContext *s) { - CFHDContext *s = avctx->priv_data; int i, j; - for (i = 0; i < 4; i++) { + for (i = 0; i < FF_ARRAY_ELEMS(s->plane); i++) { av_freep(&s->plane[i].idwt_buf); av_freep(&s->plane[i].idwt_tmp); @@ -156,37 +194,44 @@ static void free_buffers(AVCodecContext *avctx) static int alloc_buffers(AVCodecContext *avctx) { CFHDContext *s = avctx->priv_data; - int i, j, k, ret, planes; + int i, j, ret, planes; + int chroma_x_shift, chroma_y_shift; + unsigned k; if ((ret = ff_set_dimensions(avctx, s->coded_width, s->coded_height)) < 0) return ret; avctx->pix_fmt = s->coded_format; - avcodec_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_x_shift, &s->chroma_y_shift); - planes = av_pix_fmt_count_planes(avctx->pix_fmt); + if ((ret = av_pix_fmt_get_chroma_sub_sample(s->coded_format, + &chroma_x_shift, + &chroma_y_shift)) < 0) + return ret; + planes = av_pix_fmt_count_planes(s->coded_format); for (i = 0; i < planes; i++) { - int width = i ? avctx->width >> s->chroma_x_shift : avctx->width; - int height = i ? avctx->height >> s->chroma_y_shift : avctx->height; - int stride = FFALIGN(width / 8, 8) * 8; int w8, h8, w4, h4, w2, h2; - height = FFALIGN(height / 8, 2) * 8; - s->plane[i].width = width; + int width = i ? avctx->width >> chroma_x_shift : avctx->width; + int height = i ? avctx->height >> chroma_y_shift : avctx->height; + ptrdiff_t stride = FFALIGN(width / 8, 8) * 8; + if (chroma_y_shift) + height = FFALIGN(height / 8, 2) * 8; + s->plane[i].width = width; s->plane[i].height = height; s->plane[i].stride = stride; - w8 = FFALIGN(s->plane[i].width / 8, 8); - h8 = FFALIGN(s->plane[i].height / 8, 2); + w8 = FFALIGN(s->plane[i].width / 8, 8); + h8 = height / 8; w4 = w8 * 2; h4 = h8 * 2; w2 = w4 * 2; h2 = h4 * 2; - s->plane[i].idwt_buf = av_mallocz_array(height * stride, sizeof(*s->plane[i].idwt_buf)); - s->plane[i].idwt_tmp = av_malloc_array(height * stride, sizeof(*s->plane[i].idwt_tmp)); - if (!s->plane[i].idwt_buf || !s->plane[i].idwt_tmp) { + s->plane[i].idwt_buf = + av_mallocz_array(height * stride, sizeof(*s->plane[i].idwt_buf)); + s->plane[i].idwt_tmp = + av_malloc_array(height * stride, sizeof(*s->plane[i].idwt_tmp)); + if (!s->plane[i].idwt_buf || !s->plane[i].idwt_tmp) return AVERROR(ENOMEM); - } s->plane[i].subband[0] = s->plane[i].idwt_buf; s->plane[i].subband[1] = s->plane[i].idwt_buf + 2 * w8 * h8; @@ -200,7 +245,7 @@ static int alloc_buffers(AVCodecContext *avctx) s->plane[i].subband[9] = s->plane[i].idwt_buf + 3 * w2 * h2; for (j = 0; j < DWT_LEVELS; j++) { - for(k = 0; k < 4; k++) { + for (k = 0; k < FF_ARRAY_ELEMS(s->plane[i].band[j]); k++) { s->plane[i].band[j][k].a_width = w8 << j; s->plane[i].band[j][k].a_height = h8 << j; } @@ -209,10 +254,10 @@ static int alloc_buffers(AVCodecContext *avctx) /* ll2 and ll1 commented out because they are done in-place */ s->plane[i].l_h[0] = s->plane[i].idwt_tmp; s->plane[i].l_h[1] = s->plane[i].idwt_tmp + 2 * w8 * h8; - //s->plane[i].l_h[2] = ll2; + // s->plane[i].l_h[2] = ll2; s->plane[i].l_h[3] = s->plane[i].idwt_tmp; s->plane[i].l_h[4] = s->plane[i].idwt_tmp + 2 * w4 * h4; - //s->plane[i].l_h[5] = ll1; + // s->plane[i].l_h[5] = ll1; s->plane[i].l_h[6] = s->plane[i].idwt_tmp; s->plane[i].l_h[7] = s->plane[i].idwt_tmp + 2 * w2 * h2; } @@ -250,10 +295,10 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, uint16_t data = bytestream2_get_be16(&gb); if (abs_tag8 >= 0x60 && abs_tag8 <= 0x6f) { av_log(avctx, AV_LOG_DEBUG, "large len %x\n", ((tagu & 0xff) << 16) | data); - } else if (tag == 20) { + } else if (tag == ImageWidth) { av_log(avctx, AV_LOG_DEBUG, "Width %"PRIu16"\n", data); s->coded_width = data; - } else if (tag == 21) { + } else if (tag == ImageHeight) { av_log(avctx, AV_LOG_DEBUG, "Height %"PRIu16"\n", data); s->coded_height = data; } else if (tag == 101) { @@ -264,7 +309,7 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, break; } s->bpc = data; - } else if (tag == 12) { + } else if (tag == ChannelCount) { av_log(avctx, AV_LOG_DEBUG, "Channel Count: %"PRIu16"\n", data); s->channel_cnt = data; if (data > 4) { @@ -272,14 +317,14 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, ret = AVERROR_PATCHWELCOME; break; } - } else if (tag == 14) { + } else if (tag == SubbandCount) { av_log(avctx, AV_LOG_DEBUG, "Subband Count: %"PRIu16"\n", data); if (data != SUBBAND_COUNT) { av_log(avctx, AV_LOG_ERROR, "Subband Count of %"PRIu16" is unsupported\n", data); ret = AVERROR_PATCHWELCOME; break; } - } else if (tag == 62) { + } else if (tag == ChannelNumber) { s->channel_num = data; av_log(avctx, AV_LOG_DEBUG, "Channel number %"PRIu16"\n", data); if (s->channel_num >= planes) { @@ -288,7 +333,7 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, break; } init_plane_defaults(s); - } else if (tag == 48) { + } else if (tag == SubbandNumber) { if (s->subband_num != 0 && data == 1) // hack s->level++; av_log(avctx, AV_LOG_DEBUG, "Subband number %"PRIu16"\n", data); @@ -311,12 +356,12 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, ret = AVERROR(EINVAL); break; } - } else if (tag == 35) + } else if (tag == LowpassPrecision) av_log(avctx, AV_LOG_DEBUG, "Lowpass precision bits: %"PRIu16"\n", data); - else if (tag == 53) { + else if (tag == Quantization) { s->quantisation = data; av_log(avctx, AV_LOG_DEBUG, "Quantisation: %"PRIu16"\n", data); - } else if (tag == 109) { + } else if (tag == PrescaleShift) { s->prescale_shift[0] = (data >> 0) & 0x7; s->prescale_shift[1] = (data >> 3) & 0x7; s->prescale_shift[2] = (data >> 6) & 0x7; @@ -429,6 +474,9 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, break; } planes = av_pix_fmt_count_planes(s->coded_format); + } else if (tag == -85) { + av_log(avctx, AV_LOG_DEBUG, "Cropped height %"PRIu16"\n", data); + s->cropped_height = data; } else av_log(avctx, AV_LOG_DEBUG, "Unknown tag %i data %x\n", tag, data); @@ -437,15 +485,17 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, s->coded_format != AV_PIX_FMT_NONE) { if (s->a_width != s->coded_width || s->a_height != s->coded_height || s->a_format != s->coded_format) { - free_buffers(avctx); + free_buffers(s); if ((ret = alloc_buffers(avctx)) < 0) { - free_buffers(avctx); + free_buffers(s); return ret; } } ret = ff_set_dimensions(avctx, s->coded_width, s->coded_height); if (ret < 0) return ret; + if (s->cropped_height) + avctx->height = s->cropped_height; frame.f->width = frame.f->height = 0; @@ -760,6 +810,8 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, high = s->plane[plane].l_h[7]; for (i = 0; i < lowpass_height * 2; i++) { horiz_filter_clip(dst, low, high, lowpass_width, s->bpc); + if (act_plane == 3) + process_alpha(dst, lowpass_width * 2); low += lowpass_width; high += lowpass_width; dst += pic->linesize[act_plane] / 2; @@ -775,11 +827,11 @@ static int cfhd_decode(AVCodecContext *avctx, void *data, int *got_frame, return avpkt->size; } -static av_cold int cfhd_close_decoder(AVCodecContext *avctx) +static av_cold int cfhd_close(AVCodecContext *avctx) { CFHDContext *s = avctx->priv_data; - free_buffers(avctx); + free_buffers(s); if (!avctx->internal->is_copy) { ff_free_vlc(&s->vlc_9); @@ -790,14 +842,14 @@ static av_cold int cfhd_close_decoder(AVCodecContext *avctx) } AVCodec ff_cfhd_decoder = { - .name = "cfhd", - .long_name = NULL_IF_CONFIG_SMALL("Cineform HD"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_CFHD, - .priv_data_size = sizeof(CFHDContext), - .init = cfhd_decode_init, - .close = cfhd_close_decoder, - .decode = cfhd_decode, - .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS, - .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, + .name = "cfhd", + .long_name = NULL_IF_CONFIG_SMALL("Cineform HD"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_CFHD, + .priv_data_size = sizeof(CFHDContext), + .init = cfhd_init, + .close = cfhd_close, + .decode = cfhd_decode, + .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/cfhd.h b/libavcodec/cfhd.h index 67a0e4c32c5a8..2573e750a6dd8 100644 --- a/libavcodec/cfhd.h +++ b/libavcodec/cfhd.h @@ -27,10 +27,10 @@ #include "avcodec.h" #include "get_bits.h" +#include "vlc.h" -#define VLC_BITS 9 -#define NB_VLC_TABLE_9 (71+3) -#define NB_VLC_TABLE_18 (263+1) +#define VLC_BITS 9 +#define SUBBAND_COUNT 10 typedef struct CFHD_RL_VLC_ELEM { int16_t level; @@ -43,7 +43,7 @@ typedef struct CFHD_RL_VLC_ELEM { typedef struct SubBand { int level; int orientation; - int stride; + ptrdiff_t stride; int a_width; int width; int a_height; @@ -62,7 +62,7 @@ typedef struct Plane { int16_t *idwt_tmp; /* TODO: merge this into SubBand structure */ - int16_t *subband[10]; + int16_t *subband[SUBBAND_COUNT]; int16_t *l_h[8]; SubBand band[DWT_LEVELS][4]; @@ -79,18 +79,16 @@ typedef struct CFHDContext { GetBitContext gb; - int chroma_x_shift; - int chroma_y_shift; - int coded_width; int coded_height; - int coded_format; + int cropped_height; + enum AVPixelFormat coded_format; int a_width; int a_height; int a_format; - int bpc; + int bpc; // bits per channel/component int channel_cnt; int subband_cnt; int channel_num; @@ -106,7 +104,6 @@ typedef struct CFHDContext { uint8_t prescale_shift[3]; Plane plane[4]; - } CFHDContext; int ff_cfhd_init_vlcs(CFHDContext *s); diff --git a/libavcodec/cfhddata.c b/libavcodec/cfhddata.c index 9330d3464550c..5df68d4b3c8f1 100644 --- a/libavcodec/cfhddata.c +++ b/libavcodec/cfhddata.c @@ -18,7 +18,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "stdint.h" +#include + +#include "libavutil/attributes.h" + #include "cfhd.h" /* some special codewords, not sure what they all mean */ @@ -29,6 +32,31 @@ #define TABLE_9_BAND_END3 0x38F0B3Eh #define TABLE_9_BAND_END_LEN3 26 +#define NB_VLC_TABLE_9 (71 + 3) +#define NB_VLC_TABLE_18 (263 + 1) + +static const uint32_t table_9_vlc_bits[NB_VLC_TABLE_9] = { + 0, 0x2, 0xc, 0x1a, + 0x1d, 0x1e, 0x39, 0x3e, + 0x37, 0x7e, 0x6c, 0xe2, + 0xfe, 0xdb, 0xe0, 0x1c3, + 0x1c6, 0x1ff, 0x1fe, 0x1b5, + 0x369, 0x385, 0x71d, 0x6d0, + 0x708, 0x71f, 0xe3d, 0xe39, + 0xe13, 0xe12, 0x1c71, 0x1b45, + 0x1b47, 0x3689, 0x38f2, 0x38e1, + 0x38e0, 0x38f1, 0x3688, 0x6d1b, + 0x71e0, 0x6d19, 0x71e7, 0xe3cd, + 0xda35, 0xda30, 0xe3c3, 0x1b469, + 0x1b462, 0x1c798, 0x1b463, 0x1c799, + 0x38f08, 0x38f09, 0x38f0a, 0x6d1a0, + 0x6d1a3, 0x6d1a1, 0xda345, 0xda344, + 0xe3c2d, 0xe3c2f, 0xe3c2e, 0x38f0b2, + 0x71e160, 0x71e162, 0x71e166, 0x71e161, + 0xe3c2ce, 0xe3c2c6, 0xe3c2c7, 0x1C7859E, + 0x38F0B3F, 0x38F0B3E, +}; + static const uint8_t table_9_vlc_len[NB_VLC_TABLE_9] = { 1, 2, 4, 5, 5, 5, 6, 6, 6, 7, 7, 8, 8, 8, 8, 9, @@ -42,19 +70,6 @@ static const uint8_t table_9_vlc_len[NB_VLC_TABLE_9] = { 26, 26, }; -static const uint32_t table_9_vlc_bits[NB_VLC_TABLE_9] = { - 0, 0x2, 0xc, 0x1a, 0x1d, 0x1e, 0x39, 0x3e, - 0x37, 0x7e, 0x6c, 0xe2, 0xfe, 0xdb, 0xe0, 0x1c3, - 0x1c6, 0x1ff, 0x1fe, 0x1b5, 0x369, 0x385, 0x71d, 0x6d0, - 0x708, 0x71f, 0xe3d, 0xe39, 0xe13, 0xe12, 0x1c71, 0x1b45, - 0x1b47, 0x3689, 0x38f2, 0x38e1, 0x38e0, 0x38f1, 0x3688, 0x6d1b, - 0x71e0, 0x6d19, 0x71e7, 0xe3cd, 0xda35, 0xda30, 0xe3c3, 0x1b469, - 0x1b462, 0x1c798, 0x1b463, 0x1c799, 0x38f08, 0x38f09, 0x38f0a, 0x6d1a0, - 0x6d1a3, 0x6d1a1, 0xda345, 0xda344, 0xe3c2d, 0xe3c2f, 0xe3c2e, 0x38f0b2, - 0x71e160, 0x71e162, 0x71e166, 0x71e161, 0xe3c2ce, 0xe3c2c6, 0xe3c2c7, 0x1C7859E, - 0x38F0B3F, 0x38F0B3E, -}; - static const uint16_t table_9_vlc_run[NB_VLC_TABLE_9] = { 1, 1, 1, 1, 12, 1, 32, 160, 1, 1, 1, 320, 1, 1, 80, 120, @@ -82,39 +97,72 @@ static const uint8_t table_9_vlc_level[NB_VLC_TABLE_9] = { }; static const uint32_t table_18_vlc_bits[NB_VLC_TABLE_18] = { - 0, 0x2, 0x7, 0x19, 0x30, 0x36, 0x6f, 0x63, - 0x69, 0x6b, 0xd1, 0xd4, 0xdc, 0x189, 0x18a, 0x1a0, - 0x1ab, 0x377, 0x310, 0x316, 0x343, 0x354, 0x375, 0x623, - 0x684, 0x685, 0x6ab, 0x6ec, 0xddb, 0xc5c, 0xc5e, 0xc44, - 0xd55, 0xdd1, 0xdd3, 0x1bb5, 0x188b, 0x18bb, 0x18bf, 0x1aa8, - 0x1ba0, 0x1ba5, 0x1ba4, 0x3115, 0x3175, 0x317d, 0x3553, 0x3768, - 0x6e87, 0x6ed3, 0x62e8, 0x62f8, 0x6228, 0x6aa4, 0x6e85, 0xc453, - 0xc5d3, 0xc5f3, 0xdda4, 0xdd08, 0xdd0c, 0x1bb4b, 0x1bb4a, 0x18ba5, - 0x18be5, 0x1aa95, 0x1aa97, 0x188a4, 0x1ba13, 0x31748, 0x317c8, 0x35528, - 0x3552c, 0x37424, 0x37434, 0x37436, 0x62294, 0x62e92, 0x62f92, 0x6aa52, - 0x6aa5a, 0x6e86a, 0x6e86e, 0x6e84a, 0xc452a, 0xc5d27, 0xc5f26, 0xd54a6, - 0xd54b6, 0xdd096, 0xdd0d6, 0xdd0de, 0x188a56, 0x18ba4d, 0x18be4e, 0x18be4f, - 0x1aa96e, 0x1ba12e, 0x1ba12f, 0x1ba1af, 0x1ba1bf, 0x37435d, 0x37437d, 0x317498, - 0x35529c, 0x35529d, 0x3552de, 0x3552df, 0x62e933, 0x62295d, 0x6aa53d, 0x6aa53f, - 0x6aa53e, 0x6e86b9, 0x6e86f8, 0xd54a79, 0xc5d265, 0xc452b8, 0xdd0d71, 0xd54a78, - 0xdd0d70, 0xdd0df2, 0xdd0df3, 0x188a5f6, 0x188a5f5, 0x188a5f4, 0x188a5f3, 0x188a5f2, - 0x188a5f1, 0x188a5f0, 0x188a5ef, 0x188a5ee, 0x188a5ed, 0x188a5aa, 0x188a5e3, 0x188a5df, - 0x188a589, 0x188a5dd, 0x188a578, 0x188a5e0, 0x188a588, 0x188a5d6, 0x188a5db, 0x188a5e1, - 0x188a587, 0x188a59a, 0x188a5c4, 0x188a5ec, 0x188a586, 0x188a573, 0x188a59c, 0x188a5c8, - 0x188a5fb, 0x188a5a1, 0x188a5eb, 0x188a5a8, 0x188a584, 0x188a5d2, 0x188a599, 0x188a598, - 0x188a583, 0x18ba4c9, 0x188a5d0, 0x188a594, 0x188a582, 0x188a5cb, 0x188a5d8, 0x188a5e7, - 0x188a581, 0x188a5ea, 0x188a5a9, 0x188a5a6, 0x188a580, 0x188a5a0, 0x188a59d, 0x188a5c3, - 0x188a57f, 0x188a5c0, 0x188a5de, 0x188a5d4, 0x188a57e, 0x188a5c2, 0x188a592, 0x188a5cd, - 0x188a57d, 0x188a5a3, 0x188a5e8, 0x188a5a2, 0x188a57c, 0x188a58e, 0x188a5b3, 0x188a5b2, - 0x188a5b1, 0x188a5b0, 0x188a5af, 0x188a5ae, 0x188a5ad, 0x188a5ac, 0x188a5ab, 0x188a5da, - 0x188a5e4, 0x188a5e5, 0x188a5d9, 0x188a5b5, 0x188a5bc, 0x188a5bd, 0x188a5e9, 0x188a5cc, - 0x188a585, 0x188a5d3, 0x188a5e2, 0x188a595, 0x188a596, 0x188a5b8, 0x188a590, 0x188a5c9, - 0x188a5a4, 0x188a5e6, 0x188a5a5, 0x188a5ce, 0x188a5bf, 0x188a572, 0x188a59b, 0x188a5be, - 0x188a5c7, 0x188a5ca, 0x188a5d5, 0x188a57b, 0x188a58d, 0x188a58c, 0x188a58b, 0x188a58a, - 0x18ba4c8, 0x188a5c5, 0x188a5fa, 0x188a5bb, 0x188a5c1, 0x188a5cf, 0x188a5b9, 0x188a5b6, - 0x188a597, 0x188a5fe, 0x188a5d7, 0x188a5ba, 0x188a591, 0x188a5c6, 0x188a5dc, 0x188a57a, - 0x188a59f, 0x188a5f9, 0x188a5b4, 0x188a5a7, 0x188a58f, 0x188a5fd, 0x188a5b7, 0x188a593, - 0x188a59e, 0x188a5f8, 0x188a5ff, 0x188a5fc, 0x188a579, 0x188a5f7, 0x3114ba2, 0x3114ba3, + 0, 0x2, 0x7, 0x19, + 0x30, 0x36, 0x6f, 0x63, + 0x69, 0x6b, 0xd1, 0xd4, + 0xdc, 0x189, 0x18a, 0x1a0, + 0x1ab, 0x377, 0x310, 0x316, + 0x343, 0x354, 0x375, 0x623, + 0x684, 0x685, 0x6ab, 0x6ec, + 0xddb, 0xc5c, 0xc5e, 0xc44, + 0xd55, 0xdd1, 0xdd3, 0x1bb5, + 0x188b, 0x18bb, 0x18bf, 0x1aa8, + 0x1ba0, 0x1ba5, 0x1ba4, 0x3115, + 0x3175, 0x317d, 0x3553, 0x3768, + 0x6e87, 0x6ed3, 0x62e8, 0x62f8, + 0x6228, 0x6aa4, 0x6e85, 0xc453, + 0xc5d3, 0xc5f3, 0xdda4, 0xdd08, + 0xdd0c, 0x1bb4b, 0x1bb4a, 0x18ba5, + 0x18be5, 0x1aa95, 0x1aa97, 0x188a4, + 0x1ba13, 0x31748, 0x317c8, 0x35528, + 0x3552c, 0x37424, 0x37434, 0x37436, + 0x62294, 0x62e92, 0x62f92, 0x6aa52, + 0x6aa5a, 0x6e86a, 0x6e86e, 0x6e84a, + 0xc452a, 0xc5d27, 0xc5f26, 0xd54a6, + 0xd54b6, 0xdd096, 0xdd0d6, 0xdd0de, + 0x188a56, 0x18ba4d, 0x18be4e, 0x18be4f, + 0x1aa96e, 0x1ba12e, 0x1ba12f, 0x1ba1af, + 0x1ba1bf, 0x37435d, 0x37437d, 0x317498, + 0x35529c, 0x35529d, 0x3552de, 0x3552df, + 0x62e933, 0x62295d, 0x6aa53d, 0x6aa53f, + 0x6aa53e, 0x6e86b9, 0x6e86f8, 0xd54a79, + 0xc5d265, 0xc452b8, 0xdd0d71, 0xd54a78, + 0xdd0d70, 0xdd0df2, 0xdd0df3, 0x188a5f6, + 0x188a5f5, 0x188a5f4, 0x188a5f3, 0x188a5f2, + 0x188a5f1, 0x188a5f0, 0x188a5ef, 0x188a5ee, + 0x188a5ed, 0x188a5aa, 0x188a5e3, 0x188a5df, + 0x188a589, 0x188a5dd, 0x188a578, 0x188a5e0, + 0x188a588, 0x188a5d6, 0x188a5db, 0x188a5e1, + 0x188a587, 0x188a59a, 0x188a5c4, 0x188a5ec, + 0x188a586, 0x188a573, 0x188a59c, 0x188a5c8, + 0x188a5fb, 0x188a5a1, 0x188a5eb, 0x188a5a8, + 0x188a584, 0x188a5d2, 0x188a599, 0x188a598, + 0x188a583, 0x18ba4c9, 0x188a5d0, 0x188a594, + 0x188a582, 0x188a5cb, 0x188a5d8, 0x188a5e7, + 0x188a581, 0x188a5ea, 0x188a5a9, 0x188a5a6, + 0x188a580, 0x188a5a0, 0x188a59d, 0x188a5c3, + 0x188a57f, 0x188a5c0, 0x188a5de, 0x188a5d4, + 0x188a57e, 0x188a5c2, 0x188a592, 0x188a5cd, + 0x188a57d, 0x188a5a3, 0x188a5e8, 0x188a5a2, + 0x188a57c, 0x188a58e, 0x188a5b3, 0x188a5b2, + 0x188a5b1, 0x188a5b0, 0x188a5af, 0x188a5ae, + 0x188a5ad, 0x188a5ac, 0x188a5ab, 0x188a5da, + 0x188a5e4, 0x188a5e5, 0x188a5d9, 0x188a5b5, + 0x188a5bc, 0x188a5bd, 0x188a5e9, 0x188a5cc, + 0x188a585, 0x188a5d3, 0x188a5e2, 0x188a595, + 0x188a596, 0x188a5b8, 0x188a590, 0x188a5c9, + 0x188a5a4, 0x188a5e6, 0x188a5a5, 0x188a5ce, + 0x188a5bf, 0x188a572, 0x188a59b, 0x188a5be, + 0x188a5c7, 0x188a5ca, 0x188a5d5, 0x188a57b, + 0x188a58d, 0x188a58c, 0x188a58b, 0x188a58a, + 0x18ba4c8, 0x188a5c5, 0x188a5fa, 0x188a5bb, + 0x188a5c1, 0x188a5cf, 0x188a5b9, 0x188a5b6, + 0x188a597, 0x188a5fe, 0x188a5d7, 0x188a5ba, + 0x188a591, 0x188a5c6, 0x188a5dc, 0x188a57a, + 0x188a59f, 0x188a5f9, 0x188a5b4, 0x188a5a7, + 0x188a58f, 0x188a5fd, 0x188a5b7, 0x188a593, + 0x188a59e, 0x188a5f8, 0x188a5ff, 0x188a5fc, + 0x188a579, 0x188a5f7, 0x3114ba2, 0x3114ba3, }; static const uint8_t table_18_vlc_len[NB_VLC_TABLE_18] = { @@ -154,39 +202,39 @@ static const uint8_t table_18_vlc_len[NB_VLC_TABLE_18] = { }; static const uint16_t table_18_vlc_run[NB_VLC_TABLE_18] = { - 1, 1, 1, 1, 1, 1, 1, 1, - 12, 1, 20, 1, 1, 1, 32, 1, - 1, 1, 1, 1, 60, 1, 1, 1, - 1, 100, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 180, 1, - 1, 320, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 2, + 1, 1, 1, 1, 1, 1, 1, 1, + 12, 1, 20, 1, 1, 1, 32, 1, + 1, 1, 1, 1, 60, 1, 1, 1, + 1, 100, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 180, 1, + 1, 320, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 2, }; static const uint8_t table_18_vlc_level[NB_VLC_TABLE_18] = { diff --git a/libavcodec/chomp_bsf.c b/libavcodec/chomp_bsf.c index cc94380535a46..3ba45f3e06dff 100644 --- a/libavcodec/chomp_bsf.c +++ b/libavcodec/chomp_bsf.c @@ -23,20 +23,16 @@ #include "bsf.h" #include "internal.h" -static int chomp_filter(AVBSFContext *ctx, AVPacket *out) +static int chomp_filter(AVBSFContext *ctx, AVPacket *pkt) { - AVPacket *in; int ret; - ret = ff_bsf_get_packet(ctx, &in); + ret = ff_bsf_get_packet_ref(ctx, pkt); if (ret < 0) return ret; - while (in->size > 0 && !in->data[in->size - 1]) - in->size--; - - av_packet_move_ref(out, in); - av_packet_free(&in); + while (pkt->size > 0 && !pkt->data[pkt->size - 1]) + pkt->size--; return 0; } diff --git a/libavcodec/cinepak.c b/libavcodec/cinepak.c index 89e940ae0dfbd..9b0077402f063 100644 --- a/libavcodec/cinepak.c +++ b/libavcodec/cinepak.c @@ -315,14 +315,11 @@ static int cinepak_decode_strip (CinepakContext *s, return AVERROR_INVALIDDATA; } -static int cinepak_decode (CinepakContext *s) +static int cinepak_predecode_check (CinepakContext *s) { - const uint8_t *eod = (s->data + s->size); - int i, result, strip_size, frame_flags, num_strips; - int y0 = 0; + int num_strips; int encoded_buf_size; - frame_flags = s->data[0]; num_strips = AV_RB16 (&s->data[8]); encoded_buf_size = AV_RB24(&s->data[1]); @@ -353,6 +350,21 @@ static int cinepak_decode (CinepakContext *s) s->sega_film_skip_bytes = 0; } + if (s->size < 10 + s->sega_film_skip_bytes + num_strips * 12) + return AVERROR_INVALIDDATA; + + return 0; +} + +static int cinepak_decode (CinepakContext *s) +{ + const uint8_t *eod = (s->data + s->size); + int i, result, strip_size, frame_flags, num_strips; + int y0 = 0; + + frame_flags = s->data[0]; + num_strips = AV_RB16 (&s->data[8]); + s->data += 10 + s->sega_film_skip_bytes; num_strips = FFMIN(num_strips, MAX_STRIPS); @@ -432,6 +444,7 @@ static int cinepak_decode_frame(AVCodecContext *avctx, const uint8_t *buf = avpkt->data; int ret = 0, buf_size = avpkt->size; CinepakContext *s = avctx->priv_data; + int num_strips; s->data = buf; s->size = buf_size; @@ -439,6 +452,17 @@ static int cinepak_decode_frame(AVCodecContext *avctx, if (s->size < 10) return AVERROR_INVALIDDATA; + num_strips = AV_RB16 (&s->data[8]); + + //Empty frame, do not waste time + if (!num_strips && (!s->palette_video || !av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, NULL))) + return buf_size; + + if ((ret = cinepak_predecode_check(s)) < 0) { + av_log(avctx, AV_LOG_ERROR, "cinepak_predecode_check failed\n"); + return ret; + } + if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) return ret; diff --git a/libavcodec/cinepakenc.c b/libavcodec/cinepakenc.c index a28f6690708f6..93917fafe89c6 100644 --- a/libavcodec/cinepakenc.c +++ b/libavcodec/cinepakenc.c @@ -4,90 +4,61 @@ * * Fixes and improvements, vintage decoders compatibility * (c) 2013, 2014 Rl, Aetey Global Technologies AB + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ -Permission is hereby granted, free of charge, to any person obtaining a -copy of this software and associated documentation files (the "Software"), -to deal in the Software without restriction, including without limitation -the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included -in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. - +/* + * TODO: + * - optimize: color space conversion (move conversion to libswscale), ... * MAYBE: * - "optimally" split the frame into several non-regular areas * using a separate codebook pair for each area and approximating * the area by several rectangular strips (generally not full width ones) * (use quadtree splitting? a simple fixed-granularity grid?) - * - * - * version 2014-01-23 Rl - * - added option handling for flexibility - * - * version 2014-01-21 Rl - * - believe it or not, now we get even smaller files, with better quality - * (which means I missed an optimization earlier :) - * - * version 2014-01-20 Rl - * - made the encoder compatible with vintage decoders - * and added some yet unused code for possible future - * incremental codebook updates - * - fixed a small memory leak - * - * version 2013-04-28 Rl - * - bugfixed codebook optimization logic - * - * version 2013-02-14 Rl - * "Valentine's Day" version: - * - made strip division more robust - * - minimized bruteforcing the number of strips, - * (costs some R/D but speeds up compession a lot), the heuristic - * assumption is that score as a function of the number of strips has - * one wide minimum which moves slowly, of course not fully true - * - simplified codebook generation, - * the old code was meant for other optimizations than we actually do - * - optimized the codebook generation / error estimation for MODE_MC - * - * version 2013-02-12 Rl - * - separated codebook training sets, avoided the transfer of wasted bytes, - * which yields both better quality and smaller files - * - now using the correct colorspace (TODO: move conversion to libswscale) - * - * version 2013-02-08 Rl - * - fixes/optimization in multistrip encoding and codebook size choice, - * quality/bitrate is now better than that of the binary proprietary encoder */ +#include + +#include "libavutil/avassert.h" +#include "libavutil/common.h" +#include "libavutil/internal.h" #include "libavutil/intreadwrite.h" -#include "avcodec.h" #include "libavutil/lfg.h" +#include "libavutil/opt.h" + +#include "avcodec.h" #include "elbg.h" #include "internal.h" -#include "libavutil/avassert.h" -#include "libavutil/opt.h" - #define CVID_HEADER_SIZE 10 #define STRIP_HEADER_SIZE 12 #define CHUNK_HEADER_SIZE 4 #define MB_SIZE 4 //4x4 MBs -#define MB_AREA (MB_SIZE*MB_SIZE) +#define MB_AREA (MB_SIZE * MB_SIZE) -#define VECTOR_MAX 6 //six or four entries per vector depending on format -#define CODEBOOK_MAX 256 //size of a codebook +#define VECTOR_MAX 6 // six or four entries per vector depending on format +#define CODEBOOK_MAX 256 // size of a codebook -#define MAX_STRIPS 32 //Note: having fewer choices regarding the number of strips speeds up encoding (obviously) -#define MIN_STRIPS 1 //Note: having more strips speeds up encoding the frame (this is less obvious) +#define MAX_STRIPS 32 // Note: having fewer choices regarding the number of strips speeds up encoding (obviously) +#define MIN_STRIPS 1 // Note: having more strips speeds up encoding the frame (this is less obvious) // MAX_STRIPS limits the maximum quality you can reach // when you want high quality on high resolutions, // MIN_STRIPS limits the minimum efficiently encodable bit rate @@ -97,7 +68,7 @@ OTHER DEALINGS IN THE SOFTWARE. // NOTE the decoder in ffmpeg has its own arbitrary limitation on the number // of strips, currently 32 -typedef enum { +typedef enum CinepakMode { MODE_V1_ONLY = 0, MODE_V1_V4, MODE_MC, @@ -105,7 +76,7 @@ typedef enum { MODE_COUNT, } CinepakMode; -typedef enum { +typedef enum mb_encoding { ENC_V1, ENC_V4, ENC_SKIP, @@ -113,24 +84,24 @@ typedef enum { ENC_UNCERTAIN } mb_encoding; -typedef struct { - int v1_vector; //index into v1 codebook - int v1_error; //error when using V1 encoding - int v4_vector[4]; //indices into v4 codebook - int v4_error; //error when using V4 encoding - int skip_error; //error when block is skipped (aka copied from last frame) - mb_encoding best_encoding; //last result from calculate_mode_score() +typedef struct mb_info { + int v1_vector; // index into v1 codebook + int v1_error; // error when using V1 encoding + int v4_vector[4]; // indices into v4 codebook + int v4_error; // error when using V4 encoding + int skip_error; // error when block is skipped (aka copied from last frame) + mb_encoding best_encoding; // last result from calculate_mode_score() } mb_info; -typedef struct { - int v1_codebook[CODEBOOK_MAX*VECTOR_MAX]; - int v4_codebook[CODEBOOK_MAX*VECTOR_MAX]; +typedef struct strip_info { + int v1_codebook[CODEBOOK_MAX * VECTOR_MAX]; + int v4_codebook[CODEBOOK_MAX * VECTOR_MAX]; int v1_size; int v4_size; CinepakMode mode; } strip_info; -typedef struct { +typedef struct CinepakEncContext { const AVClass *class; AVCodecContext *avctx; unsigned char *pict_bufs[4], *strip_buf, *frame_buf; @@ -146,15 +117,10 @@ typedef struct { uint64_t lambda; int *codebook_input; int *codebook_closest; - mb_info *mb; //MB RD state - int min_strips; //the current limit - int max_strips; //the current limit -#ifdef CINEPAKENC_DEBUG - mb_info *best_mb; //TODO: remove. only used for printing stats - int num_v1_mode, num_v4_mode, num_mc_mode; - int num_v1_encs, num_v4_encs, num_skips; -#endif -// options + mb_info *mb; // MB RD state + int min_strips; // the current limit + int max_strips; // the current limit + // options int max_extra_cb_iterations; int skip_empty_cb; int min_min_strips; @@ -165,11 +131,16 @@ typedef struct { #define OFFSET(x) offsetof(CinepakEncContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { "max_extra_cb_iterations", "Max extra codebook recalculation passes, more is better and slower", OFFSET(max_extra_cb_iterations), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, INT_MAX, VE }, - { "skip_empty_cb", "Avoid wasting bytes, ignore vintage MacOS decoder", OFFSET(skip_empty_cb), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "max_strips", "Limit strips/frame, vintage compatible is 1..3, otherwise the more the better", OFFSET(max_max_strips), AV_OPT_TYPE_INT, { .i64 = 3 }, MIN_STRIPS, MAX_STRIPS, VE }, - { "min_strips", "Enforce min strips/frame, more is worse and faster, must be <= max_strips", OFFSET(min_min_strips), AV_OPT_TYPE_INT, { .i64 = MIN_STRIPS }, MIN_STRIPS, MAX_STRIPS, VE }, - { "strip_number_adaptivity", "How fast the strip number adapts, more is slightly better, much slower", OFFSET(strip_number_delta_range), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, MAX_STRIPS-MIN_STRIPS, VE }, + { "max_extra_cb_iterations", "Max extra codebook recalculation passes, more is better and slower", + OFFSET(max_extra_cb_iterations), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, INT_MAX, VE }, + { "skip_empty_cb", "Avoid wasting bytes, ignore vintage MacOS decoder", + OFFSET(skip_empty_cb), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + { "max_strips", "Limit strips/frame, vintage compatible is 1..3, otherwise the more the better", + OFFSET(max_max_strips), AV_OPT_TYPE_INT, { .i64 = 3 }, MIN_STRIPS, MAX_STRIPS, VE }, + { "min_strips", "Enforce min strips/frame, more is worse and faster, must be <= max_strips", + OFFSET(min_min_strips), AV_OPT_TYPE_INT, { .i64 = MIN_STRIPS }, MIN_STRIPS, MAX_STRIPS, VE }, + { "strip_number_adaptivity", "How fast the strip number adapts, more is slightly better, much slower", + OFFSET(strip_number_delta_range), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, MAX_STRIPS - MIN_STRIPS, VE }, { NULL }, }; @@ -187,13 +158,13 @@ static av_cold int cinepak_encode_init(AVCodecContext *avctx) if (avctx->width & 3 || avctx->height & 3) { av_log(avctx, AV_LOG_ERROR, "width and height must be multiples of four (got %ix%i)\n", - avctx->width, avctx->height); + avctx->width, avctx->height); return AVERROR(EINVAL); } if (s->min_min_strips > s->max_max_strips) { - av_log(avctx, AV_LOG_ERROR, "minimal number of strips can not exceed maximal (got %i and %i)\n", - s->min_min_strips, s->max_max_strips); + av_log(avctx, AV_LOG_ERROR, "minimum number of strips must not exceed maximum (got %i and %i)\n", + s->min_min_strips, s->max_max_strips); return AVERROR(EINVAL); } @@ -207,23 +178,23 @@ static av_cold int cinepak_encode_init(AVCodecContext *avctx) if (!(s->input_frame = av_frame_alloc())) goto enomem; - if (!(s->codebook_input = av_malloc(sizeof(int) * (avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4) * (avctx->width * avctx->height) >> 2))) + if (!(s->codebook_input = av_malloc_array((avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4) * (avctx->width * avctx->height) >> 2, sizeof(*s->codebook_input)))) goto enomem; - if (!(s->codebook_closest = av_malloc(sizeof(int) * (avctx->width * avctx->height) >> 2))) + if (!(s->codebook_closest = av_malloc_array((avctx->width * avctx->height) >> 2, sizeof(*s->codebook_closest)))) goto enomem; - for(x = 0; x < (avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 4 : 3); x++) - if(!(s->pict_bufs[x] = av_malloc((avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4) * (avctx->width * avctx->height) >> 2))) + for (x = 0; x < (avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 4 : 3); x++) + if (!(s->pict_bufs[x] = av_malloc((avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4) * (avctx->width * avctx->height) >> 2))) goto enomem; mb_count = avctx->width * avctx->height / MB_AREA; - //the largest possible chunk is 0x31 with all MBs encoded in V4 mode - //and full codebooks being replaced in INTER mode, + // the largest possible chunk is 0x31 with all MBs encoded in V4 mode + // and full codebooks being replaced in INTER mode, // which is 34 bits per MB - //and 2*256 extra flag bits per strip - strip_buf_size = STRIP_HEADER_SIZE + 3 * CHUNK_HEADER_SIZE + 2 * VECTOR_MAX * CODEBOOK_MAX + 4 * (mb_count + (mb_count + 15) / 16) + (2 * CODEBOOK_MAX)/8; + // and 2*256 extra flag bits per strip + strip_buf_size = STRIP_HEADER_SIZE + 3 * CHUNK_HEADER_SIZE + 2 * VECTOR_MAX * CODEBOOK_MAX + 4 * (mb_count + (mb_count + 15) / 16) + (2 * CODEBOOK_MAX) / 8; frame_buf_size = CVID_HEADER_SIZE + s->max_max_strips * strip_buf_size; @@ -236,21 +207,16 @@ static av_cold int cinepak_encode_init(AVCodecContext *avctx) if (!(s->mb = av_malloc_array(mb_count, sizeof(mb_info)))) goto enomem; -#ifdef CINEPAKENC_DEBUG - if (!(s->best_mb = av_malloc_array(mb_count, sizeof(mb_info)))) - goto enomem; -#endif - av_lfg_init(&s->randctx, 1); - s->avctx = avctx; - s->w = avctx->width; - s->h = avctx->height; + s->avctx = avctx; + s->w = avctx->width; + s->h = avctx->height; s->frame_buf_size = frame_buf_size; - s->curframe = 0; - s->keyint = avctx->keyint_min; - s->pix_fmt = avctx->pix_fmt; + s->curframe = 0; + s->keyint = avctx->keyint_min; + s->pix_fmt = avctx->pix_fmt; - //set up AVFrames + // set up AVFrames s->last_frame->data[0] = s->pict_bufs[0]; s->last_frame->linesize[0] = s->w; s->best_frame->data[0] = s->pict_bufs[1]; @@ -259,32 +225,32 @@ static av_cold int cinepak_encode_init(AVCodecContext *avctx) s->scratch_frame->linesize[0] = s->w; if (s->pix_fmt == AV_PIX_FMT_RGB24) { - s->last_frame->data[1] = s->last_frame->data[0] + s->w * s->h; - s->last_frame->data[2] = s->last_frame->data[1] + ((s->w * s->h) >> 2); - s->last_frame->linesize[1] = s->last_frame->linesize[2] = s->w >> 1; + s->last_frame->data[1] = s->last_frame->data[0] + s->w * s->h; + s->last_frame->data[2] = s->last_frame->data[1] + ((s->w * s->h) >> 2); + s->last_frame->linesize[1] = + s->last_frame->linesize[2] = s->w >> 1; - s->best_frame->data[1] = s->best_frame->data[0] + s->w * s->h; - s->best_frame->data[2] = s->best_frame->data[1] + ((s->w * s->h) >> 2); - s->best_frame->linesize[1] = s->best_frame->linesize[2] = s->w >> 1; + s->best_frame->data[1] = s->best_frame->data[0] + s->w * s->h; + s->best_frame->data[2] = s->best_frame->data[1] + ((s->w * s->h) >> 2); + s->best_frame->linesize[1] = + s->best_frame->linesize[2] = s->w >> 1; - s->scratch_frame->data[1] = s->scratch_frame->data[0] + s->w * s->h; + s->scratch_frame->data[1] = s->scratch_frame->data[0] + s->w * s->h; s->scratch_frame->data[2] = s->scratch_frame->data[1] + ((s->w * s->h) >> 2); - s->scratch_frame->linesize[1] = s->scratch_frame->linesize[2] = s->w >> 1; - - s->input_frame->data[0] = s->pict_bufs[3]; - s->input_frame->linesize[0] = s->w; - s->input_frame->data[1] = s->input_frame->data[0] + s->w * s->h; - s->input_frame->data[2] = s->input_frame->data[1] + ((s->w * s->h) >> 2); - s->input_frame->linesize[1] = s->input_frame->linesize[2] = s->w >> 1; + s->scratch_frame->linesize[1] = + s->scratch_frame->linesize[2] = s->w >> 1; + + s->input_frame->data[0] = s->pict_bufs[3]; + s->input_frame->linesize[0] = s->w; + s->input_frame->data[1] = s->input_frame->data[0] + s->w * s->h; + s->input_frame->data[2] = s->input_frame->data[1] + ((s->w * s->h) >> 2); + s->input_frame->linesize[1] = + s->input_frame->linesize[2] = s->w >> 1; } s->min_strips = s->min_min_strips; s->max_strips = s->max_max_strips; -#ifdef CINEPAKENC_DEBUG - s->num_v1_mode = s->num_v4_mode = s->num_mc_mode = s->num_v1_encs = s->num_v4_encs = s->num_skips = 0; -#endif - return 0; enomem: @@ -298,90 +264,68 @@ static av_cold int cinepak_encode_init(AVCodecContext *avctx) av_freep(&s->strip_buf); av_freep(&s->frame_buf); av_freep(&s->mb); -#ifdef CINEPAKENC_DEBUG - av_freep(&s->best_mb); -#endif - for(x = 0; x < (avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 4 : 3); x++) + for (x = 0; x < (avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 4 : 3); x++) av_freep(&s->pict_bufs[x]); return AVERROR(ENOMEM); } -static int64_t calculate_mode_score(CinepakEncContext *s, int h, strip_info *info, int report, int *training_set_v1_shrunk, int *training_set_v4_shrunk -#ifdef CINEPAK_REPORT_SERR -, int64_t *serr -#endif -) +static int64_t calculate_mode_score(CinepakEncContext *s, int h, + strip_info *info, int report, + int *training_set_v1_shrunk, + int *training_set_v4_shrunk) { - //score = FF_LAMBDA_SCALE * error + lambda * bits + // score = FF_LAMBDA_SCALE * error + lambda * bits int x; int entry_size = s->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4; - int mb_count = s->w * h / MB_AREA; + int mb_count = s->w * h / MB_AREA; mb_info *mb; int64_t score1, score2, score3; int64_t ret = s->lambda * ((info->v1_size ? CHUNK_HEADER_SIZE + info->v1_size * entry_size : 0) + - (info->v4_size ? CHUNK_HEADER_SIZE + info->v4_size * entry_size : 0) + - CHUNK_HEADER_SIZE) << 3; - - //av_log(s->avctx, AV_LOG_INFO, "sizes %3i %3i -> %9"PRId64" score mb_count %i", info->v1_size, info->v4_size, ret, mb_count); + (info->v4_size ? CHUNK_HEADER_SIZE + info->v4_size * entry_size : 0) + + CHUNK_HEADER_SIZE) << 3; -#ifdef CINEPAK_REPORT_SERR - *serr = 0; -#endif - - switch(info->mode) { + switch (info->mode) { case MODE_V1_ONLY: - //one byte per MB + // one byte per MB ret += s->lambda * 8 * mb_count; -// while calculating we assume all blocks are ENC_V1 - for(x = 0; x < mb_count; x++) { - mb = &s->mb[x]; + // while calculating we assume all blocks are ENC_V1 + for (x = 0; x < mb_count; x++) { + mb = &s->mb[x]; ret += FF_LAMBDA_SCALE * mb->v1_error; -#ifdef CINEPAK_REPORT_SERR - *serr += mb->v1_error; -#endif -// this function is never called for report in MODE_V1_ONLY -// if(!report) + // this function is never called for report in MODE_V1_ONLY + // if (!report) mb->best_encoding = ENC_V1; } break; case MODE_V1_V4: - //9 or 33 bits per MB - if(report) { -// no moves between the corresponding training sets are allowed + // 9 or 33 bits per MB + if (report) { + // no moves between the corresponding training sets are allowed *training_set_v1_shrunk = *training_set_v4_shrunk = 0; - for(x = 0; x < mb_count; x++) { + for (x = 0; x < mb_count; x++) { int mberr; mb = &s->mb[x]; - if(mb->best_encoding == ENC_V1) - score1 = s->lambda * 9 + FF_LAMBDA_SCALE * (mberr=mb->v1_error); + if (mb->best_encoding == ENC_V1) + score1 = s->lambda * 9 + FF_LAMBDA_SCALE * (mberr = mb->v1_error); else - score1 = s->lambda * 33 + FF_LAMBDA_SCALE * (mberr=mb->v4_error); + score1 = s->lambda * 33 + FF_LAMBDA_SCALE * (mberr = mb->v4_error); ret += score1; -#ifdef CINEPAK_REPORT_SERR - *serr += mberr; -#endif } } else { // find best mode per block - for(x = 0; x < mb_count; x++) { - mb = &s->mb[x]; - score1 = s->lambda * 9 + FF_LAMBDA_SCALE * mb->v1_error; + for (x = 0; x < mb_count; x++) { + mb = &s->mb[x]; + score1 = s->lambda * 9 + FF_LAMBDA_SCALE * mb->v1_error; score2 = s->lambda * 33 + FF_LAMBDA_SCALE * mb->v4_error; - if(score1 <= score2) { + if (score1 <= score2) { ret += score1; -#ifdef CINEPAK_REPORT_SERR - *serr += mb->v1_error; -#endif mb->best_encoding = ENC_V1; } else { ret += score2; -#ifdef CINEPAK_REPORT_SERR - *serr += mb->v4_error; -#endif mb->best_encoding = ENC_V4; } } @@ -389,75 +333,51 @@ static int64_t calculate_mode_score(CinepakEncContext *s, int h, strip_info *inf break; case MODE_MC: - //1, 10 or 34 bits per MB - if(report) { + // 1, 10 or 34 bits per MB + if (report) { int v1_shrunk = 0, v4_shrunk = 0; - for(x = 0; x < mb_count; x++) { + for (x = 0; x < mb_count; x++) { mb = &s->mb[x]; -// it is OK to move blocks to ENC_SKIP here -// but not to any codebook encoding! - score1 = s->lambda * 1 + FF_LAMBDA_SCALE * mb->skip_error; - if(mb->best_encoding == ENC_SKIP) { + // it is OK to move blocks to ENC_SKIP here + // but not to any codebook encoding! + score1 = s->lambda * 1 + FF_LAMBDA_SCALE * mb->skip_error; + if (mb->best_encoding == ENC_SKIP) { ret += score1; -#ifdef CINEPAK_REPORT_SERR - *serr += mb->skip_error; -#endif - } else if(mb->best_encoding == ENC_V1) { - if((score2=s->lambda * 10 + FF_LAMBDA_SCALE * mb->v1_error) >= score1) { + } else if (mb->best_encoding == ENC_V1) { + if ((score2 = s->lambda * 10 + FF_LAMBDA_SCALE * mb->v1_error) >= score1) { mb->best_encoding = ENC_SKIP; ++v1_shrunk; ret += score1; -#ifdef CINEPAK_REPORT_SERR - *serr += mb->skip_error; -#endif } else { ret += score2; -#ifdef CINEPAK_REPORT_SERR - *serr += mb->v1_error; -#endif } } else { - if((score3=s->lambda * 34 + FF_LAMBDA_SCALE * mb->v4_error) >= score1) { + if ((score3 = s->lambda * 34 + FF_LAMBDA_SCALE * mb->v4_error) >= score1) { mb->best_encoding = ENC_SKIP; ++v4_shrunk; ret += score1; -#ifdef CINEPAK_REPORT_SERR - *serr += mb->skip_error; -#endif } else { ret += score3; -#ifdef CINEPAK_REPORT_SERR - *serr += mb->v4_error; -#endif } } } *training_set_v1_shrunk = v1_shrunk; *training_set_v4_shrunk = v4_shrunk; } else { // find best mode per block - for(x = 0; x < mb_count; x++) { - mb = &s->mb[x]; - score1 = s->lambda * 1 + FF_LAMBDA_SCALE * mb->skip_error; + for (x = 0; x < mb_count; x++) { + mb = &s->mb[x]; + score1 = s->lambda * 1 + FF_LAMBDA_SCALE * mb->skip_error; score2 = s->lambda * 10 + FF_LAMBDA_SCALE * mb->v1_error; score3 = s->lambda * 34 + FF_LAMBDA_SCALE * mb->v4_error; - if(score1 <= score2 && score1 <= score3) { + if (score1 <= score2 && score1 <= score3) { ret += score1; -#ifdef CINEPAK_REPORT_SERR - *serr += mb->skip_error; -#endif mb->best_encoding = ENC_SKIP; - } else if(score2 <= score3) { + } else if (score2 <= score3) { ret += score2; -#ifdef CINEPAK_REPORT_SERR - *serr += mb->v1_error; -#endif mb->best_encoding = ENC_V1; } else { ret += score3; -#ifdef CINEPAK_REPORT_SERR - *serr += mb->v4_error; -#endif mb->best_encoding = ENC_V4; } } @@ -476,123 +396,125 @@ static int write_chunk_header(unsigned char *buf, int chunk_type, int chunk_size return CHUNK_HEADER_SIZE; } -static int encode_codebook(CinepakEncContext *s, int *codebook, int size, int chunk_type_yuv, int chunk_type_gray, unsigned char *buf) +static int encode_codebook(CinepakEncContext *s, int *codebook, int size, + int chunk_type_yuv, int chunk_type_gray, + unsigned char *buf) { int x, y, ret, entry_size = s->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4; int incremental_codebook_replacement_mode = 0; // hardcoded here, - // the compiler should notice that this is a constant -- rl + // the compiler should notice that this is a constant -- rl ret = write_chunk_header(buf, - s->pix_fmt == AV_PIX_FMT_RGB24 ? - chunk_type_yuv+(incremental_codebook_replacement_mode?1:0) : - chunk_type_gray+(incremental_codebook_replacement_mode?1:0), - entry_size * size - + (incremental_codebook_replacement_mode?(size+31)/32*4:0) ); - -// we do codebook encoding according to the "intra" mode -// but we keep the "dead" code for reference in case we will want -// to use incremental codebook updates (which actually would give us -// "kind of" motion compensation, especially in 1 strip/frame case) -- rl -// (of course, the code will be not useful as-is) - if(incremental_codebook_replacement_mode) { + s->pix_fmt == AV_PIX_FMT_RGB24 ? + chunk_type_yuv + (incremental_codebook_replacement_mode ? 1 : 0) : + chunk_type_gray + (incremental_codebook_replacement_mode ? 1 : 0), + entry_size * size + + (incremental_codebook_replacement_mode ? (size + 31) / 32 * 4 : 0)); + + // we do codebook encoding according to the "intra" mode + // but we keep the "dead" code for reference in case we will want + // to use incremental codebook updates (which actually would give us + // "kind of" motion compensation, especially in 1 strip/frame case) -- rl + // (of course, the code will be not useful as-is) + if (incremental_codebook_replacement_mode) { int flags = 0; int flagsind; - for(x = 0; x < size; x++) { - if(flags == 0) { + for (x = 0; x < size; x++) { + if (flags == 0) { flagsind = ret; - ret += 4; - flags = 0x80000000; + ret += 4; + flags = 0x80000000; } else - flags = ((flags>>1) | 0x80000000); - for(y = 0; y < entry_size; y++) - buf[ret++] = codebook[y + x*entry_size] ^ (y >= 4 ? 0x80 : 0); - if((flags&0xffffffff) == 0xffffffff) { + flags = ((flags >> 1) | 0x80000000); + for (y = 0; y < entry_size; y++) + buf[ret++] = codebook[y + x * entry_size] ^ (y >= 4 ? 0x80 : 0); + if ((flags & 0xffffffff) == 0xffffffff) { AV_WB32(&buf[flagsind], flags); flags = 0; } } - if(flags) + if (flags) AV_WB32(&buf[flagsind], flags); } else - for(x = 0; x < size; x++) - for(y = 0; y < entry_size; y++) - buf[ret++] = codebook[y + x*entry_size] ^ (y >= 4 ? 0x80 : 0); + for (x = 0; x < size; x++) + for (y = 0; y < entry_size; y++) + buf[ret++] = codebook[y + x * entry_size] ^ (y >= 4 ? 0x80 : 0); return ret; } -//sets out to the sub picture starting at (x,y) in in +// sets out to the sub picture starting at (x,y) in in static void get_sub_picture(CinepakEncContext *s, int x, int y, uint8_t * in_data[4], int in_linesize[4], uint8_t *out_data[4], int out_linesize[4]) { - out_data[0] = in_data[0] + x + y * in_linesize[0]; + out_data[0] = in_data[0] + x + y * in_linesize[0]; out_linesize[0] = in_linesize[0]; - if(s->pix_fmt == AV_PIX_FMT_RGB24) { - out_data[1] = in_data[1] + (x >> 1) + (y >> 1) * in_linesize[1]; + if (s->pix_fmt == AV_PIX_FMT_RGB24) { + out_data[1] = in_data[1] + (x >> 1) + (y >> 1) * in_linesize[1]; out_linesize[1] = in_linesize[1]; - out_data[2] = in_data[2] + (x >> 1) + (y >> 1) * in_linesize[2]; + out_data[2] = in_data[2] + (x >> 1) + (y >> 1) * in_linesize[2]; out_linesize[2] = in_linesize[2]; } } -//decodes the V1 vector in mb into the 4x4 MB pointed to by data +// decodes the V1 vector in mb into the 4x4 MB pointed to by data static void decode_v1_vector(CinepakEncContext *s, uint8_t *data[4], int linesize[4], int v1_vector, strip_info *info) { int entry_size = s->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4; data[0][0] = - data[0][1] = - data[0][ linesize[0]] = - data[0][1+ linesize[0]] = info->v1_codebook[v1_vector*entry_size]; + data[0][1] = + data[0][ linesize[0]] = + data[0][1 + linesize[0]] = info->v1_codebook[v1_vector * entry_size]; data[0][2] = - data[0][3] = - data[0][2+ linesize[0]] = - data[0][3+ linesize[0]] = info->v1_codebook[v1_vector*entry_size+1]; + data[0][3] = + data[0][2 + linesize[0]] = + data[0][3 + linesize[0]] = info->v1_codebook[v1_vector * entry_size + 1]; - data[0][2*linesize[0]] = - data[0][1+2*linesize[0]] = - data[0][ 3*linesize[0]] = - data[0][1+3*linesize[0]] = info->v1_codebook[v1_vector*entry_size+2]; + data[0][ 2 * linesize[0]] = + data[0][1 + 2 * linesize[0]] = + data[0][ 3 * linesize[0]] = + data[0][1 + 3 * linesize[0]] = info->v1_codebook[v1_vector * entry_size + 2]; - data[0][2+2*linesize[0]] = - data[0][3+2*linesize[0]] = - data[0][2+3*linesize[0]] = - data[0][3+3*linesize[0]] = info->v1_codebook[v1_vector*entry_size+3]; + data[0][2 + 2 * linesize[0]] = + data[0][3 + 2 * linesize[0]] = + data[0][2 + 3 * linesize[0]] = + data[0][3 + 3 * linesize[0]] = info->v1_codebook[v1_vector * entry_size + 3]; - if(s->pix_fmt == AV_PIX_FMT_RGB24) { + if (s->pix_fmt == AV_PIX_FMT_RGB24) { data[1][0] = - data[1][1] = - data[1][ linesize[1]] = - data[1][1+ linesize[1]] = info->v1_codebook[v1_vector*entry_size+4]; + data[1][1] = + data[1][ linesize[1]] = + data[1][1 + linesize[1]] = info->v1_codebook[v1_vector * entry_size + 4]; data[2][0] = - data[2][1] = - data[2][ linesize[2]] = - data[2][1+ linesize[2]] = info->v1_codebook[v1_vector*entry_size+5]; + data[2][1] = + data[2][ linesize[2]] = + data[2][1 + linesize[2]] = info->v1_codebook[v1_vector * entry_size + 5]; } } -//decodes the V4 vectors in mb into the 4x4 MB pointed to by data +// decodes the V4 vectors in mb into the 4x4 MB pointed to by data static void decode_v4_vector(CinepakEncContext *s, uint8_t *data[4], int linesize[4], int *v4_vector, strip_info *info) { int i, x, y, entry_size = s->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4; - for(i = y = 0; y < 4; y += 2) { - for(x = 0; x < 4; x += 2, i++) { - data[0][x + y*linesize[0]] = info->v4_codebook[v4_vector[i]*entry_size]; - data[0][x+1 + y*linesize[0]] = info->v4_codebook[v4_vector[i]*entry_size+1]; - data[0][x + (y+1)*linesize[0]] = info->v4_codebook[v4_vector[i]*entry_size+2]; - data[0][x+1 + (y+1)*linesize[0]] = info->v4_codebook[v4_vector[i]*entry_size+3]; + for (i = y = 0; y < 4; y += 2) { + for (x = 0; x < 4; x += 2, i++) { + data[0][x + y * linesize[0]] = info->v4_codebook[v4_vector[i] * entry_size]; + data[0][x + 1 + y * linesize[0]] = info->v4_codebook[v4_vector[i] * entry_size + 1]; + data[0][x + (y + 1) * linesize[0]] = info->v4_codebook[v4_vector[i] * entry_size + 2]; + data[0][x + 1 + (y + 1) * linesize[0]] = info->v4_codebook[v4_vector[i] * entry_size + 3]; - if(s->pix_fmt == AV_PIX_FMT_RGB24) { - data[1][(x>>1) + (y>>1)*linesize[1]] = info->v4_codebook[v4_vector[i]*entry_size+4]; - data[2][(x>>1) + (y>>1)*linesize[2]] = info->v4_codebook[v4_vector[i]*entry_size+5]; + if (s->pix_fmt == AV_PIX_FMT_RGB24) { + data[1][(x >> 1) + (y >> 1) * linesize[1]] = info->v4_codebook[v4_vector[i] * entry_size + 4]; + data[2][(x >> 1) + (y >> 1) * linesize[2]] = info->v4_codebook[v4_vector[i] * entry_size + 5]; } } } @@ -604,19 +526,16 @@ static void copy_mb(CinepakEncContext *s, { int y, p; - for(y = 0; y < MB_SIZE; y++) { - memcpy(a_data[0]+y*a_linesize[0], b_data[0]+y*b_linesize[0], + for (y = 0; y < MB_SIZE; y++) + memcpy(a_data[0] + y * a_linesize[0], b_data[0] + y * b_linesize[0], MB_SIZE); - } - if(s->pix_fmt == AV_PIX_FMT_RGB24) { - for(p = 1; p <= 2; p++) { - for(y = 0; y < MB_SIZE/2; y++) { - memcpy(a_data[p] + y*a_linesize[p], - b_data[p] + y*b_linesize[p], - MB_SIZE/2); - } - } + if (s->pix_fmt == AV_PIX_FMT_RGB24) { + for (p = 1; p <= 2; p++) + for (y = 0; y < MB_SIZE / 2; y++) + memcpy(a_data[p] + y * a_linesize[p], + b_data[p] + y * b_linesize[p], + MB_SIZE / 2); } } @@ -627,74 +546,71 @@ static int encode_mode(CinepakEncContext *s, int h, { int x, y, z, flags, bits, temp_size, header_ofs, ret = 0, mb_count = s->w * h / MB_AREA; int needs_extra_bit, should_write_temp; - unsigned char temp[64]; //32/2 = 16 V4 blocks at 4 B each -> 64 B + unsigned char temp[64]; // 32/2 = 16 V4 blocks at 4 B each -> 64 B mb_info *mb; - uint8_t *sub_scratch_data[4] = {0}, *sub_last_data[4] = {0}; - int sub_scratch_linesize[4] = {0}, sub_last_linesize[4] = {0}; - - //encode codebooks -////// MacOS vintage decoder compatibility dictates the presence of -////// the codebook chunk even when the codebook is empty - pretty dumb... -////// and also the certain order of the codebook chunks -- rl - if(info->v4_size || !s->skip_empty_cb) + uint8_t *sub_scratch_data[4] = { 0 }, *sub_last_data[4] = { 0 }; + int sub_scratch_linesize[4] = { 0 }, sub_last_linesize[4] = { 0 }; + + // encode codebooks + ////// MacOS vintage decoder compatibility dictates the presence of + ////// the codebook chunk even when the codebook is empty - pretty dumb... + ////// and also the certain order of the codebook chunks -- rl + if (info->v4_size || !s->skip_empty_cb) ret += encode_codebook(s, info->v4_codebook, info->v4_size, 0x20, 0x24, buf + ret); - if(info->v1_size || !s->skip_empty_cb) + if (info->v1_size || !s->skip_empty_cb) ret += encode_codebook(s, info->v1_codebook, info->v1_size, 0x22, 0x26, buf + ret); - //update scratch picture - for(z = y = 0; y < h; y += MB_SIZE) { - for(x = 0; x < s->w; x += MB_SIZE, z++) { + // update scratch picture + for (z = y = 0; y < h; y += MB_SIZE) + for (x = 0; x < s->w; x += MB_SIZE, z++) { mb = &s->mb[z]; get_sub_picture(s, x, y, scratch_data, scratch_linesize, sub_scratch_data, sub_scratch_linesize); - if(info->mode == MODE_MC && mb->best_encoding == ENC_SKIP) { - get_sub_picture(s, x, y, - last_data, last_linesize, + if (info->mode == MODE_MC && mb->best_encoding == ENC_SKIP) { + get_sub_picture(s, x, y, last_data, last_linesize, sub_last_data, sub_last_linesize); copy_mb(s, sub_scratch_data, sub_scratch_linesize, sub_last_data, sub_last_linesize); - } else if(info->mode == MODE_V1_ONLY || mb->best_encoding == ENC_V1) + } else if (info->mode == MODE_V1_ONLY || mb->best_encoding == ENC_V1) decode_v1_vector(s, sub_scratch_data, sub_scratch_linesize, mb->v1_vector, info); else decode_v4_vector(s, sub_scratch_data, sub_scratch_linesize, mb->v4_vector, info); } - } - switch(info->mode) { + switch (info->mode) { case MODE_V1_ONLY: - //av_log(s->avctx, AV_LOG_INFO, "mb_count = %i\n", mb_count); ret += write_chunk_header(buf + ret, 0x32, mb_count); - for(x = 0; x < mb_count; x++) + for (x = 0; x < mb_count; x++) buf[ret++] = s->mb[x].v1_vector; break; case MODE_V1_V4: - //remember header position + // remember header position header_ofs = ret; - ret += CHUNK_HEADER_SIZE; + ret += CHUNK_HEADER_SIZE; - for(x = 0; x < mb_count; x += 32) { + for (x = 0; x < mb_count; x += 32) { flags = 0; - for(y = x; y < FFMIN(x+32, mb_count); y++) - if(s->mb[y].best_encoding == ENC_V4) + for (y = x; y < FFMIN(x + 32, mb_count); y++) + if (s->mb[y].best_encoding == ENC_V4) flags |= 1 << (31 - y + x); AV_WB32(&buf[ret], flags); ret += 4; - for(y = x; y < FFMIN(x+32, mb_count); y++) { + for (y = x; y < FFMIN(x + 32, mb_count); y++) { mb = &s->mb[y]; - if(mb->best_encoding == ENC_V1) + if (mb->best_encoding == ENC_V1) buf[ret++] = mb->v1_vector; else - for(z = 0; z < 4; z++) + for (z = 0; z < 4; z++) buf[ret++] = mb->v4_vector[z]; } } @@ -703,56 +619,56 @@ static int encode_mode(CinepakEncContext *s, int h, break; case MODE_MC: - //remember header position + // remember header position header_ofs = ret; - ret += CHUNK_HEADER_SIZE; - flags = bits = temp_size = 0; + ret += CHUNK_HEADER_SIZE; + flags = bits = temp_size = 0; - for(x = 0; x < mb_count; x++) { - mb = &s->mb[x]; - flags |= (mb->best_encoding != ENC_SKIP) << (31 - bits++); - needs_extra_bit = 0; + for (x = 0; x < mb_count; x++) { + mb = &s->mb[x]; + flags |= (mb->best_encoding != ENC_SKIP) << (31 - bits++); + needs_extra_bit = 0; should_write_temp = 0; - if(mb->best_encoding != ENC_SKIP) { - if(bits < 32) + if (mb->best_encoding != ENC_SKIP) { + if (bits < 32) flags |= (mb->best_encoding == ENC_V4) << (31 - bits++); else needs_extra_bit = 1; } - if(bits == 32) { + if (bits == 32) { AV_WB32(&buf[ret], flags); - ret += 4; + ret += 4; flags = bits = 0; - if(mb->best_encoding == ENC_SKIP || needs_extra_bit) { + if (mb->best_encoding == ENC_SKIP || needs_extra_bit) { memcpy(&buf[ret], temp, temp_size); - ret += temp_size; + ret += temp_size; temp_size = 0; } else should_write_temp = 1; } - if(needs_extra_bit) { + if (needs_extra_bit) { flags = (mb->best_encoding == ENC_V4) << 31; - bits = 1; + bits = 1; } - if(mb->best_encoding == ENC_V1) + if (mb->best_encoding == ENC_V1) temp[temp_size++] = mb->v1_vector; - else if(mb->best_encoding == ENC_V4) - for(z = 0; z < 4; z++) + else if (mb->best_encoding == ENC_V4) + for (z = 0; z < 4; z++) temp[temp_size++] = mb->v4_vector[z]; - if(should_write_temp) { + if (should_write_temp) { memcpy(&buf[ret], temp, temp_size); - ret += temp_size; + ret += temp_size; temp_size = 0; } } - if(bits > 0) { + if (bits > 0) { AV_WB32(&buf[ret], flags); ret += 4; memcpy(&buf[ret], temp, temp_size); @@ -767,28 +683,26 @@ static int encode_mode(CinepakEncContext *s, int h, return ret; } -//computes distortion of 4x4 MB in b compared to a +// computes distortion of 4x4 MB in b compared to a static int compute_mb_distortion(CinepakEncContext *s, uint8_t *a_data[4], int a_linesize[4], uint8_t *b_data[4], int b_linesize[4]) { int x, y, p, d, ret = 0; - for(y = 0; y < MB_SIZE; y++) { - for(x = 0; x < MB_SIZE; x++) { - d = a_data[0][x + y*a_linesize[0]] - b_data[0][x + y*b_linesize[0]]; - ret += d*d; + for (y = 0; y < MB_SIZE; y++) + for (x = 0; x < MB_SIZE; x++) { + d = a_data[0][x + y * a_linesize[0]] - b_data[0][x + y * b_linesize[0]]; + ret += d * d; } - } - if(s->pix_fmt == AV_PIX_FMT_RGB24) { - for(p = 1; p <= 2; p++) { - for(y = 0; y < MB_SIZE/2; y++) { - for(x = 0; x < MB_SIZE/2; x++) { - d = a_data[p][x + y*a_linesize[p]] - b_data[p][x + y*b_linesize[p]]; - ret += d*d; + if (s->pix_fmt == AV_PIX_FMT_RGB24) { + for (p = 1; p <= 2; p++) { + for (y = 0; y < MB_SIZE / 2; y++) + for (x = 0; x < MB_SIZE / 2; x++) { + d = a_data[p][x + y * a_linesize[p]] - b_data[p][x + y * b_linesize[p]]; + ret += d * d; } - } } } @@ -796,114 +710,108 @@ static int compute_mb_distortion(CinepakEncContext *s, } // return the possibly adjusted size of the codebook -#define CERTAIN(x) ((x)!=ENC_UNCERTAIN) -static int quantize(CinepakEncContext *s, int h, - uint8_t *data[4], int linesize[4], - int v1mode, strip_info *info, +#define CERTAIN(x) ((x) != ENC_UNCERTAIN) +static int quantize(CinepakEncContext *s, int h, uint8_t *data[4], + int linesize[4], int v1mode, strip_info *info, mb_encoding encoding) { int x, y, i, j, k, x2, y2, x3, y3, plane, shift, mbn; - int entry_size = s->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4; - int *codebook = v1mode ? info->v1_codebook : info->v4_codebook; - int size = v1mode ? info->v1_size : info->v4_size; + int entry_size = s->pix_fmt == AV_PIX_FMT_RGB24 ? 6 : 4; + int *codebook = v1mode ? info->v1_codebook : info->v4_codebook; + int size = v1mode ? info->v1_size : info->v4_size; int64_t total_error = 0; - uint8_t vq_pict_buf[(MB_AREA*3)/2]; - uint8_t *sub_data [4], *vq_data [4]; + uint8_t vq_pict_buf[(MB_AREA * 3) / 2]; + uint8_t *sub_data[4], *vq_data[4]; int sub_linesize[4], vq_linesize[4]; - for(mbn = i = y = 0; y < h; y += MB_SIZE) { - for(x = 0; x < s->w; x += MB_SIZE, ++mbn) { + for (mbn = i = y = 0; y < h; y += MB_SIZE) { + for (x = 0; x < s->w; x += MB_SIZE, ++mbn) { int *base; - if(CERTAIN(encoding)) { -// use for the training only the blocks known to be to be encoded [sic:-] - if(s->mb[mbn].best_encoding != encoding) continue; + if (CERTAIN(encoding)) { + // use for the training only the blocks known to be to be encoded [sic:-] + if (s->mb[mbn].best_encoding != encoding) + continue; } - base = s->codebook_input + i*entry_size; - if(v1mode) { - //subsample - for(j = y2 = 0; y2 < entry_size; y2 += 2) { - for(x2 = 0; x2 < 4; x2 += 2, j++) { - plane = y2 < 4 ? 0 : 1 + (x2 >> 1); - shift = y2 < 4 ? 0 : 1; - x3 = shift ? 0 : x2; - y3 = shift ? 0 : y2; - base[j] = (data[plane][((x+x3) >> shift) + ((y+y3) >> shift) * linesize[plane]] + - data[plane][((x+x3) >> shift) + 1 + ((y+y3) >> shift) * linesize[plane]] + - data[plane][((x+x3) >> shift) + (((y+y3) >> shift) + 1) * linesize[plane]] + - data[plane][((x+x3) >> shift) + 1 + (((y+y3) >> shift) + 1) * linesize[plane]]) >> 2; + base = s->codebook_input + i * entry_size; + if (v1mode) { + // subsample + for (j = y2 = 0; y2 < entry_size; y2 += 2) + for (x2 = 0; x2 < 4; x2 += 2, j++) { + plane = y2 < 4 ? 0 : 1 + (x2 >> 1); + shift = y2 < 4 ? 0 : 1; + x3 = shift ? 0 : x2; + y3 = shift ? 0 : y2; + base[j] = (data[plane][((x + x3) >> shift) + ((y + y3) >> shift) * linesize[plane]] + + data[plane][((x + x3) >> shift) + 1 + ((y + y3) >> shift) * linesize[plane]] + + data[plane][((x + x3) >> shift) + (((y + y3) >> shift) + 1) * linesize[plane]] + + data[plane][((x + x3) >> shift) + 1 + (((y + y3) >> shift) + 1) * linesize[plane]]) >> 2; } - } } else { - //copy - for(j = y2 = 0; y2 < MB_SIZE; y2 += 2) { - for(x2 = 0; x2 < MB_SIZE; x2 += 2) { - for(k = 0; k < entry_size; k++, j++) { + // copy + for (j = y2 = 0; y2 < MB_SIZE; y2 += 2) { + for (x2 = 0; x2 < MB_SIZE; x2 += 2) + for (k = 0; k < entry_size; k++, j++) { plane = k >= 4 ? k - 3 : 0; - if(k >= 4) { - x3 = (x+x2) >> 1; - y3 = (y+y2) >> 1; + if (k >= 4) { + x3 = (x + x2) >> 1; + y3 = (y + y2) >> 1; } else { x3 = x + x2 + (k & 1); y3 = y + y2 + (k >> 1); } - base[j] = data[plane][x3 + y3*linesize[plane]]; + base[j] = data[plane][x3 + y3 * linesize[plane]]; } - } } } i += v1mode ? 1 : 4; } } -// if(i < mbn*(v1mode ? 1 : 4)) { -// av_log(s->avctx, AV_LOG_INFO, "reducing training set for %s from %i to %i (encoding %i)\n", v1mode?"v1":"v4", mbn*(v1mode ? 1 : 4), i, encoding); -// } - if(i == 0) // empty training set, nothing to do + if (i == 0) // empty training set, nothing to do return 0; - if(i < size) { - //av_log(s->avctx, (CERTAIN(encoding) ? AV_LOG_ERROR : AV_LOG_INFO), "WOULD WASTE: %s cbsize %i bigger than training set size %i (encoding %i)\n", v1mode?"v1":"v4", size, i, encoding); + if (i < size) size = i; - } avpriv_init_elbg(s->codebook_input, entry_size, i, codebook, size, 1, s->codebook_closest, &s->randctx); avpriv_do_elbg(s->codebook_input, entry_size, i, codebook, size, 1, s->codebook_closest, &s->randctx); - //setup vq_data, which contains a single MB - vq_data[0] = vq_pict_buf; + // set up vq_data, which contains a single MB + vq_data[0] = vq_pict_buf; vq_linesize[0] = MB_SIZE; - vq_data[1] = &vq_pict_buf[MB_AREA]; - vq_data[2] = vq_data[1] + (MB_AREA >> 2); - vq_linesize[1] = vq_linesize[2] = MB_SIZE >> 1; - - //copy indices - for(i = j = y = 0; y < h; y += MB_SIZE) { - for(x = 0; x < s->w; x += MB_SIZE, j++) { + vq_data[1] = &vq_pict_buf[MB_AREA]; + vq_data[2] = vq_data[1] + (MB_AREA >> 2); + vq_linesize[1] = + vq_linesize[2] = MB_SIZE >> 1; + + // copy indices + for (i = j = y = 0; y < h; y += MB_SIZE) + for (x = 0; x < s->w; x += MB_SIZE, j++) { mb_info *mb = &s->mb[j]; -// skip uninteresting blocks if we know their preferred encoding - if(CERTAIN(encoding) && mb->best_encoding != encoding) + // skip uninteresting blocks if we know their preferred encoding + if (CERTAIN(encoding) && mb->best_encoding != encoding) continue; - //point sub_data to current MB + // point sub_data to current MB get_sub_picture(s, x, y, data, linesize, sub_data, sub_linesize); - if(v1mode) { + if (v1mode) { mb->v1_vector = s->codebook_closest[i]; - //fill in vq_data with V1 data + // fill in vq_data with V1 data decode_v1_vector(s, vq_data, vq_linesize, mb->v1_vector, info); mb->v1_error = compute_mb_distortion(s, sub_data, sub_linesize, vq_data, vq_linesize); total_error += mb->v1_error; } else { - for(k = 0; k < 4; k++) - mb->v4_vector[k] = s->codebook_closest[i+k]; + for (k = 0; k < 4; k++) + mb->v4_vector[k] = s->codebook_closest[i + k]; - //fill in vq_data with V4 data + // fill in vq_data with V4 data decode_v4_vector(s, vq_data, vq_linesize, mb->v4_vector, info); mb->v4_error = compute_mb_distortion(s, sub_data, sub_linesize, @@ -912,12 +820,9 @@ static int quantize(CinepakEncContext *s, int h, } i += v1mode ? 1 : 4; } - } -// check that we did it right in the beginning of the function + // check that we did it right in the beginning of the function av_assert0(i >= size); // training set is no smaller than the codebook - //av_log(s->avctx, AV_LOG_INFO, "isv1 %i size= %i i= %i error %"PRId64"\n", v1mode, size, i, total_error); - return size; } @@ -930,221 +835,160 @@ static void calculate_skip_errors(CinepakEncContext *s, int h, uint8_t *sub_last_data [4], *sub_pict_data [4]; int sub_last_linesize[4], sub_pict_linesize[4]; - for(i = y = 0; y < h; y += MB_SIZE) { - for(x = 0; x < s->w; x += MB_SIZE, i++) { - get_sub_picture(s, x, y, last_data, last_linesize, - sub_last_data, sub_last_linesize); - get_sub_picture(s, x, y, data, linesize, - sub_pict_data, sub_pict_linesize); - - s->mb[i].skip_error = compute_mb_distortion(s, - sub_last_data, sub_last_linesize, - sub_pict_data, sub_pict_linesize); + for (i = y = 0; y < h; y += MB_SIZE) + for (x = 0; x < s->w; x += MB_SIZE, i++) { + get_sub_picture(s, x, y, last_data, last_linesize, + sub_last_data, sub_last_linesize); + get_sub_picture(s, x, y, data, linesize, + sub_pict_data, sub_pict_linesize); + + s->mb[i].skip_error = + compute_mb_distortion(s, + sub_last_data, sub_last_linesize, + sub_pict_data, sub_pict_linesize); } - } } -static void write_strip_header(CinepakEncContext *s, int y, int h, int keyframe, unsigned char *buf, int strip_size) +static void write_strip_header(CinepakEncContext *s, int y, int h, int keyframe, + unsigned char *buf, int strip_size) { -// actually we are exclusively using intra strip coding (how much can we win -// otherwise? how to choose which part of a codebook to update?), -// keyframes are different only because we disallow ENC_SKIP on them -- rl -// (besides, the logic here used to be inverted: ) -// buf[0] = keyframe ? 0x11: 0x10; - buf[0] = keyframe ? 0x10: 0x11; + // actually we are exclusively using intra strip coding (how much can we win + // otherwise? how to choose which part of a codebook to update?), + // keyframes are different only because we disallow ENC_SKIP on them -- rl + // (besides, the logic here used to be inverted: ) + // buf[0] = keyframe ? 0x11: 0x10; + buf[0] = keyframe ? 0x10 : 0x11; AV_WB24(&buf[1], strip_size + STRIP_HEADER_SIZE); -// AV_WB16(&buf[4], y); /* using absolute y values works -- rl */ + // AV_WB16(&buf[4], y); /* using absolute y values works -- rl */ AV_WB16(&buf[4], 0); /* using relative values works as well -- rl */ AV_WB16(&buf[6], 0); -// AV_WB16(&buf[8], y+h); /* using absolute y values works -- rl */ + // AV_WB16(&buf[8], y + h); /* using absolute y values works -- rl */ AV_WB16(&buf[8], h); /* using relative values works as well -- rl */ AV_WB16(&buf[10], s->w); - //av_log(s->avctx, AV_LOG_INFO, "write_strip_header() %x keyframe=%d\n", buf[0], keyframe); } static int rd_strip(CinepakEncContext *s, int y, int h, int keyframe, uint8_t *last_data[4], int last_linesize[4], uint8_t *data[4], int linesize[4], uint8_t *scratch_data[4], int scratch_linesize[4], - unsigned char *buf, int64_t *best_score -#ifdef CINEPAK_REPORT_SERR -, int64_t *best_serr -#endif -) + unsigned char *buf, int64_t *best_score) { int64_t score = 0; -#ifdef CINEPAK_REPORT_SERR - int64_t serr; -#endif int best_size = 0; strip_info info; -// for codebook optimization: + // for codebook optimization: int v1enough, v1_size, v4enough, v4_size; int new_v1_size, new_v4_size; int v1shrunk, v4shrunk; - if(!keyframe) + if (!keyframe) calculate_skip_errors(s, h, last_data, last_linesize, data, linesize, &info); - //try some powers of 4 for the size of the codebooks - //constraint the v4 codebook to be no bigger than v1 one, - //(and no less than v1_size/4) - //thus making v1 preferable and possibly losing small details? should be ok + // try some powers of 4 for the size of the codebooks + // constraint the v4 codebook to be no bigger than v1 one, + // (and no less than v1_size/4) + // thus making v1 preferable and possibly losing small details? should be ok #define SMALLEST_CODEBOOK 1 - for(v1enough = 0, v1_size = SMALLEST_CODEBOOK; v1_size <= CODEBOOK_MAX && !v1enough; v1_size <<= 2) { - for(v4enough = 0, v4_size = 0; v4_size <= v1_size && !v4enough; v4_size = v4_size ? v4_size << 2 : v1_size >= SMALLEST_CODEBOOK << 2 ? v1_size >> 2 : SMALLEST_CODEBOOK) { - //try all modes - for(CinepakMode mode = 0; mode < MODE_COUNT; mode++) { - //don't allow MODE_MC in intra frames - if(keyframe && mode == MODE_MC) + for (v1enough = 0, v1_size = SMALLEST_CODEBOOK; v1_size <= CODEBOOK_MAX && !v1enough; v1_size <<= 2) { + for (v4enough = 0, v4_size = 0; v4_size <= v1_size && !v4enough; v4_size = v4_size ? v4_size << 2 : v1_size >= SMALLEST_CODEBOOK << 2 ? v1_size >> 2 : SMALLEST_CODEBOOK) { + CinepakMode mode; + // try all modes + for (mode = 0; mode < MODE_COUNT; mode++) { + // don't allow MODE_MC in intra frames + if (keyframe && mode == MODE_MC) continue; - if(mode == MODE_V1_ONLY) { + if (mode == MODE_V1_ONLY) { info.v1_size = v1_size; -// the size may shrink even before optimizations if the input is short: + // the size may shrink even before optimizations if the input is short: info.v1_size = quantize(s, h, data, linesize, 1, &info, ENC_UNCERTAIN); - if(info.v1_size < v1_size) -// too few eligible blocks, no sense in trying bigger sizes + if (info.v1_size < v1_size) + // too few eligible blocks, no sense in trying bigger sizes v1enough = 1; info.v4_size = 0; } else { // mode != MODE_V1_ONLY // if v4 codebook is empty then only allow V1-only mode - if(!v4_size) + if (!v4_size) continue; - if(mode == MODE_V1_V4) { + if (mode == MODE_V1_V4) { info.v4_size = v4_size; info.v4_size = quantize(s, h, data, linesize, 0, &info, ENC_UNCERTAIN); - if(info.v4_size < v4_size) -// too few eligible blocks, no sense in trying bigger sizes + if (info.v4_size < v4_size) + // too few eligible blocks, no sense in trying bigger sizes v4enough = 1; } } info.mode = mode; -// choose the best encoding per block, based on current experience + // choose the best encoding per block, based on current experience score = calculate_mode_score(s, h, &info, 0, - &v1shrunk, &v4shrunk -#ifdef CINEPAK_REPORT_SERR -, &serr -#endif -); + &v1shrunk, &v4shrunk); - if(mode != MODE_V1_ONLY){ + if (mode != MODE_V1_ONLY) { int extra_iterations_limit = s->max_extra_cb_iterations; -// recompute the codebooks, omitting the extra blocks -// we assume we _may_ come here with more blocks to encode than before + // recompute the codebooks, omitting the extra blocks + // we assume we _may_ come here with more blocks to encode than before info.v1_size = v1_size; new_v1_size = quantize(s, h, data, linesize, 1, &info, ENC_V1); - if(new_v1_size < info.v1_size){ - //av_log(s->avctx, AV_LOG_INFO, "mode %i, %3i, %3i: cut v1 codebook to %i entries\n", mode, v1_size, v4_size, new_v1_size); + if (new_v1_size < info.v1_size) info.v1_size = new_v1_size; - } -// we assume we _may_ come here with more blocks to encode than before + // we assume we _may_ come here with more blocks to encode than before info.v4_size = v4_size; new_v4_size = quantize(s, h, data, linesize, 0, &info, ENC_V4); - if(new_v4_size < info.v4_size) { - //av_log(s->avctx, AV_LOG_INFO, "mode %i, %3i, %3i: cut v4 codebook to %i entries at first iteration\n", mode, v1_size, v4_size, new_v4_size); + if (new_v4_size < info.v4_size) info.v4_size = new_v4_size; - } -// calculate the resulting score -// (do not move blocks to codebook encodings now, as some blocks may have -// got bigger errors despite a smaller training set - but we do not -// ever grow the training sets back) - for(;;) { + // calculate the resulting score + // (do not move blocks to codebook encodings now, as some blocks may have + // got bigger errors despite a smaller training set - but we do not + // ever grow the training sets back) + for (;;) { score = calculate_mode_score(s, h, &info, 1, - &v1shrunk, &v4shrunk -#ifdef CINEPAK_REPORT_SERR -, &serr -#endif -); -// do we have a reason to reiterate? if so, have we reached the limit? - if((!v1shrunk && !v4shrunk) || !extra_iterations_limit--) break; -// recompute the codebooks, omitting the extra blocks - if(v1shrunk) { + &v1shrunk, &v4shrunk); + // do we have a reason to reiterate? if so, have we reached the limit? + if ((!v1shrunk && !v4shrunk) || !extra_iterations_limit--) + break; + // recompute the codebooks, omitting the extra blocks + if (v1shrunk) { info.v1_size = v1_size; new_v1_size = quantize(s, h, data, linesize, 1, &info, ENC_V1); - if(new_v1_size < info.v1_size){ - //av_log(s->avctx, AV_LOG_INFO, "mode %i, %3i, %3i: cut v1 codebook to %i entries\n", mode, v1_size, v4_size, new_v1_size); + if (new_v1_size < info.v1_size) info.v1_size = new_v1_size; - } } - if(v4shrunk) { + if (v4shrunk) { info.v4_size = v4_size; new_v4_size = quantize(s, h, data, linesize, 0, &info, ENC_V4); - if(new_v4_size < info.v4_size) { - //av_log(s->avctx, AV_LOG_INFO, "mode %i, %3i, %3i: cut v4 codebook to %i entries\n", mode, v1_size, v4_size, new_v4_size); + if (new_v4_size < info.v4_size) info.v4_size = new_v4_size; - } } } } - //av_log(s->avctx, AV_LOG_INFO, "%3i %3i score = %"PRId64"\n", v1_size, v4_size, score); - - if(best_size == 0 || score < *best_score) { - + if (best_size == 0 || score < *best_score) { *best_score = score; -#ifdef CINEPAK_REPORT_SERR - *best_serr = serr; -#endif best_size = encode_mode(s, h, scratch_data, scratch_linesize, last_data, last_linesize, &info, s->strip_buf + STRIP_HEADER_SIZE); - //av_log(s->avctx, AV_LOG_INFO, "mode %i, %3i, %3i: %18"PRId64" %i B", mode, info.v1_size, info.v4_size, score, best_size); - //av_log(s->avctx, AV_LOG_INFO, "\n"); -#ifdef CINEPAK_REPORT_SERR - av_log(s->avctx, AV_LOG_INFO, "mode %i, %3i, %3i: %18"PRId64" %i B\n", mode, v1_size, v4_size, serr, best_size); -#endif - -#ifdef CINEPAKENC_DEBUG - //save MB encoding choices - memcpy(s->best_mb, s->mb, mb_count*sizeof(mb_info)); -#endif - - //memcpy(strip_temp + STRIP_HEADER_SIZE, strip_temp, best_size); write_strip_header(s, y, h, keyframe, s->strip_buf, best_size); - } } } } -#ifdef CINEPAKENC_DEBUG - //gather stats. this will only work properly of MAX_STRIPS == 1 - if(best_info.mode == MODE_V1_ONLY) { - s->num_v1_mode++; - s->num_v1_encs += s->w*h/MB_AREA; - } else { - if(best_info.mode == MODE_V1_V4) - s->num_v4_mode++; - else - s->num_mc_mode++; - - int x; - for(x = 0; x < s->w*h/MB_AREA; x++) - if(s->best_mb[x].best_encoding == ENC_V1) - s->num_v1_encs++; - else if(s->best_mb[x].best_encoding == ENC_V4) - s->num_v4_encs++; - else - s->num_skips++; - } -#endif - best_size += STRIP_HEADER_SIZE; memcpy(buf, s->strip_buf, best_size); return best_size; } -static int write_cvid_header(CinepakEncContext *s, unsigned char *buf, int num_strips, int data_size, int isakeyframe) +static int write_cvid_header(CinepakEncContext *s, unsigned char *buf, + int num_strips, int data_size, int isakeyframe) { buf[0] = isakeyframe ? 0 : 1; AV_WB24(&buf[1], data_size + CVID_HEADER_SIZE); @@ -1158,91 +1002,93 @@ static int write_cvid_header(CinepakEncContext *s, unsigned char *buf, int num_s static int rd_frame(CinepakEncContext *s, const AVFrame *frame, int isakeyframe, unsigned char *buf, int buf_size) { - int num_strips, strip, i, y, nexty, size, temp_size; + int num_strips, strip, i, y, nexty, size, temp_size, best_size; uint8_t *last_data [4], *data [4], *scratch_data [4]; int last_linesize[4], linesize[4], scratch_linesize[4]; int64_t best_score = 0, score, score_temp; -#ifdef CINEPAK_REPORT_SERR - int64_t best_serr = 0, serr, serr_temp; -#endif - - int best_nstrips = -1, best_size = -1; // mark as uninitialzed + int best_nstrips; - if(s->pix_fmt == AV_PIX_FMT_RGB24) { + if (s->pix_fmt == AV_PIX_FMT_RGB24) { int x; -// build a copy of the given frame in the correct colorspace - for(y = 0; y < s->h; y += 2) { - for(x = 0; x < s->w; x += 2) { - uint8_t *ir[2]; int32_t r, g, b, rr, gg, bb; - ir[0] = frame->data[0] + x*3 + y*frame->linesize[0]; + // build a copy of the given frame in the correct colorspace + for (y = 0; y < s->h; y += 2) + for (x = 0; x < s->w; x += 2) { + uint8_t *ir[2]; + int32_t r, g, b, rr, gg, bb; + ir[0] = frame->data[0] + x * 3 + y * frame->linesize[0]; ir[1] = ir[0] + frame->linesize[0]; get_sub_picture(s, x, y, s->input_frame->data, s->input_frame->linesize, scratch_data, scratch_linesize); r = g = b = 0; - for(i=0; i<4; ++i) { + for (i = 0; i < 4; ++i) { int i1, i2; - i1 = (i&1); i2 = (i>=2); - rr = ir[i2][i1*3+0]; - gg = ir[i2][i1*3+1]; - bb = ir[i2][i1*3+2]; - r += rr; g += gg; b += bb; -// using fixed point arithmetic for portable repeatability, scaling by 2^23 -// "Y" -// rr = 0.2857*rr + 0.5714*gg + 0.1429*bb; - rr = (2396625*rr + 4793251*gg + 1198732*bb) >> 23; - if( rr < 0) rr = 0; - else if (rr > 255) rr = 255; - scratch_data[0][i1 + i2*scratch_linesize[0]] = rr; + i1 = (i & 1); + i2 = (i >= 2); + rr = ir[i2][i1 * 3 + 0]; + gg = ir[i2][i1 * 3 + 1]; + bb = ir[i2][i1 * 3 + 2]; + r += rr; + g += gg; + b += bb; + // using fixed point arithmetic for portable repeatability, scaling by 2^23 + // "Y" + // rr = 0.2857 * rr + 0.5714 * gg + 0.1429 * bb; + rr = (2396625 * rr + 4793251 * gg + 1198732 * bb) >> 23; + if (rr < 0) + rr = 0; + else if (rr > 255) + rr = 255; + scratch_data[0][i1 + i2 * scratch_linesize[0]] = rr; } -// let us scale down as late as possible -// r /= 4; g /= 4; b /= 4; -// "U" -// rr = -0.1429*r - 0.2857*g + 0.4286*b; - rr = (-299683*r - 599156*g + 898839*b) >> 23; - if( rr < -128) rr = -128; - else if (rr > 127) rr = 127; + // let us scale down as late as possible + // r /= 4; g /= 4; b /= 4; + // "U" + // rr = -0.1429 * r - 0.2857 * g + 0.4286 * b; + rr = (-299683 * r - 599156 * g + 898839 * b) >> 23; + if (rr < -128) + rr = -128; + else if (rr > 127) + rr = 127; scratch_data[1][0] = rr + 128; // quantize needs unsigned -// "V" -// rr = 0.3571*r - 0.2857*g - 0.0714*b; - rr = (748893*r - 599156*g - 149737*b) >> 23; - if( rr < -128) rr = -128; - else if (rr > 127) rr = 127; + // "V" + // rr = 0.3571 * r - 0.2857 * g - 0.0714 * b; + rr = (748893 * r - 599156 * g - 149737 * b) >> 23; + if (rr < -128) + rr = -128; + else if (rr > 127) + rr = 127; scratch_data[2][0] = rr + 128; // quantize needs unsigned } - } } - //would be nice but quite certainly incompatible with vintage players: + // would be nice but quite certainly incompatible with vintage players: // support encoding zero strips (meaning skip the whole frame) - for(num_strips = s->min_strips; num_strips <= s->max_strips && num_strips <= s->h / MB_SIZE; num_strips++) { + for (num_strips = s->min_strips; num_strips <= s->max_strips && num_strips <= s->h / MB_SIZE; num_strips++) { score = 0; - size = 0; -#ifdef CINEPAK_REPORT_SERR - serr = 0; -#endif + size = 0; - for(y = 0, strip = 1; y < s->h; strip++, y = nexty) { + for (y = 0, strip = 1; y < s->h; strip++, y = nexty) { int strip_height; nexty = strip * s->h / num_strips; // <= s->h - //make nexty the next multiple of 4 if not already there - if(nexty & 3) + // make nexty the next multiple of 4 if not already there + if (nexty & 3) nexty += 4 - (nexty & 3); strip_height = nexty - y; - if(strip_height <= 0) { // can this ever happen? + if (strip_height <= 0) { // can this ever happen? av_log(s->avctx, AV_LOG_INFO, "skipping zero height strip %i of %i\n", strip, num_strips); continue; } - if(s->pix_fmt == AV_PIX_FMT_RGB24) + if (s->pix_fmt == AV_PIX_FMT_RGB24) get_sub_picture(s, 0, y, s->input_frame->data, s->input_frame->linesize, data, linesize); else get_sub_picture(s, 0, y, - (uint8_t **)frame->data, (int*)frame->linesize, + (uint8_t **)frame->data, (int *)frame->linesize, data, linesize); get_sub_picture(s, 0, y, s->last_frame->data, s->last_frame->linesize, @@ -1251,68 +1097,51 @@ static int rd_frame(CinepakEncContext *s, const AVFrame *frame, s->scratch_frame->data, s->scratch_frame->linesize, scratch_data, scratch_linesize); - if((temp_size = rd_strip(s, y, strip_height, isakeyframe, - last_data, last_linesize, data, linesize, - scratch_data, scratch_linesize, - s->frame_buf + size + CVID_HEADER_SIZE, &score_temp -#ifdef CINEPAK_REPORT_SERR -, &serr_temp -#endif -)) < 0) + if ((temp_size = rd_strip(s, y, strip_height, isakeyframe, + last_data, last_linesize, data, linesize, + scratch_data, scratch_linesize, + s->frame_buf + size + CVID_HEADER_SIZE, + &score_temp)) < 0) return temp_size; score += score_temp; -#ifdef CINEPAK_REPORT_SERR - serr += serr_temp; -#endif size += temp_size; - //av_log(s->avctx, AV_LOG_INFO, "strip %d, isakeyframe=%d", strip, isakeyframe); - //av_log(s->avctx, AV_LOG_INFO, "\n"); } - if(best_score == 0 || score < best_score) { + if (best_score == 0 || score < best_score) { best_score = score; -#ifdef CINEPAK_REPORT_SERR - best_serr = serr; -#endif best_size = size + write_cvid_header(s, s->frame_buf, num_strips, size, isakeyframe); - //av_log(s->avctx, AV_LOG_INFO, "best number of strips so far: %2i, %12"PRId64", %i B\n", num_strips, score, best_size); -#ifdef CINEPAK_REPORT_SERR - av_log(s->avctx, AV_LOG_INFO, "best number of strips so far: %2i, %12"PRId64", %i B\n", num_strips, serr, best_size); -#endif FFSWAP(AVFrame *, s->best_frame, s->scratch_frame); memcpy(buf, s->frame_buf, best_size); best_nstrips = num_strips; } -// avoid trying too many strip numbers without a real reason -// (this makes the processing of the very first frame faster) - if(num_strips - best_nstrips > 4) + // avoid trying too many strip numbers without a real reason + // (this makes the processing of the very first frame faster) + if (num_strips - best_nstrips > 4) break; } - av_assert0(best_nstrips >= 0 && best_size >= 0); - -// let the number of strips slowly adapt to the changes in the contents, -// compared to full bruteforcing every time this will occasionally lead -// to some r/d performance loss but makes encoding up to several times faster - if(!s->strip_number_delta_range) { - if(best_nstrips == s->max_strips) { // let us try to step up + // let the number of strips slowly adapt to the changes in the contents, + // compared to full bruteforcing every time this will occasionally lead + // to some r/d performance loss but makes encoding up to several times faster + if (!s->strip_number_delta_range) { + if (best_nstrips == s->max_strips) { // let us try to step up s->max_strips = best_nstrips + 1; - if(s->max_strips >= s->max_max_strips) + if (s->max_strips >= s->max_max_strips) s->max_strips = s->max_max_strips; } else { // try to step down s->max_strips = best_nstrips; } s->min_strips = s->max_strips - 1; - if(s->min_strips < s->min_min_strips) + if (s->min_strips < s->min_min_strips) s->min_strips = s->min_min_strips; } else { s->max_strips = best_nstrips + s->strip_number_delta_range; - if(s->max_strips >= s->max_max_strips) + if (s->max_strips >= s->max_max_strips) s->max_strips = s->max_max_strips; s->min_strips = best_nstrips - s->strip_number_delta_range; - if(s->min_strips < s->min_min_strips) + if (s->min_strips < s->min_min_strips) s->min_strips = s->min_min_strips; } @@ -1329,7 +1158,7 @@ static int cinepak_encode_frame(AVCodecContext *avctx, AVPacket *pkt, if ((ret = ff_alloc_packet2(avctx, pkt, s->frame_buf_size, 0)) < 0) return ret; - ret = rd_frame(s, frame, (s->curframe == 0), pkt->data, s->frame_buf_size); + ret = rd_frame(s, frame, (s->curframe == 0), pkt->data, s->frame_buf_size); pkt->size = ret; if (s->curframe == 0) pkt->flags |= AV_PKT_FLAG_KEY; @@ -1358,30 +1187,22 @@ static av_cold int cinepak_encode_end(AVCodecContext *avctx) av_freep(&s->strip_buf); av_freep(&s->frame_buf); av_freep(&s->mb); -#ifdef CINEPAKENC_DEBUG - av_freep(&s->best_mb); -#endif - for(x = 0; x < (avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 4 : 3); x++) + for (x = 0; x < (avctx->pix_fmt == AV_PIX_FMT_RGB24 ? 4 : 3); x++) av_freep(&s->pict_bufs[x]); -#ifdef CINEPAKENC_DEBUG - av_log(avctx, AV_LOG_INFO, "strip coding stats: %i V1 mode, %i V4 mode, %i MC mode (%i V1 encs, %i V4 encs, %i skips)\n", - s->num_v1_mode, s->num_v4_mode, s->num_mc_mode, s->num_v1_encs, s->num_v4_encs, s->num_skips); -#endif - return 0; } AVCodec ff_cinepak_encoder = { .name = "cinepak", + .long_name = NULL_IF_CONFIG_SMALL("Cinepak"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_CINEPAK, .priv_data_size = sizeof(CinepakEncContext), .init = cinepak_encode_init, .encode2 = cinepak_encode_frame, .close = cinepak_encode_end, - .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_RGB24, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE}, - .long_name = NULL_IF_CONFIG_SMALL("Cinepak"), + .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_RGB24, AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE }, .priv_class = &cinepak_class, }; diff --git a/libavcodec/clearvideo.c b/libavcodec/clearvideo.c index 067942a131666..6061cb571ea20 100644 --- a/libavcodec/clearvideo.c +++ b/libavcodec/clearvideo.c @@ -1,6 +1,6 @@ /* * ClearVideo decoder - * Copyright (c) 2012 Konstantin Shishkov + * Copyright (c) 2012-2018 Konstantin Shishkov * * This file is part of FFmpeg. * @@ -25,107 +25,56 @@ */ #include "avcodec.h" +#include "bytestream.h" +#include "get_bits.h" #include "idctdsp.h" #include "internal.h" -#include "get_bits.h" -#include "bytestream.h" - -#define NUM_DC_CODES 127 -#define NUM_AC_CODES 103 - -static const uint8_t clv_dc_codes[NUM_DC_CODES] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x13, 0x14, 0x07, 0x0B, - 0x0C, 0x08, 0x08, 0x09, 0x04, 0x06, 0x07, 0x05, - 0x04, 0x05, 0x04, 0x06, 0x05, 0x06, 0x07, 0x05, - 0x06, 0x07, 0x06, 0x07, 0x08, 0x06, 0x07, 0x08, - 0x09, 0x0A, 0x0B, 0x07, 0x08, 0x09, 0x07, 0x08, - 0x06, 0x07, 0x08, 0x06, 0x04, 0x05, 0x02, 0x01, - 0x03, 0x06, 0x07, 0x07, 0x09, 0x0A, 0x0B, 0x09, - 0x0A, 0x0B, 0x0A, 0x0B, 0x0C, 0x0D, 0x0C, 0x09, - 0x0D, 0x0A, 0x0B, 0x08, 0x09, 0x0A, 0x0B, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x06, 0x07, 0x06, 0x08, - 0x07, 0x09, 0x0A, 0x0B, 0x09, 0x0A, 0x0B, 0x0C, - 0x14, 0x0D, 0x0D, 0x0E, 0x0F, 0x15, 0x15, 0x16, - 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, - 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, -}; - -static const uint8_t clv_dc_bits[NUM_DC_CODES] = { - 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 21, 22, 22, 19, 20, - 20, 19, 18, 18, 15, 17, 17, 16, - 14, 15, 12, 13, 14, 14, 14, 12, - 12, 12, 11, 11, 11, 10, 10, 10, - 10, 10, 10, 9, 9, 9, 8, 8, - 7, 7, 7, 6, 5, 5, 3, 1, - 3, 5, 5, 6, 7, 7, 7, 8, - 8, 8, 9, 9, 9, 9, 10, 11, - 10, 11, 11, 12, 12, 12, 12, 13, - 14, 14, 14, 14, 15, 15, 16, 17, - 16, 17, 18, 18, 19, 19, 19, 19, - 21, 19, 20, 19, 19, 21, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, -}; - -static const uint16_t clv_ac_syms[NUM_AC_CODES] = { - 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, - 0x0009, 0x000A, 0x000B, 0x000C, 0x0011, 0x0012, 0x0013, 0x0014, - 0x0015, 0x0016, 0x0021, 0x0022, 0x0023, 0x0024, 0x0031, 0x0032, - 0x0033, 0x0041, 0x0042, 0x0043, 0x0051, 0x0052, 0x0053, 0x0061, - 0x0062, 0x0063, 0x0071, 0x0072, 0x0081, 0x0082, 0x0091, 0x0092, - 0x00A1, 0x00A2, 0x00B1, 0x00C1, 0x00D1, 0x00E1, 0x00F1, 0x0101, - 0x0111, 0x0121, 0x0131, 0x0141, 0x0151, 0x0161, 0x0171, 0x0181, - 0x0191, 0x01A1, 0x1001, 0x1002, 0x1003, 0x1011, 0x1012, 0x1021, - 0x1031, 0x1041, 0x1051, 0x1061, 0x1071, 0x1081, 0x1091, 0x10A1, - 0x10B1, 0x10C1, 0x10D1, 0x10E1, 0x10F1, 0x1101, 0x1111, 0x1121, - 0x1131, 0x1141, 0x1151, 0x1161, 0x1171, 0x1181, 0x1191, 0x11A1, - 0x11B1, 0x11C1, 0x11D1, 0x11E1, 0x11F1, 0x1201, 0x1211, 0x1221, - 0x1231, 0x1241, 0x1251, 0x1261, 0x1271, 0x1281, 0x1BFF, -}; - -static const uint8_t clv_ac_codes[NUM_AC_CODES] = { - 0x02, 0x0F, 0x15, 0x17, 0x1F, 0x25, 0x24, 0x21, - 0x20, 0x07, 0x06, 0x20, 0x06, 0x14, 0x1E, 0x0F, - 0x21, 0x50, 0x0E, 0x1D, 0x0E, 0x51, 0x0D, 0x23, - 0x0D, 0x0C, 0x22, 0x52, 0x0B, 0x0C, 0x53, 0x13, - 0x0B, 0x54, 0x12, 0x0A, 0x11, 0x09, 0x10, 0x08, - 0x16, 0x55, 0x15, 0x14, 0x1C, 0x1B, 0x21, 0x20, - 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x22, 0x23, - 0x56, 0x57, 0x07, 0x19, 0x05, 0x0F, 0x04, 0x0E, - 0x0D, 0x0C, 0x13, 0x12, 0x11, 0x10, 0x1A, 0x19, - 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x18, 0x17, - 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x07, 0x06, - 0x05, 0x04, 0x24, 0x25, 0x26, 0x27, 0x58, 0x59, - 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x03, -}; - -static const uint8_t clv_ac_bits[NUM_AC_CODES] = { - 2, 4, 6, 7, 8, 9, 9, 10, - 10, 11, 11, 11, 3, 6, 8, 10, - 11, 12, 4, 8, 10, 12, 5, 9, - 10, 5, 9, 12, 5, 10, 12, 6, - 10, 12, 6, 10, 6, 10, 6, 10, - 7, 12, 7, 7, 8, 8, 9, 9, - 9, 9, 9, 9, 9, 9, 11, 11, - 12, 12, 4, 9, 11, 6, 11, 6, - 6, 6, 7, 7, 7, 7, 8, 8, - 8, 8, 8, 8, 8, 8, 9, 9, - 9, 9, 9, 9, 9, 9, 10, 10, - 10, 10, 11, 11, 11, 11, 12, 12, - 12, 12, 12, 12, 12, 12, 7, -}; +#include "mathops.h" +#include "clearvideodata.h" + +typedef struct LevelCodes { + uint16_t mv_esc; + uint16_t bias_esc; + VLC flags_cb; + VLC mv_cb; + VLC bias_cb; +} LevelCodes; + +typedef struct MV { + int16_t x, y; +} MV; + +static const MV zero_mv = { 0 }; + +typedef struct MVInfo { + int mb_w; + int mb_h; + int mb_size; + int mb_stride; + int top; + MV *mv; +} MVInfo; + +typedef struct TileInfo { + uint16_t flags; + int16_t bias; + MV mv; + struct TileInfo *child[4]; +} TileInfo; typedef struct CLVContext { AVCodecContext *avctx; IDCTDSPContext idsp; AVFrame *pic; + AVFrame *prev; GetBitContext gb; int mb_width, mb_height; + int pmb_width, pmb_height; + MVInfo mvi; + int tile_size; + int tile_shift; VLC dc_vlc, ac_vlc; + LevelCodes ylev[4], ulev[3], vlev[3]; int luma_dc_quant, chroma_dc_quant, ac_quant; DECLARE_ALIGNED(16, int16_t, block)[64]; int top_dc[3], left_dc[4]; @@ -179,12 +128,12 @@ static inline int decode_block(CLVContext *ctx, int16_t *blk, int has_ac, } #define DCT_TEMPLATE(blk, step, bias, shift, dshift, OP) \ - const int t0 = OP( 2841 * blk[1 * step] + 565 * blk[7 * step]); \ - const int t1 = OP( 565 * blk[1 * step] - 2841 * blk[7 * step]); \ - const int t2 = OP( 1609 * blk[5 * step] + 2408 * blk[3 * step]); \ - const int t3 = OP( 2408 * blk[5 * step] - 1609 * blk[3 * step]); \ - const int t4 = OP( 1108 * blk[2 * step] - 2676 * blk[6 * step]); \ - const int t5 = OP( 2676 * blk[2 * step] + 1108 * blk[6 * step]); \ + const int t0 = OP(2841 * blk[1 * step] + 565 * blk[7 * step]); \ + const int t1 = OP( 565 * blk[1 * step] - 2841 * blk[7 * step]); \ + const int t2 = OP(1609 * blk[5 * step] + 2408 * blk[3 * step]); \ + const int t3 = OP(2408 * blk[5 * step] - 1609 * blk[3 * step]); \ + const int t4 = OP(1108 * blk[2 * step] - 2676 * blk[6 * step]); \ + const int t5 = OP(2676 * blk[2 * step] + 1108 * blk[6 * step]); \ const int t6 = ((blk[0 * step] + blk[4 * step]) * (1 << dshift)) + bias; \ const int t7 = ((blk[0 * step] - blk[4 * step]) * (1 << dshift)) + bias; \ const int t8 = t0 + t2; \ @@ -225,9 +174,7 @@ static void clv_dct(int16_t *block) static int decode_mb(CLVContext *c, int x, int y) { - int i; - int has_ac[6]; - int off; + int i, has_ac[6], off; for (i = 0; i < 6; i++) has_ac[i] = get_bits1(&c->gb); @@ -247,7 +194,8 @@ static int decode_mb(CLVContext *c, int x, int y) clv_dct(c->block); if (i == 2) off += c->pic->linesize[0] * 8; - c->idsp.put_pixels_clamped(c->block, c->pic->data[0] + off + (i & 1) * 8, + c->idsp.put_pixels_clamped(c->block, + c->pic->data[0] + off + (i & 1) * 8, c->pic->linesize[0]); } @@ -271,6 +219,283 @@ static int decode_mb(CLVContext *c, int x, int y) return 0; } +static int copy_block(AVCodecContext *avctx, AVFrame *dst, AVFrame *src, + int plane, int x, int y, int dx, int dy, int size) +{ + int shift = plane > 0; + int sx = x + dx; + int sy = y + dy; + int sstride, dstride, soff, doff; + uint8_t *sbuf, *dbuf; + int i; + + if (x < 0 || sx < 0 || y < 0 || sy < 0 || + x + size > avctx->coded_width >> shift || + y + size > avctx->coded_height >> shift || + sx + size > avctx->coded_width >> shift || + sy + size > avctx->coded_height >> shift) + return AVERROR_INVALIDDATA; + + sstride = src->linesize[plane]; + dstride = dst->linesize[plane]; + soff = sx + sy * sstride; + sbuf = src->data[plane]; + doff = x + y * dstride; + dbuf = dst->data[plane]; + + for (i = 0; i < size; i++) { + uint8_t *dptr = &dbuf[doff]; + uint8_t *sptr = &sbuf[soff]; + + memcpy(dptr, sptr, size); + doff += dstride; + soff += sstride; + } + + return 0; +} + +static int copyadd_block(AVCodecContext *avctx, AVFrame *dst, AVFrame *src, + int plane, int x, int y, int dx, int dy, int size, int bias) +{ + int shift = plane > 0; + int sx = x + dx; + int sy = y + dy; + int sstride = src->linesize[plane]; + int dstride = dst->linesize[plane]; + int soff = sx + sy * sstride; + uint8_t *sbuf = src->data[plane]; + int doff = x + y * dstride; + uint8_t *dbuf = dst->data[plane]; + int i, j; + + if (x < 0 || sx < 0 || y < 0 || sy < 0 || + x + size > avctx->coded_width >> shift || + y + size > avctx->coded_height >> shift || + sx + size > avctx->coded_width >> shift || + sy + size > avctx->coded_height >> shift) + return AVERROR_INVALIDDATA; + + for (j = 0; j < size; j++) { + uint8_t *dptr = &dbuf[doff]; + uint8_t *sptr = &sbuf[soff]; + + for (i = 0; i < size; i++) { + int val = sptr[i] + bias; + + dptr[i] = av_clip_uint8(val); + } + + doff += dstride; + soff += sstride; + } + + return 0; +} + +static MV mvi_predict(MVInfo *mvi, int mb_x, int mb_y, MV diff) +{ + MV res, pred_mv; + int left_mv, right_mv, top_mv, bot_mv; + + if (mvi->top) { + if (mb_x > 0) { + pred_mv = mvi->mv[mvi->mb_stride + mb_x - 1]; + } else { + pred_mv = zero_mv; + } + } else if ((mb_x == 0) || (mb_x == mvi->mb_w - 1)) { + pred_mv = mvi->mv[mb_x]; + } else { + MV A = mvi->mv[mvi->mb_stride + mb_x - 1]; + MV B = mvi->mv[ mb_x ]; + MV C = mvi->mv[ mb_x + 1]; + pred_mv.x = mid_pred(A.x, B.x, C.x); + pred_mv.y = mid_pred(A.y, B.y, C.y); + } + + res = pred_mv; + + left_mv = -((mb_x * mvi->mb_size)); + right_mv = ((mvi->mb_w - mb_x - 1) * mvi->mb_size); + if (res.x < left_mv) { + res.x = left_mv; + } + if (res.x > right_mv) { + res.x = right_mv; + } + top_mv = -((mb_y * mvi->mb_size)); + bot_mv = ((mvi->mb_h - mb_y - 1) * mvi->mb_size); + if (res.y < top_mv) { + res.y = top_mv; + } + if (res.y > bot_mv) { + res.y = bot_mv; + } + + mvi->mv[mvi->mb_stride + mb_x].x = res.x + diff.x; + mvi->mv[mvi->mb_stride + mb_x].y = res.y + diff.y; + + return res; +} + +static void mvi_reset(MVInfo *mvi, int mb_w, int mb_h, int mb_size) +{ + mvi->top = 1; + mvi->mb_w = mb_w; + mvi->mb_h = mb_h; + mvi->mb_size = mb_size; + mvi->mb_stride = mb_w; + memset(mvi->mv, 0, sizeof(MV) * mvi->mb_stride * 2); +} + +static void mvi_update_row(MVInfo *mvi) +{ + int i; + + mvi->top = 0; + for (i = 0 ; i < mvi->mb_stride; i++) { + mvi->mv[i] = mvi->mv[mvi->mb_stride + i]; + } +} + +static TileInfo* decode_tile_info(GetBitContext *gb, LevelCodes *lc, int level) +{ + TileInfo *ti; + int i, flags = 0; + int16_t bias = 0; + MV mv = { 0 }; + + if (lc[level].flags_cb.table) { + flags = get_vlc2(gb, lc[level].flags_cb.table, lc[level].flags_cb.bits, 2); + } + + if (lc[level].mv_cb.table) { + uint16_t mv_code = get_vlc2(gb, lc[level].mv_cb.table, lc[level].mv_cb.bits, 3); + + if (mv_code != lc[level].mv_esc) { + mv.x = (int8_t)(mv_code & 0xff); + mv.y = (int8_t)(mv_code >> 8); + } else { + mv.x = get_sbits(gb, 8); + mv.y = get_sbits(gb, 8); + } + } + + if (lc[level].bias_cb.table) { + uint16_t bias_val = get_vlc2(gb, lc[level].bias_cb.table, lc[level].bias_cb.bits, 2); + + if (bias_val != lc[level].bias_esc) { + bias = (int16_t)(bias_val); + } else { + bias = get_sbits(gb, 16); + } + } + + ti = av_calloc(1, sizeof(*ti)); + if (!ti) + return NULL; + + ti->flags = flags; + ti->mv = mv; + ti->bias = bias; + + if (ti->flags) { + for (i = 0; i < 4; i++) { + if (ti->flags & (1 << i)) { + TileInfo *subti = decode_tile_info(gb, lc, level + 1); + ti->child[i] = subti; + } + } + } + + return ti; +} + +static int tile_do_block(AVCodecContext *avctx, AVFrame *dst, AVFrame *src, + int plane, int x, int y, int dx, int dy, int size, int bias) +{ + int ret; + + if (!bias) { + ret = copy_block(avctx, dst, src, plane, x, y, dx, dy, size); + } else { + ret = copyadd_block(avctx, dst, src, plane, x, y, dx, dy, size, bias); + } + + return ret; +} + +static int restore_tree(AVCodecContext *avctx, AVFrame *dst, AVFrame *src, + int plane, int x, int y, int size, + TileInfo *tile, MV root_mv) +{ + int ret; + MV mv; + + mv.x = root_mv.x + tile->mv.x; + mv.y = root_mv.y + tile->mv.y; + + if (!tile->flags) { + ret = tile_do_block(avctx, dst, src, plane, x, y, mv.x, mv.y, size, tile->bias); + } else { + int i, hsize = size >> 1; + + for (i = 0; i < 4; i++) { + int xoff = (i & 2) == 0 ? 0 : hsize; + int yoff = (i & 1) == 0 ? 0 : hsize; + + if (tile->child[i]) { + ret = restore_tree(avctx, dst, src, plane, x + xoff, y + yoff, hsize, tile->child[i], root_mv); + av_freep(&tile->child[i]); + } else { + ret = tile_do_block(avctx, dst, src, plane, x + xoff, y + yoff, mv.x, mv.y, hsize, tile->bias); + } + } + } + + return ret; +} + +static void extend_edges(AVFrame *buf, int tile_size) +{ + int comp, i, j; + + for (comp = 0; comp < 3; comp++) { + int shift = comp > 0; + int w = buf->width >> shift; + int h = buf->height >> shift; + int size = comp == 0 ? tile_size : tile_size >> 1; + int stride = buf->linesize[comp]; + uint8_t *framebuf = buf->data[comp]; + + int right = size - (w & (size - 1)); + int bottom = size - (h & (size - 1)); + + if ((right == size) && (bottom == size)) { + return; + } + if (right != size) { + int off = w; + for (j = 0; j < h; j++) { + for (i = 0; i < right; i++) { + framebuf[off + i] = 0x80; + } + off += stride; + } + } + if (bottom != size) { + int off = h * stride; + for (j = 0; j < bottom; j++) { + for (i = 0; i < stride; i++) { + framebuf[off + i] = 0x80; + } + off += stride; + } + } + } +} + static int clv_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { @@ -279,19 +504,24 @@ static int clv_decode_frame(AVCodecContext *avctx, void *data, CLVContext *c = avctx->priv_data; GetByteContext gb; uint32_t frame_type; - int i, j; - int ret; + int i, j, ret; int mb_ret = 0; bytestream2_init(&gb, buf, buf_size); - if (avctx->codec_tag == MKTAG('C','L','V','1')) { + if (avctx->codec_tag == MKTAG('C', 'L', 'V', '1')) { int skip = bytestream2_get_byte(&gb); bytestream2_skip(&gb, (skip + 1) * 8); } frame_type = bytestream2_get_byte(&gb); - if (frame_type & 0x2) { + if ((frame_type & 0x7f) == 0x30) { + if ((ret = ff_reget_buffer(avctx, c->pic)) < 0) + return ret; + + c->pic->key_frame = 0; + c->pic->pict_type = AV_PICTURE_TYPE_P; + } else if (frame_type & 0x2) { if (buf_size < c->mb_width * c->mb_height) { av_log(avctx, AV_LOG_ERROR, "Packet too small\n"); return AVERROR_INVALIDDATA; @@ -300,8 +530,8 @@ static int clv_decode_frame(AVCodecContext *avctx, void *data, if ((ret = ff_reget_buffer(avctx, c->pic)) < 0) return ret; - c->pic->key_frame = frame_type & 0x20 ? 1 : 0; - c->pic->pict_type = frame_type & 0x20 ? AV_PICTURE_TYPE_I : AV_PICTURE_TYPE_P; + c->pic->key_frame = 1; + c->pic->pict_type = AV_PICTURE_TYPE_I; bytestream2_get_be32(&gb); // frame size; c->ac_quant = bytestream2_get_byte(&gb); @@ -309,7 +539,7 @@ static int clv_decode_frame(AVCodecContext *avctx, void *data, c->chroma_dc_quant = 32; if ((ret = init_get_bits8(&c->gb, buf + bytestream2_tell(&gb), - (buf_size - bytestream2_tell(&gb)))) < 0) + buf_size - bytestream2_tell(&gb))) < 0) return ret; for (i = 0; i < 3; i++) @@ -324,33 +554,137 @@ static int clv_decode_frame(AVCodecContext *avctx, void *data, mb_ret = ret; } } + extend_edges(c->pic, c->tile_size); + } else { + int plane; - if ((ret = av_frame_ref(data, c->pic)) < 0) + if ((ret = ff_reget_buffer(avctx, c->pic)) < 0) return ret; - *got_frame = 1; - } else { + ret = av_frame_copy(c->pic, c->prev); + if (ret < 0) + return ret; + + if ((ret = init_get_bits8(&c->gb, buf + bytestream2_tell(&gb), + buf_size - bytestream2_tell(&gb))) < 0) + return ret; + + mvi_reset(&c->mvi, c->pmb_width, c->pmb_height, 1 << c->tile_shift); + + for (j = 0; j < c->pmb_height; j++) { + for (i = 0; i < c->pmb_width; i++) { + if (get_bits1(&c->gb)) { + MV mv = mvi_predict(&c->mvi, i, j, zero_mv); + + for (plane = 0; plane < 3; plane++) { + int16_t x = plane == 0 ? i << c->tile_shift : i << (c->tile_shift - 1); + int16_t y = plane == 0 ? j << c->tile_shift : j << (c->tile_shift - 1); + int16_t size = plane == 0 ? 1 << c->tile_shift : 1 << (c->tile_shift - 1); + int16_t mx = plane == 0 ? mv.x : mv.x / 2; + int16_t my = plane == 0 ? mv.y : mv.y / 2; + + ret = copy_block(avctx, c->pic, c->prev, plane, x, y, mx, my, size); + if (ret < 0) + mb_ret = ret; + } + } else { + int x = i << c->tile_shift; + int y = j << c->tile_shift; + int size = 1 << c->tile_shift; + TileInfo *tile; + MV mv, cmv; + + tile = decode_tile_info(&c->gb, c->ylev, 0); + if (!tile) + return AVERROR(ENOMEM); + mv = mvi_predict(&c->mvi, i, j, tile->mv); + ret = restore_tree(avctx, c->pic, c->prev, 0, x, y, size, tile, mv); + if (ret < 0) + mb_ret = ret; + x = i << (c->tile_shift - 1); + y = j << (c->tile_shift - 1); + size = 1 << (c->tile_shift - 1); + cmv.x = mv.x + tile->mv.x; + cmv.y = mv.y + tile->mv.y; + cmv.x /= 2; + cmv.y /= 2; + av_freep(&tile); + tile = decode_tile_info(&c->gb, c->ulev, 0); + if (!tile) + return AVERROR(ENOMEM); + ret = restore_tree(avctx, c->pic, c->prev, 1, x, y, size, tile, cmv); + if (ret < 0) + mb_ret = ret; + av_freep(&tile); + tile = decode_tile_info(&c->gb, c->vlev, 0); + if (!tile) + return AVERROR(ENOMEM); + ret = restore_tree(avctx, c->pic, c->prev, 2, x, y, size, tile, cmv); + if (ret < 0) + mb_ret = ret; + av_freep(&tile); + } + } + mvi_update_row(&c->mvi); + } + extend_edges(c->pic, c->tile_size); + + c->pic->key_frame = 0; + c->pic->pict_type = AV_PICTURE_TYPE_P; } + if ((ret = av_frame_ref(data, c->pic)) < 0) + return ret; + + FFSWAP(AVFrame *, c->pic, c->prev); + + *got_frame = 1; + return mb_ret < 0 ? mb_ret : buf_size; } static av_cold int clv_decode_init(AVCodecContext *avctx) { - CLVContext * const c = avctx->priv_data; - int ret; + CLVContext *const c = avctx->priv_data; + int ret, w, h; + + if (avctx->extradata_size == 110) { + c->tile_size = AV_RL32(&avctx->extradata[94]); + } else if (avctx->extradata_size == 150) { + c->tile_size = AV_RB32(&avctx->extradata[134]); + } else if (!avctx->extradata_size) { + c->tile_size = 16; + } else { + av_log(avctx, AV_LOG_ERROR, "Unsupported extradata size: %d\n", avctx->extradata_size); + return AVERROR_INVALIDDATA; + } - c->avctx = avctx; + c->tile_shift = av_log2(c->tile_size); + if (1 << c->tile_shift != c->tile_size) { + av_log(avctx, AV_LOG_ERROR, "Tile size: %d, is not power of 2.\n", c->tile_size); + return AVERROR_INVALIDDATA; + } avctx->pix_fmt = AV_PIX_FMT_YUV420P; - - c->pic = av_frame_alloc(); - if (!c->pic) + w = avctx->width; + h = avctx->height; + ret = ff_set_dimensions(avctx, FFALIGN(w, 1 << c->tile_shift), FFALIGN(h, 1 << c->tile_shift)); + if (ret < 0) + return ret; + avctx->width = w; + avctx->height = h; + + c->avctx = avctx; + c->mb_width = FFALIGN(avctx->width, 16) >> 4; + c->mb_height = FFALIGN(avctx->height, 16) >> 4; + c->pmb_width = (w + c->tile_size - 1) >> c->tile_shift; + c->pmb_height = (h + c->tile_size - 1) >> c->tile_shift; + c->pic = av_frame_alloc(); + c->prev = av_frame_alloc(); + c->mvi.mv = av_calloc(c->pmb_width * 2, sizeof(*c->mvi.mv)); + if (!c->pic || !c->prev || !c->mvi.mv) return AVERROR(ENOMEM); - c->mb_width = FFALIGN(avctx->width, 16) >> 4; - c->mb_height = FFALIGN(avctx->height, 16) >> 4; - ff_idctdsp_init(&c->idsp, avctx); ret = init_vlc(&c->dc_vlc, 9, NUM_DC_CODES, clv_dc_bits, 1, 1, @@ -368,23 +702,205 @@ static av_cold int clv_decode_init(AVCodecContext *avctx) return ret; } + ret = init_vlc(&c->ylev[0].flags_cb, 9, FF_ARRAY_ELEMS(clv_flagsy_0_bits), + clv_flagsy_0_bits, 1, 1, + clv_flagsy_0_codes, 2, 2, 0); + if (ret) + return ret; + + ret = init_vlc(&c->ylev[1].flags_cb, 9, FF_ARRAY_ELEMS(clv_flagsy_1_bits), + clv_flagsy_1_bits, 1, 1, + clv_flagsy_1_codes, 2, 2, 0); + if (ret) + return ret; + + ret = init_vlc(&c->ylev[2].flags_cb, 9, FF_ARRAY_ELEMS(clv_flagsy_2_bits), + clv_flagsy_2_bits, 1, 1, + clv_flagsy_2_codes, 2, 2, 0); + if (ret) + return ret; + + ret = init_vlc(&c->ulev[0].flags_cb, 9, FF_ARRAY_ELEMS(clv_flagsu_0_bits), + clv_flagsu_0_bits, 1, 1, + clv_flagsu_0_codes, 2, 2, 0); + if (ret) + return ret; + + ret = init_vlc(&c->ulev[1].flags_cb, 9, FF_ARRAY_ELEMS(clv_flagsu_1_bits), + clv_flagsu_1_bits, 1, 1, + clv_flagsu_1_codes, 2, 2, 0); + if (ret) + return ret; + + ret = init_vlc(&c->vlev[0].flags_cb, 9, FF_ARRAY_ELEMS(clv_flagsv_0_bits), + clv_flagsv_0_bits, 1, 1, + clv_flagsv_0_codes, 2, 2, 0); + if (ret) + return ret; + + ret = init_vlc(&c->vlev[1].flags_cb, 9, FF_ARRAY_ELEMS(clv_flagsv_1_bits), + clv_flagsv_1_bits, 1, 1, + clv_flagsv_1_codes, 2, 2, 0); + if (ret) + return ret; + + ret = ff_init_vlc_sparse(&c->ylev[0].mv_cb, 9, FF_ARRAY_ELEMS(clv_mvy_0_bits), + clv_mvy_0_bits, 1, 1, + clv_mvy_0_codes, 2, 2, + clv_mvy_0_syms, 2, 2, 0); + if (ret) + return ret; + + ret = ff_init_vlc_sparse(&c->ylev[1].mv_cb, 9, FF_ARRAY_ELEMS(clv_mvy_1_bits), + clv_mvy_1_bits, 1, 1, + clv_mvy_1_codes, 2, 2, + clv_mvy_1_syms, 2, 2, 0); + if (ret) + return ret; + + ret = ff_init_vlc_sparse(&c->ylev[2].mv_cb, 9, FF_ARRAY_ELEMS(clv_mvy_2_bits), + clv_mvy_2_bits, 1, 1, + clv_mvy_2_codes, 2, 2, + clv_mvy_2_syms, 2, 2, 0); + if (ret) + return ret; + + ret = ff_init_vlc_sparse(&c->ylev[3].mv_cb, 9, FF_ARRAY_ELEMS(clv_mvy_3_bits), + clv_mvy_3_bits, 1, 1, + clv_mvy_3_codes, 2, 2, + clv_mvy_3_syms, 2, 2, 0); + if (ret) + return ret; + + ret = ff_init_vlc_sparse(&c->ulev[1].mv_cb, 9, FF_ARRAY_ELEMS(clv_mvu_1_bits), + clv_mvu_1_bits, 1, 1, + clv_mvu_1_codes, 2, 2, + clv_mvu_1_syms, 2, 2, 0); + if (ret) + return ret; + + ret = ff_init_vlc_sparse(&c->ulev[2].mv_cb, 9, FF_ARRAY_ELEMS(clv_mvu_2_bits), + clv_mvu_2_bits, 1, 1, + clv_mvu_2_codes, 2, 2, + clv_mvu_2_syms, 2, 2, 0); + if (ret) + return ret; + + ret = ff_init_vlc_sparse(&c->vlev[1].mv_cb, 9, FF_ARRAY_ELEMS(clv_mvv_1_bits), + clv_mvv_1_bits, 1, 1, + clv_mvv_1_codes, 2, 2, + clv_mvv_1_syms, 2, 2, 0); + if (ret) + return ret; + + ret = ff_init_vlc_sparse(&c->vlev[2].mv_cb, 9, FF_ARRAY_ELEMS(clv_mvv_2_bits), + clv_mvv_2_bits, 1, 1, + clv_mvv_2_codes, 2, 2, + clv_mvv_2_syms, 2, 2, 0); + if (ret) + return ret; + + ret = ff_init_vlc_sparse(&c->ylev[1].bias_cb, 9, FF_ARRAY_ELEMS(clv_biasy_1_bits), + clv_biasy_1_bits, 1, 1, + clv_biasy_1_codes, 2, 2, + clv_biasy_1_syms, 2, 2, 0); + if (ret) + return ret; + + ret = ff_init_vlc_sparse(&c->ylev[2].bias_cb, 9, FF_ARRAY_ELEMS(clv_biasy_2_bits), + clv_biasy_2_bits, 1, 1, + clv_biasy_2_codes, 2, 2, + clv_biasy_2_syms, 2, 2, 0); + if (ret) + return ret; + + ret = ff_init_vlc_sparse(&c->ylev[3].bias_cb, 9, FF_ARRAY_ELEMS(clv_biasy_3_bits), + clv_biasy_3_bits, 1, 1, + clv_biasy_3_codes, 2, 2, + clv_biasy_3_syms, 2, 2, 0); + if (ret) + return ret; + + ret = ff_init_vlc_sparse(&c->ulev[1].bias_cb, 9, FF_ARRAY_ELEMS(clv_biasu_1_bits), + clv_biasu_1_bits, 1, 1, + clv_biasu_1_codes, 2, 2, + clv_biasu_1_syms, 2, 2, 0); + if (ret) + return ret; + + ret = ff_init_vlc_sparse(&c->ulev[2].bias_cb, 9, FF_ARRAY_ELEMS(clv_biasu_2_bits), + clv_biasu_2_bits, 1, 1, + clv_biasu_2_codes, 2, 2, + clv_biasu_2_syms, 2, 2, 0); + if (ret) + return ret; + + ret = ff_init_vlc_sparse(&c->vlev[1].bias_cb, 9, FF_ARRAY_ELEMS(clv_biasv_1_bits), + clv_biasv_1_bits, 1, 1, + clv_biasv_1_codes, 2, 2, + clv_biasv_1_syms, 2, 2, 0); + if (ret) + return ret; + + ret = ff_init_vlc_sparse(&c->vlev[2].bias_cb, 9, FF_ARRAY_ELEMS(clv_biasv_2_bits), + clv_biasv_2_bits, 1, 1, + clv_biasv_2_codes, 2, 2, + clv_biasv_2_syms, 2, 2, 0); + if (ret) + return ret; + + c->ylev[0].mv_esc = 0x0909; + c->ylev[1].mv_esc = 0x0A0A; + c->ylev[2].mv_esc = 0x1010; + c->ylev[3].mv_esc = 0x1313; + c->ulev[1].mv_esc = 0x0808; + c->ulev[2].mv_esc = 0x0B0B; + c->vlev[1].mv_esc = 0x0808; + c->vlev[2].mv_esc = 0x0B0B; + + c->ylev[1].bias_esc = 0x100; + c->ylev[2].bias_esc = 0x100; + c->ylev[3].bias_esc = 0x100; + c->ulev[1].bias_esc = 0x100; + c->ulev[2].bias_esc = 0x100; + c->vlev[1].bias_esc = 0x100; + c->vlev[2].bias_esc = 0x100; + return 0; } static av_cold int clv_decode_end(AVCodecContext *avctx) { - CLVContext * const c = avctx->priv_data; + CLVContext *const c = avctx->priv_data; + int i; + av_frame_free(&c->prev); av_frame_free(&c->pic); + av_freep(&c->mvi.mv); + ff_free_vlc(&c->dc_vlc); ff_free_vlc(&c->ac_vlc); + for (i = 0; i < 4; i++) { + ff_free_vlc(&c->ylev[i].mv_cb); + ff_free_vlc(&c->ylev[i].flags_cb); + ff_free_vlc(&c->ylev[i].bias_cb); + } + for (i = 0; i < 3; i++) { + ff_free_vlc(&c->ulev[i].mv_cb); + ff_free_vlc(&c->ulev[i].flags_cb); + ff_free_vlc(&c->ulev[i].bias_cb); + ff_free_vlc(&c->vlev[i].mv_cb); + ff_free_vlc(&c->vlev[i].flags_cb); + ff_free_vlc(&c->vlev[i].bias_cb); + } return 0; } AVCodec ff_clearvideo_decoder = { .name = "clearvideo", + .long_name = NULL_IF_CONFIG_SMALL("Iterated Systems ClearVideo"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_CLEARVIDEO, .priv_data_size = sizeof(CLVContext), @@ -392,5 +908,5 @@ AVCodec ff_clearvideo_decoder = { .close = clv_decode_end, .decode = clv_decode_frame, .capabilities = AV_CODEC_CAP_DR1, - .long_name = NULL_IF_CONFIG_SMALL("Iterated Systems ClearVideo"), + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/clearvideodata.h b/libavcodec/clearvideodata.h new file mode 100644 index 0000000000000..43d12dee43458 --- /dev/null +++ b/libavcodec/clearvideodata.h @@ -0,0 +1,1832 @@ +/* + * ClearVideo decoder + * Copyright (c) 2012-2018 Konstantin Shishkov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_CLEARVIDEODATA_H +#define AVCODEC_CLEARVIDEODATA_H + +#include "libavutil/common.h" + +#define NUM_DC_CODES 127 +#define NUM_AC_CODES 103 + +static const uint8_t clv_dc_codes[NUM_DC_CODES] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x13, 0x14, 0x07, 0x0B, + 0x0C, 0x08, 0x08, 0x09, 0x04, 0x06, 0x07, 0x05, + 0x04, 0x05, 0x04, 0x06, 0x05, 0x06, 0x07, 0x05, + 0x06, 0x07, 0x06, 0x07, 0x08, 0x06, 0x07, 0x08, + 0x09, 0x0A, 0x0B, 0x07, 0x08, 0x09, 0x07, 0x08, + 0x06, 0x07, 0x08, 0x06, 0x04, 0x05, 0x02, 0x01, + 0x03, 0x06, 0x07, 0x07, 0x09, 0x0A, 0x0B, 0x09, + 0x0A, 0x0B, 0x0A, 0x0B, 0x0C, 0x0D, 0x0C, 0x09, + 0x0D, 0x0A, 0x0B, 0x08, 0x09, 0x0A, 0x0B, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x06, 0x07, 0x06, 0x08, + 0x07, 0x09, 0x0A, 0x0B, 0x09, 0x0A, 0x0B, 0x0C, + 0x14, 0x0D, 0x0D, 0x0E, 0x0F, 0x15, 0x15, 0x16, + 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, + 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, +}; + +static const uint8_t clv_dc_bits[NUM_DC_CODES] = { + 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 21, 22, 22, 19, 20, + 20, 19, 18, 18, 15, 17, 17, 16, + 14, 15, 12, 13, 14, 14, 14, 12, + 12, 12, 11, 11, 11, 10, 10, 10, + 10, 10, 10, 9, 9, 9, 8, 8, + 7, 7, 7, 6, 5, 5, 3, 1, + 3, 5, 5, 6, 7, 7, 7, 8, + 8, 8, 9, 9, 9, 9, 10, 11, + 10, 11, 11, 12, 12, 12, 12, 13, + 14, 14, 14, 14, 15, 15, 16, 17, + 16, 17, 18, 18, 19, 19, 19, 19, + 21, 19, 20, 19, 19, 21, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, +}; + +static const uint16_t clv_ac_syms[NUM_AC_CODES] = { + 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, + 0x0009, 0x000A, 0x000B, 0x000C, 0x0011, 0x0012, 0x0013, 0x0014, + 0x0015, 0x0016, 0x0021, 0x0022, 0x0023, 0x0024, 0x0031, 0x0032, + 0x0033, 0x0041, 0x0042, 0x0043, 0x0051, 0x0052, 0x0053, 0x0061, + 0x0062, 0x0063, 0x0071, 0x0072, 0x0081, 0x0082, 0x0091, 0x0092, + 0x00A1, 0x00A2, 0x00B1, 0x00C1, 0x00D1, 0x00E1, 0x00F1, 0x0101, + 0x0111, 0x0121, 0x0131, 0x0141, 0x0151, 0x0161, 0x0171, 0x0181, + 0x0191, 0x01A1, 0x1001, 0x1002, 0x1003, 0x1011, 0x1012, 0x1021, + 0x1031, 0x1041, 0x1051, 0x1061, 0x1071, 0x1081, 0x1091, 0x10A1, + 0x10B1, 0x10C1, 0x10D1, 0x10E1, 0x10F1, 0x1101, 0x1111, 0x1121, + 0x1131, 0x1141, 0x1151, 0x1161, 0x1171, 0x1181, 0x1191, 0x11A1, + 0x11B1, 0x11C1, 0x11D1, 0x11E1, 0x11F1, 0x1201, 0x1211, 0x1221, + 0x1231, 0x1241, 0x1251, 0x1261, 0x1271, 0x1281, 0x1BFF, +}; + +static const uint8_t clv_ac_codes[NUM_AC_CODES] = { + 0x02, 0x0F, 0x15, 0x17, 0x1F, 0x25, 0x24, 0x21, + 0x20, 0x07, 0x06, 0x20, 0x06, 0x14, 0x1E, 0x0F, + 0x21, 0x50, 0x0E, 0x1D, 0x0E, 0x51, 0x0D, 0x23, + 0x0D, 0x0C, 0x22, 0x52, 0x0B, 0x0C, 0x53, 0x13, + 0x0B, 0x54, 0x12, 0x0A, 0x11, 0x09, 0x10, 0x08, + 0x16, 0x55, 0x15, 0x14, 0x1C, 0x1B, 0x21, 0x20, + 0x1F, 0x1E, 0x1D, 0x1C, 0x1B, 0x1A, 0x22, 0x23, + 0x56, 0x57, 0x07, 0x19, 0x05, 0x0F, 0x04, 0x0E, + 0x0D, 0x0C, 0x13, 0x12, 0x11, 0x10, 0x1A, 0x19, + 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x18, 0x17, + 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x07, 0x06, + 0x05, 0x04, 0x24, 0x25, 0x26, 0x27, 0x58, 0x59, + 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x03, +}; + +static const uint8_t clv_ac_bits[NUM_AC_CODES] = { + 2, 4, 6, 7, 8, 9, 9, 10, + 10, 11, 11, 11, 3, 6, 8, 10, + 11, 12, 4, 8, 10, 12, 5, 9, + 10, 5, 9, 12, 5, 10, 12, 6, + 10, 12, 6, 10, 6, 10, 6, 10, + 7, 12, 7, 7, 8, 8, 9, 9, + 9, 9, 9, 9, 9, 9, 11, 11, + 12, 12, 4, 9, 11, 6, 11, 6, + 6, 6, 7, 7, 7, 7, 8, 8, + 8, 8, 8, 8, 8, 8, 9, 9, + 9, 9, 9, 9, 9, 9, 10, 10, + 10, 10, 11, 11, 11, 11, 12, 12, + 12, 12, 12, 12, 12, 12, 7, +}; + +static const uint8_t clv_flagsy_0_bits[] = { + 3, 4, 4, 4, 4, 4, 6, 5, 4, 7, 4, 5, 4, 7, 5, 2, +}; + +static const uint16_t clv_flagsy_0_codes[] = { + 0x0002, 0x0009, 0x000B, 0x0006, 0x000C, 0x0007, 0x003E, 0x001C, + 0x000D, 0x007E, 0x000A, 0x001D, 0x0008, 0x007F, 0x001E, 0x0000, +}; + +static const uint8_t clv_flagsy_1_bits[] = { + 2, 4, 4, 3, 4, 4, 7, 6, 4, 6, 4, 6, 4, 8, 8, 3, +}; + +static const uint16_t clv_flagsy_1_codes[] = { + 0x0000, 0x000A, 0x000C, 0x0003, 0x000B, 0x0009, 0x007E, 0x003D, + 0x000D, 0x003E, 0x000E, 0x003C, 0x0008, 0x00FE, 0x00FF, 0x0002, +}; + +static const uint8_t clv_flagsy_2_bits[] = { + 1, 4, 4, 4, 4, 5, 7, 5, 4, 6, 5, 8, 4, 9, 10, 10, +}; + +static const uint16_t clv_flagsy_2_codes[] = { + 0x0000, 0x000C, 0x000B, 0x0008, 0x000A, 0x001C, 0x007E, 0x001D, + 0x000D, 0x003E, 0x001E, 0x00FE, 0x0009, 0x01FE, 0x03FE, 0x03FF, +}; + +static const uint8_t clv_flagsu_0_bits[] = { + 1, 4, 4, 4, 5, 5, 9, 7, 5, 9, 4, 7, 4, 8, 7, 4, +}; + +static const uint16_t clv_flagsu_0_codes[] = { + 0x0000, 0x000B, 0x000D, 0x0009, 0x001D, 0x001C, 0x01FF, 0x007D, + 0x001E, 0x01FE, 0x000C, 0x007C, 0x000A, 0x00FE, 0x007E, 0x0008, +}; + +static const uint8_t clv_flagsu_1_bits[] = { + 1, 4, 4, 4, 4, 4, 8, 6, 4, 8, 5, 8, 4, 10, 9, 10, +}; + +static const uint16_t clv_flagsu_1_codes[] = { + 0x0000, 0x000C, 0x0008, 0x000A, 0x000B, 0x000E, 0x00FD, 0x003E, + 0x000D, 0x00FC, 0x001E, 0x00FE, 0x0009, 0x03FE, 0x01FE, 0x03FF, +}; + +static const uint8_t clv_flagsv_0_bits[] = { + 1, 4, 5, 4, 5, 5, 8, 10, 5, 9, 5, 6, 4, 10, 7, 3, +}; + +static const uint16_t clv_flagsv_0_codes[] = { + 0x0000, 0x000A, 0x001B, 0x000C, 0x001E, 0x001C, 0x00FE, 0x03FE, + 0x001D, 0x01FE, 0x001A, 0x003E, 0x000B, 0x03FF, 0x007E, 0x0004, +}; + +static const uint8_t clv_flagsv_1_bits[] = { + 1, 4, 4, 4, 4, 5, 8, 6, 3, 7, 5, 10, 5, 11, 9, 11, +}; + +static const uint16_t clv_flagsv_1_codes[] = { + 0x0000, 0x000D, 0x000C, 0x000A, 0x000B, 0x001D, 0x00FE, 0x003E, + 0x0004, 0x007E, 0x001E, 0x03FE, 0x001C, 0x07FE, 0x01FE, 0x07FF, +}; + +static const uint8_t clv_mvy_0_bits[] = { + 16, 14, 13, 13, 13, 12, 11, 11, 9, 11, 11, 12, 13, 13, 13, 14, + 16, 15, 14, 14, 14, 13, 13, 12, 10, 7, 10, 12, 13, 13, 14, 14, + 14, 15, 15, 14, 14, 14, 13, 13, 11, 10, 7, 10, 11, 13, 13, 14, + 14, 14, 15, 15, 14, 14, 13, 13, 12, 11, 10, 7, 10, 11, 12, 13, + 13, 14, 14, 15, 16, 15, 14, 12, 12, 12, 11, 10, 6, 10, 11, 12, + 12, 12, 14, 15, 16, 15, 14, 13, 13, 12, 11, 10, 9, 6, 9, 10, + 11, 12, 13, 13, 14, 15, 14, 14, 13, 12, 12, 11, 10, 8, 6, 8, + 10, 11, 12, 12, 13, 14, 14, 14, 13, 13, 13, 11, 11, 9, 7, 4, + 7, 9, 11, 11, 12, 13, 13, 14, 11, 10, 10, 9, 9, 8, 7, 5, + 1, 5, 7, 8, 9, 9, 10, 10, 11, 14, 13, 13, 12, 11, 11, 9, + 7, 4, 7, 9, 11, 11, 13, 13, 13, 14, 14, 14, 13, 12, 12, 11, + 10, 8, 6, 8, 10, 11, 12, 12, 13, 14, 14, 15, 14, 13, 13, 12, + 11, 10, 9, 7, 9, 10, 11, 12, 13, 13, 14, 15, 16, 15, 14, 12, + 12, 12, 11, 10, 6, 10, 11, 12, 12, 12, 14, 15, 16, 15, 14, 14, + 13, 13, 12, 11, 10, 7, 10, 11, 12, 13, 13, 14, 14, 15, 15, 14, + 14, 14, 13, 13, 11, 10, 7, 10, 11, 13, 13, 14, 14, 14, 15, 15, + 14, 14, 14, 13, 13, 12, 10, 7, 10, 12, 13, 13, 14, 14, 14, 15, + 16, 14, 13, 13, 13, 12, 11, 11, 9, 11, 11, 12, 13, 13, 13, 14, + 16, 6, +}; + +static const uint16_t clv_mvy_0_codes[] = { + 0xFFFD, 0x3FE5, 0x1FD8, 0x1FC4, 0x1FBC, 0x0FCB, 0x07CF, 0x07C4, + 0x01D7, 0x07C6, 0x07CE, 0x0FCA, 0x1FBD, 0x1FC2, 0x1FD9, 0x3FE4, + 0xFFFE, 0x7FF0, 0x3FEF, 0x3FD2, 0x3FC9, 0x1FCC, 0x1FC0, 0x0FB6, + 0x03D6, 0x0070, 0x03D7, 0x0FB7, 0x1FC1, 0x1FCD, 0x3FCB, 0x3FD0, + 0x3FED, 0x7FF2, 0x7FFB, 0x3FDC, 0x3FD9, 0x3FD4, 0x1FB6, 0x1FAE, + 0x07C0, 0x03BC, 0x006D, 0x03BD, 0x07C1, 0x1FAF, 0x1FB7, 0x3FD1, + 0x3FDB, 0x3FDF, 0x7FF9, 0x7FEE, 0x3FF0, 0x3FC7, 0x1FC9, 0x1FA7, + 0x0FAD, 0x07D2, 0x03CE, 0x006C, 0x03CF, 0x07D0, 0x0FAF, 0x1FA6, + 0x1FC6, 0x3FC4, 0x3FF1, 0x7FED, 0xFFFB, 0x7FF6, 0x3FE6, 0x0FCC, + 0x0FC4, 0x0FB0, 0x07B0, 0x03C6, 0x0031, 0x03C7, 0x07B1, 0x0FB1, + 0x0FC5, 0x0FCD, 0x3FEA, 0x7FF7, 0xFFF9, 0x7FE9, 0x3FCE, 0x1FCF, + 0x1FB2, 0x0FB8, 0x07BC, 0x03D0, 0x01DA, 0x002F, 0x01DB, 0x03D1, + 0x07BE, 0x0FBA, 0x1FB4, 0x1FD0, 0x3FCD, 0x7FEB, 0x3FE1, 0x3FC1, + 0x1FD3, 0x0FC3, 0x0FBE, 0x07B6, 0x03C4, 0x00E4, 0x002D, 0x00E5, + 0x03C5, 0x07B7, 0x0FBF, 0x0FC1, 0x1FD2, 0x3FC3, 0x3FE2, 0x3FBF, + 0x1FDB, 0x1FAD, 0x1FA5, 0x07CB, 0x07BB, 0x01D5, 0x0068, 0x0008, + 0x0065, 0x01D2, 0x07B8, 0x07C8, 0x0FD0, 0x1FAA, 0x1FDA, 0x3FBC, + 0x07D4, 0x03CA, 0x03C0, 0x01D8, 0x01D0, 0x00E6, 0x0069, 0x0014, + 0x0000, 0x0015, 0x006A, 0x00E7, 0x01D1, 0x01D9, 0x03C1, 0x03CB, + 0x07D5, 0x3FBE, 0x1FDC, 0x1FAB, 0x0FD1, 0x07C9, 0x07B9, 0x01D3, + 0x0066, 0x0009, 0x0067, 0x01D4, 0x07BA, 0x07CA, 0x1FA4, 0x1FAC, + 0x1FDD, 0x3FBD, 0x3FE0, 0x3FC0, 0x1FD5, 0x0FC0, 0x0FBC, 0x07B4, + 0x03C2, 0x00E2, 0x002C, 0x00E3, 0x03C3, 0x07B5, 0x0FBD, 0x0FC2, + 0x1FD7, 0x3FC2, 0x3FE3, 0x7FEA, 0x3FCC, 0x1FCE, 0x1FB3, 0x0FB9, + 0x07BD, 0x03D2, 0x01DC, 0x0064, 0x01DD, 0x03D3, 0x07BF, 0x0FBB, + 0x1FB5, 0x1FD1, 0x3FCF, 0x7FE8, 0xFFFA, 0x7FF4, 0x3FEB, 0x0FCE, + 0x0FC6, 0x0FB2, 0x07B2, 0x03C8, 0x0030, 0x03C9, 0x07B3, 0x0FB3, + 0x0FC7, 0x0FCF, 0x3FE9, 0x7FF5, 0xFFF8, 0x7FF3, 0x3FF3, 0x3FC6, + 0x1FC8, 0x1FA8, 0x0FAC, 0x07D1, 0x03CC, 0x006B, 0x03CD, 0x07D3, + 0x0FAE, 0x1FA9, 0x1FC7, 0x3FC5, 0x3FF2, 0x7FEC, 0x7FFA, 0x3FDE, + 0x3FDA, 0x3FD7, 0x1FB9, 0x1FB0, 0x07C2, 0x03BE, 0x006E, 0x03BF, + 0x07C3, 0x1FB1, 0x1FB8, 0x3FD3, 0x3FD8, 0x3FDD, 0x7FF8, 0x7FEF, + 0x3FEE, 0x3FD6, 0x3FC8, 0x1FCB, 0x1FBE, 0x0FB5, 0x03D4, 0x006F, + 0x03D5, 0x0FB4, 0x1FBF, 0x1FCA, 0x3FCA, 0x3FD5, 0x3FEC, 0x7FF1, + 0xFFFF, 0x3FE8, 0x1FD4, 0x1FC5, 0x1FBA, 0x0FC9, 0x07CD, 0x07C7, + 0x01D6, 0x07C5, 0x07CC, 0x0FC8, 0x1FBB, 0x1FC3, 0x1FD6, 0x3FE7, + 0xFFFC, 0x002E, +}; + +static const uint16_t clv_mvy_0_syms[] = { + 0xF8F8, 0xF9F8, 0xFAF8, 0xFBF8, 0xFCF8, 0xFDF8, 0xFEF8, 0xFFF8, + 0x00F8, 0x01F8, 0x02F8, 0x03F8, 0x04F8, 0x05F8, 0x06F8, 0x07F8, + 0x08F8, 0xF8F9, 0xF9F9, 0xFAF9, 0xFBF9, 0xFCF9, 0xFDF9, 0xFEF9, + 0xFFF9, 0x00F9, 0x01F9, 0x02F9, 0x03F9, 0x04F9, 0x05F9, 0x06F9, + 0x07F9, 0x08F9, 0xF8FA, 0xF9FA, 0xFAFA, 0xFBFA, 0xFCFA, 0xFDFA, + 0xFEFA, 0xFFFA, 0x00FA, 0x01FA, 0x02FA, 0x03FA, 0x04FA, 0x05FA, + 0x06FA, 0x07FA, 0x08FA, 0xF8FB, 0xF9FB, 0xFAFB, 0xFBFB, 0xFCFB, + 0xFDFB, 0xFEFB, 0xFFFB, 0x00FB, 0x01FB, 0x02FB, 0x03FB, 0x04FB, + 0x05FB, 0x06FB, 0x07FB, 0x08FB, 0xF8FC, 0xF9FC, 0xFAFC, 0xFBFC, + 0xFCFC, 0xFDFC, 0xFEFC, 0xFFFC, 0x00FC, 0x01FC, 0x02FC, 0x03FC, + 0x04FC, 0x05FC, 0x06FC, 0x07FC, 0x08FC, 0xF8FD, 0xF9FD, 0xFAFD, + 0xFBFD, 0xFCFD, 0xFDFD, 0xFEFD, 0xFFFD, 0x00FD, 0x01FD, 0x02FD, + 0x03FD, 0x04FD, 0x05FD, 0x06FD, 0x07FD, 0x08FD, 0xF8FE, 0xF9FE, + 0xFAFE, 0xFBFE, 0xFCFE, 0xFDFE, 0xFEFE, 0xFFFE, 0x00FE, 0x01FE, + 0x02FE, 0x03FE, 0x04FE, 0x05FE, 0x06FE, 0x07FE, 0x08FE, 0xF8FF, + 0xF9FF, 0xFAFF, 0xFBFF, 0xFCFF, 0xFDFF, 0xFEFF, 0xFFFF, 0x00FF, + 0x01FF, 0x02FF, 0x03FF, 0x04FF, 0x05FF, 0x06FF, 0x07FF, 0x08FF, + 0xF800, 0xF900, 0xFA00, 0xFB00, 0xFC00, 0xFD00, 0xFE00, 0xFF00, + 0x0000, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, 0x0700, + 0x0800, 0xF801, 0xF901, 0xFA01, 0xFB01, 0xFC01, 0xFD01, 0xFE01, + 0xFF01, 0x0001, 0x0101, 0x0201, 0x0301, 0x0401, 0x0501, 0x0601, + 0x0701, 0x0801, 0xF802, 0xF902, 0xFA02, 0xFB02, 0xFC02, 0xFD02, + 0xFE02, 0xFF02, 0x0002, 0x0102, 0x0202, 0x0302, 0x0402, 0x0502, + 0x0602, 0x0702, 0x0802, 0xF803, 0xF903, 0xFA03, 0xFB03, 0xFC03, + 0xFD03, 0xFE03, 0xFF03, 0x0003, 0x0103, 0x0203, 0x0303, 0x0403, + 0x0503, 0x0603, 0x0703, 0x0803, 0xF804, 0xF904, 0xFA04, 0xFB04, + 0xFC04, 0xFD04, 0xFE04, 0xFF04, 0x0004, 0x0104, 0x0204, 0x0304, + 0x0404, 0x0504, 0x0604, 0x0704, 0x0804, 0xF805, 0xF905, 0xFA05, + 0xFB05, 0xFC05, 0xFD05, 0xFE05, 0xFF05, 0x0005, 0x0105, 0x0205, + 0x0305, 0x0405, 0x0505, 0x0605, 0x0705, 0x0805, 0xF806, 0xF906, + 0xFA06, 0xFB06, 0xFC06, 0xFD06, 0xFE06, 0xFF06, 0x0006, 0x0106, + 0x0206, 0x0306, 0x0406, 0x0506, 0x0606, 0x0706, 0x0806, 0xF807, + 0xF907, 0xFA07, 0xFB07, 0xFC07, 0xFD07, 0xFE07, 0xFF07, 0x0007, + 0x0107, 0x0207, 0x0307, 0x0407, 0x0507, 0x0607, 0x0707, 0x0807, + 0xF808, 0xF908, 0xFA08, 0xFB08, 0xFC08, 0xFD08, 0xFE08, 0xFF08, + 0x0008, 0x0108, 0x0208, 0x0308, 0x0408, 0x0508, 0x0608, 0x0708, + 0x0808, 0x0909, +}; + +static const uint8_t clv_mvy_1_bits[] = { + 15, 15, 15, 15, 14, 14, 13, 13, 11, 9, 11, 13, 13, 14, 14, 15, + 15, 15, 15, 15, 14, 14, 13, 13, 12, 12, 12, 10, 9, 10, 12, 12, + 12, 13, 13, 14, 14, 15, 15, 15, 14, 14, 13, 13, 13, 12, 11, 8, + 11, 12, 13, 13, 13, 14, 14, 15, 15, 14, 14, 14, 14, 13, 12, 12, + 12, 10, 8, 10, 12, 12, 12, 13, 14, 14, 14, 14, 15, 14, 14, 13, + 13, 12, 12, 11, 10, 8, 10, 11, 12, 12, 13, 13, 14, 14, 15, 14, + 14, 13, 13, 13, 12, 12, 11, 9, 7, 9, 11, 12, 12, 13, 13, 13, + 14, 14, 14, 14, 13, 13, 13, 12, 11, 10, 9, 7, 9, 10, 11, 12, + 13, 13, 13, 14, 14, 14, 13, 13, 12, 12, 11, 11, 10, 8, 7, 8, + 10, 11, 11, 12, 12, 13, 13, 14, 13, 13, 13, 12, 11, 11, 10, 9, + 6, 4, 6, 9, 10, 11, 12, 12, 13, 13, 13, 12, 11, 10, 10, 10, + 9, 9, 7, 5, 1, 5, 7, 9, 9, 10, 10, 10, 11, 12, 13, 13, + 13, 12, 11, 11, 10, 9, 6, 4, 6, 9, 10, 11, 11, 12, 13, 13, + 13, 14, 13, 13, 12, 12, 11, 11, 10, 8, 7, 8, 10, 11, 11, 12, + 12, 13, 13, 14, 14, 14, 13, 13, 13, 12, 11, 10, 9, 7, 9, 10, + 11, 12, 13, 13, 13, 14, 14, 14, 14, 13, 13, 13, 12, 12, 11, 9, + 7, 9, 11, 12, 12, 13, 13, 13, 14, 14, 15, 14, 14, 13, 13, 12, + 12, 11, 10, 8, 10, 11, 12, 12, 13, 13, 14, 14, 15, 14, 14, 14, + 14, 13, 12, 12, 12, 10, 8, 10, 12, 12, 12, 13, 14, 14, 14, 14, + 15, 15, 14, 14, 13, 13, 13, 12, 11, 8, 11, 12, 13, 13, 13, 14, + 14, 15, 15, 15, 14, 14, 13, 13, 12, 12, 12, 10, 9, 10, 12, 12, + 12, 13, 13, 14, 14, 15, 15, 15, 15, 15, 14, 14, 13, 13, 11, 9, + 11, 13, 13, 14, 14, 15, 15, 15, 15, 5, +}; + +static const uint16_t clv_mvy_1_codes[] = { + 0x7FF9, 0x7FF6, 0x7FEB, 0x7FE3, 0x3FCF, 0x3FB3, 0x1FBD, 0x1FA1, + 0x07AD, 0x01CE, 0x07AF, 0x1FA0, 0x1FBB, 0x3FB0, 0x3FCC, 0x7FE2, + 0x7FE9, 0x7FF4, 0x7FFB, 0x7FF1, 0x3FE7, 0x3FBD, 0x1FA5, 0x1F9B, + 0x0FB4, 0x0FAF, 0x0FAA, 0x03CC, 0x01CD, 0x03CD, 0x0FAB, 0x0FAD, + 0x0FB1, 0x1F9C, 0x1FA3, 0x3FBE, 0x3FE6, 0x7FF0, 0x7FFC, 0x7FE5, + 0x3FB5, 0x3FAE, 0x1FB4, 0x1FAA, 0x1F97, 0x0F85, 0x07A2, 0x00DD, + 0x07A3, 0x0F86, 0x1F99, 0x1FAD, 0x1FB2, 0x3FAC, 0x3FB7, 0x7FE4, + 0x7FFD, 0x3FEA, 0x3FD8, 0x3FC3, 0x3FBB, 0x1FC9, 0x0FBC, 0x0F97, + 0x0F8F, 0x03B8, 0x00DA, 0x03B9, 0x0F90, 0x0F98, 0x0FB9, 0x1FC6, + 0x3FBA, 0x3FC0, 0x3FD9, 0x3FEB, 0x7FEF, 0x3FEE, 0x3FD7, 0x1FC3, + 0x1F96, 0x0FC0, 0x0FA8, 0x07AA, 0x03BE, 0x00D9, 0x03BF, 0x07AB, + 0x0FA7, 0x0FBF, 0x1F98, 0x1FC5, 0x3FD6, 0x3FEF, 0x7FEE, 0x3FDC, + 0x3FCA, 0x1FBF, 0x1F8B, 0x1F87, 0x0FA2, 0x0F94, 0x07A5, 0x01D4, + 0x0069, 0x01D5, 0x07A6, 0x0F95, 0x0FA3, 0x1F89, 0x1F8D, 0x1FC0, + 0x3FC6, 0x3FDE, 0x3FE0, 0x3FD3, 0x1FB8, 0x1F8F, 0x1F84, 0x0F89, + 0x07BC, 0x03C6, 0x01C6, 0x0067, 0x01C7, 0x03C7, 0x07BD, 0x0F87, + 0x1F82, 0x1F8A, 0x1FB6, 0x3FD1, 0x3FE2, 0x3FC5, 0x1FCE, 0x1FAE, + 0x0FB5, 0x0F8B, 0x07B4, 0x07B0, 0x03B4, 0x00DE, 0x0064, 0x00DF, + 0x03B5, 0x07B1, 0x07B5, 0x0F8C, 0x0FB6, 0x1FAF, 0x1FD1, 0x3FCB, + 0x1FD3, 0x1FCC, 0x1FA7, 0x0F9B, 0x07BE, 0x079C, 0x03C0, 0x01C8, + 0x002E, 0x0008, 0x002F, 0x01C9, 0x03C1, 0x079D, 0x0F82, 0x0F9A, + 0x1FA9, 0x1FCA, 0x1FD4, 0x0F9F, 0x07B6, 0x03C8, 0x03B2, 0x03B0, + 0x01D6, 0x01D0, 0x006A, 0x0014, 0x0000, 0x0015, 0x006B, 0x01D1, + 0x01D7, 0x03B1, 0x03B3, 0x03C9, 0x07B7, 0x0FA0, 0x1FD5, 0x1FCB, + 0x1FAB, 0x0F9C, 0x07BF, 0x079E, 0x03C2, 0x01CA, 0x0030, 0x0009, + 0x0031, 0x01CB, 0x03C3, 0x079F, 0x07C0, 0x0F9D, 0x1FAC, 0x1FCD, + 0x1FD2, 0x3FC8, 0x1FD0, 0x1FB0, 0x0FB7, 0x0F8D, 0x07B8, 0x07B2, + 0x03B6, 0x00E0, 0x0065, 0x00E1, 0x03B7, 0x07B3, 0x07B9, 0x0F8E, + 0x0FB8, 0x1FB1, 0x1FCF, 0x3FC9, 0x3FE1, 0x3FD2, 0x1FB7, 0x1F8E, + 0x1F83, 0x0F88, 0x07BA, 0x03C4, 0x01C4, 0x0066, 0x01C5, 0x03C5, + 0x07BB, 0x0F8A, 0x1F85, 0x1F90, 0x1FB9, 0x3FD0, 0x3FE3, 0x3FDD, + 0x3FC7, 0x1FC1, 0x1F91, 0x1F88, 0x0FA4, 0x0F96, 0x07A7, 0x01D2, + 0x0068, 0x01D3, 0x07A4, 0x0F93, 0x0FA1, 0x1F86, 0x1F8C, 0x1FBE, + 0x3FC4, 0x3FDF, 0x7FED, 0x3FEC, 0x3FD4, 0x1FC4, 0x1F92, 0x0FBD, + 0x0FA5, 0x07A8, 0x03BC, 0x00D8, 0x03BD, 0x07A9, 0x0FA6, 0x0FBE, + 0x1F93, 0x1FC2, 0x3FD5, 0x3FED, 0x7FEC, 0x3FE8, 0x3FDB, 0x3FC1, + 0x3FB9, 0x1FC7, 0x0FBA, 0x0F9E, 0x0F91, 0x03BA, 0x00DB, 0x03BB, + 0x0F92, 0x0F99, 0x0FBB, 0x1FC8, 0x3FB8, 0x3FC2, 0x3FDA, 0x3FE9, + 0x7FFF, 0x7FE7, 0x3FB6, 0x3FAF, 0x1FB3, 0x1FA6, 0x1F94, 0x0F83, + 0x07A0, 0x00DC, 0x07A1, 0x0F84, 0x1F95, 0x1FA8, 0x1FB5, 0x3FAD, + 0x3FB4, 0x7FE6, 0x7FFE, 0x7FF3, 0x3FE5, 0x3FBC, 0x1FA4, 0x1F9D, + 0x0FB2, 0x0FAE, 0x0FA9, 0x03CA, 0x01CC, 0x03CB, 0x0FAC, 0x0FB0, + 0x0FB3, 0x1F9A, 0x1FA2, 0x3FBF, 0x3FE4, 0x7FF2, 0x7FF8, 0x7FF5, + 0x7FEA, 0x7FE0, 0x3FCD, 0x3FB1, 0x1FBA, 0x1F9F, 0x07AE, 0x01CF, + 0x07AC, 0x1F9E, 0x1FBC, 0x3FB2, 0x3FCE, 0x7FE1, 0x7FE8, 0x7FF7, + 0x7FFA, 0x0016, +}; + +static const uint16_t clv_mvy_1_syms[] = { + 0xF7F7, 0xF8F7, 0xF9F7, 0xFAF7, 0xFBF7, 0xFCF7, 0xFDF7, 0xFEF7, + 0xFFF7, 0x00F7, 0x01F7, 0x02F7, 0x03F7, 0x04F7, 0x05F7, 0x06F7, + 0x07F7, 0x08F7, 0x09F7, 0xF7F8, 0xF8F8, 0xF9F8, 0xFAF8, 0xFBF8, + 0xFCF8, 0xFDF8, 0xFEF8, 0xFFF8, 0x00F8, 0x01F8, 0x02F8, 0x03F8, + 0x04F8, 0x05F8, 0x06F8, 0x07F8, 0x08F8, 0x09F8, 0xF7F9, 0xF8F9, + 0xF9F9, 0xFAF9, 0xFBF9, 0xFCF9, 0xFDF9, 0xFEF9, 0xFFF9, 0x00F9, + 0x01F9, 0x02F9, 0x03F9, 0x04F9, 0x05F9, 0x06F9, 0x07F9, 0x08F9, + 0x09F9, 0xF7FA, 0xF8FA, 0xF9FA, 0xFAFA, 0xFBFA, 0xFCFA, 0xFDFA, + 0xFEFA, 0xFFFA, 0x00FA, 0x01FA, 0x02FA, 0x03FA, 0x04FA, 0x05FA, + 0x06FA, 0x07FA, 0x08FA, 0x09FA, 0xF7FB, 0xF8FB, 0xF9FB, 0xFAFB, + 0xFBFB, 0xFCFB, 0xFDFB, 0xFEFB, 0xFFFB, 0x00FB, 0x01FB, 0x02FB, + 0x03FB, 0x04FB, 0x05FB, 0x06FB, 0x07FB, 0x08FB, 0x09FB, 0xF7FC, + 0xF8FC, 0xF9FC, 0xFAFC, 0xFBFC, 0xFCFC, 0xFDFC, 0xFEFC, 0xFFFC, + 0x00FC, 0x01FC, 0x02FC, 0x03FC, 0x04FC, 0x05FC, 0x06FC, 0x07FC, + 0x08FC, 0x09FC, 0xF7FD, 0xF8FD, 0xF9FD, 0xFAFD, 0xFBFD, 0xFCFD, + 0xFDFD, 0xFEFD, 0xFFFD, 0x00FD, 0x01FD, 0x02FD, 0x03FD, 0x04FD, + 0x05FD, 0x06FD, 0x07FD, 0x08FD, 0x09FD, 0xF7FE, 0xF8FE, 0xF9FE, + 0xFAFE, 0xFBFE, 0xFCFE, 0xFDFE, 0xFEFE, 0xFFFE, 0x00FE, 0x01FE, + 0x02FE, 0x03FE, 0x04FE, 0x05FE, 0x06FE, 0x07FE, 0x08FE, 0x09FE, + 0xF7FF, 0xF8FF, 0xF9FF, 0xFAFF, 0xFBFF, 0xFCFF, 0xFDFF, 0xFEFF, + 0xFFFF, 0x00FF, 0x01FF, 0x02FF, 0x03FF, 0x04FF, 0x05FF, 0x06FF, + 0x07FF, 0x08FF, 0x09FF, 0xF700, 0xF800, 0xF900, 0xFA00, 0xFB00, + 0xFC00, 0xFD00, 0xFE00, 0xFF00, 0x0000, 0x0100, 0x0200, 0x0300, + 0x0400, 0x0500, 0x0600, 0x0700, 0x0800, 0x0900, 0xF701, 0xF801, + 0xF901, 0xFA01, 0xFB01, 0xFC01, 0xFD01, 0xFE01, 0xFF01, 0x0001, + 0x0101, 0x0201, 0x0301, 0x0401, 0x0501, 0x0601, 0x0701, 0x0801, + 0x0901, 0xF702, 0xF802, 0xF902, 0xFA02, 0xFB02, 0xFC02, 0xFD02, + 0xFE02, 0xFF02, 0x0002, 0x0102, 0x0202, 0x0302, 0x0402, 0x0502, + 0x0602, 0x0702, 0x0802, 0x0902, 0xF703, 0xF803, 0xF903, 0xFA03, + 0xFB03, 0xFC03, 0xFD03, 0xFE03, 0xFF03, 0x0003, 0x0103, 0x0203, + 0x0303, 0x0403, 0x0503, 0x0603, 0x0703, 0x0803, 0x0903, 0xF704, + 0xF804, 0xF904, 0xFA04, 0xFB04, 0xFC04, 0xFD04, 0xFE04, 0xFF04, + 0x0004, 0x0104, 0x0204, 0x0304, 0x0404, 0x0504, 0x0604, 0x0704, + 0x0804, 0x0904, 0xF705, 0xF805, 0xF905, 0xFA05, 0xFB05, 0xFC05, + 0xFD05, 0xFE05, 0xFF05, 0x0005, 0x0105, 0x0205, 0x0305, 0x0405, + 0x0505, 0x0605, 0x0705, 0x0805, 0x0905, 0xF706, 0xF806, 0xF906, + 0xFA06, 0xFB06, 0xFC06, 0xFD06, 0xFE06, 0xFF06, 0x0006, 0x0106, + 0x0206, 0x0306, 0x0406, 0x0506, 0x0606, 0x0706, 0x0806, 0x0906, + 0xF707, 0xF807, 0xF907, 0xFA07, 0xFB07, 0xFC07, 0xFD07, 0xFE07, + 0xFF07, 0x0007, 0x0107, 0x0207, 0x0307, 0x0407, 0x0507, 0x0607, + 0x0707, 0x0807, 0x0907, 0xF708, 0xF808, 0xF908, 0xFA08, 0xFB08, + 0xFC08, 0xFD08, 0xFE08, 0xFF08, 0x0008, 0x0108, 0x0208, 0x0308, + 0x0408, 0x0508, 0x0608, 0x0708, 0x0808, 0x0908, 0xF709, 0xF809, + 0xF909, 0xFA09, 0xFB09, 0xFC09, 0xFD09, 0xFE09, 0xFF09, 0x0009, + 0x0109, 0x0209, 0x0309, 0x0409, 0x0509, 0x0609, 0x0709, 0x0809, + 0x0909, 0x0A0A, +}; + +static const uint8_t clv_mvy_2_bits[] = { + 16, 16, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 13, 13, 12, 11, + 12, 13, 13, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, + 15, 15, 15, 15, 15, 14, 14, 14, 14, 13, 13, 13, 13, 11, 10, 11, + 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 15, 16, 16, 15, + 15, 15, 15, 14, 14, 14, 14, 14, 14, 13, 13, 13, 11, 10, 11, 13, + 13, 13, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 15, 15, + 15, 14, 14, 14, 14, 14, 14, 13, 13, 13, 12, 11, 9, 11, 12, 13, + 13, 13, 14, 14, 14, 14, 14, 14, 15, 15, 15, 16, 16, 15, 15, 14, + 14, 13, 13, 13, 13, 13, 13, 13, 12, 11, 11, 9, 11, 11, 12, 13, + 13, 13, 13, 13, 13, 13, 14, 14, 14, 15, 16, 16, 15, 15, 15, 14, + 13, 13, 13, 13, 13, 13, 13, 12, 11, 11, 9, 11, 11, 12, 13, 13, + 13, 13, 13, 13, 13, 14, 15, 15, 15, 16, 16, 15, 15, 15, 15, 14, + 14, 13, 13, 13, 12, 12, 12, 11, 11, 9, 11, 11, 12, 12, 12, 13, + 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 15, 15, 14, 14, 14, 13, + 13, 13, 12, 12, 12, 12, 11, 10, 8, 10, 11, 12, 12, 12, 12, 13, + 13, 13, 14, 14, 14, 15, 15, 16, 16, 15, 14, 14, 14, 13, 13, 13, + 13, 12, 12, 12, 11, 11, 10, 8, 10, 11, 11, 12, 12, 12, 13, 13, + 13, 13, 14, 14, 14, 15, 16, 15, 15, 14, 14, 13, 13, 13, 13, 13, + 12, 12, 12, 11, 10, 9, 8, 9, 10, 11, 12, 12, 12, 13, 13, 13, + 13, 13, 14, 14, 15, 15, 15, 15, 14, 14, 13, 13, 13, 13, 13, 12, + 12, 11, 11, 10, 10, 7, 10, 10, 11, 11, 12, 12, 13, 13, 13, 13, + 13, 14, 14, 15, 15, 14, 14, 14, 14, 13, 13, 12, 12, 12, 12, 12, + 11, 11, 10, 9, 7, 9, 10, 11, 11, 12, 12, 12, 12, 12, 13, 13, + 14, 14, 14, 14, 15, 13, 13, 13, 13, 13, 12, 12, 12, 11, 11, 11, + 11, 10, 8, 7, 8, 10, 11, 11, 11, 11, 12, 12, 12, 13, 13, 13, + 13, 13, 15, 14, 14, 14, 13, 13, 12, 12, 12, 11, 11, 11, 10, 10, + 9, 8, 6, 8, 9, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 14, + 14, 14, 16, 13, 13, 13, 12, 12, 12, 11, 11, 11, 10, 9, 9, 8, + 6, 4, 6, 8, 9, 9, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, + 16, 12, 12, 12, 12, 11, 11, 10, 10, 9, 9, 8, 8, 8, 7, 4, + 2, 4, 7, 8, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, + 16, 13, 13, 13, 12, 12, 12, 11, 11, 11, 10, 9, 9, 8, 6, 4, + 6, 8, 9, 9, 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 16, 14, + 14, 14, 13, 13, 12, 12, 12, 11, 11, 11, 10, 10, 9, 8, 6, 8, + 9, 10, 10, 11, 11, 11, 12, 12, 12, 13, 13, 14, 14, 14, 15, 13, + 13, 13, 13, 13, 12, 12, 12, 11, 11, 11, 11, 10, 8, 7, 8, 10, + 11, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 13, 15, 14, 14, 14, + 14, 13, 13, 12, 12, 12, 12, 12, 11, 11, 10, 9, 7, 9, 10, 11, + 11, 12, 12, 12, 12, 12, 13, 13, 14, 14, 14, 14, 15, 15, 14, 14, + 13, 13, 13, 13, 13, 12, 12, 11, 11, 10, 10, 7, 10, 10, 11, 11, + 12, 12, 13, 13, 13, 13, 13, 14, 14, 15, 15, 15, 15, 14, 14, 13, + 13, 13, 13, 13, 12, 12, 12, 11, 10, 9, 8, 9, 10, 11, 12, 12, + 12, 13, 13, 13, 13, 13, 14, 14, 15, 15, 16, 15, 14, 14, 14, 13, + 13, 13, 13, 12, 12, 12, 11, 11, 10, 8, 10, 11, 11, 12, 12, 12, + 13, 13, 13, 13, 14, 14, 14, 15, 16, 16, 15, 15, 14, 14, 14, 13, + 13, 13, 12, 12, 12, 12, 11, 10, 8, 10, 11, 12, 12, 12, 12, 13, + 13, 13, 14, 14, 14, 15, 15, 16, 16, 15, 15, 15, 15, 14, 14, 13, + 13, 13, 12, 12, 12, 11, 11, 9, 11, 11, 12, 12, 12, 13, 13, 13, + 14, 14, 15, 15, 15, 15, 16, 16, 15, 15, 15, 14, 13, 13, 13, 13, + 13, 13, 13, 12, 11, 11, 9, 11, 11, 12, 13, 13, 13, 13, 13, 13, + 13, 14, 15, 15, 15, 16, 16, 15, 15, 14, 14, 13, 13, 13, 13, 13, + 13, 13, 12, 11, 11, 9, 11, 11, 12, 13, 13, 13, 13, 13, 13, 13, + 14, 14, 14, 15, 16, 16, 15, 15, 15, 14, 14, 14, 14, 14, 14, 13, + 13, 13, 12, 11, 9, 11, 12, 13, 13, 13, 14, 14, 14, 14, 14, 14, + 15, 15, 15, 16, 16, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 13, + 13, 13, 11, 10, 11, 13, 13, 13, 14, 14, 14, 14, 14, 14, 15, 15, + 15, 15, 16, 16, 15, 15, 15, 15, 15, 14, 14, 14, 14, 13, 13, 13, + 13, 12, 10, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, + 15, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 13, 13, + 12, 11, 12, 13, 13, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 16, + 16, 7, +}; + +static const uint16_t clv_mvy_2_codes[] = { + 0xFFF5, 0xFFD8, 0x7FE6, 0x7FB9, 0x7FB5, 0x7FB0, 0x7FA0, 0x7F99, + 0x7F93, 0x3FAA, 0x3F9B, 0x3F52, 0x1F76, 0x1EF5, 0x0F0B, 0x06F0, + 0x0F08, 0x1EF0, 0x1F75, 0x3F53, 0x3F9A, 0x3FA8, 0x7F94, 0x7F98, + 0x7F9E, 0x7FAE, 0x7FAF, 0x7FB7, 0x7FE9, 0xFFDB, 0xFFF6, 0xFFFD, + 0x7FD9, 0x7FCC, 0x7FC6, 0x7F9C, 0x7F80, 0x3FA5, 0x3F80, 0x3F6A, + 0x3F31, 0x1F54, 0x1F40, 0x1F11, 0x1F05, 0x075E, 0x0360, 0x075F, + 0x1F07, 0x1F12, 0x1F43, 0x1F56, 0x3F33, 0x3F68, 0x3F83, 0x3FA6, + 0x7F7F, 0x7F9A, 0x7FC9, 0x7FCA, 0x7FDB, 0xFFF8, 0xFFEC, 0x7FDE, + 0x7FE2, 0x7FA6, 0x7F6F, 0x3FA1, 0x3F8D, 0x3F5C, 0x3F39, 0x3F21, + 0x3F18, 0x1F58, 0x1F1E, 0x1EF1, 0x0740, 0x035A, 0x0741, 0x1EF2, + 0x1F1F, 0x1F5A, 0x3F19, 0x3F22, 0x3F3B, 0x3F5E, 0x3F8E, 0x3FA3, + 0x7F6B, 0x7FA2, 0x7FE3, 0x7FE1, 0xFFEE, 0xFFFC, 0x7FC3, 0x7FBC, + 0x7F71, 0x3F96, 0x3F86, 0x3F7A, 0x3F72, 0x3F59, 0x3F46, 0x1F0A, + 0x1EFD, 0x1ED0, 0x0F02, 0x0712, 0x019F, 0x0713, 0x0F03, 0x1ED3, + 0x1EFF, 0x1F09, 0x3F4A, 0x3F5A, 0x3F76, 0x3F7B, 0x3F87, 0x3F97, + 0x7F73, 0x7FBB, 0x7FBF, 0xFFFB, 0xFFEB, 0x7F88, 0x7F5C, 0x3F7C, + 0x3F3C, 0x1F60, 0x1F4C, 0x1F14, 0x1F0C, 0x1F00, 0x1EF9, 0x1ED8, + 0x0F42, 0x075A, 0x0714, 0x0186, 0x0715, 0x075B, 0x0F43, 0x1EDA, + 0x1EFA, 0x1F01, 0x1F0E, 0x1F15, 0x1F4D, 0x1F62, 0x3F3D, 0x3F7D, + 0x3FAC, 0x7F86, 0xFFE8, 0xFFE7, 0x7FA7, 0x7F8C, 0x7F68, 0x3F9C, + 0x1F7C, 0x1F6C, 0x1F69, 0x1EEC, 0x1EE4, 0x1ED5, 0x1ECD, 0x0EF0, + 0x0752, 0x06F6, 0x018C, 0x06F7, 0x0753, 0x0EF1, 0x1ECE, 0x1ED6, + 0x1EE5, 0x1EED, 0x1F6A, 0x1F6E, 0x1F7D, 0x3F9F, 0x7F66, 0x7F8A, + 0x7FA5, 0xFFE6, 0xFFDC, 0x7FDA, 0x7FC0, 0x7FAC, 0x7F61, 0x3F42, + 0x3F0E, 0x1F45, 0x1F2C, 0x1ECA, 0x0F27, 0x0EF6, 0x0EEE, 0x072E, + 0x06F4, 0x0185, 0x06F5, 0x072F, 0x0EEF, 0x0EF7, 0x0F28, 0x1ECB, + 0x1F2F, 0x1F46, 0x3F0F, 0x3F40, 0x7F5F, 0x7FB4, 0x7FC2, 0x7FDC, + 0xFFDA, 0xFFE0, 0x7F72, 0x7F63, 0x3F70, 0x3F1C, 0x3F16, 0x1F82, + 0x1EE2, 0x1EB2, 0x0F4C, 0x0EFC, 0x0EE0, 0x0ED3, 0x0722, 0x036C, + 0x00BF, 0x036D, 0x0723, 0x0ECC, 0x0EE1, 0x0EFF, 0x0F4D, 0x1EB3, + 0x1EE3, 0x1F83, 0x3F17, 0x3F1F, 0x3F75, 0x7F65, 0x7F70, 0xFFE2, + 0xFFD7, 0x7F76, 0x3F2B, 0x3F13, 0x3F0A, 0x1F33, 0x1F23, 0x1EB4, + 0x1EA0, 0x0F46, 0x0F32, 0x0F1A, 0x0756, 0x0728, 0x0356, 0x00B0, + 0x0357, 0x0729, 0x0757, 0x0F1B, 0x0F33, 0x0F47, 0x1EA1, 0x1EB5, + 0x1F20, 0x1F30, 0x3F08, 0x3F10, 0x3F28, 0x7F77, 0xFFD5, 0x7FD5, + 0x7FD1, 0x3F5D, 0x3F25, 0x1F34, 0x1F24, 0x1EE8, 0x1EBC, 0x1EA8, + 0x0F3A, 0x0F2E, 0x0EE2, 0x071C, 0x0374, 0x01A0, 0x00AE, 0x01A1, + 0x0375, 0x071D, 0x0EE3, 0x0F2F, 0x0F3C, 0x1EA9, 0x1EBD, 0x1EE9, + 0x1F25, 0x1F36, 0x3F24, 0x3F61, 0x7FCE, 0x7FD2, 0x7F91, 0x7F7D, + 0x3F6C, 0x3F34, 0x1F72, 0x1F61, 0x1EDD, 0x1EC5, 0x1EA5, 0x0F05, + 0x0ED6, 0x0750, 0x073E, 0x0368, 0x034A, 0x0052, 0x034B, 0x0369, + 0x073F, 0x0751, 0x0ED7, 0x0F07, 0x1EA7, 0x1EC7, 0x1EDF, 0x1F65, + 0x1F70, 0x3F36, 0x3F6F, 0x7F7C, 0x7F8F, 0x3F90, 0x3F66, 0x3F58, + 0x3F4E, 0x1F48, 0x1EBB, 0x0F40, 0x0F18, 0x0F10, 0x0EDA, 0x0ECF, + 0x0732, 0x0704, 0x0354, 0x0190, 0x004F, 0x0191, 0x0355, 0x0705, + 0x0733, 0x0ED0, 0x0EDB, 0x0F11, 0x0F19, 0x0F41, 0x1EB8, 0x1F4B, + 0x3F4F, 0x3F55, 0x3F65, 0x3F92, 0x7F85, 0x1F51, 0x1F39, 0x1F2B, + 0x1F18, 0x1EC2, 0x0F38, 0x0F14, 0x0ECA, 0x074C, 0x0736, 0x0700, + 0x06FC, 0x0350, 0x00BA, 0x004D, 0x00BB, 0x0351, 0x06FD, 0x0701, + 0x0737, 0x074D, 0x0ECB, 0x0F15, 0x0F39, 0x1EC3, 0x1F1B, 0x1F2E, + 0x1F3A, 0x1F53, 0x7F82, 0x3F8A, 0x3F47, 0x3F2E, 0x1F5E, 0x1E9E, + 0x0F24, 0x0F20, 0x0EC6, 0x0746, 0x0726, 0x070E, 0x0370, 0x035E, + 0x018A, 0x00AC, 0x0021, 0x00AD, 0x018B, 0x035F, 0x0371, 0x070F, + 0x0727, 0x0747, 0x0EC7, 0x0F21, 0x0F25, 0x1E9F, 0x1F5F, 0x3F2D, + 0x3F48, 0x3F8B, 0xFFF1, 0x1F78, 0x1F3D, 0x1EAD, 0x0F2B, 0x0EF9, + 0x0EE9, 0x0739, 0x0719, 0x0709, 0x0363, 0x019B, 0x0195, 0x00B3, + 0x0023, 0x0005, 0x0024, 0x00B4, 0x0196, 0x019C, 0x0364, 0x070A, + 0x071A, 0x073A, 0x0EEA, 0x0EFA, 0x0F2C, 0x1EAE, 0x1F3E, 0x1F79, + 0xFFF0, 0x0F0C, 0x0EE6, 0x0EDC, 0x0EC2, 0x0748, 0x0706, 0x0372, + 0x034C, 0x0198, 0x0192, 0x00C0, 0x00BC, 0x00B6, 0x0053, 0x0006, + 0x0000, 0x0007, 0x0054, 0x00B7, 0x00BD, 0x00C1, 0x0193, 0x0199, + 0x034D, 0x0373, 0x0707, 0x0749, 0x0EC3, 0x0EDD, 0x0EE7, 0x0F0D, + 0xFFF2, 0x1F7A, 0x1F3F, 0x1EAF, 0x0F2D, 0x0EFB, 0x0EEB, 0x073B, + 0x071B, 0x070B, 0x0365, 0x019D, 0x0197, 0x00B5, 0x0025, 0x0004, + 0x0022, 0x00B2, 0x0194, 0x019A, 0x0362, 0x0708, 0x0718, 0x0738, + 0x0EE8, 0x0EF8, 0x0F2A, 0x1EAC, 0x1F3C, 0x1F7B, 0xFFF3, 0x3F89, + 0x3F44, 0x3F2F, 0x1F5C, 0x1E9C, 0x0F22, 0x0F1E, 0x0EC4, 0x0744, + 0x0724, 0x070C, 0x036E, 0x035C, 0x0188, 0x00AA, 0x0020, 0x00AB, + 0x0189, 0x035D, 0x036F, 0x070D, 0x0725, 0x0745, 0x0EC5, 0x0F1F, + 0x0F23, 0x1E9D, 0x1F5D, 0x3F2C, 0x3F45, 0x3F88, 0x7F81, 0x1F52, + 0x1F38, 0x1F28, 0x1F19, 0x1EC0, 0x0F36, 0x0F12, 0x0EC8, 0x074A, + 0x0734, 0x06FE, 0x06FA, 0x034E, 0x00B8, 0x004C, 0x00B9, 0x034F, + 0x06FB, 0x06FF, 0x0735, 0x074B, 0x0EC9, 0x0F13, 0x0F37, 0x1EC1, + 0x1F1A, 0x1F29, 0x1F3B, 0x1F50, 0x7F84, 0x3F91, 0x3F64, 0x3F54, + 0x3F4C, 0x1F49, 0x1EB9, 0x0F3B, 0x0F16, 0x0F0E, 0x0ED8, 0x0ECD, + 0x0730, 0x0702, 0x0352, 0x018E, 0x004E, 0x018F, 0x0353, 0x0703, + 0x0731, 0x0ECE, 0x0ED9, 0x0F0F, 0x0F17, 0x0F3D, 0x1EBA, 0x1F4A, + 0x3F4D, 0x3F51, 0x3F67, 0x3F93, 0x7F90, 0x7F7A, 0x3F6E, 0x3F37, + 0x1F71, 0x1F63, 0x1EDC, 0x1EC4, 0x1EA4, 0x0F04, 0x0ED4, 0x074E, + 0x073C, 0x0366, 0x0348, 0x0051, 0x0349, 0x0367, 0x073D, 0x074F, + 0x0ED5, 0x0F06, 0x1EA6, 0x1EC6, 0x1EDE, 0x1F64, 0x1F73, 0x3F35, + 0x3F6D, 0x7F7B, 0x7F8E, 0x7FD4, 0x7FD0, 0x3F5F, 0x3F26, 0x1F35, + 0x1F27, 0x1EEA, 0x1EBE, 0x1EAA, 0x0F3E, 0x0F30, 0x0EE4, 0x071E, + 0x0376, 0x01A2, 0x00AF, 0x01A3, 0x0377, 0x071F, 0x0EE5, 0x0F31, + 0x0F3F, 0x1EAB, 0x1EBF, 0x1EEB, 0x1F26, 0x1F37, 0x3F27, 0x3F62, + 0x7FCF, 0x7FD3, 0xFFD4, 0x7F78, 0x3F29, 0x3F11, 0x3F0B, 0x1F32, + 0x1F22, 0x1EB6, 0x1EA2, 0x0F48, 0x0F34, 0x0F1C, 0x0758, 0x072A, + 0x0358, 0x00B1, 0x0359, 0x072B, 0x0759, 0x0F1D, 0x0F35, 0x0F49, + 0x1EA3, 0x1EB7, 0x1F21, 0x1F31, 0x3F09, 0x3F12, 0x3F2A, 0x7F79, + 0xFFD6, 0xFFE1, 0x7F6D, 0x7F64, 0x3F73, 0x3F1D, 0x3F14, 0x1F81, + 0x1EE0, 0x1EB0, 0x0F4A, 0x0EFD, 0x0EDE, 0x0ED1, 0x0720, 0x036A, + 0x00BE, 0x036B, 0x0721, 0x0ED2, 0x0EDF, 0x0EFE, 0x0F4B, 0x1EB1, + 0x1EE1, 0x1F7E, 0x3F15, 0x3F1E, 0x3F74, 0x7F62, 0x7F75, 0xFFE3, + 0xFFDE, 0x7FDD, 0x7FBE, 0x7FB3, 0x7F60, 0x3F43, 0x3F0C, 0x1F47, + 0x1F2D, 0x1EC8, 0x0F26, 0x0EF4, 0x0EEC, 0x072C, 0x06F2, 0x0184, + 0x06F3, 0x072D, 0x0EED, 0x0EF5, 0x0F29, 0x1EC9, 0x1F2A, 0x1F44, + 0x3F0D, 0x3F41, 0x7F5E, 0x7FB1, 0x7FC1, 0x7FD7, 0xFFDF, 0xFFEA, + 0x7FA3, 0x7F8B, 0x7F69, 0x3F9E, 0x1F7F, 0x1F6D, 0x1F6B, 0x1EEE, + 0x1EE6, 0x1ED4, 0x1ECF, 0x0EF2, 0x0754, 0x06F8, 0x018D, 0x06F9, + 0x0755, 0x0EF3, 0x1ECC, 0x1ED7, 0x1EE7, 0x1EEF, 0x1F68, 0x1F6F, + 0x1F80, 0x3F9D, 0x7F67, 0x7F8D, 0x7FA8, 0xFFE9, 0xFFE5, 0x7F89, + 0x7F5D, 0x3F7F, 0x3F3F, 0x1F67, 0x1F4F, 0x1F17, 0x1F0F, 0x1F02, + 0x1EFB, 0x1ED9, 0x0F45, 0x075C, 0x0716, 0x0187, 0x0717, 0x075D, + 0x0F44, 0x1EDB, 0x1EF8, 0x1F03, 0x1F0D, 0x1F16, 0x1F4E, 0x1F66, + 0x3F3E, 0x3F7E, 0x3FAD, 0x7F87, 0xFFE4, 0xFFF9, 0x7FC4, 0x7FBA, + 0x7F6E, 0x3F95, 0x3F85, 0x3F78, 0x3F77, 0x3F5B, 0x3F49, 0x1F08, + 0x1EFE, 0x1ED2, 0x0F01, 0x0710, 0x019E, 0x0711, 0x0F00, 0x1ED1, + 0x1EFC, 0x1F0B, 0x3F4B, 0x3F57, 0x3F71, 0x3F79, 0x3F84, 0x3F94, + 0x7F74, 0x7FBD, 0x7FC5, 0xFFFE, 0xFFED, 0x7FE0, 0x7FDF, 0x7FA4, + 0x7F6A, 0x3FA0, 0x3F8F, 0x3F63, 0x3F3A, 0x3F23, 0x3F1A, 0x1F59, + 0x1F1D, 0x1EF3, 0x0743, 0x035B, 0x0742, 0x1EF7, 0x1F1C, 0x1F5B, + 0x3F1B, 0x3F20, 0x3F38, 0x3F60, 0x3F8C, 0x3FA2, 0x7F6C, 0x7FA9, + 0x7FE5, 0x7FE4, 0xFFEF, 0xFFFF, 0x7FD6, 0x7FCB, 0x7FC7, 0x7F9B, + 0x7F83, 0x3FA4, 0x3F81, 0x3F69, 0x3F30, 0x1F57, 0x1F41, 0x1F13, + 0x1F06, 0x0EC0, 0x0361, 0x0EC1, 0x1F04, 0x1F10, 0x1F42, 0x1F55, + 0x3F32, 0x3F6B, 0x3F82, 0x3FA7, 0x7F7E, 0x7F9D, 0x7FC8, 0x7FCD, + 0x7FD8, 0xFFFA, 0xFFF7, 0xFFD9, 0x7FE8, 0x7FB6, 0x7FAB, 0x7FAA, + 0x7FA1, 0x7F96, 0x7F95, 0x3FAB, 0x3F98, 0x3F50, 0x1F77, 0x1EF4, + 0x0F0A, 0x06F1, 0x0F09, 0x1EF6, 0x1F74, 0x3F56, 0x3F99, 0x3FA9, + 0x7F92, 0x7F97, 0x7F9F, 0x7FAD, 0x7FB2, 0x7FB8, 0x7FE7, 0xFFDD, + 0xFFF4, 0x0050, +}; + +static const uint16_t clv_mvy_2_syms[] = { + 0xF1F1, 0xF2F1, 0xF3F1, 0xF4F1, 0xF5F1, 0xF6F1, 0xF7F1, 0xF8F1, + 0xF9F1, 0xFAF1, 0xFBF1, 0xFCF1, 0xFDF1, 0xFEF1, 0xFFF1, 0x00F1, + 0x01F1, 0x02F1, 0x03F1, 0x04F1, 0x05F1, 0x06F1, 0x07F1, 0x08F1, + 0x09F1, 0x0AF1, 0x0BF1, 0x0CF1, 0x0DF1, 0x0EF1, 0x0FF1, 0xF1F2, + 0xF2F2, 0xF3F2, 0xF4F2, 0xF5F2, 0xF6F2, 0xF7F2, 0xF8F2, 0xF9F2, + 0xFAF2, 0xFBF2, 0xFCF2, 0xFDF2, 0xFEF2, 0xFFF2, 0x00F2, 0x01F2, + 0x02F2, 0x03F2, 0x04F2, 0x05F2, 0x06F2, 0x07F2, 0x08F2, 0x09F2, + 0x0AF2, 0x0BF2, 0x0CF2, 0x0DF2, 0x0EF2, 0x0FF2, 0xF1F3, 0xF2F3, + 0xF3F3, 0xF4F3, 0xF5F3, 0xF6F3, 0xF7F3, 0xF8F3, 0xF9F3, 0xFAF3, + 0xFBF3, 0xFCF3, 0xFDF3, 0xFEF3, 0xFFF3, 0x00F3, 0x01F3, 0x02F3, + 0x03F3, 0x04F3, 0x05F3, 0x06F3, 0x07F3, 0x08F3, 0x09F3, 0x0AF3, + 0x0BF3, 0x0CF3, 0x0DF3, 0x0EF3, 0x0FF3, 0xF1F4, 0xF2F4, 0xF3F4, + 0xF4F4, 0xF5F4, 0xF6F4, 0xF7F4, 0xF8F4, 0xF9F4, 0xFAF4, 0xFBF4, + 0xFCF4, 0xFDF4, 0xFEF4, 0xFFF4, 0x00F4, 0x01F4, 0x02F4, 0x03F4, + 0x04F4, 0x05F4, 0x06F4, 0x07F4, 0x08F4, 0x09F4, 0x0AF4, 0x0BF4, + 0x0CF4, 0x0DF4, 0x0EF4, 0x0FF4, 0xF1F5, 0xF2F5, 0xF3F5, 0xF4F5, + 0xF5F5, 0xF6F5, 0xF7F5, 0xF8F5, 0xF9F5, 0xFAF5, 0xFBF5, 0xFCF5, + 0xFDF5, 0xFEF5, 0xFFF5, 0x00F5, 0x01F5, 0x02F5, 0x03F5, 0x04F5, + 0x05F5, 0x06F5, 0x07F5, 0x08F5, 0x09F5, 0x0AF5, 0x0BF5, 0x0CF5, + 0x0DF5, 0x0EF5, 0x0FF5, 0xF1F6, 0xF2F6, 0xF3F6, 0xF4F6, 0xF5F6, + 0xF6F6, 0xF7F6, 0xF8F6, 0xF9F6, 0xFAF6, 0xFBF6, 0xFCF6, 0xFDF6, + 0xFEF6, 0xFFF6, 0x00F6, 0x01F6, 0x02F6, 0x03F6, 0x04F6, 0x05F6, + 0x06F6, 0x07F6, 0x08F6, 0x09F6, 0x0AF6, 0x0BF6, 0x0CF6, 0x0DF6, + 0x0EF6, 0x0FF6, 0xF1F7, 0xF2F7, 0xF3F7, 0xF4F7, 0xF5F7, 0xF6F7, + 0xF7F7, 0xF8F7, 0xF9F7, 0xFAF7, 0xFBF7, 0xFCF7, 0xFDF7, 0xFEF7, + 0xFFF7, 0x00F7, 0x01F7, 0x02F7, 0x03F7, 0x04F7, 0x05F7, 0x06F7, + 0x07F7, 0x08F7, 0x09F7, 0x0AF7, 0x0BF7, 0x0CF7, 0x0DF7, 0x0EF7, + 0x0FF7, 0xF1F8, 0xF2F8, 0xF3F8, 0xF4F8, 0xF5F8, 0xF6F8, 0xF7F8, + 0xF8F8, 0xF9F8, 0xFAF8, 0xFBF8, 0xFCF8, 0xFDF8, 0xFEF8, 0xFFF8, + 0x00F8, 0x01F8, 0x02F8, 0x03F8, 0x04F8, 0x05F8, 0x06F8, 0x07F8, + 0x08F8, 0x09F8, 0x0AF8, 0x0BF8, 0x0CF8, 0x0DF8, 0x0EF8, 0x0FF8, + 0xF1F9, 0xF2F9, 0xF3F9, 0xF4F9, 0xF5F9, 0xF6F9, 0xF7F9, 0xF8F9, + 0xF9F9, 0xFAF9, 0xFBF9, 0xFCF9, 0xFDF9, 0xFEF9, 0xFFF9, 0x00F9, + 0x01F9, 0x02F9, 0x03F9, 0x04F9, 0x05F9, 0x06F9, 0x07F9, 0x08F9, + 0x09F9, 0x0AF9, 0x0BF9, 0x0CF9, 0x0DF9, 0x0EF9, 0x0FF9, 0xF1FA, + 0xF2FA, 0xF3FA, 0xF4FA, 0xF5FA, 0xF6FA, 0xF7FA, 0xF8FA, 0xF9FA, + 0xFAFA, 0xFBFA, 0xFCFA, 0xFDFA, 0xFEFA, 0xFFFA, 0x00FA, 0x01FA, + 0x02FA, 0x03FA, 0x04FA, 0x05FA, 0x06FA, 0x07FA, 0x08FA, 0x09FA, + 0x0AFA, 0x0BFA, 0x0CFA, 0x0DFA, 0x0EFA, 0x0FFA, 0xF1FB, 0xF2FB, + 0xF3FB, 0xF4FB, 0xF5FB, 0xF6FB, 0xF7FB, 0xF8FB, 0xF9FB, 0xFAFB, + 0xFBFB, 0xFCFB, 0xFDFB, 0xFEFB, 0xFFFB, 0x00FB, 0x01FB, 0x02FB, + 0x03FB, 0x04FB, 0x05FB, 0x06FB, 0x07FB, 0x08FB, 0x09FB, 0x0AFB, + 0x0BFB, 0x0CFB, 0x0DFB, 0x0EFB, 0x0FFB, 0xF1FC, 0xF2FC, 0xF3FC, + 0xF4FC, 0xF5FC, 0xF6FC, 0xF7FC, 0xF8FC, 0xF9FC, 0xFAFC, 0xFBFC, + 0xFCFC, 0xFDFC, 0xFEFC, 0xFFFC, 0x00FC, 0x01FC, 0x02FC, 0x03FC, + 0x04FC, 0x05FC, 0x06FC, 0x07FC, 0x08FC, 0x09FC, 0x0AFC, 0x0BFC, + 0x0CFC, 0x0DFC, 0x0EFC, 0x0FFC, 0xF1FD, 0xF2FD, 0xF3FD, 0xF4FD, + 0xF5FD, 0xF6FD, 0xF7FD, 0xF8FD, 0xF9FD, 0xFAFD, 0xFBFD, 0xFCFD, + 0xFDFD, 0xFEFD, 0xFFFD, 0x00FD, 0x01FD, 0x02FD, 0x03FD, 0x04FD, + 0x05FD, 0x06FD, 0x07FD, 0x08FD, 0x09FD, 0x0AFD, 0x0BFD, 0x0CFD, + 0x0DFD, 0x0EFD, 0x0FFD, 0xF1FE, 0xF2FE, 0xF3FE, 0xF4FE, 0xF5FE, + 0xF6FE, 0xF7FE, 0xF8FE, 0xF9FE, 0xFAFE, 0xFBFE, 0xFCFE, 0xFDFE, + 0xFEFE, 0xFFFE, 0x00FE, 0x01FE, 0x02FE, 0x03FE, 0x04FE, 0x05FE, + 0x06FE, 0x07FE, 0x08FE, 0x09FE, 0x0AFE, 0x0BFE, 0x0CFE, 0x0DFE, + 0x0EFE, 0x0FFE, 0xF1FF, 0xF2FF, 0xF3FF, 0xF4FF, 0xF5FF, 0xF6FF, + 0xF7FF, 0xF8FF, 0xF9FF, 0xFAFF, 0xFBFF, 0xFCFF, 0xFDFF, 0xFEFF, + 0xFFFF, 0x00FF, 0x01FF, 0x02FF, 0x03FF, 0x04FF, 0x05FF, 0x06FF, + 0x07FF, 0x08FF, 0x09FF, 0x0AFF, 0x0BFF, 0x0CFF, 0x0DFF, 0x0EFF, + 0x0FFF, 0xF100, 0xF200, 0xF300, 0xF400, 0xF500, 0xF600, 0xF700, + 0xF800, 0xF900, 0xFA00, 0xFB00, 0xFC00, 0xFD00, 0xFE00, 0xFF00, + 0x0000, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, 0x0700, + 0x0800, 0x0900, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00, 0x0F00, + 0xF101, 0xF201, 0xF301, 0xF401, 0xF501, 0xF601, 0xF701, 0xF801, + 0xF901, 0xFA01, 0xFB01, 0xFC01, 0xFD01, 0xFE01, 0xFF01, 0x0001, + 0x0101, 0x0201, 0x0301, 0x0401, 0x0501, 0x0601, 0x0701, 0x0801, + 0x0901, 0x0A01, 0x0B01, 0x0C01, 0x0D01, 0x0E01, 0x0F01, 0xF102, + 0xF202, 0xF302, 0xF402, 0xF502, 0xF602, 0xF702, 0xF802, 0xF902, + 0xFA02, 0xFB02, 0xFC02, 0xFD02, 0xFE02, 0xFF02, 0x0002, 0x0102, + 0x0202, 0x0302, 0x0402, 0x0502, 0x0602, 0x0702, 0x0802, 0x0902, + 0x0A02, 0x0B02, 0x0C02, 0x0D02, 0x0E02, 0x0F02, 0xF103, 0xF203, + 0xF303, 0xF403, 0xF503, 0xF603, 0xF703, 0xF803, 0xF903, 0xFA03, + 0xFB03, 0xFC03, 0xFD03, 0xFE03, 0xFF03, 0x0003, 0x0103, 0x0203, + 0x0303, 0x0403, 0x0503, 0x0603, 0x0703, 0x0803, 0x0903, 0x0A03, + 0x0B03, 0x0C03, 0x0D03, 0x0E03, 0x0F03, 0xF104, 0xF204, 0xF304, + 0xF404, 0xF504, 0xF604, 0xF704, 0xF804, 0xF904, 0xFA04, 0xFB04, + 0xFC04, 0xFD04, 0xFE04, 0xFF04, 0x0004, 0x0104, 0x0204, 0x0304, + 0x0404, 0x0504, 0x0604, 0x0704, 0x0804, 0x0904, 0x0A04, 0x0B04, + 0x0C04, 0x0D04, 0x0E04, 0x0F04, 0xF105, 0xF205, 0xF305, 0xF405, + 0xF505, 0xF605, 0xF705, 0xF805, 0xF905, 0xFA05, 0xFB05, 0xFC05, + 0xFD05, 0xFE05, 0xFF05, 0x0005, 0x0105, 0x0205, 0x0305, 0x0405, + 0x0505, 0x0605, 0x0705, 0x0805, 0x0905, 0x0A05, 0x0B05, 0x0C05, + 0x0D05, 0x0E05, 0x0F05, 0xF106, 0xF206, 0xF306, 0xF406, 0xF506, + 0xF606, 0xF706, 0xF806, 0xF906, 0xFA06, 0xFB06, 0xFC06, 0xFD06, + 0xFE06, 0xFF06, 0x0006, 0x0106, 0x0206, 0x0306, 0x0406, 0x0506, + 0x0606, 0x0706, 0x0806, 0x0906, 0x0A06, 0x0B06, 0x0C06, 0x0D06, + 0x0E06, 0x0F06, 0xF107, 0xF207, 0xF307, 0xF407, 0xF507, 0xF607, + 0xF707, 0xF807, 0xF907, 0xFA07, 0xFB07, 0xFC07, 0xFD07, 0xFE07, + 0xFF07, 0x0007, 0x0107, 0x0207, 0x0307, 0x0407, 0x0507, 0x0607, + 0x0707, 0x0807, 0x0907, 0x0A07, 0x0B07, 0x0C07, 0x0D07, 0x0E07, + 0x0F07, 0xF108, 0xF208, 0xF308, 0xF408, 0xF508, 0xF608, 0xF708, + 0xF808, 0xF908, 0xFA08, 0xFB08, 0xFC08, 0xFD08, 0xFE08, 0xFF08, + 0x0008, 0x0108, 0x0208, 0x0308, 0x0408, 0x0508, 0x0608, 0x0708, + 0x0808, 0x0908, 0x0A08, 0x0B08, 0x0C08, 0x0D08, 0x0E08, 0x0F08, + 0xF109, 0xF209, 0xF309, 0xF409, 0xF509, 0xF609, 0xF709, 0xF809, + 0xF909, 0xFA09, 0xFB09, 0xFC09, 0xFD09, 0xFE09, 0xFF09, 0x0009, + 0x0109, 0x0209, 0x0309, 0x0409, 0x0509, 0x0609, 0x0709, 0x0809, + 0x0909, 0x0A09, 0x0B09, 0x0C09, 0x0D09, 0x0E09, 0x0F09, 0xF10A, + 0xF20A, 0xF30A, 0xF40A, 0xF50A, 0xF60A, 0xF70A, 0xF80A, 0xF90A, + 0xFA0A, 0xFB0A, 0xFC0A, 0xFD0A, 0xFE0A, 0xFF0A, 0x000A, 0x010A, + 0x020A, 0x030A, 0x040A, 0x050A, 0x060A, 0x070A, 0x080A, 0x090A, + 0x0A0A, 0x0B0A, 0x0C0A, 0x0D0A, 0x0E0A, 0x0F0A, 0xF10B, 0xF20B, + 0xF30B, 0xF40B, 0xF50B, 0xF60B, 0xF70B, 0xF80B, 0xF90B, 0xFA0B, + 0xFB0B, 0xFC0B, 0xFD0B, 0xFE0B, 0xFF0B, 0x000B, 0x010B, 0x020B, + 0x030B, 0x040B, 0x050B, 0x060B, 0x070B, 0x080B, 0x090B, 0x0A0B, + 0x0B0B, 0x0C0B, 0x0D0B, 0x0E0B, 0x0F0B, 0xF10C, 0xF20C, 0xF30C, + 0xF40C, 0xF50C, 0xF60C, 0xF70C, 0xF80C, 0xF90C, 0xFA0C, 0xFB0C, + 0xFC0C, 0xFD0C, 0xFE0C, 0xFF0C, 0x000C, 0x010C, 0x020C, 0x030C, + 0x040C, 0x050C, 0x060C, 0x070C, 0x080C, 0x090C, 0x0A0C, 0x0B0C, + 0x0C0C, 0x0D0C, 0x0E0C, 0x0F0C, 0xF10D, 0xF20D, 0xF30D, 0xF40D, + 0xF50D, 0xF60D, 0xF70D, 0xF80D, 0xF90D, 0xFA0D, 0xFB0D, 0xFC0D, + 0xFD0D, 0xFE0D, 0xFF0D, 0x000D, 0x010D, 0x020D, 0x030D, 0x040D, + 0x050D, 0x060D, 0x070D, 0x080D, 0x090D, 0x0A0D, 0x0B0D, 0x0C0D, + 0x0D0D, 0x0E0D, 0x0F0D, 0xF10E, 0xF20E, 0xF30E, 0xF40E, 0xF50E, + 0xF60E, 0xF70E, 0xF80E, 0xF90E, 0xFA0E, 0xFB0E, 0xFC0E, 0xFD0E, + 0xFE0E, 0xFF0E, 0x000E, 0x010E, 0x020E, 0x030E, 0x040E, 0x050E, + 0x060E, 0x070E, 0x080E, 0x090E, 0x0A0E, 0x0B0E, 0x0C0E, 0x0D0E, + 0x0E0E, 0x0F0E, 0xF10F, 0xF20F, 0xF30F, 0xF40F, 0xF50F, 0xF60F, + 0xF70F, 0xF80F, 0xF90F, 0xFA0F, 0xFB0F, 0xFC0F, 0xFD0F, 0xFE0F, + 0xFF0F, 0x000F, 0x010F, 0x020F, 0x030F, 0x040F, 0x050F, 0x060F, + 0x070F, 0x080F, 0x090F, 0x0A0F, 0x0B0F, 0x0C0F, 0x0D0F, 0x0E0F, + 0x0F0F, 0x1010, +}; + +static const uint8_t clv_mvy_3_bits[] = { + 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 13, + 13, 12, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 15, 15, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, + 15, 15, 14, 14, 14, 13, 12, 11, 12, 13, 14, 14, 14, 15, 15, 15, + 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, + 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 12, 11, 12, 14, 14, + 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, + 16, 16, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, + 12, 11, 12, 13, 13, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, + 15, 16, 16, 16, 16, 16, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 13, 13, 12, 10, 12, 13, 13, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 15, 15, 15, 15, + 14, 14, 14, 14, 13, 13, 13, 13, 13, 12, 12, 10, 12, 12, 13, 13, + 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 15, 15, + 15, 15, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 11, + 10, 11, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 13, 13, 13, 13, 12, 12, + 12, 12, 12, 11, 10, 9, 10, 11, 12, 12, 12, 12, 12, 13, 13, 13, + 13, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 13, 13, + 12, 12, 12, 12, 12, 12, 12, 11, 11, 10, 9, 10, 11, 11, 12, 12, + 12, 12, 12, 12, 12, 13, 13, 14, 14, 14, 15, 15, 15, 16, 15, 15, + 15, 15, 14, 14, 13, 13, 12, 12, 12, 12, 12, 11, 11, 11, 10, 9, + 10, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 14, 14, 15, 15, 15, + 15, 16, 15, 15, 14, 14, 14, 14, 14, 13, 13, 12, 12, 12, 12, 12, + 11, 11, 11, 10, 9, 10, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, + 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 14, 14, 14, 13, 13, 12, + 12, 12, 12, 12, 12, 11, 11, 11, 10, 8, 10, 11, 11, 11, 12, 12, + 12, 12, 12, 12, 13, 13, 14, 14, 14, 15, 15, 15, 15, 15, 14, 14, + 14, 14, 13, 13, 12, 12, 12, 12, 12, 11, 11, 11, 10, 10, 8, 10, + 10, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 14, 14, 14, 14, 15, + 15, 15, 14, 14, 14, 14, 13, 13, 13, 12, 12, 12, 12, 11, 11, 11, + 10, 10, 9, 7, 9, 10, 10, 11, 11, 11, 12, 12, 12, 12, 13, 13, + 13, 14, 14, 14, 14, 15, 15, 14, 14, 14, 14, 13, 13, 13, 12, 12, + 12, 12, 11, 11, 11, 10, 10, 9, 7, 9, 10, 10, 11, 11, 11, 12, + 12, 12, 12, 13, 13, 13, 14, 14, 14, 14, 15, 15, 14, 14, 14, 14, + 13, 13, 12, 12, 12, 12, 11, 11, 11, 11, 10, 9, 9, 7, 9, 9, + 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 14, 14, 14, 14, 15, + 15, 14, 14, 14, 13, 13, 13, 13, 12, 11, 11, 11, 11, 10, 10, 10, + 9, 8, 6, 8, 9, 10, 10, 10, 11, 11, 11, 11, 12, 13, 13, 13, + 13, 14, 14, 14, 15, 15, 14, 14, 14, 13, 13, 12, 12, 11, 11, 11, + 11, 10, 10, 9, 9, 8, 6, 4, 6, 8, 9, 9, 10, 10, 11, 11, + 11, 11, 12, 12, 13, 13, 14, 14, 14, 15, 13, 13, 13, 12, 12, 12, + 12, 11, 10, 10, 10, 10, 9, 9, 8, 8, 7, 5, 2, 5, 7, 8, + 8, 9, 9, 10, 10, 10, 10, 11, 12, 12, 12, 12, 13, 13, 13, 15, + 14, 14, 14, 13, 13, 12, 12, 11, 11, 11, 11, 10, 10, 9, 9, 8, + 6, 4, 6, 8, 9, 9, 10, 10, 11, 11, 11, 11, 12, 12, 13, 13, + 14, 14, 14, 15, 15, 14, 14, 14, 13, 13, 13, 13, 12, 11, 11, 11, + 11, 10, 10, 10, 9, 8, 6, 8, 9, 10, 10, 10, 11, 11, 11, 11, + 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, 14, 14, 14, 14, 13, 13, + 12, 12, 12, 12, 11, 11, 11, 11, 10, 9, 9, 7, 9, 9, 10, 11, + 11, 11, 11, 12, 12, 12, 12, 13, 13, 14, 14, 14, 14, 15, 15, 14, + 14, 14, 14, 13, 13, 13, 12, 12, 12, 12, 11, 11, 11, 10, 10, 9, + 7, 9, 10, 10, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 14, 14, + 14, 14, 15, 15, 14, 14, 14, 14, 13, 13, 13, 12, 12, 12, 12, 11, + 11, 11, 10, 10, 9, 7, 9, 10, 10, 11, 11, 11, 12, 12, 12, 12, + 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 14, 14, 14, 14, 13, 13, + 12, 12, 12, 12, 12, 11, 11, 11, 10, 10, 8, 10, 10, 11, 11, 11, + 12, 12, 12, 12, 12, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 15, + 14, 14, 14, 13, 13, 12, 12, 12, 12, 12, 12, 11, 11, 11, 10, 8, + 10, 11, 11, 11, 12, 12, 12, 12, 12, 12, 13, 13, 14, 14, 14, 15, + 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 12, 12, 12, 12, 12, + 11, 11, 11, 10, 9, 10, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, + 14, 14, 14, 14, 14, 15, 15, 16, 15, 15, 15, 15, 14, 14, 13, 13, + 12, 12, 12, 12, 12, 11, 11, 11, 10, 9, 10, 11, 11, 11, 12, 12, + 12, 12, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 15, 15, 15, 14, + 14, 14, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 10, 9, 10, + 11, 11, 12, 12, 12, 12, 12, 12, 12, 13, 13, 14, 14, 14, 15, 15, + 15, 15, 15, 15, 15, 14, 14, 14, 13, 13, 13, 13, 12, 12, 12, 12, + 12, 11, 10, 9, 10, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 14, + 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, + 13, 13, 13, 13, 13, 13, 13, 11, 10, 11, 13, 13, 13, 13, 13, 13, + 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 15, 15, + 15, 15, 14, 14, 14, 14, 13, 13, 13, 13, 13, 12, 12, 10, 12, 12, + 13, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, + 16, 16, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, + 13, 12, 10, 12, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, + 15, 15, 15, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 14, + 14, 14, 14, 14, 13, 13, 12, 11, 12, 13, 13, 14, 14, 14, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 15, 15, 15, + 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 12, 11, 12, 14, 14, + 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 13, + 12, 11, 12, 13, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, + 15, 14, 14, 13, 13, 12, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, + 15, 15, 16, 16, 16, 16, 16, 16, 16, 7, +}; + +static const uint16_t clv_mvy_3_codes[] = { + 0xFFF6, 0xFFEE, 0xFFDC, 0xFFD7, 0xFFB4, 0xFFAA, 0xFFA0, 0x7FCC, + 0x7F8E, 0x7F7B, 0x7F77, 0x7F13, 0x7F11, 0x3F56, 0x3F48, 0x1F16, + 0x1E94, 0x0F28, 0x06F0, 0x0F2A, 0x1E96, 0x1F1C, 0x3F46, 0x3F58, + 0x7F15, 0x7F0E, 0x7F76, 0x7F80, 0x7F90, 0x7FC8, 0xFFA2, 0xFFA7, + 0xFFB5, 0xFFD8, 0xFFDD, 0xFFEC, 0xFFF5, 0xFFF1, 0xFFEA, 0xFFE4, + 0xFFD1, 0xFFC1, 0xFFA8, 0x7F70, 0x7F5C, 0x7F44, 0x7F40, 0x7F2A, + 0x7F16, 0x7EDF, 0x3ED6, 0x3ECA, 0x3ECC, 0x1EB5, 0x0EDE, 0x06D3, + 0x0EDF, 0x1EB6, 0x3ECE, 0x3ED0, 0x3ED8, 0x7EE5, 0x7F19, 0x7F31, + 0x7F3E, 0x7F45, 0x7F5B, 0x7F6F, 0xFFA9, 0xFFC0, 0xFFCE, 0xFFE5, + 0xFFE8, 0xFFF2, 0xFFFE, 0xFFE2, 0xFFBE, 0x7FBB, 0x7F75, 0x7F6B, + 0x7F58, 0x7EF9, 0x7EDC, 0x3F68, 0x3F27, 0x3F28, 0x3EDF, 0x3ED2, + 0x3EC1, 0x3EA6, 0x3E87, 0x0F0F, 0x06B3, 0x0F10, 0x3E89, 0x3EA8, + 0x3EC3, 0x3ED5, 0x3EE0, 0x3F2B, 0x3F26, 0x3F67, 0x7EDA, 0x7EFB, + 0x7F56, 0x7F6A, 0x7F72, 0x7FC1, 0xFFBC, 0xFFE0, 0xFFFF, 0xFFF8, + 0xFFD3, 0xFFB9, 0x7FAC, 0x7F94, 0x7F8B, 0x7F62, 0x7F4A, 0x7F05, + 0x7EEE, 0x3F44, 0x3EA4, 0x3E78, 0x3E6F, 0x3E54, 0x1EEF, 0x1EA9, + 0x0ED4, 0x06A8, 0x0ED5, 0x1EA8, 0x1EEC, 0x3E51, 0x3E69, 0x3E75, + 0x3EA3, 0x3F43, 0x7EF1, 0x7F04, 0x7F4B, 0x7F5D, 0x7F89, 0x7F95, + 0x7FAA, 0xFFBB, 0xFFC8, 0xFFF9, 0xFFD9, 0xFFCA, 0x7FC3, 0x7F8C, + 0x7F38, 0x7F02, 0x3F5A, 0x3F4A, 0x3F30, 0x3EFF, 0x3EF4, 0x3EE9, + 0x3E95, 0x3E73, 0x3E43, 0x1F08, 0x1E81, 0x0E84, 0x0349, 0x0E85, + 0x1E82, 0x1F07, 0x3E45, 0x3E74, 0x3E96, 0x3EEA, 0x3EF1, 0x3F00, + 0x3F32, 0x3F4F, 0x3F5C, 0x7F01, 0x7F3B, 0x7F8D, 0x7FC2, 0xFFCF, + 0xFFD6, 0xFFC7, 0xFFB1, 0xFFA6, 0x7FA1, 0x7F2F, 0x7F24, 0x7F0A, + 0x3EF6, 0x3E97, 0x3E83, 0x3E7F, 0x1F04, 0x1EE1, 0x1ECB, 0x1EAE, + 0x1E7E, 0x0EBA, 0x0E8C, 0x0333, 0x0E8D, 0x0EBB, 0x1E7F, 0x1EAF, + 0x1ECC, 0x1EE2, 0x1F05, 0x3E80, 0x3E84, 0x3E98, 0x3EF9, 0x7F06, + 0x7F1B, 0x7F2D, 0x7F9F, 0xFFAF, 0xFFB0, 0xFFC6, 0x7FB5, 0x7FB1, + 0x7F36, 0x7F25, 0x3F63, 0x3F3A, 0x3F1B, 0x3EBB, 0x3E63, 0x3E5B, + 0x3E40, 0x1F14, 0x1EF5, 0x1EEB, 0x1EBE, 0x1E92, 0x1E6A, 0x070C, + 0x032D, 0x070D, 0x1E6B, 0x1E93, 0x1EBF, 0x1EE8, 0x1EF3, 0x1F15, + 0x3E3F, 0x3E5C, 0x3E64, 0x3EB9, 0x3F1C, 0x3F3C, 0x3F62, 0x7F22, + 0x7F39, 0x7FAF, 0x7FAE, 0x7FC6, 0x7F7F, 0x7F53, 0x7F32, 0x3F66, + 0x3EF0, 0x3E65, 0x1EDA, 0x1ED3, 0x1E98, 0x1E74, 0x0F20, 0x0F1D, + 0x0EEA, 0x0EA9, 0x0E70, 0x0718, 0x033E, 0x0179, 0x033F, 0x0719, + 0x0E71, 0x0EAB, 0x0EE9, 0x0F1F, 0x0F22, 0x1E76, 0x1E9B, 0x1ED5, + 0x1EDD, 0x3E68, 0x3EF3, 0x3F6C, 0x7F33, 0x7F4E, 0x7F7D, 0x7FCB, + 0x7FBD, 0x7F21, 0x7EF6, 0x3F0C, 0x3EBE, 0x3EAE, 0x1EA3, 0x1E85, + 0x0F0C, 0x0F06, 0x0EEE, 0x0EE6, 0x0ECA, 0x0EA2, 0x0E78, 0x0720, + 0x06BA, 0x0326, 0x015D, 0x0327, 0x06BB, 0x0721, 0x0E79, 0x0EA3, + 0x0ECB, 0x0EE7, 0x0EEF, 0x0F07, 0x0F0D, 0x1E86, 0x1EA4, 0x3EAF, + 0x3EBF, 0x3F0A, 0x7EF8, 0x7F1E, 0x7FBF, 0xFF9F, 0x7FB3, 0x7F96, + 0x7F0B, 0x7EF5, 0x3E85, 0x3E4E, 0x1EB3, 0x1E6E, 0x0F2D, 0x0EBD, + 0x0E97, 0x0E93, 0x0E86, 0x071A, 0x06E4, 0x06BC, 0x0338, 0x015A, + 0x0339, 0x06BD, 0x06E5, 0x071B, 0x0E87, 0x0E94, 0x0E98, 0x0EBE, + 0x0F2E, 0x1E6F, 0x1EB4, 0x3E4F, 0x3E88, 0x7EF4, 0x7F07, 0x7F99, + 0x7FB7, 0xFF9D, 0x7FA8, 0x7EEB, 0x3F5D, 0x3EB2, 0x3EAA, 0x3E5D, + 0x3E49, 0x1EFE, 0x1E89, 0x0F16, 0x0F12, 0x0EE0, 0x0E7A, 0x0E6A, + 0x070E, 0x06FA, 0x06B4, 0x0314, 0x0158, 0x0315, 0x06B5, 0x06FB, + 0x070F, 0x0E6B, 0x0E7B, 0x0EE1, 0x0F13, 0x0F17, 0x1E8A, 0x1EFF, + 0x3E4A, 0x3E5E, 0x3EAB, 0x3EB3, 0x3F59, 0x7EEC, 0x7FA2, 0x7F82, + 0x7F5E, 0x7F28, 0x3EDA, 0x3EC9, 0x3E7A, 0x1ED6, 0x1ECE, 0x0EFC, + 0x0EF0, 0x0E9A, 0x0E7E, 0x0E66, 0x0E5E, 0x0722, 0x06C0, 0x06A0, + 0x02FA, 0x00A8, 0x02FB, 0x06A1, 0x06C1, 0x0723, 0x0E5F, 0x0E67, + 0x0E7F, 0x0E9B, 0x0EF1, 0x0EFD, 0x1ECF, 0x1ED7, 0x3E79, 0x3ECD, + 0x3EDB, 0x7F26, 0x7F5A, 0x7F83, 0x7F54, 0x7EE8, 0x3F54, 0x3F0E, + 0x3EFB, 0x3E47, 0x1EC1, 0x1EB9, 0x0EF9, 0x0EF3, 0x0EC1, 0x0E8F, + 0x0E74, 0x0714, 0x06F4, 0x06B0, 0x0336, 0x030A, 0x009F, 0x030B, + 0x0337, 0x06B1, 0x06F5, 0x0715, 0x0E75, 0x0E91, 0x0EC3, 0x0EF6, + 0x0EFB, 0x1EBB, 0x1EC3, 0x3E41, 0x3EF8, 0x3F10, 0x3F4D, 0x7EE9, + 0x7F52, 0x7F9A, 0x3F3F, 0x3F1F, 0x3F03, 0x3EA0, 0x1F0F, 0x1E72, + 0x1E62, 0x0EDA, 0x0ED2, 0x0EB2, 0x0E64, 0x0708, 0x06EA, 0x06DA, + 0x0346, 0x032A, 0x0176, 0x004B, 0x0177, 0x032B, 0x0347, 0x06DB, + 0x06EB, 0x0709, 0x0E65, 0x0EB3, 0x0ED3, 0x0EDB, 0x1E63, 0x1E6C, + 0x1F0E, 0x3E9E, 0x3F01, 0x3F1D, 0x3F3D, 0x7F9B, 0x7EDE, 0x3F36, + 0x3F2E, 0x3F07, 0x3E99, 0x1F0D, 0x1EA1, 0x1E8C, 0x0EB4, 0x0EAC, + 0x0E5A, 0x0E50, 0x0702, 0x06D4, 0x06C6, 0x032E, 0x0310, 0x0162, + 0x0046, 0x0163, 0x0311, 0x032F, 0x06C7, 0x06D5, 0x0703, 0x0E51, + 0x0E5B, 0x0EAD, 0x0EB5, 0x1E8F, 0x1EA7, 0x1F0C, 0x3E9A, 0x3F02, + 0x3F2D, 0x3F35, 0x7EE0, 0x7F66, 0x3F11, 0x3EE1, 0x3EBC, 0x3E56, + 0x1EC4, 0x1E64, 0x0F04, 0x0EC7, 0x0E56, 0x0E4C, 0x06EC, 0x06DC, + 0x069C, 0x0694, 0x0320, 0x016C, 0x0154, 0x0044, 0x0155, 0x016D, + 0x0321, 0x0695, 0x069D, 0x06DD, 0x06ED, 0x0E4D, 0x0E57, 0x0EC4, + 0x0F05, 0x1E65, 0x1EC5, 0x3E55, 0x3EB7, 0x3EE3, 0x3F13, 0x7F67, + 0x7FA7, 0x3F49, 0x3F22, 0x3EE5, 0x1EF6, 0x1EE5, 0x1E9C, 0x1E78, + 0x0EA4, 0x06F6, 0x06DE, 0x06CE, 0x06AA, 0x0340, 0x0318, 0x02FE, + 0x015E, 0x009A, 0x001C, 0x009B, 0x015F, 0x02FF, 0x0319, 0x0341, + 0x06AB, 0x06CF, 0x06DF, 0x06F7, 0x0EA5, 0x1E79, 0x1E9D, 0x1EE7, + 0x1EF7, 0x3EE6, 0x3F23, 0x3F4B, 0x7FA3, 0x7F49, 0x3F14, 0x3E8D, + 0x3E6B, 0x1F17, 0x1EF8, 0x0F24, 0x0ECC, 0x06FE, 0x06CA, 0x06A4, + 0x0698, 0x030C, 0x0302, 0x0170, 0x0168, 0x00A0, 0x001E, 0x0004, + 0x001F, 0x00A1, 0x0169, 0x0171, 0x0303, 0x030D, 0x0699, 0x06A5, + 0x06CB, 0x06FF, 0x0ECD, 0x0F25, 0x1EF9, 0x1F18, 0x3E6C, 0x3E8E, + 0x3F15, 0x7F46, 0x1EF0, 0x1EDE, 0x1EC8, 0x0F1A, 0x0F00, 0x0E9E, + 0x0E54, 0x06C4, 0x031E, 0x031C, 0x0306, 0x02F8, 0x017A, 0x0166, + 0x00A6, 0x00A4, 0x0048, 0x000C, 0x0000, 0x000D, 0x0049, 0x00A5, + 0x00A7, 0x0167, 0x017B, 0x02F9, 0x0307, 0x031D, 0x031F, 0x06C5, + 0x0E55, 0x0E9F, 0x0F01, 0x0F1B, 0x1EC9, 0x1EDF, 0x1EF1, 0x7F47, + 0x3F12, 0x3E8F, 0x3E6D, 0x1F1B, 0x1EFA, 0x0F26, 0x0ECE, 0x0700, + 0x06CC, 0x06A6, 0x069A, 0x030E, 0x0304, 0x0172, 0x016A, 0x00A2, + 0x0020, 0x0005, 0x0021, 0x00A3, 0x016B, 0x0173, 0x0305, 0x030F, + 0x069B, 0x06A7, 0x06CD, 0x0701, 0x0ECF, 0x0F27, 0x1EFB, 0x1F1D, + 0x3E6E, 0x3E90, 0x3F17, 0x7F48, 0x7FA9, 0x3F50, 0x3F24, 0x3EE7, + 0x1EFC, 0x1EE9, 0x1E9E, 0x1E7A, 0x0EA6, 0x06F8, 0x06E0, 0x06D0, + 0x06AC, 0x0342, 0x031A, 0x0300, 0x0160, 0x009C, 0x001D, 0x009D, + 0x0161, 0x0301, 0x031B, 0x0343, 0x06AD, 0x06D1, 0x06E1, 0x06F9, + 0x0EA7, 0x1E7B, 0x1E9F, 0x1EEA, 0x1EFD, 0x3EE8, 0x3F21, 0x3F52, + 0x7F9E, 0x7F68, 0x3F16, 0x3EE2, 0x3EBA, 0x3E57, 0x1EC6, 0x1E66, + 0x0F08, 0x0EC5, 0x0E58, 0x0E4E, 0x06EE, 0x06E2, 0x069E, 0x0696, + 0x0322, 0x016E, 0x0156, 0x0045, 0x0157, 0x016F, 0x0323, 0x0697, + 0x069F, 0x06E3, 0x06EF, 0x0E4F, 0x0E59, 0x0EC6, 0x0F09, 0x1E67, + 0x1EC7, 0x3E58, 0x3EB8, 0x3EE4, 0x3F18, 0x7F69, 0x7EE2, 0x3F38, + 0x3F33, 0x3F04, 0x3E9C, 0x1F0A, 0x1EA5, 0x1E8D, 0x0EB6, 0x0EAE, + 0x0E5C, 0x0E52, 0x0704, 0x06D6, 0x06C8, 0x0330, 0x0312, 0x0164, + 0x0047, 0x0165, 0x0313, 0x0331, 0x06C9, 0x06D7, 0x0705, 0x0E53, + 0x0E5D, 0x0EAF, 0x0EB7, 0x1E8E, 0x1EA6, 0x1F0B, 0x3E9B, 0x3F05, + 0x3F31, 0x3F39, 0x7EE1, 0x7F9C, 0x3F40, 0x3F1E, 0x3F06, 0x3E9D, + 0x1F10, 0x1E70, 0x1E60, 0x0ED8, 0x0ED0, 0x0EB0, 0x0E62, 0x0706, + 0x06E8, 0x06D8, 0x0344, 0x0328, 0x0174, 0x004A, 0x0175, 0x0329, + 0x0345, 0x06D9, 0x06E9, 0x0707, 0x0E63, 0x0EB1, 0x0ED1, 0x0ED9, + 0x1E61, 0x1E71, 0x1F11, 0x3E9F, 0x3F08, 0x3F20, 0x3F3E, 0x7F9D, + 0x7F4F, 0x7EE6, 0x3F53, 0x3F0D, 0x3EFA, 0x3E46, 0x1EC0, 0x1EB8, + 0x0EF8, 0x0EF2, 0x0EC0, 0x0E8E, 0x0E72, 0x0712, 0x06F2, 0x06AE, + 0x0334, 0x0308, 0x009E, 0x0309, 0x0335, 0x06AF, 0x06F3, 0x0713, + 0x0E73, 0x0E90, 0x0EC2, 0x0EF4, 0x0EFA, 0x1EBA, 0x1EC2, 0x3E48, + 0x3EFC, 0x3F0B, 0x3F51, 0x7EE7, 0x7F51, 0x7F84, 0x7F61, 0x7F27, + 0x3EDC, 0x3EC5, 0x3E7C, 0x1ED8, 0x1ED0, 0x0EFE, 0x0EF5, 0x0E9C, + 0x0E80, 0x0E68, 0x0E60, 0x0724, 0x06C2, 0x06A2, 0x02FC, 0x00A9, + 0x02FD, 0x06A3, 0x06C3, 0x0725, 0x0E61, 0x0E69, 0x0E81, 0x0E9D, + 0x0EF7, 0x0EFF, 0x1ED1, 0x1ED9, 0x3E7B, 0x3ECF, 0x3ED9, 0x7F29, + 0x7F65, 0x7F85, 0x7FA0, 0x7EEA, 0x3F60, 0x3EB4, 0x3EAC, 0x3E5F, + 0x3E4B, 0x1F00, 0x1E8B, 0x0F18, 0x0F14, 0x0EE2, 0x0E7C, 0x0E6C, + 0x0710, 0x06FC, 0x06B6, 0x0316, 0x0159, 0x0317, 0x06B7, 0x06FD, + 0x0711, 0x0E6D, 0x0E7D, 0x0EE3, 0x0F15, 0x0F19, 0x1E88, 0x1F01, + 0x3E4C, 0x3E60, 0x3EA9, 0x3EB1, 0x3F5B, 0x7EED, 0x7FA5, 0xFF9E, + 0x7FBE, 0x7F98, 0x7F0D, 0x7EF3, 0x3E8C, 0x3E50, 0x1EB7, 0x1E73, + 0x0F2F, 0x0EBF, 0x0E99, 0x0E95, 0x0E88, 0x071C, 0x06E6, 0x06BE, + 0x033A, 0x015B, 0x033B, 0x06BF, 0x06E7, 0x071D, 0x0E89, 0x0E92, + 0x0E96, 0x0EBC, 0x0F2C, 0x1E6D, 0x1EB0, 0x3E4D, 0x3E8B, 0x7EF2, + 0x7F08, 0x7F97, 0x7FB0, 0xFF9C, 0x7FB2, 0x7F23, 0x7EFA, 0x3F0F, + 0x3EBD, 0x3EAD, 0x1EA0, 0x1E87, 0x0F0A, 0x0F02, 0x0EED, 0x0EE4, + 0x0EC8, 0x0EA0, 0x0E76, 0x071E, 0x06B8, 0x0324, 0x015C, 0x0325, + 0x06B9, 0x071F, 0x0E77, 0x0EA1, 0x0EC9, 0x0EE5, 0x0EEC, 0x0F03, + 0x0F0B, 0x1E84, 0x1EA2, 0x3EB0, 0x3EC4, 0x3F09, 0x7EF7, 0x7F1D, + 0x7FBC, 0x7FCD, 0x7F81, 0x7F50, 0x7F34, 0x3F65, 0x3EED, 0x3E67, + 0x1EDB, 0x1ED2, 0x1E99, 0x1E77, 0x0F21, 0x0F1C, 0x0EE8, 0x0EA8, + 0x0E6E, 0x0716, 0x033C, 0x0178, 0x033D, 0x0717, 0x0E6F, 0x0EAA, + 0x0EEB, 0x0F1E, 0x0F23, 0x1E75, 0x1E9A, 0x1ED4, 0x1EDC, 0x3E66, + 0x3EEE, 0x3F6B, 0x7F35, 0x7F55, 0x7F7A, 0x7FCA, 0x7FB6, 0x7FB8, + 0x7F37, 0x7F1F, 0x3F61, 0x3F37, 0x3F1A, 0x3EB5, 0x3E62, 0x3E5A, + 0x1F1E, 0x1F13, 0x1EF2, 0x1EE6, 0x1EBC, 0x1E91, 0x1E68, 0x070A, + 0x032C, 0x070B, 0x1E69, 0x1E90, 0x1EBD, 0x1EE4, 0x1EF4, 0x1F12, + 0x3E3E, 0x3E59, 0x3E61, 0x3EB6, 0x3F19, 0x3F3B, 0x3F64, 0x7F1C, + 0x7F3D, 0x7FB4, 0x7FB9, 0xFFC5, 0xFFB6, 0xFFAD, 0x7FA4, 0x7F2C, + 0x7F20, 0x7F09, 0x3EF5, 0x3E93, 0x3E82, 0x3E7E, 0x1F02, 0x1EE3, + 0x1ECA, 0x1EAD, 0x1E7C, 0x0EB8, 0x0E8A, 0x0332, 0x0E8B, 0x0EB9, + 0x1E7D, 0x1EAC, 0x1ECD, 0x1EE0, 0x1F03, 0x3E7D, 0x3E81, 0x3E91, + 0x3EF7, 0x7F0C, 0x7F1A, 0x7F2E, 0x7FA6, 0xFFA4, 0xFFB7, 0xFFC4, + 0xFFD4, 0xFFCC, 0x7FC5, 0x7F8A, 0x7F3C, 0x7EFF, 0x3F5E, 0x3F4E, + 0x3F2F, 0x3EFD, 0x3EEF, 0x3EEB, 0x3E92, 0x3E71, 0x3E42, 0x1F09, + 0x1E83, 0x0E82, 0x0348, 0x0E83, 0x1E80, 0x1F06, 0x3E44, 0x3E72, + 0x3E94, 0x3EEC, 0x3EF2, 0x3EFE, 0x3F34, 0x3F4C, 0x3F5F, 0x7EFE, + 0x7F3A, 0x7F86, 0x7FC4, 0xFFD2, 0xFFD5, 0xFFFA, 0xFFCD, 0xFFBA, + 0x7FAB, 0x7F92, 0x7F87, 0x7F63, 0x7F4C, 0x7F03, 0x7EF0, 0x3F42, + 0x3EA1, 0x3E76, 0x3E6A, 0x3E52, 0x1EEE, 0x1EAB, 0x0ED6, 0x06A9, + 0x0ED7, 0x1EAA, 0x1EED, 0x3E53, 0x3E70, 0x3E77, 0x3EA2, 0x3F41, + 0x7EEF, 0x7F00, 0x7F4D, 0x7F60, 0x7F88, 0x7F93, 0x7FAD, 0xFFB8, + 0xFFCB, 0xFFFB, 0xFFFC, 0xFFE1, 0xFFBF, 0x7FBA, 0x7F73, 0x7F6C, + 0x7F57, 0x7EFC, 0x7EDD, 0x3F6A, 0x3F2A, 0x3F25, 0x3EDD, 0x3ED3, + 0x3EC2, 0x3EA7, 0x3E86, 0x0F11, 0x06B2, 0x0F0E, 0x3E8A, 0x3EA5, + 0x3EC0, 0x3ED1, 0x3EDE, 0x3F2C, 0x3F29, 0x3F69, 0x7EDB, 0x7EFD, + 0x7F59, 0x7F6D, 0x7F74, 0x7FC0, 0xFFC3, 0xFFE3, 0xFFFD, 0xFFF0, + 0xFFE9, 0xFFE7, 0xFFC9, 0xFFBD, 0xFFAE, 0x7F71, 0x7F5F, 0x7F42, + 0x7F41, 0x7F30, 0x7F17, 0x7EE4, 0x3ED7, 0x3EC7, 0x3ECB, 0x1EB1, + 0x0EDC, 0x06D2, 0x0EDD, 0x1EB2, 0x3EC6, 0x3EC8, 0x3ED4, 0x7EE3, + 0x7F18, 0x7F2B, 0x7F3F, 0x7F43, 0x7F64, 0x7F6E, 0xFFAB, 0xFFC2, + 0xFFD0, 0xFFE6, 0xFFEF, 0xFFF3, 0xFFF7, 0xFFEB, 0xFFDE, 0xFFDA, + 0xFFB3, 0xFFAC, 0xFFA3, 0x7FC9, 0x7F8F, 0x7F7C, 0x7F79, 0x7F0F, + 0x7F10, 0x3F55, 0x3F45, 0x1F1A, 0x1E95, 0x0F2B, 0x06F1, 0x0F29, + 0x1E97, 0x1F19, 0x3F47, 0x3F57, 0x7F14, 0x7F12, 0x7F78, 0x7F7E, + 0x7F91, 0x7FC7, 0xFFA1, 0xFFA5, 0xFFB2, 0xFFDB, 0xFFDF, 0xFFED, + 0xFFF4, 0x004C, +}; + +static const uint16_t clv_mvy_3_syms[] = { + 0xEEEE, 0xEFEE, 0xF0EE, 0xF1EE, 0xF2EE, 0xF3EE, 0xF4EE, 0xF5EE, + 0xF6EE, 0xF7EE, 0xF8EE, 0xF9EE, 0xFAEE, 0xFBEE, 0xFCEE, 0xFDEE, + 0xFEEE, 0xFFEE, 0x00EE, 0x01EE, 0x02EE, 0x03EE, 0x04EE, 0x05EE, + 0x06EE, 0x07EE, 0x08EE, 0x09EE, 0x0AEE, 0x0BEE, 0x0CEE, 0x0DEE, + 0x0EEE, 0x0FEE, 0x10EE, 0x11EE, 0x12EE, 0xEEEF, 0xEFEF, 0xF0EF, + 0xF1EF, 0xF2EF, 0xF3EF, 0xF4EF, 0xF5EF, 0xF6EF, 0xF7EF, 0xF8EF, + 0xF9EF, 0xFAEF, 0xFBEF, 0xFCEF, 0xFDEF, 0xFEEF, 0xFFEF, 0x00EF, + 0x01EF, 0x02EF, 0x03EF, 0x04EF, 0x05EF, 0x06EF, 0x07EF, 0x08EF, + 0x09EF, 0x0AEF, 0x0BEF, 0x0CEF, 0x0DEF, 0x0EEF, 0x0FEF, 0x10EF, + 0x11EF, 0x12EF, 0xEEF0, 0xEFF0, 0xF0F0, 0xF1F0, 0xF2F0, 0xF3F0, + 0xF4F0, 0xF5F0, 0xF6F0, 0xF7F0, 0xF8F0, 0xF9F0, 0xFAF0, 0xFBF0, + 0xFCF0, 0xFDF0, 0xFEF0, 0xFFF0, 0x00F0, 0x01F0, 0x02F0, 0x03F0, + 0x04F0, 0x05F0, 0x06F0, 0x07F0, 0x08F0, 0x09F0, 0x0AF0, 0x0BF0, + 0x0CF0, 0x0DF0, 0x0EF0, 0x0FF0, 0x10F0, 0x11F0, 0x12F0, 0xEEF1, + 0xEFF1, 0xF0F1, 0xF1F1, 0xF2F1, 0xF3F1, 0xF4F1, 0xF5F1, 0xF6F1, + 0xF7F1, 0xF8F1, 0xF9F1, 0xFAF1, 0xFBF1, 0xFCF1, 0xFDF1, 0xFEF1, + 0xFFF1, 0x00F1, 0x01F1, 0x02F1, 0x03F1, 0x04F1, 0x05F1, 0x06F1, + 0x07F1, 0x08F1, 0x09F1, 0x0AF1, 0x0BF1, 0x0CF1, 0x0DF1, 0x0EF1, + 0x0FF1, 0x10F1, 0x11F1, 0x12F1, 0xEEF2, 0xEFF2, 0xF0F2, 0xF1F2, + 0xF2F2, 0xF3F2, 0xF4F2, 0xF5F2, 0xF6F2, 0xF7F2, 0xF8F2, 0xF9F2, + 0xFAF2, 0xFBF2, 0xFCF2, 0xFDF2, 0xFEF2, 0xFFF2, 0x00F2, 0x01F2, + 0x02F2, 0x03F2, 0x04F2, 0x05F2, 0x06F2, 0x07F2, 0x08F2, 0x09F2, + 0x0AF2, 0x0BF2, 0x0CF2, 0x0DF2, 0x0EF2, 0x0FF2, 0x10F2, 0x11F2, + 0x12F2, 0xEEF3, 0xEFF3, 0xF0F3, 0xF1F3, 0xF2F3, 0xF3F3, 0xF4F3, + 0xF5F3, 0xF6F3, 0xF7F3, 0xF8F3, 0xF9F3, 0xFAF3, 0xFBF3, 0xFCF3, + 0xFDF3, 0xFEF3, 0xFFF3, 0x00F3, 0x01F3, 0x02F3, 0x03F3, 0x04F3, + 0x05F3, 0x06F3, 0x07F3, 0x08F3, 0x09F3, 0x0AF3, 0x0BF3, 0x0CF3, + 0x0DF3, 0x0EF3, 0x0FF3, 0x10F3, 0x11F3, 0x12F3, 0xEEF4, 0xEFF4, + 0xF0F4, 0xF1F4, 0xF2F4, 0xF3F4, 0xF4F4, 0xF5F4, 0xF6F4, 0xF7F4, + 0xF8F4, 0xF9F4, 0xFAF4, 0xFBF4, 0xFCF4, 0xFDF4, 0xFEF4, 0xFFF4, + 0x00F4, 0x01F4, 0x02F4, 0x03F4, 0x04F4, 0x05F4, 0x06F4, 0x07F4, + 0x08F4, 0x09F4, 0x0AF4, 0x0BF4, 0x0CF4, 0x0DF4, 0x0EF4, 0x0FF4, + 0x10F4, 0x11F4, 0x12F4, 0xEEF5, 0xEFF5, 0xF0F5, 0xF1F5, 0xF2F5, + 0xF3F5, 0xF4F5, 0xF5F5, 0xF6F5, 0xF7F5, 0xF8F5, 0xF9F5, 0xFAF5, + 0xFBF5, 0xFCF5, 0xFDF5, 0xFEF5, 0xFFF5, 0x00F5, 0x01F5, 0x02F5, + 0x03F5, 0x04F5, 0x05F5, 0x06F5, 0x07F5, 0x08F5, 0x09F5, 0x0AF5, + 0x0BF5, 0x0CF5, 0x0DF5, 0x0EF5, 0x0FF5, 0x10F5, 0x11F5, 0x12F5, + 0xEEF6, 0xEFF6, 0xF0F6, 0xF1F6, 0xF2F6, 0xF3F6, 0xF4F6, 0xF5F6, + 0xF6F6, 0xF7F6, 0xF8F6, 0xF9F6, 0xFAF6, 0xFBF6, 0xFCF6, 0xFDF6, + 0xFEF6, 0xFFF6, 0x00F6, 0x01F6, 0x02F6, 0x03F6, 0x04F6, 0x05F6, + 0x06F6, 0x07F6, 0x08F6, 0x09F6, 0x0AF6, 0x0BF6, 0x0CF6, 0x0DF6, + 0x0EF6, 0x0FF6, 0x10F6, 0x11F6, 0x12F6, 0xEEF7, 0xEFF7, 0xF0F7, + 0xF1F7, 0xF2F7, 0xF3F7, 0xF4F7, 0xF5F7, 0xF6F7, 0xF7F7, 0xF8F7, + 0xF9F7, 0xFAF7, 0xFBF7, 0xFCF7, 0xFDF7, 0xFEF7, 0xFFF7, 0x00F7, + 0x01F7, 0x02F7, 0x03F7, 0x04F7, 0x05F7, 0x06F7, 0x07F7, 0x08F7, + 0x09F7, 0x0AF7, 0x0BF7, 0x0CF7, 0x0DF7, 0x0EF7, 0x0FF7, 0x10F7, + 0x11F7, 0x12F7, 0xEEF8, 0xEFF8, 0xF0F8, 0xF1F8, 0xF2F8, 0xF3F8, + 0xF4F8, 0xF5F8, 0xF6F8, 0xF7F8, 0xF8F8, 0xF9F8, 0xFAF8, 0xFBF8, + 0xFCF8, 0xFDF8, 0xFEF8, 0xFFF8, 0x00F8, 0x01F8, 0x02F8, 0x03F8, + 0x04F8, 0x05F8, 0x06F8, 0x07F8, 0x08F8, 0x09F8, 0x0AF8, 0x0BF8, + 0x0CF8, 0x0DF8, 0x0EF8, 0x0FF8, 0x10F8, 0x11F8, 0x12F8, 0xEEF9, + 0xEFF9, 0xF0F9, 0xF1F9, 0xF2F9, 0xF3F9, 0xF4F9, 0xF5F9, 0xF6F9, + 0xF7F9, 0xF8F9, 0xF9F9, 0xFAF9, 0xFBF9, 0xFCF9, 0xFDF9, 0xFEF9, + 0xFFF9, 0x00F9, 0x01F9, 0x02F9, 0x03F9, 0x04F9, 0x05F9, 0x06F9, + 0x07F9, 0x08F9, 0x09F9, 0x0AF9, 0x0BF9, 0x0CF9, 0x0DF9, 0x0EF9, + 0x0FF9, 0x10F9, 0x11F9, 0x12F9, 0xEEFA, 0xEFFA, 0xF0FA, 0xF1FA, + 0xF2FA, 0xF3FA, 0xF4FA, 0xF5FA, 0xF6FA, 0xF7FA, 0xF8FA, 0xF9FA, + 0xFAFA, 0xFBFA, 0xFCFA, 0xFDFA, 0xFEFA, 0xFFFA, 0x00FA, 0x01FA, + 0x02FA, 0x03FA, 0x04FA, 0x05FA, 0x06FA, 0x07FA, 0x08FA, 0x09FA, + 0x0AFA, 0x0BFA, 0x0CFA, 0x0DFA, 0x0EFA, 0x0FFA, 0x10FA, 0x11FA, + 0x12FA, 0xEEFB, 0xEFFB, 0xF0FB, 0xF1FB, 0xF2FB, 0xF3FB, 0xF4FB, + 0xF5FB, 0xF6FB, 0xF7FB, 0xF8FB, 0xF9FB, 0xFAFB, 0xFBFB, 0xFCFB, + 0xFDFB, 0xFEFB, 0xFFFB, 0x00FB, 0x01FB, 0x02FB, 0x03FB, 0x04FB, + 0x05FB, 0x06FB, 0x07FB, 0x08FB, 0x09FB, 0x0AFB, 0x0BFB, 0x0CFB, + 0x0DFB, 0x0EFB, 0x0FFB, 0x10FB, 0x11FB, 0x12FB, 0xEEFC, 0xEFFC, + 0xF0FC, 0xF1FC, 0xF2FC, 0xF3FC, 0xF4FC, 0xF5FC, 0xF6FC, 0xF7FC, + 0xF8FC, 0xF9FC, 0xFAFC, 0xFBFC, 0xFCFC, 0xFDFC, 0xFEFC, 0xFFFC, + 0x00FC, 0x01FC, 0x02FC, 0x03FC, 0x04FC, 0x05FC, 0x06FC, 0x07FC, + 0x08FC, 0x09FC, 0x0AFC, 0x0BFC, 0x0CFC, 0x0DFC, 0x0EFC, 0x0FFC, + 0x10FC, 0x11FC, 0x12FC, 0xEEFD, 0xEFFD, 0xF0FD, 0xF1FD, 0xF2FD, + 0xF3FD, 0xF4FD, 0xF5FD, 0xF6FD, 0xF7FD, 0xF8FD, 0xF9FD, 0xFAFD, + 0xFBFD, 0xFCFD, 0xFDFD, 0xFEFD, 0xFFFD, 0x00FD, 0x01FD, 0x02FD, + 0x03FD, 0x04FD, 0x05FD, 0x06FD, 0x07FD, 0x08FD, 0x09FD, 0x0AFD, + 0x0BFD, 0x0CFD, 0x0DFD, 0x0EFD, 0x0FFD, 0x10FD, 0x11FD, 0x12FD, + 0xEEFE, 0xEFFE, 0xF0FE, 0xF1FE, 0xF2FE, 0xF3FE, 0xF4FE, 0xF5FE, + 0xF6FE, 0xF7FE, 0xF8FE, 0xF9FE, 0xFAFE, 0xFBFE, 0xFCFE, 0xFDFE, + 0xFEFE, 0xFFFE, 0x00FE, 0x01FE, 0x02FE, 0x03FE, 0x04FE, 0x05FE, + 0x06FE, 0x07FE, 0x08FE, 0x09FE, 0x0AFE, 0x0BFE, 0x0CFE, 0x0DFE, + 0x0EFE, 0x0FFE, 0x10FE, 0x11FE, 0x12FE, 0xEEFF, 0xEFFF, 0xF0FF, + 0xF1FF, 0xF2FF, 0xF3FF, 0xF4FF, 0xF5FF, 0xF6FF, 0xF7FF, 0xF8FF, + 0xF9FF, 0xFAFF, 0xFBFF, 0xFCFF, 0xFDFF, 0xFEFF, 0xFFFF, 0x00FF, + 0x01FF, 0x02FF, 0x03FF, 0x04FF, 0x05FF, 0x06FF, 0x07FF, 0x08FF, + 0x09FF, 0x0AFF, 0x0BFF, 0x0CFF, 0x0DFF, 0x0EFF, 0x0FFF, 0x10FF, + 0x11FF, 0x12FF, 0xEE00, 0xEF00, 0xF000, 0xF100, 0xF200, 0xF300, + 0xF400, 0xF500, 0xF600, 0xF700, 0xF800, 0xF900, 0xFA00, 0xFB00, + 0xFC00, 0xFD00, 0xFE00, 0xFF00, 0x0000, 0x0100, 0x0200, 0x0300, + 0x0400, 0x0500, 0x0600, 0x0700, 0x0800, 0x0900, 0x0A00, 0x0B00, + 0x0C00, 0x0D00, 0x0E00, 0x0F00, 0x1000, 0x1100, 0x1200, 0xEE01, + 0xEF01, 0xF001, 0xF101, 0xF201, 0xF301, 0xF401, 0xF501, 0xF601, + 0xF701, 0xF801, 0xF901, 0xFA01, 0xFB01, 0xFC01, 0xFD01, 0xFE01, + 0xFF01, 0x0001, 0x0101, 0x0201, 0x0301, 0x0401, 0x0501, 0x0601, + 0x0701, 0x0801, 0x0901, 0x0A01, 0x0B01, 0x0C01, 0x0D01, 0x0E01, + 0x0F01, 0x1001, 0x1101, 0x1201, 0xEE02, 0xEF02, 0xF002, 0xF102, + 0xF202, 0xF302, 0xF402, 0xF502, 0xF602, 0xF702, 0xF802, 0xF902, + 0xFA02, 0xFB02, 0xFC02, 0xFD02, 0xFE02, 0xFF02, 0x0002, 0x0102, + 0x0202, 0x0302, 0x0402, 0x0502, 0x0602, 0x0702, 0x0802, 0x0902, + 0x0A02, 0x0B02, 0x0C02, 0x0D02, 0x0E02, 0x0F02, 0x1002, 0x1102, + 0x1202, 0xEE03, 0xEF03, 0xF003, 0xF103, 0xF203, 0xF303, 0xF403, + 0xF503, 0xF603, 0xF703, 0xF803, 0xF903, 0xFA03, 0xFB03, 0xFC03, + 0xFD03, 0xFE03, 0xFF03, 0x0003, 0x0103, 0x0203, 0x0303, 0x0403, + 0x0503, 0x0603, 0x0703, 0x0803, 0x0903, 0x0A03, 0x0B03, 0x0C03, + 0x0D03, 0x0E03, 0x0F03, 0x1003, 0x1103, 0x1203, 0xEE04, 0xEF04, + 0xF004, 0xF104, 0xF204, 0xF304, 0xF404, 0xF504, 0xF604, 0xF704, + 0xF804, 0xF904, 0xFA04, 0xFB04, 0xFC04, 0xFD04, 0xFE04, 0xFF04, + 0x0004, 0x0104, 0x0204, 0x0304, 0x0404, 0x0504, 0x0604, 0x0704, + 0x0804, 0x0904, 0x0A04, 0x0B04, 0x0C04, 0x0D04, 0x0E04, 0x0F04, + 0x1004, 0x1104, 0x1204, 0xEE05, 0xEF05, 0xF005, 0xF105, 0xF205, + 0xF305, 0xF405, 0xF505, 0xF605, 0xF705, 0xF805, 0xF905, 0xFA05, + 0xFB05, 0xFC05, 0xFD05, 0xFE05, 0xFF05, 0x0005, 0x0105, 0x0205, + 0x0305, 0x0405, 0x0505, 0x0605, 0x0705, 0x0805, 0x0905, 0x0A05, + 0x0B05, 0x0C05, 0x0D05, 0x0E05, 0x0F05, 0x1005, 0x1105, 0x1205, + 0xEE06, 0xEF06, 0xF006, 0xF106, 0xF206, 0xF306, 0xF406, 0xF506, + 0xF606, 0xF706, 0xF806, 0xF906, 0xFA06, 0xFB06, 0xFC06, 0xFD06, + 0xFE06, 0xFF06, 0x0006, 0x0106, 0x0206, 0x0306, 0x0406, 0x0506, + 0x0606, 0x0706, 0x0806, 0x0906, 0x0A06, 0x0B06, 0x0C06, 0x0D06, + 0x0E06, 0x0F06, 0x1006, 0x1106, 0x1206, 0xEE07, 0xEF07, 0xF007, + 0xF107, 0xF207, 0xF307, 0xF407, 0xF507, 0xF607, 0xF707, 0xF807, + 0xF907, 0xFA07, 0xFB07, 0xFC07, 0xFD07, 0xFE07, 0xFF07, 0x0007, + 0x0107, 0x0207, 0x0307, 0x0407, 0x0507, 0x0607, 0x0707, 0x0807, + 0x0907, 0x0A07, 0x0B07, 0x0C07, 0x0D07, 0x0E07, 0x0F07, 0x1007, + 0x1107, 0x1207, 0xEE08, 0xEF08, 0xF008, 0xF108, 0xF208, 0xF308, + 0xF408, 0xF508, 0xF608, 0xF708, 0xF808, 0xF908, 0xFA08, 0xFB08, + 0xFC08, 0xFD08, 0xFE08, 0xFF08, 0x0008, 0x0108, 0x0208, 0x0308, + 0x0408, 0x0508, 0x0608, 0x0708, 0x0808, 0x0908, 0x0A08, 0x0B08, + 0x0C08, 0x0D08, 0x0E08, 0x0F08, 0x1008, 0x1108, 0x1208, 0xEE09, + 0xEF09, 0xF009, 0xF109, 0xF209, 0xF309, 0xF409, 0xF509, 0xF609, + 0xF709, 0xF809, 0xF909, 0xFA09, 0xFB09, 0xFC09, 0xFD09, 0xFE09, + 0xFF09, 0x0009, 0x0109, 0x0209, 0x0309, 0x0409, 0x0509, 0x0609, + 0x0709, 0x0809, 0x0909, 0x0A09, 0x0B09, 0x0C09, 0x0D09, 0x0E09, + 0x0F09, 0x1009, 0x1109, 0x1209, 0xEE0A, 0xEF0A, 0xF00A, 0xF10A, + 0xF20A, 0xF30A, 0xF40A, 0xF50A, 0xF60A, 0xF70A, 0xF80A, 0xF90A, + 0xFA0A, 0xFB0A, 0xFC0A, 0xFD0A, 0xFE0A, 0xFF0A, 0x000A, 0x010A, + 0x020A, 0x030A, 0x040A, 0x050A, 0x060A, 0x070A, 0x080A, 0x090A, + 0x0A0A, 0x0B0A, 0x0C0A, 0x0D0A, 0x0E0A, 0x0F0A, 0x100A, 0x110A, + 0x120A, 0xEE0B, 0xEF0B, 0xF00B, 0xF10B, 0xF20B, 0xF30B, 0xF40B, + 0xF50B, 0xF60B, 0xF70B, 0xF80B, 0xF90B, 0xFA0B, 0xFB0B, 0xFC0B, + 0xFD0B, 0xFE0B, 0xFF0B, 0x000B, 0x010B, 0x020B, 0x030B, 0x040B, + 0x050B, 0x060B, 0x070B, 0x080B, 0x090B, 0x0A0B, 0x0B0B, 0x0C0B, + 0x0D0B, 0x0E0B, 0x0F0B, 0x100B, 0x110B, 0x120B, 0xEE0C, 0xEF0C, + 0xF00C, 0xF10C, 0xF20C, 0xF30C, 0xF40C, 0xF50C, 0xF60C, 0xF70C, + 0xF80C, 0xF90C, 0xFA0C, 0xFB0C, 0xFC0C, 0xFD0C, 0xFE0C, 0xFF0C, + 0x000C, 0x010C, 0x020C, 0x030C, 0x040C, 0x050C, 0x060C, 0x070C, + 0x080C, 0x090C, 0x0A0C, 0x0B0C, 0x0C0C, 0x0D0C, 0x0E0C, 0x0F0C, + 0x100C, 0x110C, 0x120C, 0xEE0D, 0xEF0D, 0xF00D, 0xF10D, 0xF20D, + 0xF30D, 0xF40D, 0xF50D, 0xF60D, 0xF70D, 0xF80D, 0xF90D, 0xFA0D, + 0xFB0D, 0xFC0D, 0xFD0D, 0xFE0D, 0xFF0D, 0x000D, 0x010D, 0x020D, + 0x030D, 0x040D, 0x050D, 0x060D, 0x070D, 0x080D, 0x090D, 0x0A0D, + 0x0B0D, 0x0C0D, 0x0D0D, 0x0E0D, 0x0F0D, 0x100D, 0x110D, 0x120D, + 0xEE0E, 0xEF0E, 0xF00E, 0xF10E, 0xF20E, 0xF30E, 0xF40E, 0xF50E, + 0xF60E, 0xF70E, 0xF80E, 0xF90E, 0xFA0E, 0xFB0E, 0xFC0E, 0xFD0E, + 0xFE0E, 0xFF0E, 0x000E, 0x010E, 0x020E, 0x030E, 0x040E, 0x050E, + 0x060E, 0x070E, 0x080E, 0x090E, 0x0A0E, 0x0B0E, 0x0C0E, 0x0D0E, + 0x0E0E, 0x0F0E, 0x100E, 0x110E, 0x120E, 0xEE0F, 0xEF0F, 0xF00F, + 0xF10F, 0xF20F, 0xF30F, 0xF40F, 0xF50F, 0xF60F, 0xF70F, 0xF80F, + 0xF90F, 0xFA0F, 0xFB0F, 0xFC0F, 0xFD0F, 0xFE0F, 0xFF0F, 0x000F, + 0x010F, 0x020F, 0x030F, 0x040F, 0x050F, 0x060F, 0x070F, 0x080F, + 0x090F, 0x0A0F, 0x0B0F, 0x0C0F, 0x0D0F, 0x0E0F, 0x0F0F, 0x100F, + 0x110F, 0x120F, 0xEE10, 0xEF10, 0xF010, 0xF110, 0xF210, 0xF310, + 0xF410, 0xF510, 0xF610, 0xF710, 0xF810, 0xF910, 0xFA10, 0xFB10, + 0xFC10, 0xFD10, 0xFE10, 0xFF10, 0x0010, 0x0110, 0x0210, 0x0310, + 0x0410, 0x0510, 0x0610, 0x0710, 0x0810, 0x0910, 0x0A10, 0x0B10, + 0x0C10, 0x0D10, 0x0E10, 0x0F10, 0x1010, 0x1110, 0x1210, 0xEE11, + 0xEF11, 0xF011, 0xF111, 0xF211, 0xF311, 0xF411, 0xF511, 0xF611, + 0xF711, 0xF811, 0xF911, 0xFA11, 0xFB11, 0xFC11, 0xFD11, 0xFE11, + 0xFF11, 0x0011, 0x0111, 0x0211, 0x0311, 0x0411, 0x0511, 0x0611, + 0x0711, 0x0811, 0x0911, 0x0A11, 0x0B11, 0x0C11, 0x0D11, 0x0E11, + 0x0F11, 0x1011, 0x1111, 0x1211, 0xEE12, 0xEF12, 0xF012, 0xF112, + 0xF212, 0xF312, 0xF412, 0xF512, 0xF612, 0xF712, 0xF812, 0xF912, + 0xFA12, 0xFB12, 0xFC12, 0xFD12, 0xFE12, 0xFF12, 0x0012, 0x0112, + 0x0212, 0x0312, 0x0412, 0x0512, 0x0612, 0x0712, 0x0812, 0x0912, + 0x0A12, 0x0B12, 0x0C12, 0x0D12, 0x0E12, 0x0F12, 0x1012, 0x1112, + 0x1212, 0x1313, +}; + +static const uint8_t clv_mvu_1_bits[] = { + 16, 14, 14, 14, 13, 12, 12, 10, 12, 12, 13, 14, 14, 14, 16, 15, + 13, 13, 12, 12, 11, 11, 7, 11, 11, 12, 12, 13, 13, 15, 16, 16, + 16, 13, 12, 10, 10, 6, 10, 10, 12, 13, 16, 16, 16, 14, 14, 11, + 11, 11, 11, 9, 7, 9, 11, 11, 11, 11, 14, 14, 15, 13, 13, 12, + 9, 8, 8, 4, 8, 8, 9, 12, 13, 13, 15, 14, 14, 11, 11, 10, + 9, 8, 4, 8, 9, 10, 11, 12, 14, 14, 12, 12, 11, 10, 10, 8, + 6, 3, 6, 8, 10, 10, 11, 12, 12, 11, 10, 9, 6, 6, 6, 5, + 4, 5, 6, 6, 6, 9, 10, 11, 12, 12, 11, 10, 10, 8, 6, 3, + 6, 7, 10, 10, 11, 12, 12, 14, 14, 11, 11, 10, 9, 8, 4, 8, + 9, 10, 11, 11, 14, 14, 15, 13, 13, 12, 9, 8, 8, 4, 8, 8, + 9, 12, 13, 13, 15, 14, 14, 11, 11, 11, 11, 9, 7, 9, 11, 11, + 11, 11, 14, 14, 16, 16, 16, 13, 12, 10, 10, 6, 10, 10, 12, 13, + 16, 16, 16, 15, 13, 13, 12, 12, 11, 11, 7, 11, 11, 12, 12, 13, + 13, 15, 16, 14, 14, 14, 13, 12, 12, 10, 12, 12, 13, 14, 14, 14, + 16, 7, +}; + +static const uint16_t clv_mvu_1_codes[] = { + 0xFFFC, 0x3FED, 0x3FE5, 0x3FE3, 0x1FD9, 0x0FD9, 0x0FD6, 0x03CE, + 0x0FD3, 0x0FD8, 0x1FD6, 0x3FE0, 0x3FE8, 0x3FEC, 0xFFFE, 0x7FF3, + 0x1FE7, 0x1FDA, 0x0FCF, 0x0FCC, 0x07DD, 0x07CC, 0x006B, 0x07CD, + 0x07DE, 0x0FCE, 0x0FD2, 0x1FDD, 0x1FEC, 0x7FF0, 0xFFF6, 0xFFFA, + 0xFFF2, 0x1FDE, 0x0FDB, 0x03D8, 0x03CA, 0x002E, 0x03CB, 0x03D9, + 0x0FDC, 0x1FDF, 0xFFF3, 0xFFF9, 0xFFF5, 0x3FF3, 0x3FDD, 0x07DA, + 0x07D2, 0x07CA, 0x07C2, 0x01DE, 0x0069, 0x01DF, 0x07C3, 0x07CB, + 0x07D3, 0x07DB, 0x3FDF, 0x3FF6, 0x7FF7, 0x1FED, 0x1FE5, 0x0FDF, + 0x01D8, 0x00E3, 0x00DF, 0x0007, 0x00E0, 0x00E4, 0x01D9, 0x0FE0, + 0x1FE3, 0x1FE9, 0x7FF4, 0x3FF5, 0x3FE7, 0x07E4, 0x07C6, 0x03D2, + 0x01E2, 0x00E9, 0x0006, 0x00EA, 0x01E3, 0x03D3, 0x07C7, 0x0FCA, + 0x3FE9, 0x3FF0, 0x0FE8, 0x0FE5, 0x07D5, 0x03DD, 0x03D5, 0x00DC, + 0x002B, 0x0001, 0x002C, 0x00DD, 0x03D6, 0x03DE, 0x07D6, 0x0FE4, + 0x0FE9, 0x07E0, 0x03C8, 0x01D6, 0x0032, 0x0030, 0x0028, 0x0012, + 0x0004, 0x0013, 0x0029, 0x0031, 0x0033, 0x01D7, 0x03C9, 0x07E1, + 0x0FEA, 0x0FE6, 0x07D7, 0x03DF, 0x03D7, 0x00DE, 0x002D, 0x0000, + 0x002A, 0x006D, 0x03D4, 0x03DC, 0x07D4, 0x0FE3, 0x0FE7, 0x3FF1, + 0x3FE4, 0x07E2, 0x07C4, 0x03D0, 0x01E0, 0x00E7, 0x0005, 0x00E8, + 0x01E1, 0x03D1, 0x07C5, 0x07E3, 0x3FEA, 0x3FF7, 0x7FF6, 0x1FE6, + 0x1FE4, 0x0FE1, 0x01DA, 0x00E5, 0x00E1, 0x0008, 0x00E2, 0x00E6, + 0x01DB, 0x0FE2, 0x1FE2, 0x1FEB, 0x7FF5, 0x3FF4, 0x3FDC, 0x07D9, + 0x07D0, 0x07C8, 0x07C0, 0x01DC, 0x0068, 0x01DD, 0x07C1, 0x07C9, + 0x07D1, 0x07D8, 0x3FDE, 0x3FF2, 0xFFFB, 0xFFF4, 0xFFF0, 0x1FE1, + 0x0FDD, 0x03DA, 0x03CC, 0x002F, 0x03CD, 0x03DB, 0x0FDE, 0x1FE0, + 0xFFF1, 0xFFF7, 0xFFF8, 0x7FF2, 0x1FEA, 0x1FDC, 0x0FD1, 0x0FCD, + 0x07DC, 0x07CF, 0x006C, 0x07CE, 0x07DF, 0x0FCB, 0x0FD0, 0x1FDB, + 0x1FE8, 0x7FF1, 0xFFFD, 0x3FEE, 0x3FEB, 0x3FE1, 0x1FD7, 0x0FD7, + 0x0FD5, 0x03CF, 0x0FD4, 0x0FDA, 0x1FD8, 0x3FE2, 0x3FE6, 0x3FEF, + 0xFFFF, 0x006A, +}; + +static const uint16_t clv_mvu_1_syms[] = { + 0xF9F9, 0xFAF9, 0xFBF9, 0xFCF9, 0xFDF9, 0xFEF9, 0xFFF9, 0x00F9, + 0x01F9, 0x02F9, 0x03F9, 0x04F9, 0x05F9, 0x06F9, 0x07F9, 0xF9FA, + 0xFAFA, 0xFBFA, 0xFCFA, 0xFDFA, 0xFEFA, 0xFFFA, 0x00FA, 0x01FA, + 0x02FA, 0x03FA, 0x04FA, 0x05FA, 0x06FA, 0x07FA, 0xF9FB, 0xFAFB, + 0xFBFB, 0xFCFB, 0xFDFB, 0xFEFB, 0xFFFB, 0x00FB, 0x01FB, 0x02FB, + 0x03FB, 0x04FB, 0x05FB, 0x06FB, 0x07FB, 0xF9FC, 0xFAFC, 0xFBFC, + 0xFCFC, 0xFDFC, 0xFEFC, 0xFFFC, 0x00FC, 0x01FC, 0x02FC, 0x03FC, + 0x04FC, 0x05FC, 0x06FC, 0x07FC, 0xF9FD, 0xFAFD, 0xFBFD, 0xFCFD, + 0xFDFD, 0xFEFD, 0xFFFD, 0x00FD, 0x01FD, 0x02FD, 0x03FD, 0x04FD, + 0x05FD, 0x06FD, 0x07FD, 0xF9FE, 0xFAFE, 0xFBFE, 0xFCFE, 0xFDFE, + 0xFEFE, 0xFFFE, 0x00FE, 0x01FE, 0x02FE, 0x03FE, 0x04FE, 0x05FE, + 0x06FE, 0x07FE, 0xF9FF, 0xFAFF, 0xFBFF, 0xFCFF, 0xFDFF, 0xFEFF, + 0xFFFF, 0x00FF, 0x01FF, 0x02FF, 0x03FF, 0x04FF, 0x05FF, 0x06FF, + 0x07FF, 0xF900, 0xFA00, 0xFB00, 0xFC00, 0xFD00, 0xFE00, 0xFF00, + 0x0000, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, 0x0700, + 0xF901, 0xFA01, 0xFB01, 0xFC01, 0xFD01, 0xFE01, 0xFF01, 0x0001, + 0x0101, 0x0201, 0x0301, 0x0401, 0x0501, 0x0601, 0x0701, 0xF902, + 0xFA02, 0xFB02, 0xFC02, 0xFD02, 0xFE02, 0xFF02, 0x0002, 0x0102, + 0x0202, 0x0302, 0x0402, 0x0502, 0x0602, 0x0702, 0xF903, 0xFA03, + 0xFB03, 0xFC03, 0xFD03, 0xFE03, 0xFF03, 0x0003, 0x0103, 0x0203, + 0x0303, 0x0403, 0x0503, 0x0603, 0x0703, 0xF904, 0xFA04, 0xFB04, + 0xFC04, 0xFD04, 0xFE04, 0xFF04, 0x0004, 0x0104, 0x0204, 0x0304, + 0x0404, 0x0504, 0x0604, 0x0704, 0xF905, 0xFA05, 0xFB05, 0xFC05, + 0xFD05, 0xFE05, 0xFF05, 0x0005, 0x0105, 0x0205, 0x0305, 0x0405, + 0x0505, 0x0605, 0x0705, 0xF906, 0xFA06, 0xFB06, 0xFC06, 0xFD06, + 0xFE06, 0xFF06, 0x0006, 0x0106, 0x0206, 0x0306, 0x0406, 0x0506, + 0x0606, 0x0706, 0xF907, 0xFA07, 0xFB07, 0xFC07, 0xFD07, 0xFE07, + 0xFF07, 0x0007, 0x0107, 0x0207, 0x0307, 0x0407, 0x0507, 0x0607, + 0x0707, 0x0808, +}; + +static const uint8_t clv_mvu_2_bits[] = { + 16, 16, 16, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 15, 15, + 15, 15, 16, 16, 16, 16, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, + 13, 14, 14, 14, 14, 14, 15, 15, 15, 16, 16, 15, 15, 14, 14, 14, + 14, 14, 14, 13, 13, 13, 14, 14, 14, 14, 14, 14, 15, 15, 16, 16, + 15, 15, 14, 13, 13, 13, 13, 13, 12, 12, 12, 13, 13, 13, 13, 13, + 14, 15, 15, 16, 14, 14, 14, 14, 13, 12, 12, 12, 12, 11, 10, 11, + 12, 12, 12, 12, 13, 14, 14, 14, 14, 14, 14, 14, 13, 12, 12, 12, + 12, 11, 10, 9, 10, 11, 12, 12, 12, 12, 13, 14, 14, 14, 15, 14, + 13, 13, 12, 12, 12, 12, 11, 10, 8, 10, 11, 12, 12, 12, 12, 13, + 13, 14, 15, 14, 14, 14, 13, 12, 12, 11, 11, 10, 9, 7, 9, 10, + 11, 11, 12, 12, 13, 14, 14, 14, 14, 14, 13, 12, 12, 11, 11, 10, + 9, 8, 7, 8, 9, 10, 11, 11, 12, 12, 13, 14, 14, 14, 13, 13, + 12, 11, 9, 9, 8, 7, 6, 5, 6, 7, 8, 9, 9, 11, 12, 13, + 13, 14, 14, 13, 13, 13, 11, 11, 10, 8, 7, 4, 1, 4, 7, 8, + 10, 11, 11, 13, 13, 13, 14, 14, 13, 13, 12, 11, 9, 9, 8, 7, + 6, 5, 6, 7, 8, 9, 9, 11, 12, 13, 13, 14, 14, 14, 13, 12, + 11, 11, 11, 9, 9, 8, 7, 8, 9, 10, 11, 11, 12, 12, 13, 14, + 14, 14, 14, 14, 13, 12, 12, 11, 11, 10, 9, 7, 9, 10, 11, 11, + 12, 12, 13, 14, 14, 14, 15, 14, 13, 13, 12, 12, 12, 12, 11, 10, + 9, 10, 11, 12, 12, 12, 12, 13, 13, 14, 15, 14, 14, 14, 13, 12, + 12, 12, 12, 11, 10, 8, 10, 11, 12, 12, 12, 12, 13, 14, 14, 14, + 14, 14, 14, 14, 13, 12, 12, 12, 12, 11, 10, 11, 12, 12, 12, 12, + 13, 14, 14, 14, 14, 16, 15, 15, 14, 13, 13, 13, 13, 13, 12, 12, + 12, 13, 13, 13, 13, 13, 14, 15, 15, 16, 16, 15, 15, 14, 14, 14, + 14, 14, 14, 13, 12, 13, 14, 14, 14, 14, 14, 14, 15, 15, 16, 16, + 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, 14, 14, 14, 14, 14, + 15, 15, 15, 16, 16, 16, 16, 15, 15, 15, 15, 14, 14, 14, 14, 14, + 14, 14, 15, 15, 15, 15, 16, 16, 16, 6, +}; + +static const uint16_t clv_mvu_2_codes[] = { + 0xFFF2, 0xFFEF, 0xFFEA, 0x7FEC, 0x7FD5, 0x7FC5, 0x7FCF, 0x3FD3, + 0x3FC9, 0x3FB4, 0x3F72, 0x3FAE, 0x3FDC, 0x3FE1, 0x7FC4, 0x7FC8, + 0x7FD7, 0x7FF0, 0xFFE9, 0xFFEC, 0xFFF8, 0xFFF4, 0x7FF3, 0x7FDE, + 0x7FD3, 0x3FC0, 0x3F99, 0x3FA8, 0x3FAC, 0x3F8E, 0x1FA8, 0x1F79, + 0x1FA2, 0x3F89, 0x3F93, 0x3F95, 0x3F9C, 0x3FB8, 0x7FD2, 0x7FE6, + 0x7FDA, 0xFFF7, 0xFFFE, 0x7FED, 0x7FE2, 0x3FD5, 0x3FD7, 0x3FB3, + 0x3FA2, 0x3F80, 0x3F7A, 0x1F88, 0x1F70, 0x1F8A, 0x3F83, 0x3F84, + 0x3FAA, 0x3FC4, 0x3FDA, 0x3FDF, 0x7FDB, 0x7FE3, 0xFFF1, 0xFFFB, + 0x7FE1, 0x7FC7, 0x3FB0, 0x1FAA, 0x1FAB, 0x1FA3, 0x1F8E, 0x1F81, + 0x0FA7, 0x0F7F, 0x0FA8, 0x1F82, 0x1F8F, 0x1FA4, 0x1FAC, 0x1FAD, + 0x3FB5, 0x7FC6, 0x7FDD, 0xFFF3, 0x3FDD, 0x3FBE, 0x3FB9, 0x3F7C, + 0x1F77, 0x0FB5, 0x0F9D, 0x0F99, 0x0F90, 0x0794, 0x03BE, 0x0795, + 0x0F92, 0x0F9A, 0x0F9E, 0x0FB6, 0x1F78, 0x3F78, 0x3FB2, 0x3FBF, + 0x3FD2, 0x3FA7, 0x3F8C, 0x3F75, 0x1F9E, 0x0F93, 0x0F94, 0x0F7B, + 0x0F73, 0x07B4, 0x03BB, 0x01D9, 0x03BC, 0x07B5, 0x0F74, 0x0F7C, + 0x0F95, 0x0F96, 0x1FA0, 0x3F76, 0x3F8F, 0x3FA5, 0x7FE5, 0x3FC7, + 0x1F95, 0x1F71, 0x0FAB, 0x0FAC, 0x0F9F, 0x0F7D, 0x0796, 0x03BF, + 0x00DE, 0x03C0, 0x0797, 0x0F7E, 0x0FA0, 0x0FAD, 0x0FAE, 0x1F72, + 0x1F97, 0x3FD1, 0x7FD8, 0x3FA9, 0x3FA0, 0x3F6D, 0x1F99, 0x0F87, + 0x0F77, 0x07A8, 0x079C, 0x03C5, 0x01CA, 0x0067, 0x01CB, 0x03C6, + 0x079D, 0x07A9, 0x0F78, 0x0F8A, 0x1F9F, 0x3F6E, 0x3F98, 0x3F9A, + 0x3FCA, 0x3F70, 0x1FAF, 0x0F8D, 0x0F6F, 0x07AC, 0x07A0, 0x03B7, + 0x01CE, 0x00DA, 0x0063, 0x00DB, 0x01CF, 0x03B8, 0x07A1, 0x07AD, + 0x0F70, 0x0F91, 0x1FB2, 0x3F73, 0x3FD6, 0x3F7D, 0x1F91, 0x1F85, + 0x0FA3, 0x07A2, 0x01D4, 0x01D0, 0x00E0, 0x0068, 0x002C, 0x0014, + 0x002D, 0x0069, 0x00E1, 0x01D1, 0x01D5, 0x07A3, 0x0FA4, 0x1F89, + 0x1F92, 0x3F81, 0x3FA6, 0x1F7B, 0x1F7C, 0x1F7D, 0x07B0, 0x07AE, + 0x03C7, 0x00DC, 0x0064, 0x0008, 0x0000, 0x0009, 0x0065, 0x00DD, + 0x03C8, 0x07AF, 0x07B1, 0x1F7E, 0x1F7F, 0x1F80, 0x3F9E, 0x3F85, + 0x1F93, 0x1F8B, 0x0FA5, 0x07A4, 0x01D6, 0x01D2, 0x00E2, 0x006A, + 0x002E, 0x0015, 0x002F, 0x006B, 0x00E3, 0x01D3, 0x01D7, 0x07A5, + 0x0FA6, 0x1F8C, 0x1F94, 0x3F87, 0x3FCE, 0x3F77, 0x1FB4, 0x0F83, + 0x07B6, 0x07AA, 0x079E, 0x01DA, 0x01CC, 0x00D8, 0x0062, 0x00D9, + 0x01CD, 0x03B6, 0x079F, 0x07AB, 0x0F6E, 0x0F84, 0x1FA9, 0x3F6A, + 0x3FCD, 0x3F90, 0x3F92, 0x3F6B, 0x1F96, 0x0F85, 0x0F75, 0x07A6, + 0x079A, 0x03C3, 0x01C8, 0x0066, 0x01C9, 0x03C4, 0x079B, 0x07A7, + 0x0F76, 0x0F86, 0x1F9D, 0x3F6C, 0x3F96, 0x3F97, 0x7FE9, 0x3FD8, + 0x1F98, 0x1F73, 0x0FAF, 0x0FB0, 0x0FA1, 0x0F80, 0x0798, 0x03C1, + 0x01D8, 0x03C2, 0x0799, 0x0F81, 0x0FA2, 0x0FB1, 0x0FB2, 0x1F74, + 0x1F9A, 0x3FE0, 0x7FEE, 0x3F94, 0x3F8B, 0x3F6F, 0x1F9B, 0x0F88, + 0x0F89, 0x0F79, 0x0F71, 0x07B2, 0x03B9, 0x00DF, 0x03BA, 0x07B3, + 0x0F72, 0x0F7A, 0x0F8B, 0x0F8C, 0x1F9C, 0x3F71, 0x3F8A, 0x3F9B, + 0x3FC8, 0x3FBD, 0x3FC5, 0x3F79, 0x1F75, 0x0FB3, 0x0F9C, 0x0F97, + 0x0F8E, 0x0792, 0x03BD, 0x0793, 0x0F8F, 0x0F98, 0x0F9B, 0x0FB4, + 0x1F76, 0x3F82, 0x3FC3, 0x3FBA, 0x3FC6, 0xFFFD, 0x7FDF, 0x7FCC, + 0x3FBB, 0x1FB0, 0x1FAE, 0x1FA1, 0x1F90, 0x1F83, 0x0FAA, 0x0F82, + 0x0FA9, 0x1F84, 0x1F8D, 0x1FA5, 0x1FB1, 0x1FB3, 0x3FC2, 0x7FCA, + 0x7FE8, 0xFFF5, 0xFFFF, 0x7FDC, 0x7FD9, 0x3FCC, 0x3FD9, 0x3FB7, + 0x3F9F, 0x3F7E, 0x3F86, 0x1F86, 0x0FB7, 0x1F87, 0x3F7B, 0x3F7F, + 0x3FA1, 0x3FBC, 0x3FCB, 0x3FD4, 0x7FF1, 0x7FF2, 0xFFFA, 0xFFFC, + 0x7FE4, 0x7FE7, 0x7FD4, 0x3FAF, 0x3FA3, 0x3F91, 0x3F9D, 0x3F88, + 0x1FA6, 0x1F7A, 0x1FA7, 0x3F8D, 0x3FAB, 0x3FAD, 0x3FA4, 0x3FB6, + 0x7FD0, 0x7FE0, 0x7FEB, 0xFFF0, 0xFFF9, 0xFFEB, 0xFFED, 0x7FEA, + 0x7FD6, 0x7FC9, 0x7FCB, 0x3FD0, 0x3FDE, 0x3FB1, 0x3F74, 0x3FC1, + 0x3FCF, 0x3FDB, 0x7FCD, 0x7FCE, 0x7FD1, 0x7FEF, 0xFFE8, 0xFFEE, + 0xFFF6, 0x0030, +}; + +static const uint16_t clv_mvu_2_syms[] = { + 0xF6F6, 0xF7F6, 0xF8F6, 0xF9F6, 0xFAF6, 0xFBF6, 0xFCF6, 0xFDF6, + 0xFEF6, 0xFFF6, 0x00F6, 0x01F6, 0x02F6, 0x03F6, 0x04F6, 0x05F6, + 0x06F6, 0x07F6, 0x08F6, 0x09F6, 0x0AF6, 0xF6F7, 0xF7F7, 0xF8F7, + 0xF9F7, 0xFAF7, 0xFBF7, 0xFCF7, 0xFDF7, 0xFEF7, 0xFFF7, 0x00F7, + 0x01F7, 0x02F7, 0x03F7, 0x04F7, 0x05F7, 0x06F7, 0x07F7, 0x08F7, + 0x09F7, 0x0AF7, 0xF6F8, 0xF7F8, 0xF8F8, 0xF9F8, 0xFAF8, 0xFBF8, + 0xFCF8, 0xFDF8, 0xFEF8, 0xFFF8, 0x00F8, 0x01F8, 0x02F8, 0x03F8, + 0x04F8, 0x05F8, 0x06F8, 0x07F8, 0x08F8, 0x09F8, 0x0AF8, 0xF6F9, + 0xF7F9, 0xF8F9, 0xF9F9, 0xFAF9, 0xFBF9, 0xFCF9, 0xFDF9, 0xFEF9, + 0xFFF9, 0x00F9, 0x01F9, 0x02F9, 0x03F9, 0x04F9, 0x05F9, 0x06F9, + 0x07F9, 0x08F9, 0x09F9, 0x0AF9, 0xF6FA, 0xF7FA, 0xF8FA, 0xF9FA, + 0xFAFA, 0xFBFA, 0xFCFA, 0xFDFA, 0xFEFA, 0xFFFA, 0x00FA, 0x01FA, + 0x02FA, 0x03FA, 0x04FA, 0x05FA, 0x06FA, 0x07FA, 0x08FA, 0x09FA, + 0x0AFA, 0xF6FB, 0xF7FB, 0xF8FB, 0xF9FB, 0xFAFB, 0xFBFB, 0xFCFB, + 0xFDFB, 0xFEFB, 0xFFFB, 0x00FB, 0x01FB, 0x02FB, 0x03FB, 0x04FB, + 0x05FB, 0x06FB, 0x07FB, 0x08FB, 0x09FB, 0x0AFB, 0xF6FC, 0xF7FC, + 0xF8FC, 0xF9FC, 0xFAFC, 0xFBFC, 0xFCFC, 0xFDFC, 0xFEFC, 0xFFFC, + 0x00FC, 0x01FC, 0x02FC, 0x03FC, 0x04FC, 0x05FC, 0x06FC, 0x07FC, + 0x08FC, 0x09FC, 0x0AFC, 0xF6FD, 0xF7FD, 0xF8FD, 0xF9FD, 0xFAFD, + 0xFBFD, 0xFCFD, 0xFDFD, 0xFEFD, 0xFFFD, 0x00FD, 0x01FD, 0x02FD, + 0x03FD, 0x04FD, 0x05FD, 0x06FD, 0x07FD, 0x08FD, 0x09FD, 0x0AFD, + 0xF6FE, 0xF7FE, 0xF8FE, 0xF9FE, 0xFAFE, 0xFBFE, 0xFCFE, 0xFDFE, + 0xFEFE, 0xFFFE, 0x00FE, 0x01FE, 0x02FE, 0x03FE, 0x04FE, 0x05FE, + 0x06FE, 0x07FE, 0x08FE, 0x09FE, 0x0AFE, 0xF6FF, 0xF7FF, 0xF8FF, + 0xF9FF, 0xFAFF, 0xFBFF, 0xFCFF, 0xFDFF, 0xFEFF, 0xFFFF, 0x00FF, + 0x01FF, 0x02FF, 0x03FF, 0x04FF, 0x05FF, 0x06FF, 0x07FF, 0x08FF, + 0x09FF, 0x0AFF, 0xF600, 0xF700, 0xF800, 0xF900, 0xFA00, 0xFB00, + 0xFC00, 0xFD00, 0xFE00, 0xFF00, 0x0000, 0x0100, 0x0200, 0x0300, + 0x0400, 0x0500, 0x0600, 0x0700, 0x0800, 0x0900, 0x0A00, 0xF601, + 0xF701, 0xF801, 0xF901, 0xFA01, 0xFB01, 0xFC01, 0xFD01, 0xFE01, + 0xFF01, 0x0001, 0x0101, 0x0201, 0x0301, 0x0401, 0x0501, 0x0601, + 0x0701, 0x0801, 0x0901, 0x0A01, 0xF602, 0xF702, 0xF802, 0xF902, + 0xFA02, 0xFB02, 0xFC02, 0xFD02, 0xFE02, 0xFF02, 0x0002, 0x0102, + 0x0202, 0x0302, 0x0402, 0x0502, 0x0602, 0x0702, 0x0802, 0x0902, + 0x0A02, 0xF603, 0xF703, 0xF803, 0xF903, 0xFA03, 0xFB03, 0xFC03, + 0xFD03, 0xFE03, 0xFF03, 0x0003, 0x0103, 0x0203, 0x0303, 0x0403, + 0x0503, 0x0603, 0x0703, 0x0803, 0x0903, 0x0A03, 0xF604, 0xF704, + 0xF804, 0xF904, 0xFA04, 0xFB04, 0xFC04, 0xFD04, 0xFE04, 0xFF04, + 0x0004, 0x0104, 0x0204, 0x0304, 0x0404, 0x0504, 0x0604, 0x0704, + 0x0804, 0x0904, 0x0A04, 0xF605, 0xF705, 0xF805, 0xF905, 0xFA05, + 0xFB05, 0xFC05, 0xFD05, 0xFE05, 0xFF05, 0x0005, 0x0105, 0x0205, + 0x0305, 0x0405, 0x0505, 0x0605, 0x0705, 0x0805, 0x0905, 0x0A05, + 0xF606, 0xF706, 0xF806, 0xF906, 0xFA06, 0xFB06, 0xFC06, 0xFD06, + 0xFE06, 0xFF06, 0x0006, 0x0106, 0x0206, 0x0306, 0x0406, 0x0506, + 0x0606, 0x0706, 0x0806, 0x0906, 0x0A06, 0xF607, 0xF707, 0xF807, + 0xF907, 0xFA07, 0xFB07, 0xFC07, 0xFD07, 0xFE07, 0xFF07, 0x0007, + 0x0107, 0x0207, 0x0307, 0x0407, 0x0507, 0x0607, 0x0707, 0x0807, + 0x0907, 0x0A07, 0xF608, 0xF708, 0xF808, 0xF908, 0xFA08, 0xFB08, + 0xFC08, 0xFD08, 0xFE08, 0xFF08, 0x0008, 0x0108, 0x0208, 0x0308, + 0x0408, 0x0508, 0x0608, 0x0708, 0x0808, 0x0908, 0x0A08, 0xF609, + 0xF709, 0xF809, 0xF909, 0xFA09, 0xFB09, 0xFC09, 0xFD09, 0xFE09, + 0xFF09, 0x0009, 0x0109, 0x0209, 0x0309, 0x0409, 0x0509, 0x0609, + 0x0709, 0x0809, 0x0909, 0x0A09, 0xF60A, 0xF70A, 0xF80A, 0xF90A, + 0xFA0A, 0xFB0A, 0xFC0A, 0xFD0A, 0xFE0A, 0xFF0A, 0x000A, 0x010A, + 0x020A, 0x030A, 0x040A, 0x050A, 0x060A, 0x070A, 0x080A, 0x090A, + 0x0A0A, 0x0B0B, +}; + +static const uint8_t clv_mvv_1_bits[] = { + 16, 15, 13, 13, 13, 12, 10, 10, 10, 12, 13, 13, 13, 15, 16, 16, + 15, 14, 13, 12, 11, 10, 9, 10, 11, 12, 13, 14, 15, 16, 15, 14, + 13, 13, 11, 10, 10, 5, 10, 10, 11, 13, 13, 14, 15, 12, 12, 12, + 11, 10, 10, 9, 5, 9, 10, 10, 11, 12, 12, 12, 14, 12, 12, 12, + 11, 9, 8, 5, 8, 9, 11, 12, 12, 12, 14, 14, 11, 11, 9, 9, + 9, 7, 5, 7, 9, 9, 9, 11, 11, 14, 13, 12, 11, 10, 10, 8, + 6, 3, 6, 8, 10, 10, 11, 12, 13, 11, 10, 9, 7, 6, 6, 4, + 4, 4, 6, 7, 7, 10, 10, 11, 13, 12, 11, 10, 10, 8, 6, 3, + 6, 8, 10, 10, 11, 12, 13, 14, 11, 11, 9, 9, 9, 7, 5, 7, + 9, 9, 9, 11, 11, 14, 14, 12, 12, 12, 11, 9, 8, 5, 8, 9, + 11, 12, 12, 12, 14, 12, 12, 12, 11, 10, 10, 9, 5, 9, 10, 10, + 11, 12, 12, 12, 15, 14, 13, 13, 11, 10, 10, 5, 10, 10, 11, 13, + 13, 14, 15, 16, 15, 14, 13, 12, 11, 10, 9, 10, 11, 12, 13, 14, + 15, 16, 16, 15, 13, 13, 13, 12, 10, 10, 10, 12, 13, 13, 13, 15, + 16, 7, +}; + +static const uint16_t clv_mvv_1_codes[] = { + 0xFFFD, 0x7FF8, 0x1FF2, 0x1FDC, 0x1FDB, 0x0FD2, 0x03D6, 0x03BF, + 0x03D3, 0x0FD0, 0x1FDA, 0x1FDE, 0x1FF0, 0x7FF9, 0xFFFE, 0xFFFA, + 0x7FFB, 0x3FF3, 0x1FE9, 0x0FD6, 0x07CB, 0x03E1, 0x01C8, 0x03E2, + 0x07CC, 0x0FD9, 0x1FE8, 0x3FF6, 0x7FFA, 0xFFF9, 0x7FF1, 0x3FEE, + 0x1FE4, 0x1FE0, 0x07D4, 0x03DB, 0x03CB, 0x0014, 0x03CC, 0x03DC, + 0x07D6, 0x1FE3, 0x1FE7, 0x3FEC, 0x7FF3, 0x0FEA, 0x0FE0, 0x0FDE, + 0x07DE, 0x03C9, 0x03C3, 0x01DC, 0x0013, 0x01DD, 0x03C4, 0x03CA, + 0x07DF, 0x0FDF, 0x0FE3, 0x0FEB, 0x3FF1, 0x0FE7, 0x0FCF, 0x0FC8, + 0x07D8, 0x01D2, 0x00E0, 0x0010, 0x00E1, 0x01D4, 0x07D9, 0x0FC9, + 0x0FCC, 0x0FE6, 0x3FF5, 0x3FEA, 0x07E2, 0x07D2, 0x01D7, 0x01D0, + 0x01CC, 0x006A, 0x000F, 0x006B, 0x01CD, 0x01D1, 0x01D9, 0x07D3, + 0x07E3, 0x3FEB, 0x1FEE, 0x0FD5, 0x07C7, 0x03D8, 0x03D0, 0x00DD, + 0x002D, 0x0001, 0x002E, 0x00DE, 0x03D1, 0x03D9, 0x07C8, 0x0FD8, + 0x1FEF, 0x07CE, 0x03C5, 0x01DE, 0x006C, 0x0032, 0x0030, 0x0005, + 0x0004, 0x0006, 0x0031, 0x0066, 0x006D, 0x03BE, 0x03C6, 0x07CF, + 0x1FEC, 0x0FDA, 0x07C9, 0x03DA, 0x03D2, 0x00DF, 0x002F, 0x0000, + 0x002C, 0x00DC, 0x03CF, 0x03D7, 0x07C6, 0x0FD4, 0x1FED, 0x3FE9, + 0x07E0, 0x07D0, 0x01D3, 0x01CE, 0x01CA, 0x0068, 0x000E, 0x0069, + 0x01CB, 0x01CF, 0x01D5, 0x07D1, 0x07E1, 0x3FE8, 0x3FF4, 0x0FE4, + 0x0FCD, 0x0FCB, 0x07DA, 0x01D6, 0x00E2, 0x0011, 0x00E3, 0x01D8, + 0x07DB, 0x0FCA, 0x0FCE, 0x0FE5, 0x3FF7, 0x0FE8, 0x0FE1, 0x0FDD, + 0x07DD, 0x03C7, 0x03C1, 0x01DA, 0x0012, 0x01DB, 0x03C2, 0x03C8, + 0x07DC, 0x0FDC, 0x0FE2, 0x0FE9, 0x7FF0, 0x3FEF, 0x1FE5, 0x1FE1, + 0x07D7, 0x03DD, 0x03CD, 0x0015, 0x03CE, 0x03DE, 0x07D5, 0x1FE2, + 0x1FE6, 0x3FED, 0x7FF2, 0xFFF8, 0x7FF4, 0x3FF2, 0x1FEB, 0x0FD7, + 0x07CD, 0x03DF, 0x01C9, 0x03E0, 0x07CA, 0x0FDB, 0x1FEA, 0x3FF0, + 0x7FF5, 0xFFFB, 0xFFFC, 0x7FF6, 0x1FF3, 0x1FDD, 0x1FD9, 0x0FD1, + 0x03D5, 0x03C0, 0x03D4, 0x0FD3, 0x1FD8, 0x1FDF, 0x1FF1, 0x7FF7, + 0xFFFF, 0x0067, +}; + +static const uint16_t clv_mvv_1_syms[] = { + 0xF9F9, 0xFAF9, 0xFBF9, 0xFCF9, 0xFDF9, 0xFEF9, 0xFFF9, 0x00F9, + 0x01F9, 0x02F9, 0x03F9, 0x04F9, 0x05F9, 0x06F9, 0x07F9, 0xF9FA, + 0xFAFA, 0xFBFA, 0xFCFA, 0xFDFA, 0xFEFA, 0xFFFA, 0x00FA, 0x01FA, + 0x02FA, 0x03FA, 0x04FA, 0x05FA, 0x06FA, 0x07FA, 0xF9FB, 0xFAFB, + 0xFBFB, 0xFCFB, 0xFDFB, 0xFEFB, 0xFFFB, 0x00FB, 0x01FB, 0x02FB, + 0x03FB, 0x04FB, 0x05FB, 0x06FB, 0x07FB, 0xF9FC, 0xFAFC, 0xFBFC, + 0xFCFC, 0xFDFC, 0xFEFC, 0xFFFC, 0x00FC, 0x01FC, 0x02FC, 0x03FC, + 0x04FC, 0x05FC, 0x06FC, 0x07FC, 0xF9FD, 0xFAFD, 0xFBFD, 0xFCFD, + 0xFDFD, 0xFEFD, 0xFFFD, 0x00FD, 0x01FD, 0x02FD, 0x03FD, 0x04FD, + 0x05FD, 0x06FD, 0x07FD, 0xF9FE, 0xFAFE, 0xFBFE, 0xFCFE, 0xFDFE, + 0xFEFE, 0xFFFE, 0x00FE, 0x01FE, 0x02FE, 0x03FE, 0x04FE, 0x05FE, + 0x06FE, 0x07FE, 0xF9FF, 0xFAFF, 0xFBFF, 0xFCFF, 0xFDFF, 0xFEFF, + 0xFFFF, 0x00FF, 0x01FF, 0x02FF, 0x03FF, 0x04FF, 0x05FF, 0x06FF, + 0x07FF, 0xF900, 0xFA00, 0xFB00, 0xFC00, 0xFD00, 0xFE00, 0xFF00, + 0x0000, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, 0x0700, + 0xF901, 0xFA01, 0xFB01, 0xFC01, 0xFD01, 0xFE01, 0xFF01, 0x0001, + 0x0101, 0x0201, 0x0301, 0x0401, 0x0501, 0x0601, 0x0701, 0xF902, + 0xFA02, 0xFB02, 0xFC02, 0xFD02, 0xFE02, 0xFF02, 0x0002, 0x0102, + 0x0202, 0x0302, 0x0402, 0x0502, 0x0602, 0x0702, 0xF903, 0xFA03, + 0xFB03, 0xFC03, 0xFD03, 0xFE03, 0xFF03, 0x0003, 0x0103, 0x0203, + 0x0303, 0x0403, 0x0503, 0x0603, 0x0703, 0xF904, 0xFA04, 0xFB04, + 0xFC04, 0xFD04, 0xFE04, 0xFF04, 0x0004, 0x0104, 0x0204, 0x0304, + 0x0404, 0x0504, 0x0604, 0x0704, 0xF905, 0xFA05, 0xFB05, 0xFC05, + 0xFD05, 0xFE05, 0xFF05, 0x0005, 0x0105, 0x0205, 0x0305, 0x0405, + 0x0505, 0x0605, 0x0705, 0xF906, 0xFA06, 0xFB06, 0xFC06, 0xFD06, + 0xFE06, 0xFF06, 0x0006, 0x0106, 0x0206, 0x0306, 0x0406, 0x0506, + 0x0606, 0x0706, 0xF907, 0xFA07, 0xFB07, 0xFC07, 0xFD07, 0xFE07, + 0xFF07, 0x0007, 0x0107, 0x0207, 0x0307, 0x0407, 0x0507, 0x0607, + 0x0707, 0x0808, +}; + +static const uint8_t clv_mvv_2_bits[] = { + 16, 15, 15, 15, 15, 15, 14, 14, 14, 13, 12, 13, 14, 14, 14, 15, + 15, 15, 15, 15, 16, 16, 16, 16, 15, 15, 14, 14, 14, 13, 13, 12, + 12, 13, 14, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 14, 14, 14, + 14, 14, 14, 13, 13, 13, 14, 14, 14, 14, 14, 14, 16, 16, 16, 15, + 15, 14, 14, 14, 13, 13, 13, 13, 12, 12, 12, 13, 13, 13, 13, 14, + 14, 14, 15, 15, 16, 14, 14, 14, 13, 12, 12, 12, 10, 10, 10, 10, + 10, 12, 12, 12, 13, 14, 14, 14, 16, 14, 14, 14, 13, 13, 12, 12, + 12, 10, 10, 7, 10, 10, 12, 12, 12, 13, 13, 14, 14, 14, 14, 14, + 13, 12, 12, 12, 12, 10, 9, 8, 7, 8, 9, 10, 12, 12, 12, 12, + 13, 14, 14, 14, 14, 13, 12, 12, 12, 12, 10, 9, 8, 7, 8, 9, + 10, 12, 12, 12, 12, 13, 14, 14, 14, 14, 13, 13, 12, 12, 11, 10, + 9, 8, 7, 8, 9, 10, 11, 12, 12, 13, 13, 14, 14, 14, 13, 13, + 12, 10, 10, 9, 8, 7, 6, 5, 6, 7, 8, 9, 10, 10, 12, 13, + 13, 14, 13, 13, 13, 13, 11, 10, 9, 8, 7, 5, 1, 5, 7, 8, + 9, 10, 11, 13, 13, 13, 13, 14, 13, 13, 12, 10, 10, 9, 8, 7, + 6, 5, 6, 7, 8, 9, 10, 10, 12, 13, 13, 14, 14, 14, 13, 13, + 12, 12, 11, 9, 9, 8, 7, 8, 9, 9, 11, 12, 12, 13, 13, 14, + 14, 14, 14, 13, 12, 12, 12, 12, 10, 9, 8, 7, 8, 9, 10, 12, + 12, 12, 12, 13, 14, 14, 14, 14, 13, 12, 12, 12, 12, 10, 9, 8, + 7, 8, 9, 10, 12, 12, 12, 12, 13, 14, 14, 14, 14, 14, 13, 13, + 12, 12, 12, 10, 10, 7, 10, 10, 12, 12, 12, 13, 13, 14, 14, 14, + 16, 14, 14, 14, 13, 12, 12, 12, 10, 10, 10, 10, 10, 12, 12, 12, + 13, 14, 14, 14, 16, 15, 15, 14, 14, 14, 13, 13, 13, 13, 12, 12, + 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, 16, 16, 16, 14, 14, 14, + 14, 14, 14, 13, 13, 13, 14, 14, 14, 14, 14, 14, 16, 16, 16, 16, + 16, 16, 15, 15, 14, 14, 14, 13, 12, 12, 12, 13, 14, 14, 14, 15, + 15, 16, 16, 16, 16, 15, 15, 15, 15, 15, 14, 14, 14, 13, 10, 13, + 14, 14, 14, 15, 15, 15, 15, 15, 16, 6, +}; + +static const uint16_t clv_mvv_2_codes[] = { + 0xFFFF, 0x7FE7, 0x7FD9, 0x7FE6, 0x7FE5, 0x7FCE, 0x3FD6, 0x3FD3, + 0x3F9C, 0x1FB2, 0x0F7A, 0x1FB5, 0x3FA8, 0x3FDD, 0x3FE5, 0x7FD0, + 0x7FEA, 0x7FEC, 0x7FEF, 0x7FDB, 0xFFF3, 0xFFF5, 0xFFE2, 0xFFEB, + 0x7FEB, 0x7FE0, 0x3FA7, 0x3F84, 0x3F79, 0x1FAE, 0x1F70, 0x0F78, + 0x0FAA, 0x1FAA, 0x3F76, 0x3F7E, 0x3FAC, 0x7FE1, 0x7FDD, 0xFFEC, + 0xFFEE, 0xFFF8, 0xFFF9, 0xFFEA, 0xFFE4, 0x3FE1, 0x3FBA, 0x3FC5, + 0x3FB9, 0x3FA1, 0x3FAA, 0x1F8B, 0x1F8D, 0x1F8E, 0x3FA6, 0x3FA9, + 0x3FC4, 0x3FBC, 0x3FC6, 0x3FDB, 0xFFE3, 0xFFE1, 0xFFFB, 0x7FD4, + 0x7FCC, 0x3FCD, 0x3F88, 0x3F7C, 0x1FA1, 0x1FA2, 0x1F95, 0x1F77, + 0x0F95, 0x0F79, 0x0F97, 0x1F78, 0x1F96, 0x1FA3, 0x1FA4, 0x3F7F, + 0x3F8B, 0x3FCB, 0x7FCF, 0x7FD5, 0xFFF6, 0x3FD7, 0x3FE0, 0x3F91, + 0x1F7B, 0x0FB4, 0x0FA5, 0x0FA6, 0x03D5, 0x03CB, 0x03BF, 0x03CC, + 0x03D6, 0x0FA7, 0x0FA8, 0x0FB5, 0x1F7D, 0x3F87, 0x3FD2, 0x3FDF, + 0xFFF0, 0x3F95, 0x3F8A, 0x3F96, 0x1FB7, 0x1F9F, 0x0F9F, 0x0F8F, + 0x0F76, 0x03D1, 0x03BC, 0x0067, 0x03BD, 0x03D2, 0x0F77, 0x0F90, + 0x0FA0, 0x1FA0, 0x1FB9, 0x3F97, 0x3F98, 0x3F99, 0x3FC3, 0x3FAF, + 0x1F81, 0x0FA9, 0x0F91, 0x0F7E, 0x0F68, 0x03B2, 0x01C6, 0x00D4, + 0x0062, 0x00D5, 0x01C7, 0x03B3, 0x0F6A, 0x0F81, 0x0F93, 0x0FAC, + 0x1F83, 0x3FB3, 0x3FB4, 0x3FC7, 0x3FBB, 0x1F86, 0x0FAF, 0x0F98, + 0x0F84, 0x0F6D, 0x03B8, 0x01CC, 0x00DA, 0x0065, 0x00DB, 0x01CD, + 0x03B9, 0x0F6F, 0x0F86, 0x0F9B, 0x0FB1, 0x1F88, 0x3FB8, 0x3FC9, + 0x3FDC, 0x3F80, 0x1FB3, 0x1F93, 0x0F87, 0x0F72, 0x07B0, 0x03B0, + 0x01D4, 0x00E0, 0x0061, 0x00E1, 0x01D5, 0x03B1, 0x07B1, 0x0F73, + 0x0F88, 0x1F94, 0x1FB4, 0x3F81, 0x3FD4, 0x3F9E, 0x1F99, 0x1F73, + 0x0F89, 0x03C4, 0x03C0, 0x01CE, 0x00D0, 0x005C, 0x0028, 0x0010, + 0x0029, 0x005D, 0x00D1, 0x01CF, 0x03C1, 0x03C5, 0x0F8A, 0x1F74, + 0x1F9A, 0x3FA4, 0x1FAC, 0x1F8C, 0x1F7E, 0x1F71, 0x07B2, 0x03CF, + 0x01C4, 0x00DC, 0x005A, 0x0012, 0x0000, 0x0013, 0x005B, 0x00DD, + 0x01C5, 0x03D0, 0x07B3, 0x1F72, 0x1F7F, 0x1F8F, 0x1FAD, 0x3FAB, + 0x1F9B, 0x1F75, 0x0F8B, 0x03C6, 0x03C2, 0x01D0, 0x00D2, 0x005E, + 0x002A, 0x0011, 0x002B, 0x005F, 0x00D3, 0x01D1, 0x03C3, 0x03C7, + 0x0F8C, 0x1F76, 0x1F9C, 0x3FAD, 0x3FCF, 0x3F85, 0x1FBA, 0x1F91, + 0x0F7D, 0x0F70, 0x07AE, 0x01D6, 0x01D2, 0x00DE, 0x0060, 0x00DF, + 0x01D3, 0x01D7, 0x07AF, 0x0F71, 0x0F7F, 0x1F92, 0x1FAF, 0x3F7B, + 0x3FD0, 0x3FC0, 0x3FB1, 0x1F82, 0x0FAB, 0x0F92, 0x0F80, 0x0F69, + 0x03B4, 0x01C8, 0x00D6, 0x0063, 0x00D7, 0x01C9, 0x03B5, 0x0F6B, + 0x0F82, 0x0F94, 0x0FAD, 0x1F84, 0x3FB5, 0x3FC2, 0x3FB6, 0x3FBF, + 0x1F85, 0x0FAE, 0x0F96, 0x0F83, 0x0F6C, 0x03B6, 0x01CA, 0x00D8, + 0x0064, 0x00D9, 0x01CB, 0x03B7, 0x0F6E, 0x0F85, 0x0F99, 0x0FB0, + 0x1F87, 0x3FB0, 0x3FB2, 0x3F93, 0x3F86, 0x3F8E, 0x1FB1, 0x1F9D, + 0x0F9A, 0x0F8D, 0x0F74, 0x03CD, 0x03BA, 0x0066, 0x03BB, 0x03CE, + 0x0F75, 0x0F8E, 0x0F9C, 0x1F9E, 0x1FB0, 0x3F8C, 0x3F94, 0x3F8D, + 0xFFFC, 0x3FCA, 0x3FD5, 0x3F8F, 0x1F79, 0x0FB2, 0x0FA1, 0x0FA2, + 0x03D3, 0x03C9, 0x03BE, 0x03CA, 0x03D4, 0x0FA3, 0x0FA4, 0x0FB3, + 0x1F7A, 0x3F90, 0x3FE3, 0x3FD8, 0xFFF2, 0x7FD7, 0x7FCD, 0x3FE4, + 0x3F92, 0x3F82, 0x1FA6, 0x1FA8, 0x1F98, 0x1F7C, 0x0F9D, 0x0F7B, + 0x0F9E, 0x1F80, 0x1F97, 0x1FA7, 0x1FA5, 0x3F7A, 0x3F89, 0x3FDA, + 0x7FD2, 0x7FD6, 0xFFFE, 0xFFED, 0xFFE8, 0x3FCC, 0x3FBD, 0x3FAE, + 0x3FC1, 0x3F9F, 0x3F9A, 0x1F89, 0x1F90, 0x1F8A, 0x3FA3, 0x3FA0, + 0x3FC8, 0x3FBE, 0x3FB7, 0x3FD1, 0xFFE7, 0xFFE9, 0xFFFD, 0xFFF4, + 0xFFE5, 0xFFEF, 0x7FD8, 0x7FDC, 0x3FA2, 0x3F83, 0x3F78, 0x1FA9, + 0x0FB6, 0x0F7C, 0x0FB7, 0x1FAB, 0x3F77, 0x3F7D, 0x3F9B, 0x7FDE, + 0x7FED, 0xFFE6, 0xFFE0, 0xFFF7, 0xFFF1, 0x7FDA, 0x7FE9, 0x7FE2, + 0x7FE3, 0x7FD1, 0x3FD9, 0x3FE2, 0x3FA5, 0x1FB8, 0x03C8, 0x1FB6, + 0x3F9D, 0x3FDE, 0x3FCE, 0x7FD3, 0x7FEE, 0x7FDF, 0x7FE8, 0x7FE4, + 0xFFFA, 0x002C, +}; + +static const uint16_t clv_mvv_2_syms[] = { + 0xF6F6, 0xF7F6, 0xF8F6, 0xF9F6, 0xFAF6, 0xFBF6, 0xFCF6, 0xFDF6, + 0xFEF6, 0xFFF6, 0x00F6, 0x01F6, 0x02F6, 0x03F6, 0x04F6, 0x05F6, + 0x06F6, 0x07F6, 0x08F6, 0x09F6, 0x0AF6, 0xF6F7, 0xF7F7, 0xF8F7, + 0xF9F7, 0xFAF7, 0xFBF7, 0xFCF7, 0xFDF7, 0xFEF7, 0xFFF7, 0x00F7, + 0x01F7, 0x02F7, 0x03F7, 0x04F7, 0x05F7, 0x06F7, 0x07F7, 0x08F7, + 0x09F7, 0x0AF7, 0xF6F8, 0xF7F8, 0xF8F8, 0xF9F8, 0xFAF8, 0xFBF8, + 0xFCF8, 0xFDF8, 0xFEF8, 0xFFF8, 0x00F8, 0x01F8, 0x02F8, 0x03F8, + 0x04F8, 0x05F8, 0x06F8, 0x07F8, 0x08F8, 0x09F8, 0x0AF8, 0xF6F9, + 0xF7F9, 0xF8F9, 0xF9F9, 0xFAF9, 0xFBF9, 0xFCF9, 0xFDF9, 0xFEF9, + 0xFFF9, 0x00F9, 0x01F9, 0x02F9, 0x03F9, 0x04F9, 0x05F9, 0x06F9, + 0x07F9, 0x08F9, 0x09F9, 0x0AF9, 0xF6FA, 0xF7FA, 0xF8FA, 0xF9FA, + 0xFAFA, 0xFBFA, 0xFCFA, 0xFDFA, 0xFEFA, 0xFFFA, 0x00FA, 0x01FA, + 0x02FA, 0x03FA, 0x04FA, 0x05FA, 0x06FA, 0x07FA, 0x08FA, 0x09FA, + 0x0AFA, 0xF6FB, 0xF7FB, 0xF8FB, 0xF9FB, 0xFAFB, 0xFBFB, 0xFCFB, + 0xFDFB, 0xFEFB, 0xFFFB, 0x00FB, 0x01FB, 0x02FB, 0x03FB, 0x04FB, + 0x05FB, 0x06FB, 0x07FB, 0x08FB, 0x09FB, 0x0AFB, 0xF6FC, 0xF7FC, + 0xF8FC, 0xF9FC, 0xFAFC, 0xFBFC, 0xFCFC, 0xFDFC, 0xFEFC, 0xFFFC, + 0x00FC, 0x01FC, 0x02FC, 0x03FC, 0x04FC, 0x05FC, 0x06FC, 0x07FC, + 0x08FC, 0x09FC, 0x0AFC, 0xF6FD, 0xF7FD, 0xF8FD, 0xF9FD, 0xFAFD, + 0xFBFD, 0xFCFD, 0xFDFD, 0xFEFD, 0xFFFD, 0x00FD, 0x01FD, 0x02FD, + 0x03FD, 0x04FD, 0x05FD, 0x06FD, 0x07FD, 0x08FD, 0x09FD, 0x0AFD, + 0xF6FE, 0xF7FE, 0xF8FE, 0xF9FE, 0xFAFE, 0xFBFE, 0xFCFE, 0xFDFE, + 0xFEFE, 0xFFFE, 0x00FE, 0x01FE, 0x02FE, 0x03FE, 0x04FE, 0x05FE, + 0x06FE, 0x07FE, 0x08FE, 0x09FE, 0x0AFE, 0xF6FF, 0xF7FF, 0xF8FF, + 0xF9FF, 0xFAFF, 0xFBFF, 0xFCFF, 0xFDFF, 0xFEFF, 0xFFFF, 0x00FF, + 0x01FF, 0x02FF, 0x03FF, 0x04FF, 0x05FF, 0x06FF, 0x07FF, 0x08FF, + 0x09FF, 0x0AFF, 0xF600, 0xF700, 0xF800, 0xF900, 0xFA00, 0xFB00, + 0xFC00, 0xFD00, 0xFE00, 0xFF00, 0x0000, 0x0100, 0x0200, 0x0300, + 0x0400, 0x0500, 0x0600, 0x0700, 0x0800, 0x0900, 0x0A00, 0xF601, + 0xF701, 0xF801, 0xF901, 0xFA01, 0xFB01, 0xFC01, 0xFD01, 0xFE01, + 0xFF01, 0x0001, 0x0101, 0x0201, 0x0301, 0x0401, 0x0501, 0x0601, + 0x0701, 0x0801, 0x0901, 0x0A01, 0xF602, 0xF702, 0xF802, 0xF902, + 0xFA02, 0xFB02, 0xFC02, 0xFD02, 0xFE02, 0xFF02, 0x0002, 0x0102, + 0x0202, 0x0302, 0x0402, 0x0502, 0x0602, 0x0702, 0x0802, 0x0902, + 0x0A02, 0xF603, 0xF703, 0xF803, 0xF903, 0xFA03, 0xFB03, 0xFC03, + 0xFD03, 0xFE03, 0xFF03, 0x0003, 0x0103, 0x0203, 0x0303, 0x0403, + 0x0503, 0x0603, 0x0703, 0x0803, 0x0903, 0x0A03, 0xF604, 0xF704, + 0xF804, 0xF904, 0xFA04, 0xFB04, 0xFC04, 0xFD04, 0xFE04, 0xFF04, + 0x0004, 0x0104, 0x0204, 0x0304, 0x0404, 0x0504, 0x0604, 0x0704, + 0x0804, 0x0904, 0x0A04, 0xF605, 0xF705, 0xF805, 0xF905, 0xFA05, + 0xFB05, 0xFC05, 0xFD05, 0xFE05, 0xFF05, 0x0005, 0x0105, 0x0205, + 0x0305, 0x0405, 0x0505, 0x0605, 0x0705, 0x0805, 0x0905, 0x0A05, + 0xF606, 0xF706, 0xF806, 0xF906, 0xFA06, 0xFB06, 0xFC06, 0xFD06, + 0xFE06, 0xFF06, 0x0006, 0x0106, 0x0206, 0x0306, 0x0406, 0x0506, + 0x0606, 0x0706, 0x0806, 0x0906, 0x0A06, 0xF607, 0xF707, 0xF807, + 0xF907, 0xFA07, 0xFB07, 0xFC07, 0xFD07, 0xFE07, 0xFF07, 0x0007, + 0x0107, 0x0207, 0x0307, 0x0407, 0x0507, 0x0607, 0x0707, 0x0807, + 0x0907, 0x0A07, 0xF608, 0xF708, 0xF808, 0xF908, 0xFA08, 0xFB08, + 0xFC08, 0xFD08, 0xFE08, 0xFF08, 0x0008, 0x0108, 0x0208, 0x0308, + 0x0408, 0x0508, 0x0608, 0x0708, 0x0808, 0x0908, 0x0A08, 0xF609, + 0xF709, 0xF809, 0xF909, 0xFA09, 0xFB09, 0xFC09, 0xFD09, 0xFE09, + 0xFF09, 0x0009, 0x0109, 0x0209, 0x0309, 0x0409, 0x0509, 0x0609, + 0x0709, 0x0809, 0x0909, 0x0A09, 0xF60A, 0xF70A, 0xF80A, 0xF90A, + 0xFA0A, 0xFB0A, 0xFC0A, 0xFD0A, 0xFE0A, 0xFF0A, 0x000A, 0x010A, + 0x020A, 0x030A, 0x040A, 0x050A, 0x060A, 0x070A, 0x080A, 0x090A, + 0x0A0A, 0x0B0B, +}; + +static const uint8_t clv_biasy_1_bits[] = { + 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 13, 13, 13, + 13, 13, 13, 13, 13, 12, 12, 12, 12, 11, 11, 11, 10, 10, 10, 9, + 8, 8, 7, 7, 5, 2, 1, 3, 5, 7, 7, 8, 9, 9, 10, 10, + 10, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, + 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 16, 12, +}; + +static const uint16_t clv_biasy_1_codes[] = { + 0xFFFE, 0x7FFE, 0x7FFC, 0x7FFA, 0x7FF6, 0x7FF7, 0x7FF3, 0x7FF2, + 0x7FEF, 0x7FEE, 0x3FF5, 0x3FF3, 0x3FF1, 0x1FF7, 0x1FF5, 0x1FF2, + 0x1FF0, 0x1FEE, 0x1FEC, 0x1FEA, 0x1FE8, 0x0FF2, 0x0FF0, 0x0FEE, + 0x0FEB, 0x07F4, 0x07F3, 0x07F1, 0x03F7, 0x03F5, 0x03F3, 0x01F7, + 0x00FA, 0x00F8, 0x007A, 0x0078, 0x001C, 0x0002, 0x0000, 0x0006, + 0x001D, 0x0079, 0x007B, 0x00F9, 0x01F6, 0x01F8, 0x03F2, 0x03F4, + 0x03F6, 0x07F0, 0x07F2, 0x0FEA, 0x0FEC, 0x0FEF, 0x0FF1, 0x0FF3, + 0x1FE9, 0x1FEB, 0x1FED, 0x1FEF, 0x1FF1, 0x1FF3, 0x1FF4, 0x1FF6, + 0x3FF0, 0x3FF2, 0x3FF4, 0x3FF6, 0x7FF0, 0x7FF1, 0x7FF4, 0x7FF8, + 0x7FF5, 0x7FF9, 0x7FFB, 0x7FFD, 0xFFFF, 0x0FED, +}; + +static const uint16_t clv_biasy_1_syms[] = { + 0xFF68, 0xFF6C, 0xFF70, 0xFF74, 0xFF78, 0xFF7C, 0xFF80, 0xFF84, + 0xFF88, 0xFF8C, 0xFF90, 0xFF94, 0xFF98, 0xFF9C, 0xFFA0, 0xFFA4, + 0xFFA8, 0xFFAC, 0xFFB0, 0xFFB4, 0xFFB8, 0xFFBC, 0xFFC0, 0xFFC4, + 0xFFC8, 0xFFCC, 0xFFD0, 0xFFD4, 0xFFD8, 0xFFDC, 0xFFE0, 0xFFE4, + 0xFFE8, 0xFFEC, 0xFFF0, 0xFFF4, 0xFFF8, 0xFFFC, 0x0000, 0x0004, + 0x0008, 0x000C, 0x0010, 0x0014, 0x0018, 0x001C, 0x0020, 0x0024, + 0x0028, 0x002C, 0x0030, 0x0034, 0x0038, 0x003C, 0x0040, 0x0044, + 0x0048, 0x004C, 0x0050, 0x0054, 0x0058, 0x005C, 0x0060, 0x0064, + 0x0068, 0x006C, 0x0070, 0x0074, 0x0078, 0x007C, 0x0080, 0x0084, + 0x0088, 0x008C, 0x0090, 0x0094, 0x0098, 0x0100, +}; + +static const uint8_t clv_biasy_2_bits[] = { + 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 14, 14, 14, 14, 13, 13, 13, 13, 12, 12, 12, 12, 12, 11, + 11, 11, 10, 10, 10, 10, 9, 9, 8, 8, 8, 7, 6, 6, 4, 3, + 1, 3, 4, 6, 6, 7, 8, 8, 8, 9, 9, 10, 10, 10, 10, 11, + 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 14, 14, 14, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, + 16, 15, +}; + +static const uint16_t clv_biasy_2_codes[] = { + 0xFFFE, 0xFFFC, 0xFFFA, 0xFFF9, 0xFFF6, 0xFFF5, 0xFFF3, 0x7FF7, + 0x7FF5, 0x7FF1, 0x7FF3, 0x7FF0, 0x7FEE, 0x7FEC, 0x7FE9, 0x7FE6, + 0x7FE4, 0x7FE2, 0x3FEF, 0x3FEE, 0x3FEC, 0x3FEA, 0x1FF2, 0x1FF1, + 0x1FEF, 0x1FED, 0x0FF4, 0x0FF3, 0x0FF1, 0x0FEF, 0x0FED, 0x07F4, + 0x07F3, 0x07F1, 0x03F6, 0x03F4, 0x03F2, 0x03F0, 0x01F6, 0x01F4, + 0x00F8, 0x00F6, 0x00F4, 0x0078, 0x003A, 0x0038, 0x000C, 0x0004, + 0x0000, 0x0005, 0x000D, 0x0039, 0x003B, 0x0079, 0x00F5, 0x00F7, + 0x00F9, 0x01F5, 0x01F7, 0x03F1, 0x03F3, 0x03F5, 0x03F7, 0x07F0, + 0x07F2, 0x07F5, 0x0FEC, 0x0FEE, 0x0FF0, 0x0FF2, 0x0FF5, 0x1FEC, + 0x1FEE, 0x1FF0, 0x1FF3, 0x1FF4, 0x3FEB, 0x3FED, 0x3FF0, 0x7FE3, + 0x7FE5, 0x7FE7, 0x7FEA, 0x7FEB, 0x7FED, 0x7FEF, 0x7FF4, 0x7FF2, + 0x7FF6, 0x7FF8, 0xFFF2, 0xFFF4, 0xFFF7, 0xFFF8, 0xFFFB, 0xFFFD, + 0xFFFF, 0x7FE8, +}; + +static const uint16_t clv_biasy_2_syms[] = { + 0xFF40, 0xFF44, 0xFF48, 0xFF4C, 0xFF50, 0xFF54, 0xFF58, 0xFF5C, + 0xFF60, 0xFF64, 0xFF68, 0xFF6C, 0xFF70, 0xFF74, 0xFF78, 0xFF7C, + 0xFF80, 0xFF84, 0xFF88, 0xFF8C, 0xFF90, 0xFF94, 0xFF98, 0xFF9C, + 0xFFA0, 0xFFA4, 0xFFA8, 0xFFAC, 0xFFB0, 0xFFB4, 0xFFB8, 0xFFBC, + 0xFFC0, 0xFFC4, 0xFFC8, 0xFFCC, 0xFFD0, 0xFFD4, 0xFFD8, 0xFFDC, + 0xFFE0, 0xFFE4, 0xFFE8, 0xFFEC, 0xFFF0, 0xFFF4, 0xFFF8, 0xFFFC, + 0x0000, 0x0004, 0x0008, 0x000C, 0x0010, 0x0014, 0x0018, 0x001C, + 0x0020, 0x0024, 0x0028, 0x002C, 0x0030, 0x0034, 0x0038, 0x003C, + 0x0040, 0x0044, 0x0048, 0x004C, 0x0050, 0x0054, 0x0058, 0x005C, + 0x0060, 0x0064, 0x0068, 0x006C, 0x0070, 0x0074, 0x0078, 0x007C, + 0x0080, 0x0084, 0x0088, 0x008C, 0x0090, 0x0094, 0x0098, 0x009C, + 0x00A0, 0x00A4, 0x00A8, 0x00AC, 0x00B0, 0x00B4, 0x00B8, 0x00BC, + 0x00C0, 0x0100, +}; + +static const uint8_t clv_biasy_3_bits[] = { + 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, + 14, 14, 13, 13, 13, 13, 12, 12, 12, 11, 11, 11, 11, 10, 10, 10, + 10, 9, 9, 9, 9, 8, 8, 7, 7, 6, 5, 4, 4, 2, 2, 3, + 4, 5, 6, 6, 7, 7, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, + 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 14, 14, 14, 14, 14, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 15, +}; + +static const uint16_t clv_biasy_3_codes[] = { + 0xFFFF, 0xFFFC, 0xFFFA, 0x7FFC, 0x7FF9, 0x7FF6, 0x7FF4, 0x7FF2, + 0x7FF1, 0x7FEF, 0x7FEC, 0x7FEB, 0x7FE9, 0x3FF3, 0x3FF0, 0x3FEE, + 0x3FED, 0x3FEA, 0x1FF3, 0x1FF2, 0x1FF0, 0x1FEE, 0x0FF4, 0x0FF3, + 0x0FF1, 0x07F7, 0x07F5, 0x07F3, 0x07F1, 0x03F7, 0x03F4, 0x03F2, + 0x03F0, 0x01F6, 0x01F4, 0x01F2, 0x01F0, 0x00F6, 0x00F4, 0x0078, + 0x0076, 0x0039, 0x001B, 0x000C, 0x000A, 0x0001, 0x0000, 0x0004, + 0x000B, 0x001A, 0x0038, 0x003A, 0x0077, 0x0079, 0x00F5, 0x00F7, + 0x01F1, 0x01F3, 0x01F5, 0x01F7, 0x03F1, 0x03F3, 0x03F5, 0x03F6, + 0x07F0, 0x07F2, 0x07F4, 0x07F6, 0x0FF0, 0x0FF2, 0x0FF5, 0x0FF6, + 0x1FEF, 0x1FF1, 0x1FF4, 0x3FEB, 0x3FEC, 0x3FEF, 0x3FF1, 0x3FF2, + 0x7FE8, 0x7FEA, 0x7FED, 0x7FEE, 0x7FF0, 0x7FF3, 0x7FF5, 0x7FF7, + 0x7FFA, 0x7FFB, 0xFFFB, 0xFFFD, 0xFFFE, 0x7FF8, +}; + +static const uint16_t clv_biasy_3_syms[] = { + 0xFF48, 0xFF4C, 0xFF50, 0xFF54, 0xFF58, 0xFF5C, 0xFF60, 0xFF64, + 0xFF68, 0xFF6C, 0xFF70, 0xFF74, 0xFF78, 0xFF7C, 0xFF80, 0xFF84, + 0xFF88, 0xFF8C, 0xFF90, 0xFF94, 0xFF98, 0xFF9C, 0xFFA0, 0xFFA4, + 0xFFA8, 0xFFAC, 0xFFB0, 0xFFB4, 0xFFB8, 0xFFBC, 0xFFC0, 0xFFC4, + 0xFFC8, 0xFFCC, 0xFFD0, 0xFFD4, 0xFFD8, 0xFFDC, 0xFFE0, 0xFFE4, + 0xFFE8, 0xFFEC, 0xFFF0, 0xFFF4, 0xFFF8, 0xFFFC, 0x0000, 0x0004, + 0x0008, 0x000C, 0x0010, 0x0014, 0x0018, 0x001C, 0x0020, 0x0024, + 0x0028, 0x002C, 0x0030, 0x0034, 0x0038, 0x003C, 0x0040, 0x0044, + 0x0048, 0x004C, 0x0050, 0x0054, 0x0058, 0x005C, 0x0060, 0x0064, + 0x0068, 0x006C, 0x0070, 0x0074, 0x0078, 0x007C, 0x0080, 0x0084, + 0x0088, 0x008C, 0x0090, 0x0094, 0x0098, 0x009C, 0x00A0, 0x00A4, + 0x00A8, 0x00AC, 0x00B0, 0x00B4, 0x00B8, 0x0100, +}; + +static const uint8_t clv_biasu_1_bits[] = { + 16, 15, 14, 13, 13, 13, 12, 12, 12, 12, 11, 10, 10, 9, 9, 8, + 7, 6, 5, 2, 1, 3, 5, 7, 7, 8, 9, 9, 10, 10, 11, 12, + 12, 12, 12, 13, 13, 13, 14, 15, 15, 16, +}; + +static const uint16_t clv_biasu_1_codes[] = { + 0xFFFE, 0x7FFC, 0x3FFC, 0x1FFC, 0x1FFA, 0x1FF9, 0x0FFA, 0x0FF7, + 0x0FF8, 0x0FF5, 0x07F8, 0x03FA, 0x03F8, 0x01FA, 0x01F9, 0x00FA, + 0x007B, 0x003C, 0x001C, 0x0002, 0x0000, 0x0006, 0x001D, 0x007A, + 0x007C, 0x00FB, 0x01F8, 0x01FB, 0x03F9, 0x03FB, 0x07F9, 0x0FF4, + 0x0FF6, 0x0FF9, 0x0FFB, 0x1FF8, 0x1FFB, 0x1FFD, 0x3FFD, 0x7FFD, + 0x7FFE, 0xFFFF, +}; + +static const uint16_t clv_biasu_1_syms[] = { + 0xFFB0, 0xFFB4, 0xFFB8, 0xFFBC, 0xFFC0, 0xFFC4, 0xFFC8, 0xFFCC, + 0xFFD0, 0xFFD4, 0xFFD8, 0xFFDC, 0xFFE0, 0xFFE4, 0xFFE8, 0xFFEC, + 0xFFF0, 0xFFF4, 0xFFF8, 0xFFFC, 0x0000, 0x0004, 0x0008, 0x000C, + 0x0010, 0x0014, 0x0018, 0x001C, 0x0020, 0x0024, 0x0028, 0x002C, + 0x0030, 0x0034, 0x0038, 0x003C, 0x0040, 0x0044, 0x0048, 0x004C, + 0x0050, 0x0100, +}; + +static const uint8_t clv_biasu_2_bits[] = { + 16, 16, 16, 16, 15, 15, 15, 14, 14, 14, 13, 12, 12, 11, 11, 10, + 10, 9, 9, 8, 8, 7, 6, 5, 4, 3, 1, 3, 4, 6, 6, 7, + 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 14, 14, 14, 15, 15, + 15, 16, 16, 16, 16, 14, +}; + +static const uint16_t clv_biasu_2_codes[] = { + 0xFFFC, 0xFFF8, 0xFFFA, 0xFFFD, 0x7FF8, 0x7FFA, 0x7FF7, 0x3FF6, + 0x3FF7, 0x3FF4, 0x1FF9, 0x0FFB, 0x0FF9, 0x07FB, 0x07F9, 0x03FA, + 0x03F8, 0x01FA, 0x01F9, 0x00FB, 0x00F9, 0x007B, 0x003B, 0x001C, + 0x000C, 0x0004, 0x0000, 0x0005, 0x000D, 0x003A, 0x003C, 0x007A, + 0x00F8, 0x00FA, 0x01F8, 0x01FB, 0x03F9, 0x03FB, 0x07F8, 0x07FA, + 0x0FF8, 0x0FFA, 0x1FF8, 0x3FF5, 0x3FF8, 0x3FF9, 0x7FFB, 0x7FF9, + 0x7FF6, 0xFFF9, 0xFFFF, 0xFFFE, 0xFFFB, 0x3FFA, +}; + +static const uint16_t clv_biasu_2_syms[] = { + 0xFF98, 0xFF9C, 0xFFA0, 0xFFA4, 0xFFA8, 0xFFAC, 0xFFB0, 0xFFB4, + 0xFFB8, 0xFFBC, 0xFFC0, 0xFFC4, 0xFFC8, 0xFFCC, 0xFFD0, 0xFFD4, + 0xFFD8, 0xFFDC, 0xFFE0, 0xFFE4, 0xFFE8, 0xFFEC, 0xFFF0, 0xFFF4, + 0xFFF8, 0xFFFC, 0x0000, 0x0004, 0x0008, 0x000C, 0x0010, 0x0014, + 0x0018, 0x001C, 0x0020, 0x0024, 0x0028, 0x002C, 0x0030, 0x0034, + 0x0038, 0x003C, 0x0040, 0x0044, 0x0048, 0x004C, 0x0050, 0x0054, + 0x0058, 0x005C, 0x0060, 0x0064, 0x0068, 0x0100, +}; + +static const uint8_t clv_biasv_1_bits[] = { + 16, 15, 14, 14, 14, 13, 13, 13, 12, 12, 11, 11, 10, 10, 9, 8, + 7, 6, 5, 2, 1, 3, 5, 6, 8, 8, 9, 10, 10, 11, 12, 12, + 12, 13, 13, 13, 14, 14, 15, 15, 16, 14, +}; + +static const uint16_t clv_biasv_1_codes[] = { + 0xFFFF, 0x7FFD, 0x3FFD, 0x3FFB, 0x3FF9, 0x1FFB, 0x1FF8, 0x1FF6, + 0x0FFA, 0x0FF8, 0x07FA, 0x07F8, 0x03FA, 0x03F8, 0x01FB, 0x00FB, + 0x007C, 0x003C, 0x001C, 0x0002, 0x0000, 0x0006, 0x001D, 0x003D, + 0x00FA, 0x00FC, 0x01FA, 0x03F9, 0x03FB, 0x07F9, 0x0FF6, 0x0FF7, + 0x0FF9, 0x1FF7, 0x1FF9, 0x1FFA, 0x3FFA, 0x3FFC, 0x7FFC, 0x7FFE, + 0xFFFE, 0x3FF8, +}; + +static const uint16_t clv_biasv_1_syms[] = { + 0xFFB0, 0xFFB4, 0xFFB8, 0xFFBC, 0xFFC0, 0xFFC4, 0xFFC8, 0xFFCC, + 0xFFD0, 0xFFD4, 0xFFD8, 0xFFDC, 0xFFE0, 0xFFE4, 0xFFE8, 0xFFEC, + 0xFFF0, 0xFFF4, 0xFFF8, 0xFFFC, 0x0000, 0x0004, 0x0008, 0x000C, + 0x0010, 0x0014, 0x0018, 0x001C, 0x0020, 0x0024, 0x0028, 0x002C, + 0x0030, 0x0034, 0x0038, 0x003C, 0x0040, 0x0044, 0x0048, 0x004C, + 0x0050, 0x0100, +}; + +static const uint8_t clv_biasv_2_bits[] = { + 16, 15, 14, 13, 13, 13, 13, 13, 12, 12, 11, 10, 10, 9, 9, 8, + 7, 6, 5, 4, 3, 1, 3, 4, 5, 7, 7, 8, 9, 9, 10, 10, + 10, 12, 12, 13, 13, 13, 13, 13, 14, 16, 15, 15, +}; + +static const uint16_t clv_biasv_2_codes[] = { + 0xFFFE, 0x7FFD, 0x3FFC, 0x1FFC, 0x1FFB, 0x1FF8, 0x1FF7, 0x1FF4, + 0x0FF8, 0x0FF7, 0x07FA, 0x03FB, 0x03F8, 0x01FA, 0x01F9, 0x00FA, + 0x007B, 0x003C, 0x001C, 0x000C, 0x0004, 0x0000, 0x0005, 0x000D, + 0x001D, 0x007A, 0x007C, 0x00FB, 0x01F8, 0x01FB, 0x03F9, 0x03FA, + 0x03FC, 0x0FF6, 0x0FF9, 0x1FF5, 0x1FF9, 0x1FF6, 0x1FFA, 0x1FFD, + 0x3FFD, 0xFFFF, 0x7FFE, 0x7FFC, +}; + +static const uint16_t clv_biasv_2_syms[] = { + 0xFFAC, 0xFFB0, 0xFFB4, 0xFFB8, 0xFFBC, 0xFFC0, 0xFFC4, 0xFFC8, + 0xFFCC, 0xFFD0, 0xFFD4, 0xFFD8, 0xFFDC, 0xFFE0, 0xFFE4, 0xFFE8, + 0xFFEC, 0xFFF0, 0xFFF4, 0xFFF8, 0xFFFC, 0x0000, 0x0004, 0x0008, + 0x000C, 0x0010, 0x0014, 0x0018, 0x001C, 0x0020, 0x0024, 0x0028, + 0x002C, 0x0030, 0x0034, 0x0038, 0x003C, 0x0040, 0x0044, 0x0048, + 0x004C, 0x0050, 0x0054, 0x0100, +}; + +#endif /* AVCODEC_CLEARVIDEODATA_H */ diff --git a/libavcodec/cngdec.c b/libavcodec/cngdec.c index 1e884f3c33955..28432ac7194b6 100644 --- a/libavcodec/cngdec.c +++ b/libavcodec/cngdec.c @@ -153,7 +153,7 @@ static int cng_decode_frame(AVCodecContext *avctx, void *data, return ret; buf_out = (int16_t *)frame->data[0]; for (i = 0; i < avctx->frame_size; i++) - buf_out[i] = p->filter_out[i + p->order]; + buf_out[i] = av_clip_int16(p->filter_out[i + p->order]); memcpy(p->filter_out, p->filter_out + avctx->frame_size, p->order * sizeof(*p->filter_out)); diff --git a/libavcodec/codec2utils.c b/libavcodec/codec2utils.c new file mode 100644 index 0000000000000..931478f22a3e1 --- /dev/null +++ b/libavcodec/codec2utils.c @@ -0,0 +1,80 @@ +/* + * codec2 utility functions + * Copyright (c) 2017 Tomas Härdin + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "internal.h" +#include "libavcodec/codec2utils.h" + +int avpriv_codec2_mode_bit_rate(void *logctx, int mode) +{ + int frame_size = avpriv_codec2_mode_frame_size(logctx, mode); + int block_align = avpriv_codec2_mode_block_align(logctx, mode); + + if (frame_size <= 0 || block_align <= 0) { + return 0; + } + + return 8 * 8000 * block_align / frame_size; +} + +int avpriv_codec2_mode_frame_size(void *logctx, int mode) +{ + int frame_size_table[AVPRIV_CODEC2_MODE_MAX+1] = { + 160, // 3200 + 160, // 2400 + 320, // 1600 + 320, // 1400 + 320, // 1300 + 320, // 1200 + 320, // 700 + 320, // 700B + 320, // 700C + }; + + if (mode < 0 || mode > AVPRIV_CODEC2_MODE_MAX) { + av_log(logctx, AV_LOG_ERROR, "unknown codec2 mode %i, can't find frame_size\n", mode); + return 0; + } else { + return frame_size_table[mode]; + } +} + +int avpriv_codec2_mode_block_align(void *logctx, int mode) +{ + int block_align_table[AVPRIV_CODEC2_MODE_MAX+1] = { + 8, // 3200 + 6, // 2400 + 8, // 1600 + 7, // 1400 + 7, // 1300 + 6, // 1200 + 4, // 700 + 4, // 700B + 4, // 700C + }; + + if (mode < 0 || mode > AVPRIV_CODEC2_MODE_MAX) { + av_log(logctx, AV_LOG_ERROR, "unknown codec2 mode %i, can't find block_align\n", mode); + return 0; + } else { + return block_align_table[mode]; + } +} diff --git a/libavcodec/codec2utils.h b/libavcodec/codec2utils.h new file mode 100644 index 0000000000000..6def4d4aa3958 --- /dev/null +++ b/libavcodec/codec2utils.h @@ -0,0 +1,82 @@ +/* + * codec2 utility functions + * Copyright (c) 2017 Tomas Härdin + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_CODEC2UTILS_H +#define AVCODEC_CODEC2UTILS_H + +#include + +//Highest mode we're willing to use. +//Don't want to let users accidentally produce files that can't be decoded in the future. +//CODEC2_MODE_WB (9) is experimental/unstable as of 2017-11-23. +#define AVPRIV_CODEC2_MODE_MAX 8 //CODEC2_MODE_700C + +//Used by both codec2raw demuxer and libcodec2 encoder. +//The integers match the values in codec2.h, so "3200" -> CODEC2_MODE_3000 = 0 and so on. +//It is possible that we're linked to a version of libcodec2 that lacks some of these modes. +//For example Debian stretch ships with libcodec2.so.0.4 which lacks CODEC2_MODE_700C. +#define AVPRIV_CODEC2_AVOPTIONS(desc, classname, min_val, default_val, option_flags) \ + { "mode", desc, offsetof(classname, mode), AV_OPT_TYPE_INT, {.i64 = default_val}, min_val, AVPRIV_CODEC2_MODE_MAX, .flags=option_flags, .unit="codec2_mode"},\ + { "3200", "3200", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, .flags=option_flags, .unit="codec2_mode"},\ + { "2400", "2400", 0, AV_OPT_TYPE_CONST, {.i64 = 1}, .flags=option_flags, .unit="codec2_mode"},\ + { "1600", "1600", 0, AV_OPT_TYPE_CONST, {.i64 = 2}, .flags=option_flags, .unit="codec2_mode"},\ + { "1400", "1400", 0, AV_OPT_TYPE_CONST, {.i64 = 3}, .flags=option_flags, .unit="codec2_mode"},\ + { "1300", "1300", 0, AV_OPT_TYPE_CONST, {.i64 = 4}, .flags=option_flags, .unit="codec2_mode"},\ + { "1200", "1200", 0, AV_OPT_TYPE_CONST, {.i64 = 5}, .flags=option_flags, .unit="codec2_mode"},\ + { "700", "700", 0, AV_OPT_TYPE_CONST, {.i64 = 6}, .flags=option_flags, .unit="codec2_mode"},\ + { "700B", "700B", 0, AV_OPT_TYPE_CONST, {.i64 = 7}, .flags=option_flags, .unit="codec2_mode"},\ + { "700C", "700C", 0, AV_OPT_TYPE_CONST, {.i64 = 8}, .flags=option_flags, .unit="codec2_mode"} + +//The three following functions are here to avoid needing libavformat/codec2.c to depend on libcodec2 + +//Computes bitrate from mode, with frames rounded up to the nearest octet. +//So 700 bit/s (28 bits/frame) becomes 800 bits/s (32 bits/frame). +//logctx is used for av_log() +//Returns <0 if mode is invalid +int avpriv_codec2_mode_bit_rate(void *logctx, int mode); + +//Mimics codec2_samples_per_frame() +int avpriv_codec2_mode_frame_size(void *logctx, int mode); + +//Mimics (codec2_bits_per_frame()+7)/8 +int avpriv_codec2_mode_block_align(void *logctx, int mode); + +#define AVPRIV_CODEC2_EXTRADATA_SIZE 4 + +//Used in codec2raw demuxer and libcodec2 encoder +static inline void avpriv_codec2_make_extradata(uint8_t *ptr, int mode) { + //version 0.8 as of 2017-12-23 (r3386) + ptr[0] = 0; //major + ptr[1] = 8; //minor + ptr[2] = mode; //mode + ptr[3] = 0; //flags +} + +//Returns version as a 16-bit value. 0.8 -> 0x0008 +static inline uint16_t avpriv_codec2_version_from_extradata(uint8_t *ptr) { + return (ptr[0] << 8) + ptr[1]; +} + +static inline uint8_t avpriv_codec2_mode_from_extradata(uint8_t *ptr) { + return ptr[2]; +} + +#endif /* AVCODEC_CODEC2UTILS_H */ diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 6a13bbbf0ee0c..79552a910d647 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -46,15 +46,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_REORDER, .profiles = NULL_IF_CONFIG_SMALL(ff_mpeg2_video_profiles), }, -#if FF_API_XVMC - { - .id = AV_CODEC_ID_MPEG2VIDEO_XVMC, - .type = AVMEDIA_TYPE_VIDEO, - .name = "mpegvideo_xvmc", - .long_name = NULL_IF_CONFIG_SMALL("MPEG-1/2 video XvMC (X-Video Motion Compensation)"), - .props = AV_CODEC_PROP_LOSSY, - }, -#endif /* FF_API_XVMC */ { .id = AV_CODEC_ID_H261, .type = AVMEDIA_TYPE_VIDEO, @@ -98,6 +89,28 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Apple MJPEG-B"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_LJPEG, + .type = AVMEDIA_TYPE_VIDEO, + .name = "ljpeg", + .long_name = NULL_IF_CONFIG_SMALL("Lossless JPEG"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_SP5X, + .type = AVMEDIA_TYPE_VIDEO, + .name = "sp5x", + .long_name = NULL_IF_CONFIG_SMALL("Sunplus JPEG (SP5X)"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_JPEGLS, + .type = AVMEDIA_TYPE_VIDEO, + .name = "jpegls", + .long_name = NULL_IF_CONFIG_SMALL("JPEG-LS"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY | + AV_CODEC_PROP_LOSSLESS, + }, { .id = AV_CODEC_ID_MPEG4, .type = AVMEDIA_TYPE_VIDEO, @@ -169,14 +182,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("FLV / Sorenson Spark / Sorenson H.263 (Flash Video)"), .props = AV_CODEC_PROP_LOSSY, }, - { - .id = AV_CODEC_ID_SVG, - .type = AVMEDIA_TYPE_VIDEO, - .name = "svg", - .long_name = NULL_IF_CONFIG_SMALL("Scalable Vector Graphics"), - .props = AV_CODEC_PROP_LOSSLESS, - .mime_types= MT("image/svg+xml"), - }, { .id = AV_CODEC_ID_SVQ1, .type = AVMEDIA_TYPE_VIDEO, @@ -416,13 +421,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("QuickTime Animation (RLE) video"), .props = AV_CODEC_PROP_LOSSLESS, }, - { - .id = AV_CODEC_ID_SNOW, - .type = AVMEDIA_TYPE_VIDEO, - .name = "snow", - .long_name = NULL_IF_CONFIG_SMALL("Snow"), - .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS, - }, { .id = AV_CODEC_ID_TSCC, .type = AVMEDIA_TYPE_VIDEO, @@ -458,6 +456,50 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Q-team QPEG"), .props = AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_PNG, + .type = AVMEDIA_TYPE_VIDEO, + .name = "png", + .long_name = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"), + .props = AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/png"), + }, + { + .id = AV_CODEC_ID_PPM, + .type = AVMEDIA_TYPE_VIDEO, + .name = "ppm", + .long_name = NULL_IF_CONFIG_SMALL("PPM (Portable PixelMap) image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PBM, + .type = AVMEDIA_TYPE_VIDEO, + .name = "pbm", + .long_name = NULL_IF_CONFIG_SMALL("PBM (Portable BitMap) image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PGM, + .type = AVMEDIA_TYPE_VIDEO, + .name = "pgm", + .long_name = NULL_IF_CONFIG_SMALL("PGM (Portable GrayMap) image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PGMYUV, + .type = AVMEDIA_TYPE_VIDEO, + .name = "pgmyuv", + .long_name = NULL_IF_CONFIG_SMALL("PGMYUV (Portable GrayMap YUV) image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PAM, + .type = AVMEDIA_TYPE_VIDEO, + .name = "pam", + .long_name = NULL_IF_CONFIG_SMALL("PAM (Portable AnyMap) image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/x-portable-pixmap"), + }, { .id = AV_CODEC_ID_FFVHUFF, .type = AVMEDIA_TYPE_VIDEO, @@ -646,6 +688,14 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("On2 VP6 (Flash version)"), .props = AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_TARGA, + .type = AVMEDIA_TYPE_VIDEO, + .name = "targa", + .long_name = NULL_IF_CONFIG_SMALL("Truevision Targa image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/x-targa", "image/x-tga"), + }, { .id = AV_CODEC_ID_DSICINVIDEO, .type = AVMEDIA_TYPE_VIDEO, @@ -660,6 +710,22 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Tiertex Limited SEQ video"), .props = AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_TIFF, + .type = AVMEDIA_TYPE_VIDEO, + .name = "tiff", + .long_name = NULL_IF_CONFIG_SMALL("TIFF image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/tiff"), + }, + { + .id = AV_CODEC_ID_GIF, + .type = AVMEDIA_TYPE_VIDEO, + .name = "gif", + .long_name = NULL_IF_CONFIG_SMALL("GIF (Graphics Interchange Format)"), + .props = AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/gif"), + }, { .id = AV_CODEC_ID_DXA, .type = AVMEDIA_TYPE_VIDEO, @@ -682,6 +748,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Nintendo Gamecube THP video"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_SGI, + .type = AVMEDIA_TYPE_VIDEO, + .name = "sgi", + .long_name = NULL_IF_CONFIG_SMALL("SGI image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, { .id = AV_CODEC_ID_C93, .type = AVMEDIA_TYPE_VIDEO, @@ -696,6 +769,20 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Bethesda VID video"), .props = AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_PTX, + .type = AVMEDIA_TYPE_VIDEO, + .name = "ptx", + .long_name = NULL_IF_CONFIG_SMALL("V.Flash PTX image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_TXD, + .type = AVMEDIA_TYPE_VIDEO, + .name = "txd", + .long_name = NULL_IF_CONFIG_SMALL("Renderware TXD (TeXture Dictionary) image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, { .id = AV_CODEC_ID_VP6A, .type = AVMEDIA_TYPE_VIDEO, @@ -717,6 +804,21 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Beam Software VB"), .props = AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_PCX, + .type = AVMEDIA_TYPE_VIDEO, + .name = "pcx", + .long_name = NULL_IF_CONFIG_SMALL("PC Paintbrush PCX image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/x-pcx"), + }, + { + .id = AV_CODEC_ID_SUNRAST, + .type = AVMEDIA_TYPE_VIDEO, + .name = "sunrast", + .long_name = NULL_IF_CONFIG_SMALL("Sun Rasterfile image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, { .id = AV_CODEC_ID_INDEO4, .type = AVMEDIA_TYPE_VIDEO, @@ -752,13 +854,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Escape 124"), .props = AV_CODEC_PROP_LOSSY, }, - { - .id = AV_CODEC_ID_DAALA, - .type = AVMEDIA_TYPE_VIDEO, - .name = "daala", - .long_name = NULL_IF_CONFIG_SMALL("Daala"), - .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS, - }, { .id = AV_CODEC_ID_DIRAC, .type = AVMEDIA_TYPE_VIDEO, @@ -843,6 +938,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Uncompressed 4:2:2 10-bit"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, + { + .id = AV_CODEC_ID_DPX, + .type = AVMEDIA_TYPE_VIDEO, + .name = "dpx", + .long_name = NULL_IF_CONFIG_SMALL("DPX (Digital Picture Exchange) image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, { .id = AV_CODEC_ID_MAD, .type = AVMEDIA_TYPE_VIDEO, @@ -920,14 +1022,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("On2 VP8"), .props = AV_CODEC_PROP_LOSSY, }, - { - .id = AV_CODEC_ID_VP9, - .type = AVMEDIA_TYPE_VIDEO, - .name = "vp9", - .long_name = NULL_IF_CONFIG_SMALL("Google VP9"), - .props = AV_CODEC_PROP_LOSSY, - .profiles = NULL_IF_CONFIG_SMALL(ff_vp9_profiles), - }, { .id = AV_CODEC_ID_PICTOR, .type = AVMEDIA_TYPE_VIDEO, @@ -935,6 +1029,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Pictor/PC Paint"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_ANSI, + .type = AVMEDIA_TYPE_VIDEO, + .name = "ansi", + .long_name = NULL_IF_CONFIG_SMALL("ASCII/ANSI art"), + .props = AV_CODEC_PROP_LOSSY, + }, { .id = AV_CODEC_ID_A64_MULTI, .type = AVMEDIA_TYPE_VIDEO, @@ -956,27 +1057,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("AJA Kona 10-bit RGB Codec"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, - { - .id = AV_CODEC_ID_M101, - .type = AVMEDIA_TYPE_VIDEO, - .name = "m101", - .long_name = NULL_IF_CONFIG_SMALL("Matrox Uncompressed SD"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, - }, - { - .id = AV_CODEC_ID_MVC1, - .type = AVMEDIA_TYPE_VIDEO, - .name = "mvc1", - .long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 1"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, - }, - { - .id = AV_CODEC_ID_MVC2, - .type = AVMEDIA_TYPE_VIDEO, - .name = "mvc2", - .long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 2"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, - }, { .id = AV_CODEC_ID_MXPEG, .type = AVMEDIA_TYPE_VIDEO, @@ -1012,6 +1092,20 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Chronomaster DFA"), .props = AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_WMV3IMAGE, + .type = AVMEDIA_TYPE_VIDEO, + .name = "wmv3image", + .long_name = NULL_IF_CONFIG_SMALL("Windows Media Video 9 Image"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_VC1IMAGE, + .type = AVMEDIA_TYPE_VIDEO, + .name = "vc1image", + .long_name = NULL_IF_CONFIG_SMALL("Windows Media Video 9 Image v2"), + .props = AV_CODEC_PROP_LOSSY, + }, { .id = AV_CODEC_ID_UTVIDEO, .type = AVMEDIA_TYPE_VIDEO, @@ -1047,6 +1141,14 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Uncompressed 4:4:4 10-bit"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, + { + .id = AV_CODEC_ID_XWD, + .type = AVMEDIA_TYPE_VIDEO, + .name = "xwd", + .long_name = NULL_IF_CONFIG_SMALL("XWD (X Window Dump) image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/x-xwindowdump"), + }, { .id = AV_CODEC_ID_CDXL, .type = AVMEDIA_TYPE_VIDEO, @@ -1054,6 +1156,14 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Commodore CDXL video"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_XBM, + .type = AVMEDIA_TYPE_VIDEO, + .name = "xbm", + .long_name = NULL_IF_CONFIG_SMALL("XBM (X BitMap) image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/x-xbitmap"), + }, { .id = AV_CODEC_ID_ZEROCODEC, .type = AVMEDIA_TYPE_VIDEO, @@ -1103,6 +1213,14 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("MS Windows Media Video V9 Screen"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_VP9, + .type = AVMEDIA_TYPE_VIDEO, + .name = "vp9", + .long_name = NULL_IF_CONFIG_SMALL("Google VP9"), + .props = AV_CODEC_PROP_LOSSY, + .profiles = NULL_IF_CONFIG_SMALL(ff_vp9_profiles), + }, { .id = AV_CODEC_ID_AIC, .type = AVMEDIA_TYPE_VIDEO, @@ -1110,13 +1228,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Apple Intermediate Codec"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, - { - .id = AV_CODEC_ID_Y41P, - .type = AVMEDIA_TYPE_VIDEO, - .name = "y41p", - .long_name = NULL_IF_CONFIG_SMALL("Uncompressed YUV 4:1:1 12-bit"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, - }, { .id = AV_CODEC_ID_ESCAPE130, .type = AVMEDIA_TYPE_VIDEO, @@ -1125,93 +1236,20 @@ static const AVCodecDescriptor codec_descriptors[] = { .props = AV_CODEC_PROP_LOSSY, }, { - .id = AV_CODEC_ID_AVRP, + .id = AV_CODEC_ID_G2M, .type = AVMEDIA_TYPE_VIDEO, - .name = "avrp", - .long_name = NULL_IF_CONFIG_SMALL("Avid 1:1 10-bit RGB Packer"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + .name = "g2m", + .long_name = NULL_IF_CONFIG_SMALL("Go2Meeting"), + .props = AV_CODEC_PROP_LOSSY, }, { - .id = AV_CODEC_ID_012V, + .id = AV_CODEC_ID_WEBP, .type = AVMEDIA_TYPE_VIDEO, - .name = "012v", - .long_name = NULL_IF_CONFIG_SMALL("Uncompressed 4:2:2 10-bit"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, - }, - { - .id = AV_CODEC_ID_AVUI, - .type = AVMEDIA_TYPE_VIDEO, - .name = "avui", - .long_name = NULL_IF_CONFIG_SMALL("Avid Meridien Uncompressed"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, - }, - { - .id = AV_CODEC_ID_AYUV, - .type = AVMEDIA_TYPE_VIDEO, - .name = "ayuv", - .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed MS 4:4:4:4"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, - }, - { - .id = AV_CODEC_ID_TARGA_Y216, - .type = AVMEDIA_TYPE_VIDEO, - .name = "targa_y216", - .long_name = NULL_IF_CONFIG_SMALL("Pinnacle TARGA CineWave YUV16"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, - }, - { - .id = AV_CODEC_ID_V308, - .type = AVMEDIA_TYPE_VIDEO, - .name = "v308", - .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed 4:4:4"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, - }, - { - .id = AV_CODEC_ID_V408, - .type = AVMEDIA_TYPE_VIDEO, - .name = "v408", - .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed QT 4:4:4:4"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, - }, - { - .id = AV_CODEC_ID_YUV4, - .type = AVMEDIA_TYPE_VIDEO, - .name = "yuv4", - .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed 4:2:0"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, - }, - { - .id = AV_CODEC_ID_AVRN, - .type = AVMEDIA_TYPE_VIDEO, - .name = "avrn", - .long_name = NULL_IF_CONFIG_SMALL("Avid AVI Codec"), - }, - { - .id = AV_CODEC_ID_CPIA, - .type = AVMEDIA_TYPE_VIDEO, - .name = "cpia", - .long_name = NULL_IF_CONFIG_SMALL("CPiA video format"), - }, - { - .id = AV_CODEC_ID_XFACE, - .type = AVMEDIA_TYPE_VIDEO, - .name = "xface", - .long_name = NULL_IF_CONFIG_SMALL("X-face image"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, - }, - { - .id = AV_CODEC_ID_SMVJPEG, - .type = AVMEDIA_TYPE_VIDEO, - .name = "smvjpeg", - .long_name = NULL_IF_CONFIG_SMALL("Sigmatel Motion Video"), - }, - - { - .id = AV_CODEC_ID_G2M, - .type = AVMEDIA_TYPE_VIDEO, - .name = "g2m", - .long_name = NULL_IF_CONFIG_SMALL("Go2Meeting"), - .props = AV_CODEC_PROP_LOSSY, + .name = "webp", + .long_name = NULL_IF_CONFIG_SMALL("WebP"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY | + AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/webp"), }, { .id = AV_CODEC_ID_HNM4_VIDEO, @@ -1235,6 +1273,20 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Mirillis FIC"), .props = AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_ALIAS_PIX, + .type = AVMEDIA_TYPE_VIDEO, + .name = "alias_pix", + .long_name = NULL_IF_CONFIG_SMALL("Alias/Wavefront PIX image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_BRENDER_PIX, + .type = AVMEDIA_TYPE_VIDEO, + .name = "brender_pix", + .long_name = NULL_IF_CONFIG_SMALL("BRender PIX image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + }, { .id = AV_CODEC_ID_PAF_VIDEO, .type = AVMEDIA_TYPE_VIDEO, @@ -1242,6 +1294,14 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Amazing Studio Packed Animation File Video"), .props = AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_EXR, + .type = AVMEDIA_TYPE_VIDEO, + .name = "exr", + .long_name = NULL_IF_CONFIG_SMALL("OpenEXR image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY | + AV_CODEC_PROP_LOSSLESS, + }, { .id = AV_CODEC_ID_VP7, .type = AVMEDIA_TYPE_VIDEO, @@ -1263,6 +1323,20 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("SGI RLE 8-bit"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, + { + .id = AV_CODEC_ID_MVC1, + .type = AVMEDIA_TYPE_VIDEO, + .name = "mvc1", + .long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 1"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_MVC2, + .type = AVMEDIA_TYPE_VIDEO, + .name = "mvc2", + .long_name = NULL_IF_CONFIG_SMALL("Silicon Graphics Motion Video Compressor 2"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + }, { .id = AV_CODEC_ID_HQX, .type = AVMEDIA_TYPE_VIDEO, @@ -1270,6 +1344,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Canopus HQX"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_TDSC, + .type = AVMEDIA_TYPE_VIDEO, + .name = "tdsc", + .long_name = NULL_IF_CONFIG_SMALL("TDSC"), + .props = AV_CODEC_PROP_LOSSY, + }, { .id = AV_CODEC_ID_HQ_HQA, .type = AVMEDIA_TYPE_VIDEO, @@ -1284,6 +1365,14 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Vidvox Hap"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_DDS, + .type = AVMEDIA_TYPE_VIDEO, + .name = "dds", + .long_name = NULL_IF_CONFIG_SMALL("DirectDraw Surface image decoder"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY | + AV_CODEC_PROP_LOSSLESS, + }, { .id = AV_CODEC_ID_DXV, .type = AVMEDIA_TYPE_VIDEO, @@ -1298,20 +1387,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Screenpresso"), .props = AV_CODEC_PROP_LOSSLESS, }, - { - .id = AV_CODEC_ID_SPEEDHQ, - .type = AVMEDIA_TYPE_VIDEO, - .name = "speedhq", - .long_name = NULL_IF_CONFIG_SMALL("NewTek SpeedHQ"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, - }, - { - .id = AV_CODEC_ID_WRAPPED_AVFRAME, - .type = AVMEDIA_TYPE_VIDEO, - .name = "wrapped_avframe", - .long_name = NULL_IF_CONFIG_SMALL("AVFrame to AVPacket passthrough"), - .props = AV_CODEC_PROP_LOSSLESS, - }, { .id = AV_CODEC_ID_RSCC, .type = AVMEDIA_TYPE_VIDEO, @@ -1320,229 +1395,155 @@ static const AVCodecDescriptor codec_descriptors[] = { .props = AV_CODEC_PROP_LOSSLESS, }, { - .id = AV_CODEC_ID_MAGICYUV, + .id = AV_CODEC_ID_Y41P, .type = AVMEDIA_TYPE_VIDEO, - .name = "magicyuv", - .long_name = NULL_IF_CONFIG_SMALL("MagicYUV video"), + .name = "y41p", + .long_name = NULL_IF_CONFIG_SMALL("Uncompressed YUV 4:1:1 12-bit"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, { - .id = AV_CODEC_ID_TRUEMOTION2RT, - .type = AVMEDIA_TYPE_VIDEO, - .name = "truemotion2rt", - .long_name = NULL_IF_CONFIG_SMALL("Duck TrueMotion 2.0 Real Time"), - .props = AV_CODEC_PROP_LOSSY, - }, - { - .id = AV_CODEC_ID_CFHD, - .type = AVMEDIA_TYPE_VIDEO, - .name = "cfhd", - .long_name = NULL_IF_CONFIG_SMALL("Cineform HD"), - .props = AV_CODEC_PROP_LOSSY, - }, - { - .id = AV_CODEC_ID_SHEERVIDEO, + .id = AV_CODEC_ID_AVRP, .type = AVMEDIA_TYPE_VIDEO, - .name = "sheervideo", - .long_name = NULL_IF_CONFIG_SMALL("BitJazz SheerVideo"), + .name = "avrp", + .long_name = NULL_IF_CONFIG_SMALL("Avid 1:1 10-bit RGB Packer"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, { - .id = AV_CODEC_ID_YLC, + .id = AV_CODEC_ID_012V, .type = AVMEDIA_TYPE_VIDEO, - .name = "ylc", - .long_name = NULL_IF_CONFIG_SMALL("YUY2 Lossless Codec"), + .name = "012v", + .long_name = NULL_IF_CONFIG_SMALL("Uncompressed 4:2:2 10-bit"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, { - .id = AV_CODEC_ID_PIXLET, - .type = AVMEDIA_TYPE_VIDEO, - .name = "pixlet", - .long_name = NULL_IF_CONFIG_SMALL("Apple Pixlet"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, - }, - { - .id = AV_CODEC_ID_FMVC, - .type = AVMEDIA_TYPE_VIDEO, - .name = "fmvc", - .long_name = NULL_IF_CONFIG_SMALL("FM Screen Capture Codec"), - .props = AV_CODEC_PROP_LOSSLESS, - }, - { - .id = AV_CODEC_ID_SCPR, - .type = AVMEDIA_TYPE_VIDEO, - .name = "scpr", - .long_name = NULL_IF_CONFIG_SMALL("ScreenPressor"), - .props = AV_CODEC_PROP_LOSSLESS | AV_CODEC_PROP_LOSSY, - }, - { - .id = AV_CODEC_ID_CLEARVIDEO, - .type = AVMEDIA_TYPE_VIDEO, - .name = "clearvideo", - .long_name = NULL_IF_CONFIG_SMALL("Iterated Systems ClearVideo"), - .props = AV_CODEC_PROP_LOSSY, - }, - { - .id = AV_CODEC_ID_AV1, - .type = AVMEDIA_TYPE_VIDEO, - .name = "av1", - .long_name = NULL_IF_CONFIG_SMALL("Alliance for Open Media AV1"), - .props = AV_CODEC_PROP_LOSSY, - }, - { - .id = AV_CODEC_ID_BITPACKED, + .id = AV_CODEC_ID_AVUI, .type = AVMEDIA_TYPE_VIDEO, - .name = "bitpacked", - .long_name = NULL_IF_CONFIG_SMALL("Bitpacked"), + .name = "avui", + .long_name = NULL_IF_CONFIG_SMALL("Avid Meridien Uncompressed"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, { - .id = AV_CODEC_ID_MSCC, + .id = AV_CODEC_ID_AYUV, .type = AVMEDIA_TYPE_VIDEO, - .name = "mscc", - .long_name = NULL_IF_CONFIG_SMALL("Mandsoft Screen Capture Codec"), + .name = "ayuv", + .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed MS 4:4:4:4"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, { - .id = AV_CODEC_ID_SRGC, + .id = AV_CODEC_ID_TARGA_Y216, .type = AVMEDIA_TYPE_VIDEO, - .name = "srgc", - .long_name = NULL_IF_CONFIG_SMALL("Screen Recorder Gold Codec"), + .name = "targa_y216", + .long_name = NULL_IF_CONFIG_SMALL("Pinnacle TARGA CineWave YUV16"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, { - .id = AV_CODEC_ID_GDV, - .type = AVMEDIA_TYPE_VIDEO, - .name = "gdv", - .long_name = NULL_IF_CONFIG_SMALL("Gremlin Digital Video"), - .props = AV_CODEC_PROP_LOSSY, - }, - - /* image codecs */ - { - .id = AV_CODEC_ID_ALIAS_PIX, + .id = AV_CODEC_ID_V308, .type = AVMEDIA_TYPE_VIDEO, - .name = "alias_pix", - .long_name = NULL_IF_CONFIG_SMALL("Alias/Wavefront PIX image"), + .name = "v308", + .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed 4:4:4"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, { - .id = AV_CODEC_ID_ANSI, - .type = AVMEDIA_TYPE_VIDEO, - .name = "ansi", - .long_name = NULL_IF_CONFIG_SMALL("ASCII/ANSI art"), - .props = AV_CODEC_PROP_LOSSY, - }, - { - .id = AV_CODEC_ID_BRENDER_PIX, + .id = AV_CODEC_ID_V408, .type = AVMEDIA_TYPE_VIDEO, - .name = "brender_pix", - .long_name = NULL_IF_CONFIG_SMALL("BRender PIX image"), + .name = "v408", + .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed QT 4:4:4:4"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, { - .id = AV_CODEC_ID_DDS, + .id = AV_CODEC_ID_YUV4, .type = AVMEDIA_TYPE_VIDEO, - .name = "dds", - .long_name = NULL_IF_CONFIG_SMALL("DirectDraw Surface image decoder"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY | - AV_CODEC_PROP_LOSSLESS, + .name = "yuv4", + .long_name = NULL_IF_CONFIG_SMALL("Uncompressed packed 4:2:0"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, { - .id = AV_CODEC_ID_DPX, + .id = AV_CODEC_ID_AVRN, .type = AVMEDIA_TYPE_VIDEO, - .name = "dpx", - .long_name = NULL_IF_CONFIG_SMALL("DPX (Digital Picture Exchange) image"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + .name = "avrn", + .long_name = NULL_IF_CONFIG_SMALL("Avid AVI Codec"), }, { - .id = AV_CODEC_ID_EXR, + .id = AV_CODEC_ID_CPIA, .type = AVMEDIA_TYPE_VIDEO, - .name = "exr", - .long_name = NULL_IF_CONFIG_SMALL("OpenEXR image"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY | - AV_CODEC_PROP_LOSSLESS, + .name = "cpia", + .long_name = NULL_IF_CONFIG_SMALL("CPiA video format"), }, { - .id = AV_CODEC_ID_FITS, + .id = AV_CODEC_ID_XFACE, .type = AVMEDIA_TYPE_VIDEO, - .name = "fits", - .long_name = NULL_IF_CONFIG_SMALL("FITS (Flexible Image Transport System)"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + .name = "xface", + .long_name = NULL_IF_CONFIG_SMALL("X-face image"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, { - .id = AV_CODEC_ID_GIF, + .id = AV_CODEC_ID_SNOW, .type = AVMEDIA_TYPE_VIDEO, - .name = "gif", - .long_name = NULL_IF_CONFIG_SMALL("GIF (Graphics Interchange Format)"), - .props = AV_CODEC_PROP_LOSSLESS, - .mime_types= MT("image/gif"), + .name = "snow", + .long_name = NULL_IF_CONFIG_SMALL("Snow"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS, }, { - .id = AV_CODEC_ID_JPEGLS, + .id = AV_CODEC_ID_SMVJPEG, .type = AVMEDIA_TYPE_VIDEO, - .name = "jpegls", - .long_name = NULL_IF_CONFIG_SMALL("JPEG-LS"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY | - AV_CODEC_PROP_LOSSLESS, + .name = "smvjpeg", + .long_name = NULL_IF_CONFIG_SMALL("Sigmatel Motion Video"), }, { - .id = AV_CODEC_ID_LJPEG, + .id = AV_CODEC_ID_APNG, .type = AVMEDIA_TYPE_VIDEO, - .name = "ljpeg", - .long_name = NULL_IF_CONFIG_SMALL("Lossless JPEG"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + .name = "apng", + .long_name = NULL_IF_CONFIG_SMALL("APNG (Animated Portable Network Graphics) image"), + .props = AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/png"), }, { - .id = AV_CODEC_ID_PAM, + .id = AV_CODEC_ID_DAALA, .type = AVMEDIA_TYPE_VIDEO, - .name = "pam", - .long_name = NULL_IF_CONFIG_SMALL("PAM (Portable AnyMap) image"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, - .mime_types= MT("image/x-portable-pixmap"), + .name = "daala", + .long_name = NULL_IF_CONFIG_SMALL("Daala"), + .props = AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS, }, { - .id = AV_CODEC_ID_PBM, + .id = AV_CODEC_ID_CFHD, .type = AVMEDIA_TYPE_VIDEO, - .name = "pbm", - .long_name = NULL_IF_CONFIG_SMALL("PBM (Portable BitMap) image"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + .name = "cfhd", + .long_name = NULL_IF_CONFIG_SMALL("Cineform HD"), + .props = AV_CODEC_PROP_LOSSY, }, { - .id = AV_CODEC_ID_PCX, + .id = AV_CODEC_ID_TRUEMOTION2RT, .type = AVMEDIA_TYPE_VIDEO, - .name = "pcx", - .long_name = NULL_IF_CONFIG_SMALL("PC Paintbrush PCX image"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, - .mime_types= MT("image/x-pcx"), + .name = "truemotion2rt", + .long_name = NULL_IF_CONFIG_SMALL("Duck TrueMotion 2.0 Real Time"), + .props = AV_CODEC_PROP_LOSSY, }, { - .id = AV_CODEC_ID_PGM, + .id = AV_CODEC_ID_M101, .type = AVMEDIA_TYPE_VIDEO, - .name = "pgm", - .long_name = NULL_IF_CONFIG_SMALL("PGM (Portable GrayMap) image"), + .name = "m101", + .long_name = NULL_IF_CONFIG_SMALL("Matrox Uncompressed SD"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, { - .id = AV_CODEC_ID_PGMYUV, + .id = AV_CODEC_ID_MAGICYUV, .type = AVMEDIA_TYPE_VIDEO, - .name = "pgmyuv", - .long_name = NULL_IF_CONFIG_SMALL("PGMYUV (Portable GrayMap YUV) image"), + .name = "magicyuv", + .long_name = NULL_IF_CONFIG_SMALL("MagicYUV video"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, { - .id = AV_CODEC_ID_PNG, + .id = AV_CODEC_ID_SHEERVIDEO, .type = AVMEDIA_TYPE_VIDEO, - .name = "png", - .long_name = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"), - .props = AV_CODEC_PROP_LOSSLESS, - .mime_types= MT("image/png"), + .name = "sheervideo", + .long_name = NULL_IF_CONFIG_SMALL("BitJazz SheerVideo"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, { - .id = AV_CODEC_ID_PPM, + .id = AV_CODEC_ID_YLC, .type = AVMEDIA_TYPE_VIDEO, - .name = "ppm", - .long_name = NULL_IF_CONFIG_SMALL("PPM (Portable PixelMap) image"), + .name = "ylc", + .long_name = NULL_IF_CONFIG_SMALL("YUY2 Lossless Codec"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, { @@ -1553,117 +1554,98 @@ static const AVCodecDescriptor codec_descriptors[] = { .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, { - .id = AV_CODEC_ID_PTX, + .id = AV_CODEC_ID_PIXLET, .type = AVMEDIA_TYPE_VIDEO, - .name = "ptx", - .long_name = NULL_IF_CONFIG_SMALL("V.Flash PTX image"), + .name = "pixlet", + .long_name = NULL_IF_CONFIG_SMALL("Apple Pixlet"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, { - .id = AV_CODEC_ID_SGI, - .type = AVMEDIA_TYPE_VIDEO, - .name = "sgi", - .long_name = NULL_IF_CONFIG_SMALL("SGI image"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, - }, - { - .id = AV_CODEC_ID_SP5X, + .id = AV_CODEC_ID_SPEEDHQ, .type = AVMEDIA_TYPE_VIDEO, - .name = "sp5x", - .long_name = NULL_IF_CONFIG_SMALL("Sunplus JPEG (SP5X)"), + .name = "speedhq", + .long_name = NULL_IF_CONFIG_SMALL("NewTek SpeedHQ"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, }, { - .id = AV_CODEC_ID_SUNRAST, + .id = AV_CODEC_ID_FMVC, .type = AVMEDIA_TYPE_VIDEO, - .name = "sunrast", - .long_name = NULL_IF_CONFIG_SMALL("Sun Rasterfile image"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, + .name = "fmvc", + .long_name = NULL_IF_CONFIG_SMALL("FM Screen Capture Codec"), + .props = AV_CODEC_PROP_LOSSLESS, }, { - .id = AV_CODEC_ID_TARGA, + .id = AV_CODEC_ID_SCPR, .type = AVMEDIA_TYPE_VIDEO, - .name = "targa", - .long_name = NULL_IF_CONFIG_SMALL("Truevision Targa image"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, - .mime_types= MT("image/x-targa", "image/x-tga"), + .name = "scpr", + .long_name = NULL_IF_CONFIG_SMALL("ScreenPressor"), + .props = AV_CODEC_PROP_LOSSLESS | AV_CODEC_PROP_LOSSY, }, { - .id = AV_CODEC_ID_TDSC, + .id = AV_CODEC_ID_CLEARVIDEO, .type = AVMEDIA_TYPE_VIDEO, - .name = "tdsc", - .long_name = NULL_IF_CONFIG_SMALL("TDSC"), + .name = "clearvideo", + .long_name = NULL_IF_CONFIG_SMALL("Iterated Systems ClearVideo"), .props = AV_CODEC_PROP_LOSSY, }, { - .id = AV_CODEC_ID_TIFF, + .id = AV_CODEC_ID_XPM, .type = AVMEDIA_TYPE_VIDEO, - .name = "tiff", - .long_name = NULL_IF_CONFIG_SMALL("TIFF image"), + .name = "xpm", + .long_name = NULL_IF_CONFIG_SMALL("XPM (X PixMap) image"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, - .mime_types= MT("image/tiff"), - }, - { - .id = AV_CODEC_ID_TXD, - .type = AVMEDIA_TYPE_VIDEO, - .name = "txd", - .long_name = NULL_IF_CONFIG_SMALL("Renderware TXD (TeXture Dictionary) image"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY, + .mime_types= MT("image/x-xpixmap"), }, { - .id = AV_CODEC_ID_VC1IMAGE, + .id = AV_CODEC_ID_AV1, .type = AVMEDIA_TYPE_VIDEO, - .name = "vc1image", - .long_name = NULL_IF_CONFIG_SMALL("Windows Media Video 9 Image v2"), + .name = "av1", + .long_name = NULL_IF_CONFIG_SMALL("Alliance for Open Media AV1"), .props = AV_CODEC_PROP_LOSSY, + .profiles = NULL_IF_CONFIG_SMALL(ff_av1_profiles), }, { - .id = AV_CODEC_ID_WEBP, + .id = AV_CODEC_ID_BITPACKED, .type = AVMEDIA_TYPE_VIDEO, - .name = "webp", - .long_name = NULL_IF_CONFIG_SMALL("WebP"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY | - AV_CODEC_PROP_LOSSLESS, - .mime_types= MT("image/webp"), + .name = "bitpacked", + .long_name = NULL_IF_CONFIG_SMALL("Bitpacked"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, { - .id = AV_CODEC_ID_WMV3IMAGE, + .id = AV_CODEC_ID_MSCC, .type = AVMEDIA_TYPE_VIDEO, - .name = "wmv3image", - .long_name = NULL_IF_CONFIG_SMALL("Windows Media Video 9 Image"), - .props = AV_CODEC_PROP_LOSSY, + .name = "mscc", + .long_name = NULL_IF_CONFIG_SMALL("Mandsoft Screen Capture Codec"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, { - .id = AV_CODEC_ID_XBM, + .id = AV_CODEC_ID_SRGC, .type = AVMEDIA_TYPE_VIDEO, - .name = "xbm", - .long_name = NULL_IF_CONFIG_SMALL("XBM (X BitMap) image"), + .name = "srgc", + .long_name = NULL_IF_CONFIG_SMALL("Screen Recorder Gold Codec"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, - .mime_types= MT("image/x-xbitmap"), }, { - .id = AV_CODEC_ID_XPM, + .id = AV_CODEC_ID_SVG, .type = AVMEDIA_TYPE_VIDEO, - .name = "xpm", - .long_name = NULL_IF_CONFIG_SMALL("XPM (X PixMap) image"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, - .mime_types= MT("image/x-xpixmap"), + .name = "svg", + .long_name = NULL_IF_CONFIG_SMALL("Scalable Vector Graphics"), + .props = AV_CODEC_PROP_LOSSLESS, + .mime_types= MT("image/svg+xml"), }, { - .id = AV_CODEC_ID_XWD, + .id = AV_CODEC_ID_GDV, .type = AVMEDIA_TYPE_VIDEO, - .name = "xwd", - .long_name = NULL_IF_CONFIG_SMALL("XWD (X Window Dump) image"), - .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, - .mime_types= MT("image/x-xwindowdump"), + .name = "gdv", + .long_name = NULL_IF_CONFIG_SMALL("Gremlin Digital Video"), + .props = AV_CODEC_PROP_LOSSY, }, { - .id = AV_CODEC_ID_APNG, + .id = AV_CODEC_ID_FITS, .type = AVMEDIA_TYPE_VIDEO, - .name = "apng", - .long_name = NULL_IF_CONFIG_SMALL("APNG (Animated Portable Network Graphics) image"), - .props = AV_CODEC_PROP_LOSSLESS, - .mime_types= MT("image/png"), + .name = "fits", + .long_name = NULL_IF_CONFIG_SMALL("FITS (Flexible Image Transport System)"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, /* various PCM "codecs" */ @@ -1737,20 +1719,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("PCM signed 32-bit big-endian"), .props = AV_CODEC_PROP_LOSSLESS, }, - { - .id = AV_CODEC_ID_PCM_S64LE, - .type = AVMEDIA_TYPE_AUDIO, - .name = "pcm_s64le", - .long_name = NULL_IF_CONFIG_SMALL("PCM signed 64-bit little-endian"), - .props = AV_CODEC_PROP_LOSSLESS, - }, - { - .id = AV_CODEC_ID_PCM_S64BE, - .type = AVMEDIA_TYPE_AUDIO, - .name = "pcm_s64be", - .long_name = NULL_IF_CONFIG_SMALL("PCM signed 64-bit big-endian"), - .props = AV_CODEC_PROP_LOSSLESS, - }, { .id = AV_CODEC_ID_PCM_U32LE, .type = AVMEDIA_TYPE_AUDIO, @@ -1807,13 +1775,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("PCM Zork"), .props = AV_CODEC_PROP_LOSSY, }, - { - .id = AV_CODEC_ID_PCM_S16BE_PLANAR, - .type = AVMEDIA_TYPE_AUDIO, - .name = "pcm_s16be_planar", - .long_name = NULL_IF_CONFIG_SMALL("PCM signed 16-bit big-endian planar"), - .props = AV_CODEC_PROP_LOSSLESS, - }, { .id = AV_CODEC_ID_PCM_S16LE_PLANAR, .type = AVMEDIA_TYPE_AUDIO, @@ -1821,20 +1782,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("PCM signed 16-bit little-endian planar"), .props = AV_CODEC_PROP_LOSSLESS, }, - { - .id = AV_CODEC_ID_PCM_S24LE_PLANAR, - .type = AVMEDIA_TYPE_AUDIO, - .name = "pcm_s24le_planar", - .long_name = NULL_IF_CONFIG_SMALL("PCM signed 24-bit little-endian planar"), - .props = AV_CODEC_PROP_LOSSLESS, - }, - { - .id = AV_CODEC_ID_PCM_S32LE_PLANAR, - .type = AVMEDIA_TYPE_AUDIO, - .name = "pcm_s32le_planar", - .long_name = NULL_IF_CONFIG_SMALL("PCM signed 32-bit little-endian planar"), - .props = AV_CODEC_PROP_LOSSLESS, - }, { .id = AV_CODEC_ID_PCM_DVD, .type = AVMEDIA_TYPE_AUDIO, @@ -1842,20 +1789,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("PCM signed 20|24-bit big-endian"), .props = AV_CODEC_PROP_LOSSLESS, }, - { - .id = AV_CODEC_ID_PCM_F16LE, - .type = AVMEDIA_TYPE_AUDIO, - .name = "pcm_f16le", - .long_name = NULL_IF_CONFIG_SMALL("PCM 16.8 floating point little-endian"), - .props = AV_CODEC_PROP_LOSSLESS, - }, - { - .id = AV_CODEC_ID_PCM_F24LE, - .type = AVMEDIA_TYPE_AUDIO, - .name = "pcm_f24le", - .long_name = NULL_IF_CONFIG_SMALL("PCM 24.0 floating point little-endian"), - .props = AV_CODEC_PROP_LOSSLESS, - }, { .id = AV_CODEC_ID_PCM_F32BE, .type = AVMEDIA_TYPE_AUDIO, @@ -1892,24 +1825,73 @@ static const AVCodecDescriptor codec_descriptors[] = { .props = AV_CODEC_PROP_LOSSLESS, }, { - .id = AV_CODEC_ID_PCM_LXF, + .id = AV_CODEC_ID_PCM_LXF, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_lxf", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 20-bit little-endian planar"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_S302M, + .type = AVMEDIA_TYPE_AUDIO, + .name = "s302m", + .long_name = NULL_IF_CONFIG_SMALL("SMPTE 302M"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_S8_PLANAR, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_s8_planar", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 8-bit planar"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_S24LE_PLANAR, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_s24le_planar", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 24-bit little-endian planar"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_S32LE_PLANAR, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_s32le_planar", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 32-bit little-endian planar"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_S16BE_PLANAR, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_s16be_planar", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 16-bit big-endian planar"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_S64LE, + .type = AVMEDIA_TYPE_AUDIO, + .name = "pcm_s64le", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 64-bit little-endian"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_PCM_S64BE, .type = AVMEDIA_TYPE_AUDIO, - .name = "pcm_lxf", - .long_name = NULL_IF_CONFIG_SMALL("PCM signed 20-bit little-endian planar"), + .name = "pcm_s64be", + .long_name = NULL_IF_CONFIG_SMALL("PCM signed 64-bit big-endian"), .props = AV_CODEC_PROP_LOSSLESS, }, { - .id = AV_CODEC_ID_S302M, + .id = AV_CODEC_ID_PCM_F16LE, .type = AVMEDIA_TYPE_AUDIO, - .name = "s302m", - .long_name = NULL_IF_CONFIG_SMALL("SMPTE 302M"), + .name = "pcm_f16le", + .long_name = NULL_IF_CONFIG_SMALL("PCM 16.8 floating point little-endian"), .props = AV_CODEC_PROP_LOSSLESS, }, { - .id = AV_CODEC_ID_PCM_S8_PLANAR, + .id = AV_CODEC_ID_PCM_F24LE, .type = AVMEDIA_TYPE_AUDIO, - .name = "pcm_s8_planar", - .long_name = NULL_IF_CONFIG_SMALL("PCM signed 8-bit planar"), + .name = "pcm_f24le", + .long_name = NULL_IF_CONFIG_SMALL("PCM 24.0 floating point little-endian"), .props = AV_CODEC_PROP_LOSSLESS, }, @@ -2047,13 +2029,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("ADPCM Nintendo THP"), .props = AV_CODEC_PROP_LOSSY, }, - { - .id = AV_CODEC_ID_ADPCM_THP_LE, - .type = AVMEDIA_TYPE_AUDIO, - .name = "adpcm_thp_le", - .long_name = NULL_IF_CONFIG_SMALL("ADPCM Nintendo THP (Little-Endian)"), - .props = AV_CODEC_PROP_LOSSY, - }, { .id = AV_CODEC_ID_ADPCM_IMA_AMV, .type = AVMEDIA_TYPE_AUDIO, @@ -2131,6 +2106,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA CRYO APC"), .props = AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_ADPCM_VIMA, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_vima", + .long_name = NULL_IF_CONFIG_SMALL("LucasArts VIMA audio"), + .props = AV_CODEC_PROP_LOSSY, + }, { .id = AV_CODEC_ID_ADPCM_AFC, .type = AVMEDIA_TYPE_AUDIO, @@ -2167,10 +2149,10 @@ static const AVCodecDescriptor codec_descriptors[] = { .props = AV_CODEC_PROP_LOSSY, }, { - .id = AV_CODEC_ID_ADPCM_VIMA, + .id = AV_CODEC_ID_ADPCM_THP_LE, .type = AVMEDIA_TYPE_AUDIO, - .name = "adpcm_vima", - .long_name = NULL_IF_CONFIG_SMALL("LucasArts VIMA audio"), + .name = "adpcm_thp_le", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Nintendo THP (Little-Endian)"), .props = AV_CODEC_PROP_LOSSY, }, { @@ -2194,6 +2176,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Eurocom DAT4"), .props = AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_ADPCM_MTAF, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_mtaf", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM MTAF"), + .props = AV_CODEC_PROP_LOSSY, + }, /* AMR */ { @@ -2499,15 +2488,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("ATRAC3 (Adaptive TRansform Acoustic Coding 3)"), .props = AV_CODEC_PROP_LOSSY, }, -#if FF_API_VOXWARE - { - .id = AV_CODEC_ID_VOXWARE, - .type = AVMEDIA_TYPE_AUDIO, - .name = "voxware", - .long_name = NULL_IF_CONFIG_SMALL("Voxware RT29 Metasound"), - .props = AV_CODEC_PROP_LOSSY, - }, -#endif { .id = AV_CODEC_ID_APE, .type = AVMEDIA_TYPE_AUDIO, @@ -2564,20 +2544,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("ATRAC3+ (Adaptive TRansform Acoustic Coding 3+)"), .props = AV_CODEC_PROP_LOSSY, }, - { - .id = AV_CODEC_ID_ATRAC3PAL, - .type = AVMEDIA_TYPE_AUDIO, - .name = "atrac3pal", - .long_name = NULL_IF_CONFIG_SMALL("ATRAC3+ AL (Adaptive TRansform Acoustic Coding 3+ Advanced Lossless)"), - .props = AV_CODEC_PROP_LOSSLESS, - }, - { - .id = AV_CODEC_ID_ATRAC3AL, - .type = AVMEDIA_TYPE_AUDIO, - .name = "atrac3al", - .long_name = NULL_IF_CONFIG_SMALL("ATRAC3 AL (Adaptive TRansform Acoustic Coding 3 Advanced Lossless)"), - .props = AV_CODEC_PROP_LOSSLESS, - }, { .id = AV_CODEC_ID_EAC3, .type = AVMEDIA_TYPE_AUDIO, @@ -2670,20 +2636,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("G.723.1"), .props = AV_CODEC_PROP_LOSSY, }, - { - .id = AV_CODEC_ID_DSS_SP, - .type = AVMEDIA_TYPE_AUDIO, - .name = "dss_sp", - .long_name = NULL_IF_CONFIG_SMALL("Digital Speech Standard - Standard Play mode (DSS SP)"), - .props = AV_CODEC_PROP_LOSSY, - }, - { - .id = AV_CODEC_ID_DOLBY_E, - .type = AVMEDIA_TYPE_AUDIO, - .name = "dolby_e", - .long_name = NULL_IF_CONFIG_SMALL("Dolby E"), - .props = AV_CODEC_PROP_LOSSY, - }, { .id = AV_CODEC_ID_G729, .type = AVMEDIA_TYPE_AUDIO, @@ -2733,24 +2685,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("iLBC (Internet Low Bitrate Codec)"), .props = AV_CODEC_PROP_LOSSY, }, - { - .id = AV_CODEC_ID_FFWAVESYNTH, - .type = AVMEDIA_TYPE_AUDIO, - .name = "wavesynth", - .long_name = NULL_IF_CONFIG_SMALL("Wave synthesis pseudo-codec"), - }, - { - .id = AV_CODEC_ID_SONIC, - .type = AVMEDIA_TYPE_AUDIO, - .name = "sonic", - .long_name = NULL_IF_CONFIG_SMALL("Sonic"), - }, - { - .id = AV_CODEC_ID_SONIC_LS, - .type = AVMEDIA_TYPE_AUDIO, - .name = "sonicls", - .long_name = NULL_IF_CONFIG_SMALL("Sonic lossless"), - }, { .id = AV_CODEC_ID_OPUS, .type = AVMEDIA_TYPE_AUDIO, @@ -2793,6 +2727,38 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("On2 Audio for Video Codec"), .props = AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_DSS_SP, + .type = AVMEDIA_TYPE_AUDIO, + .name = "dss_sp", + .long_name = NULL_IF_CONFIG_SMALL("Digital Speech Standard - Standard Play mode (DSS SP)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_CODEC2, + .type = AVMEDIA_TYPE_AUDIO, + .name = "codec2", + .long_name = NULL_IF_CONFIG_SMALL("codec2 (very low bitrate speech codec)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_FFWAVESYNTH, + .type = AVMEDIA_TYPE_AUDIO, + .name = "wavesynth", + .long_name = NULL_IF_CONFIG_SMALL("Wave synthesis pseudo-codec"), + }, + { + .id = AV_CODEC_ID_SONIC, + .type = AVMEDIA_TYPE_AUDIO, + .name = "sonic", + .long_name = NULL_IF_CONFIG_SMALL("Sonic"), + }, + { + .id = AV_CODEC_ID_SONIC_LS, + .type = AVMEDIA_TYPE_AUDIO, + .name = "sonicls", + .long_name = NULL_IF_CONFIG_SMALL("Sonic lossless"), + }, { .id = AV_CODEC_ID_EVRC, .type = AVMEDIA_TYPE_AUDIO, @@ -2807,13 +2773,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("SMV (Selectable Mode Vocoder)"), .props = AV_CODEC_PROP_LOSSY, }, - { - .id = AV_CODEC_ID_4GV, - .type = AVMEDIA_TYPE_AUDIO, - .name = "4gv", - .long_name = NULL_IF_CONFIG_SMALL("4GV (Fourth Generation Vocoder)"), - .props = AV_CODEC_PROP_LOSSY, - }, { .id = AV_CODEC_ID_DSD_LSBF, .type = AVMEDIA_TYPE_AUDIO, @@ -2842,6 +2801,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("DSD (Direct Stream Digital), most significant bit first, planar"), .props = AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_4GV, + .type = AVMEDIA_TYPE_AUDIO, + .name = "4gv", + .long_name = NULL_IF_CONFIG_SMALL("4GV (Fourth Generation Vocoder)"), + .props = AV_CODEC_PROP_LOSSY, + }, { .id = AV_CODEC_ID_INTERPLAY_ACM, .type = AVMEDIA_TYPE_AUDIO, @@ -2871,10 +2837,45 @@ static const AVCodecDescriptor codec_descriptors[] = { .props = AV_CODEC_PROP_LOSSLESS, }, { - .id = AV_CODEC_ID_ADPCM_MTAF, + .id = AV_CODEC_ID_ATRAC3AL, .type = AVMEDIA_TYPE_AUDIO, - .name = "adpcm_mtaf", - .long_name = NULL_IF_CONFIG_SMALL("ADPCM MTAF"), + .name = "atrac3al", + .long_name = NULL_IF_CONFIG_SMALL("ATRAC3 AL (Adaptive TRansform Acoustic Coding 3 Advanced Lossless)"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_ATRAC3PAL, + .type = AVMEDIA_TYPE_AUDIO, + .name = "atrac3pal", + .long_name = NULL_IF_CONFIG_SMALL("ATRAC3+ AL (Adaptive TRansform Acoustic Coding 3+ Advanced Lossless)"), + .props = AV_CODEC_PROP_LOSSLESS, + }, + { + .id = AV_CODEC_ID_DOLBY_E, + .type = AVMEDIA_TYPE_AUDIO, + .name = "dolby_e", + .long_name = NULL_IF_CONFIG_SMALL("Dolby E"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_APTX, + .type = AVMEDIA_TYPE_AUDIO, + .name = "aptx", + .long_name = NULL_IF_CONFIG_SMALL("aptX (Audio Processing Technology for Bluetooth)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_APTX_HD, + .type = AVMEDIA_TYPE_AUDIO, + .name = "aptx_hd", + .long_name = NULL_IF_CONFIG_SMALL("aptX HD (Audio Processing Technology for Bluetooth)"), + .props = AV_CODEC_PROP_LOSSY, + }, + { + .id = AV_CODEC_ID_SBC, + .type = AVMEDIA_TYPE_AUDIO, + .name = "sbc", + .long_name = NULL_IF_CONFIG_SMALL("SBC (low-complexity subband codec)"), .props = AV_CODEC_PROP_LOSSY, }, @@ -2907,13 +2908,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("XSUB"), .props = AV_CODEC_PROP_BITMAP_SUB, }, - { - .id = AV_CODEC_ID_ASS, - .type = AVMEDIA_TYPE_SUBTITLE, - .name = "ass", - .long_name = NULL_IF_CONFIG_SMALL("ASS (Advanced SSA) subtitle"), - .props = AV_CODEC_PROP_TEXT_SUB, - }, { .id = AV_CODEC_ID_SSA, .type = AVMEDIA_TYPE_SUBTITLE, @@ -2948,13 +2942,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle with embedded timing"), .props = AV_CODEC_PROP_TEXT_SUB, }, - { - .id = AV_CODEC_ID_SUBRIP, - .type = AVMEDIA_TYPE_SUBTITLE, - .name = "subrip", - .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"), - .props = AV_CODEC_PROP_TEXT_SUB, - }, { .id = AV_CODEC_ID_MICRODVD, .type = AVMEDIA_TYPE_SUBTITLE, @@ -2962,13 +2949,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("MicroDVD subtitle"), .props = AV_CODEC_PROP_TEXT_SUB, }, - { - .id = AV_CODEC_ID_MPL2, - .type = AVMEDIA_TYPE_SUBTITLE, - .name = "mpl2", - .long_name = NULL_IF_CONFIG_SMALL("MPL2 subtitle"), - .props = AV_CODEC_PROP_TEXT_SUB, - }, { .id = AV_CODEC_ID_EIA_608, .type = AVMEDIA_TYPE_SUBTITLE, @@ -2983,13 +2963,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("JACOsub subtitle"), .props = AV_CODEC_PROP_TEXT_SUB, }, - { - .id = AV_CODEC_ID_PJS, - .type = AVMEDIA_TYPE_SUBTITLE, - .name = "pjs", - .long_name = NULL_IF_CONFIG_SMALL("PJS (Phoenix Japanimation Society) subtitle"), - .props = AV_CODEC_PROP_TEXT_SUB, - }, { .id = AV_CODEC_ID_SAMI, .type = AVMEDIA_TYPE_SUBTITLE, @@ -3026,10 +2999,10 @@ static const AVCodecDescriptor codec_descriptors[] = { .props = AV_CODEC_PROP_TEXT_SUB, }, { - .id = AV_CODEC_ID_VPLAYER, + .id = AV_CODEC_ID_SUBRIP, .type = AVMEDIA_TYPE_SUBTITLE, - .name = "vplayer", - .long_name = NULL_IF_CONFIG_SMALL("VPlayer subtitle"), + .name = "subrip", + .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"), .props = AV_CODEC_PROP_TEXT_SUB, }, { @@ -3039,6 +3012,34 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("WebVTT subtitle"), .props = AV_CODEC_PROP_TEXT_SUB, }, + { + .id = AV_CODEC_ID_MPL2, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "mpl2", + .long_name = NULL_IF_CONFIG_SMALL("MPL2 subtitle"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_VPLAYER, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "vplayer", + .long_name = NULL_IF_CONFIG_SMALL("VPlayer subtitle"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_PJS, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "pjs", + .long_name = NULL_IF_CONFIG_SMALL("PJS (Phoenix Japanimation Society) subtitle"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, + { + .id = AV_CODEC_ID_ASS, + .type = AVMEDIA_TYPE_SUBTITLE, + .name = "ass", + .long_name = NULL_IF_CONFIG_SMALL("ASS (Advanced SSA) subtitle"), + .props = AV_CODEC_PROP_TEXT_SUB, + }, { .id = AV_CODEC_ID_HDMV_TEXT_SUBTITLE, .type = AVMEDIA_TYPE_SUBTITLE, @@ -3055,6 +3056,12 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("TrueType font"), .mime_types= MT("application/x-truetype-font", "application/x-font"), }, + { + .id = AV_CODEC_ID_SCTE_35, + .type = AVMEDIA_TYPE_DATA, + .name = "scte_35", + .long_name = NULL_IF_CONFIG_SMALL("SCTE 35 Message Queue"), + }, { .id = AV_CODEC_ID_BINTEXT, .type = AVMEDIA_TYPE_VIDEO, @@ -3109,23 +3116,26 @@ static const AVCodecDescriptor codec_descriptors[] = { .mime_types= MT("application/octet-stream"), }, { - .id = AV_CODEC_ID_SCTE_35, - .type = AVMEDIA_TYPE_DATA, - .name = "scte_35", - .long_name = NULL_IF_CONFIG_SMALL("SCTE 35 Message Queue"), + .id = AV_CODEC_ID_WRAPPED_AVFRAME, + .type = AVMEDIA_TYPE_VIDEO, + .name = "wrapped_avframe", + .long_name = NULL_IF_CONFIG_SMALL("AVFrame to AVPacket passthrough"), + .props = AV_CODEC_PROP_LOSSLESS, }, - - /* deprecated codec ids */ }; -const AVCodecDescriptor *avcodec_descriptor_get(enum AVCodecID id) +static int descriptor_compare(const void *key, const void *member) { - int i; + enum AVCodecID id = *(const enum AVCodecID *) key; + const AVCodecDescriptor *desc = member; - for (i = 0; i < FF_ARRAY_ELEMS(codec_descriptors); i++) - if (codec_descriptors[i].id == id) - return &codec_descriptors[i]; - return NULL; + return id - desc->id; +} + +const AVCodecDescriptor *avcodec_descriptor_get(enum AVCodecID id) +{ + return bsearch(&id, codec_descriptors, FF_ARRAY_ELEMS(codec_descriptors), + sizeof(codec_descriptors[0]), descriptor_compare); } const AVCodecDescriptor *avcodec_descriptor_next(const AVCodecDescriptor *prev) diff --git a/libavcodec/crystalhd.c b/libavcodec/crystalhd.c index 83bc8bf364107..e3c5955969e16 100644 --- a/libavcodec/crystalhd.c +++ b/libavcodec/crystalhd.c @@ -786,8 +786,9 @@ static int crystalhd_receive_frame(AVCodecContext *avctx, AVFrame *frame) .receive_frame = crystalhd_receive_frame, \ .flush = flush, \ .bsfs = bsf_name, \ - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \ + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \ .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUYV422, AV_PIX_FMT_NONE}, \ + .wrapper_name = "crystalhd", \ }; #if CONFIG_H264_CRYSTALHD_DECODER diff --git a/libavcodec/cscd.c b/libavcodec/cscd.c index 9e1dec9d967f7..35c4ee08c3528 100644 --- a/libavcodec/cscd.c +++ b/libavcodec/cscd.c @@ -81,15 +81,19 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, switch ((buf[0] >> 1) & 7) { case 0: { // lzo compression int outlen = c->decomp_size, inlen = buf_size - 2; - if (av_lzo1x_decode(c->decomp_buf, &outlen, &buf[2], &inlen)) + if (av_lzo1x_decode(c->decomp_buf, &outlen, &buf[2], &inlen)) { av_log(avctx, AV_LOG_ERROR, "error during lzo decompression\n"); + return AVERROR_INVALIDDATA; + } break; } case 1: { // zlib compression #if CONFIG_ZLIB unsigned long dlen = c->decomp_size; - if (uncompress(c->decomp_buf, &dlen, &buf[2], buf_size - 2) != Z_OK) + if (uncompress(c->decomp_buf, &dlen, &buf[2], buf_size - 2) != Z_OK) { av_log(avctx, AV_LOG_ERROR, "error during zlib decompression\n"); + return AVERROR_INVALIDDATA; + } break; #else av_log(avctx, AV_LOG_ERROR, "compiled without zlib support\n"); diff --git a/libavcodec/cuvid.c b/libavcodec/cuviddec.c similarity index 97% rename from libavcodec/cuvid.c rename to libavcodec/cuviddec.c index 2ba8e00c6af1f..122c28f6e87ef 100644 --- a/libavcodec/cuvid.c +++ b/libavcodec/cuviddec.c @@ -32,6 +32,7 @@ #include "avcodec.h" #include "decode.h" +#include "hwaccel.h" #include "internal.h" typedef struct CuvidContext @@ -73,6 +74,8 @@ typedef struct CuvidContext int internal_error; int decoder_flushing; + int *key_frame; + cudaVideoCodec codec_type; cudaVideoChromaFormat chroma_format; @@ -339,6 +342,8 @@ static int CUDAAPI cuvid_handle_picture_decode(void *opaque, CUVIDPICPARAMS* pic av_log(avctx, AV_LOG_TRACE, "pfnDecodePicture\n"); + ctx->key_frame[picparams->CurrPicIdx] = picparams->intra_pic_flag; + ctx->internal_error = CHECK_CU(ctx->cvdl->cuvidDecodePicture(ctx->cudecoder, picparams)); if (ctx->internal_error < 0) return 0; @@ -589,6 +594,7 @@ static int cuvid_output_frame(AVCodecContext *avctx, AVFrame *frame) goto error; } + frame->key_frame = ctx->key_frame[parsed_frame.dispinfo.picture_index]; frame->width = avctx->width; frame->height = avctx->height; if (avctx->pkt_timebase.num && avctx->pkt_timebase.den) @@ -692,6 +698,8 @@ static av_cold int cuvid_decode_end(AVCodecContext *avctx) av_buffer_unref(&ctx->hwframe); av_buffer_unref(&ctx->hwdevice); + av_freep(&ctx->key_frame); + cuvid_free_functions(&ctx->cvdl); return 0; @@ -835,7 +843,7 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx) goto error; } - ret = cuvid_load_functions(&ctx->cvdl); + ret = cuvid_load_functions(&ctx->cvdl, avctx); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Failed loading nvcuvid.\n"); goto error; @@ -976,6 +984,12 @@ static av_cold int cuvid_decode_init(AVCodecContext *avctx) FFMIN(sizeof(ctx->cuparse_ext.raw_seqhdr_data), avctx->extradata_size)); } + ctx->key_frame = av_mallocz(ctx->nb_surfaces * sizeof(int)); + if (!ctx->key_frame) { + ret = AVERROR(ENOMEM); + goto error; + } + ctx->cuparseinfo.ulMaxNumDecodeSurfaces = ctx->nb_surfaces; ctx->cuparseinfo.ulMaxDisplayDelay = 4; ctx->cuparseinfo.pUserData = avctx; @@ -1094,6 +1108,19 @@ static const AVOption options[] = { { NULL } }; +static const AVCodecHWConfigInternal *cuvid_hw_configs[] = { + &(const AVCodecHWConfigInternal) { + .public = { + .pix_fmt = AV_PIX_FMT_CUDA, + .methods = AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX | + AV_CODEC_HW_CONFIG_METHOD_INTERNAL, + .device_type = AV_HWDEVICE_TYPE_CUDA + }, + .hwaccel = NULL, + }, + NULL +}; + #define DEFINE_CUVID_CODEC(x, X) \ static const AVClass x##_cuvid_class = { \ .class_name = #x "_cuvid", \ @@ -1101,12 +1128,6 @@ static const AVOption options[] = { .option = options, \ .version = LIBAVUTIL_VERSION_INT, \ }; \ - AVHWAccel ff_##x##_cuvid_hwaccel = { \ - .name = #x "_cuvid", \ - .type = AVMEDIA_TYPE_VIDEO, \ - .id = AV_CODEC_ID_##X, \ - .pix_fmt = AV_PIX_FMT_CUDA, \ - }; \ AVCodec ff_##x##_cuvid_decoder = { \ .name = #x "_cuvid", \ .long_name = NULL_IF_CONFIG_SMALL("Nvidia CUVID " #X " decoder"), \ @@ -1119,12 +1140,14 @@ static const AVOption options[] = { .decode = cuvid_decode_frame, \ .receive_frame = cuvid_output_frame, \ .flush = cuvid_flush, \ - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, \ + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \ .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_CUDA, \ AV_PIX_FMT_NV12, \ AV_PIX_FMT_P010, \ AV_PIX_FMT_P016, \ AV_PIX_FMT_NONE }, \ + .hw_configs = cuvid_hw_configs, \ + .wrapper_name = "cuvid", \ }; #if CONFIG_HEVC_CUVID_DECODER diff --git a/libavcodec/dca.c b/libavcodec/dca.c index 307b21471e661..a0729e61abc55 100644 --- a/libavcodec/dca.c +++ b/libavcodec/dca.c @@ -146,12 +146,17 @@ int ff_dca_parse_core_frame_header(DCACoreFrameHeader *h, GetBitContext *gb) return 0; } -int avpriv_dca_parse_core_frame_header(DCACoreFrameHeader *h, uint8_t *buf, int size) +int avpriv_dca_parse_core_frame_header(DCACoreFrameHeader *h, const uint8_t *buf, int size) { GetBitContext gb; + int ret; - if (init_get_bits8(&gb, buf, size) < 0) - return DCA_PARSE_ERROR_INVALIDDATA; + ret = init_get_bits8(&gb, buf, size); + if (ret < 0) + return ret; - return ff_dca_parse_core_frame_header(h, &gb); + if (ff_dca_parse_core_frame_header(h, &gb) < 0) + return AVERROR_INVALIDDATA; + + return 0; } diff --git a/libavcodec/dca.h b/libavcodec/dca.h index 172c965b3b412..e96c589c02dfa 100644 --- a/libavcodec/dca.h +++ b/libavcodec/dca.h @@ -29,10 +29,10 @@ #include #include "libavutil/common.h" -#include "libavutil/internal.h" #include "libavutil/intreadwrite.h" #include "get_bits.h" +#include "internal.h" #define DCA_CORE_FRAME_HEADER_SIZE 18 @@ -46,7 +46,6 @@ enum DCAParseError { DCA_PARSE_ERROR_RESERVED_BIT = -7, DCA_PARSE_ERROR_LFE_FLAG = -8, DCA_PARSE_ERROR_PCM_RES = -9, - DCA_PARSE_ERROR_INVALIDDATA = -10, }; typedef struct DCACoreFrameHeader { @@ -196,7 +195,7 @@ enum DCADownMixType { DCA_DMIX_TYPE_COUNT }; -extern av_export const uint32_t avpriv_dca_sample_rates[16]; +extern av_export_avcodec const uint32_t avpriv_dca_sample_rates[16]; extern const uint32_t ff_dca_sampling_freqs[16]; extern const uint8_t ff_dca_freq_ranges[16]; @@ -211,10 +210,19 @@ int avpriv_dca_convert_bitstream(const uint8_t *src, int src_size, uint8_t *dst, /** * Parse and validate core frame header - * @return 0 on success, negative DCA_PARSE_ERROR_ code on failure + * @param[out] h Pointer to struct where header info is written. + * @param[in] buf Pointer to the data buffer + * @param[in] size Size of the data buffer + * @return 0 on success, negative AVERROR code on failure */ -int avpriv_dca_parse_core_frame_header(DCACoreFrameHeader *h, uint8_t *buf, int size); +int avpriv_dca_parse_core_frame_header(DCACoreFrameHeader *h, const uint8_t *buf, int size); +/** + * Parse and validate core frame header + * @param[out] h Pointer to struct where header info is written. + * @param[in] gbc BitContext containing the first 120 bits of the frame. + * @return 0 on success, negative DCA_PARSE_ERROR_ code on failure + */ int ff_dca_parse_core_frame_header(DCACoreFrameHeader *h, GetBitContext *gb); #endif /* AVCODEC_DCA_H */ diff --git a/libavcodec/dca_core_bsf.c b/libavcodec/dca_core_bsf.c index 9edc0cfd61867..8565796951e16 100644 --- a/libavcodec/dca_core_bsf.c +++ b/libavcodec/dca_core_bsf.c @@ -24,18 +24,17 @@ #include "dca_syncwords.h" #include "libavutil/mem.h" -static int dca_core_filter(AVBSFContext *ctx, AVPacket *out) +static int dca_core_filter(AVBSFContext *ctx, AVPacket *pkt) { - AVPacket *in; GetByteContext gb; uint32_t syncword; int core_size = 0, ret; - ret = ff_bsf_get_packet(ctx, &in); + ret = ff_bsf_get_packet_ref(ctx, pkt); if (ret < 0) return ret; - bytestream2_init(&gb, in->data, in->size); + bytestream2_init(&gb, pkt->data, pkt->size); syncword = bytestream2_get_be32(&gb); bytestream2_skip(&gb, 1); @@ -45,11 +44,8 @@ static int dca_core_filter(AVBSFContext *ctx, AVPacket *out) break; } - av_packet_move_ref(out, in); - av_packet_free(&in); - - if (core_size > 0 && core_size <= out->size) { - out->size = core_size; + if (core_size > 0 && core_size <= pkt->size) { + pkt->size = core_size; } return 0; diff --git a/libavcodec/dcaenc.c b/libavcodec/dcaenc.c index dd601ffae0077..186997c6311d2 100644 --- a/libavcodec/dcaenc.c +++ b/libavcodec/dcaenc.c @@ -21,6 +21,9 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#define FFT_FLOAT 0 +#define FFT_FIXED_32 1 + #include "libavutil/avassert.h" #include "libavutil/channel_layout.h" #include "libavutil/common.h" @@ -33,6 +36,7 @@ #include "dca_core.h" #include "dcadata.h" #include "dcaenc.h" +#include "fft.h" #include "internal.h" #include "mathops.h" #include "put_bits.h" @@ -48,6 +52,8 @@ #define SUBBAND_SAMPLES (SUBFRAMES * SUBSUBFRAMES * 8) #define AUBANDS 25 +#define COS_T(x) (c->cos_table[(x) & 2047]) + typedef struct CompressionOptions { int adpcm_mode; } CompressionOptions; @@ -56,6 +62,7 @@ typedef struct DCAEncContext { AVClass *class; PutBitContext pb; DCAADPCMEncContext adpcm_ctx; + FFTContext mdct; CompressionOptions options; int frame_size; int frame_bits; @@ -92,15 +99,15 @@ typedef struct DCAEncContext { int32_t worst_noise_ever; int consumed_bits; int consumed_adpcm_bits; ///< Number of bits to transmit ADPCM related info -} DCAEncContext; -static int32_t cos_table[2048]; -static int32_t band_interpolation[2][512]; -static int32_t band_spectrum[2][8]; -static int32_t auf[9][AUBANDS][256]; -static int32_t cb_to_add[256]; -static int32_t cb_to_level[2048]; -static int32_t lfe_fir_64i[512]; + int32_t cos_table[2048]; + int32_t band_interpolation_tab[2][512]; + int32_t band_spectrum_tab[2][8]; + int32_t auf[9][AUBANDS][256]; + int32_t cb_to_add[256]; + int32_t cb_to_level[2048]; + int32_t lfe_fir_64i[512]; +} DCAEncContext; /* Transfer function of outer and middle ear, Hz -> dB */ static double hom(double f) @@ -153,15 +160,16 @@ static int encode_init(AVCodecContext *avctx) { DCAEncContext *c = avctx->priv_data; uint64_t layout = avctx->channel_layout; - int i, j, min_frame_bits; + int i, j, k, min_frame_bits; + int ret; if (subband_bufer_alloc(c)) return AVERROR(ENOMEM); c->fullband_channels = c->channels = avctx->channels; c->lfe_channel = (avctx->channels == 3 || avctx->channels == 6); - c->band_interpolation = band_interpolation[1]; - c->band_spectrum = band_spectrum[1]; + c->band_interpolation = c->band_interpolation_tab[1]; + c->band_spectrum = c->band_spectrum_tab[1]; c->worst_quantization_noise = -2047; c->worst_noise_ever = -2047; c->consumed_adpcm_bits = 0; @@ -231,91 +239,77 @@ static int encode_init(AVCodecContext *avctx) avctx->frame_size = 32 * SUBBAND_SAMPLES; - if (!cos_table[0]) { - int j, k; - - cos_table[0] = 0x7fffffff; - cos_table[512] = 0; - cos_table[1024] = -cos_table[0]; - for (i = 1; i < 512; i++) { - cos_table[i] = (int32_t)(0x7fffffff * cos(M_PI * i / 1024)); - cos_table[1024-i] = -cos_table[i]; - cos_table[1024+i] = -cos_table[i]; - cos_table[2048-i] = cos_table[i]; - } - for (i = 0; i < 2048; i++) { - cb_to_level[i] = (int32_t)(0x7fffffff * ff_exp10(-0.005 * i)); - } + if ((ret = ff_mdct_init(&c->mdct, 9, 0, 1.0)) < 0) + return ret; - for (k = 0; k < 32; k++) { - for (j = 0; j < 8; j++) { - lfe_fir_64i[64 * j + k] = (int32_t)(0xffffff800000ULL * ff_dca_lfe_fir_64[8 * k + j]); - lfe_fir_64i[64 * (7-j) + (63 - k)] = (int32_t)(0xffffff800000ULL * ff_dca_lfe_fir_64[8 * k + j]); - } - } + /* Init all tables */ + c->cos_table[0] = 0x7fffffff; + c->cos_table[512] = 0; + c->cos_table[1024] = -c->cos_table[0]; + for (i = 1; i < 512; i++) { + c->cos_table[i] = (int32_t)(0x7fffffff * cos(M_PI * i / 1024)); + c->cos_table[1024-i] = -c->cos_table[i]; + c->cos_table[1024+i] = -c->cos_table[i]; + c->cos_table[2048-i] = +c->cos_table[i]; + } - for (i = 0; i < 512; i++) { - band_interpolation[0][i] = (int32_t)(0x1000000000ULL * ff_dca_fir_32bands_perfect[i]); - band_interpolation[1][i] = (int32_t)(0x1000000000ULL * ff_dca_fir_32bands_nonperfect[i]); + for (i = 0; i < 2048; i++) + c->cb_to_level[i] = (int32_t)(0x7fffffff * ff_exp10(-0.005 * i)); + + for (k = 0; k < 32; k++) { + for (j = 0; j < 8; j++) { + c->lfe_fir_64i[64 * j + k] = (int32_t)(0xffffff800000ULL * ff_dca_lfe_fir_64[8 * k + j]); + c->lfe_fir_64i[64 * (7-j) + (63 - k)] = (int32_t)(0xffffff800000ULL * ff_dca_lfe_fir_64[8 * k + j]); } + } + + for (i = 0; i < 512; i++) { + c->band_interpolation_tab[0][i] = (int32_t)(0x1000000000ULL * ff_dca_fir_32bands_perfect[i]); + c->band_interpolation_tab[1][i] = (int32_t)(0x1000000000ULL * ff_dca_fir_32bands_nonperfect[i]); + } - for (i = 0; i < 9; i++) { - for (j = 0; j < AUBANDS; j++) { - for (k = 0; k < 256; k++) { - double freq = sample_rates[i] * (k + 0.5) / 512; + for (i = 0; i < 9; i++) { + for (j = 0; j < AUBANDS; j++) { + for (k = 0; k < 256; k++) { + double freq = sample_rates[i] * (k + 0.5) / 512; - auf[i][j][k] = (int32_t)(10 * (hom(freq) + gammafilter(j, freq))); - } + c->auf[i][j][k] = (int32_t)(10 * (hom(freq) + gammafilter(j, freq))); } } + } - for (i = 0; i < 256; i++) { - double add = 1 + ff_exp10(-0.01 * i); - cb_to_add[i] = (int32_t)(100 * log10(add)); - } - for (j = 0; j < 8; j++) { - double accum = 0; - for (i = 0; i < 512; i++) { - double reconst = ff_dca_fir_32bands_perfect[i] * ((i & 64) ? (-1) : 1); - accum += reconst * cos(2 * M_PI * (i + 0.5 - 256) * (j + 0.5) / 512); - } - band_spectrum[0][j] = (int32_t)(200 * log10(accum)); + for (i = 0; i < 256; i++) { + double add = 1 + ff_exp10(-0.01 * i); + c->cb_to_add[i] = (int32_t)(100 * log10(add)); + } + for (j = 0; j < 8; j++) { + double accum = 0; + for (i = 0; i < 512; i++) { + double reconst = ff_dca_fir_32bands_perfect[i] * ((i & 64) ? (-1) : 1); + accum += reconst * cos(2 * M_PI * (i + 0.5 - 256) * (j + 0.5) / 512); } - for (j = 0; j < 8; j++) { - double accum = 0; - for (i = 0; i < 512; i++) { - double reconst = ff_dca_fir_32bands_nonperfect[i] * ((i & 64) ? (-1) : 1); - accum += reconst * cos(2 * M_PI * (i + 0.5 - 256) * (j + 0.5) / 512); - } - band_spectrum[1][j] = (int32_t)(200 * log10(accum)); + c->band_spectrum_tab[0][j] = (int32_t)(200 * log10(accum)); + } + for (j = 0; j < 8; j++) { + double accum = 0; + for (i = 0; i < 512; i++) { + double reconst = ff_dca_fir_32bands_nonperfect[i] * ((i & 64) ? (-1) : 1); + accum += reconst * cos(2 * M_PI * (i + 0.5 - 256) * (j + 0.5) / 512); } + c->band_spectrum_tab[1][j] = (int32_t)(200 * log10(accum)); } - return 0; -} -static av_cold int encode_close(AVCodecContext *avctx) -{ - if (avctx->priv_data) { - DCAEncContext *c = avctx->priv_data; - subband_bufer_free(c); - ff_dcaadpcm_free(&c->adpcm_ctx); - } return 0; } -static inline int32_t cos_t(int x) -{ - return cos_table[x & 2047]; -} - -static inline int32_t sin_t(int x) +static av_cold int encode_close(AVCodecContext *avctx) { - return cos_t(x - 512); -} + DCAEncContext *c = avctx->priv_data; + ff_mdct_end(&c->mdct); + subband_bufer_free(c); + ff_dcaadpcm_free(&c->adpcm_ctx); -static inline int32_t half32(int32_t a) -{ - return (a + 1) >> 1; + return 0; } static void subband_transform(DCAEncContext *c, const int32_t *input) @@ -353,7 +347,7 @@ static void subband_transform(DCAEncContext *c, const int32_t *input) resp = 0; for (i = 16; i < 48; i++) { int s = (2 * band + 1) * (2 * (i + 16) + 1); - resp += mul32(accum[i], cos_t(s << 3)) >> 3; + resp += mul32(accum[i], COS_T(s << 3)) >> 3; } c->subband[ch][band][subs] = ((band + 1) & 2) ? -resp : resp; @@ -384,9 +378,9 @@ static void lfe_downsample(DCAEncContext *c, const int32_t *input) accum = 0; for (i = hist_start, j = 0; i < 512; i++, j++) - accum += mul32(hist[i], lfe_fir_64i[j]); + accum += mul32(hist[i], c->lfe_fir_64i[j]); for (i = 0; i < hist_start; i++, j++) - accum += mul32(hist[i], lfe_fir_64i[j]); + accum += mul32(hist[i], c->lfe_fir_64i[j]); c->downsampled_lfe[lfes] = accum; @@ -398,131 +392,72 @@ static void lfe_downsample(DCAEncContext *c, const int32_t *input) } } -typedef struct { - int32_t re; - int32_t im; -} cplx32; - -static void fft(const int32_t in[2 * 256], cplx32 out[256]) -{ - cplx32 buf[256], rin[256], rout[256]; - int i, j, k, l; - - /* do two transforms in parallel */ - for (i = 0; i < 256; i++) { - /* Apply the Hann window */ - rin[i].re = mul32(in[2 * i], 0x3fffffff - (cos_t(8 * i + 2) >> 1)); - rin[i].im = mul32(in[2 * i + 1], 0x3fffffff - (cos_t(8 * i + 6) >> 1)); - } - /* pre-rotation */ - for (i = 0; i < 256; i++) { - buf[i].re = mul32(cos_t(4 * i + 2), rin[i].re) - - mul32(sin_t(4 * i + 2), rin[i].im); - buf[i].im = mul32(cos_t(4 * i + 2), rin[i].im) - + mul32(sin_t(4 * i + 2), rin[i].re); - } - - for (j = 256, l = 1; j != 1; j >>= 1, l <<= 1) { - for (k = 0; k < 256; k += j) { - for (i = k; i < k + j / 2; i++) { - cplx32 sum, diff; - int t = 8 * l * i; - - sum.re = buf[i].re + buf[i + j / 2].re; - sum.im = buf[i].im + buf[i + j / 2].im; - - diff.re = buf[i].re - buf[i + j / 2].re; - diff.im = buf[i].im - buf[i + j / 2].im; - - buf[i].re = half32(sum.re); - buf[i].im = half32(sum.im); - - buf[i + j / 2].re = mul32(diff.re, cos_t(t)) - - mul32(diff.im, sin_t(t)); - buf[i + j / 2].im = mul32(diff.im, cos_t(t)) - + mul32(diff.re, sin_t(t)); - } - } - } - /* post-rotation */ - for (i = 0; i < 256; i++) { - int b = ff_reverse[i]; - rout[i].re = mul32(buf[b].re, cos_t(4 * i)) - - mul32(buf[b].im, sin_t(4 * i)); - rout[i].im = mul32(buf[b].im, cos_t(4 * i)) - + mul32(buf[b].re, sin_t(4 * i)); - } - for (i = 0; i < 256; i++) { - /* separate the results of the two transforms */ - cplx32 o1, o2; - - o1.re = rout[i].re - rout[255 - i].re; - o1.im = rout[i].im + rout[255 - i].im; - - o2.re = rout[i].im - rout[255 - i].im; - o2.im = -rout[i].re - rout[255 - i].re; - - /* combine them into one long transform */ - out[i].re = mul32( o1.re + o2.re, cos_t(2 * i + 1)) - + mul32( o1.im - o2.im, sin_t(2 * i + 1)); - out[i].im = mul32( o1.im + o2.im, cos_t(2 * i + 1)) - + mul32(-o1.re + o2.re, sin_t(2 * i + 1)); - } -} - -static int32_t get_cb(int32_t in) +static int32_t get_cb(DCAEncContext *c, int32_t in) { - int i, res; + int i, res = 0; + in = FFABS(in); - res = 0; - if (in < 0) - in = -in; for (i = 1024; i > 0; i >>= 1) { - if (cb_to_level[i + res] >= in) + if (c->cb_to_level[i + res] >= in) res += i; } return -res; } -static int32_t add_cb(int32_t a, int32_t b) +static int32_t add_cb(DCAEncContext *c, int32_t a, int32_t b) { if (a < b) FFSWAP(int32_t, a, b); if (a - b >= 256) return a; - return a + cb_to_add[a - b]; + return a + c->cb_to_add[a - b]; +} + +static void calc_power(DCAEncContext *c, + const int32_t in[2 * 256], int32_t power[256]) +{ + int i; + LOCAL_ALIGNED_32(int32_t, data, [512]); + LOCAL_ALIGNED_32(int32_t, coeff, [256]); + + for (i = 0; i < 512; i++) + data[i] = norm__(mul32(in[i], 0x3fffffff - (COS_T(4 * i + 2) >> 1)), 4); + + c->mdct.mdct_calc(&c->mdct, coeff, data); + for (i = 0; i < 256; i++) { + const int32_t cb = get_cb(c, coeff[i]); + power[i] = add_cb(c, cb, cb); + } } -static void adjust_jnd(int samplerate_index, +static void adjust_jnd(DCAEncContext *c, const int32_t in[512], int32_t out_cb[256]) { int32_t power[256]; - cplx32 out[256]; int32_t out_cb_unnorm[256]; int32_t denom; const int32_t ca_cb = -1114; const int32_t cs_cb = 928; + const int samplerate_index = c->samplerate_index; int i, j; - fft(in, out); + calc_power(c, in, power); - for (j = 0; j < 256; j++) { - power[j] = add_cb(get_cb(out[j].re), get_cb(out[j].im)); + for (j = 0; j < 256; j++) out_cb_unnorm[j] = -2047; /* and can only grow */ - } for (i = 0; i < AUBANDS; i++) { denom = ca_cb; /* and can only grow */ for (j = 0; j < 256; j++) - denom = add_cb(denom, power[j] + auf[samplerate_index][i][j]); + denom = add_cb(c, denom, power[j] + c->auf[samplerate_index][i][j]); for (j = 0; j < 256; j++) - out_cb_unnorm[j] = add_cb(out_cb_unnorm[j], - -denom + auf[samplerate_index][i][j]); + out_cb_unnorm[j] = add_cb(c, out_cb_unnorm[j], + -denom + c->auf[samplerate_index][i][j]); } for (j = 0; j < 256; j++) - out_cb[j] = add_cb(out_cb[j], -out_cb_unnorm[j] - ca_cb - cs_cb); + out_cb[j] = add_cb(c, out_cb[j], -out_cb_unnorm[j] - ca_cb - cs_cb); } typedef void (*walk_band_t)(DCAEncContext *c, int band1, int band2, int f, @@ -586,7 +521,7 @@ static void calc_masking(DCAEncContext *c, const int32_t *input) data[i] = c->history[ch][k]; for (k -= 512; i < 512; i++, k++) data[i] = input[k * c->channels + chi]; - adjust_jnd(c->samplerate_index, data, c->masking_curve_cb[ssf]); + adjust_jnd(c, data, c->masking_curve_cb[ssf]); } for (i = 0; i < 256; i++) { int32_t m = 2048; @@ -604,16 +539,16 @@ static void calc_masking(DCAEncContext *c, const int32_t *input) } } -static inline int32_t find_peak(const int32_t *in, int len) { +static inline int32_t find_peak(DCAEncContext *c, const int32_t *in, int len) +{ int sample; int32_t m = 0; for (sample = 0; sample < len; sample++) { int32_t s = abs(in[sample]); - if (m < s) { + if (m < s) m = s; - } } - return get_cb(m); + return get_cb(c, m); } static void find_peaks(DCAEncContext *c) @@ -621,14 +556,13 @@ static void find_peaks(DCAEncContext *c) int band, ch; for (ch = 0; ch < c->fullband_channels; ch++) { - for (band = 0; band < 32; band++) { - c->peak_cb[ch][band] = find_peak(c->subband[ch][band], SUBBAND_SAMPLES); - } + for (band = 0; band < 32; band++) + c->peak_cb[ch][band] = find_peak(c, c->subband[ch][band], + SUBBAND_SAMPLES); } - if (c->lfe_channel) { - c->lfe_peak_cb = find_peak(c->downsampled_lfe, DCA_LFE_SAMPLES); - } + if (c->lfe_channel) + c->lfe_peak_cb = find_peak(c, c->downsampled_lfe, DCA_LFE_SAMPLES); } static void adpcm_analysis(DCAEncContext *c) @@ -642,11 +576,12 @@ static void adpcm_analysis(DCAEncContext *c) for (ch = 0; ch < c->fullband_channels; ch++) { for (band = 0; band < 32; band++) { samples = c->subband[ch][band] - DCA_ADPCM_COEFFS; - pred_vq_id = ff_dcaadpcm_subband_analysis(&c->adpcm_ctx, samples, SUBBAND_SAMPLES, estimated_diff); + pred_vq_id = ff_dcaadpcm_subband_analysis(&c->adpcm_ctx, samples, + SUBBAND_SAMPLES, estimated_diff); if (pred_vq_id >= 0) { c->prediction_mode[ch][band] = pred_vq_id; c->consumed_adpcm_bits += 12; //12 bits to transmit prediction vq index - c->diff_peak_cb[ch][band] = find_peak(estimated_diff, 16); + c->diff_peak_cb[ch][band] = find_peak(c, estimated_diff, 16); } else { c->prediction_mode[ch][band] = -1; } @@ -658,7 +593,7 @@ static const int snr_fudge = 128; #define USED_1ABITS 1 #define USED_26ABITS 4 -static inline int32_t get_step_size(const DCAEncContext *c, int ch, int band) +static inline int32_t get_step_size(DCAEncContext *c, int ch, int band) { int32_t step_size; @@ -670,7 +605,8 @@ static inline int32_t get_step_size(const DCAEncContext *c, int ch, int band) return step_size; } -static int calc_one_scale(int32_t peak_cb, int abits, softfloat *quant) +static int calc_one_scale(DCAEncContext *c, int32_t peak_cb, int abits, + softfloat *quant) { int32_t peak; int our_nscale, try_remove; @@ -680,7 +616,7 @@ static int calc_one_scale(int32_t peak_cb, int abits, softfloat *quant) av_assert0(peak_cb >= -2047); our_nscale = 127; - peak = cb_to_level[-peak_cb]; + peak = c->cb_to_level[-peak_cb]; for (try_remove = 64; try_remove > 0; try_remove >>= 1) { if (scalefactor_inv[our_nscale - try_remove].e + stepsize_inv[abits].e <= 17) @@ -706,15 +642,17 @@ static inline void quantize_adpcm_subband(DCAEncContext *c, int ch, int band) { int32_t step_size; int32_t diff_peak_cb = c->diff_peak_cb[ch][band]; - c->scale_factor[ch][band] = calc_one_scale(diff_peak_cb, + c->scale_factor[ch][band] = calc_one_scale(c, diff_peak_cb, c->abits[ch][band], &c->quant[ch][band]); step_size = get_step_size(c, ch, band); ff_dcaadpcm_do_real(c->prediction_mode[ch][band], - c->quant[ch][band], ff_dca_scale_factor_quant7[c->scale_factor[ch][band]], step_size, - c->adpcm_history[ch][band], c->subband[ch][band], c->adpcm_history[ch][band]+4, c->quantized[ch][band], - SUBBAND_SAMPLES, cb_to_level[-diff_peak_cb]); + c->quant[ch][band], + ff_dca_scale_factor_quant7[c->scale_factor[ch][band]], + step_size, c->adpcm_history[ch][band], c->subband[ch][band], + c->adpcm_history[ch][band] + 4, c->quantized[ch][band], + SUBBAND_SAMPLES, c->cb_to_level[-diff_peak_cb]); } static void quantize_adpcm(DCAEncContext *c) @@ -731,21 +669,31 @@ static void quantize_pcm(DCAEncContext *c) { int sample, band, ch; - for (ch = 0; ch < c->fullband_channels; ch++) - for (band = 0; band < 32; band++) - if (c->prediction_mode[ch][band] == -1) - for (sample = 0; sample < SUBBAND_SAMPLES; sample++) - c->quantized[ch][band][sample] = quantize_value(c->subband[ch][band][sample], c->quant[ch][band]); + for (ch = 0; ch < c->fullband_channels; ch++) { + for (band = 0; band < 32; band++) { + if (c->prediction_mode[ch][band] == -1) { + for (sample = 0; sample < SUBBAND_SAMPLES; sample++) { + int32_t val = quantize_value(c->subband[ch][band][sample], + c->quant[ch][band]); + c->quantized[ch][band][sample] = val; + } + } + } + } } -static void accumulate_huff_bit_consumption(int abits, int32_t *quantized, uint32_t *result) +static void accumulate_huff_bit_consumption(int abits, int32_t *quantized, + uint32_t *result) { uint8_t sel, id = abits - 1; for (sel = 0; sel < ff_dca_quant_index_group_size[id]; sel++) - result[sel] += ff_dca_vlc_calc_quant_bits(quantized, SUBBAND_SAMPLES, sel, id); + result[sel] += ff_dca_vlc_calc_quant_bits(quantized, SUBBAND_SAMPLES, + sel, id); } -static uint32_t set_best_code(uint32_t vlc_bits[DCA_CODE_BOOKS][7], uint32_t clc_bits[DCA_CODE_BOOKS], int32_t res[DCA_CODE_BOOKS]) +static uint32_t set_best_code(uint32_t vlc_bits[DCA_CODE_BOOKS][7], + uint32_t clc_bits[DCA_CODE_BOOKS], + int32_t res[DCA_CODE_BOOKS]) { uint8_t i, sel; uint32_t best_sel_bits[DCA_CODE_BOOKS]; @@ -784,7 +732,8 @@ static uint32_t set_best_code(uint32_t vlc_bits[DCA_CODE_BOOKS][7], uint32_t clc return bits; } -static uint32_t set_best_abits_code(int abits[DCAENC_SUBBANDS], int bands, int32_t *res) +static uint32_t set_best_abits_code(int abits[DCAENC_SUBBANDS], int bands, + int32_t *res) { uint8_t i; uint32_t t; @@ -845,7 +794,8 @@ static int init_quantization_noise(DCAEncContext *c, int noise, int forbid_zero) ret &= ~(USED_26ABITS | USED_1ABITS); } } - c->consumed_bits += set_best_abits_code(c->abits[ch], 32, &c->bit_allocation_sel[ch]); + c->consumed_bits += set_best_abits_code(c->abits[ch], 32, + &c->bit_allocation_sel[ch]); } /* Recalc scale_factor each time to get bits consumption in case of Huffman coding. @@ -854,7 +804,7 @@ static int init_quantization_noise(DCAEncContext *c, int noise, int forbid_zero) for (ch = 0; ch < c->fullband_channels; ch++) { for (band = 0; band < 32; band++) { if (c->prediction_mode[ch][band] == -1) { - c->scale_factor[ch][band] = calc_one_scale(c->peak_cb[ch][band], + c->scale_factor[ch][band] = calc_one_scale(c, c->peak_cb[ch][band], c->abits[ch][band], &c->quant[ch][band]); } @@ -868,7 +818,9 @@ static int init_quantization_noise(DCAEncContext *c, int noise, int forbid_zero) for (ch = 0; ch < c->fullband_channels; ch++) { for (band = 0; band < 32; band++) { if (c->abits[ch][band] && c->abits[ch][band] <= DCA_CODE_BOOKS) { - accumulate_huff_bit_consumption(c->abits[ch][band], c->quantized[ch][band], huff_bit_count_accum[ch][c->abits[ch][band] - 1]); + accumulate_huff_bit_consumption(c->abits[ch][band], + c->quantized[ch][band], + huff_bit_count_accum[ch][c->abits[ch][band] - 1]); clc_bit_count_accum[ch][c->abits[ch][band] - 1] += bit_consumption[c->abits[ch][band]]; } else { bits_counter += bit_consumption[c->abits[ch][band]]; @@ -877,7 +829,9 @@ static int init_quantization_noise(DCAEncContext *c, int noise, int forbid_zero) } for (ch = 0; ch < c->fullband_channels; ch++) { - bits_counter += set_best_code(huff_bit_count_accum[ch], clc_bit_count_accum[ch], c->quant_index_sel[ch]); + bits_counter += set_best_code(huff_bit_count_accum[ch], + clc_bit_count_accum[ch], + c->quant_index_sel[ch]); } c->consumed_bits += bits_counter; @@ -954,7 +908,8 @@ static void fill_in_adpcm_bufer(DCAEncContext *c) step_size = get_step_size(c, ch, band); ff_dca_core_dequantize(c->adpcm_history[ch][band], - c->quantized[ch][band]+12, step_size, ff_dca_scale_factor_quant7[c->scale_factor[ch][band]], 0, 4); + c->quantized[ch][band]+12, step_size, + ff_dca_scale_factor_quant7[c->scale_factor[ch][band]], 0, 4); } else { AV_COPY128U(c->adpcm_history[ch][band], c->adpcm_history[ch][band]+4); } @@ -977,7 +932,7 @@ static void fill_in_adpcm_bufer(DCAEncContext *c) static void calc_lfe_scales(DCAEncContext *c) { if (c->lfe_channel) - c->lfe_scale_factor = calc_one_scale(c->lfe_peak_cb, 11, &c->lfe_quant); + c->lfe_scale_factor = calc_one_scale(c, c->lfe_peak_cb, 11, &c->lfe_quant); } static void put_frame_header(DCAEncContext *c) @@ -1118,7 +1073,8 @@ static void put_subframe_samples(DCAEncContext *c, int ss, int band, int ch) sel = c->quant_index_sel[ch][c->abits[ch][band] - 1]; // Huffman codes if (sel < ff_dca_quant_index_group_size[c->abits[ch][band] - 1]) { - ff_dca_vlc_enc_quant(&c->pb, &c->quantized[ch][band][ss * 8], 8, sel, c->abits[ch][band] - 1); + ff_dca_vlc_enc_quant(&c->pb, &c->quantized[ch][band][ss * 8], 8, + sel, c->abits[ch][band] - 1); return; } @@ -1171,7 +1127,8 @@ static void put_subframe(DCAEncContext *c, int subframe) put_bits(&c->pb, 5, c->abits[ch][band]); } } else { - ff_dca_vlc_enc_alloc(&c->pb, c->abits[ch], DCAENC_SUBBANDS, c->bit_allocation_sel[ch]); + ff_dca_vlc_enc_alloc(&c->pb, c->abits[ch], DCAENC_SUBBANDS, + c->bit_allocation_sel[ch]); } } @@ -1287,6 +1244,7 @@ AVCodec ff_dca_encoder = { .close = encode_close, .encode2 = encode_frame, .capabilities = AV_CODEC_CAP_EXPERIMENTAL, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_NONE }, .supported_samplerates = sample_rates, diff --git a/libavcodec/decode.c b/libavcodec/decode.c index 1337ffb5271b9..421a8f1a3570e 100644 --- a/libavcodec/decode.c +++ b/libavcodec/decode.c @@ -40,6 +40,7 @@ #include "avcodec.h" #include "bytestream.h" #include "decode.h" +#include "hwaccel.h" #include "internal.h" #include "thread.h" @@ -129,7 +130,7 @@ static int extract_packet_props(AVCodecInternal *avci, const AVPacket *pkt) if (pkt) { ret = av_packet_copy_props(avci->last_pkt_props, pkt); if (!ret) - avci->last_pkt_props->size = pkt->size; // HACK: Needed for ff_init_buffer_info(). + avci->last_pkt_props->size = pkt->size; // HACK: Needed for ff_decode_frame_props(). } return ret; } @@ -369,8 +370,7 @@ static int decode_simple_internal(AVCodecContext *avctx, AVFrame *frame) DecodeSimpleContext *ds = &avci->ds; AVPacket *pkt = ds->in_pkt; // copy to ensure we do not change pkt - AVPacket tmp; - int got_frame, actual_got_frame, did_split; + int got_frame, actual_got_frame; int ret; if (!pkt->data && !avci->draining) { @@ -390,31 +390,12 @@ static int decode_simple_internal(AVCodecContext *avctx, AVFrame *frame) avctx->active_thread_type & FF_THREAD_FRAME)) return AVERROR_EOF; - tmp = *pkt; -#if FF_API_MERGE_SD -FF_DISABLE_DEPRECATION_WARNINGS - did_split = avci->compat_decode_partial_size ? - ff_packet_split_and_drop_side_data(&tmp) : - av_packet_split_side_data(&tmp); - - if (did_split) { - ret = extract_packet_props(avctx->internal, &tmp); - if (ret < 0) - return ret; - - ret = apply_param_change(avctx, &tmp); - if (ret < 0) - return ret; - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif - got_frame = 0; if (HAVE_THREADS && avctx->active_thread_type & FF_THREAD_FRAME) { - ret = ff_thread_decode_frame(avctx, frame, &got_frame, &tmp); + ret = ff_thread_decode_frame(avctx, frame, &got_frame, pkt); } else { - ret = avctx->codec->decode(avctx, frame, &got_frame, &tmp); + ret = avctx->codec->decode(avctx, frame, &got_frame, pkt); if (!(avctx->codec->caps_internal & FF_CODEC_CAP_SETS_PKT_DTS)) frame->pkt_dts = pkt->dts; @@ -544,13 +525,6 @@ FF_ENABLE_DEPRECATION_WARNINGS } } } -#if FF_API_MERGE_SD - if (did_split) { - av_packet_free_side_data(&tmp); - if(ret == tmp.size) - ret = pkt->size; - } -#endif if (avctx->codec->type == AVMEDIA_TYPE_AUDIO && !avci->showed_multi_packet_warning && @@ -640,6 +614,28 @@ static int decode_receive_frame_internal(AVCodecContext *avctx, AVFrame *frame) if (ret == AVERROR_EOF) avci->draining_done = 1; + if (!ret) { + /* the only case where decode data is not set should be decoders + * that do not call ff_get_buffer() */ + av_assert0((frame->private_ref && frame->private_ref->size == sizeof(FrameDecodeData)) || + !(avctx->codec->capabilities & AV_CODEC_CAP_DR1)); + + if (frame->private_ref) { + FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data; + + if (fdd->post_process) { + ret = fdd->post_process(avctx, frame); + if (ret < 0) { + av_frame_unref(frame); + return ret; + } + } + } + } + + /* free the per-frame decode data */ + av_buffer_unref(&frame->private_ref); + return ret; } @@ -753,6 +749,11 @@ static int compat_decode(AVCodecContext *avctx, AVFrame *frame, av_assert0(avci->compat_decode_consumed == 0); + if (avci->draining_done && pkt && pkt->size != 0) { + av_log(avctx, AV_LOG_WARNING, "Got unexpected packet after EOF\n"); + avcodec_flush_buffers(avctx); + } + *got_frame = 0; avci->compat_decode = 1; @@ -999,7 +1000,6 @@ int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, AVPacket *avpkt) { int i, ret = 0; - AVCodecInternal *avci = avctx->internal; if (!avpkt->data && avpkt->size) { av_log(avctx, AV_LOG_ERROR, "invalid packet: NULL data, size != 0\n"); @@ -1016,29 +1016,9 @@ int avcodec_decode_subtitle2(AVCodecContext *avctx, AVSubtitle *sub, get_subtitle_defaults(sub); if ((avctx->codec->capabilities & AV_CODEC_CAP_DELAY) || avpkt->size) { - AVPacket pkt_recoded; - AVPacket tmp = *avpkt; -#if FF_API_MERGE_SD -FF_DISABLE_DEPRECATION_WARNINGS - int did_split = avci->compat_decode_partial_size ? - ff_packet_split_and_drop_side_data(&tmp) : - av_packet_split_side_data(&tmp); - //apply_param_change(avctx, &tmp); - - if (did_split) { - /* FFMIN() prevents overflow in case the packet wasn't allocated with - * proper padding. - * If the side data is smaller than the buffer padding size, the - * remaining bytes should have already been filled with zeros by the - * original packet allocation anyway. */ - memset(tmp.data + tmp.size, 0, - FFMIN(avpkt->size - tmp.size, AV_INPUT_BUFFER_PADDING_SIZE)); - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif + AVPacket pkt_recoded = *avpkt; - pkt_recoded = tmp; - ret = recode_subtitle(avctx, &pkt_recoded, &tmp); + ret = recode_subtitle(avctx, &pkt_recoded, avpkt); if (ret < 0) { *got_sub_ptr = 0; } else { @@ -1077,7 +1057,8 @@ FF_ENABLE_DEPRECATION_WARNINGS sub->format = 1; for (i = 0; i < sub->num_rects; i++) { - if (sub->rects[i]->ass && !utf8_check(sub->rects[i]->ass)) { + if (avctx->sub_charenc_mode != FF_SUB_CHARENC_MODE_IGNORE && + sub->rects[i]->ass && !utf8_check(sub->rects[i]->ass)) { av_log(avctx, AV_LOG_ERROR, "Invalid UTF-8 in decoded subtitles text; " "maybe missing -sub_charenc option\n"); @@ -1087,7 +1068,7 @@ FF_ENABLE_DEPRECATION_WARNINGS } } - if (tmp.data != pkt_recoded.data) { // did we recode? + if (avpkt->data != pkt_recoded.data) { // did we recode? /* prevent from destroying side data from original packet */ pkt_recoded.side_data = NULL; pkt_recoded.side_data_elems = 0; @@ -1096,14 +1077,6 @@ FF_ENABLE_DEPRECATION_WARNINGS } } -#if FF_API_MERGE_SD - if (did_split) { - av_packet_free_side_data(&tmp); - if(ret == tmp.size) - ret = avpkt->size; - } -#endif - if (*got_sub_ptr) avctx->frame_number++; } @@ -1111,84 +1084,238 @@ FF_ENABLE_DEPRECATION_WARNINGS return ret; } -static int is_hwaccel_pix_fmt(enum AVPixelFormat pix_fmt) +enum AVPixelFormat avcodec_default_get_format(struct AVCodecContext *avctx, + const enum AVPixelFormat *fmt) { - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); - return desc->flags & AV_PIX_FMT_FLAG_HWACCEL; -} + const AVPixFmtDescriptor *desc; + const AVCodecHWConfig *config; + int i, n; + + // If a device was supplied when the codec was opened, assume that the + // user wants to use it. + if (avctx->hw_device_ctx && avctx->codec->hw_configs) { + AVHWDeviceContext *device_ctx = + (AVHWDeviceContext*)avctx->hw_device_ctx->data; + for (i = 0;; i++) { + config = &avctx->codec->hw_configs[i]->public; + if (!config) + break; + if (!(config->methods & + AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX)) + continue; + if (device_ctx->type != config->device_type) + continue; + for (n = 0; fmt[n] != AV_PIX_FMT_NONE; n++) { + if (config->pix_fmt == fmt[n]) + return fmt[n]; + } + } + } + // No device or other setup, so we have to choose from things which + // don't any other external information. + + // If the last element of the list is a software format, choose it + // (this should be best software format if any exist). + for (n = 0; fmt[n] != AV_PIX_FMT_NONE; n++); + desc = av_pix_fmt_desc_get(fmt[n - 1]); + if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) + return fmt[n - 1]; + + // Finally, traverse the list in order and choose the first entry + // with no external dependencies (if there is no hardware configuration + // information available then this just picks the first entry). + for (n = 0; fmt[n] != AV_PIX_FMT_NONE; n++) { + for (i = 0;; i++) { + config = avcodec_get_hw_config(avctx->codec, i); + if (!config) + break; + if (config->pix_fmt == fmt[n]) + break; + } + if (!config) { + // No specific config available, so the decoder must be able + // to handle this format without any additional setup. + return fmt[n]; + } + if (config->methods & AV_CODEC_HW_CONFIG_METHOD_INTERNAL) { + // Usable with only internal setup. + return fmt[n]; + } + } -enum AVPixelFormat avcodec_default_get_format(struct AVCodecContext *s, const enum AVPixelFormat *fmt) -{ - while (*fmt != AV_PIX_FMT_NONE && is_hwaccel_pix_fmt(*fmt)) - ++fmt; - return fmt[0]; + // Nothing is usable, give up. + return AV_PIX_FMT_NONE; } -static AVHWAccel *find_hwaccel(enum AVCodecID codec_id, - enum AVPixelFormat pix_fmt) +int ff_decode_get_hw_frames_ctx(AVCodecContext *avctx, + enum AVHWDeviceType dev_type) { - AVHWAccel *hwaccel = NULL; + AVHWDeviceContext *device_ctx; + AVHWFramesContext *frames_ctx; + int ret; + + if (!avctx->hwaccel) + return AVERROR(ENOSYS); + + if (avctx->hw_frames_ctx) + return 0; + if (!avctx->hw_device_ctx) { + av_log(avctx, AV_LOG_ERROR, "A hardware frames or device context is " + "required for hardware accelerated decoding.\n"); + return AVERROR(EINVAL); + } + + device_ctx = (AVHWDeviceContext *)avctx->hw_device_ctx->data; + if (device_ctx->type != dev_type) { + av_log(avctx, AV_LOG_ERROR, "Device type %s expected for hardware " + "decoding, but got %s.\n", av_hwdevice_get_type_name(dev_type), + av_hwdevice_get_type_name(device_ctx->type)); + return AVERROR(EINVAL); + } + + ret = avcodec_get_hw_frames_parameters(avctx, + avctx->hw_device_ctx, + avctx->hwaccel->pix_fmt, + &avctx->hw_frames_ctx); + if (ret < 0) + return ret; + + frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; - while ((hwaccel = av_hwaccel_next(hwaccel))) - if (hwaccel->id == codec_id - && hwaccel->pix_fmt == pix_fmt) - return hwaccel; - return NULL; + + if (frames_ctx->initial_pool_size) { + // We guarantee 4 base work surfaces. The function above guarantees 1 + // (the absolute minimum), so add the missing count. + frames_ctx->initial_pool_size += 3; + } + + ret = av_hwframe_ctx_init(avctx->hw_frames_ctx); + if (ret < 0) { + av_buffer_unref(&avctx->hw_frames_ctx); + return ret; + } + + return 0; } -static int setup_hwaccel(AVCodecContext *avctx, - const enum AVPixelFormat fmt, - const char *name) +int avcodec_get_hw_frames_parameters(AVCodecContext *avctx, + AVBufferRef *device_ref, + enum AVPixelFormat hw_pix_fmt, + AVBufferRef **out_frames_ref) { - AVHWAccel *hwa = find_hwaccel(avctx->codec_id, fmt); - int ret = 0; + AVBufferRef *frames_ref = NULL; + const AVCodecHWConfigInternal *hw_config; + const AVHWAccel *hwa; + int i, ret; - if (!hwa) { - av_log(avctx, AV_LOG_ERROR, - "Could not find an AVHWAccel for the pixel format: %s", - name); + for (i = 0;; i++) { + hw_config = avctx->codec->hw_configs[i]; + if (!hw_config) + return AVERROR(ENOENT); + if (hw_config->public.pix_fmt == hw_pix_fmt) + break; + } + + hwa = hw_config->hwaccel; + if (!hwa || !hwa->frame_params) return AVERROR(ENOENT); + + frames_ref = av_hwframe_ctx_alloc(device_ref); + if (!frames_ref) + return AVERROR(ENOMEM); + + ret = hwa->frame_params(avctx, frames_ref); + if (ret >= 0) { + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)frames_ref->data; + + if (frames_ctx->initial_pool_size) { + // If the user has requested that extra output surfaces be + // available then add them here. + if (avctx->extra_hw_frames > 0) + frames_ctx->initial_pool_size += avctx->extra_hw_frames; + + // If frame threading is enabled then an extra surface per thread + // is also required. + if (avctx->active_thread_type & FF_THREAD_FRAME) + frames_ctx->initial_pool_size += avctx->thread_count; + } + + *out_frames_ref = frames_ref; + } else { + av_buffer_unref(&frames_ref); } + return ret; +} - if (hwa->capabilities & AV_HWACCEL_CODEC_CAP_EXPERIMENTAL && +static int hwaccel_init(AVCodecContext *avctx, + const AVCodecHWConfigInternal *hw_config) +{ + const AVHWAccel *hwaccel; + int err; + + hwaccel = hw_config->hwaccel; + if (hwaccel->capabilities & AV_HWACCEL_CODEC_CAP_EXPERIMENTAL && avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { av_log(avctx, AV_LOG_WARNING, "Ignoring experimental hwaccel: %s\n", - hwa->name); + hwaccel->name); return AVERROR_PATCHWELCOME; } - if (hwa->priv_data_size) { - avctx->internal->hwaccel_priv_data = av_mallocz(hwa->priv_data_size); + if (hwaccel->priv_data_size) { + avctx->internal->hwaccel_priv_data = + av_mallocz(hwaccel->priv_data_size); if (!avctx->internal->hwaccel_priv_data) return AVERROR(ENOMEM); } - avctx->hwaccel = hwa; - if (hwa->init) { - ret = hwa->init(avctx); - if (ret < 0) { + avctx->hwaccel = hwaccel; + if (hwaccel->init) { + err = hwaccel->init(avctx); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed setup for format %s: " + "hwaccel initialisation returned error.\n", + av_get_pix_fmt_name(hw_config->public.pix_fmt)); av_freep(&avctx->internal->hwaccel_priv_data); avctx->hwaccel = NULL; - return ret; + return err; } } return 0; } +static void hwaccel_uninit(AVCodecContext *avctx) +{ + if (avctx->hwaccel && avctx->hwaccel->uninit) + avctx->hwaccel->uninit(avctx); + + av_freep(&avctx->internal->hwaccel_priv_data); + + avctx->hwaccel = NULL; + + av_buffer_unref(&avctx->hw_frames_ctx); +} + int ff_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt) { const AVPixFmtDescriptor *desc; enum AVPixelFormat *choices; - enum AVPixelFormat ret; - unsigned n = 0; - - while (fmt[n] != AV_PIX_FMT_NONE) - ++n; - + enum AVPixelFormat ret, user_choice; + const AVCodecHWConfigInternal *hw_config; + const AVCodecHWConfig *config; + int i, n, err; + + // Find end of list. + for (n = 0; fmt[n] != AV_PIX_FMT_NONE; n++); + // Must contain at least one entry. av_assert0(n >= 1); - avctx->sw_pix_fmt = fmt[n - 1]; - av_assert2(!is_hwaccel_pix_fmt(avctx->sw_pix_fmt)); + // If a software format is available, it must be the last entry. + desc = av_pix_fmt_desc_get(fmt[n - 1]); + if (desc->flags & AV_PIX_FMT_FLAG_HWACCEL) { + // No software format is available. + } else { + avctx->sw_pix_fmt = fmt[n - 1]; + } choices = av_malloc_array(n + 1, sizeof(*choices)); if (!choices) @@ -1197,48 +1324,108 @@ int ff_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt) memcpy(choices, fmt, (n + 1) * sizeof(*choices)); for (;;) { - if (avctx->hwaccel && avctx->hwaccel->uninit) - avctx->hwaccel->uninit(avctx); - av_freep(&avctx->internal->hwaccel_priv_data); - avctx->hwaccel = NULL; + // Remove the previous hwaccel, if there was one. + hwaccel_uninit(avctx); - av_buffer_unref(&avctx->hw_frames_ctx); - - ret = avctx->get_format(avctx, choices); + user_choice = avctx->get_format(avctx, choices); + if (user_choice == AV_PIX_FMT_NONE) { + // Explicitly chose nothing, give up. + ret = AV_PIX_FMT_NONE; + break; + } - desc = av_pix_fmt_desc_get(ret); + desc = av_pix_fmt_desc_get(user_choice); if (!desc) { + av_log(avctx, AV_LOG_ERROR, "Invalid format returned by " + "get_format() callback.\n"); ret = AV_PIX_FMT_NONE; break; } + av_log(avctx, AV_LOG_DEBUG, "Format %s chosen by get_format().\n", + desc->name); - if (!(desc->flags & AV_PIX_FMT_FLAG_HWACCEL)) - break; -#if FF_API_CAP_VDPAU - if (avctx->codec->capabilities&AV_CODEC_CAP_HWACCEL_VDPAU) + for (i = 0; i < n; i++) { + if (choices[i] == user_choice) + break; + } + if (i == n) { + av_log(avctx, AV_LOG_ERROR, "Invalid return from get_format(): " + "%s not in possible list.\n", desc->name); break; -#endif + } - if (avctx->hw_frames_ctx) { - AVHWFramesContext *hw_frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; - if (hw_frames_ctx->format != ret) { - av_log(avctx, AV_LOG_ERROR, "Format returned from get_buffer() " - "does not match the format of provided AVHWFramesContext\n"); - ret = AV_PIX_FMT_NONE; - break; + if (avctx->codec->hw_configs) { + for (i = 0;; i++) { + hw_config = avctx->codec->hw_configs[i]; + if (!hw_config) + break; + if (hw_config->public.pix_fmt == user_choice) + break; } + } else { + hw_config = NULL; } - if (!setup_hwaccel(avctx, ret, desc->name)) + if (!hw_config) { + // No config available, so no extra setup required. + ret = user_choice; break; + } + config = &hw_config->public; + + if (config->methods & + AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX && + avctx->hw_frames_ctx) { + const AVHWFramesContext *frames_ctx = + (AVHWFramesContext*)avctx->hw_frames_ctx->data; + if (frames_ctx->format != user_choice) { + av_log(avctx, AV_LOG_ERROR, "Invalid setup for format %s: " + "does not match the format of the provided frames " + "context.\n", desc->name); + goto try_again; + } + } else if (config->methods & + AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX && + avctx->hw_device_ctx) { + const AVHWDeviceContext *device_ctx = + (AVHWDeviceContext*)avctx->hw_device_ctx->data; + if (device_ctx->type != config->device_type) { + av_log(avctx, AV_LOG_ERROR, "Invalid setup for format %s: " + "does not match the type of the provided device " + "context.\n", desc->name); + goto try_again; + } + } else if (config->methods & + AV_CODEC_HW_CONFIG_METHOD_INTERNAL) { + // Internal-only setup, no additional configuration. + } else if (config->methods & + AV_CODEC_HW_CONFIG_METHOD_AD_HOC) { + // Some ad-hoc configuration we can't see and can't check. + } else { + av_log(avctx, AV_LOG_ERROR, "Invalid setup for format %s: " + "missing configuration.\n", desc->name); + goto try_again; + } + if (hw_config->hwaccel) { + av_log(avctx, AV_LOG_DEBUG, "Format %s requires hwaccel " + "initialisation.\n", desc->name); + err = hwaccel_init(avctx, hw_config); + if (err < 0) + goto try_again; + } + ret = user_choice; + break; - /* Remove failed hwaccel from choices */ - for (n = 0; choices[n] != ret; n++) - av_assert0(choices[n] != AV_PIX_FMT_NONE); - - do - choices[n] = choices[n + 1]; - while (choices[n++] != AV_PIX_FMT_NONE); + try_again: + av_log(avctx, AV_LOG_DEBUG, "Format %s not usable, retrying " + "get_format() without it.\n", desc->name); + for (i = 0; i < n; i++) { + if (choices[i] == user_choice) + break; + } + for (; i + 1 < n; i++) + choices[i] = choices[i + 1]; + --n; } av_freep(&choices); @@ -1427,7 +1614,7 @@ static int video_get_buffer(AVCodecContext *s, AVFrame *pic) pic->linesize[i] = 0; } if (desc->flags & AV_PIX_FMT_FLAG_PAL || - desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) + ((desc->flags & FF_PSEUDOPAL) && pic->data[1])) avpriv_set_systematic_pal2((uint32_t *)pic->data[1], pic->format); if (s->debug & FF_DEBUG_BUFFERS) @@ -1475,7 +1662,7 @@ static int add_metadata_from_side_data(const AVPacket *avpkt, AVFrame *frame) return av_packet_unpack_dictionary(side_metadata, size, frame_md); } -int ff_init_buffer_info(AVCodecContext *avctx, AVFrame *frame) +int ff_decode_frame_props(AVCodecContext *avctx, AVFrame *frame) { const AVPacket *pkt = avctx->internal->last_pkt_props; int i; @@ -1583,11 +1770,6 @@ FF_ENABLE_DEPRECATION_WARNINGS return 0; } -int ff_decode_frame_props(AVCodecContext *avctx, AVFrame *frame) -{ - return ff_init_buffer_info(avctx, frame); -} - static void validate_avframe_allocation(AVCodecContext *avctx, AVFrame *frame) { if (avctx->codec_type == AVMEDIA_TYPE_VIDEO) { @@ -1597,12 +1779,11 @@ static void validate_avframe_allocation(AVCodecContext *avctx, AVFrame *frame) int flags = desc ? desc->flags : 0; if (num_planes == 1 && (flags & AV_PIX_FMT_FLAG_PAL)) num_planes = 2; + if ((flags & FF_PSEUDOPAL) && frame->data[1]) + num_planes = 2; for (i = 0; i < num_planes; i++) { av_assert0(frame->data[i]); } - // For now do not enforce anything for palette of pseudopal formats - if (num_planes == 1 && (flags & AV_PIX_FMT_FLAG_PSEUDOPAL)) - num_planes = 2; // For formats without data like hwaccel allow unused pointers to be non-NULL. for (i = num_planes; num_planes > 0 && i < FF_ARRAY_ELEMS(frame->data); i++) { if (frame->data[i]) @@ -1612,6 +1793,43 @@ static void validate_avframe_allocation(AVCodecContext *avctx, AVFrame *frame) } } +static void decode_data_free(void *opaque, uint8_t *data) +{ + FrameDecodeData *fdd = (FrameDecodeData*)data; + + if (fdd->post_process_opaque_free) + fdd->post_process_opaque_free(fdd->post_process_opaque); + + if (fdd->hwaccel_priv_free) + fdd->hwaccel_priv_free(fdd->hwaccel_priv); + + av_freep(&fdd); +} + +int ff_attach_decode_data(AVFrame *frame) +{ + AVBufferRef *fdd_buf; + FrameDecodeData *fdd; + + av_assert1(!frame->private_ref); + av_buffer_unref(&frame->private_ref); + + fdd = av_mallocz(sizeof(*fdd)); + if (!fdd) + return AVERROR(ENOMEM); + + fdd_buf = av_buffer_create((uint8_t*)fdd, sizeof(*fdd), decode_data_free, + NULL, AV_BUFFER_FLAG_READONLY); + if (!fdd_buf) { + av_freep(&fdd); + return AVERROR(ENOMEM); + } + + frame->private_ref = fdd_buf; + + return 0; +} + static int get_buffer_internal(AVCodecContext *avctx, AVFrame *frame, int flags) { const AVHWAccel *hwaccel = avctx->hwaccel; @@ -1648,8 +1866,14 @@ static int get_buffer_internal(AVCodecContext *avctx, AVFrame *frame, int flags) avctx->sw_pix_fmt = avctx->pix_fmt; ret = avctx->get_buffer2(avctx, frame, flags); - if (ret >= 0) - validate_avframe_allocation(avctx, frame); + if (ret < 0) + goto end; + + validate_avframe_allocation(avctx, frame); + + ret = ff_attach_decode_data(frame); + if (ret < 0) + goto end; end: if (avctx->codec_type == AVMEDIA_TYPE_VIDEO && !override_dimensions && @@ -1658,6 +1882,9 @@ static int get_buffer_internal(AVCodecContext *avctx, AVFrame *frame, int flags) frame->height = avctx->height; } + if (ret < 0) + av_frame_unref(frame); + return ret; } @@ -1684,8 +1911,6 @@ static int reget_buffer_internal(AVCodecContext *avctx, AVFrame *frame) av_frame_unref(frame); } - ff_init_buffer_info(avctx, frame); - if (!frame->data[0]) return ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF); diff --git a/libavcodec/decode.h b/libavcodec/decode.h index c9630228dc5fe..15271c529ab64 100644 --- a/libavcodec/decode.h +++ b/libavcodec/decode.h @@ -21,8 +21,38 @@ #ifndef AVCODEC_DECODE_H #define AVCODEC_DECODE_H +#include "libavutil/buffer.h" +#include "libavutil/frame.h" +#include "libavutil/hwcontext.h" + #include "avcodec.h" +/** + * This struct stores per-frame lavc-internal data and is attached to it via + * private_ref. + */ +typedef struct FrameDecodeData { + /** + * The callback to perform some delayed processing on the frame right + * before it is returned to the caller. + * + * @note This code is called at some unspecified point after the frame is + * returned from the decoder's decode/receive_frame call. Therefore it cannot rely + * on AVCodecContext being in any specific state, so it does not get to + * access AVCodecContext directly at all. All the state it needs must be + * stored in the post_process_opaque object. + */ + int (*post_process)(void *logctx, AVFrame *frame); + void *post_process_opaque; + void (*post_process_opaque_free)(void *opaque); + + /** + * Per-frame private data for hwaccels. + */ + void *hwaccel_priv; + void (*hwaccel_priv_free)(void *priv); +} FrameDecodeData; + /** * Called by decoders to get the next packet for decoding. * @@ -36,4 +66,14 @@ int ff_decode_get_packet(AVCodecContext *avctx, AVPacket *pkt); void ff_decode_bsfs_uninit(AVCodecContext *avctx); +/** + * Make sure avctx.hw_frames_ctx is set. If it's not set, the function will + * try to allocate it from hw_device_ctx. If that is not possible, an error + * message is printed, and an error code is returned. + */ +int ff_decode_get_hw_frames_ctx(AVCodecContext *avctx, + enum AVHWDeviceType dev_type); + +int ff_attach_decode_data(AVFrame *frame); + #endif /* AVCODEC_DECODE_H */ diff --git a/libavcodec/dfa.c b/libavcodec/dfa.c index 43dba2c8e966b..970175fb73468 100644 --- a/libavcodec/dfa.c +++ b/libavcodec/dfa.c @@ -41,7 +41,7 @@ static av_cold int dfa_decode_init(AVCodecContext *avctx) avctx->pix_fmt = AV_PIX_FMT_PAL8; - if (!avctx->width || !avctx->height) + if (!avctx->width || !avctx->height || FFMAX(avctx->width, avctx->height) >= (1<<16)) return AVERROR_INVALIDDATA; av_assert0(av_image_check_size(avctx->width, avctx->height, 0, avctx) >= 0); @@ -149,6 +149,8 @@ static int decode_dds1(GetByteContext *gb, uint8_t *frame, int width, int height int mask = 0x10000, bitbuf = 0; int i, v, offset, count, segments; + if ((width | height) & 1) + return AVERROR_INVALIDDATA; segments = bytestream2_get_le16(gb); while (segments--) { if (bytestream2_get_bytes_left(gb) < 2) @@ -176,7 +178,7 @@ static int decode_dds1(GetByteContext *gb, uint8_t *frame, int width, int height return AVERROR_INVALIDDATA; frame += v; } else { - if (frame_end - frame < width + 4) + if (width < 4 || frame_end - frame < width + 4) return AVERROR_INVALIDDATA; frame[0] = frame[1] = frame[width] = frame[width + 1] = bytestream2_get_byte(gb); diff --git a/libavcodec/dirac.c b/libavcodec/dirac.c index 027ce79a2e13a..d5870d6c00d5c 100644 --- a/libavcodec/dirac.c +++ b/libavcodec/dirac.c @@ -147,6 +147,7 @@ static int parse_source_parameters(AVDiracSeqHeader *dsh, GetBitContext *gb, unsigned luma_depth = 8, luma_offset = 16; int idx; int chroma_x_shift, chroma_y_shift; + int ret; /* [DIRAC_STD] 10.3.2 Frame size. frame_size(video_params) */ /* [DIRAC_STD] custom_dimensions_flag */ @@ -269,7 +270,10 @@ static int parse_source_parameters(AVDiracSeqHeader *dsh, GetBitContext *gb, return AVERROR_INVALIDDATA; dsh->pix_fmt = dirac_pix_fmt[dsh->chroma_format][dsh->pixel_range_index-2]; - avcodec_get_chroma_sub_sample(dsh->pix_fmt, &chroma_x_shift, &chroma_y_shift); + ret = av_pix_fmt_get_chroma_sub_sample(dsh->pix_fmt, &chroma_x_shift, &chroma_y_shift); + if (ret) + return ret; + if ((dsh->width % (1<height % (1<> 2)) + (b1 - (unsigned)((int)(b0 + (unsigned)(b2) + 2) >> 2)) #define COMPOSE_DIRAC53iH0(b0, b1, b2)\ - (b1 + ((int)(b0 + (unsigned)(b2) + 1) >> 1)) + (b1 + (unsigned)((int)(b0 + (unsigned)(b2) + 1) >> 1)) #define COMPOSE_DD97iH0(b0, b1, b2, b3, b4)\ - (b2 + ((int)(-b0 + 9U*b1 + 9U*b3 - b4 + 8) >> 4)) + (int)(((unsigned)(b2) + ((int)(-b0 + 9U*b1 + 9U*b3 - b4 + 8) >> 4))) #define COMPOSE_DD137iL0(b0, b1, b2, b3, b4)\ - (b2 - ((-b0 + 9*b1 + 9*b3 - b4 + 16) >> 5)) + (int)(((unsigned)(b2) - ((int)(-b0 + 9U*b1 + 9U*b3 - b4 + 16) >> 5))) #define COMPOSE_HAARiL0(b0, b1)\ - (b0 - ((b1 + 1) >> 1)) + ((int)(b0 - (unsigned)((int)(b1 + 1U) >> 1))) #define COMPOSE_HAARiH0(b0, b1)\ - (b0 + b1) + ((int)(b0 + (unsigned)(b1))) #define COMPOSE_FIDELITYiL0(b0, b1, b2, b3, b4, b5, b6, b7, b8)\ - (b4 - ((int)(-8*(b0+(unsigned)b8) + 21*(b1+(unsigned)b7) - 46*(b2+(unsigned)b6) + 161*(b3+(unsigned)b5) + 128) >> 8)) + ((unsigned)b4 - ((int)(-8*(b0+(unsigned)b8) + 21*(b1+(unsigned)b7) - 46*(b2+(unsigned)b6) + 161*(b3+(unsigned)b5) + 128) >> 8)) #define COMPOSE_FIDELITYiH0(b0, b1, b2, b3, b4, b5, b6, b7, b8)\ - (b4 + ((int)(-2*(b0+(unsigned)b8) + 10*(b1+(unsigned)b7) - 25*(b2+(unsigned)b6) + 81*(b3+(unsigned)b5) + 128) >> 8)) + ((unsigned)b4 + ((int)(-2*(b0+(unsigned)b8) + 10*(b1+(unsigned)b7) - 25*(b2+(unsigned)b6) + 81*(b3+(unsigned)b5) + 128) >> 8)) #define COMPOSE_DAUB97iL1(b0, b1, b2)\ - (b1 - ((int)(1817*(b0 + (unsigned)b2) + 2048) >> 12)) + ((unsigned)(b1) - ((int)(1817*(b0 + (unsigned)b2) + 2048) >> 12)) #define COMPOSE_DAUB97iH1(b0, b1, b2)\ - (b1 - ((int)( 113*(b0 + (unsigned)b2) + 64) >> 7)) + ((unsigned)(b1) - ((int)( 113*(b0 + (unsigned)b2) + 64) >> 7)) #define COMPOSE_DAUB97iL0(b0, b1, b2)\ - (b1 + ((int)( 217*(b0 + (unsigned)b2) + 2048) >> 12)) + ((unsigned)(b1) + ((int)( 217*(b0 + (unsigned)b2) + 2048) >> 12)) #define COMPOSE_DAUB97iH0(b0, b1, b2)\ - (b1 + ((int)(6497*(b0 + (unsigned)b2) + 2048) >> 12)) + ((unsigned)(b1) + ((int)(6497*(b0 + (unsigned)b2) + 2048) >> 12)) #endif /* AVCODEC_DWT_H */ diff --git a/libavcodec/dirac_dwt_template.c b/libavcodec/dirac_dwt_template.c index e436c247a1fd6..8c25c1f8228cd 100644 --- a/libavcodec/dirac_dwt_template.c +++ b/libavcodec/dirac_dwt_template.c @@ -49,7 +49,7 @@ static void RENAME(vertical_compose53iL0)(uint8_t *_b0, uint8_t *_b1, uint8_t *_ TYPE *b1 = (TYPE *)_b1; TYPE *b2 = (TYPE *)_b2; for (i = 0; i < width; i++) - b1[i] -= (int)(b0[i] + (unsigned)b2[i] + 2) >> 2; + b1[i] -= (unsigned)((int)(b0[i] + (unsigned)b2[i] + 2) >> 2); } static av_always_inline void RENAME(interleave)(TYPE *dst, TYPE *src0, TYPE *src1, int w2, @@ -95,8 +95,8 @@ static void RENAME(horizontal_compose_dd97i)(uint8_t *_b, uint8_t *_tmp, int w) tmp[w2+1] = tmp[w2] = tmp[w2-1]; for (x = 0; x < w2; x++) { - b[2*x ] = (tmp[x] + 1)>>1; - b[2*x+1] = (COMPOSE_DD97iH0(tmp[x-1], tmp[x], b[x+w2], tmp[x+1], tmp[x+2]) + 1)>>1; + b[2*x ] = ((int)(tmp[x] + 1U))>>1; + b[2*x+1] = ((int)(COMPOSE_DD97iH0(tmp[x-1], tmp[x], b[x+w2], tmp[x+1], tmp[x+2]) + 1U))>>1; } } @@ -118,8 +118,8 @@ static void RENAME(horizontal_compose_dd137i)(uint8_t *_b, uint8_t *_tmp, int w) tmp[w2+1] = tmp[w2] = tmp[w2-1]; for (x = 0; x < w2; x++) { - b[2*x ] = (tmp[x] + 1)>>1; - b[2*x+1] = (COMPOSE_DD97iH0(tmp[x-1], tmp[x], b[x+w2], tmp[x+1], tmp[x+2]) + 1)>>1; + b[2*x ] = ((int)(tmp[x] + 1U))>>1; + b[2*x+1] = ((int)(COMPOSE_DD97iH0(tmp[x-1], tmp[x], b[x+w2], tmp[x+1], tmp[x+2]) + 1U))>>1; } } diff --git a/libavcodec/diracdec.c b/libavcodec/diracdec.c index 0abb8b05990b2..753adeff61ce8 100644 --- a/libavcodec/diracdec.c +++ b/libavcodec/diracdec.c @@ -26,6 +26,7 @@ * @author Marco Gerards , David Conrad, Jordi Ortiz */ +#include "libavutil/pixdesc.h" #include "libavutil/thread.h" #include "avcodec.h" #include "get_bits.h" @@ -508,16 +509,16 @@ static inline void codeblock(DiracContext *s, SubBand *b, } if (s->codeblock_mode && !(s->old_delta_quant && blockcnt_one)) { - int quant = b->quant; + int quant; if (is_arith) - quant += dirac_get_arith_int(c, CTX_DELTA_Q_F, CTX_DELTA_Q_DATA); + quant = dirac_get_arith_int(c, CTX_DELTA_Q_F, CTX_DELTA_Q_DATA); else - quant += dirac_get_se_golomb(gb); - if (quant < 0) { + quant = dirac_get_se_golomb(gb); + if (quant > INT_MAX - b->quant || b->quant + quant < 0) { av_log(s->avctx, AV_LOG_ERROR, "Invalid quant\n"); return; } - b->quant = quant; + b->quant += quant; } if (b->quant > (DIRAC_MAX_QUANT_INDEX - 1)) { @@ -1398,8 +1399,8 @@ static void global_mv(DiracContext *s, DiracBlock *block, int x, int y, int ref) int *c = s->globalmc[ref].perspective; int m = (1<u.mv[ref][0] = (mx + (1<<(ez+ep))) >> (ez+ep); block->u.mv[ref][1] = (my + (1<<(ez+ep))) >> (ez+ep); @@ -1436,8 +1437,8 @@ static void decode_block_params(DiracContext *s, DiracArith arith[8], DiracBlock global_mv(s, block, x, y, i); } else { pred_mv(block, stride, x, y, i); - block->u.mv[i][0] += dirac_get_arith_int(arith + 4 + 2 * i, CTX_MV_F1, CTX_MV_DATA); - block->u.mv[i][1] += dirac_get_arith_int(arith + 5 + 2 * i, CTX_MV_F1, CTX_MV_DATA); + block->u.mv[i][0] += (unsigned)dirac_get_arith_int(arith + 4 + 2 * i, CTX_MV_F1, CTX_MV_DATA); + block->u.mv[i][1] += (unsigned)dirac_get_arith_int(arith + 5 + 2 * i, CTX_MV_F1, CTX_MV_DATA); } } } @@ -1927,7 +1928,10 @@ static int get_buffer_with_edge(AVCodecContext *avctx, AVFrame *f, int flags) { int ret, i; int chroma_x_shift, chroma_y_shift; - avcodec_get_chroma_sub_sample(avctx->pix_fmt, &chroma_x_shift, &chroma_y_shift); + ret = av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, &chroma_x_shift, + &chroma_y_shift); + if (ret < 0) + return ret; f->width = avctx->width + 2 * EDGE_WIDTH; f->height = avctx->height + 2 * EDGE_WIDTH + 2; @@ -2126,7 +2130,11 @@ static int dirac_decode_data_unit(AVCodecContext *avctx, const uint8_t *buf, int s->pshift = s->bit_depth > 8; - avcodec_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_x_shift, &s->chroma_y_shift); + ret = av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, + &s->chroma_x_shift, + &s->chroma_y_shift); + if (ret < 0) + return ret; ret = alloc_sequence_buffers(s); if (ret < 0) diff --git a/libavcodec/diracdsp.c b/libavcodec/diracdsp.c index 8bc79b788ce6c..2dd56f83f33ce 100644 --- a/libavcodec/diracdsp.c +++ b/libavcodec/diracdsp.c @@ -159,10 +159,10 @@ static void put_signed_rect_clamped_ ## PX ## bit_c(uint8_t *_dst, int dst_strid int32_t *src = (int32_t *)_src; \ for (y = 0; y < height; y++) { \ for (x = 0; x < width; x+=4) { \ - dst[x ] = av_clip_uintp2(src[x ] + (1 << (PX - 1)), PX); \ - dst[x+1] = av_clip_uintp2(src[x+1] + (1 << (PX - 1)), PX); \ - dst[x+2] = av_clip_uintp2(src[x+2] + (1 << (PX - 1)), PX); \ - dst[x+3] = av_clip_uintp2(src[x+3] + (1 << (PX - 1)), PX); \ + dst[x ] = av_clip_uintp2(src[x ] + (1U << (PX - 1)), PX); \ + dst[x+1] = av_clip_uintp2(src[x+1] + (1U << (PX - 1)), PX); \ + dst[x+2] = av_clip_uintp2(src[x+2] + (1U << (PX - 1)), PX); \ + dst[x+3] = av_clip_uintp2(src[x+3] + (1U << (PX - 1)), PX); \ } \ dst += dst_stride >> 1; \ src += src_stride >> 2; \ diff --git a/libavcodec/dnxhddata.c b/libavcodec/dnxhddata.c index 4462df3c2a603..e9dd29ce4c605 100644 --- a/libavcodec/dnxhddata.c +++ b/libavcodec/dnxhddata.c @@ -939,96 +939,84 @@ const CIDEntry ff_dnxhd_cid_table[] = { dnxhd_1235_dc_codes, dnxhd_1235_dc_bits, dnxhd_1235_ac_codes, dnxhd_1235_ac_bits, dnxhd_1235_ac_info, dnxhd_1235_run_codes, dnxhd_1235_run_bits, dnxhd_1235_run, - { 175, 185, 365, 440 }, - { { 24000, 1001 }, { 25, 1 }, { 50, 1 }, { 60000, 1001 } } }, + { 175, 185, 365, 440 } }, { 1237, 1920, 1080, 606208, 606208, 0, 4, 8, 3, dnxhd_1237_luma_weight, dnxhd_1237_chroma_weight, dnxhd_1237_dc_codes, dnxhd_1237_dc_bits, dnxhd_1237_ac_codes, dnxhd_1237_ac_bits, dnxhd_1237_ac_info, dnxhd_1237_run_codes, dnxhd_1237_run_bits, dnxhd_1237_run, - { 115, 120, 145, 240, 290 }, - { { 24000, 1001 }, { 25, 1 }, { 30000, 1001 }, { 50, 1 }, { 60000, 1001 } } }, + { 115, 120, 145, 240, 290 } }, { 1238, 1920, 1080, 917504, 917504, 0, 4, 8, 4, dnxhd_1238_luma_weight, dnxhd_1238_chroma_weight, dnxhd_1237_dc_codes, dnxhd_1237_dc_bits, dnxhd_1238_ac_codes, dnxhd_1238_ac_bits, dnxhd_1238_ac_info, dnxhd_1235_run_codes, dnxhd_1235_run_bits, dnxhd_1238_run, - { 175, 185, 220, 365, 440 }, - { { 24000, 1001 }, { 25, 1 }, { 30000, 1001 }, { 50, 1 }, { 60000, 1001 } } }, + { 175, 185, 220, 365, 440 } }, { 1241, 1920, 1080, 917504, 458752, DNXHD_INTERLACED, 6, 10, 4, dnxhd_1241_luma_weight, dnxhd_1241_chroma_weight, dnxhd_1235_dc_codes, dnxhd_1235_dc_bits, dnxhd_1235_ac_codes, dnxhd_1235_ac_bits, dnxhd_1235_ac_info, dnxhd_1235_run_codes, dnxhd_1235_run_bits, dnxhd_1235_run, - { 185, 220 }, - { { 25, 1 }, { 30000, 1001 } } }, + { 185, 220 } }, { 1242, 1920, 1080, 606208, 303104, DNXHD_INTERLACED, 4, 8, 3, dnxhd_1242_luma_weight, dnxhd_1242_chroma_weight, dnxhd_1237_dc_codes, dnxhd_1237_dc_bits, dnxhd_1237_ac_codes, dnxhd_1237_ac_bits, dnxhd_1237_ac_info, dnxhd_1237_run_codes, dnxhd_1237_run_bits, dnxhd_1237_run, - { 120, 145 }, - { { 25, 1 }, { 30000, 1001 } } }, + { 120, 145 } }, { 1243, 1920, 1080, 917504, 458752, DNXHD_INTERLACED, 4, 8, 4, dnxhd_1243_luma_weight, dnxhd_1243_chroma_weight, dnxhd_1237_dc_codes, dnxhd_1237_dc_bits, dnxhd_1238_ac_codes, dnxhd_1238_ac_bits, dnxhd_1238_ac_info, dnxhd_1235_run_codes, dnxhd_1235_run_bits, dnxhd_1238_run, - { 185, 220 }, - { { 25, 1 }, { 30000, 1001 } } }, + { 185, 220 } }, { 1244, 1440, 1080, 606208, 303104, DNXHD_INTERLACED, 4, 8, 3, dnxhd_1260_luma_weight, dnxhd_1260_chroma_weight, dnxhd_1237_dc_codes, dnxhd_1237_dc_bits, dnxhd_1237_ac_codes, dnxhd_1237_ac_bits, dnxhd_1237_ac_info, dnxhd_1237_run_codes, dnxhd_1237_run_bits, dnxhd_1237_run, - { 120, 145 }, - { { 25, 1 }, { 30000, 1001 } } }, + { 120, 145 } }, { 1250, 1280, 720, 458752, 458752, 0, 6, 10, 4, dnxhd_1250_luma_weight, dnxhd_1250_chroma_weight, dnxhd_1235_dc_codes, dnxhd_1235_dc_bits, dnxhd_1250_ac_codes, dnxhd_1250_ac_bits, dnxhd_1250_ac_info, dnxhd_1250_run_codes, dnxhd_1250_run_bits, dnxhd_1250_run, - { 90, 90, 180, 220 }, - { { 24000, 1001 }, { 25, 1 }, { 50, 1 }, { 60000, 1001 } } }, + { 90, 180, 220 } }, { 1251, 1280, 720, 458752, 458752, 0, 4, 8, 4, dnxhd_1251_luma_weight, dnxhd_1251_chroma_weight, dnxhd_1237_dc_codes, dnxhd_1237_dc_bits, dnxhd_1251_ac_codes, dnxhd_1251_ac_bits, dnxhd_1251_ac_info, dnxhd_1250_run_codes, dnxhd_1250_run_bits, dnxhd_1250_run, - { 90, 90, 110, 180, 220 }, - { { 24000, 1001 }, { 25, 1 }, { 30000, 1001 }, { 50, 1 }, { 60000, 1001 } } }, + { 90, 110, 180, 220 } }, { 1252, 1280, 720, 303104, 303104, 0, 4, 8, 5, dnxhd_1252_luma_weight, dnxhd_1252_chroma_weight, dnxhd_1237_dc_codes, dnxhd_1237_dc_bits, dnxhd_1252_ac_codes, dnxhd_1252_ac_bits, dnxhd_1252_ac_info, dnxhd_1250_run_codes, dnxhd_1250_run_bits, dnxhd_1250_run, - { 60, 60, 75, 120, 145 }, - { { 24000, 1001 }, { 25, 1 }, { 30000, 1001 }, { 50, 1 }, { 60000, 1001 } } }, + { 60, 75, 120, 145 } }, { 1253, 1920, 1080, 188416, 188416, 0, 4, 8, 3, dnxhd_1237_luma_weight, dnxhd_1237_chroma_weight, dnxhd_1237_dc_codes, dnxhd_1237_dc_bits, dnxhd_1237_ac_codes, dnxhd_1237_ac_bits, dnxhd_1237_ac_info, dnxhd_1237_run_codes, dnxhd_1237_run_bits, dnxhd_1237_run, - { 36, 36, 45, 75, 90 }, - { { 24000, 1001 }, { 25, 1 }, { 30000, 1001 }, { 50, 1 }, { 60000, 1001 } } }, + { 36, 45, 75, 90 } }, { 1256, 1920, 1080, 1835008, 1835008, DNXHD_444, 6, 10, 4, dnxhd_1235_luma_weight, dnxhd_1235_luma_weight, dnxhd_1235_dc_codes, dnxhd_1235_dc_bits, dnxhd_1235_ac_codes, dnxhd_1235_ac_bits, dnxhd_1235_ac_info, dnxhd_1235_run_codes, dnxhd_1235_run_bits, dnxhd_1235_run, - { 350, 390, 440, 730, 880 }, - { { 24000, 1001 }, { 25, 1 }, { 30000, 1001 }, { 50, 1 }, { 60000, 1001 } } }, + { 350, 390, 440, 730, 880 } }, { 1258, 960, 720, 212992, 212992, 0, 4, 8, 5, dnxhd_1252_luma_weight, dnxhd_1252_chroma_weight, @@ -1056,35 +1044,35 @@ const CIDEntry ff_dnxhd_cid_table[] = { dnxhd_1235_dc_codes, dnxhd_1235_dc_bits, dnxhd_1235_ac_codes, dnxhd_1235_ac_bits, dnxhd_1235_ac_info, dnxhd_1235_run_codes, dnxhd_1235_run_bits, dnxhd_1235_run, - { 0 }, { { 0 } }, { 57344, 255} }, + { 0 }, { 57344, 255} }, { 1271, DNXHD_VARIABLE, DNXHD_VARIABLE, DNXHD_VARIABLE, DNXHD_VARIABLE, 0, 6, DNXHD_VARIABLE, 4, dnxhd_1241_luma_weight, dnxhd_1241_chroma_weight, dnxhd_1235_dc_codes, dnxhd_1235_dc_bits, dnxhd_1235_ac_codes, dnxhd_1235_ac_bits, dnxhd_1235_ac_info, dnxhd_1235_run_codes, dnxhd_1235_run_bits, dnxhd_1235_run, - { 0 }, { { 0 } }, { 28672, 255} }, + { 0 }, { 28672, 255} }, { 1272, DNXHD_VARIABLE, DNXHD_VARIABLE, DNXHD_VARIABLE, DNXHD_VARIABLE, 0, 4, 8, 4, dnxhd_1238_luma_weight, dnxhd_1238_chroma_weight, dnxhd_1237_dc_codes, dnxhd_1237_dc_bits, dnxhd_1238_ac_codes, dnxhd_1238_ac_bits, dnxhd_1238_ac_info, dnxhd_1235_run_codes, dnxhd_1235_run_bits, dnxhd_1238_run, - { 0 }, { { 0 } }, { 28672, 255} }, + { 0 }, { 28672, 255} }, { 1273, DNXHD_VARIABLE, DNXHD_VARIABLE, DNXHD_VARIABLE, DNXHD_VARIABLE, 0, 4, 8, 3, dnxhd_1237_luma_weight, dnxhd_1237_chroma_weight, dnxhd_1237_dc_codes, dnxhd_1237_dc_bits, dnxhd_1237_ac_codes, dnxhd_1237_ac_bits, dnxhd_1237_ac_info, dnxhd_1237_run_codes, dnxhd_1237_run_bits, dnxhd_1237_run, - { 0 }, { { 0 } }, { 18944, 255} }, + { 0 }, { 18944, 255} }, { 1274, DNXHD_VARIABLE, DNXHD_VARIABLE, DNXHD_VARIABLE, DNXHD_VARIABLE, 0, 4, 8, 3, dnxhd_1237_luma_weight, dnxhd_1237_chroma_weight, dnxhd_1237_dc_codes, dnxhd_1237_dc_bits, dnxhd_1237_ac_codes, dnxhd_1237_ac_bits, dnxhd_1237_ac_info, dnxhd_1237_run_codes, dnxhd_1237_run_bits, dnxhd_1237_run, - { 0 }, { { 0 } }, { 5888, 255} }, + { 0 }, { 5888, 255} }, }; int ff_dnxhd_get_cid_table(int cid) @@ -1112,13 +1100,6 @@ int avpriv_dnxhd_get_interlaced(int cid) return ff_dnxhd_cid_table[i].flags & DNXHD_INTERLACED ? 1 : 0; } -#if LIBAVCODEC_VERSION_MAJOR < 58 -uint64_t avpriv_dnxhd_parse_header_prefix(const uint8_t *buf) -{ - return ff_dnxhd_parse_header_prefix(buf); -} -#endif - static int dnxhd_find_hr_cid(AVCodecContext *avctx) { switch (avctx->profile) { @@ -1175,9 +1156,9 @@ void ff_dnxhd_print_profiles(AVCodecContext *avctx, int loglevel) if (!cid->bit_rates[j]) break; - av_log(avctx, loglevel, "Frame size: %dx%d%c; bitrate: %dMbps; pixel format: %s; framerate: %d/%d\n", + av_log(avctx, loglevel, "Frame size: %dx%d%c; bitrate: %dMbps; pixel format: %s\n", cid->width, cid->height, cid->flags & DNXHD_INTERLACED ? 'i' : 'p', cid->bit_rates[j], - cid->bit_depth == 10 ? "yuv422p10" : "yuv422p", cid->frame_rates[j].num, cid->frame_rates[j].den); + cid->flags & DNXHD_444 ? "yuv444p10, gbrp10" : cid->bit_depth == 10 ? "yuv422p10" : "yuv422p"); } } } diff --git a/libavcodec/dnxhddata.h b/libavcodec/dnxhddata.h index c96c5e8f65aa8..f80ce18f3c43d 100644 --- a/libavcodec/dnxhddata.h +++ b/libavcodec/dnxhddata.h @@ -55,7 +55,6 @@ typedef struct CIDEntry { const uint16_t *run_codes; const uint8_t *run_bits, *run; int bit_rates[5]; ///< Helper to choose variants, rounded to nearest 5Mb/s - AVRational frame_rates[5]; AVRational packet_scale; } CIDEntry; @@ -106,8 +105,5 @@ static av_always_inline int ff_dnxhd_get_hr_frame_size(int cid, int w, int h) int avpriv_dnxhd_get_frame_size(int cid); int avpriv_dnxhd_get_interlaced(int cid); -#if LIBAVCODEC_VERSION_MAJOR < 58 -attribute_deprecated -uint64_t avpriv_dnxhd_parse_header_prefix(const uint8_t *buf); -#endif + #endif /* AVCODEC_DNXHDDATA_H */ diff --git a/libavcodec/dnxhddec.c b/libavcodec/dnxhddec.c index f46e41a456239..11d0bf424aae4 100644 --- a/libavcodec/dnxhddec.c +++ b/libavcodec/dnxhddec.c @@ -93,7 +93,9 @@ static av_cold int dnxhd_decode_init(AVCodecContext *avctx) ctx->avctx = avctx; ctx->cid = -1; - avctx->colorspace = AVCOL_SPC_BT709; + if (avctx->colorspace == AVCOL_SPC_UNSPECIFIED) { + avctx->colorspace = AVCOL_SPC_BT709; + } avctx->coded_width = FFALIGN(avctx->width, 16); avctx->coded_height = FFALIGN(avctx->height, 16); @@ -381,6 +383,10 @@ static av_always_inline int dnxhd_decode_dct_block(const DNXHDContext *ctx, UPDATE_CACHE(bs, &row->gb); GET_VLC(len, bs, &row->gb, ctx->dc_vlc.table, DNXHD_DC_VLC_BITS, 1); + if (len < 0) { + ret = len; + goto error; + } if (len) { level = GET_CACHE(bs, &row->gb); LAST_SKIP_BITS(bs, &row->gb, len); @@ -434,7 +440,7 @@ static av_always_inline int dnxhd_decode_dct_block(const DNXHDContext *ctx, GET_VLC(index1, bs, &row->gb, ctx->ac_vlc.table, DNXHD_VLC_BITS, 2); } - +error: CLOSE_READER(bs, &row->gb); return ret; } diff --git a/libavcodec/dnxhdenc.c b/libavcodec/dnxhdenc.c index 0d80381a2da85..86e71ca8b034d 100644 --- a/libavcodec/dnxhdenc.c +++ b/libavcodec/dnxhdenc.c @@ -490,12 +490,6 @@ static av_cold int dnxhd_encode_init(AVCodecContext *avctx) else ctx->data_offset = 0x280; -#if FF_API_QUANT_BIAS -FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->intra_quant_bias != FF_DEFAULT_QUANT_BIAS) - ctx->intra_quant_bias = avctx->intra_quant_bias; -FF_ENABLE_DEPRECATION_WARNINGS -#endif // XXX tune lbias/cbias if ((ret = dnxhd_init_qmat(ctx, ctx->intra_quant_bias, 0)) < 0) return ret; diff --git a/libavcodec/dpx.c b/libavcodec/dpx.c index 1aa2cbd1c8aca..026fb10e902b0 100644 --- a/libavcodec/dpx.c +++ b/libavcodec/dpx.c @@ -65,6 +65,38 @@ static uint16_t read10in32(const uint8_t **ptr, uint32_t * lbuf, return *lbuf & 0x3FF; } +static uint16_t read12in32(const uint8_t **ptr, uint32_t * lbuf, + int * n_datum, int is_big) +{ + if (*n_datum) + (*n_datum)--; + else { + *lbuf = read32(ptr, is_big); + *n_datum = 7; + } + + switch (*n_datum){ + case 7: return *lbuf & 0xFFF; + case 6: return (*lbuf >> 12) & 0xFFF; + case 5: { + uint32_t c = *lbuf >> 24; + *lbuf = read32(ptr, is_big); + c |= *lbuf << 8; + return c & 0xFFF; + } + case 4: return (*lbuf >> 4) & 0xFFF; + case 3: return (*lbuf >> 16) & 0xFFF; + case 2: { + uint32_t c = *lbuf >> 28; + *lbuf = read32(ptr, is_big); + c |= *lbuf << 4; + return c & 0xFFF; + } + case 1: return (*lbuf >> 8) & 0xFFF; + default: return *lbuf >> 20; + } +} + static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, @@ -201,10 +233,27 @@ static int decode_frame(AVCodecContext *avctx, break; case 12: if (!packing) { - av_log(avctx, AV_LOG_ERROR, "Packing to 16bit required\n"); - return -1; + int tested = 0; + if (descriptor == 50 && endian && (avctx->width%8) == 0) { // Little endian and widths not a multiple of 8 need tests + tested = 1; + } + if (!tested) { + av_log(avctx, AV_LOG_ERROR, "Packing to 16bit required\n"); + return -1; + } + } + stride = avctx->width * elements; + if (packing) { + stride *= 2; + } else { + stride *= 3; + if (stride % 8) { + stride /= 8; + stride++; + stride *= 8; + } + stride /= 2; } - stride = 2 * avctx->width * elements; break; case 16: stride = 2 * avctx->width * elements; @@ -349,6 +398,7 @@ static int decode_frame(AVCodecContext *avctx, (uint16_t*)ptr[2], (uint16_t*)ptr[3]}; for (y = 0; y < avctx->width; y++) { + if (packing) { if (elements >= 3) *dst[2]++ = read16(&buf, endian) >> 4; *dst[0] = read16(&buf, endian) >> 4; @@ -357,6 +407,17 @@ static int decode_frame(AVCodecContext *avctx, *dst[1]++ = read16(&buf, endian) >> 4; if (elements == 4) *dst[3]++ = read16(&buf, endian) >> 4; + } else { + *dst[2]++ = read12in32(&buf, &rgbBuffer, + &n_datum, endian); + *dst[0]++ = read12in32(&buf, &rgbBuffer, + &n_datum, endian); + *dst[1]++ = read12in32(&buf, &rgbBuffer, + &n_datum, endian); + if (elements == 4) + *dst[3]++ = read12in32(&buf, &rgbBuffer, + &n_datum, endian); + } } for (i = 0; i < elements; i++) ptr[i] += p->linesize[i]; diff --git a/libavcodec/dsicinvideo.c b/libavcodec/dsicinvideo.c index f95cbc74a0743..aa080417d25f1 100644 --- a/libavcodec/dsicinvideo.c +++ b/libavcodec/dsicinvideo.c @@ -158,6 +158,9 @@ static int cin_decode_lzss(const unsigned char *src, int src_size, } } + if (dst_end - dst > dst_size - dst_size/10) + return AVERROR_INVALIDDATA; + return 0; } @@ -184,6 +187,10 @@ static int cin_decode_rle(const unsigned char *src, int src_size, } dst += len; } + + if (dst_end - dst > dst_size - dst_size/10) + return AVERROR_INVALIDDATA; + return 0; } @@ -226,27 +233,35 @@ static int cinvideo_decode_frame(AVCodecContext *avctx, * surface.width = surface.pitch */ switch (bitmap_frame_type) { case 9: - cin_decode_rle(buf, bitmap_frame_size, + res = cin_decode_rle(buf, bitmap_frame_size, cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); + if (res < 0) + return res; break; case 34: - cin_decode_rle(buf, bitmap_frame_size, + res = cin_decode_rle(buf, bitmap_frame_size, cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); + if (res < 0) + return res; cin_apply_delta_data(cin->bitmap_table[CIN_PRE_BMP], cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); break; case 35: bitmap_frame_size = cin_decode_huffman(buf, bitmap_frame_size, cin->bitmap_table[CIN_INT_BMP], cin->bitmap_size); - cin_decode_rle(cin->bitmap_table[CIN_INT_BMP], bitmap_frame_size, + res = cin_decode_rle(cin->bitmap_table[CIN_INT_BMP], bitmap_frame_size, cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); + if (res < 0) + return res; break; case 36: bitmap_frame_size = cin_decode_huffman(buf, bitmap_frame_size, cin->bitmap_table[CIN_INT_BMP], cin->bitmap_size); - cin_decode_rle(cin->bitmap_table[CIN_INT_BMP], bitmap_frame_size, + res = cin_decode_rle(cin->bitmap_table[CIN_INT_BMP], bitmap_frame_size, cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); + if (res < 0) + return res; cin_apply_delta_data(cin->bitmap_table[CIN_PRE_BMP], cin->bitmap_table[CIN_CUR_BMP], cin->bitmap_size); break; diff --git a/libavcodec/dump_extradata_bsf.c b/libavcodec/dump_extradata_bsf.c index fa7bc86e1911c..98703749f7570 100644 --- a/libavcodec/dump_extradata_bsf.c +++ b/libavcodec/dump_extradata_bsf.c @@ -78,13 +78,14 @@ static int dump_extradata(AVBSFContext *ctx, AVPacket *out) } #define OFFSET(x) offsetof(DumpExtradataContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM) static const AVOption options[] = { { "freq", "When do dump extradata", OFFSET(freq), AV_OPT_TYPE_INT, - { .i64 = DUMP_FREQ_KEYFRAME }, DUMP_FREQ_KEYFRAME, DUMP_FREQ_ALL, 0, "freq" }, - { "k", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = DUMP_FREQ_KEYFRAME }, .unit = "freq" }, - { "keyframe", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = DUMP_FREQ_KEYFRAME }, .unit = "freq" }, - { "e", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = DUMP_FREQ_ALL }, .unit = "freq" }, - { "all", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = DUMP_FREQ_ALL }, .unit = "freq" }, + { .i64 = DUMP_FREQ_KEYFRAME }, DUMP_FREQ_KEYFRAME, DUMP_FREQ_ALL, FLAGS, "freq" }, + { "k", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = DUMP_FREQ_KEYFRAME }, .flags = FLAGS, .unit = "freq" }, + { "keyframe", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = DUMP_FREQ_KEYFRAME }, .flags = FLAGS, .unit = "freq" }, + { "e", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = DUMP_FREQ_ALL }, .flags = FLAGS, .unit = "freq" }, + { "all", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = DUMP_FREQ_ALL }, .flags = FLAGS, .unit = "freq" }, { NULL }, }; @@ -92,7 +93,7 @@ static const AVClass dump_extradata_class = { .class_name = "dump_extradata bsf", .item_name = av_default_item_name, .option = options, - .version = LIBAVUTIL_VERSION_MAJOR, + .version = LIBAVUTIL_VERSION_INT, }; const AVBitStreamFilter ff_dump_extradata_bsf = { diff --git a/libavcodec/dvbsub.c b/libavcodec/dvbsub.c index 3cdbade99c429..8cce702a9e002 100644 --- a/libavcodec/dvbsub.c +++ b/libavcodec/dvbsub.c @@ -239,9 +239,9 @@ static void dvb_encode_rle8(uint8_t **pq, x += len; } /* end of line */ - // 00000000 00000000 end of 8-bit/pixel_code_string - *q++ = 0x00; + // 00000000 end of 8-bit/pixel_code_string *q++ = 0x00; + *q++ = 0xf0; bitmap += linesize; } *pq = q; @@ -342,6 +342,9 @@ static int encode_dvb_subtitles(DVBSubtitleContext *s, } else if (h->rects[region_id]->nb_colors <= 16) { /* 4 bpp, standard encoding */ bpp_index = 1; + } else if (h->rects[region_id]->nb_colors <= 256) { + /* 8 bpp, standard encoding */ + bpp_index = 2; } else { return -1; } diff --git a/libavcodec/dvbsubdec.c b/libavcodec/dvbsubdec.c index b683109643cf9..a657b1d3d0f1b 100644 --- a/libavcodec/dvbsubdec.c +++ b/libavcodec/dvbsubdec.c @@ -96,6 +96,9 @@ typedef struct DVBSubRegion { int clut; int bgcolor; + uint8_t computed_clut[4*256]; + int has_computed_clut; + uint8_t *pbuf; int buf_size; int dirty; @@ -647,14 +650,14 @@ static int dvbsub_read_8bit_string(AVCodecContext *avctx, return pixels_read; } -static void compute_default_clut(AVSubtitleRect *rect, int w, int h) +static void compute_default_clut(uint8_t *clut, AVSubtitleRect *rect, int w, int h) { uint8_t list[256] = {0}; uint8_t list_inv[256]; int counttab[256] = {0}; int count, i, x, y; - -#define V(x,y) rect->data[0][(x) + (y)*rect->linesize[0]] + ptrdiff_t stride = rect->linesize[0]; +#define V(x,y) rect->data[0][(x) + (y)*stride] for (y = 0; ydata[0][(x) + (y)*rect->linesize[0]] ] +#define L(x,y) list[d[(x) + (y)*stride]] for (i = 0; i<256; i++) { int scoretab[256] = {0}; @@ -673,20 +676,24 @@ static void compute_default_clut(AVSubtitleRect *rect, int w, int h) int bestv = 0; for (y = 0; ydata[0][x + y*rect->linesize[0]]; + uint8_t *d = &rect->data[0][x + y*stride]; + int v = *d; int l_m = list[v]; - int l_l = x ? L(x-1, y) : 1; - int l_r = x+1 bestscore) { bestscore = score; - bestv = v; + bestv = x; } } } @@ -699,7 +706,7 @@ static void compute_default_clut(AVSubtitleRect *rect, int w, int h) count = FFMAX(i - 1, 1); for (i--; i>=0; i--) { int v = i*255/count; - AV_WN32(rect->data[1] + 4*list_inv[i], RGBA(v/2,v,v/2,v)); + AV_WN32(clut + 4*list_inv[i], RGBA(v/2,v,v/2,v)); } } @@ -749,8 +756,13 @@ static int save_subtitle_set(AVCodecContext *avctx, AVSubtitle *sub, int *got_ou goto fail; } - for(i=0; inum_rects; i++) + for (i = 0; i < sub->num_rects; i++) { sub->rects[i] = av_mallocz(sizeof(*sub->rects[i])); + if (!sub->rects[i]) { + ret = AVERROR(ENOMEM); + goto fail; + } + } i = 0; @@ -805,8 +817,14 @@ static int save_subtitle_set(AVCodecContext *avctx, AVSubtitle *sub, int *got_ou memcpy(rect->data[0], region->pbuf, region->buf_size); - if ((clut == &default_clut && ctx->compute_clut == -1) || ctx->compute_clut == 1) - compute_default_clut(rect, rect->w, rect->h); + if ((clut == &default_clut && ctx->compute_clut == -1) || ctx->compute_clut == 1) { + if (!region->has_computed_clut) { + compute_default_clut(region->computed_clut, rect, rect->w, rect->h); + region->has_computed_clut = 1; + } + + memcpy(rect->data[1], region->computed_clut, sizeof(region->computed_clut)); + } #if FF_API_AVPICTURE FF_DISABLE_DEPRECATION_WARNINGS @@ -955,6 +973,7 @@ static void dvbsub_parse_pixel_data_block(AVCodecContext *avctx, DVBSubObjectDis } } + region->has_computed_clut = 0; } static int dvbsub_parse_object_segment(AVCodecContext *avctx, diff --git a/libavcodec/dxtory.c b/libavcodec/dxtory.c index 6f8652ad499db..285ca38efb8b4 100644 --- a/libavcodec/dxtory.c +++ b/libavcodec/dxtory.c @@ -305,11 +305,7 @@ static int dxtory_decode_v2(AVCodecContext *avctx, AVFrame *pic, } if (avctx->height - line) { - av_log(avctx, AV_LOG_VERBOSE, - "Not enough slice data available, " - "cropping the frame by %d pixels\n", - avctx->height - line); - avctx->height = line; + avpriv_request_sample(avctx, "Not enough slice data available"); } return 0; @@ -326,7 +322,7 @@ static int dx2_decode_slice_5x5(GetBitContext *gb, AVFrame *frame, int stride = frame->linesize[0]; uint8_t *dst = frame->data[0] + stride * line; - for (y = 0; y < left && get_bits_left(gb) > 16; y++) { + for (y = 0; y < left && get_bits_left(gb) > 6 * width; y++) { for (x = 0; x < width; x++) { b = decode_sym_565(gb, lru[0], 5); g = decode_sym_565(gb, lru[1], is_565 ? 6 : 5); @@ -392,7 +388,7 @@ static int dx2_decode_slice_rgb(GetBitContext *gb, AVFrame *frame, int stride = frame->linesize[0]; uint8_t *dst = frame->data[0] + stride * line; - for (y = 0; y < left && get_bits_left(gb) > 16; y++) { + for (y = 0; y < left && get_bits_left(gb) > 6 * width; y++) { for (x = 0; x < width; x++) { dst[x * 3 + 0] = decode_sym(gb, lru[0]); dst[x * 3 + 1] = decode_sym(gb, lru[1]); @@ -437,7 +433,7 @@ static int dx2_decode_slice_410(GetBitContext *gb, AVFrame *frame, uint8_t *U = frame->data[1] + (ustride >> 2) * line; uint8_t *V = frame->data[2] + (vstride >> 2) * line; - for (y = 0; y < left - 3 && get_bits_left(gb) > 16; y += 4) { + for (y = 0; y < left - 3 && get_bits_left(gb) > 9 * width; y += 4) { for (x = 0; x < width; x += 4) { for (j = 0; j < 4; j++) for (i = 0; i < 4; i++) @@ -481,7 +477,7 @@ static int dx2_decode_slice_420(GetBitContext *gb, AVFrame *frame, uint8_t *V = frame->data[2] + (vstride >> 1) * line; - for (y = 0; y < left - 1 && get_bits_left(gb) > 16; y += 2) { + for (y = 0; y < left - 1 && get_bits_left(gb) > 6 * width; y += 2) { for (x = 0; x < width; x += 2) { Y[x + 0 + 0 * ystride] = decode_sym(gb, lru[0]); Y[x + 1 + 0 * ystride] = decode_sym(gb, lru[0]); @@ -524,7 +520,7 @@ static int dx2_decode_slice_444(GetBitContext *gb, AVFrame *frame, uint8_t *U = frame->data[1] + ustride * line; uint8_t *V = frame->data[2] + vstride * line; - for (y = 0; y < left && get_bits_left(gb) > 16; y++) { + for (y = 0; y < left && get_bits_left(gb) > 6 * width; y++) { for (x = 0; x < width; x++) { Y[x] = decode_sym(gb, lru[0]); U[x] = decode_sym(gb, lru[1]) ^ 0x80; diff --git a/libavcodec/dxv.c b/libavcodec/dxv.c index 529e2112589e3..08aca73b1fd8b 100644 --- a/libavcodec/dxv.c +++ b/libavcodec/dxv.c @@ -1,6 +1,7 @@ /* * Resolume DXV decoder * Copyright (C) 2015 Vittorio Giovara + * Copyright (C) 2018 Paul B Mahol * * This file is part of FFmpeg. * @@ -23,6 +24,7 @@ #include "libavutil/imgutils.h" +#include "mathops.h" #include "avcodec.h" #include "bytestream.h" #include "internal.h" @@ -34,50 +36,211 @@ typedef struct DXVContext { TextureDSPContext texdsp; GetByteContext gbc; - uint8_t *tex_data; // Compressed texture - int tex_rat; // Compression ratio - int tex_step; // Distance between blocks - int64_t tex_size; // Texture size + uint8_t *tex_data; // Compressed texture + uint8_t *ctex_data; // Compressed texture + int tex_rat; // Compression ratio + int tex_step; // Distance between blocks + int ctex_step; // Distance between blocks + int64_t tex_size; // Texture size + int64_t ctex_size; // Texture size /* Optimal number of slices for parallel decoding */ int slice_count; + uint8_t *op_data[4]; // Opcodes + int64_t op_size[4]; // Opcodes size + + int texture_block_w; + int texture_block_h; + + int ctexture_block_w; + int ctexture_block_h; + /* Pointer to the selected decompression function */ int (*tex_funct)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*tex_funct_planar[2])(uint8_t *plane0, ptrdiff_t stride0, + uint8_t *plane1, ptrdiff_t stride1, + const uint8_t *block); } DXVContext; +static void decompress_indices(uint8_t *dst, const uint8_t *src) +{ + int block, i; + + for (block = 0; block < 2; block++) { + int tmp = AV_RL24(src); + + /* Unpack 8x3 bit from last 3 byte block */ + for (i = 0; i < 8; i++) + dst[i] = (tmp >> (i * 3)) & 0x7; + + src += 3; + dst += 8; + } +} + +static int extract_component(int yo0, int yo1, int code) +{ + int yo; + + if (yo0 == yo1) { + yo = yo0; + } else if (code == 0) { + yo = yo0; + } else if (code == 1) { + yo = yo1; + } else { + if (yo0 > yo1) { + yo = (uint8_t) (((8 - code) * yo0 + + (code - 1) * yo1) / 7); + } else { + if (code == 6) { + yo = 0; + } else if (code == 7) { + yo = 255; + } else { + yo = (uint8_t) (((6 - code) * yo0 + + (code - 1) * yo1) / 5); + } + } + } + + return yo; +} + +static int cocg_block(uint8_t *plane0, ptrdiff_t stride0, + uint8_t *plane1, ptrdiff_t stride1, + const uint8_t *block) +{ + uint8_t co_indices[16]; + uint8_t cg_indices[16]; + uint8_t co0 = *(block); + uint8_t co1 = *(block + 1); + uint8_t cg0 = *(block + 8); + uint8_t cg1 = *(block + 9); + int x, y; + + decompress_indices(co_indices, block + 2); + decompress_indices(cg_indices, block + 10); + + for (y = 0; y < 4; y++) { + for (x = 0; x < 4; x++) { + int co_code = co_indices[x + y * 4]; + int cg_code = cg_indices[x + y * 4]; + + plane0[x] = extract_component(cg0, cg1, cg_code); + plane1[x] = extract_component(co0, co1, co_code); + } + plane0 += stride0; + plane1 += stride1; + } + + return 16; +} + +static void yao_subblock(uint8_t *dst, uint8_t *yo_indices, + ptrdiff_t stride, const uint8_t *block) +{ + uint8_t yo0 = *(block); + uint8_t yo1 = *(block + 1); + int x, y; + + decompress_indices(yo_indices, block + 2); + + for (y = 0; y < 4; y++) { + for (x = 0; x < 4; x++) { + int yo_code = yo_indices[x + y * 4]; + + dst[x] = extract_component(yo0, yo1, yo_code); + } + dst += stride; + } +} + +static int yo_block(uint8_t *dst, ptrdiff_t stride, + uint8_t *unused0, ptrdiff_t unused1, + const uint8_t *block) +{ + uint8_t yo_indices[16]; + + yao_subblock(dst, yo_indices, stride, block); + yao_subblock(dst + 4, yo_indices, stride, block + 8); + yao_subblock(dst + 8, yo_indices, stride, block + 16); + yao_subblock(dst + 12, yo_indices, stride, block + 24); + + return 32; +} + +static int yao_block(uint8_t *plane0, ptrdiff_t stride0, + uint8_t *plane3, ptrdiff_t stride1, + const uint8_t *block) +{ + uint8_t yo_indices[16]; + uint8_t a_indices[16]; + + yao_subblock(plane0, yo_indices, stride0, block); + yao_subblock(plane3, a_indices, stride1, block + 8); + yao_subblock(plane0 + 4, yo_indices, stride0, block + 16); + yao_subblock(plane3 + 4, a_indices, stride1, block + 24); + yao_subblock(plane0 + 8, yo_indices, stride0, block + 32); + yao_subblock(plane3 + 8, a_indices, stride1, block + 40); + yao_subblock(plane0 + 12, yo_indices, stride0, block + 48); + yao_subblock(plane3 + 12, a_indices, stride1, block + 56); + + return 64; +} + static int decompress_texture_thread(AVCodecContext *avctx, void *arg, int slice, int thread_nb) { DXVContext *ctx = avctx->priv_data; AVFrame *frame = arg; const uint8_t *d = ctx->tex_data; - int w_block = avctx->coded_width / TEXTURE_BLOCK_W; - int h_block = avctx->coded_height / TEXTURE_BLOCK_H; + int w_block = avctx->coded_width / ctx->texture_block_w; + int h_block = avctx->coded_height / ctx->texture_block_h; int x, y; int start_slice, end_slice; - int base_blocks_per_slice = h_block / ctx->slice_count; - int remainder_blocks = h_block % ctx->slice_count; - - /* When the frame height (in blocks) doesn't divide evenly between the - * number of slices, spread the remaining blocks evenly between the first - * operations */ - start_slice = slice * base_blocks_per_slice; - /* Add any extra blocks (one per slice) that have been added - * before this slice */ - start_slice += FFMIN(slice, remainder_blocks); - - end_slice = start_slice + base_blocks_per_slice; - /* Add an extra block if there are remainder blocks to be accounted for */ - if (slice < remainder_blocks) - end_slice++; - - for (y = start_slice; y < end_slice; y++) { - uint8_t *p = frame->data[0] + y * frame->linesize[0] * TEXTURE_BLOCK_H; - int off = y * w_block; - for (x = 0; x < w_block; x++) { - ctx->tex_funct(p + x * 16, frame->linesize[0], - d + (off + x) * ctx->tex_step); + + start_slice = h_block * slice / ctx->slice_count; + end_slice = h_block * (slice + 1) / ctx->slice_count; + + if (ctx->tex_funct) { + for (y = start_slice; y < end_slice; y++) { + uint8_t *p = frame->data[0] + y * frame->linesize[0] * ctx->texture_block_h; + int off = y * w_block; + for (x = 0; x < w_block; x++) { + ctx->tex_funct(p + x * 4 * ctx->texture_block_w, frame->linesize[0], + d + (off + x) * ctx->tex_step); + } + } + } else { + const uint8_t *c = ctx->ctex_data; + + for (y = start_slice; y < end_slice; y++) { + uint8_t *p0 = frame->data[0] + y * frame->linesize[0] * ctx->texture_block_h; + uint8_t *p3 = ctx->tex_step != 64 ? NULL : frame->data[3] + y * frame->linesize[3] * ctx->texture_block_h; + int off = y * w_block; + for (x = 0; x < w_block; x++) { + ctx->tex_funct_planar[0](p0 + x * ctx->texture_block_w, frame->linesize[0], + p3 != NULL ? p3 + x * ctx->texture_block_w : NULL, frame->linesize[3], + d + (off + x) * ctx->tex_step); + } + } + + w_block = (avctx->coded_width / 2) / ctx->ctexture_block_w; + h_block = (avctx->coded_height / 2) / ctx->ctexture_block_h; + start_slice = h_block * slice / ctx->slice_count; + end_slice = h_block * (slice + 1) / ctx->slice_count; + + for (y = start_slice; y < end_slice; y++) { + uint8_t *p0 = frame->data[1] + y * frame->linesize[1] * ctx->ctexture_block_h; + uint8_t *p1 = frame->data[2] + y * frame->linesize[2] * ctx->ctexture_block_h; + int off = y * w_block; + for (x = 0; x < w_block; x++) { + ctx->tex_funct_planar[1](p0 + x * ctx->ctexture_block_w, frame->linesize[1], + p1 + x * ctx->ctexture_block_w, frame->linesize[2], + c + (off + x) * ctx->ctex_step); + } } } @@ -169,6 +332,529 @@ static int dxv_decompress_dxt1(AVCodecContext *avctx) return 0; } +typedef struct OpcodeTable { + int16_t next; + uint8_t val1; + uint8_t val2; +} OpcodeTable; + +static int fill_ltable(GetByteContext *gb, uint32_t *table, int *nb_elements) +{ + unsigned half = 512, bits = 1023, left = 1024, input, mask; + int value, counter = 0, rshift = 10, lshift = 30; + + mask = bytestream2_get_le32(gb) >> 2; + while (left) { + if (counter >= 256) + return AVERROR_INVALIDDATA; + value = bits & mask; + left -= bits & mask; + mask >>= rshift; + lshift -= rshift; + table[counter++] = value; + if (lshift < 16) { + if (bytestream2_get_bytes_left(gb) <= 0) + return AVERROR_INVALIDDATA; + + input = bytestream2_get_le16(gb); + mask += input << lshift; + lshift += 16; + } + if (left < half) { + half >>= 1; + bits >>= 1; + rshift--; + } + } + + for (; !table[counter - 1]; counter--) + if (counter <= 0) + return AVERROR_INVALIDDATA; + + *nb_elements = counter; + + if (counter < 256) + memset(&table[counter], 0, 4 * (256 - counter)); + + if (lshift >= 16) + bytestream2_seek(gb, -2, SEEK_CUR); + + return 0; +} + +static int fill_optable(unsigned *table0, OpcodeTable *table1, int nb_elements) +{ + unsigned table2[256] = { 0 }; + unsigned x = 0; + int val0, val1, i, j = 2, k = 0; + + table2[0] = table0[0]; + for (i = 0; i < nb_elements - 1; i++, table2[i] = val0) { + val0 = table0[i + 1] + table2[i]; + } + + if (!table2[0]) { + do { + k++; + } while (!table2[k]); + } + + j = 2; + for (i = 1024; i > 0; i--) { + for (table1[x].val1 = k; k < 256 && j > table2[k]; k++); + x = (x - 383) & 0x3FF; + j++; + } + + if (nb_elements > 0) + memcpy(&table2[0], table0, 4 * nb_elements); + + for (i = 0; i < 1024; i++) { + val0 = table1[i].val1; + val1 = table2[val0]; + table2[val0]++; + x = 31 - ff_clz(val1); + if (x > 10) + return AVERROR_INVALIDDATA; + table1[i].val2 = 10 - x; + table1[i].next = (val1 << table1[i].val2) - 1024; + } + + return 0; +} + +static int get_opcodes(GetByteContext *gb, uint32_t *table, uint8_t *dst, int op_size, int nb_elements) +{ + OpcodeTable optable[1024]; + int sum, x, val, lshift, rshift, ret, size_in_bits, i, idx; + unsigned endoffset, newoffset, offset; + unsigned next; + uint8_t *src = (uint8_t *)gb->buffer; + + ret = fill_optable(table, optable, nb_elements); + if (ret < 0) + return ret; + + size_in_bits = bytestream2_get_le32(gb); + endoffset = ((size_in_bits + 7) >> 3) - 4; + if (endoffset <= 0 || bytestream2_get_bytes_left(gb) < endoffset) + return AVERROR_INVALIDDATA; + + offset = endoffset; + next = AV_RL32(src + endoffset); + rshift = (((size_in_bits & 0xFF) - 1) & 7) + 15; + lshift = 32 - rshift; + idx = (next >> rshift) & 0x3FF; + for (i = 0; i < op_size; i++) { + dst[i] = optable[idx].val1; + val = optable[idx].val2; + sum = val + lshift; + x = (next << lshift) >> 1 >> (31 - val); + newoffset = offset - (sum >> 3); + lshift = sum & 7; + idx = x + optable[idx].next; + offset = newoffset; + if (offset > endoffset) + return AVERROR_INVALIDDATA; + next = AV_RL32(src + offset); + } + + bytestream2_skip(gb, (size_in_bits + 7 >> 3) - 4); + + return 0; +} + +static int dxv_decompress_opcodes(GetByteContext *gb, void *dstp, size_t op_size) +{ + int pos = bytestream2_tell(gb); + int flag = bytestream2_peek_byte(gb); + + if ((flag & 3) == 0) { + bytestream2_skip(gb, 1); + bytestream2_get_buffer(gb, dstp, op_size); + } else if ((flag & 3) == 1) { + bytestream2_skip(gb, 1); + memset(dstp, bytestream2_get_byte(gb), op_size); + } else { + uint32_t table[256]; + int ret, elements = 0; + + ret = fill_ltable(gb, table, &elements); + if (ret < 0) + return ret; + ret = get_opcodes(gb, table, dstp, op_size, elements); + if (ret < 0) + return ret; + } + return bytestream2_tell(gb) - pos; +} + +static int dxv_decompress_cgo(DXVContext *ctx, GetByteContext *gb, + uint8_t *tex_data, int tex_size, + uint8_t *op_data, int *oindex, + int op_size, + uint8_t **dstp, int *statep, + uint8_t **tab0, uint8_t **tab1, + int offset) +{ + uint8_t *dst = *dstp; + uint8_t *tptr0, *tptr1, *tptr3; + int oi = *oindex; + int state = *statep; + int opcode, v, vv; + + if (state <= 0) { + if (oi >= op_size) + return AVERROR_INVALIDDATA; + opcode = op_data[oi++]; + if (!opcode) { + v = bytestream2_get_byte(gb); + if (v == 255) { + do { + if (bytestream2_get_bytes_left(gb) <= 0) + return AVERROR_INVALIDDATA; + opcode = bytestream2_get_le16(gb); + v += opcode; + } while (opcode == 0xFFFF); + } + AV_WL32(dst, AV_RL32(dst - (8 + offset))); + AV_WL32(dst + 4, AV_RL32(dst - (4 + offset))); + state = v + 4; + goto done; + } + + switch (opcode) { + case 1: + AV_WL32(dst, AV_RL32(dst - (8 + offset))); + AV_WL32(dst + 4, AV_RL32(dst - (4 + offset))); + break; + case 2: + vv = (8 + offset) * (bytestream2_get_le16(gb) + 1); + if (vv < 0 || vv > dst - tex_data) + return AVERROR_INVALIDDATA; + tptr0 = dst - vv; + v = AV_RL32(tptr0); + AV_WL32(dst, AV_RL32(tptr0)); + AV_WL32(dst + 4, AV_RL32(tptr0 + 4)); + tab0[0x9E3779B1 * (uint16_t)v >> 24] = dst; + tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; + break; + case 3: + AV_WL32(dst, bytestream2_get_le32(gb)); + AV_WL32(dst + 4, bytestream2_get_le32(gb)); + tab0[0x9E3779B1 * AV_RL16(dst) >> 24] = dst; + tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; + break; + case 4: + tptr3 = tab1[bytestream2_get_byte(gb)]; + if (!tptr3) + return AVERROR_INVALIDDATA; + AV_WL16(dst, bytestream2_get_le16(gb)); + AV_WL16(dst + 2, AV_RL16(tptr3)); + dst[4] = tptr3[2]; + AV_WL16(dst + 5, bytestream2_get_le16(gb)); + dst[7] = bytestream2_get_byte(gb); + tab0[0x9E3779B1 * AV_RL16(dst) >> 24] = dst; + break; + case 5: + tptr3 = tab1[bytestream2_get_byte(gb)]; + if (!tptr3) + return AVERROR_INVALIDDATA; + AV_WL16(dst, bytestream2_get_le16(gb)); + AV_WL16(dst + 2, bytestream2_get_le16(gb)); + dst[4] = bytestream2_get_byte(gb); + AV_WL16(dst + 5, AV_RL16(tptr3)); + dst[7] = tptr3[2]; + tab0[0x9E3779B1 * AV_RL16(dst) >> 24] = dst; + tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; + break; + case 6: + tptr0 = tab1[bytestream2_get_byte(gb)]; + if (!tptr0) + return AVERROR_INVALIDDATA; + tptr1 = tab1[bytestream2_get_byte(gb)]; + if (!tptr1) + return AVERROR_INVALIDDATA; + AV_WL16(dst, bytestream2_get_le16(gb)); + AV_WL16(dst + 2, AV_RL16(tptr0)); + dst[4] = tptr0[2]; + AV_WL16(dst + 5, AV_RL16(tptr1)); + dst[7] = tptr1[2]; + tab0[0x9E3779B1 * AV_RL16(dst) >> 24] = dst; + break; + case 7: + v = (8 + offset) * (bytestream2_get_le16(gb) + 1); + if (v < 0 || v > dst - tex_data) + return AVERROR_INVALIDDATA; + tptr0 = dst - v; + AV_WL16(dst, bytestream2_get_le16(gb)); + AV_WL16(dst + 2, AV_RL16(tptr0 + 2)); + AV_WL32(dst + 4, AV_RL32(tptr0 + 4)); + tab0[0x9E3779B1 * AV_RL16(dst) >> 24] = dst; + tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; + break; + case 8: + tptr1 = tab0[bytestream2_get_byte(gb)]; + if (!tptr1) + return AVERROR_INVALIDDATA; + AV_WL16(dst, AV_RL16(tptr1)); + AV_WL16(dst + 2, bytestream2_get_le16(gb)); + AV_WL32(dst + 4, bytestream2_get_le32(gb)); + tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; + break; + case 9: + tptr1 = tab0[bytestream2_get_byte(gb)]; + if (!tptr1) + return AVERROR_INVALIDDATA; + tptr3 = tab1[bytestream2_get_byte(gb)]; + if (!tptr3) + return AVERROR_INVALIDDATA; + AV_WL16(dst, AV_RL16(tptr1)); + AV_WL16(dst + 2, AV_RL16(tptr3)); + dst[4] = tptr3[2]; + AV_WL16(dst + 5, bytestream2_get_le16(gb)); + dst[7] = bytestream2_get_byte(gb); + tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; + break; + case 10: + tptr1 = tab0[bytestream2_get_byte(gb)]; + if (!tptr1) + return AVERROR_INVALIDDATA; + tptr3 = tab1[bytestream2_get_byte(gb)]; + if (!tptr3) + return AVERROR_INVALIDDATA; + AV_WL16(dst, AV_RL16(tptr1)); + AV_WL16(dst + 2, bytestream2_get_le16(gb)); + dst[4] = bytestream2_get_byte(gb); + AV_WL16(dst + 5, AV_RL16(tptr3)); + dst[7] = tptr3[2]; + tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; + break; + case 11: + tptr0 = tab0[bytestream2_get_byte(gb)]; + if (!tptr0) + return AVERROR_INVALIDDATA; + tptr3 = tab1[bytestream2_get_byte(gb)]; + if (!tptr3) + return AVERROR_INVALIDDATA; + tptr1 = tab1[bytestream2_get_byte(gb)]; + if (!tptr1) + return AVERROR_INVALIDDATA; + AV_WL16(dst, AV_RL16(tptr0)); + AV_WL16(dst + 2, AV_RL16(tptr3)); + dst[4] = tptr3[2]; + AV_WL16(dst + 5, AV_RL16(tptr1)); + dst[7] = tptr1[2]; + break; + case 12: + tptr1 = tab0[bytestream2_get_byte(gb)]; + if (!tptr1) + return AVERROR_INVALIDDATA; + v = (8 + offset) * (bytestream2_get_le16(gb) + 1); + if (v < 0 || v > dst - tex_data) + return AVERROR_INVALIDDATA; + tptr0 = dst - v; + AV_WL16(dst, AV_RL16(tptr1)); + AV_WL16(dst + 2, AV_RL16(tptr0 + 2)); + AV_WL32(dst + 4, AV_RL32(tptr0 + 4)); + tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; + break; + case 13: + AV_WL16(dst, AV_RL16(dst - (8 + offset))); + AV_WL16(dst + 2, bytestream2_get_le16(gb)); + AV_WL32(dst + 4, bytestream2_get_le32(gb)); + tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; + break; + case 14: + tptr3 = tab1[bytestream2_get_byte(gb)]; + if (!tptr3) + return AVERROR_INVALIDDATA; + AV_WL16(dst, AV_RL16(dst - (8 + offset))); + AV_WL16(dst + 2, AV_RL16(tptr3)); + dst[4] = tptr3[2]; + AV_WL16(dst + 5, bytestream2_get_le16(gb)); + dst[7] = bytestream2_get_byte(gb); + tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; + break; + case 15: + tptr3 = tab1[bytestream2_get_byte(gb)]; + if (!tptr3) + return AVERROR_INVALIDDATA; + AV_WL16(dst, AV_RL16(dst - (8 + offset))); + AV_WL16(dst + 2, bytestream2_get_le16(gb)); + dst[4] = bytestream2_get_byte(gb); + AV_WL16(dst + 5, AV_RL16(tptr3)); + dst[7] = tptr3[2]; + tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; + break; + case 16: + tptr3 = tab1[bytestream2_get_byte(gb)]; + if (!tptr3) + return AVERROR_INVALIDDATA; + tptr1 = tab1[bytestream2_get_byte(gb)]; + if (!tptr1) + return AVERROR_INVALIDDATA; + AV_WL16(dst, AV_RL16(dst - (8 + offset))); + AV_WL16(dst + 2, AV_RL16(tptr3)); + dst[4] = tptr3[2]; + AV_WL16(dst + 5, AV_RL16(tptr1)); + dst[7] = tptr1[2]; + break; + case 17: + v = (8 + offset) * (bytestream2_get_le16(gb) + 1); + if (v < 0 || v > dst - tex_data) + return AVERROR_INVALIDDATA; + AV_WL16(dst, AV_RL16(dst - (8 + offset))); + AV_WL16(dst + 2, AV_RL16(&dst[-v + 2])); + AV_WL32(dst + 4, AV_RL32(&dst[-v + 4])); + tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFFu) >> 24] = dst + 2; + break; + default: + break; + } + } else { +done: + AV_WL32(dst, AV_RL32(dst - (8 + offset))); + AV_WL32(dst + 4, AV_RL32(dst - (4 + offset))); + state--; + } + if (dst - tex_data + 8 > tex_size) + return AVERROR_INVALIDDATA; + dst += 8; + + *oindex = oi; + *dstp = dst; + *statep = state; + + return 0; +} + +static int dxv_decompress_cocg(DXVContext *ctx, GetByteContext *gb, + uint8_t *tex_data, int tex_size, + uint8_t *op_data0, uint8_t *op_data1, + int max_op_size0, int max_op_size1) +{ + uint8_t *dst, *tab2[256] = { 0 }, *tab0[256] = { 0 }, *tab3[256] = { 0 }, *tab1[256] = { 0 }; + int op_offset = bytestream2_get_le32(gb); + unsigned op_size0 = bytestream2_get_le32(gb); + unsigned op_size1 = bytestream2_get_le32(gb); + int data_start = bytestream2_tell(gb); + int skip0, skip1, oi0 = 0, oi1 = 0; + int ret, state0 = 0, state1 = 0; + + dst = tex_data; + bytestream2_skip(gb, op_offset - 12); + if (op_size0 > max_op_size0) + return AVERROR_INVALIDDATA; + skip0 = dxv_decompress_opcodes(gb, op_data0, op_size0); + if (skip0 < 0) + return skip0; + bytestream2_seek(gb, data_start + op_offset + skip0 - 12, SEEK_SET); + if (op_size1 > max_op_size1) + return AVERROR_INVALIDDATA; + skip1 = dxv_decompress_opcodes(gb, op_data1, op_size1); + if (skip1 < 0) + return skip1; + bytestream2_seek(gb, data_start, SEEK_SET); + + AV_WL32(dst, bytestream2_get_le32(gb)); + AV_WL32(dst + 4, bytestream2_get_le32(gb)); + AV_WL32(dst + 8, bytestream2_get_le32(gb)); + AV_WL32(dst + 12, bytestream2_get_le32(gb)); + + tab0[0x9E3779B1 * AV_RL16(dst) >> 24] = dst; + tab1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFF) >> 24] = dst + 2; + tab2[0x9E3779B1 * AV_RL16(dst + 8) >> 24] = dst + 8; + tab3[0x9E3779B1 * (AV_RL32(dst + 10) & 0xFFFFFF) >> 24] = dst + 10; + dst += 16; + while (dst + 10 < tex_data + tex_size) { + ret = dxv_decompress_cgo(ctx, gb, tex_data, tex_size, op_data0, &oi0, op_size0, + &dst, &state0, tab0, tab1, 8); + if (ret < 0) + return ret; + ret = dxv_decompress_cgo(ctx, gb, tex_data, tex_size, op_data1, &oi1, op_size1, + &dst, &state1, tab2, tab3, 8); + if (ret < 0) + return ret; + } + + bytestream2_seek(gb, data_start + op_offset + skip0 + skip1 - 12, SEEK_SET); + + return 0; +} + +static int dxv_decompress_yo(DXVContext *ctx, GetByteContext *gb, + uint8_t *tex_data, int tex_size, + uint8_t *op_data, int max_op_size) +{ + int op_offset = bytestream2_get_le32(gb); + unsigned op_size = bytestream2_get_le32(gb); + int data_start = bytestream2_tell(gb); + uint8_t *dst, *table0[256] = { 0 }, *table1[256] = { 0 }; + int ret, state = 0, skip, oi = 0, v, vv; + + dst = tex_data; + bytestream2_skip(gb, op_offset - 8); + if (op_size > max_op_size) + return AVERROR_INVALIDDATA; + skip = dxv_decompress_opcodes(gb, op_data, op_size); + if (skip < 0) + return skip; + bytestream2_seek(gb, data_start, SEEK_SET); + + v = bytestream2_get_le32(gb); + AV_WL32(dst, v); + vv = bytestream2_get_le32(gb); + table0[0x9E3779B1 * (uint16_t)v >> 24] = dst; + AV_WL32(dst + 4, vv); + table1[0x9E3779B1 * (AV_RL32(dst + 2) & 0xFFFFFF) >> 24] = dst + 2; + dst += 8; + + while (dst < tex_data + tex_size) { + ret = dxv_decompress_cgo(ctx, gb, tex_data, tex_size, op_data, &oi, op_size, + &dst, &state, table0, table1, 0); + if (ret < 0) + return ret; + } + + bytestream2_seek(gb, data_start + op_offset + skip - 8, SEEK_SET); + + return 0; +} + +static int dxv_decompress_ycg6(AVCodecContext *avctx) +{ + DXVContext *ctx = avctx->priv_data; + GetByteContext *gb = &ctx->gbc; + int ret; + + ret = dxv_decompress_yo(ctx, gb, ctx->tex_data, ctx->tex_size, + ctx->op_data[0], ctx->op_size[0]); + if (ret < 0) + return ret; + + return dxv_decompress_cocg(ctx, gb, ctx->ctex_data, ctx->ctex_size, + ctx->op_data[1], ctx->op_data[2], + ctx->op_size[1], ctx->op_size[2]); +} + +static int dxv_decompress_yg10(AVCodecContext *avctx) +{ + DXVContext *ctx = avctx->priv_data; + GetByteContext *gb = &ctx->gbc; + int ret; + + ret = dxv_decompress_cocg(ctx, gb, ctx->tex_data, ctx->tex_size, + ctx->op_data[0], ctx->op_data[3], + ctx->op_size[0], ctx->op_size[3]); + if (ret < 0) + return ret; + + return dxv_decompress_cocg(ctx, gb, ctx->ctex_data, ctx->ctex_size, + ctx->op_data[1], ctx->op_data[2], + ctx->op_size[1], ctx->op_size[2]); +} + static int dxv_decompress_dxt5(AVCodecContext *avctx) { DXVContext *ctx = avctx->priv_data; @@ -359,6 +1045,12 @@ static int dxv_decode(AVCodecContext *avctx, void *data, bytestream2_init(gbc, avpkt->data, avpkt->size); + ctx->texture_block_h = 4; + ctx->texture_block_w = 4; + + avctx->pix_fmt = AV_PIX_FMT_RGBA; + avctx->colorspace = AVCOL_SPC_RGB; + tag = bytestream2_get_le32(gbc); switch (tag) { case MKBETAG('D', 'X', 'T', '1'): @@ -378,9 +1070,39 @@ static int dxv_decode(AVCodecContext *avctx, void *data, msgtext = "DXT5"; break; case MKBETAG('Y', 'C', 'G', '6'): + decompress_tex = dxv_decompress_ycg6; + ctx->tex_funct_planar[0] = yo_block; + ctx->tex_funct_planar[1] = cocg_block; + ctx->tex_rat = 8; + ctx->tex_step = 32; + ctx->ctex_step = 16; + msgcomp = "YOCOCG6"; + msgtext = "YCG6"; + ctx->ctex_size = avctx->coded_width * avctx->coded_height / 4; + ctx->texture_block_h = 4; + ctx->texture_block_w = 16; + ctx->ctexture_block_h = 4; + ctx->ctexture_block_w = 4; + avctx->pix_fmt = AV_PIX_FMT_YUV420P; + avctx->colorspace = AVCOL_SPC_YCOCG; + break; case MKBETAG('Y', 'G', '1', '0'): - avpriv_report_missing_feature(avctx, "Tag 0x%08"PRIX32, tag); - return AVERROR_PATCHWELCOME; + decompress_tex = dxv_decompress_yg10; + ctx->tex_funct_planar[0] = yao_block; + ctx->tex_funct_planar[1] = cocg_block; + ctx->tex_rat = 4; + ctx->tex_step = 64; + ctx->ctex_step = 16; + msgcomp = "YAOCOCG10"; + msgtext = "YG10"; + ctx->ctex_size = avctx->coded_width * avctx->coded_height / 4; + ctx->texture_block_h = 4; + ctx->texture_block_w = 16; + ctx->ctexture_block_h = 4; + ctx->ctexture_block_w = 4; + avctx->pix_fmt = AV_PIX_FMT_YUVA420P; + avctx->colorspace = AVCOL_SPC_YCOCG; + break; default: /* Old version does not have a real header, just size and type. */ size = tag & 0x00FFFFFF; @@ -413,6 +1135,10 @@ static int dxv_decode(AVCodecContext *avctx, void *data, break; } + ctx->slice_count = av_clip(avctx->thread_count, 1, + avctx->coded_height / FFMAX(ctx->texture_block_h, + ctx->ctexture_block_h)); + /* New header is 12 bytes long. */ if (!old_type) { version_major = bytestream2_get_byte(gbc) - 1; @@ -440,10 +1166,28 @@ static int dxv_decode(AVCodecContext *avctx, void *data, } ctx->tex_size = avctx->coded_width * avctx->coded_height * 4 / ctx->tex_rat; - ret = av_reallocp(&ctx->tex_data, ctx->tex_size); + ret = av_reallocp(&ctx->tex_data, ctx->tex_size + AV_INPUT_BUFFER_PADDING_SIZE); if (ret < 0) return ret; + if (ctx->ctex_size) { + int i; + + ctx->op_size[0] = avctx->coded_width * avctx->coded_height / 16; + ctx->op_size[1] = avctx->coded_width * avctx->coded_height / 32; + ctx->op_size[2] = avctx->coded_width * avctx->coded_height / 32; + ctx->op_size[3] = avctx->coded_width * avctx->coded_height / 16; + + ret = av_reallocp(&ctx->ctex_data, ctx->ctex_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (ret < 0) + return ret; + for (i = 0; i < 4; i++) { + ret = av_reallocp(&ctx->op_data[i], ctx->op_size[i]); + if (ret < 0) + return ret; + } + } + /* Decompress texture out of the intermediate compression. */ ret = decompress_tex(avctx); if (ret < 0) @@ -482,10 +1226,6 @@ static int dxv_init(AVCodecContext *avctx) avctx->coded_height = FFALIGN(avctx->height, 16); ff_texturedsp_init(&ctx->texdsp); - avctx->pix_fmt = AV_PIX_FMT_RGBA; - - ctx->slice_count = av_clip(avctx->thread_count, 1, - avctx->coded_height / TEXTURE_BLOCK_H); return 0; } @@ -495,6 +1235,11 @@ static int dxv_close(AVCodecContext *avctx) DXVContext *ctx = avctx->priv_data; av_freep(&ctx->tex_data); + av_freep(&ctx->ctex_data); + av_freep(&ctx->op_data[0]); + av_freep(&ctx->op_data[1]); + av_freep(&ctx->op_data[2]); + av_freep(&ctx->op_data[3]); return 0; } diff --git a/libavcodec/dxva2.c b/libavcodec/dxva2.c index afcd361ef68cb..32416112bfd9c 100644 --- a/libavcodec/dxva2.c +++ b/libavcodec/dxva2.c @@ -29,6 +29,7 @@ #include "libavutil/time.h" #include "avcodec.h" +#include "decode.h" #include "dxva2_internal.h" /* define all the GUIDs used directly here, @@ -43,6 +44,7 @@ DEFINE_GUID(ff_DXVA2_ModeVC1_D2010, 0x1b81beA4, 0xa0c7,0x11d3,0xb9,0x84,0x0 DEFINE_GUID(ff_DXVA2_ModeHEVC_VLD_Main, 0x5b11d51b, 0x2f4c,0x4452,0xbc,0xc3,0x09,0xf2,0xa1,0x16,0x0c,0xc0); DEFINE_GUID(ff_DXVA2_ModeHEVC_VLD_Main10,0x107af0e0, 0xef1a,0x4d19,0xab,0xa8,0x67,0xa1,0x63,0x07,0x3d,0x13); DEFINE_GUID(ff_DXVA2_ModeVP9_VLD_Profile0,0x463707f8,0xa1d0,0x4585,0x87,0x6d,0x83,0xaa,0x6d,0x60,0xb8,0x9e); +DEFINE_GUID(ff_DXVA2_ModeVP9_VLD_10bit_Profile2,0xa4c749ef,0x6ecf,0x48aa,0x84,0x48,0x50,0xa7,0xa1,0x16,0x5f,0xf7); DEFINE_GUID(ff_DXVA2_NoEncrypt, 0x1b81beD0, 0xa0c7,0x11d3,0xb9,0x84,0x00,0xc0,0x4f,0x2e,0x73,0xc5); DEFINE_GUID(ff_GUID_NULL, 0x00000000, 0x0000,0x0000,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00); DEFINE_GUID(ff_IID_IDirectXVideoDecoderService, 0xfc51a551,0xd5e7,0x11d9,0xaf,0x55,0x00,0x05,0x4e,0x43,0xff,0x02); @@ -66,6 +68,10 @@ static const int prof_hevc_main[] = {FF_PROFILE_HEVC_MAIN, FF_PROFILE_UNKNOWN}; static const int prof_hevc_main10[] = {FF_PROFILE_HEVC_MAIN_10, FF_PROFILE_UNKNOWN}; +static const int prof_vp9_profile0[] = {FF_PROFILE_VP9_0, + FF_PROFILE_UNKNOWN}; +static const int prof_vp9_profile2[] = {FF_PROFILE_VP9_2, + FF_PROFILE_UNKNOWN}; static const dxva_mode dxva_modes[] = { /* MPEG-2 */ @@ -89,7 +95,8 @@ static const dxva_mode dxva_modes[] = { { &ff_DXVA2_ModeHEVC_VLD_Main, AV_CODEC_ID_HEVC, prof_hevc_main }, /* VP8/9 */ - { &ff_DXVA2_ModeVP9_VLD_Profile0,AV_CODEC_ID_VP9 }, + { &ff_DXVA2_ModeVP9_VLD_Profile0, AV_CODEC_ID_VP9, prof_vp9_profile0 }, + { &ff_DXVA2_ModeVP9_VLD_10bit_Profile2, AV_CODEC_ID_VP9, prof_vp9_profile2 }, { NULL, 0 }, }; @@ -576,14 +583,20 @@ static void ff_dxva2_unlock(AVCodecContext *avctx) #endif } -// This must work before the decoder is created. -// This somehow needs to be exported to the user. -static void dxva_adjust_hwframes(AVCodecContext *avctx, AVHWFramesContext *frames_ctx) +int ff_dxva2_common_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx) { - FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx); + AVHWFramesContext *frames_ctx = (AVHWFramesContext *)hw_frames_ctx->data; + AVHWDeviceContext *device_ctx = frames_ctx->device_ctx; int surface_alignment, num_surfaces; - frames_ctx->format = sctx->pix_fmt; + if (device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) { + frames_ctx->format = AV_PIX_FMT_DXVA2_VLD; + } else if (device_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) { + frames_ctx->format = AV_PIX_FMT_D3D11; + } else { + return AVERROR(EINVAL); + } /* decoding MPEG-2 requires additional alignment on some Intel GPUs, but it causes issues for H.264 on certain AMD GPUs..... */ @@ -596,8 +609,8 @@ static void dxva_adjust_hwframes(AVCodecContext *avctx, AVHWFramesContext *frame else surface_alignment = 16; - /* 4 base work surfaces */ - num_surfaces = 4; + /* 1 base work surface */ + num_surfaces = 1; /* add surfaces based on number of possible refs */ if (avctx->codec_id == AV_CODEC_ID_H264 || avctx->codec_id == AV_CODEC_ID_HEVC) @@ -607,10 +620,6 @@ static void dxva_adjust_hwframes(AVCodecContext *avctx, AVHWFramesContext *frame else num_surfaces += 2; - /* add extra surfaces for frame threading */ - if (avctx->active_thread_type & FF_THREAD_FRAME) - num_surfaces += avctx->thread_count; - frames_ctx->sw_format = avctx->sw_pix_fmt == AV_PIX_FMT_YUV420P10 ? AV_PIX_FMT_P010 : AV_PIX_FMT_NV12; frames_ctx->width = FFALIGN(avctx->coded_width, surface_alignment); @@ -633,12 +642,16 @@ static void dxva_adjust_hwframes(AVCodecContext *avctx, AVHWFramesContext *frame frames_hwctx->BindFlags |= D3D11_BIND_DECODER; } #endif + + return 0; } int ff_dxva2_decode_init(AVCodecContext *avctx) { FFDXVASharedContext *sctx = DXVA_SHARED_CONTEXT(avctx); - AVHWFramesContext *frames_ctx = NULL; + AVHWFramesContext *frames_ctx; + enum AVHWDeviceType dev_type = avctx->hwaccel->pix_fmt == AV_PIX_FMT_DXVA2_VLD + ? AV_HWDEVICE_TYPE_DXVA2 : AV_HWDEVICE_TYPE_D3D11VA; int ret = 0; // Old API. @@ -648,32 +661,14 @@ int ff_dxva2_decode_init(AVCodecContext *avctx) // (avctx->pix_fmt is not updated yet at this point) sctx->pix_fmt = avctx->hwaccel->pix_fmt; - if (!avctx->hw_frames_ctx && !avctx->hw_device_ctx) { - av_log(avctx, AV_LOG_ERROR, "Either a hw_frames_ctx or a hw_device_ctx needs to be set for hardware decoding.\n"); - return AVERROR(EINVAL); - } - - if (avctx->hw_frames_ctx) { - frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; - } else { - avctx->hw_frames_ctx = av_hwframe_ctx_alloc(avctx->hw_device_ctx); - if (!avctx->hw_frames_ctx) - return AVERROR(ENOMEM); - - frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; - - dxva_adjust_hwframes(avctx, frames_ctx); - - ret = av_hwframe_ctx_init(avctx->hw_frames_ctx); - if (ret < 0) - goto fail; - } + ret = ff_decode_get_hw_frames_ctx(avctx, dev_type); + if (ret < 0) + return ret; + frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; sctx->device_ctx = frames_ctx->device_ctx; - if (frames_ctx->format != sctx->pix_fmt || - !((sctx->pix_fmt == AV_PIX_FMT_D3D11 && CONFIG_D3D11VA) || - (sctx->pix_fmt == AV_PIX_FMT_DXVA2_VLD && CONFIG_DXVA2))) { + if (frames_ctx->format != sctx->pix_fmt) { av_log(avctx, AV_LOG_ERROR, "Invalid pixfmt for hwaccel!\n"); ret = AVERROR(EINVAL); goto fail; diff --git a/libavcodec/dxva2_h264.c b/libavcodec/dxva2_h264.c index e3a3f7866edd6..5b23b28f1202b 100644 --- a/libavcodec/dxva2_h264.c +++ b/libavcodec/dxva2_h264.c @@ -22,16 +22,12 @@ #include "libavutil/avassert.h" +#include "dxva2_internal.h" #include "h264dec.h" #include "h264data.h" #include "h264_ps.h" #include "mpegutils.h" -// The headers above may include w32threads.h, which uses the original -// _WIN32_WINNT define, while dxva2_internal.h redefines it to target a -// potentially newer version. -#include "dxva2_internal.h" - struct dxva2_picture_context { DXVA_PicParams_H264 pp; DXVA_Qmatrix_H264 qm; @@ -518,7 +514,7 @@ static int dxva2_h264_end_frame(AVCodecContext *avctx) } #if CONFIG_H264_DXVA2_HWACCEL -AVHWAccel ff_h264_dxva2_hwaccel = { +const AVHWAccel ff_h264_dxva2_hwaccel = { .name = "h264_dxva2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, @@ -528,13 +524,14 @@ AVHWAccel ff_h264_dxva2_hwaccel = { .start_frame = dxva2_h264_start_frame, .decode_slice = dxva2_h264_decode_slice, .end_frame = dxva2_h264_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_H264_D3D11VA_HWACCEL -AVHWAccel ff_h264_d3d11va_hwaccel = { +const AVHWAccel ff_h264_d3d11va_hwaccel = { .name = "h264_d3d11va", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, @@ -544,13 +541,14 @@ AVHWAccel ff_h264_d3d11va_hwaccel = { .start_frame = dxva2_h264_start_frame, .decode_slice = dxva2_h264_decode_slice, .end_frame = dxva2_h264_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_H264_D3D11VA2_HWACCEL -AVHWAccel ff_h264_d3d11va2_hwaccel = { +const AVHWAccel ff_h264_d3d11va2_hwaccel = { .name = "h264_d3d11va2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, @@ -560,6 +558,7 @@ AVHWAccel ff_h264_d3d11va2_hwaccel = { .start_frame = dxva2_h264_start_frame, .decode_slice = dxva2_h264_decode_slice, .end_frame = dxva2_h264_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; diff --git a/libavcodec/dxva2_hevc.c b/libavcodec/dxva2_hevc.c index 88f887a1b5ac6..dbb701fb1c3fc 100644 --- a/libavcodec/dxva2_hevc.c +++ b/libavcodec/dxva2_hevc.c @@ -22,14 +22,10 @@ #include "libavutil/avassert.h" +#include "dxva2_internal.h" #include "hevc_data.h" #include "hevcdec.h" -// The headers above may include w32threads.h, which uses the original -// _WIN32_WINNT define, while dxva2_internal.h redefines it to target a -// potentially newer version. -#include "dxva2_internal.h" - #define MAX_SLICES 256 struct hevc_dxva2_picture_context { @@ -422,7 +418,7 @@ static int dxva2_hevc_end_frame(AVCodecContext *avctx) } #if CONFIG_HEVC_DXVA2_HWACCEL -AVHWAccel ff_hevc_dxva2_hwaccel = { +const AVHWAccel ff_hevc_dxva2_hwaccel = { .name = "hevc_dxva2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_HEVC, @@ -432,13 +428,14 @@ AVHWAccel ff_hevc_dxva2_hwaccel = { .start_frame = dxva2_hevc_start_frame, .decode_slice = dxva2_hevc_decode_slice, .end_frame = dxva2_hevc_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct hevc_dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_HEVC_D3D11VA_HWACCEL -AVHWAccel ff_hevc_d3d11va_hwaccel = { +const AVHWAccel ff_hevc_d3d11va_hwaccel = { .name = "hevc_d3d11va", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_HEVC, @@ -448,13 +445,14 @@ AVHWAccel ff_hevc_d3d11va_hwaccel = { .start_frame = dxva2_hevc_start_frame, .decode_slice = dxva2_hevc_decode_slice, .end_frame = dxva2_hevc_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct hevc_dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_HEVC_D3D11VA2_HWACCEL -AVHWAccel ff_hevc_d3d11va2_hwaccel = { +const AVHWAccel ff_hevc_d3d11va2_hwaccel = { .name = "hevc_d3d11va2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_HEVC, @@ -464,6 +462,7 @@ AVHWAccel ff_hevc_d3d11va2_hwaccel = { .start_frame = dxva2_hevc_start_frame, .decode_slice = dxva2_hevc_decode_slice, .end_frame = dxva2_hevc_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct hevc_dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; diff --git a/libavcodec/dxva2_internal.h b/libavcodec/dxva2_internal.h index 352a9db1abd6f..8bb3344090aaa 100644 --- a/libavcodec/dxva2_internal.h +++ b/libavcodec/dxva2_internal.h @@ -156,6 +156,9 @@ int ff_dxva2_decode_init(AVCodecContext *avctx); int ff_dxva2_decode_uninit(AVCodecContext *avctx); +int ff_dxva2_common_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx); + int ff_dxva2_is_d3d11(const AVCodecContext *avctx); #endif /* AVCODEC_DXVA2_INTERNAL_H */ diff --git a/libavcodec/dxva2_mpeg2.c b/libavcodec/dxva2_mpeg2.c index b7c69378f090d..8cc21bf19957d 100644 --- a/libavcodec/dxva2_mpeg2.c +++ b/libavcodec/dxva2_mpeg2.c @@ -21,13 +21,10 @@ */ #include "libavutil/log.h" -#include "mpegutils.h" -#include "mpegvideo.h" -// The headers above may include w32threads.h, which uses the original -// _WIN32_WINNT define, while dxva2_internal.h redefines it to target a -// potentially newer version. #include "dxva2_internal.h" +#include "mpegutils.h" +#include "mpegvideo.h" #define MAX_SLICES 1024 struct dxva2_picture_context { @@ -317,7 +314,7 @@ static int dxva2_mpeg2_end_frame(AVCodecContext *avctx) } #if CONFIG_MPEG2_DXVA2_HWACCEL -AVHWAccel ff_mpeg2_dxva2_hwaccel = { +const AVHWAccel ff_mpeg2_dxva2_hwaccel = { .name = "mpeg2_dxva2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG2VIDEO, @@ -327,13 +324,14 @@ AVHWAccel ff_mpeg2_dxva2_hwaccel = { .start_frame = dxva2_mpeg2_start_frame, .decode_slice = dxva2_mpeg2_decode_slice, .end_frame = dxva2_mpeg2_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_MPEG2_D3D11VA_HWACCEL -AVHWAccel ff_mpeg2_d3d11va_hwaccel = { +const AVHWAccel ff_mpeg2_d3d11va_hwaccel = { .name = "mpeg2_d3d11va", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG2VIDEO, @@ -343,13 +341,14 @@ AVHWAccel ff_mpeg2_d3d11va_hwaccel = { .start_frame = dxva2_mpeg2_start_frame, .decode_slice = dxva2_mpeg2_decode_slice, .end_frame = dxva2_mpeg2_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_MPEG2_D3D11VA2_HWACCEL -AVHWAccel ff_mpeg2_d3d11va2_hwaccel = { +const AVHWAccel ff_mpeg2_d3d11va2_hwaccel = { .name = "mpeg2_d3d11va2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG2VIDEO, @@ -359,6 +358,7 @@ AVHWAccel ff_mpeg2_d3d11va2_hwaccel = { .start_frame = dxva2_mpeg2_start_frame, .decode_slice = dxva2_mpeg2_decode_slice, .end_frame = dxva2_mpeg2_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; diff --git a/libavcodec/dxva2_vc1.c b/libavcodec/dxva2_vc1.c index e5353cdddca30..f08ac8b5a0d7c 100644 --- a/libavcodec/dxva2_vc1.c +++ b/libavcodec/dxva2_vc1.c @@ -20,16 +20,13 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "dxva2_internal.h" #include "mpegutils.h" #include "vc1.h" #include "vc1data.h" -// The headers above may include w32threads.h, which uses the original -// _WIN32_WINNT define, while dxva2_internal.h redefines it to target a -// potentially newer version. -#include "dxva2_internal.h" - #define MAX_SLICES 1024 + struct dxva2_picture_context { DXVA_PictureParameters pp; unsigned slice_count; @@ -378,7 +375,7 @@ static int dxva2_vc1_end_frame(AVCodecContext *avctx) } #if CONFIG_WMV3_DXVA2_HWACCEL -AVHWAccel ff_wmv3_dxva2_hwaccel = { +const AVHWAccel ff_wmv3_dxva2_hwaccel = { .name = "wmv3_dxva2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_WMV3, @@ -388,13 +385,14 @@ AVHWAccel ff_wmv3_dxva2_hwaccel = { .start_frame = dxva2_vc1_start_frame, .decode_slice = dxva2_vc1_decode_slice, .end_frame = dxva2_vc1_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_VC1_DXVA2_HWACCEL -AVHWAccel ff_vc1_dxva2_hwaccel = { +const AVHWAccel ff_vc1_dxva2_hwaccel = { .name = "vc1_dxva2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VC1, @@ -404,13 +402,14 @@ AVHWAccel ff_vc1_dxva2_hwaccel = { .start_frame = dxva2_vc1_start_frame, .decode_slice = dxva2_vc1_decode_slice, .end_frame = dxva2_vc1_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_WMV3_D3D11VA_HWACCEL -AVHWAccel ff_wmv3_d3d11va_hwaccel = { +const AVHWAccel ff_wmv3_d3d11va_hwaccel = { .name = "wmv3_d3d11va", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_WMV3, @@ -420,13 +419,14 @@ AVHWAccel ff_wmv3_d3d11va_hwaccel = { .start_frame = dxva2_vc1_start_frame, .decode_slice = dxva2_vc1_decode_slice, .end_frame = dxva2_vc1_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_WMV3_D3D11VA2_HWACCEL -AVHWAccel ff_wmv3_d3d11va2_hwaccel = { +const AVHWAccel ff_wmv3_d3d11va2_hwaccel = { .name = "wmv3_d3d11va2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_WMV3, @@ -436,13 +436,14 @@ AVHWAccel ff_wmv3_d3d11va2_hwaccel = { .start_frame = dxva2_vc1_start_frame, .decode_slice = dxva2_vc1_decode_slice, .end_frame = dxva2_vc1_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_VC1_D3D11VA_HWACCEL -AVHWAccel ff_vc1_d3d11va_hwaccel = { +const AVHWAccel ff_vc1_d3d11va_hwaccel = { .name = "vc1_d3d11va", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VC1, @@ -452,13 +453,14 @@ AVHWAccel ff_vc1_d3d11va_hwaccel = { .start_frame = dxva2_vc1_start_frame, .decode_slice = dxva2_vc1_decode_slice, .end_frame = dxva2_vc1_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_VC1_D3D11VA2_HWACCEL -AVHWAccel ff_vc1_d3d11va2_hwaccel = { +const AVHWAccel ff_vc1_d3d11va2_hwaccel = { .name = "vc1_d3d11va2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VC1, @@ -468,6 +470,7 @@ AVHWAccel ff_vc1_d3d11va2_hwaccel = { .start_frame = dxva2_vc1_start_frame, .decode_slice = dxva2_vc1_decode_slice, .end_frame = dxva2_vc1_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; diff --git a/libavcodec/dxva2_vp9.c b/libavcodec/dxva2_vp9.c index 6d87fdd9f24bd..eaeab3af7af23 100644 --- a/libavcodec/dxva2_vp9.c +++ b/libavcodec/dxva2_vp9.c @@ -23,12 +23,8 @@ #include "libavutil/avassert.h" #include "libavutil/pixdesc.h" -#include "vp9shared.h" - -// The headers above may include w32threads.h, which uses the original -// _WIN32_WINNT define, while dxva2_internal.h redefines it to target a -// potentially newer version. #include "dxva2_internal.h" +#include "vp9shared.h" struct vp9_dxva2_picture_context { DXVA_PicParams_VP9 pp; @@ -309,7 +305,7 @@ static int dxva2_vp9_end_frame(AVCodecContext *avctx) } #if CONFIG_VP9_DXVA2_HWACCEL -AVHWAccel ff_vp9_dxva2_hwaccel = { +const AVHWAccel ff_vp9_dxva2_hwaccel = { .name = "vp9_dxva2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VP9, @@ -319,13 +315,14 @@ AVHWAccel ff_vp9_dxva2_hwaccel = { .start_frame = dxva2_vp9_start_frame, .decode_slice = dxva2_vp9_decode_slice, .end_frame = dxva2_vp9_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct vp9_dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_VP9_D3D11VA_HWACCEL -AVHWAccel ff_vp9_d3d11va_hwaccel = { +const AVHWAccel ff_vp9_d3d11va_hwaccel = { .name = "vp9_d3d11va", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VP9, @@ -335,13 +332,14 @@ AVHWAccel ff_vp9_d3d11va_hwaccel = { .start_frame = dxva2_vp9_start_frame, .decode_slice = dxva2_vp9_decode_slice, .end_frame = dxva2_vp9_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct vp9_dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; #endif #if CONFIG_VP9_D3D11VA2_HWACCEL -AVHWAccel ff_vp9_d3d11va2_hwaccel = { +const AVHWAccel ff_vp9_d3d11va2_hwaccel = { .name = "vp9_d3d11va2", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VP9, @@ -351,6 +349,7 @@ AVHWAccel ff_vp9_d3d11va2_hwaccel = { .start_frame = dxva2_vp9_start_frame, .decode_slice = dxva2_vp9_decode_slice, .end_frame = dxva2_vp9_end_frame, + .frame_params = ff_dxva2_common_frame_params, .frame_priv_data_size = sizeof(struct vp9_dxva2_picture_context), .priv_data_size = sizeof(FFDXVASharedContext), }; diff --git a/libavcodec/eac3_core_bsf.c b/libavcodec/eac3_core_bsf.c new file mode 100644 index 0000000000000..3e4dc2e2a234c --- /dev/null +++ b/libavcodec/eac3_core_bsf.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avcodec.h" +#include "bsf.h" +#include "get_bits.h" +#include "ac3_parser_internal.h" + +static int eac3_core_filter(AVBSFContext *ctx, AVPacket *pkt) +{ + AC3HeaderInfo hdr; + GetBitContext gbc; + int ret; + + ret = ff_bsf_get_packet_ref(ctx, pkt); + if (ret < 0) + return ret; + ret = init_get_bits8(&gbc, pkt->data, pkt->size); + if (ret < 0) + goto fail; + + ret = ff_ac3_parse_header(&gbc, &hdr); + if (ret < 0) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + + if (hdr.frame_type == EAC3_FRAME_TYPE_INDEPENDENT || + hdr.frame_type == EAC3_FRAME_TYPE_AC3_CONVERT) { + pkt->size = FFMIN(hdr.frame_size, pkt->size); + } else if (hdr.frame_type == EAC3_FRAME_TYPE_DEPENDENT && pkt->size > hdr.frame_size) { + AC3HeaderInfo hdr2; + + ret = init_get_bits8(&gbc, pkt->data + hdr.frame_size, pkt->size - hdr.frame_size); + if (ret < 0) + goto fail; + + ret = ff_ac3_parse_header(&gbc, &hdr2); + if (ret < 0) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + + if (hdr2.frame_type == EAC3_FRAME_TYPE_INDEPENDENT || + hdr2.frame_type == EAC3_FRAME_TYPE_AC3_CONVERT) { + pkt->size -= hdr.frame_size; + pkt->data += hdr.frame_size; + } else { + pkt->size = 0; + } + } else { + pkt->size = 0; + } + + return 0; +fail: + av_packet_unref(pkt); + return ret; +} + +static const enum AVCodecID codec_ids[] = { + AV_CODEC_ID_EAC3, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_eac3_core_bsf = { + .name = "eac3_core", + .filter = eac3_core_filter, + .codec_ids = codec_ids, +}; diff --git a/libavcodec/eac3dec.c b/libavcodec/eac3dec.c index c971879b2dc83..fe97d2903261b 100644 --- a/libavcodec/eac3dec.c +++ b/libavcodec/eac3dec.c @@ -48,7 +48,6 @@ #include "internal.h" #include "aac_ac3_parser.h" #include "ac3.h" -#include "ac3_parser.h" #include "ac3dec.h" #include "ac3dec_data.h" #include "eac3_data.h" @@ -304,13 +303,7 @@ static int ff_eac3_parse_header(AC3DecodeContext *s) /* An E-AC-3 stream can have multiple independent streams which the application can select from. each independent stream can also contain dependent streams which are used to add or replace channels. */ - if (s->frame_type == EAC3_FRAME_TYPE_DEPENDENT) { - if (!s->eac3_frame_dependent_found) { - s->eac3_frame_dependent_found = 1; - avpriv_request_sample(s->avctx, "Dependent substream decoding"); - } - return AAC_AC3_PARSE_ERROR_FRAME_TYPE; - } else if (s->frame_type == EAC3_FRAME_TYPE_RESERVED) { + if (s->frame_type == EAC3_FRAME_TYPE_RESERVED) { av_log(s->avctx, AV_LOG_ERROR, "Reserved frame type\n"); return AAC_AC3_PARSE_ERROR_FRAME_TYPE; } @@ -356,7 +349,8 @@ static int ff_eac3_parse_header(AC3DecodeContext *s) /* dependent stream channel map */ if (s->frame_type == EAC3_FRAME_TYPE_DEPENDENT) { if (get_bits1(gbc)) { - skip_bits(gbc, 16); // skip custom channel map + s->channel_map = get_bits(gbc, 16); + av_log(s->avctx, AV_LOG_DEBUG, "channel_map: %0X\n", s->channel_map); } } diff --git a/libavcodec/encode.c b/libavcodec/encode.c index c961dbace10b5..d9761515aa84e 100644 --- a/libavcodec/encode.c +++ b/libavcodec/encode.c @@ -223,12 +223,9 @@ int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx, avpkt->buf = user_pkt.buf; avpkt->data = user_pkt.data; } else if (!avpkt->buf) { - AVPacket tmp = { 0 }; - ret = av_packet_ref(&tmp, avpkt); - av_packet_unref(avpkt); + ret = av_packet_make_refcounted(avpkt); if (ret < 0) goto end; - *avpkt = tmp; } } @@ -257,10 +254,6 @@ int attribute_align_arg avcodec_encode_audio2(AVCodecContext *avctx, av_frame_free(&padded_frame); av_free(extended_frame); -#if FF_API_AUDIOENC_DELAY - avctx->delay = avctx->initial_padding; -#endif - return ret; } @@ -322,12 +315,9 @@ int attribute_align_arg avcodec_encode_video2(AVCodecContext *avctx, avpkt->buf = user_pkt.buf; avpkt->data = user_pkt.data; } else if (!avpkt->buf) { - AVPacket tmp = { 0 }; - ret = av_packet_ref(&tmp, avpkt); - av_packet_unref(avpkt); + ret = av_packet_make_refcounted(avpkt); if (ret < 0) return ret; - *avpkt = tmp; } } diff --git a/libavcodec/error_resilience.c b/libavcodec/error_resilience.c index 5364940e9466c..25e54a535b720 100644 --- a/libavcodec/error_resilience.c +++ b/libavcodec/error_resilience.c @@ -27,7 +27,6 @@ #include -#include "libavutil/atomic.h" #include "libavutil/internal.h" #include "avcodec.h" #include "error_resilience.h" @@ -807,18 +806,16 @@ void ff_er_frame_start(ERContext *s) memset(s->error_status_table, ER_MB_ERROR | VP_START | ER_MB_END, s->mb_stride * s->mb_height * sizeof(uint8_t)); - s->error_count = 3 * s->mb_num; + atomic_init(&s->error_count, 3 * s->mb_num); s->error_occurred = 0; } static int er_supported(ERContext *s) { if(s->avctx->hwaccel && s->avctx->hwaccel->decode_slice || -#if FF_API_CAP_VDPAU - s->avctx->codec->capabilities&AV_CODEC_CAP_HWACCEL_VDPAU || -#endif !s->cur_pic.f || - s->cur_pic.field_picture + s->cur_pic.field_picture || + s->avctx->profile == FF_PROFILE_MPEG4_SIMPLE_STUDIO ) return 0; return 1; @@ -855,20 +852,20 @@ void ff_er_add_slice(ERContext *s, int startx, int starty, mask &= ~VP_START; if (status & (ER_AC_ERROR | ER_AC_END)) { mask &= ~(ER_AC_ERROR | ER_AC_END); - avpriv_atomic_int_add_and_fetch(&s->error_count, start_i - end_i - 1); + atomic_fetch_add(&s->error_count, start_i - end_i - 1); } if (status & (ER_DC_ERROR | ER_DC_END)) { mask &= ~(ER_DC_ERROR | ER_DC_END); - avpriv_atomic_int_add_and_fetch(&s->error_count, start_i - end_i - 1); + atomic_fetch_add(&s->error_count, start_i - end_i - 1); } if (status & (ER_MV_ERROR | ER_MV_END)) { mask &= ~(ER_MV_ERROR | ER_MV_END); - avpriv_atomic_int_add_and_fetch(&s->error_count, start_i - end_i - 1); + atomic_fetch_add(&s->error_count, start_i - end_i - 1); } if (status & ER_MB_ERROR) { s->error_occurred = 1; - avpriv_atomic_int_set(&s->error_count, INT_MAX); + atomic_store(&s->error_count, INT_MAX); } if (mask == ~0x7F) { @@ -881,7 +878,7 @@ void ff_er_add_slice(ERContext *s, int startx, int starty, } if (end_i == s->mb_num) - avpriv_atomic_int_set(&s->error_count, INT_MAX); + atomic_store(&s->error_count, INT_MAX); else { s->error_status_table[end_xy] &= mask; s->error_status_table[end_xy] |= status; @@ -896,7 +893,7 @@ void ff_er_add_slice(ERContext *s, int startx, int starty, prev_status &= ~ VP_START; if (prev_status != (ER_MV_END | ER_DC_END | ER_AC_END)) { s->error_occurred = 1; - avpriv_atomic_int_set(&s->error_count, INT_MAX); + atomic_store(&s->error_count, INT_MAX); } } } @@ -913,10 +910,10 @@ void ff_er_frame_end(ERContext *s) /* We do not support ER of field pictures yet, * though it should not crash if enabled. */ - if (!s->avctx->error_concealment || s->error_count == 0 || + if (!s->avctx->error_concealment || !atomic_load(&s->error_count) || s->avctx->lowres || !er_supported(s) || - s->error_count == 3 * s->mb_width * + atomic_load(&s->error_count) == 3 * s->mb_width * (s->avctx->skip_top + s->avctx->skip_bottom)) { return; } @@ -930,7 +927,7 @@ void ff_er_frame_end(ERContext *s) if ( mb_x == s->mb_width && s->avctx->codec_id == AV_CODEC_ID_MPEG2VIDEO && (FFALIGN(s->avctx->height, 16)&16) - && s->error_count == 3 * s->mb_width * (s->avctx->skip_top + s->avctx->skip_bottom + 1) + && atomic_load(&s->error_count) == 3 * s->mb_width * (s->avctx->skip_top + s->avctx->skip_bottom + 1) ) { av_log(s->avctx, AV_LOG_DEBUG, "ignoring last missing slice\n"); return; diff --git a/libavcodec/error_resilience.h b/libavcodec/error_resilience.h index 27c20086948e9..664a765659272 100644 --- a/libavcodec/error_resilience.h +++ b/libavcodec/error_resilience.h @@ -20,6 +20,7 @@ #define AVCODEC_ERROR_RESILIENCE_H #include +#include #include "avcodec.h" #include "me_cmp.h" @@ -60,7 +61,7 @@ typedef struct ERContext { ptrdiff_t mb_stride; ptrdiff_t b8_stride; - volatile int error_count; + atomic_int error_count; int error_occurred; uint8_t *error_status_table; uint8_t *er_temp_buffer; diff --git a/libavcodec/exif.c b/libavcodec/exif.c index 07ce1741c2642..2874772db4d7d 100644 --- a/libavcodec/exif.c +++ b/libavcodec/exif.c @@ -92,7 +92,7 @@ static int exif_decode_tag(void *logctx, GetByteContext *gbytes, int le, // store metadata or proceed with next IFD ret = ff_tis_ifd(id); if (ret) { - ret = avpriv_exif_decode_ifd(logctx, gbytes, le, depth + 1, metadata); + ret = ff_exif_decode_ifd(logctx, gbytes, le, depth + 1, metadata); } else { const char *name = exif_get_tag_name(id); char *use_name = (char*) name; @@ -119,8 +119,8 @@ static int exif_decode_tag(void *logctx, GetByteContext *gbytes, int le, } -int avpriv_exif_decode_ifd(void *logctx, GetByteContext *gbytes, int le, - int depth, AVDictionary **metadata) +int ff_exif_decode_ifd(void *logctx, GetByteContext *gbytes, + int le, int depth, AVDictionary **metadata) { int i, ret; int entries; @@ -140,3 +140,13 @@ int avpriv_exif_decode_ifd(void *logctx, GetByteContext *gbytes, int le, // return next IDF offset or 0x000000000 or a value < 0 for failure return ff_tget_long(gbytes, le); } + +int avpriv_exif_decode_ifd(void *logctx, const uint8_t *buf, int size, + int le, int depth, AVDictionary **metadata) +{ + GetByteContext gb; + + bytestream2_init(&gb, buf, size); + + return ff_exif_decode_ifd(logctx, &gb, le, depth, metadata); +} diff --git a/libavcodec/exif.h b/libavcodec/exif.h index 5f09208b9d766..05af756c48fd0 100644 --- a/libavcodec/exif.h +++ b/libavcodec/exif.h @@ -164,7 +164,10 @@ static const struct exif_tag tag_list[] = { // JEITA CP-3451 EXIF specification: /** Recursively decodes all IFD's and * adds included TAGS into the metadata dictionary. */ -int avpriv_exif_decode_ifd(void *logctx, GetByteContext *gbytes, int le, - int depth, AVDictionary **metadata); +int avpriv_exif_decode_ifd(void *logctx, const uint8_t *buf, int size, + int le, int depth, AVDictionary **metadata); + +int ff_exif_decode_ifd(void *logctx, GetByteContext *gbytes, int le, + int depth, AVDictionary **metadata); #endif /* AVCODEC_EXIF_H */ diff --git a/libavcodec/exr.c b/libavcodec/exr.c index 0b755db3cb3e8..5253cc3f136c7 100644 --- a/libavcodec/exr.c +++ b/libavcodec/exr.c @@ -558,7 +558,7 @@ static int huf_decode(const uint64_t *hcode, const HufDec *hdecod, while (lc > 0) { const HufDec pl = hdecod[(c << (HUF_DECBITS - lc)) & HUF_DECMASK]; - if (pl.len) { + if (pl.len && lc >= pl.len) { lc -= pl.len; get_code(pl.lit, rlc, c, lc, gb, out, oe, outb); } else { @@ -855,7 +855,7 @@ static int pxr24_uncompress(EXRContext *s, const uint8_t *src, in = ptr[2] + td->xsize; for (j = 0; j < td->xsize; ++j) { - uint32_t diff = (*(ptr[0]++) << 24) | + uint32_t diff = ((unsigned)*(ptr[0]++) << 24) | (*(ptr[1]++) << 16) | (*(ptr[2]++) << 8); pixel += diff; @@ -899,7 +899,7 @@ static int pxr24_uncompress(EXRContext *s, const uint8_t *src, static void unpack_14(const uint8_t b[14], uint16_t s[16]) { - unsigned short shift = (b[ 2] >> 2); + unsigned short shift = (b[ 2] >> 2) & 15; unsigned short bias = (0x20 << shift); int i; @@ -1051,7 +1051,7 @@ static int decode_block(AVCodecContext *avctx, void *tdata, line_offset = AV_RL64(s->gb.buffer + jobnr * 8); if (s->is_tile) { - if (line_offset > buf_size - 20) + if (buf_size < 20 || line_offset > buf_size - 20) return AVERROR_INVALIDDATA; src = buf + line_offset + 20; @@ -1062,7 +1062,7 @@ static int decode_block(AVCodecContext *avctx, void *tdata, tile_level_y = AV_RL32(src - 8); data_size = AV_RL32(src - 4); - if (data_size <= 0 || data_size > buf_size) + if (data_size <= 0 || data_size > buf_size - line_offset - 20) return AVERROR_INVALIDDATA; if (tile_level_x || tile_level_y) { /* tile level, is not the full res level */ @@ -1095,7 +1095,7 @@ static int decode_block(AVCodecContext *avctx, void *tdata, td->channel_line_size = td->xsize * s->current_channel_offset;/* uncompress size of one line */ uncompressed_size = td->channel_line_size * (uint64_t)td->ysize;/* uncompress size of the block */ } else { - if (line_offset > buf_size - 8) + if (buf_size < 8 || line_offset > buf_size - 8) return AVERROR_INVALIDDATA; src = buf + line_offset + 8; @@ -1105,7 +1105,7 @@ static int decode_block(AVCodecContext *avctx, void *tdata, return AVERROR_INVALIDDATA; data_size = AV_RL32(src - 4); - if (data_size <= 0 || data_size > buf_size) + if (data_size <= 0 || data_size > buf_size - line_offset - 8) return AVERROR_INVALIDDATA; td->ysize = FFMIN(s->scan_lines_per_block, s->ymax - line + 1); /* s->ydelta - line ?? */ @@ -1306,6 +1306,7 @@ static int decode_header(EXRContext *s, AVFrame *frame) AVDictionary *metadata = NULL; int magic_number, version, i, flags, sar = 0; int layer_match = 0; + int ret; s->current_channel_offset = 0; s->xmin = ~0; @@ -1349,12 +1350,14 @@ static int decode_header(EXRContext *s, AVFrame *frame) flags = bytestream2_get_le24(&s->gb); - if (flags == 0x00) - s->is_tile = 0; - else if (flags & 0x02) + if (flags & 0x02) s->is_tile = 1; - else{ - avpriv_report_missing_feature(s->avctx, "flags %d", flags); + if (flags & 0x08) { + avpriv_report_missing_feature(s->avctx, "deep data"); + return AVERROR_PATCHWELCOME; + } + if (flags & 0x10) { + avpriv_report_missing_feature(s->avctx, "multipart"); return AVERROR_PATCHWELCOME; } @@ -1364,8 +1367,10 @@ static int decode_header(EXRContext *s, AVFrame *frame) if ((var_size = check_header_variable(s, "channels", "chlist", 38)) >= 0) { GetByteContext ch_gb; - if (!var_size) - return AVERROR_INVALIDDATA; + if (!var_size) { + ret = AVERROR_INVALIDDATA; + goto fail; + } bytestream2_init(&ch_gb, s->gb.buffer, var_size); @@ -1424,14 +1429,16 @@ static int decode_header(EXRContext *s, AVFrame *frame) if (bytestream2_get_bytes_left(&ch_gb) < 4) { av_log(s->avctx, AV_LOG_ERROR, "Incomplete header.\n"); - return AVERROR_INVALIDDATA; + ret = AVERROR_INVALIDDATA; + goto fail; } current_pixel_type = bytestream2_get_le32(&ch_gb); if (current_pixel_type >= EXR_UNKNOWN) { avpriv_report_missing_feature(s->avctx, "Pixel type %d", current_pixel_type); - return AVERROR_PATCHWELCOME; + ret = AVERROR_PATCHWELCOME; + goto fail; } bytestream2_skip(&ch_gb, 4); @@ -1442,7 +1449,8 @@ static int decode_header(EXRContext *s, AVFrame *frame) avpriv_report_missing_feature(s->avctx, "Subsampling %dx%d", xsub, ysub); - return AVERROR_PATCHWELCOME; + ret = AVERROR_PATCHWELCOME; + goto fail; } if (channel_index >= 0 && s->channel_offsets[channel_index] == -1) { /* channel has not been previously assigned */ @@ -1450,7 +1458,8 @@ static int decode_header(EXRContext *s, AVFrame *frame) s->pixel_type != current_pixel_type) { av_log(s->avctx, AV_LOG_ERROR, "RGB channels not of the same depth.\n"); - return AVERROR_INVALIDDATA; + ret = AVERROR_INVALIDDATA; + goto fail; } s->pixel_type = current_pixel_type; s->channel_offsets[channel_index] = s->current_channel_offset; @@ -1458,8 +1467,10 @@ static int decode_header(EXRContext *s, AVFrame *frame) s->channels = av_realloc(s->channels, ++s->nb_channels * sizeof(EXRChannel)); - if (!s->channels) - return AVERROR(ENOMEM); + if (!s->channels) { + ret = AVERROR(ENOMEM); + goto fail; + } channel = &s->channels[s->nb_channels - 1]; channel->pixel_type = current_pixel_type; channel->xsub = xsub; @@ -1484,7 +1495,8 @@ static int decode_header(EXRContext *s, AVFrame *frame) av_log(s->avctx, AV_LOG_ERROR, "Missing green channel.\n"); if (s->channel_offsets[2] < 0) av_log(s->avctx, AV_LOG_ERROR, "Missing blue channel.\n"); - return AVERROR_INVALIDDATA; + ret = AVERROR_INVALIDDATA; + goto fail; } } @@ -1493,8 +1505,10 @@ static int decode_header(EXRContext *s, AVFrame *frame) continue; } else if ((var_size = check_header_variable(s, "dataWindow", "box2i", 31)) >= 0) { - if (!var_size) - return AVERROR_INVALIDDATA; + if (!var_size) { + ret = AVERROR_INVALIDDATA; + goto fail; + } s->xmin = bytestream2_get_le32(&s->gb); s->ymin = bytestream2_get_le32(&s->gb); @@ -1506,8 +1520,10 @@ static int decode_header(EXRContext *s, AVFrame *frame) continue; } else if ((var_size = check_header_variable(s, "displayWindow", "box2i", 34)) >= 0) { - if (!var_size) - return AVERROR_INVALIDDATA; + if (!var_size) { + ret = AVERROR_INVALIDDATA; + goto fail; + } bytestream2_skip(&s->gb, 8); s->w = bytestream2_get_le32(&s->gb) + 1; @@ -1517,29 +1533,36 @@ static int decode_header(EXRContext *s, AVFrame *frame) } else if ((var_size = check_header_variable(s, "lineOrder", "lineOrder", 25)) >= 0) { int line_order; - if (!var_size) - return AVERROR_INVALIDDATA; + if (!var_size) { + ret = AVERROR_INVALIDDATA; + goto fail; + } line_order = bytestream2_get_byte(&s->gb); av_log(s->avctx, AV_LOG_DEBUG, "line order: %d.\n", line_order); if (line_order > 2) { av_log(s->avctx, AV_LOG_ERROR, "Unknown line order.\n"); - return AVERROR_INVALIDDATA; + ret = AVERROR_INVALIDDATA; + goto fail; } continue; } else if ((var_size = check_header_variable(s, "pixelAspectRatio", "float", 31)) >= 0) { - if (!var_size) - return AVERROR_INVALIDDATA; + if (!var_size) { + ret = AVERROR_INVALIDDATA; + goto fail; + } sar = bytestream2_get_le32(&s->gb); continue; } else if ((var_size = check_header_variable(s, "compression", "compression", 29)) >= 0) { - if (!var_size) - return AVERROR_INVALIDDATA; + if (!var_size) { + ret = AVERROR_INVALIDDATA; + goto fail; + } if (s->compression == EXR_UNKN) s->compression = bytestream2_get_byte(&s->gb); @@ -1566,13 +1589,15 @@ static int decode_header(EXRContext *s, AVFrame *frame) if (s->tile_attr.level_mode >= EXR_TILE_LEVEL_UNKNOWN){ avpriv_report_missing_feature(s->avctx, "Tile level mode %d", s->tile_attr.level_mode); - return AVERROR_PATCHWELCOME; + ret = AVERROR_PATCHWELCOME; + goto fail; } if (s->tile_attr.level_round >= EXR_TILE_ROUND_UNKNOWN) { avpriv_report_missing_feature(s->avctx, "Tile level round %d", s->tile_attr.level_round); - return AVERROR_PATCHWELCOME; + ret = AVERROR_PATCHWELCOME; + goto fail; } continue; @@ -1589,7 +1614,8 @@ static int decode_header(EXRContext *s, AVFrame *frame) // Check if there are enough bytes for a header if (bytestream2_get_bytes_left(&s->gb) <= 9) { av_log(s->avctx, AV_LOG_ERROR, "Incomplete header\n"); - return AVERROR_INVALIDDATA; + ret = AVERROR_INVALIDDATA; + goto fail; } // Process unknown variables @@ -1604,19 +1630,22 @@ static int decode_header(EXRContext *s, AVFrame *frame) if (s->compression == EXR_UNKN) { av_log(s->avctx, AV_LOG_ERROR, "Missing compression attribute.\n"); - return AVERROR_INVALIDDATA; + ret = AVERROR_INVALIDDATA; + goto fail; } if (s->is_tile) { if (s->tile_attr.xSize < 1 || s->tile_attr.ySize < 1) { av_log(s->avctx, AV_LOG_ERROR, "Invalid tile attribute.\n"); - return AVERROR_INVALIDDATA; + ret = AVERROR_INVALIDDATA; + goto fail; } } if (bytestream2_get_bytes_left(&s->gb) <= 0) { av_log(s->avctx, AV_LOG_ERROR, "Incomplete frame.\n"); - return AVERROR_INVALIDDATA; + ret = AVERROR_INVALIDDATA; + goto fail; } frame->metadata = metadata; @@ -1624,6 +1653,9 @@ static int decode_header(EXRContext *s, AVFrame *frame) // aaand we are done bytestream2_skip(&s->gb, 1); return 0; +fail: + av_dict_free(&metadata); + return ret; } static int decode_frame(AVCodecContext *avctx, void *data, diff --git a/libavcodec/extract_extradata_bsf.c b/libavcodec/extract_extradata_bsf.c index ed6509c681add..082b3e749bc80 100644 --- a/libavcodec/extract_extradata_bsf.c +++ b/libavcodec/extract_extradata_bsf.c @@ -36,6 +36,9 @@ typedef struct ExtractExtradataContext { int (*extract)(AVBSFContext *ctx, AVPacket *pkt, uint8_t **data, int *size); + /* H264/HEVC specifc fields */ + H2645Packet h2645_pkt; + /* AVOptions */ int remove; } ExtractExtradataContext; @@ -61,8 +64,7 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt, ExtractExtradataContext *s = ctx->priv_data; - H2645Packet h2645_pkt = { 0 }; - int extradata_size = 0; + int extradata_size = 0, filtered_size = 0; const int *extradata_nal_types; int nb_extradata_nal_types; int i, has_sps = 0, has_vps = 0, ret = 0; @@ -75,13 +77,13 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt, nb_extradata_nal_types = FF_ARRAY_ELEMS(extradata_nal_types_h264); } - ret = ff_h2645_packet_split(&h2645_pkt, pkt->data, pkt->size, + ret = ff_h2645_packet_split(&s->h2645_pkt, pkt->data, pkt->size, ctx, 0, 0, ctx->par_in->codec_id, 1); if (ret < 0) return ret; - for (i = 0; i < h2645_pkt.nb_nals; i++) { - H2645NAL *nal = &h2645_pkt.nals[i]; + for (i = 0; i < s->h2645_pkt.nb_nals; i++) { + H2645NAL *nal = &s->h2645_pkt.nals[i]; if (val_in_array(extradata_nal_types, nb_extradata_nal_types, nal->type)) { extradata_size += nal->raw_size + 3; if (ctx->par_in->codec_id == AV_CODEC_ID_HEVC) { @@ -90,6 +92,8 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt, } else { if (nal->type == H264_NAL_SPS) has_sps = 1; } + } else if (s->remove) { + filtered_size += nal->raw_size + 3; } } @@ -100,26 +104,27 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt, uint8_t *extradata, *filtered_data; if (s->remove) { - filtered_buf = av_buffer_alloc(pkt->size + AV_INPUT_BUFFER_PADDING_SIZE); + filtered_buf = av_buffer_alloc(filtered_size + AV_INPUT_BUFFER_PADDING_SIZE); if (!filtered_buf) { - ret = AVERROR(ENOMEM); - goto fail; + return AVERROR(ENOMEM); } + memset(filtered_buf->data + filtered_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + filtered_data = filtered_buf->data; } extradata = av_malloc(extradata_size + AV_INPUT_BUFFER_PADDING_SIZE); if (!extradata) { av_buffer_unref(&filtered_buf); - ret = AVERROR(ENOMEM); - goto fail; + return AVERROR(ENOMEM); } + memset(extradata + extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); *data = extradata; *size = extradata_size; - for (i = 0; i < h2645_pkt.nb_nals; i++) { - H2645NAL *nal = &h2645_pkt.nals[i]; + for (i = 0; i < s->h2645_pkt.nb_nals; i++) { + H2645NAL *nal = &s->h2645_pkt.nals[i]; if (val_in_array(extradata_nal_types, nb_extradata_nal_types, nal->type)) { AV_WB24(extradata, 1); // startcode @@ -136,13 +141,11 @@ static int extract_extradata_h2645(AVBSFContext *ctx, AVPacket *pkt, av_buffer_unref(&pkt->buf); pkt->buf = filtered_buf; pkt->data = filtered_buf->data; - pkt->size = filtered_data - filtered_buf->data; + pkt->size = filtered_size; } } -fail: - ff_h2645_packet_uninit(&h2645_pkt); - return ret; + return 0; } static int extract_extradata_vc1(AVBSFContext *ctx, AVPacket *pkt, @@ -169,6 +172,7 @@ static int extract_extradata_vc1(AVBSFContext *ctx, AVPacket *pkt, return AVERROR(ENOMEM); memcpy(*data, pkt->data, extradata_size); + memset(*data + extradata_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); *size = extradata_size; if (s->remove) { @@ -199,6 +203,7 @@ static int extract_extradata_mpeg12(AVBSFContext *ctx, AVPacket *pkt, return AVERROR(ENOMEM); memcpy(*data, pkt->data, *size); + memset(*data + *size, 0, AV_INPUT_BUFFER_PADDING_SIZE); if (s->remove) { pkt->data += *size; @@ -228,6 +233,7 @@ static int extract_extradata_mpeg4(AVBSFContext *ctx, AVPacket *pkt, return AVERROR(ENOMEM); memcpy(*data, pkt->data, *size); + memset(*data + *size, 0, AV_INPUT_BUFFER_PADDING_SIZE); if (s->remove) { pkt->data += *size; @@ -271,24 +277,23 @@ static int extract_extradata_init(AVBSFContext *ctx) return 0; } -static int extract_extradata_filter(AVBSFContext *ctx, AVPacket *out) +static int extract_extradata_filter(AVBSFContext *ctx, AVPacket *pkt) { ExtractExtradataContext *s = ctx->priv_data; - AVPacket *in; uint8_t *extradata = NULL; int extradata_size; int ret = 0; - ret = ff_bsf_get_packet(ctx, &in); + ret = ff_bsf_get_packet_ref(ctx, pkt); if (ret < 0) return ret; - ret = s->extract(ctx, in, &extradata, &extradata_size); + ret = s->extract(ctx, pkt, &extradata, &extradata_size); if (ret < 0) goto fail; if (extradata) { - ret = av_packet_add_side_data(in, AV_PKT_DATA_NEW_EXTRADATA, + ret = av_packet_add_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, extradata, extradata_size); if (ret < 0) { av_freep(&extradata); @@ -296,13 +301,19 @@ static int extract_extradata_filter(AVBSFContext *ctx, AVPacket *out) } } - av_packet_move_ref(out, in); + return 0; fail: - av_packet_free(&in); + av_packet_unref(pkt); return ret; } +static void extract_extradata_close(AVBSFContext *ctx) +{ + ExtractExtradataContext *s = ctx->priv_data; + ff_h2645_packet_uninit(&s->h2645_pkt); +} + static const enum AVCodecID codec_ids[] = { AV_CODEC_ID_CAVS, AV_CODEC_ID_H264, @@ -315,9 +326,10 @@ static const enum AVCodecID codec_ids[] = { }; #define OFFSET(x) offsetof(ExtractExtradataContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM) static const AVOption options[] = { { "remove", "remove the extradata from the bitstream", OFFSET(remove), AV_OPT_TYPE_INT, - { .i64 = 0 }, 0, 1 }, + { .i64 = 0 }, 0, 1, FLAGS }, { NULL }, }; @@ -335,4 +347,5 @@ const AVBitStreamFilter ff_extract_extradata_bsf = { .priv_class = &extract_extradata_class, .init = extract_extradata_init, .filter = extract_extradata_filter, + .close = extract_extradata_close, }; diff --git a/libavcodec/ffv1dec.c b/libavcodec/ffv1dec.c index 5eadb6b158648..7658a516850d3 100644 --- a/libavcodec/ffv1dec.c +++ b/libavcodec/ffv1dec.c @@ -336,14 +336,16 @@ static int decode_slice(AVCodecContext *c, void *arg) decode_plane(fs, p->data[0] + ps*x + y*p->linesize[0] , width, height, p->linesize[0], 0, 2); decode_plane(fs, p->data[0] + ps*x + y*p->linesize[0] + 1, width, height, p->linesize[0], 1, 2); } else if (f->use32bit) { - uint8_t *planes[3] = { p->data[0] + ps * x + y * p->linesize[0], + uint8_t *planes[4] = { p->data[0] + ps * x + y * p->linesize[0], p->data[1] + ps * x + y * p->linesize[1], - p->data[2] + ps * x + y * p->linesize[2] }; + p->data[2] + ps * x + y * p->linesize[2], + p->data[3] + ps * x + y * p->linesize[3] }; decode_rgb_frame32(fs, planes, width, height, p->linesize); } else { - uint8_t *planes[3] = { p->data[0] + ps * x + y * p->linesize[0], + uint8_t *planes[4] = { p->data[0] + ps * x + y * p->linesize[0], p->data[1] + ps * x + y * p->linesize[1], - p->data[2] + ps * x + y * p->linesize[2] }; + p->data[2] + ps * x + y * p->linesize[2], + p->data[3] + ps * x + y * p->linesize[3] }; decode_rgb_frame(fs, planes, width, height, p->linesize); } if (fs->ac != AC_GOLOMB_RICE && f->version > 2) { @@ -589,7 +591,10 @@ static int read_header(FFV1Context *f) if (!f->transparency && !f->chroma_planes) { if (f->avctx->bits_per_raw_sample <= 8) f->avctx->pix_fmt = AV_PIX_FMT_GRAY8; - else if (f->avctx->bits_per_raw_sample == 10) { + else if (f->avctx->bits_per_raw_sample == 9) { + f->packed_at_lsb = 1; + f->avctx->pix_fmt = AV_PIX_FMT_GRAY9; + } else if (f->avctx->bits_per_raw_sample == 10) { f->packed_at_lsb = 1; f->avctx->pix_fmt = AV_PIX_FMT_GRAY10; } else if (f->avctx->bits_per_raw_sample == 12) { @@ -640,6 +645,7 @@ static int read_header(FFV1Context *f) f->packed_at_lsb = 1; switch(16 * f->chroma_h_shift + f->chroma_v_shift) { case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUV444P10; break; + case 0x01: f->avctx->pix_fmt = AV_PIX_FMT_YUV440P10; break; case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUV422P10; break; case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUV420P10; break; } @@ -654,9 +660,17 @@ static int read_header(FFV1Context *f) f->packed_at_lsb = 1; switch(16 * f->chroma_h_shift + f->chroma_v_shift) { case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUV444P12; break; + case 0x01: f->avctx->pix_fmt = AV_PIX_FMT_YUV440P12; break; case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUV422P12; break; case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUV420P12; break; } + } else if (f->avctx->bits_per_raw_sample == 14 && !f->transparency) { + f->packed_at_lsb = 1; + switch(16 * f->chroma_h_shift + f->chroma_v_shift) { + case 0x00: f->avctx->pix_fmt = AV_PIX_FMT_YUV444P14; break; + case 0x10: f->avctx->pix_fmt = AV_PIX_FMT_YUV422P14; break; + case 0x11: f->avctx->pix_fmt = AV_PIX_FMT_YUV420P14; break; + } } else if (f->avctx->bits_per_raw_sample == 16 && !f->transparency){ f->packed_at_lsb = 1; switch(16 * f->chroma_h_shift + f->chroma_v_shift) { @@ -686,14 +700,22 @@ static int read_header(FFV1Context *f) f->avctx->pix_fmt = AV_PIX_FMT_GBRP9; else if (f->avctx->bits_per_raw_sample == 10 && !f->transparency) f->avctx->pix_fmt = AV_PIX_FMT_GBRP10; + else if (f->avctx->bits_per_raw_sample == 10 && f->transparency) + f->avctx->pix_fmt = AV_PIX_FMT_GBRAP10; else if (f->avctx->bits_per_raw_sample == 12 && !f->transparency) f->avctx->pix_fmt = AV_PIX_FMT_GBRP12; + else if (f->avctx->bits_per_raw_sample == 12 && f->transparency) + f->avctx->pix_fmt = AV_PIX_FMT_GBRAP12; else if (f->avctx->bits_per_raw_sample == 14 && !f->transparency) f->avctx->pix_fmt = AV_PIX_FMT_GBRP14; else if (f->avctx->bits_per_raw_sample == 16 && !f->transparency) { f->avctx->pix_fmt = AV_PIX_FMT_GBRP16; f->use32bit = 1; } + else if (f->avctx->bits_per_raw_sample == 16 && f->transparency) { + f->avctx->pix_fmt = AV_PIX_FMT_GBRAP16; + f->use32bit = 1; + } } else { av_log(f->avctx, AV_LOG_ERROR, "colorspace not supported\n"); return AVERROR(ENOSYS); @@ -928,7 +950,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac } if (desc->flags & AV_PIX_FMT_FLAG_PAL || - desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) { + desc->flags & FF_PSEUDOPAL) { dst[1] = p->data[1]; src[1] = f->last_picture.f->data[1]; } diff --git a/libavcodec/ffv1dec_template.c b/libavcodec/ffv1dec_template.c index 37df7667737d3..f8a42a6d44cac 100644 --- a/libavcodec/ffv1dec_template.c +++ b/libavcodec/ffv1dec_template.c @@ -107,13 +107,14 @@ static av_always_inline int RENAME(decode_line)(FFV1Context *s, int w, return 0; } -static void RENAME(decode_rgb_frame)(FFV1Context *s, uint8_t *src[3], int w, int h, int stride[3]) +static void RENAME(decode_rgb_frame)(FFV1Context *s, uint8_t *src[4], int w, int h, int stride[4]) { int x, y, p; TYPE *sample[4][2]; int lbd = s->avctx->bits_per_raw_sample <= 8; int bits = s->avctx->bits_per_raw_sample > 0 ? s->avctx->bits_per_raw_sample : 8; int offset = 1 << bits; + int transparency = s->transparency; for (x = 0; x < 4; x++) { sample[x][0] = RENAME(s->sample_buffer) + x * 2 * (w + 6) + 3; @@ -125,7 +126,7 @@ static void RENAME(decode_rgb_frame)(FFV1Context *s, uint8_t *src[3], int w, int memset(RENAME(s->sample_buffer), 0, 8 * (w + 6) * sizeof(*RENAME(s->sample_buffer))); for (y = 0; y < h; y++) { - for (p = 0; p < 3 + s->transparency; p++) { + for (p = 0; p < 3 + transparency; p++) { TYPE *temp = sample[p][0]; // FIXME: try a normal buffer sample[p][0] = sample[p][1]; @@ -154,10 +155,12 @@ static void RENAME(decode_rgb_frame)(FFV1Context *s, uint8_t *src[3], int w, int if (lbd) *((uint32_t*)(src[0] + x*4 + stride[0]*y)) = b + ((unsigned)g<<8) + ((unsigned)r<<16) + ((unsigned)a<<24); - else if (sizeof(TYPE) == 4) { + else if (sizeof(TYPE) == 4 || transparency) { *((uint16_t*)(src[0] + x*2 + stride[0]*y)) = g; *((uint16_t*)(src[1] + x*2 + stride[1]*y)) = b; *((uint16_t*)(src[2] + x*2 + stride[2]*y)) = r; + if (transparency) + *((uint16_t*)(src[3] + x*2 + stride[3]*y)) = a; } else { *((uint16_t*)(src[0] + x*2 + stride[0]*y)) = b; *((uint16_t*)(src[1] + x*2 + stride[1]*y)) = g; diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c index c9a885ebfaa8d..dd4d7429f5484 100644 --- a/libavcodec/ffv1enc.c +++ b/libavcodec/ffv1enc.c @@ -558,6 +558,7 @@ FF_ENABLE_DEPRECATION_WARNINGS s->plane_count = 3; switch(avctx->pix_fmt) { + case AV_PIX_FMT_GRAY9: case AV_PIX_FMT_YUV444P9: case AV_PIX_FMT_YUV422P9: case AV_PIX_FMT_YUV420P9: @@ -568,6 +569,7 @@ FF_ENABLE_DEPRECATION_WARNINGS s->bits_per_raw_sample = 9; case AV_PIX_FMT_GRAY10: case AV_PIX_FMT_YUV444P10: + case AV_PIX_FMT_YUV440P10: case AV_PIX_FMT_YUV420P10: case AV_PIX_FMT_YUV422P10: case AV_PIX_FMT_YUVA444P10: @@ -577,11 +579,17 @@ FF_ENABLE_DEPRECATION_WARNINGS s->bits_per_raw_sample = 10; case AV_PIX_FMT_GRAY12: case AV_PIX_FMT_YUV444P12: + case AV_PIX_FMT_YUV440P12: case AV_PIX_FMT_YUV420P12: case AV_PIX_FMT_YUV422P12: - s->packed_at_lsb = 1; if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) s->bits_per_raw_sample = 12; + case AV_PIX_FMT_YUV444P14: + case AV_PIX_FMT_YUV420P14: + case AV_PIX_FMT_YUV422P14: + if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) + s->bits_per_raw_sample = 14; + s->packed_at_lsb = 1; case AV_PIX_FMT_GRAY16: case AV_PIX_FMT_YUV444P16: case AV_PIX_FMT_YUV422P16: @@ -624,16 +632,20 @@ FF_ENABLE_DEPRECATION_WARNINGS s->chroma_planes = 1; s->bits_per_raw_sample = 8; break; + case AV_PIX_FMT_RGBA64: + s->colorspace = 1; + s->transparency = 1; + s->chroma_planes = 1; + s->bits_per_raw_sample = 16; + s->use32bit = 1; + s->version = FFMAX(s->version, 1); + break; case AV_PIX_FMT_RGB48: s->colorspace = 1; s->chroma_planes = 1; s->bits_per_raw_sample = 16; s->use32bit = 1; s->version = FFMAX(s->version, 1); - if (avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { - av_log(avctx, AV_LOG_ERROR, "16bit RGB is experimental and under development, only use it for experiments\n"); - return AVERROR_INVALIDDATA; - } break; case AV_PIX_FMT_0RGB32: s->colorspace = 1; @@ -644,27 +656,27 @@ FF_ENABLE_DEPRECATION_WARNINGS if (!avctx->bits_per_raw_sample) s->bits_per_raw_sample = 9; case AV_PIX_FMT_GBRP10: + case AV_PIX_FMT_GBRAP10: if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) s->bits_per_raw_sample = 10; case AV_PIX_FMT_GBRP12: + case AV_PIX_FMT_GBRAP12: if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) s->bits_per_raw_sample = 12; case AV_PIX_FMT_GBRP14: if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) s->bits_per_raw_sample = 14; case AV_PIX_FMT_GBRP16: + case AV_PIX_FMT_GBRAP16: if (!avctx->bits_per_raw_sample && !s->bits_per_raw_sample) s->bits_per_raw_sample = 16; else if (!s->bits_per_raw_sample) s->bits_per_raw_sample = avctx->bits_per_raw_sample; + s->transparency = desc->nb_components == 4 || desc->nb_components == 2; s->colorspace = 1; s->chroma_planes = 1; if (s->bits_per_raw_sample >= 16) { s->use32bit = 1; - if (avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) { - av_log(avctx, AV_LOG_ERROR, "16bit RGB is experimental and under development, only use it for experiments\n"); - return AVERROR_INVALIDDATA; - } } s->version = FFMAX(s->version, 1); break; @@ -681,9 +693,6 @@ FF_ENABLE_DEPRECATION_WARNINGS s->ac = AC_RANGE_CUSTOM_TAB; } } - if (s->transparency) { - av_log(avctx, AV_LOG_WARNING, "Storing alpha plane, this will require a recent FFV1 decoder to playback!\n"); - } #if FF_API_PRIVATE_OPT FF_DISABLE_DEPRECATION_WARNINGS if (avctx->context_model) @@ -754,7 +763,10 @@ FF_ENABLE_DEPRECATION_WARNINGS if (!s->chroma_planes && s->version > 3) s->plane_count--; - avcodec_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_h_shift, &s->chroma_v_shift); + ret = av_pix_fmt_get_chroma_sub_sample (avctx->pix_fmt, &s->chroma_h_shift, &s->chroma_v_shift); + if (ret) + return ret; + s->picture_number = 0; if (avctx->flags & (AV_CODEC_FLAG_PASS1 | AV_CODEC_FLAG_PASS2)) { @@ -1029,9 +1041,10 @@ static int encode_slice(AVCodecContext *c, void *arg) const int ps = av_pix_fmt_desc_get(c->pix_fmt)->comp[0].step; int ret; RangeCoder c_bak = fs->c; - const uint8_t *planes[3] = {p->data[0] + ps*x + y*p->linesize[0], + const uint8_t *planes[4] = {p->data[0] + ps*x + y*p->linesize[0], p->data[1] ? p->data[1] + ps*x + y*p->linesize[1] : NULL, - p->data[2] ? p->data[2] + ps*x + y*p->linesize[2] : NULL}; + p->data[2] ? p->data[2] + ps*x + y*p->linesize[2] : NULL, + p->data[3] ? p->data[3] + ps*x + y*p->linesize[3] : NULL}; fs->slice_coding_mode = 0; if (f->version > 3) { @@ -1320,9 +1333,14 @@ AVCodec ff_ffv1_encoder = { AV_PIX_FMT_YUVA444P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_GRAY16, AV_PIX_FMT_GRAY8, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, + AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_YA8, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GBRP16, AV_PIX_FMT_RGB48, + AV_PIX_FMT_GBRAP16, AV_PIX_FMT_RGBA64, + AV_PIX_FMT_GRAY9, + AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14, + AV_PIX_FMT_YUV440P10, AV_PIX_FMT_YUV440P12, AV_PIX_FMT_NONE }, diff --git a/libavcodec/ffv1enc_template.c b/libavcodec/ffv1enc_template.c index b7eea0dd700dc..bc0add5ed7c23 100644 --- a/libavcodec/ffv1enc_template.c +++ b/libavcodec/ffv1enc_template.c @@ -122,8 +122,8 @@ static av_always_inline int RENAME(encode_line)(FFV1Context *s, int w, return 0; } -static int RENAME(encode_rgb_frame)(FFV1Context *s, const uint8_t *src[3], - int w, int h, const int stride[3]) +static int RENAME(encode_rgb_frame)(FFV1Context *s, const uint8_t *src[4], + int w, int h, const int stride[4]) { int x, y, p, i; const int ring_size = s->context_model ? 3 : 2; @@ -132,6 +132,8 @@ static int RENAME(encode_rgb_frame)(FFV1Context *s, const uint8_t *src[3], int packed = !src[1]; int bits = s->bits_per_raw_sample > 0 ? s->bits_per_raw_sample : 8; int offset = 1 << bits; + int transparency = s->transparency; + int packed_size = (3 + transparency)*2; s->run_index = 0; @@ -152,14 +154,18 @@ static int RENAME(encode_rgb_frame)(FFV1Context *s, const uint8_t *src[3], r = (v >> 16) & 0xFF; a = v >> 24; } else if (packed) { - const uint16_t *p = ((const uint16_t*)(src[0] + x*6 + stride[0]*y)); + const uint16_t *p = ((const uint16_t*)(src[0] + x*packed_size + stride[0]*y)); r = p[0]; g = p[1]; b = p[2]; - } else if (sizeof(TYPE) == 4) { + if (transparency) + a = p[3]; + } else if (sizeof(TYPE) == 4 || transparency) { g = *((const uint16_t *)(src[0] + x*2 + stride[0]*y)); b = *((const uint16_t *)(src[1] + x*2 + stride[1]*y)); r = *((const uint16_t *)(src[2] + x*2 + stride[2]*y)); + if (transparency) + a = *((const uint16_t *)(src[3] + x*2 + stride[3]*y)); } else { b = *((const uint16_t *)(src[0] + x*2 + stride[0]*y)); g = *((const uint16_t *)(src[1] + x*2 + stride[1]*y)); @@ -179,7 +185,7 @@ static int RENAME(encode_rgb_frame)(FFV1Context *s, const uint8_t *src[3], sample[2][0][x] = r; sample[3][0][x] = a; } - for (p = 0; p < 3 + s->transparency; p++) { + for (p = 0; p < 3 + transparency; p++) { int ret; sample[p][0][-1] = sample[p][1][0 ]; sample[p][1][ w] = sample[p][1][w-1]; diff --git a/libavcodec/filter_units_bsf.c b/libavcodec/filter_units_bsf.c new file mode 100644 index 0000000000000..1ee0afdf2b636 --- /dev/null +++ b/libavcodec/filter_units_bsf.c @@ -0,0 +1,256 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/common.h" +#include "libavutil/opt.h" + +#include "bsf.h" +#include "cbs.h" + + +typedef struct FilterUnitsContext { + const AVClass *class; + + CodedBitstreamContext *cbc; + CodedBitstreamFragment fragment; + + const char *pass_types; + const char *remove_types; + + enum { + NOOP, + PASS, + REMOVE, + } mode; + CodedBitstreamUnitType *type_list; + int nb_types; +} FilterUnitsContext; + + +static int filter_units_make_type_list(const char *list_string, + CodedBitstreamUnitType **type_list, + int *nb_types) +{ + CodedBitstreamUnitType *list = NULL; + int pass, count; + + for (pass = 1; pass <= 2; pass++) { + long value, range_start, range_end; + const char *str; + char *value_end; + + count = 0; + for (str = list_string; *str;) { + value = strtol(str, &value_end, 0); + if (str == value_end) + goto invalid; + str = (const char *)value_end; + if (*str == '-') { + ++str; + range_start = value; + range_end = strtol(str, &value_end, 0); + if (str == value_end) + goto invalid; + + for (value = range_start; value < range_end; value++) { + if (pass == 2) + list[count] = value; + ++count; + } + } else { + if (pass == 2) + list[count] = value; + ++count; + } + if (*str == '|') + ++str; + } + if (pass == 1) { + list = av_malloc_array(count, sizeof(*list)); + if (!list) + return AVERROR(ENOMEM); + } + } + + *type_list = list; + *nb_types = count; + return 0; + +invalid: + av_freep(&list); + return AVERROR(EINVAL); +} + +static int filter_units_filter(AVBSFContext *bsf, AVPacket *out) +{ + FilterUnitsContext *ctx = bsf->priv_data; + CodedBitstreamFragment *frag = &ctx->fragment; + AVPacket *in = NULL; + int err, i, j; + + while (1) { + err = ff_bsf_get_packet(bsf, &in); + if (err < 0) + return err; + + if (ctx->mode == NOOP) { + av_packet_move_ref(out, in); + av_packet_free(&in); + return 0; + } + + err = ff_cbs_read_packet(ctx->cbc, frag, in); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read packet.\n"); + goto fail; + } + + for (i = 0; i < frag->nb_units; i++) { + for (j = 0; j < ctx->nb_types; j++) { + if (frag->units[i].type == ctx->type_list[j]) + break; + } + if (ctx->mode == REMOVE ? j < ctx->nb_types + : j >= ctx->nb_types) { + ff_cbs_delete_unit(ctx->cbc, frag, i); + --i; + } + } + + if (frag->nb_units > 0) + break; + + // Don't return packets with nothing in them. + av_packet_free(&in); + ff_cbs_fragment_uninit(ctx->cbc, frag); + } + + err = ff_cbs_write_packet(ctx->cbc, out, frag); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to write packet.\n"); + goto fail; + } + + err = av_packet_copy_props(out, in); + if (err < 0) + goto fail; + +fail: + ff_cbs_fragment_uninit(ctx->cbc, frag); + av_packet_free(&in); + + return err; +} + +static int filter_units_init(AVBSFContext *bsf) +{ + FilterUnitsContext *ctx = bsf->priv_data; + int err; + + if (ctx->pass_types && ctx->remove_types) { + av_log(bsf, AV_LOG_ERROR, "Exactly one of pass_types or " + "remove_types is required.\n"); + return AVERROR(EINVAL); + } + + if (ctx->pass_types) { + ctx->mode = PASS; + err = filter_units_make_type_list(ctx->pass_types, + &ctx->type_list, &ctx->nb_types); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to parse pass_types.\n"); + return err; + } + } else if (ctx->remove_types) { + ctx->mode = REMOVE; + err = filter_units_make_type_list(ctx->remove_types, + &ctx->type_list, &ctx->nb_types); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to parse remove_types.\n"); + return err; + } + } else { + return 0; + } + + err = ff_cbs_init(&ctx->cbc, bsf->par_in->codec_id, bsf); + if (err < 0) + return err; + + // Don't actually decompose anything, we only want the unit data. + ctx->cbc->decompose_unit_types = ctx->type_list; + ctx->cbc->nb_decompose_unit_types = 0; + + if (bsf->par_in->extradata) { + CodedBitstreamFragment ps; + + err = ff_cbs_read_extradata(ctx->cbc, &ps, bsf->par_in); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read extradata.\n"); + } else { + err = ff_cbs_write_extradata(ctx->cbc, bsf->par_out, &ps); + if (err < 0) + av_log(bsf, AV_LOG_ERROR, "Failed to write extradata.\n"); + } + + ff_cbs_fragment_uninit(ctx->cbc, &ps); + } + + return err; +} + +static void filter_units_close(AVBSFContext *bsf) +{ + FilterUnitsContext *ctx = bsf->priv_data; + + av_freep(&ctx->type_list); + + ff_cbs_close(&ctx->cbc); +} + +#define OFFSET(x) offsetof(FilterUnitsContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM) +static const AVOption filter_units_options[] = { + { "pass_types", "List of unit types to pass through the filter.", + OFFSET(pass_types), AV_OPT_TYPE_STRING, + { .str = NULL }, .flags = FLAGS }, + { "remove_types", "List of unit types to remove in the filter.", + OFFSET(remove_types), AV_OPT_TYPE_STRING, + { .str = NULL }, .flags = FLAGS }, + + { NULL } +}; + +static const AVClass filter_units_class = { + .class_name = "filter_units", + .item_name = av_default_item_name, + .option = filter_units_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const AVBitStreamFilter ff_filter_units_bsf = { + .name = "filter_units", + .priv_data_size = sizeof(FilterUnitsContext), + .priv_class = &filter_units_class, + .init = &filter_units_init, + .close = &filter_units_close, + .filter = &filter_units_filter, + .codec_ids = ff_cbs_all_codec_ids, +}; diff --git a/libavcodec/flacdec.c b/libavcodec/flacdec.c index 581c73efc806d..c8eb456049db0 100644 --- a/libavcodec/flacdec.c +++ b/libavcodec/flacdec.c @@ -220,20 +220,27 @@ static int get_metadata_size(const uint8_t *buf, int buf_size) static int decode_residuals(FLACContext *s, int32_t *decoded, int pred_order) { + GetBitContext gb = s->gb; int i, tmp, partition, method_type, rice_order; int rice_bits, rice_esc; int samples; - method_type = get_bits(&s->gb, 2); + method_type = get_bits(&gb, 2); + rice_order = get_bits(&gb, 4); + + samples = s->blocksize >> rice_order; + rice_bits = 4 + method_type; + rice_esc = (1 << rice_bits) - 1; + + decoded += pred_order; + i = pred_order; + if (method_type > 1) { av_log(s->avctx, AV_LOG_ERROR, "illegal residual coding method %d\n", method_type); return AVERROR_INVALIDDATA; } - rice_order = get_bits(&s->gb, 4); - - samples= s->blocksize >> rice_order; if (samples << rice_order != s->blocksize) { av_log(s->avctx, AV_LOG_ERROR, "invalid rice order: %i blocksize %i\n", rice_order, s->blocksize); @@ -246,21 +253,16 @@ static int decode_residuals(FLACContext *s, int32_t *decoded, int pred_order) return AVERROR_INVALIDDATA; } - rice_bits = 4 + method_type; - rice_esc = (1 << rice_bits) - 1; - - decoded += pred_order; - i= pred_order; for (partition = 0; partition < (1 << rice_order); partition++) { - tmp = get_bits(&s->gb, rice_bits); + tmp = get_bits(&gb, rice_bits); if (tmp == rice_esc) { - tmp = get_bits(&s->gb, 5); + tmp = get_bits(&gb, 5); for (; i < samples; i++) - *decoded++ = get_sbits_long(&s->gb, tmp); + *decoded++ = get_sbits_long(&gb, tmp); } else { int real_limit = tmp ? (INT_MAX >> tmp) + 2 : INT_MAX; for (; i < samples; i++) { - int v = get_sr_golomb_flac(&s->gb, tmp, real_limit, 0); + int v = get_sr_golomb_flac(&gb, tmp, real_limit, 0); if (v == 0x80000000){ av_log(s->avctx, AV_LOG_ERROR, "invalid residual\n"); return AVERROR_INVALIDDATA; @@ -272,6 +274,8 @@ static int decode_residuals(FLACContext *s, int32_t *decoded, int pred_order) i= 0; } + s->gb = gb; + return 0; } @@ -298,7 +302,7 @@ static int decode_subframe_fixed(FLACContext *s, int32_t *decoded, if (pred_order > 2) c = b - decoded[pred_order-2] + decoded[pred_order-3]; if (pred_order > 3) - d = c - decoded[pred_order-2] + 2*decoded[pred_order-3] - decoded[pred_order-4]; + d = c - decoded[pred_order-2] + 2U*decoded[pred_order-3] - decoded[pred_order-4]; switch (pred_order) { case 0: @@ -456,7 +460,7 @@ static inline int decode_subframe(FLACContext *s, int channel) return AVERROR_INVALIDDATA; } - if (wasted) { + if (wasted && wasted < 32) { int i; for (i = 0; i < s->blocksize; i++) decoded[i] = (unsigned)decoded[i] << wasted; diff --git a/libavcodec/fmvc.c b/libavcodec/fmvc.c index 74e9bdd8a088d..a06b90c6fe24f 100644 --- a/libavcodec/fmvc.c +++ b/libavcodec/fmvc.c @@ -44,11 +44,11 @@ typedef struct FMVCContext { size_t buffer_size; uint8_t *pbuffer; size_t pbuffer_size; - int stride; + ptrdiff_t stride; int bpp; int yb, xb; InterBlock *blocks; - int nb_blocks; + unsigned nb_blocks; } FMVCContext; static int decode_type2(GetByteContext *gb, PutByteContext *pb) @@ -150,7 +150,7 @@ static int decode_type2(GetByteContext *gb, PutByteContext *pb) if (opcode >= 0x40) { bytestream2_skip(gb, 1); pos = - ((opcode >> 2) & 7) - 1 - 8 * bytestream2_get_byte(gb); - len = (opcode >> 5) - 1; + len = (opcode >> 5) - 1; bytestream2_init(&gbc, pb->buffer_start, pb->buffer_end - pb->buffer_start); bytestream2_seek(&gbc, bytestream2_tell_p(pb) + pos, SEEK_SET); @@ -305,7 +305,7 @@ static int decode_type1(GetByteContext *gb, PutByteContext *pb) break; opcode = bytestream2_get_byte(gb); if (opcode < 0xF8) { - opcode = opcode + 32; + opcode += 32; break; } i = opcode - 0xF8; @@ -393,9 +393,8 @@ static int decode_type1(GetByteContext *gb, PutByteContext *pb) return 0; } -static int decode_frame(AVCodecContext *avctx, - void *data, int *got_frame, - AVPacket *avpkt) +static int decode_frame(AVCodecContext *avctx, void *data, + int *got_frame, AVPacket *avpkt) { FMVCContext *s = avctx->priv_data; GetByteContext *gb = &s->gb; @@ -414,7 +413,7 @@ static int decode_frame(AVCodecContext *avctx, if (frame->key_frame) { const uint8_t *src; - int type, size; + unsigned type, size; uint8_t *dst; type = bytestream2_get_le16(gb); @@ -428,7 +427,7 @@ static int decode_frame(AVCodecContext *avctx, } else if (type == 2){ decode_type2(gb, pb); } else { - avpriv_report_missing_feature(avctx, "compression %d", type); + avpriv_report_missing_feature(avctx, "Compression type %d", type); return AVERROR_PATCHWELCOME; } @@ -440,7 +439,8 @@ static int decode_frame(AVCodecContext *avctx, src += s->stride * 4; } } else { - int block, nb_blocks, type, k, l; + unsigned block, nb_blocks; + int type, k, l; uint8_t *ssrc, *ddst; const uint32_t *src; uint32_t *dst; @@ -456,7 +456,8 @@ static int decode_frame(AVCodecContext *avctx, type = bytestream2_get_le16(gb); for (block = 0; block < nb_blocks; block++) { - int size, offset, start = 0; + unsigned size, offset; + int start = 0; offset = bytestream2_get_le16(gb); if (offset >= s->nb_blocks) @@ -472,7 +473,7 @@ static int decode_frame(AVCodecContext *avctx, } else if (type == 2){ decode_type2(gb, pb); } else { - avpriv_report_missing_feature(avctx, "compression %d", type); + avpriv_report_missing_feature(avctx, "Compression type %d", type); return AVERROR_PATCHWELCOME; } @@ -497,9 +498,8 @@ static int decode_frame(AVCodecContext *avctx, if (s->blocks[block].xor) { for (k = 0; k < block_h; k++) { uint32_t *column = dst; - for (l = 0; l < block_w; l++) { + for (l = 0; l < block_w; l++) *dst++ ^= *src++; - } dst = &column[s->stride]; } } @@ -529,17 +529,24 @@ static av_cold int decode_init(AVCodecContext *avctx) int i, j, m, block = 0, h = BLOCK_HEIGHT, w = BLOCK_WIDTH; switch (avctx->bits_per_coded_sample) { - case 16: avctx->pix_fmt = AV_PIX_FMT_RGB555; break; - case 24: avctx->pix_fmt = AV_PIX_FMT_BGR24; break; - case 32: avctx->pix_fmt = AV_PIX_FMT_BGRA; break; + case 16: + avctx->pix_fmt = AV_PIX_FMT_RGB555; + break; + case 24: + avctx->pix_fmt = AV_PIX_FMT_BGR24; + break; + case 32: + avctx->pix_fmt = AV_PIX_FMT_BGRA; + break; default: - av_log(avctx, AV_LOG_ERROR, "Unsupported bitdepth %i\n", avctx->bits_per_coded_sample); + av_log(avctx, AV_LOG_ERROR, "Unsupported bitdepth %i\n", + avctx->bits_per_coded_sample); return AVERROR_INVALIDDATA; } s->stride = (avctx->width * avctx->bits_per_coded_sample + 31) / 32; - s->xb = s->stride / BLOCK_WIDTH; - m = s->stride % BLOCK_WIDTH; + s->xb = s->stride / BLOCK_WIDTH; + m = s->stride % BLOCK_WIDTH; if (m) { if (m < 37) { w = m + BLOCK_WIDTH; @@ -550,7 +557,7 @@ static av_cold int decode_init(AVCodecContext *avctx) } s->yb = avctx->height / BLOCK_HEIGHT; - m = avctx->height % BLOCK_HEIGHT; + m = avctx->height % BLOCK_HEIGHT; if (m) { if (m < 49) { h = m + BLOCK_HEIGHT; @@ -563,8 +570,7 @@ static av_cold int decode_init(AVCodecContext *avctx) s->nb_blocks = s->xb * s->yb; if (!s->nb_blocks) return AVERROR_INVALIDDATA; - - s->blocks = av_calloc(s->nb_blocks, sizeof(*s->blocks)); + s->blocks = av_calloc(s->nb_blocks, sizeof(*s->blocks)); if (!s->blocks) return AVERROR(ENOMEM); @@ -572,32 +578,32 @@ static av_cold int decode_init(AVCodecContext *avctx) for (j = 0; j < s->xb; j++) { if (i != (s->yb - 1) || j != (s->xb - 1)) { if (i == s->yb - 1) { - s->blocks[block].w = BLOCK_WIDTH; - s->blocks[block].h = h; + s->blocks[block].w = BLOCK_WIDTH; + s->blocks[block].h = h; s->blocks[block].size = BLOCK_WIDTH * h; } else if (j == s->xb - 1) { - s->blocks[block].w = w; - s->blocks[block].h = BLOCK_HEIGHT; + s->blocks[block].w = w; + s->blocks[block].h = BLOCK_HEIGHT; s->blocks[block].size = BLOCK_HEIGHT * w; } else { - s->blocks[block].w = BLOCK_WIDTH; - s->blocks[block].h = BLOCK_HEIGHT; + s->blocks[block].w = BLOCK_WIDTH; + s->blocks[block].h = BLOCK_HEIGHT; s->blocks[block].size = BLOCK_WIDTH * BLOCK_HEIGHT; } } else { - s->blocks[block].w = w; - s->blocks[block].h = h; + s->blocks[block].w = w; + s->blocks[block].h = h; s->blocks[block].size = w * h; } block++; } } - s->bpp = avctx->bits_per_coded_sample >> 3; - s->buffer_size = avctx->width * avctx->height * 4; + s->bpp = avctx->bits_per_coded_sample >> 3; + s->buffer_size = avctx->width * avctx->height * 4; s->pbuffer_size = avctx->width * avctx->height * 4; - s->buffer = av_mallocz(s->buffer_size); - s->pbuffer = av_mallocz(s->pbuffer_size); + s->buffer = av_mallocz(s->buffer_size); + s->pbuffer = av_mallocz(s->pbuffer_size); if (!s->buffer || !s->pbuffer) return AVERROR(ENOMEM); diff --git a/libavcodec/frame_thread_encoder.c b/libavcodec/frame_thread_encoder.c index 215aee9fc06f6..5ff3f7863cb03 100644 --- a/libavcodec/frame_thread_encoder.c +++ b/libavcodec/frame_thread_encoder.c @@ -92,7 +92,7 @@ static void * attribute_align_arg worker(void *v){ pthread_mutex_unlock(&c->buffer_mutex); av_frame_free(&frame); if(got_packet) { - int ret2 = av_dup_packet(pkt); + int ret2 = av_packet_make_refcounted(pkt); if (ret >= 0 && ret2 < 0) ret = ret2; } else { diff --git a/libavcodec/g2meet.c b/libavcodec/g2meet.c index 842095ba3b40d..a46157218f23b 100644 --- a/libavcodec/g2meet.c +++ b/libavcodec/g2meet.c @@ -28,6 +28,7 @@ #include #include +#include "libavutil/imgutils.h" #include "libavutil/intreadwrite.h" #include "avcodec.h" @@ -1451,7 +1452,8 @@ static int g2m_decode_frame(AVCodecContext *avctx, void *data, c->tile_height = bytestream2_get_be32(&bc); if (c->tile_width <= 0 || c->tile_height <= 0 || ((c->tile_width | c->tile_height) & 0xF) || - c->tile_width * (uint64_t)c->tile_height >= INT_MAX / 4 + c->tile_width * (uint64_t)c->tile_height >= INT_MAX / 4 || + av_image_check_size2(c->tile_width, c->tile_height, avctx->max_pixels, avctx->pix_fmt, 0, avctx) < 0 ) { av_log(avctx, AV_LOG_ERROR, "Invalid tile dimensions %dx%d\n", diff --git a/libavcodec/gdv.c b/libavcodec/gdv.c index dc91869edf94e..e52a637610a54 100644 --- a/libavcodec/gdv.c +++ b/libavcodec/gdv.c @@ -409,17 +409,20 @@ static int gdv_decode_frame(AVCodecContext *avctx, void *data, unsigned flags; uint8_t *dst; - if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) - return ret; - if (pal && pal_size == AVPALETTE_SIZE) - memcpy(gdv->pal, pal, AVPALETTE_SIZE); - bytestream2_init(gb, avpkt->data, avpkt->size); bytestream2_init_writer(pb, gdv->frame, gdv->frame_size); flags = bytestream2_get_le32(gb); compression = flags & 0xF; + if (compression == 4 || compression == 7 || compression > 8) + return AVERROR_INVALIDDATA; + + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + if (pal && pal_size == AVPALETTE_SIZE) + memcpy(gdv->pal, pal, AVPALETTE_SIZE); + rescale(gdv, gdv->frame, avctx->width, avctx->height, !!(flags & 0x10), !!(flags & 0x20)); @@ -451,7 +454,7 @@ static int gdv_decode_frame(AVCodecContext *avctx, void *data, ret = decompress_68(avctx, flags >> 8, 1); break; default: - return AVERROR_INVALIDDATA; + av_assert0(0); } memcpy(frame->data[1], gdv->pal, AVPALETTE_SIZE); diff --git a/libavcodec/get_bits.h b/libavcodec/get_bits.h index c530015169e1c..56ef5f0cbe197 100644 --- a/libavcodec/get_bits.h +++ b/libavcodec/get_bits.h @@ -32,6 +32,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/log.h" #include "libavutil/avassert.h" +#include "avcodec.h" #include "mathops.h" #include "vlc.h" @@ -201,6 +202,13 @@ static inline int get_bits_count(const GetBitContext *s) return s->index; } +/** + * Skips the specified number of bits. + * @param n the number of bits to skip, + * For the UNCHECKED_BITSTREAM_READER this must not cause the distance + * from the start to overflow int32_t. Staying within the bitstream + padding + * is sufficient, too. + */ static inline void skip_bits_long(GetBitContext *s, int n) { #if UNCHECKED_BITSTREAM_READER @@ -428,7 +436,7 @@ static inline int init_get_bits(GetBitContext *s, const uint8_t *buffer, int buffer_size; int ret = 0; - if (bit_size >= INT_MAX - 7 || bit_size < 0 || !buffer) { + if (bit_size >= INT_MAX - FFMAX(7, AV_INPUT_BUFFER_PADDING_SIZE*8) || bit_size < 0 || !buffer) { bit_size = 0; buffer = NULL; ret = AVERROR_INVALIDDATA; @@ -550,6 +558,7 @@ static inline const uint8_t *align_get_bits(GetBitContext *s) * @param max_depth is the number of times bits bits must be read to completely * read the longest vlc code * = (max_vlc_length + bits - 1) / bits + * @returns the code parsed or -1 if no vlc matches */ static av_always_inline int get_vlc2(GetBitContext *s, VLC_TYPE (*table)[2], int bits, int max_depth) diff --git a/libavcodec/h263.h b/libavcodec/h263.h index d154d36632aef..f891f72379228 100644 --- a/libavcodec/h263.h +++ b/libavcodec/h263.h @@ -27,9 +27,7 @@ #include "h263data.h" #include "rl.h" -#if !FF_API_ASPECT_EXTENDED #define FF_ASPECT_EXTENDED 15 -#endif #define INT_BIT (CHAR_BIT * sizeof(int)) // The defines below define the number of bits that are read at once for diff --git a/libavcodec/h263dec.c b/libavcodec/h263dec.c index bcb2b08bb0f38..484bf39578a0f 100644 --- a/libavcodec/h263dec.c +++ b/libavcodec/h263dec.c @@ -33,6 +33,7 @@ #include "flv.h" #include "h263.h" #include "h263_parser.h" +#include "hwaccel.h" #include "internal.h" #include "mpeg_er.h" #include "mpeg4video.h" @@ -41,12 +42,17 @@ #include "mpegvideo.h" #include "msmpeg4.h" #include "qpeldsp.h" -#include "vdpau_compat.h" #include "thread.h" #include "wmv2.h" static enum AVPixelFormat h263_get_format(AVCodecContext *avctx) { + /* MPEG-4 Studio Profile only, not supported by hardware */ + if (avctx->bits_per_raw_sample > 8) { + av_assert1(avctx->profile == FF_PROFILE_MPEG4_SIMPLE_STUDIO); + return avctx->pix_fmt; + } + if (avctx->codec->id == AV_CODEC_ID_MSS2) return AV_PIX_FMT_YUV420P; @@ -197,6 +203,11 @@ static int decode_slice(MpegEncContext *s) ff_set_qscale(s, s->qscale); + if (s->studio_profile) { + if ((ret = ff_mpeg4_decode_studio_slice_header(s->avctx->priv_data)) < 0) + return ret; + } + if (s->avctx->hwaccel) { const uint8_t *start = s->gb.buffer + get_bits_count(&s->gb) / 8; ret = s->avctx->hwaccel->decode_slice(s->avctx, start, s->gb.buffer_end - start); @@ -603,13 +614,6 @@ int ff_h263_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, if (!s->divx_packed) ff_thread_finish_setup(avctx); -#if FF_API_CAP_VDPAU - if (CONFIG_MPEG4_VDPAU_DECODER && (s->avctx->codec->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU)) { - ff_vdpau_mpeg4_decode_picture(avctx->priv_data, s->gb.buffer, s->gb.buffer_end - s->gb.buffer); - goto frame_end; - } -#endif - if (avctx->hwaccel) { ret = avctx->hwaccel->start_frame(avctx, s->gb.buffer, s->gb.buffer_end - s->gb.buffer); @@ -722,6 +726,9 @@ const enum AVPixelFormat ff_h263_hwaccel_pixfmt_list_420[] = { #if CONFIG_H263_VAAPI_HWACCEL || CONFIG_MPEG4_VAAPI_HWACCEL AV_PIX_FMT_VAAPI, #endif +#if CONFIG_MPEG4_NVDEC_HWACCEL + AV_PIX_FMT_CUDA, +#endif #if CONFIG_MPEG4_VDPAU_HWACCEL AV_PIX_FMT_VDPAU, #endif @@ -764,4 +771,16 @@ AVCodec ff_h263p_decoder = { .flush = ff_mpeg_flush, .max_lowres = 3, .pix_fmts = ff_h263_hwaccel_pixfmt_list_420, + .hw_configs = (const AVCodecHWConfigInternal*[]) { +#if CONFIG_H263_VAAPI_HWACCEL + HWACCEL_VAAPI(h263), +#endif +#if CONFIG_MPEG4_VDPAU_HWACCEL + HWACCEL_VDPAU(mpeg4), +#endif +#if CONFIG_H263_VIDEOTOOLBOX_HWACCEL + HWACCEL_VIDEOTOOLBOX(h263), +#endif + NULL + }, }; diff --git a/libavcodec/h264.h b/libavcodec/h264.h index 86df5eb9b3fc2..650580bf3adec 100644 --- a/libavcodec/h264.h +++ b/libavcodec/h264.h @@ -44,4 +44,49 @@ enum { H264_NAL_AUXILIARY_SLICE = 19, }; + +enum { + // 7.4.2.1.1: seq_parameter_set_id is in [0, 31]. + H264_MAX_SPS_COUNT = 32, + // 7.4.2.2: pic_parameter_set_id is in [0, 255]. + H264_MAX_PPS_COUNT = 256, + + // A.3: MaxDpbFrames is bounded above by 16. + H264_MAX_DPB_FRAMES = 16, + // 7.4.2.1.1: max_num_ref_frames is in [0, MaxDpbFrames], and + // each reference frame can have two fields. + H264_MAX_REFS = 2 * H264_MAX_DPB_FRAMES, + + // 7.4.3.1: modification_of_pic_nums_idc is not equal to 3 at most + // num_ref_idx_lN_active_minus1 + 1 times (that is, once for each + // possible reference), then equal to 3 once. + H264_MAX_RPLM_COUNT = H264_MAX_REFS + 1, + + // 7.4.3.3: in the worst case, we begin with a full short-term + // reference picture list. Each picture in turn is moved to the + // long-term list (type 3) and then discarded from there (type 2). + // Then, we set the length of the long-term list (type 4), mark + // the current picture as long-term (type 6) and terminate the + // process (type 0). + H264_MAX_MMCO_COUNT = H264_MAX_REFS * 2 + 3, + + // A.2.1, A.2.3: profiles supporting FMO constrain + // num_slice_groups_minus1 to be in [0, 7]. + H264_MAX_SLICE_GROUPS = 8, + + // E.2.2: cpb_cnt_minus1 is in [0, 31]. + H264_MAX_CPB_CNT = 32, + + // A.3: in table A-1 the highest level allows a MaxFS of 139264. + H264_MAX_MB_PIC_SIZE = 139264, + // A.3.1, A.3.2: PicWidthInMbs and PicHeightInMbs are constrained + // to be not greater than sqrt(MaxFS * 8). Hence height/width are + // bounded above by sqrt(139264 * 8) = 1055.5 macroblocks. + H264_MAX_MB_WIDTH = 1055, + H264_MAX_MB_HEIGHT = 1055, + H264_MAX_WIDTH = H264_MAX_MB_WIDTH * 16, + H264_MAX_HEIGHT = H264_MAX_MB_HEIGHT * 16, +}; + + #endif /* AVCODEC_H264_H */ diff --git a/libavcodec/h2645_parse.c b/libavcodec/h2645_parse.c index b0d9ff66f00f3..e6c40381b0904 100644 --- a/libavcodec/h2645_parse.c +++ b/libavcodec/h2645_parse.c @@ -26,15 +26,15 @@ #include "libavutil/intreadwrite.h" #include "libavutil/mem.h" +#include "bytestream.h" #include "hevc.h" #include "h2645_parse.h" int ff_h2645_extract_rbsp(const uint8_t *src, int length, - H2645NAL *nal, int small_padding) + H2645RBSP *rbsp, H2645NAL *nal, int small_padding) { int i, si, di; uint8_t *dst; - int64_t padding = small_padding ? 0 : MAX_MBPAIR_SIZE; nal->skipped_bytes = 0; #define STARTCODE_TEST \ @@ -91,11 +91,7 @@ int ff_h2645_extract_rbsp(const uint8_t *src, int length, } else if (i > length) i = length; - av_fast_padded_malloc(&nal->rbsp_buffer, &nal->rbsp_buffer_size, - length + padding); - if (!nal->rbsp_buffer) - return AVERROR(ENOMEM); - + nal->rbsp_buffer = &rbsp->rbsp_buffer[rbsp->rbsp_buffer_size]; dst = nal->rbsp_buffer; memcpy(dst, src, i); @@ -144,6 +140,8 @@ int ff_h2645_extract_rbsp(const uint8_t *src, int length, nal->size = di; nal->raw_data = src; nal->raw_size = si; + rbsp->rbsp_buffer_size += si; + return si; } @@ -247,60 +245,79 @@ static int h264_parse_nal_header(H2645NAL *nal, void *logctx) return 1; } +static int find_next_start_code(const uint8_t *buf, const uint8_t *next_avc) +{ + int i = 0; + + if (buf + 3 >= next_avc) + return next_avc - buf; + + while (buf + i + 3 < next_avc) { + if (buf[i] == 0 && buf[i + 1] == 0 && buf[i + 2] == 1) + break; + i++; + } + return i + 3; +} + int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, void *logctx, int is_nalff, int nal_length_size, enum AVCodecID codec_id, int small_padding) { + GetByteContext bc; int consumed, ret = 0; - const uint8_t *next_avc = is_nalff ? buf : buf + length; + int next_avc = is_nalff ? 0 : length; + int64_t padding = small_padding ? 0 : MAX_MBPAIR_SIZE; + bytestream2_init(&bc, buf, length); + av_fast_padded_malloc(&pkt->rbsp.rbsp_buffer, &pkt->rbsp.rbsp_buffer_alloc_size, length + padding); + if (!pkt->rbsp.rbsp_buffer) + return AVERROR(ENOMEM); + + pkt->rbsp.rbsp_buffer_size = 0; pkt->nb_nals = 0; - while (length >= 4) { + while (bytestream2_get_bytes_left(&bc) >= 4) { H2645NAL *nal; int extract_length = 0; int skip_trailing_zeros = 1; - if (buf == next_avc) { + if (bytestream2_tell(&bc) == next_avc) { int i = 0; extract_length = get_nalsize(nal_length_size, - buf, length, &i, logctx); + bc.buffer, bytestream2_get_bytes_left(&bc), &i, logctx); if (extract_length < 0) return extract_length; - buf += nal_length_size; - length -= nal_length_size; + bytestream2_skip(&bc, nal_length_size); - next_avc = buf + extract_length; + next_avc = bytestream2_tell(&bc) + extract_length; } else { - if (buf > next_avc) + int buf_index; + + if (bytestream2_tell(&bc) > next_avc) av_log(logctx, AV_LOG_WARNING, "Exceeded next NALFF position, re-syncing.\n"); /* search start code */ - while (buf[0] != 0 || buf[1] != 0 || buf[2] != 1) { - ++buf; - --length; - if (length < 4) { - if (pkt->nb_nals > 0) { - // No more start codes: we discarded some irrelevant - // bytes at the end of the packet. - return 0; - } else { - av_log(logctx, AV_LOG_ERROR, "No start code is found.\n"); - return AVERROR_INVALIDDATA; - } - } else if (buf >= (next_avc - 3)) - break; + buf_index = find_next_start_code(bc.buffer, buf + next_avc); + + bytestream2_skip(&bc, buf_index); + + if (!bytestream2_get_bytes_left(&bc)) { + if (pkt->nb_nals > 0) { + // No more start codes: we discarded some irrelevant + // bytes at the end of the packet. + return 0; + } else { + av_log(logctx, AV_LOG_ERROR, "No start code is found.\n"); + return AVERROR_INVALIDDATA; + } } - buf += 3; - length -= 3; - extract_length = FFMIN(length, next_avc - buf); + extract_length = FFMIN(bytestream2_get_bytes_left(&bc), next_avc - bytestream2_tell(&bc)); - if (buf >= next_avc) { + if (bytestream2_tell(&bc) >= next_avc) { /* skip to the start of the next NAL */ - int offset = next_avc - buf; - buf += offset; - length -= offset; + bytestream2_skip(&bc, next_avc - bytestream2_tell(&bc)); continue; } } @@ -326,7 +343,7 @@ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, } nal = &pkt->nals[pkt->nb_nals]; - consumed = ff_h2645_extract_rbsp(buf, extract_length, nal, small_padding); + consumed = ff_h2645_extract_rbsp(bc.buffer, extract_length, &pkt->rbsp, nal, small_padding); if (consumed < 0) return consumed; @@ -337,10 +354,11 @@ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, pkt->nb_nals++; + bytestream2_skip(&bc, consumed); + /* see commit 3566042a0 */ - if (consumed < length - 3 && - buf[consumed] == 0x00 && buf[consumed + 1] == 0x00 && - buf[consumed + 2] == 0x01 && buf[consumed + 3] == 0xE0) + if (bytestream2_get_bytes_left(&bc) >= 4 && + bytestream2_peek_be32(&bc) == 0x000001E0) skip_trailing_zeros = 0; nal->size_bits = get_bit_length(nal, skip_trailing_zeros); @@ -360,9 +378,6 @@ int ff_h2645_packet_split(H2645Packet *pkt, const uint8_t *buf, int length, } pkt->nb_nals--; } - - buf += consumed; - length -= consumed; } return 0; @@ -372,9 +387,10 @@ void ff_h2645_packet_uninit(H2645Packet *pkt) { int i; for (i = 0; i < pkt->nals_allocated; i++) { - av_freep(&pkt->nals[i].rbsp_buffer); av_freep(&pkt->nals[i].skipped_bytes_pos); } av_freep(&pkt->nals); pkt->nals_allocated = 0; + av_freep(&pkt->rbsp.rbsp_buffer); + pkt->rbsp.rbsp_buffer_alloc_size = pkt->rbsp.rbsp_buffer_size = 0; } diff --git a/libavcodec/h2645_parse.h b/libavcodec/h2645_parse.h index 5f3e17a0f258b..2e29ad26cbca5 100644 --- a/libavcodec/h2645_parse.h +++ b/libavcodec/h2645_parse.h @@ -30,7 +30,6 @@ typedef struct H2645NAL { uint8_t *rbsp_buffer; - int rbsp_buffer_size; int size; const uint8_t *data; @@ -65,9 +64,16 @@ typedef struct H2645NAL { int ref_idc; } H2645NAL; +typedef struct H2645RBSP { + uint8_t *rbsp_buffer; + int rbsp_buffer_alloc_size; + int rbsp_buffer_size; +} H2645RBSP; + /* an input packet split into unescaped NAL units */ typedef struct H2645Packet { H2645NAL *nals; + H2645RBSP rbsp; int nb_nals; int nals_allocated; } H2645Packet; @@ -75,7 +81,7 @@ typedef struct H2645Packet { /** * Extract the raw (unescaped) bitstream. */ -int ff_h2645_extract_rbsp(const uint8_t *src, int length, +int ff_h2645_extract_rbsp(const uint8_t *src, int length, H2645RBSP *rbsp, H2645NAL *nal, int small_padding); /** diff --git a/libavcodec/h264_cabac.c b/libavcodec/h264_cabac.c index 345834645cbfa..815149a501acb 100644 --- a/libavcodec/h264_cabac.c +++ b/libavcodec/h264_cabac.c @@ -1735,7 +1735,7 @@ decode_cabac_residual_internal(const H264Context *h, H264SliceContext *sl, \ if( coeff_abs >= 15 ) { \ int j = 0; \ - while (get_cabac_bypass(CC) && j < 30) { \ + while (get_cabac_bypass(CC) && j < 16+7) { \ j++; \ } \ \ @@ -2347,7 +2347,7 @@ int ff_h264_decode_mb_cabac(const H264Context *h, H264SliceContext *sl) if (CHROMA444(h) && IS_8x8DCT(mb_type)){ int i; uint8_t *nnz_cache = sl->non_zero_count_cache; - if (h->sei.unregistered.x264_build < 151U) { + if (h->x264_build < 151U) { for (i = 0; i < 2; i++){ if (sl->left_type[LEFT(i)] && !IS_8x8DCT(sl->left_type[LEFT(i)])) { nnz_cache[3+8* 1 + 2*8*i]= diff --git a/libavcodec/h264_cavlc.c b/libavcodec/h264_cavlc.c index 187b1c64e26aa..5e6a20304a564 100644 --- a/libavcodec/h264_cavlc.c +++ b/libavcodec/h264_cavlc.c @@ -1111,6 +1111,7 @@ int ff_h264_decode_mb_cavlc(const H264Context *h, H264SliceContext *sl) else sl->qscale -= max_qp+1; if (((unsigned)sl->qscale) > max_qp){ av_log(h->avctx, AV_LOG_ERROR, "dquant out of range (%d) at %d %d\n", dquant, sl->mb_x, sl->mb_y); + sl->qscale = max_qp; return -1; } } diff --git a/libavcodec/h264_direct.c b/libavcodec/h264_direct.c index a7a107c8c2163..ec9fca0350d4d 100644 --- a/libavcodec/h264_direct.c +++ b/libavcodec/h264_direct.c @@ -410,7 +410,7 @@ static void pred_spatial_direct_motion(const H264Context *const h, H264SliceCont (l1ref0[0] < 0 && !l1ref1[0] && FFABS(l1mv1[0][0]) <= 1 && FFABS(l1mv1[0][1]) <= 1 && - h->sei.unregistered.x264_build > 33U))) { + h->x264_build > 33U))) { a = b = 0; if (ref[0] > 0) a = mv[0]; @@ -445,7 +445,7 @@ static void pred_spatial_direct_motion(const H264Context *const h, H264SliceCont (l1ref0[i8] == 0 || (l1ref0[i8] < 0 && l1ref1[i8] == 0 && - h->sei.unregistered.x264_build > 33U))) { + h->x264_build > 33U))) { const int16_t (*l1mv)[2] = l1ref0[i8] == 0 ? l1mv0 : l1mv1; if (IS_SUB_8X8(sub_mb_type)) { const int16_t *mv_col = l1mv[x8 * 3 + y8 * 3 * b4_stride]; diff --git a/libavcodec/h264_mb.c b/libavcodec/h264_mb.c index cb9fe856b266a..3cd17b7e4bafd 100644 --- a/libavcodec/h264_mb.c +++ b/libavcodec/h264_mb.c @@ -637,7 +637,7 @@ static av_always_inline void hl_decode_mb_predict_luma(const H264Context *h, uint8_t *const ptr = dest_y + block_offset[i]; const int dir = sl->intra4x4_pred_mode_cache[scan8[i]]; if (transform_bypass && h->ps.sps->profile_idc == 244 && dir <= 1) { - if (h->sei.unregistered.x264_build < 151U) { + if (h->x264_build < 151U) { h->hpc.pred8x8l_add[dir](ptr, sl->mb + (i * 16 + p * 256 << pixel_shift), linesize); } else h->hpc.pred8x8l_filter_add[dir](ptr, sl->mb + (i * 16 + p * 256 << pixel_shift), diff --git a/libavcodec/h264_metadata_bsf.c b/libavcodec/h264_metadata_bsf.c new file mode 100644 index 0000000000000..27053dbdcfa4b --- /dev/null +++ b/libavcodec/h264_metadata_bsf.c @@ -0,0 +1,709 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avstring.h" +#include "libavutil/display.h" +#include "libavutil/common.h" +#include "libavutil/opt.h" + +#include "bsf.h" +#include "cbs.h" +#include "cbs_h264.h" +#include "h264.h" +#include "h264_sei.h" + +enum { + PASS, + INSERT, + REMOVE, + EXTRACT, +}; + +enum { + FLIP_HORIZONTAL = 1, + FLIP_VERTICAL = 2, +}; + +typedef struct H264MetadataContext { + const AVClass *class; + + CodedBitstreamContext *cbc; + CodedBitstreamFragment access_unit; + + int done_first_au; + + int aud; + + AVRational sample_aspect_ratio; + + int video_format; + int video_full_range_flag; + int colour_primaries; + int transfer_characteristics; + int matrix_coefficients; + + int chroma_sample_loc_type; + + AVRational tick_rate; + int fixed_frame_rate_flag; + + int crop_left; + int crop_right; + int crop_top; + int crop_bottom; + + const char *sei_user_data; + + int delete_filler; + + int display_orientation; + double rotate; + int flip; +} H264MetadataContext; + + +static int h264_metadata_update_sps(AVBSFContext *bsf, + H264RawSPS *sps) +{ + H264MetadataContext *ctx = bsf->priv_data; + int need_vui = 0; + int crop_unit_x, crop_unit_y; + + if (ctx->sample_aspect_ratio.num && ctx->sample_aspect_ratio.den) { + // Table E-1. + static const AVRational sar_idc[] = { + { 0, 0 }, // Unspecified (never written here). + { 1, 1 }, { 12, 11 }, { 10, 11 }, { 16, 11 }, + { 40, 33 }, { 24, 11 }, { 20, 11 }, { 32, 11 }, + { 80, 33 }, { 18, 11 }, { 15, 11 }, { 64, 33 }, + { 160, 99 }, { 4, 3 }, { 3, 2 }, { 2, 1 }, + }; + int num, den, i; + + av_reduce(&num, &den, ctx->sample_aspect_ratio.num, + ctx->sample_aspect_ratio.den, 65535); + + for (i = 1; i < FF_ARRAY_ELEMS(sar_idc); i++) { + if (num == sar_idc[i].num && + den == sar_idc[i].den) + break; + } + if (i == FF_ARRAY_ELEMS(sar_idc)) { + sps->vui.aspect_ratio_idc = 255; + sps->vui.sar_width = num; + sps->vui.sar_height = den; + } else { + sps->vui.aspect_ratio_idc = i; + } + sps->vui.aspect_ratio_info_present_flag = 1; + need_vui = 1; + } + +#define SET_OR_INFER(field, value, present_flag, infer) do { \ + if (value >= 0) { \ + field = value; \ + need_vui = 1; \ + } else if (!present_flag) \ + field = infer; \ + } while (0) + + if (ctx->video_format >= 0 || + ctx->video_full_range_flag >= 0 || + ctx->colour_primaries >= 0 || + ctx->transfer_characteristics >= 0 || + ctx->matrix_coefficients >= 0) { + + SET_OR_INFER(sps->vui.video_format, ctx->video_format, + sps->vui.video_signal_type_present_flag, 5); + + SET_OR_INFER(sps->vui.video_full_range_flag, + ctx->video_full_range_flag, + sps->vui.video_signal_type_present_flag, 0); + + if (ctx->colour_primaries >= 0 || + ctx->transfer_characteristics >= 0 || + ctx->matrix_coefficients >= 0) { + + SET_OR_INFER(sps->vui.colour_primaries, + ctx->colour_primaries, + sps->vui.colour_description_present_flag, 2); + + SET_OR_INFER(sps->vui.transfer_characteristics, + ctx->transfer_characteristics, + sps->vui.colour_description_present_flag, 2); + + SET_OR_INFER(sps->vui.matrix_coefficients, + ctx->matrix_coefficients, + sps->vui.colour_description_present_flag, 2); + + sps->vui.colour_description_present_flag = 1; + } + sps->vui.video_signal_type_present_flag = 1; + need_vui = 1; + } + + if (ctx->chroma_sample_loc_type >= 0) { + sps->vui.chroma_sample_loc_type_top_field = + ctx->chroma_sample_loc_type; + sps->vui.chroma_sample_loc_type_bottom_field = + ctx->chroma_sample_loc_type; + sps->vui.chroma_loc_info_present_flag = 1; + need_vui = 1; + } + + if (ctx->tick_rate.num && ctx->tick_rate.den) { + int num, den; + + av_reduce(&num, &den, ctx->tick_rate.num, ctx->tick_rate.den, + UINT32_MAX > INT_MAX ? UINT32_MAX : INT_MAX); + + sps->vui.time_scale = num; + sps->vui.num_units_in_tick = den; + + sps->vui.timing_info_present_flag = 1; + need_vui = 1; + } + SET_OR_INFER(sps->vui.fixed_frame_rate_flag, + ctx->fixed_frame_rate_flag, + sps->vui.timing_info_present_flag, 0); + + if (sps->separate_colour_plane_flag || sps->chroma_format_idc == 0) { + crop_unit_x = 1; + crop_unit_y = 2 - sps->frame_mbs_only_flag; + } else { + crop_unit_x = 1 + (sps->chroma_format_idc < 3); + crop_unit_y = (1 + (sps->chroma_format_idc < 2)) * + (2 - sps->frame_mbs_only_flag); + } +#define CROP(border, unit) do { \ + if (ctx->crop_ ## border >= 0) { \ + if (ctx->crop_ ## border % unit != 0) { \ + av_log(bsf, AV_LOG_ERROR, "Invalid value for crop_%s: " \ + "must be a multiple of %d.\n", #border, unit); \ + return AVERROR(EINVAL); \ + } \ + sps->frame_crop_ ## border ## _offset = \ + ctx->crop_ ## border / unit; \ + sps->frame_cropping_flag = 1; \ + } \ + } while (0) + CROP(left, crop_unit_x); + CROP(right, crop_unit_x); + CROP(top, crop_unit_y); + CROP(bottom, crop_unit_y); +#undef CROP + + if (need_vui) + sps->vui_parameters_present_flag = 1; + + return 0; +} + +static int h264_metadata_filter(AVBSFContext *bsf, AVPacket *out) +{ + H264MetadataContext *ctx = bsf->priv_data; + AVPacket *in = NULL; + CodedBitstreamFragment *au = &ctx->access_unit; + int err, i, j, has_sps; + uint8_t *displaymatrix_side_data = NULL; + size_t displaymatrix_side_data_size = 0; + + err = ff_bsf_get_packet(bsf, &in); + if (err < 0) + return err; + + err = ff_cbs_read_packet(ctx->cbc, au, in); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read packet.\n"); + goto fail; + } + + if (au->nb_units == 0) { + av_log(bsf, AV_LOG_ERROR, "No NAL units in packet.\n"); + err = AVERROR_INVALIDDATA; + goto fail; + } + + // If an AUD is present, it must be the first NAL unit. + if (au->units[0].type == H264_NAL_AUD) { + if (ctx->aud == REMOVE) + ff_cbs_delete_unit(ctx->cbc, au, 0); + } else { + if (ctx->aud == INSERT) { + static const int primary_pic_type_table[] = { + 0x084, // 2, 7 + 0x0a5, // 0, 2, 5, 7 + 0x0e7, // 0, 1, 2, 5, 6, 7 + 0x210, // 4, 9 + 0x318, // 3, 4, 8, 9 + 0x294, // 2, 4, 7, 9 + 0x3bd, // 0, 2, 3, 4, 5, 7, 8, 9 + 0x3ff, // 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 + }; + int primary_pic_type_mask = 0xff; + H264RawAUD aud = { + .nal_unit_header.nal_unit_type = H264_NAL_AUD, + }; + + for (i = 0; i < au->nb_units; i++) { + if (au->units[i].type == H264_NAL_SLICE || + au->units[i].type == H264_NAL_IDR_SLICE) { + H264RawSlice *slice = au->units[i].content; + for (j = 0; j < FF_ARRAY_ELEMS(primary_pic_type_table); j++) { + if (!(primary_pic_type_table[j] & + (1 << slice->header.slice_type))) + primary_pic_type_mask &= ~(1 << j); + } + } + } + for (j = 0; j < FF_ARRAY_ELEMS(primary_pic_type_table); j++) + if (primary_pic_type_mask & (1 << j)) + break; + if (j >= FF_ARRAY_ELEMS(primary_pic_type_table)) { + av_log(bsf, AV_LOG_ERROR, "No usable primary_pic_type: " + "invalid slice types?\n"); + err = AVERROR_INVALIDDATA; + goto fail; + } + + aud.primary_pic_type = j; + + err = ff_cbs_insert_unit_content(ctx->cbc, au, + 0, H264_NAL_AUD, &aud, NULL); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to insert AUD.\n"); + goto fail; + } + } + } + + has_sps = 0; + for (i = 0; i < au->nb_units; i++) { + if (au->units[i].type == H264_NAL_SPS) { + err = h264_metadata_update_sps(bsf, au->units[i].content); + if (err < 0) + goto fail; + has_sps = 1; + } + } + + // Only insert the SEI in access units containing SPSs, and also + // unconditionally in the first access unit we ever see. + if (ctx->sei_user_data && (has_sps || !ctx->done_first_au)) { + H264RawSEIPayload payload = { + .payload_type = H264_SEI_TYPE_USER_DATA_UNREGISTERED, + }; + H264RawSEIUserDataUnregistered *udu = + &payload.payload.user_data_unregistered; + + for (i = j = 0; j < 32 && ctx->sei_user_data[i]; i++) { + int c, v; + c = ctx->sei_user_data[i]; + if (c == '-') { + continue; + } else if (av_isxdigit(c)) { + c = av_tolower(c); + v = (c <= '9' ? c - '0' : c - 'a' + 10); + } else { + goto invalid_user_data; + } + if (i & 1) + udu->uuid_iso_iec_11578[j / 2] |= v; + else + udu->uuid_iso_iec_11578[j / 2] = v << 4; + ++j; + } + if (j == 32 && ctx->sei_user_data[i] == '+') { + size_t len = strlen(ctx->sei_user_data + i + 1); + + udu->data_ref = av_buffer_alloc(len + 1); + if (!udu->data_ref) { + err = AVERROR(ENOMEM); + goto fail; + } + + udu->data = udu->data_ref->data; + udu->data_length = len + 1; + memcpy(udu->data, ctx->sei_user_data + i + 1, len + 1); + + payload.payload_size = 16 + udu->data_length; + + err = ff_cbs_h264_add_sei_message(ctx->cbc, au, &payload); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to add user data SEI " + "message to access unit.\n"); + goto fail; + } + + } else { + invalid_user_data: + av_log(bsf, AV_LOG_ERROR, "Invalid user data: " + "must be \"UUID+string\".\n"); + err = AVERROR(EINVAL); + goto fail; + } + } + + if (ctx->delete_filler) { + for (i = 0; i < au->nb_units; i++) { + if (au->units[i].type == H264_NAL_FILLER_DATA) { + // Filler NAL units. + err = ff_cbs_delete_unit(ctx->cbc, au, i); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to delete " + "filler NAL.\n"); + goto fail; + } + --i; + continue; + } + + if (au->units[i].type == H264_NAL_SEI) { + // Filler SEI messages. + H264RawSEI *sei = au->units[i].content; + + for (j = 0; j < sei->payload_count; j++) { + if (sei->payload[j].payload_type == + H264_SEI_TYPE_FILLER_PAYLOAD) { + err = ff_cbs_h264_delete_sei_message(ctx->cbc, au, + &au->units[i], j); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to delete " + "filler SEI message.\n"); + goto fail; + } + // Renumbering might have happened, start again at + // the same NAL unit position. + --i; + break; + } + } + } + } + } + + if (ctx->display_orientation != PASS) { + for (i = 0; i < au->nb_units; i++) { + H264RawSEI *sei; + if (au->units[i].type != H264_NAL_SEI) + continue; + sei = au->units[i].content; + + for (j = 0; j < sei->payload_count; j++) { + H264RawSEIDisplayOrientation *disp; + int32_t *matrix; + + if (sei->payload[j].payload_type != + H264_SEI_TYPE_DISPLAY_ORIENTATION) + continue; + disp = &sei->payload[j].payload.display_orientation; + + if (ctx->display_orientation == REMOVE || + ctx->display_orientation == INSERT) { + err = ff_cbs_h264_delete_sei_message(ctx->cbc, au, + &au->units[i], j); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to delete " + "display orientation SEI message.\n"); + goto fail; + } + --i; + break; + } + + matrix = av_mallocz(9 * sizeof(int32_t)); + if (!matrix) { + err = AVERROR(ENOMEM); + goto fail; + } + + av_display_rotation_set(matrix, + disp->anticlockwise_rotation * + 180.0 / 65536.0); + av_display_matrix_flip(matrix, disp->hor_flip, disp->ver_flip); + + // If there are multiple display orientation messages in an + // access unit then ignore all but the last one. + av_freep(&displaymatrix_side_data); + + displaymatrix_side_data = (uint8_t*)matrix; + displaymatrix_side_data_size = 9 * sizeof(int32_t); + } + } + } + if (ctx->display_orientation == INSERT) { + H264RawSEIPayload payload = { + .payload_type = H264_SEI_TYPE_DISPLAY_ORIENTATION, + }; + H264RawSEIDisplayOrientation *disp = + &payload.payload.display_orientation; + uint8_t *data; + int size; + int write = 0; + + data = av_packet_get_side_data(in, AV_PKT_DATA_DISPLAYMATRIX, &size); + if (data && size >= 9 * sizeof(int32_t)) { + int32_t matrix[9]; + int hflip, vflip; + double angle; + + memcpy(matrix, data, sizeof(matrix)); + + hflip = vflip = 0; + if (matrix[0] < 0 && matrix[4] > 0) + hflip = 1; + else if (matrix[0] > 0 && matrix[4] < 0) + vflip = 1; + av_display_matrix_flip(matrix, hflip, vflip); + + angle = av_display_rotation_get(matrix); + + if (!(angle >= -180.0 && angle <= 180.0 /* also excludes NaN */) || + matrix[2] != 0 || matrix[5] != 0 || + matrix[6] != 0 || matrix[7] != 0) { + av_log(bsf, AV_LOG_WARNING, "Input display matrix is not " + "representable in H.264 parameters.\n"); + } else { + disp->hor_flip = hflip; + disp->ver_flip = vflip; + disp->anticlockwise_rotation = + (uint16_t)rint((angle >= 0.0 ? angle + : angle + 360.0) * + 65536.0 / 360.0); + write = 1; + } + } + + if (has_sps || !ctx->done_first_au) { + if (!isnan(ctx->rotate)) { + disp->anticlockwise_rotation = + (uint16_t)rint((ctx->rotate >= 0.0 ? ctx->rotate + : ctx->rotate + 360.0) * + 65536.0 / 360.0); + write = 1; + } + if (ctx->flip) { + disp->hor_flip = !!(ctx->flip & FLIP_HORIZONTAL); + disp->ver_flip = !!(ctx->flip & FLIP_VERTICAL); + write = 1; + } + } + + if (write) { + disp->display_orientation_repetition_period = 1; + + err = ff_cbs_h264_add_sei_message(ctx->cbc, au, &payload); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to add display orientation " + "SEI message to access unit.\n"); + goto fail; + } + } + } + + err = ff_cbs_write_packet(ctx->cbc, out, au); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to write packet.\n"); + goto fail; + } + + err = av_packet_copy_props(out, in); + if (err < 0) + goto fail; + + if (displaymatrix_side_data) { + err = av_packet_add_side_data(out, AV_PKT_DATA_DISPLAYMATRIX, + displaymatrix_side_data, + displaymatrix_side_data_size); + if (err) { + av_log(bsf, AV_LOG_ERROR, "Failed to attach extracted " + "displaymatrix side data to packet.\n"); + goto fail; + } + displaymatrix_side_data = NULL; + } + + ctx->done_first_au = 1; + + err = 0; +fail: + ff_cbs_fragment_uninit(ctx->cbc, au); + av_freep(&displaymatrix_side_data); + + if (err < 0) + av_packet_unref(out); + av_packet_free(&in); + + return err; +} + +static int h264_metadata_init(AVBSFContext *bsf) +{ + H264MetadataContext *ctx = bsf->priv_data; + CodedBitstreamFragment *au = &ctx->access_unit; + int err, i; + + err = ff_cbs_init(&ctx->cbc, AV_CODEC_ID_H264, bsf); + if (err < 0) + return err; + + if (bsf->par_in->extradata) { + err = ff_cbs_read_extradata(ctx->cbc, au, bsf->par_in); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read extradata.\n"); + goto fail; + } + + for (i = 0; i < au->nb_units; i++) { + if (au->units[i].type == H264_NAL_SPS) { + err = h264_metadata_update_sps(bsf, au->units[i].content); + if (err < 0) + goto fail; + } + } + + err = ff_cbs_write_extradata(ctx->cbc, bsf->par_out, au); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to write extradata.\n"); + goto fail; + } + } + + err = 0; +fail: + ff_cbs_fragment_uninit(ctx->cbc, au); + return err; +} + +static void h264_metadata_close(AVBSFContext *bsf) +{ + H264MetadataContext *ctx = bsf->priv_data; + ff_cbs_close(&ctx->cbc); +} + +#define OFFSET(x) offsetof(H264MetadataContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM) +static const AVOption h264_metadata_options[] = { + { "aud", "Access Unit Delimiter NAL units", + OFFSET(aud), AV_OPT_TYPE_INT, + { .i64 = PASS }, PASS, REMOVE, FLAGS, "aud" }, + { "pass", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = PASS }, .flags = FLAGS, .unit = "aud" }, + { "insert", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = INSERT }, .flags = FLAGS, .unit = "aud" }, + { "remove", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = REMOVE }, .flags = FLAGS, .unit = "aud" }, + + { "sample_aspect_ratio", "Set sample aspect ratio (table E-1)", + OFFSET(sample_aspect_ratio), AV_OPT_TYPE_RATIONAL, + { .dbl = 0.0 }, 0, 65535, FLAGS }, + + { "video_format", "Set video format (table E-2)", + OFFSET(video_format), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 7, FLAGS}, + { "video_full_range_flag", "Set video full range flag", + OFFSET(video_full_range_flag), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 1, FLAGS }, + { "colour_primaries", "Set colour primaries (table E-3)", + OFFSET(colour_primaries), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255, FLAGS }, + { "transfer_characteristics", "Set transfer characteristics (table E-4)", + OFFSET(transfer_characteristics), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255, FLAGS }, + { "matrix_coefficients", "Set matrix coefficients (table E-5)", + OFFSET(matrix_coefficients), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255, FLAGS }, + + { "chroma_sample_loc_type", "Set chroma sample location type (figure E-1)", + OFFSET(chroma_sample_loc_type), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 6, FLAGS }, + + { "tick_rate", "Set VUI tick rate (num_units_in_tick / time_scale)", + OFFSET(tick_rate), AV_OPT_TYPE_RATIONAL, + { .dbl = 0.0 }, 0, UINT_MAX, FLAGS }, + { "fixed_frame_rate_flag", "Set VUI fixed frame rate flag", + OFFSET(fixed_frame_rate_flag), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 1, FLAGS }, + + { "crop_left", "Set left border crop offset", + OFFSET(crop_left), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, H264_MAX_WIDTH, FLAGS }, + { "crop_right", "Set right border crop offset", + OFFSET(crop_right), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, H264_MAX_WIDTH, FLAGS }, + { "crop_top", "Set top border crop offset", + OFFSET(crop_top), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, H264_MAX_HEIGHT, FLAGS }, + { "crop_bottom", "Set bottom border crop offset", + OFFSET(crop_bottom), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, H264_MAX_HEIGHT, FLAGS }, + + { "sei_user_data", "Insert SEI user data (UUID+string)", + OFFSET(sei_user_data), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS }, + + { "delete_filler", "Delete all filler (both NAL and SEI)", + OFFSET(delete_filler), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS}, + + { "display_orientation", "Display orientation SEI", + OFFSET(display_orientation), AV_OPT_TYPE_INT, + { .i64 = PASS }, PASS, EXTRACT, FLAGS, "disp_or" }, + { "pass", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = PASS }, .flags = FLAGS, .unit = "disp_or" }, + { "insert", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = INSERT }, .flags = FLAGS, .unit = "disp_or" }, + { "remove", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = REMOVE }, .flags = FLAGS, .unit = "disp_or" }, + { "extract", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = EXTRACT }, .flags = FLAGS, .unit = "disp_or" }, + + { "rotate", "Set rotation in display orientation SEI (anticlockwise angle in degrees)", + OFFSET(rotate), AV_OPT_TYPE_DOUBLE, + { .dbl = NAN }, -360.0, +360.0, FLAGS }, + { "flip", "Set flip in display orientation SEI", + OFFSET(flip), AV_OPT_TYPE_FLAGS, + { .i64 = 0 }, 0, FLIP_HORIZONTAL | FLIP_VERTICAL, FLAGS, "flip" }, + { "horizontal", "Set hor_flip", + 0, AV_OPT_TYPE_CONST, + { .i64 = FLIP_HORIZONTAL }, .flags = FLAGS, .unit = "flip" }, + { "vertical", "Set ver_flip", + 0, AV_OPT_TYPE_CONST, + { .i64 = FLIP_VERTICAL }, .flags = FLAGS, .unit = "flip" }, + + { NULL } +}; + +static const AVClass h264_metadata_class = { + .class_name = "h264_metadata_bsf", + .item_name = av_default_item_name, + .option = h264_metadata_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const enum AVCodecID h264_metadata_codec_ids[] = { + AV_CODEC_ID_H264, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_h264_metadata_bsf = { + .name = "h264_metadata", + .priv_data_size = sizeof(H264MetadataContext), + .priv_class = &h264_metadata_class, + .init = &h264_metadata_init, + .close = &h264_metadata_close, + .filter = &h264_metadata_filter, + .codec_ids = h264_metadata_codec_ids, +}; diff --git a/libavcodec/h264_mp4toannexb_bsf.c b/libavcodec/h264_mp4toannexb_bsf.c index 163d0f59ceb5c..292d10643307b 100644 --- a/libavcodec/h264_mp4toannexb_bsf.c +++ b/libavcodec/h264_mp4toannexb_bsf.c @@ -39,21 +39,21 @@ typedef struct H264BSFContext { static int alloc_and_copy(AVPacket *out, const uint8_t *sps_pps, uint32_t sps_pps_size, - const uint8_t *in, uint32_t in_size) + const uint8_t *in, uint32_t in_size, int ps) { uint32_t offset = out->size; - uint8_t nal_header_size = offset ? 3 : 4; + uint8_t start_code_size = offset == 0 || ps ? 4 : 3; int err; - err = av_grow_packet(out, sps_pps_size + in_size + nal_header_size); + err = av_grow_packet(out, sps_pps_size + in_size + start_code_size); if (err < 0) return err; if (sps_pps) memcpy(out->data + offset, sps_pps, sps_pps_size); - memcpy(out->data + sps_pps_size + nal_header_size + offset, in, in_size); - if (!offset) { - AV_WB32(out->data + sps_pps_size, 1); + memcpy(out->data + sps_pps_size + start_code_size + offset, in, in_size); + if (start_code_size == 4) { + AV_WB32(out->data + offset + sps_pps_size, 1); } else { (out->data + offset + sps_pps_size)[0] = (out->data + offset + sps_pps_size)[1] = 0; @@ -221,7 +221,7 @@ static int h264_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *out) if ((ret = alloc_and_copy(out, ctx->par_out->extradata + s->sps_offset, s->pps_offset != -1 ? s->pps_offset : ctx->par_out->extradata_size - s->sps_offset, - buf, nal_size)) < 0) + buf, nal_size, 1)) < 0) goto fail; s->idr_sps_seen = 1; goto next_nal; @@ -239,21 +239,21 @@ static int h264_mp4toannexb_filter(AVBSFContext *ctx, AVPacket *out) if (s->new_idr && unit_type == 5 && !s->idr_sps_seen && !s->idr_pps_seen) { if ((ret=alloc_and_copy(out, ctx->par_out->extradata, ctx->par_out->extradata_size, - buf, nal_size)) < 0) + buf, nal_size, 1)) < 0) goto fail; s->new_idr = 0; /* if only SPS has been seen, also insert PPS */ } else if (s->new_idr && unit_type == 5 && s->idr_sps_seen && !s->idr_pps_seen) { if (s->pps_offset == -1) { av_log(ctx, AV_LOG_WARNING, "PPS not present in the stream, nor in AVCC, stream may be unreadable\n"); - if ((ret = alloc_and_copy(out, NULL, 0, buf, nal_size)) < 0) + if ((ret = alloc_and_copy(out, NULL, 0, buf, nal_size, 0)) < 0) goto fail; } else if ((ret = alloc_and_copy(out, ctx->par_out->extradata + s->pps_offset, ctx->par_out->extradata_size - s->pps_offset, - buf, nal_size)) < 0) + buf, nal_size, 1)) < 0) goto fail; } else { - if ((ret=alloc_and_copy(out, NULL, 0, buf, nal_size)) < 0) + if ((ret=alloc_and_copy(out, NULL, 0, buf, nal_size, unit_type == 7 || unit_type == 8)) < 0) goto fail; if (!s->new_idr && unit_type == 1) { s->new_idr = 1; diff --git a/libavcodec/h264_parse.c b/libavcodec/h264_parse.c index a7c71d9bbbbed..87e5b3cdc5323 100644 --- a/libavcodec/h264_parse.c +++ b/libavcodec/h264_parse.c @@ -82,8 +82,11 @@ int ff_h264_pred_weight_table(GetBitContext *gb, const SPS *sps, pwt->chroma_weight[i][list][j][0] = get_se_golomb(gb); pwt->chroma_weight[i][list][j][1] = get_se_golomb(gb); if ((int8_t)pwt->chroma_weight[i][list][j][0] != pwt->chroma_weight[i][list][j][0] || - (int8_t)pwt->chroma_weight[i][list][j][1] != pwt->chroma_weight[i][list][j][1]) + (int8_t)pwt->chroma_weight[i][list][j][1] != pwt->chroma_weight[i][list][j][1]) { + pwt->chroma_weight[i][list][j][0] = chroma_def; + pwt->chroma_weight[i][list][j][1] = 0; goto out_range_weight; + } if (pwt->chroma_weight[i][list][j][0] != chroma_def || pwt->chroma_weight[i][list][j][1] != 0) { pwt->use_weight_chroma = 1; @@ -271,7 +274,7 @@ int ff_h264_init_poc(int pic_field_poc[2], int *pic_poc, int picture_structure, int nal_ref_idc) { const int max_frame_num = 1 << sps->log2_max_frame_num; - int field_poc[2]; + int64_t field_poc[2]; pc->frame_num_offset = pc->prev_frame_num_offset; if (pc->frame_num < pc->prev_frame_num) @@ -337,6 +340,10 @@ int ff_h264_init_poc(int pic_field_poc[2], int *pic_poc, field_poc[1] = poc; } + if ( field_poc[0] != (int)field_poc[0] + || field_poc[1] != (int)field_poc[1]) + return AVERROR_INVALIDDATA; + if (picture_structure != PICT_BOTTOM_FIELD) pic_field_poc[0] = field_poc[0]; if (picture_structure != PICT_TOP_FIELD) @@ -425,10 +432,9 @@ static int decode_extradata_ps_mp4(const uint8_t *buf, int buf_size, H264ParamSe escaped_buf_size = bytestream2_tell_p(&pbc); AV_WB16(escaped_buf, escaped_buf_size - 2); - ret = decode_extradata_ps(escaped_buf, escaped_buf_size, ps, 1, logctx); + (void)decode_extradata_ps(escaped_buf, escaped_buf_size, ps, 1, logctx); + // lorex.mp4 decodes ok even with extradata decoding failing av_freep(&escaped_buf); - if (ret < 0) - return ret; } return 0; diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c index dd0a965af033e..1a9840a62c542 100644 --- a/libavcodec/h264_parser.c +++ b/libavcodec/h264_parser.c @@ -243,6 +243,7 @@ static inline int parse_nal_units(AVCodecParserContext *s, const uint8_t * const buf, int buf_size) { H264ParseContext *p = s->priv_data; + H2645RBSP rbsp = { NULL }; H2645NAL nal = { NULL }; int buf_index, next_avc; unsigned int pps_id; @@ -258,11 +259,15 @@ static inline int parse_nal_units(AVCodecParserContext *s, s->picture_structure = AV_PICTURE_STRUCTURE_UNKNOWN; ff_h264_sei_uninit(&p->sei); - p->sei.frame_packing.frame_packing_arrangement_cancel_flag = -1; + p->sei.frame_packing.arrangement_cancel_flag = -1; if (!buf_size) return 0; + av_fast_padded_malloc(&rbsp.rbsp_buffer, &rbsp.rbsp_buffer_alloc_size, buf_size); + if (!rbsp.rbsp_buffer) + return AVERROR(ENOMEM); + buf_index = 0; next_avc = p->is_avc ? 0 : buf_size; for (;;) { @@ -300,7 +305,7 @@ static inline int parse_nal_units(AVCodecParserContext *s, } break; } - consumed = ff_h2645_extract_rbsp(buf + buf_index, src_length, &nal, 1); + consumed = ff_h2645_extract_rbsp(buf + buf_index, src_length, &rbsp, &nal, 1); if (consumed < 0) break; @@ -444,8 +449,10 @@ static inline int parse_nal_units(AVCodecParserContext *s, /* Decode POC of this picture. * The prev_ values needed for decoding POC of the next picture are not set here. */ field_poc[0] = field_poc[1] = INT_MAX; - ff_h264_init_poc(field_poc, &s->output_picture_number, sps, + ret = ff_h264_init_poc(field_poc, &s->output_picture_number, sps, &p->poc, p->picture_structure, nal.ref_idc); + if (ret < 0) + goto fail; /* Continue parsing to check if MMCO_RESET is present. * FIXME: MMCO_RESET could appear in non-first slice. @@ -544,18 +551,18 @@ static inline int parse_nal_units(AVCodecParserContext *s, p->last_frame_num = p->poc.frame_num; } - av_freep(&nal.rbsp_buffer); + av_freep(&rbsp.rbsp_buffer); return 0; /* no need to evaluate the rest */ } } if (q264) { - av_freep(&nal.rbsp_buffer); + av_freep(&rbsp.rbsp_buffer); return 0; } /* didn't find a picture! */ av_log(avctx, AV_LOG_ERROR, "missing picture in access unit with size %d\n", buf_size); fail: - av_freep(&nal.rbsp_buffer); + av_freep(&rbsp.rbsp_buffer); return -1; } diff --git a/libavcodec/h264_picture.c b/libavcodec/h264_picture.c index 99d9f9075c416..e833835a77a2b 100644 --- a/libavcodec/h264_picture.c +++ b/libavcodec/h264_picture.c @@ -41,7 +41,6 @@ #include "mpegutils.h" #include "rectangle.h" #include "thread.h" -#include "vdpau_compat.h" void ff_h264_unref_picture(H264Context *h, H264Picture *pic) { @@ -79,24 +78,30 @@ int ff_h264_ref_picture(H264Context *h, H264Picture *dst, H264Picture *src) dst->qscale_table_buf = av_buffer_ref(src->qscale_table_buf); dst->mb_type_buf = av_buffer_ref(src->mb_type_buf); - if (!dst->qscale_table_buf || !dst->mb_type_buf) + if (!dst->qscale_table_buf || !dst->mb_type_buf) { + ret = AVERROR(ENOMEM); goto fail; + } dst->qscale_table = src->qscale_table; dst->mb_type = src->mb_type; for (i = 0; i < 2; i++) { dst->motion_val_buf[i] = av_buffer_ref(src->motion_val_buf[i]); dst->ref_index_buf[i] = av_buffer_ref(src->ref_index_buf[i]); - if (!dst->motion_val_buf[i] || !dst->ref_index_buf[i]) + if (!dst->motion_val_buf[i] || !dst->ref_index_buf[i]) { + ret = AVERROR(ENOMEM); goto fail; + } dst->motion_val[i] = src->motion_val[i]; dst->ref_index[i] = src->ref_index[i]; } if (src->hwaccel_picture_private) { dst->hwaccel_priv_buf = av_buffer_ref(src->hwaccel_priv_buf); - if (!dst->hwaccel_priv_buf) + if (!dst->hwaccel_priv_buf) { + ret = AVERROR(ENOMEM); goto fail; + } dst->hwaccel_picture_private = dst->hwaccel_priv_buf->data; } @@ -152,12 +157,6 @@ int ff_h264_field_end(H264Context *h, H264SliceContext *sl, int in_setup) int err = 0; h->mb_y = 0; -#if FF_API_CAP_VDPAU - if (CONFIG_H264_VDPAU_DECODER && - h->avctx->codec->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU) - ff_vdpau_h264_set_reference_frames(h); -#endif - if (in_setup || !(avctx->active_thread_type & FF_THREAD_FRAME)) { if (!h->droppable) { err = ff_h264_execute_ref_pic_marking(h); @@ -175,12 +174,6 @@ int ff_h264_field_end(H264Context *h, H264SliceContext *sl, int in_setup) "hardware accelerator failed to decode picture\n"); } -#if FF_API_CAP_VDPAU - if (CONFIG_H264_VDPAU_DECODER && - h->avctx->codec->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU) - ff_vdpau_h264_picture_complete(h); -#endif - if (!in_setup && !h->droppable) ff_thread_report_progress(&h->cur_pic_ptr->tf, INT_MAX, h->picture_structure == PICT_BOTTOM_FIELD); diff --git a/libavcodec/h264_ps.c b/libavcodec/h264_ps.c index b7d5f65d32694..15fb8b6265482 100644 --- a/libavcodec/h264_ps.c +++ b/libavcodec/h264_ps.c @@ -348,7 +348,7 @@ int ff_h264_decode_seq_parameter_set(GetBitContext *gb, AVCodecContext *avctx, sps->data_size = gb->buffer_end - gb->buffer; if (sps->data_size > sizeof(sps->data)) { - av_log(avctx, AV_LOG_WARNING, "Truncating likely oversized SPS\n"); + av_log(avctx, AV_LOG_DEBUG, "Truncating likely oversized SPS\n"); sps->data_size = sizeof(sps->data); } memcpy(sps->data, gb->buffer, sps->data_size); @@ -469,7 +469,7 @@ int ff_h264_decode_seq_parameter_set(GetBitContext *gb, AVCodecContext *avctx, } sps->ref_frame_count = get_ue_golomb_31(gb); - if (avctx->codec_tag == MKTAG('S', 'M', 'V', '2')) + if (avctx && avctx->codec_tag == MKTAG('S', 'M', 'V', '2')) sps->ref_frame_count = FFMAX(2, sps->ref_frame_count); if (sps->ref_frame_count > MAX_DELAYED_PIC_COUNT) { av_log(avctx, AV_LOG_ERROR, @@ -517,7 +517,7 @@ int ff_h264_decode_seq_parameter_set(GetBitContext *gb, AVCodecContext *avctx, int width = 16 * sps->mb_width; int height = 16 * sps->mb_height; - if (avctx->flags2 & AV_CODEC_FLAG2_IGNORE_CROP) { + if (avctx && avctx->flags2 & AV_CODEC_FLAG2_IGNORE_CROP) { av_log(avctx, AV_LOG_DEBUG, "discarding sps cropping, original " "values are l:%d r:%d t:%d b:%d\n", crop_left, crop_right, crop_top, crop_bottom); @@ -588,7 +588,7 @@ int ff_h264_decode_seq_parameter_set(GetBitContext *gb, AVCodecContext *avctx, if (!sps->sar.den) sps->sar.den = 1; - if (avctx->debug & FF_DEBUG_PICT_INFO) { + if (avctx && avctx->debug & FF_DEBUG_PICT_INFO) { static const char csp[4][5] = { "Gray", "420", "422", "444" }; av_log(avctx, AV_LOG_DEBUG, "sps:%u profile:%d/%d poc:%d ref:%d %dx%d %s %s crop:%u/%u/%u/%u %s %s %"PRId32"/%"PRId32" b%d reo:%d\n", @@ -745,7 +745,7 @@ int ff_h264_decode_picture_parameter_set(GetBitContext *gb, AVCodecContext *avct pps->data_size = gb->buffer_end - gb->buffer; if (pps->data_size > sizeof(pps->data)) { - av_log(avctx, AV_LOG_WARNING, "Truncating likely oversized PPS " + av_log(avctx, AV_LOG_DEBUG, "Truncating likely oversized PPS " "(%"SIZE_SPECIFIER" > %"SIZE_SPECIFIER")\n", pps->data_size, sizeof(pps->data)); pps->data_size = sizeof(pps->data); @@ -838,7 +838,7 @@ int ff_h264_decode_picture_parameter_set(GetBitContext *gb, AVCodecContext *avct if (pps->chroma_qp_index_offset[0] != pps->chroma_qp_index_offset[1]) pps->chroma_qp_diff = 1; - if (avctx->debug & FF_DEBUG_PICT_INFO) { + if (avctx && avctx->debug & FF_DEBUG_PICT_INFO) { av_log(avctx, AV_LOG_DEBUG, "pps:%u sps:%u %s slice_groups:%d ref:%u/%u %s qp:%d/%d/%d/%d %s %s %s %s\n", pps_id, pps->sps_id, diff --git a/libavcodec/h264_redundant_pps_bsf.c b/libavcodec/h264_redundant_pps_bsf.c new file mode 100644 index 0000000000000..26baca84e3be2 --- /dev/null +++ b/libavcodec/h264_redundant_pps_bsf.c @@ -0,0 +1,178 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/common.h" +#include "libavutil/mem.h" + +#include "bsf.h" +#include "cbs.h" +#include "cbs_h264.h" +#include "h264.h" + + +typedef struct H264RedundantPPSContext { + CodedBitstreamContext *input; + CodedBitstreamContext *output; + + CodedBitstreamFragment access_unit; + + int global_pic_init_qp; + int current_pic_init_qp; +} H264RedundantPPSContext; + + +static int h264_redundant_pps_fixup_pps(H264RedundantPPSContext *ctx, + H264RawPPS *pps) +{ + // Record the current value of pic_init_qp in order to fix up + // following slices, then overwrite with the global value. + ctx->current_pic_init_qp = pps->pic_init_qp_minus26 + 26; + pps->pic_init_qp_minus26 = ctx->global_pic_init_qp - 26; + + // Some PPSs have this set, so it must be set in all of them. + // (Slices which do not use such a PPS on input will still have + // *_weight_l*flag as zero and therefore write equivalently.) + pps->weighted_pred_flag = 1; + + return 0; +} + +static int h264_redundant_pps_fixup_slice(H264RedundantPPSContext *ctx, + H264RawSliceHeader *slice) +{ + int qp; + + qp = ctx->current_pic_init_qp + slice->slice_qp_delta; + slice->slice_qp_delta = qp - ctx->global_pic_init_qp; + + return 0; +} + +static int h264_redundant_pps_filter(AVBSFContext *bsf, AVPacket *out) +{ + H264RedundantPPSContext *ctx = bsf->priv_data; + AVPacket *in; + CodedBitstreamFragment *au = &ctx->access_unit; + int au_has_sps; + int err, i; + + err = ff_bsf_get_packet(bsf, &in); + if (err < 0) + return err; + + err = ff_cbs_read_packet(ctx->input, au, in); + if (err < 0) + return err; + + au_has_sps = 0; + for (i = 0; i < au->nb_units; i++) { + CodedBitstreamUnit *nal = &au->units[i]; + + if (nal->type == H264_NAL_SPS) + au_has_sps = 1; + if (nal->type == H264_NAL_PPS) { + h264_redundant_pps_fixup_pps(ctx, nal->content); + if (!au_has_sps) { + av_log(ctx, AV_LOG_VERBOSE, "Deleting redundant PPS " + "at %"PRId64".\n", in->pts); + ff_cbs_delete_unit(ctx->input, au, i); + } + } + if (nal->type == H264_NAL_SLICE || + nal->type == H264_NAL_IDR_SLICE) { + H264RawSlice *slice = nal->content; + h264_redundant_pps_fixup_slice(ctx, &slice->header); + } + } + + err = ff_cbs_write_packet(ctx->output, out, au); + if (err < 0) + return err; + + ff_cbs_fragment_uninit(ctx->output, au); + + err = av_packet_copy_props(out, in); + if (err < 0) + return err; + + av_packet_free(&in); + + return 0; +} + +static int h264_redundant_pps_init(AVBSFContext *bsf) +{ + H264RedundantPPSContext *ctx = bsf->priv_data; + CodedBitstreamFragment *au = &ctx->access_unit; + int err, i; + + err = ff_cbs_init(&ctx->input, AV_CODEC_ID_H264, bsf); + if (err < 0) + return err; + + err = ff_cbs_init(&ctx->output, AV_CODEC_ID_H264, bsf); + if (err < 0) + return err; + + ctx->global_pic_init_qp = 26; + + if (bsf->par_in->extradata) { + err = ff_cbs_read_extradata(ctx->input, au, bsf->par_in); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read extradata.\n"); + return err; + } + + for (i = 0; i < au->nb_units; i++) { + if (au->units[i].type == H264_NAL_PPS) + h264_redundant_pps_fixup_pps(ctx, au->units[i].content); + } + + err = ff_cbs_write_extradata(ctx->output, bsf->par_out, au); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to write extradata.\n"); + return err; + } + + ff_cbs_fragment_uninit(ctx->output, au); + } + + return 0; +} + +static void h264_redundant_pps_close(AVBSFContext *bsf) +{ + H264RedundantPPSContext *ctx = bsf->priv_data; + ff_cbs_close(&ctx->input); + ff_cbs_close(&ctx->output); +} + +static const enum AVCodecID h264_redundant_pps_codec_ids[] = { + AV_CODEC_ID_H264, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_h264_redundant_pps_bsf = { + .name = "h264_redundant_pps", + .priv_data_size = sizeof(H264RedundantPPSContext), + .init = &h264_redundant_pps_init, + .close = &h264_redundant_pps_close, + .filter = &h264_redundant_pps_filter, + .codec_ids = h264_redundant_pps_codec_ids, +}; diff --git a/libavcodec/h264_refs.c b/libavcodec/h264_refs.c index af708295943cc..976044ce2c1db 100644 --- a/libavcodec/h264_refs.c +++ b/libavcodec/h264_refs.c @@ -614,6 +614,12 @@ int ff_h264_execute_ref_pic_marking(H264Context *h) int current_ref_assigned = 0, err = 0; H264Picture *av_uninit(pic); + if (!h->ps.sps) { + av_log(h->avctx, AV_LOG_ERROR, "SPS is unset\n"); + err = AVERROR_INVALIDDATA; + goto out; + } + if (!h->explicit_ref_marking) generate_sliding_window_mmcos(h); mmco_count = h->nb_mmco; @@ -817,6 +823,7 @@ int ff_h264_execute_ref_pic_marking(H264Context *h) h->frame_recovered |= FRAME_RECOVERED_SEI; } +out: return (h->avctx->err_recognition & AV_EF_EXPLODE) ? err : 0; } diff --git a/libavcodec/h264_sei.c b/libavcodec/h264_sei.c index 332ae508606c0..9defcb80b9a44 100644 --- a/libavcodec/h264_sei.c +++ b/libavcodec/h264_sei.c @@ -257,9 +257,6 @@ static int decode_unregistered_user_data(H264SEIUnregistered *h, GetBitContext * if (e == 1 && build == 1 && !strncmp(user_data+16, "x264 - core 0000", 16)) h->x264_build = 67; - if (strlen(user_data + 16) > 0) - av_log(logctx, AV_LOG_DEBUG, "user data:\"%s\"\n", user_data + 16); - av_free(user_data); return 0; } @@ -316,24 +313,25 @@ static int decode_buffering_period(H264SEIBufferingPeriod *h, GetBitContext *gb, static int decode_frame_packing_arrangement(H264SEIFramePacking *h, GetBitContext *gb) { - h->frame_packing_arrangement_id = get_ue_golomb_long(gb); - h->frame_packing_arrangement_cancel_flag = get_bits1(gb); - h->present = !h->frame_packing_arrangement_cancel_flag; + h->arrangement_id = get_ue_golomb_long(gb); + h->arrangement_cancel_flag = get_bits1(gb); + h->present = !h->arrangement_cancel_flag; if (h->present) { - h->frame_packing_arrangement_type = get_bits(gb, 7); + h->arrangement_type = get_bits(gb, 7); h->quincunx_sampling_flag = get_bits1(gb); h->content_interpretation_type = get_bits(gb, 6); - // the following skips: spatial_flipping_flag, frame0_flipped_flag, - // field_views_flag, current_frame_is_frame0_flag, + // spatial_flipping_flag, frame0_flipped_flag, field_views_flag + skip_bits(gb, 3); + h->current_frame_is_frame0_flag = get_bits1(gb); // frame0_self_contained_flag, frame1_self_contained_flag - skip_bits(gb, 6); + skip_bits(gb, 2); - if (!h->quincunx_sampling_flag && h->frame_packing_arrangement_type != 5) + if (!h->quincunx_sampling_flag && h->arrangement_type != 5) skip_bits(gb, 16); // frame[01]_grid_position_[xy] skip_bits(gb, 8); // frame_packing_arrangement_reserved_byte - h->frame_packing_arrangement_repetition_period = get_ue_golomb_long(gb); + h->arrangement_repetition_period = get_ue_golomb_long(gb); } skip_bits1(gb); // frame_packing_arrangement_extension_flag @@ -467,8 +465,8 @@ int ff_h264_sei_decode(H264SEIContext *h, GetBitContext *gb, const char *ff_h264_sei_stereo_mode(const H264SEIFramePacking *h) { - if (h->frame_packing_arrangement_cancel_flag == 0) { - switch (h->frame_packing_arrangement_type) { + if (h->arrangement_cancel_flag == 0) { + switch (h->arrangement_type) { case H264_SEI_FPA_TYPE_CHECKERBOARD: if (h->content_interpretation_type == 2) return "checkerboard_rl"; @@ -503,7 +501,7 @@ const char *ff_h264_sei_stereo_mode(const H264SEIFramePacking *h) default: return "mono"; } - } else if (h->frame_packing_arrangement_cancel_flag == 1) { + } else if (h->arrangement_cancel_flag == 1) { return "mono"; } else { return NULL; diff --git a/libavcodec/h264_sei.h b/libavcodec/h264_sei.h index a53f1899fade5..9488382b9fabd 100644 --- a/libavcodec/h264_sei.h +++ b/libavcodec/h264_sei.h @@ -119,12 +119,13 @@ typedef struct H264SEIBufferingPeriod { typedef struct H264SEIFramePacking { int present; - int frame_packing_arrangement_id; - int frame_packing_arrangement_cancel_flag; ///< is previous arrangement canceled, -1 if never received - H264_SEI_FpaType frame_packing_arrangement_type; - int frame_packing_arrangement_repetition_period; + int arrangement_id; + int arrangement_cancel_flag; ///< is previous arrangement canceled, -1 if never received + H264_SEI_FpaType arrangement_type; + int arrangement_repetition_period; int content_interpretation_type; int quincunx_sampling_flag; + int current_frame_is_frame0_flag; } H264SEIFramePacking; typedef struct H264SEIDisplayOrientation { diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c index 2577edd8a6d9f..d71ddbe9ba48e 100644 --- a/libavcodec/h264_slice.c +++ b/libavcodec/h264_slice.c @@ -399,12 +399,12 @@ int ff_h264_update_thread_context(AVCodecContext *dst, h->enable_er = h1->enable_er; h->workaround_bugs = h1->workaround_bugs; + h->x264_build = h1->x264_build; h->droppable = h1->droppable; // extradata/NAL handling h->is_avc = h1->is_avc; h->nal_length_size = h1->nal_length_size; - h->sei.unregistered.x264_build = h1->sei.unregistered.x264_build; memcpy(&h->poc, &h1->poc, sizeof(h->poc)); @@ -497,11 +497,7 @@ static int h264_frame_start(H264Context *h) if ((ret = alloc_picture(h, pic)) < 0) return ret; - if(!h->frame_recovered && !h->avctx->hwaccel -#if FF_API_CAP_VDPAU - && !(h->avctx->codec->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU) -#endif - ) + if(!h->frame_recovered && !h->avctx->hwaccel) ff_color_frame(pic->f, c); h->cur_pic_ptr = pic; @@ -549,6 +545,9 @@ static int h264_frame_start(H264Context *h) h->mb_aff_frame = h->ps.sps->mb_aff && (h->picture_structure == PICT_FRAME); + if (h->sei.unregistered.x264_build >= 0) + h->x264_build = h->sei.unregistered.x264_build; + assert(h->cur_pic_ptr->long_ref == 0); return 0; @@ -758,8 +757,8 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) { #define HWACCEL_MAX (CONFIG_H264_DXVA2_HWACCEL + \ (CONFIG_H264_D3D11VA_HWACCEL * 2) + \ + CONFIG_H264_NVDEC_HWACCEL + \ CONFIG_H264_VAAPI_HWACCEL + \ - (CONFIG_H264_VDA_HWACCEL * 2) + \ CONFIG_H264_VIDEOTOOLBOX_HWACCEL + \ CONFIG_H264_VDPAU_HWACCEL) enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmt = pix_fmts; @@ -814,6 +813,9 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) case 8: #if CONFIG_H264_VDPAU_HWACCEL *fmt++ = AV_PIX_FMT_VDPAU; +#endif +#if CONFIG_H264_NVDEC_HWACCEL + *fmt++ = AV_PIX_FMT_CUDA; #endif if (CHROMA444(h)) { if (h->avctx->colorspace == AVCOL_SPC_RGB) @@ -838,10 +840,6 @@ static enum AVPixelFormat get_pixel_format(H264Context *h, int force_callback) #if CONFIG_H264_VAAPI_HWACCEL *fmt++ = AV_PIX_FMT_VAAPI; #endif -#if CONFIG_H264_VDA_HWACCEL - *fmt++ = AV_PIX_FMT_VDA_VLD; - *fmt++ = AV_PIX_FMT_VDA; -#endif #if CONFIG_H264_VIDEOTOOLBOX_HWACCEL *fmt++ = AV_PIX_FMT_VIDEOTOOLBOX; #endif @@ -921,7 +919,7 @@ static int h264_slice_header_init(H264Context *h) if (sps->timing_info_present_flag) { int64_t den = sps->time_scale; - if (h->sei.unregistered.x264_build < 44U) + if (h->x264_build < 44U) den *= 2; av_reduce(&h->avctx->framerate.den, &h->avctx->framerate.num, sps->num_units_in_tick * h->avctx->ticks_per_frame, den, 1 << 30); @@ -939,17 +937,6 @@ static int h264_slice_header_init(H264Context *h) goto fail; } -#if FF_API_CAP_VDPAU - if (h->avctx->codec && - h->avctx->codec->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU && - (sps->bit_depth_luma != 8 || sps->chroma_format_idc > 1)) { - av_log(h->avctx, AV_LOG_ERROR, - "VDPAU decoding does not support video colorspace.\n"); - ret = AVERROR_INVALIDDATA; - goto fail; - } -#endif - if (sps->bit_depth_luma < 8 || sps->bit_depth_luma > 14 || sps->bit_depth_luma == 11 || sps->bit_depth_luma == 13 ) { @@ -1211,41 +1198,48 @@ static int h264_export_frame_props(H264Context *h) } if (h->sei.frame_packing.present && - h->sei.frame_packing.frame_packing_arrangement_type <= 6 && + h->sei.frame_packing.arrangement_type <= 6 && h->sei.frame_packing.content_interpretation_type > 0 && h->sei.frame_packing.content_interpretation_type < 3) { H264SEIFramePacking *fp = &h->sei.frame_packing; AVStereo3D *stereo = av_stereo3d_create_side_data(cur->f); if (stereo) { - switch (fp->frame_packing_arrangement_type) { - case 0: + switch (fp->arrangement_type) { + case H264_SEI_FPA_TYPE_CHECKERBOARD: stereo->type = AV_STEREO3D_CHECKERBOARD; break; - case 1: + case H264_SEI_FPA_TYPE_INTERLEAVE_COLUMN: stereo->type = AV_STEREO3D_COLUMNS; break; - case 2: + case H264_SEI_FPA_TYPE_INTERLEAVE_ROW: stereo->type = AV_STEREO3D_LINES; break; - case 3: + case H264_SEI_FPA_TYPE_SIDE_BY_SIDE: if (fp->quincunx_sampling_flag) stereo->type = AV_STEREO3D_SIDEBYSIDE_QUINCUNX; else stereo->type = AV_STEREO3D_SIDEBYSIDE; break; - case 4: + case H264_SEI_FPA_TYPE_TOP_BOTTOM: stereo->type = AV_STEREO3D_TOPBOTTOM; break; - case 5: + case H264_SEI_FPA_TYPE_INTERLEAVE_TEMPORAL: stereo->type = AV_STEREO3D_FRAMESEQUENCE; break; - case 6: + case H264_SEI_FPA_TYPE_2D: stereo->type = AV_STEREO3D_2D; break; } if (fp->content_interpretation_type == 2) stereo->flags = AV_STEREO3D_FLAG_INVERT; + + if (fp->arrangement_type == H264_SEI_FPA_TYPE_INTERLEAVE_TEMPORAL) { + if (fp->current_frame_is_frame0_flag) + stereo->view = AV_STEREO3D_VIEW_LEFT; + else + stereo->view = AV_STEREO3D_VIEW_RIGHT; + } } } @@ -1322,7 +1316,7 @@ static int h264_select_output_frame(H264Context *h) } out_of_order = MAX_DELAYED_PIC_COUNT - i; if( cur->f->pict_type == AV_PICTURE_TYPE_B - || (h->last_pocs[MAX_DELAYED_PIC_COUNT-2] > INT_MIN && h->last_pocs[MAX_DELAYED_PIC_COUNT-1] - h->last_pocs[MAX_DELAYED_PIC_COUNT-2] > 2)) + || (h->last_pocs[MAX_DELAYED_PIC_COUNT-2] > INT_MIN && h->last_pocs[MAX_DELAYED_PIC_COUNT-1] - (int64_t)h->last_pocs[MAX_DELAYED_PIC_COUNT-2] > 2)) out_of_order = FFMAX(out_of_order, 1); if (out_of_order == MAX_DELAYED_PIC_COUNT) { av_log(h->avctx, AV_LOG_VERBOSE, "Invalid POC %d<%d\n", cur->poc, h->last_pocs[0]); @@ -1577,6 +1571,12 @@ static int h264_field_start(H264Context *h, const H264SliceContext *sl, * one except for reference purposes. */ h->first_field = 1; h->cur_pic_ptr = NULL; + } else if (h->cur_pic_ptr->reference & DELAYED_PIC_REF) { + /* This frame was already output, we cannot draw into it + * anymore. + */ + h->first_field = 1; + h->cur_pic_ptr = NULL; } else { /* Second field in complementary pair */ h->first_field = 0; @@ -1607,8 +1607,10 @@ static int h264_field_start(H264Context *h, const H264SliceContext *sl, (h->mb_height * h->mb_stride - 1) * sizeof(*h->slice_table)); } - ff_h264_init_poc(h->cur_pic_ptr->field_poc, &h->cur_pic_ptr->poc, + ret = ff_h264_init_poc(h->cur_pic_ptr->field_poc, &h->cur_pic_ptr->poc, h->ps.sps, &h->poc, h->picture_structure, nal->ref_idc); + if (ret < 0) + return ret; memcpy(h->mmco, sl->mmco, sl->nb_mmco * sizeof(*h->mmco)); h->nb_mmco = sl->nb_mmco; @@ -2738,11 +2740,7 @@ int ff_h264_execute_decode_slices(H264Context *h) h->slice_ctx[0].next_slice_idx = INT_MAX; - if (h->avctx->hwaccel || context_count < 1 -#if FF_API_CAP_VDPAU - || h->avctx->codec->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU -#endif - ) + if (h->avctx->hwaccel || context_count < 1) return 0; av_assert0(context_count && h->slice_ctx[context_count - 1].mb_y < h->mb_height); diff --git a/libavcodec/h264addpx_template.c b/libavcodec/h264addpx_template.c index b71aaea439480..9a1e6a2f2f603 100644 --- a/libavcodec/h264addpx_template.c +++ b/libavcodec/h264addpx_template.c @@ -35,10 +35,10 @@ static void FUNCC(ff_h264_add_pixels4)(uint8_t *_dst, int16_t *_src, int stride) stride /= sizeof(pixel); for (i = 0; i < 4; i++) { - dst[0] += src[0]; - dst[1] += src[1]; - dst[2] += src[2]; - dst[3] += src[3]; + dst[0] += (unsigned)src[0]; + dst[1] += (unsigned)src[1]; + dst[2] += (unsigned)src[2]; + dst[3] += (unsigned)src[3]; dst += stride; src += 4; @@ -55,14 +55,14 @@ static void FUNCC(ff_h264_add_pixels8)(uint8_t *_dst, int16_t *_src, int stride) stride /= sizeof(pixel); for (i = 0; i < 8; i++) { - dst[0] += src[0]; - dst[1] += src[1]; - dst[2] += src[2]; - dst[3] += src[3]; - dst[4] += src[4]; - dst[5] += src[5]; - dst[6] += src[6]; - dst[7] += src[7]; + dst[0] += (unsigned)src[0]; + dst[1] += (unsigned)src[1]; + dst[2] += (unsigned)src[2]; + dst[3] += (unsigned)src[3]; + dst[4] += (unsigned)src[4]; + dst[5] += (unsigned)src[5]; + dst[6] += (unsigned)src[6]; + dst[7] += (unsigned)src[7]; dst += stride; src += 8; diff --git a/libavcodec/h264dec.c b/libavcodec/h264dec.c index f29c3f90488d7..7494c7a8f2ced 100644 --- a/libavcodec/h264dec.c +++ b/libavcodec/h264dec.c @@ -47,13 +47,13 @@ #include "h264_mvpred.h" #include "h264_ps.h" #include "golomb.h" +#include "hwaccel.h" #include "mathops.h" #include "me_cmp.h" #include "mpegutils.h" #include "profiles.h" #include "rectangle.h" #include "thread.h" -#include "vdpau_compat.h" const uint16_t ff_h264_mb_sizes[4] = { 256, 384, 512, 768 }; @@ -317,7 +317,7 @@ static int h264_init_context(AVCodecContext *avctx, H264Context *h) h->recovery_frame = -1; h->frame_recovered = 0; h->poc.prev_frame_num = -1; - h->sei.frame_packing.frame_packing_arrangement_cancel_flag = -1; + h->sei.frame_packing.arrangement_cancel_flag = -1; h->sei.unregistered.x264_build = -1; h->next_outputed_poc = INT_MIN; @@ -527,10 +527,6 @@ static void flush_dpb(AVCodecContext *avctx) h->context_initialized = 0; } -#if FF_API_CAP_VDPAU -static const uint8_t start_code[] = { 0x00, 0x00, 0x01 }; -#endif - static int get_last_needed_nal(H264Context *h) { int nals_needed = 0; @@ -688,11 +684,6 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) if (h->avctx->hwaccel && (ret = h->avctx->hwaccel->start_frame(h->avctx, buf, buf_size)) < 0) goto end; -#if FF_API_CAP_VDPAU - if (CONFIG_H264_VDPAU_DECODER && - h->avctx->codec->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU) - ff_vdpau_h264_picture_start(h); -#endif } max_slice_ctx = avctx->hwaccel ? 1 : h->nb_slice_ctx; @@ -701,18 +692,6 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) ret = avctx->hwaccel->decode_slice(avctx, nal->raw_data, nal->raw_size); h->nb_slice_ctx_queued = 0; } else -#if FF_API_CAP_VDPAU - if (CONFIG_H264_VDPAU_DECODER && - h->avctx->codec->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU) { - ff_vdpau_add_data_chunk(h->cur_pic_ptr->f->data[0], - start_code, - sizeof(start_code)); - ff_vdpau_add_data_chunk(h->cur_pic_ptr->f->data[0], - nal->raw_data, - nal->raw_size); - ret = 0; - } else -#endif ret = ff_h264_execute_decode_slices(h); if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE)) goto end; @@ -728,16 +707,19 @@ static int decode_nal_units(H264Context *h, const uint8_t *buf, int buf_size) h->has_recovery_point = h->has_recovery_point || h->sei.recovery_point.recovery_frame_cnt != -1; if (avctx->debug & FF_DEBUG_GREEN_MD) debug_green_metadata(&h->sei.green_metadata, h->avctx); -#if FF_API_AFD -FF_DISABLE_DEPRECATION_WARNINGS - h->avctx->dtg_active_format = h->sei.afd.active_format_description; -FF_ENABLE_DEPRECATION_WARNINGS -#endif /* FF_API_AFD */ if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE)) goto end; break; case H264_NAL_SPS: { GetBitContext tmp_gb = nal->gb; + if (avctx->hwaccel && avctx->hwaccel->decode_params) { + ret = avctx->hwaccel->decode_params(avctx, + nal->type, + nal->raw_data, + nal->raw_size); + if (ret < 0) + goto end; + } if (ff_h264_decode_seq_parameter_set(&tmp_gb, avctx, &h->ps, 0) >= 0) break; av_log(h->avctx, AV_LOG_DEBUG, @@ -749,6 +731,14 @@ FF_ENABLE_DEPRECATION_WARNINGS break; } case H264_NAL_PPS: + if (avctx->hwaccel && avctx->hwaccel->decode_params) { + ret = avctx->hwaccel->decode_params(avctx, + nal->type, + nal->raw_data, + nal->raw_size); + if (ret < 0) + goto end; + } ret = ff_h264_decode_picture_parameter_set(&nal->gb, avctx, &h->ps, nal->size_bits); if (ret < 0 && (h->avctx->err_recognition & AV_EF_EXPLODE)) @@ -848,9 +838,6 @@ static int output_frame(H264Context *h, AVFrame *dst, H264Picture *srcp) AVFrame *src = srcp->f; int ret; - if (src->format == AV_PIX_FMT_VIDEOTOOLBOX && src->buf[0]->size == 1) - return AVERROR_EXTERNAL; - ret = av_frame_ref(dst, src); if (ret < 0) return ret; @@ -1046,6 +1033,7 @@ static const AVOption h264_options[] = { { "is_avc", "is avc", OFFSET(is_avc), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, 0 }, { "nal_length_size", "nal_length_size", OFFSET(nal_length_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 4, 0 }, { "enable_er", "Enable error resilience on damaged frames (unsafe)", OFFSET(enable_er), AV_OPT_TYPE_BOOL, { .i64 = -1 }, -1, 1, VD }, + { "x264_build", "Assume this x264 version if no x264 version found in any SEI", OFFSET(x264_build), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VD }, { NULL }, }; @@ -1068,6 +1056,30 @@ AVCodec ff_h264_decoder = { .capabilities = /*AV_CODEC_CAP_DRAW_HORIZ_BAND |*/ AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS, + .hw_configs = (const AVCodecHWConfigInternal*[]) { +#if CONFIG_H264_DXVA2_HWACCEL + HWACCEL_DXVA2(h264), +#endif +#if CONFIG_H264_D3D11VA_HWACCEL + HWACCEL_D3D11VA(h264), +#endif +#if CONFIG_H264_D3D11VA2_HWACCEL + HWACCEL_D3D11VA2(h264), +#endif +#if CONFIG_H264_NVDEC_HWACCEL + HWACCEL_NVDEC(h264), +#endif +#if CONFIG_H264_VAAPI_HWACCEL + HWACCEL_VAAPI(h264), +#endif +#if CONFIG_H264_VDPAU_HWACCEL + HWACCEL_VDPAU(h264), +#endif +#if CONFIG_H264_VIDEOTOOLBOX_HWACCEL + HWACCEL_VIDEOTOOLBOX(h264), +#endif + NULL + }, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_EXPORTS_CROPPING, .flush = flush_dpb, .init_thread_copy = ONLY_IF_THREADS_ENABLED(decode_init_thread_copy), @@ -1075,29 +1087,3 @@ AVCodec ff_h264_decoder = { .profiles = NULL_IF_CONFIG_SMALL(ff_h264_profiles), .priv_class = &h264_class, }; - -#if CONFIG_H264_VDPAU_DECODER && FF_API_VDPAU -static const AVClass h264_vdpau_class = { - .class_name = "H264 VDPAU Decoder", - .item_name = av_default_item_name, - .option = h264_options, - .version = LIBAVUTIL_VERSION_INT, -}; - -AVCodec ff_h264_vdpau_decoder = { - .name = "h264_vdpau", - .long_name = NULL_IF_CONFIG_SMALL("H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (VDPAU acceleration)"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_H264, - .priv_data_size = sizeof(H264Context), - .init = h264_decode_init, - .close = h264_decode_end, - .decode = h264_decode_frame, - .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HWACCEL_VDPAU, - .flush = flush_dpb, - .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_VDPAU_H264, - AV_PIX_FMT_NONE}, - .profiles = NULL_IF_CONFIG_SMALL(ff_h264_profiles), - .priv_class = &h264_vdpau_class, -}; -#endif diff --git a/libavcodec/h264dec.h b/libavcodec/h264dec.h index 2106ba077e0f4..1d9723260dd3c 100644 --- a/libavcodec/h264dec.h +++ b/libavcodec/h264dec.h @@ -365,6 +365,7 @@ typedef struct H264Context { int context_initialized; int flags; int workaround_bugs; + int x264_build; /* Set when slice threading is used and at least one slice uses deblocking * mode 1 (i.e. across slice boundaries). Then we disable the loop filter * during normal MB decoding and execute it serially at the end. @@ -416,6 +417,7 @@ typedef struct H264Context { uint8_t (*mvd_table[2])[2]; uint8_t *direct_table; + uint8_t scan_padding[16]; uint8_t zigzag_scan[16]; uint8_t zigzag_scan8x8[64]; uint8_t zigzag_scan8x8_cavlc[64]; diff --git a/libavcodec/h264idct_template.c b/libavcodec/h264idct_template.c index 3ad58c4a11d8b..5993ae2e6e7da 100644 --- a/libavcodec/h264idct_template.c +++ b/libavcodec/h264idct_template.c @@ -76,10 +76,10 @@ void FUNCC(ff_h264_idct8_add)(uint8_t *_dst, int16_t *_block, int stride){ for( i = 0; i < 8; i++ ) { - const unsigned int a0 = block[i+0*8] + block[i+4*8]; - const unsigned int a2 = block[i+0*8] - block[i+4*8]; - const unsigned int a4 = (block[i+2*8]>>1) - block[i+6*8]; - const unsigned int a6 = (block[i+6*8]>>1) + block[i+2*8]; + const unsigned int a0 = block[i+0*8] + (unsigned)block[i+4*8]; + const unsigned int a2 = block[i+0*8] - (unsigned)block[i+4*8]; + const unsigned int a4 = (block[i+2*8]>>1) - (unsigned)block[i+6*8]; + const unsigned int a6 = (block[i+6*8]>>1) + (unsigned)block[i+2*8]; const unsigned int b0 = a0 + a6; const unsigned int b2 = a2 + a4; @@ -91,10 +91,10 @@ void FUNCC(ff_h264_idct8_add)(uint8_t *_dst, int16_t *_block, int stride){ const int a5 = -block[i+1*8] + (unsigned)block[i+7*8] + block[i+5*8] + (block[i+5*8]>>1); const int a7 = block[i+3*8] + (unsigned)block[i+5*8] + block[i+1*8] + (block[i+1*8]>>1); - const int b1 = (a7>>2) + a1; - const int b3 = a3 + (a5>>2); - const int b5 = (a3>>2) - a5; - const int b7 = a7 - (a1>>2); + const int b1 = (a7>>2) + (unsigned)a1; + const int b3 = (unsigned)a3 + (a5>>2); + const int b5 = (a3>>2) - (unsigned)a5; + const int b7 = (unsigned)a7 - (a1>>2); block[i+0*8] = b0 + b7; block[i+7*8] = b0 - b7; @@ -107,10 +107,10 @@ void FUNCC(ff_h264_idct8_add)(uint8_t *_dst, int16_t *_block, int stride){ } for( i = 0; i < 8; i++ ) { - const unsigned a0 = block[0+i*8] + block[4+i*8]; - const unsigned a2 = block[0+i*8] - block[4+i*8]; - const unsigned a4 = (block[2+i*8]>>1) - block[6+i*8]; - const unsigned a6 = (block[6+i*8]>>1) + block[2+i*8]; + const unsigned a0 = block[0+i*8] + (unsigned)block[4+i*8]; + const unsigned a2 = block[0+i*8] - (unsigned)block[4+i*8]; + const unsigned a4 = (block[2+i*8]>>1) - (unsigned)block[6+i*8]; + const unsigned a6 = (block[6+i*8]>>1) + (unsigned)block[2+i*8]; const unsigned b0 = a0 + a6; const unsigned b2 = a2 + a4; diff --git a/libavcodec/h265_metadata_bsf.c b/libavcodec/h265_metadata_bsf.c new file mode 100644 index 0000000000000..26eb2d05d071b --- /dev/null +++ b/libavcodec/h265_metadata_bsf.c @@ -0,0 +1,464 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/common.h" +#include "libavutil/opt.h" + +#include "bsf.h" +#include "cbs.h" +#include "cbs_h265.h" +#include "hevc.h" + +enum { + PASS, + INSERT, + REMOVE, +}; + +typedef struct H265MetadataContext { + const AVClass *class; + + CodedBitstreamContext *cbc; + CodedBitstreamFragment access_unit; + + H265RawAUD aud_nal; + + int aud; + + AVRational sample_aspect_ratio; + + int video_format; + int video_full_range_flag; + int colour_primaries; + int transfer_characteristics; + int matrix_coefficients; + + int chroma_sample_loc_type; + + AVRational tick_rate; + int poc_proportional_to_timing_flag; + int num_ticks_poc_diff_one; + + int crop_left; + int crop_right; + int crop_top; + int crop_bottom; +} H265MetadataContext; + + +static int h265_metadata_update_vps(AVBSFContext *bsf, + H265RawVPS *vps) +{ + H265MetadataContext *ctx = bsf->priv_data; + + if (ctx->tick_rate.num && ctx->tick_rate.den) { + int num, den; + + av_reduce(&num, &den, ctx->tick_rate.num, ctx->tick_rate.den, + UINT32_MAX > INT_MAX ? UINT32_MAX : INT_MAX); + + vps->vps_time_scale = num; + vps->vps_num_units_in_tick = den; + + vps->vps_timing_info_present_flag = 1; + + if (ctx->num_ticks_poc_diff_one > 0) { + vps->vps_num_ticks_poc_diff_one_minus1 = + ctx->num_ticks_poc_diff_one - 1; + vps->vps_poc_proportional_to_timing_flag = 1; + } else if (ctx->num_ticks_poc_diff_one == 0) { + vps->vps_poc_proportional_to_timing_flag = 0; + } + } + + return 0; +} + +static int h265_metadata_update_sps(AVBSFContext *bsf, + H265RawSPS *sps) +{ + H265MetadataContext *ctx = bsf->priv_data; + int need_vui = 0; + int crop_unit_x, crop_unit_y; + + if (ctx->sample_aspect_ratio.num && ctx->sample_aspect_ratio.den) { + // Table E-1. + static const AVRational sar_idc[] = { + { 0, 0 }, // Unspecified (never written here). + { 1, 1 }, { 12, 11 }, { 10, 11 }, { 16, 11 }, + { 40, 33 }, { 24, 11 }, { 20, 11 }, { 32, 11 }, + { 80, 33 }, { 18, 11 }, { 15, 11 }, { 64, 33 }, + { 160, 99 }, { 4, 3 }, { 3, 2 }, { 2, 1 }, + }; + int num, den, i; + + av_reduce(&num, &den, ctx->sample_aspect_ratio.num, + ctx->sample_aspect_ratio.den, 65535); + + for (i = 1; i < FF_ARRAY_ELEMS(sar_idc); i++) { + if (num == sar_idc[i].num && + den == sar_idc[i].den) + break; + } + if (i == FF_ARRAY_ELEMS(sar_idc)) { + sps->vui.aspect_ratio_idc = 255; + sps->vui.sar_width = num; + sps->vui.sar_height = den; + } else { + sps->vui.aspect_ratio_idc = i; + } + sps->vui.aspect_ratio_info_present_flag = 1; + need_vui = 1; + } + +#define SET_OR_INFER(field, value, present_flag, infer) do { \ + if (value >= 0) { \ + field = value; \ + need_vui = 1; \ + } else if (!present_flag) \ + field = infer; \ + } while (0) + + if (ctx->video_format >= 0 || + ctx->video_full_range_flag >= 0 || + ctx->colour_primaries >= 0 || + ctx->transfer_characteristics >= 0 || + ctx->matrix_coefficients >= 0) { + + SET_OR_INFER(sps->vui.video_format, ctx->video_format, + sps->vui.video_signal_type_present_flag, 5); + + SET_OR_INFER(sps->vui.video_full_range_flag, + ctx->video_full_range_flag, + sps->vui.video_signal_type_present_flag, 0); + + if (ctx->colour_primaries >= 0 || + ctx->transfer_characteristics >= 0 || + ctx->matrix_coefficients >= 0) { + + SET_OR_INFER(sps->vui.colour_primaries, + ctx->colour_primaries, + sps->vui.colour_description_present_flag, 2); + + SET_OR_INFER(sps->vui.transfer_characteristics, + ctx->transfer_characteristics, + sps->vui.colour_description_present_flag, 2); + + SET_OR_INFER(sps->vui.matrix_coefficients, + ctx->matrix_coefficients, + sps->vui.colour_description_present_flag, 2); + + sps->vui.colour_description_present_flag = 1; + } + sps->vui.video_signal_type_present_flag = 1; + need_vui = 1; + } + + if (ctx->chroma_sample_loc_type >= 0) { + sps->vui.chroma_sample_loc_type_top_field = + ctx->chroma_sample_loc_type; + sps->vui.chroma_sample_loc_type_bottom_field = + ctx->chroma_sample_loc_type; + sps->vui.chroma_loc_info_present_flag = 1; + need_vui = 1; + } + + if (ctx->tick_rate.num && ctx->tick_rate.den) { + int num, den; + + av_reduce(&num, &den, ctx->tick_rate.num, ctx->tick_rate.den, + UINT32_MAX > INT_MAX ? UINT32_MAX : INT_MAX); + + sps->vui.vui_time_scale = num; + sps->vui.vui_num_units_in_tick = den; + + sps->vui.vui_timing_info_present_flag = 1; + need_vui = 1; + + if (ctx->num_ticks_poc_diff_one > 0) { + sps->vui.vui_num_ticks_poc_diff_one_minus1 = + ctx->num_ticks_poc_diff_one - 1; + sps->vui.vui_poc_proportional_to_timing_flag = 1; + } else if (ctx->num_ticks_poc_diff_one == 0) { + sps->vui.vui_poc_proportional_to_timing_flag = 0; + } + } + + if (sps->separate_colour_plane_flag || sps->chroma_format_idc == 0) { + crop_unit_x = 1; + crop_unit_y = 1; + } else { + crop_unit_x = 1 + (sps->chroma_format_idc < 3); + crop_unit_y = 1 + (sps->chroma_format_idc < 2); + } +#define CROP(border, unit) do { \ + if (ctx->crop_ ## border >= 0) { \ + if (ctx->crop_ ## border % unit != 0) { \ + av_log(bsf, AV_LOG_ERROR, "Invalid value for crop_%s: " \ + "must be a multiple of %d.\n", #border, unit); \ + return AVERROR(EINVAL); \ + } \ + sps->conf_win_ ## border ## _offset = \ + ctx->crop_ ## border / unit; \ + sps->conformance_window_flag = 1; \ + } \ + } while (0) + CROP(left, crop_unit_x); + CROP(right, crop_unit_x); + CROP(top, crop_unit_y); + CROP(bottom, crop_unit_y); +#undef CROP + + if (need_vui) + sps->vui_parameters_present_flag = 1; + + return 0; +} + +static int h265_metadata_filter(AVBSFContext *bsf, AVPacket *out) +{ + H265MetadataContext *ctx = bsf->priv_data; + AVPacket *in = NULL; + CodedBitstreamFragment *au = &ctx->access_unit; + int err, i; + + err = ff_bsf_get_packet(bsf, &in); + if (err < 0) + return err; + + err = ff_cbs_read_packet(ctx->cbc, au, in); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read packet.\n"); + goto fail; + } + + if (au->nb_units == 0) { + av_log(bsf, AV_LOG_ERROR, "No NAL units in packet.\n"); + err = AVERROR_INVALIDDATA; + goto fail; + } + + // If an AUD is present, it must be the first NAL unit. + if (au->units[0].type == HEVC_NAL_AUD) { + if (ctx->aud == REMOVE) + ff_cbs_delete_unit(ctx->cbc, au, 0); + } else { + if (ctx->aud == INSERT) { + H265RawAUD *aud = &ctx->aud_nal; + int pic_type = 0, temporal_id = 8, layer_id = 0; + + for (i = 0; i < au->nb_units; i++) { + const H265RawNALUnitHeader *nal = au->units[i].content; + if (!nal) + continue; + if (nal->nuh_temporal_id_plus1 < temporal_id + 1) + temporal_id = nal->nuh_temporal_id_plus1 - 1; + + if (au->units[i].type <= HEVC_NAL_RSV_VCL31) { + const H265RawSlice *slice = au->units[i].content; + layer_id = nal->nuh_layer_id; + if (slice->header.slice_type == HEVC_SLICE_B && + pic_type < 2) + pic_type = 2; + if (slice->header.slice_type == HEVC_SLICE_P && + pic_type < 1) + pic_type = 1; + } + } + + aud->nal_unit_header = (H265RawNALUnitHeader) { + .nal_unit_type = HEVC_NAL_AUD, + .nuh_layer_id = layer_id, + .nuh_temporal_id_plus1 = temporal_id + 1, + }; + aud->pic_type = pic_type; + + err = ff_cbs_insert_unit_content(ctx->cbc, au, + 0, HEVC_NAL_AUD, aud, NULL); + if (err) { + av_log(bsf, AV_LOG_ERROR, "Failed to insert AUD.\n"); + goto fail; + } + } + } + + for (i = 0; i < au->nb_units; i++) { + if (au->units[i].type == HEVC_NAL_VPS) { + err = h265_metadata_update_vps(bsf, au->units[i].content); + if (err < 0) + goto fail; + } + if (au->units[i].type == HEVC_NAL_SPS) { + err = h265_metadata_update_sps(bsf, au->units[i].content); + if (err < 0) + goto fail; + } + } + + err = ff_cbs_write_packet(ctx->cbc, out, au); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to write packet.\n"); + goto fail; + } + + err = av_packet_copy_props(out, in); + if (err < 0) + goto fail; + + err = 0; +fail: + ff_cbs_fragment_uninit(ctx->cbc, au); + + if (err < 0) + av_packet_unref(out); + av_packet_free(&in); + + return err; +} + +static int h265_metadata_init(AVBSFContext *bsf) +{ + H265MetadataContext *ctx = bsf->priv_data; + CodedBitstreamFragment *au = &ctx->access_unit; + int err, i; + + err = ff_cbs_init(&ctx->cbc, AV_CODEC_ID_HEVC, bsf); + if (err < 0) + return err; + + if (bsf->par_in->extradata) { + err = ff_cbs_read_extradata(ctx->cbc, au, bsf->par_in); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read extradata.\n"); + goto fail; + } + + for (i = 0; i < au->nb_units; i++) { + if (au->units[i].type == HEVC_NAL_VPS) { + err = h265_metadata_update_vps(bsf, au->units[i].content); + if (err < 0) + goto fail; + } + if (au->units[i].type == HEVC_NAL_SPS) { + err = h265_metadata_update_sps(bsf, au->units[i].content); + if (err < 0) + goto fail; + } + } + + err = ff_cbs_write_extradata(ctx->cbc, bsf->par_out, au); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to write extradata.\n"); + goto fail; + } + } + + err = 0; +fail: + ff_cbs_fragment_uninit(ctx->cbc, au); + return err; +} + +static void h265_metadata_close(AVBSFContext *bsf) +{ + H265MetadataContext *ctx = bsf->priv_data; + ff_cbs_close(&ctx->cbc); +} + +#define OFFSET(x) offsetof(H265MetadataContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM) +static const AVOption h265_metadata_options[] = { + { "aud", "Access Unit Delimiter NAL units", + OFFSET(aud), AV_OPT_TYPE_INT, + { .i64 = PASS }, PASS, REMOVE, FLAGS, "aud" }, + { "pass", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = PASS }, .flags = FLAGS, .unit = "aud" }, + { "insert", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = INSERT }, .flags = FLAGS, .unit = "aud" }, + { "remove", NULL, 0, AV_OPT_TYPE_CONST, + { .i64 = REMOVE }, .flags = FLAGS, .unit = "aud" }, + + { "sample_aspect_ratio", "Set sample aspect ratio (table E-1)", + OFFSET(sample_aspect_ratio), AV_OPT_TYPE_RATIONAL, + { .dbl = 0.0 }, 0, 65535, FLAGS }, + + { "video_format", "Set video format (table E-2)", + OFFSET(video_format), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 7, FLAGS }, + { "video_full_range_flag", "Set video full range flag", + OFFSET(video_full_range_flag), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 1, FLAGS }, + { "colour_primaries", "Set colour primaries (table E-3)", + OFFSET(colour_primaries), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255, FLAGS }, + { "transfer_characteristics", "Set transfer characteristics (table E-4)", + OFFSET(transfer_characteristics), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255, FLAGS }, + { "matrix_coefficients", "Set matrix coefficients (table E-5)", + OFFSET(matrix_coefficients), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255, FLAGS }, + + { "chroma_sample_loc_type", "Set chroma sample location type (figure E-1)", + OFFSET(chroma_sample_loc_type), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 6, FLAGS }, + + { "tick_rate", + "Set VPS and VUI tick rate (num_units_in_tick / time_scale)", + OFFSET(tick_rate), AV_OPT_TYPE_RATIONAL, + { .dbl = 0.0 }, 0, UINT_MAX, FLAGS }, + { "num_ticks_poc_diff_one", + "Set VPS and VUI number of ticks per POC increment", + OFFSET(num_ticks_poc_diff_one), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, INT_MAX, FLAGS }, + + { "crop_left", "Set left border crop offset", + OFFSET(crop_left), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, HEVC_MAX_WIDTH, FLAGS }, + { "crop_right", "Set right border crop offset", + OFFSET(crop_right), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, HEVC_MAX_WIDTH, FLAGS }, + { "crop_top", "Set top border crop offset", + OFFSET(crop_top), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, HEVC_MAX_HEIGHT, FLAGS }, + { "crop_bottom", "Set bottom border crop offset", + OFFSET(crop_bottom), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, HEVC_MAX_HEIGHT, FLAGS }, + + { NULL } +}; + +static const AVClass h265_metadata_class = { + .class_name = "h265_metadata_bsf", + .item_name = av_default_item_name, + .option = h265_metadata_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const enum AVCodecID h265_metadata_codec_ids[] = { + AV_CODEC_ID_HEVC, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_hevc_metadata_bsf = { + .name = "hevc_metadata", + .priv_data_size = sizeof(H265MetadataContext), + .priv_class = &h265_metadata_class, + .init = &h265_metadata_init, + .close = &h265_metadata_close, + .filter = &h265_metadata_filter, + .codec_ids = h265_metadata_codec_ids, +}; diff --git a/libavcodec/hap.c b/libavcodec/hap.c index 5b3af5e1d0f49..1a330c9c9b3cc 100644 --- a/libavcodec/hap.c +++ b/libavcodec/hap.c @@ -53,3 +53,25 @@ av_cold void ff_hap_free_context(HapContext *ctx) av_freep(&ctx->chunks); av_freep(&ctx->chunk_results); } + +int ff_hap_parse_section_header(GetByteContext *gbc, int *section_size, + enum HapSectionType *section_type) +{ + if (bytestream2_get_bytes_left(gbc) < 4) + return AVERROR_INVALIDDATA; + + *section_size = bytestream2_get_le24(gbc); + *section_type = bytestream2_get_byte(gbc); + + if (*section_size == 0) { + if (bytestream2_get_bytes_left(gbc) < 4) + return AVERROR_INVALIDDATA; + + *section_size = bytestream2_get_le32(gbc); + } + + if (*section_size > bytestream2_get_bytes_left(gbc) || *section_size < 0) + return AVERROR_INVALIDDATA; + else + return 0; +} diff --git a/libavcodec/hap.h b/libavcodec/hap.h index 0ee65335d913b..bbeed11e32984 100644 --- a/libavcodec/hap.h +++ b/libavcodec/hap.h @@ -73,6 +73,7 @@ typedef struct HapContext { int *chunk_results; /* Results from threaded operations */ int tex_rat; /* Compression ratio */ + int tex_rat2; /* Compression ratio of the second texture */ const uint8_t *tex_data; /* Compressed texture */ uint8_t *tex_buf; /* Buffer for compressed texture */ size_t tex_size; /* Size of the compressed texture */ @@ -81,8 +82,13 @@ typedef struct HapContext { int slice_count; /* Number of slices for threaded operations */ + int texture_count; /* 2 for HAQA, 1 for other version */ + int texture_section_size; /* size of the part of the texture section (for HAPQA) */ + int uncompress_pix_size; /* nb of byte / pixel for the target picture */ + /* Pointer to the selected compress or decompress function */ int (*tex_fun)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*tex_fun2)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block); } HapContext; /* @@ -97,4 +103,10 @@ int ff_hap_set_chunk_count(HapContext *ctx, int count, int first_in_frame); */ av_cold void ff_hap_free_context(HapContext *ctx); +/* The first three bytes are the size of the section past the header, or zero + * if the length is stored in the next long word. The fourth byte in the first + * long word indicates the type of the current section. */ +int ff_hap_parse_section_header(GetByteContext *gbc, int *section_size, + enum HapSectionType *section_type); + #endif /* AVCODEC_HAP_H */ diff --git a/libavcodec/hapdec.c b/libavcodec/hapdec.c index fc9dff10f1923..8c845770cf3d5 100644 --- a/libavcodec/hapdec.c +++ b/libavcodec/hapdec.c @@ -3,6 +3,8 @@ * Copyright (C) 2015 Vittorio Giovara * Copyright (C) 2015 Tom Butterworth * + * HapQA and HAPAlphaOnly added by Jokyo Images + * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -41,31 +43,6 @@ #include "texturedsp.h" #include "thread.h" -/* The first three bytes are the size of the section past the header, or zero - * if the length is stored in the next long word. The fourth byte in the first - * long word indicates the type of the current section. */ -static int parse_section_header(GetByteContext *gbc, int *section_size, - enum HapSectionType *section_type) -{ - if (bytestream2_get_bytes_left(gbc) < 4) - return AVERROR_INVALIDDATA; - - *section_size = bytestream2_get_le24(gbc); - *section_type = bytestream2_get_byte(gbc); - - if (*section_size == 0) { - if (bytestream2_get_bytes_left(gbc) < 4) - return AVERROR_INVALIDDATA; - - *section_size = bytestream2_get_le32(gbc); - } - - if (*section_size > bytestream2_get_bytes_left(gbc) || *section_size < 0) - return AVERROR_INVALIDDATA; - else - return 0; -} - static int hap_parse_decode_instructions(HapContext *ctx, int size) { GetByteContext *gbc = &ctx->gbc; @@ -76,7 +53,7 @@ static int hap_parse_decode_instructions(HapContext *ctx, int size) while (size > 0) { int stream_remaining = bytestream2_get_bytes_left(gbc); - ret = parse_section_header(gbc, §ion_size, §ion_type); + ret = ff_hap_parse_section_header(gbc, §ion_size, §ion_type); if (ret != 0) return ret; @@ -157,14 +134,16 @@ static int hap_parse_frame_header(AVCodecContext *avctx) const char *compressorstr; int i, ret; - ret = parse_section_header(gbc, §ion_size, §ion_type); + ret = ff_hap_parse_section_header(gbc, &ctx->texture_section_size, §ion_type); if (ret != 0) return ret; if ((avctx->codec_tag == MKTAG('H','a','p','1') && (section_type & 0x0F) != HAP_FMT_RGBDXT1) || (avctx->codec_tag == MKTAG('H','a','p','5') && (section_type & 0x0F) != HAP_FMT_RGBADXT5) || (avctx->codec_tag == MKTAG('H','a','p','Y') && (section_type & 0x0F) != HAP_FMT_YCOCGDXT5) || - (avctx->codec_tag == MKTAG('H','a','p','A') && (section_type & 0x0F) != HAP_FMT_RGTC1)) { + (avctx->codec_tag == MKTAG('H','a','p','A') && (section_type & 0x0F) != HAP_FMT_RGTC1) || + ((avctx->codec_tag == MKTAG('H','a','p','M') && (section_type & 0x0F) != HAP_FMT_RGTC1) && + (section_type & 0x0F) != HAP_FMT_YCOCGDXT5)) { av_log(avctx, AV_LOG_ERROR, "Invalid texture format %#04x.\n", section_type & 0x0F); return AVERROR_INVALIDDATA; @@ -177,7 +156,7 @@ static int hap_parse_frame_header(AVCodecContext *avctx) if (ret == 0) { ctx->chunks[0].compressor = section_type & 0xF0; ctx->chunks[0].compressed_offset = 0; - ctx->chunks[0].compressed_size = section_size; + ctx->chunks[0].compressed_size = ctx->texture_section_size; } if (ctx->chunks[0].compressor == HAP_COMP_NONE) { compressorstr = "none"; @@ -186,7 +165,7 @@ static int hap_parse_frame_header(AVCodecContext *avctx) } break; case HAP_COMP_COMPLEX: - ret = parse_section_header(gbc, §ion_size, §ion_type); + ret = ff_hap_parse_section_header(gbc, §ion_size, §ion_type); if (ret == 0 && section_type != HAP_ST_DECODE_INSTRUCTIONS) ret = AVERROR_INVALIDDATA; if (ret == 0) @@ -266,8 +245,8 @@ static int decompress_chunks_thread(AVCodecContext *avctx, void *arg, return 0; } -static int decompress_texture_thread(AVCodecContext *avctx, void *arg, - int slice, int thread_nb) +static int decompress_texture_thread_internal(AVCodecContext *avctx, void *arg, + int slice, int thread_nb, int texture_num) { HapContext *ctx = avctx->priv_data; AVFrame *frame = arg; @@ -295,70 +274,118 @@ static int decompress_texture_thread(AVCodecContext *avctx, void *arg, uint8_t *p = frame->data[0] + y * frame->linesize[0] * TEXTURE_BLOCK_H; int off = y * w_block; for (x = 0; x < w_block; x++) { - ctx->tex_fun(p + x * 16, frame->linesize[0], - d + (off + x) * ctx->tex_rat); + if (texture_num == 0) { + ctx->tex_fun(p + x * 4 * ctx->uncompress_pix_size, frame->linesize[0], + d + (off + x) * ctx->tex_rat); + } else { + ctx->tex_fun2(p + x * 4 * ctx->uncompress_pix_size, frame->linesize[0], + d + (off + x) * ctx->tex_rat2); + } } } return 0; } +static int decompress_texture_thread(AVCodecContext *avctx, void *arg, + int slice, int thread_nb) +{ + return decompress_texture_thread_internal(avctx, arg, slice, thread_nb, 0); +} + +static int decompress_texture2_thread(AVCodecContext *avctx, void *arg, + int slice, int thread_nb) +{ + return decompress_texture_thread_internal(avctx, arg, slice, thread_nb, 1); +} + static int hap_decode(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt) { HapContext *ctx = avctx->priv_data; ThreadFrame tframe; - int ret, i; + int ret, i, t; int tex_size; + int section_size; + enum HapSectionType section_type; + int start_texture_section = 0; + int tex_rat[2] = {0, 0}; bytestream2_init(&ctx->gbc, avpkt->data, avpkt->size); - /* Check for section header */ - ret = hap_parse_frame_header(avctx); - if (ret < 0) - return ret; + tex_rat[0] = ctx->tex_rat; + + /* check for multi texture header */ + if (ctx->texture_count == 2) { + ret = ff_hap_parse_section_header(&ctx->gbc, §ion_size, §ion_type); + if (ret != 0) + return ret; + if ((section_type & 0x0F) != 0x0D) { + av_log(avctx, AV_LOG_ERROR, "Invalid section type in 2 textures mode %#04x.\n", section_type); + return AVERROR_INVALIDDATA; + } + start_texture_section = 4; + tex_rat[1] = ctx->tex_rat2; + } /* Get the output frame ready to receive data */ tframe.f = data; ret = ff_thread_get_buffer(avctx, &tframe, 0); if (ret < 0) return ret; - if (avctx->codec->update_thread_context) - ff_thread_finish_setup(avctx); - - /* Unpack the DXT texture */ - if (hap_can_use_tex_in_place(ctx)) { - /* Only DXTC texture compression in a contiguous block */ - ctx->tex_data = ctx->gbc.buffer; - tex_size = bytestream2_get_bytes_left(&ctx->gbc); - } else { - /* Perform the second-stage decompression */ - ret = av_reallocp(&ctx->tex_buf, ctx->tex_size); + + for (t = 0; t < ctx->texture_count; t++) { + bytestream2_seek(&ctx->gbc, start_texture_section, SEEK_SET); + + /* Check for section header */ + ret = hap_parse_frame_header(avctx); if (ret < 0) return ret; - avctx->execute2(avctx, decompress_chunks_thread, NULL, - ctx->chunk_results, ctx->chunk_count); + start_texture_section += ctx->texture_section_size + 4; - for (i = 0; i < ctx->chunk_count; i++) { - if (ctx->chunk_results[i] < 0) - return ctx->chunk_results[i]; + if (avctx->codec->update_thread_context) + ff_thread_finish_setup(avctx); + + /* Unpack the DXT texture */ + if (hap_can_use_tex_in_place(ctx)) { + /* Only DXTC texture compression in a contiguous block */ + ctx->tex_data = ctx->gbc.buffer; + tex_size = FFMIN(ctx->texture_section_size, bytestream2_get_bytes_left(&ctx->gbc)); + } else { + /* Perform the second-stage decompression */ + ret = av_reallocp(&ctx->tex_buf, ctx->tex_size); + if (ret < 0) + return ret; + + avctx->execute2(avctx, decompress_chunks_thread, NULL, + ctx->chunk_results, ctx->chunk_count); + + for (i = 0; i < ctx->chunk_count; i++) { + if (ctx->chunk_results[i] < 0) + return ctx->chunk_results[i]; + } + + ctx->tex_data = ctx->tex_buf; + tex_size = ctx->tex_size; } - ctx->tex_data = ctx->tex_buf; - tex_size = ctx->tex_size; - } + if (tex_size < (avctx->coded_width / TEXTURE_BLOCK_W) + *(avctx->coded_height / TEXTURE_BLOCK_H) + *tex_rat[t]) { + av_log(avctx, AV_LOG_ERROR, "Insufficient data\n"); + return AVERROR_INVALIDDATA; + } - if (tex_size < (avctx->coded_width / TEXTURE_BLOCK_W) - *(avctx->coded_height / TEXTURE_BLOCK_H) - *ctx->tex_rat) { - av_log(avctx, AV_LOG_ERROR, "Insufficient data\n"); - return AVERROR_INVALIDDATA; + /* Use the decompress function on the texture, one block per thread */ + if (t == 0){ + avctx->execute2(avctx, decompress_texture_thread, tframe.f, NULL, ctx->slice_count); + } else{ + tframe.f = data; + avctx->execute2(avctx, decompress_texture2_thread, tframe.f, NULL, ctx->slice_count); + } } - /* Use the decompress function on the texture, one block per thread */ - avctx->execute2(avctx, decompress_texture_thread, tframe.f, NULL, ctx->slice_count); - /* Frame is ready to be output */ tframe.f->pict_type = AV_PICTURE_TYPE_I; tframe.f->key_frame = 1; @@ -385,6 +412,9 @@ static av_cold int hap_init(AVCodecContext *avctx) ff_texturedsp_init(&ctx->dxtc); + ctx->texture_count = 1; + ctx->uncompress_pix_size = 4; + switch (avctx->codec_tag) { case MKTAG('H','a','p','1'): texture_name = "DXT1"; @@ -407,12 +437,19 @@ static av_cold int hap_init(AVCodecContext *avctx) case MKTAG('H','a','p','A'): texture_name = "RGTC1"; ctx->tex_rat = 8; - ctx->tex_fun = ctx->dxtc.rgtc1u_block; - avctx->pix_fmt = AV_PIX_FMT_RGB0; + ctx->tex_fun = ctx->dxtc.rgtc1u_gray_block; + avctx->pix_fmt = AV_PIX_FMT_GRAY8; + ctx->uncompress_pix_size = 1; break; case MKTAG('H','a','p','M'): - avpriv_report_missing_feature(avctx, "HapQAlpha"); - return AVERROR_PATCHWELCOME; + texture_name = "DXT5-YCoCg-scaled / RGTC1"; + ctx->tex_rat = 16; + ctx->tex_rat2 = 8; + ctx->tex_fun = ctx->dxtc.dxt5ys_block; + ctx->tex_fun2 = ctx->dxtc.rgtc1u_alpha_block; + avctx->pix_fmt = AV_PIX_FMT_RGBA; + ctx->texture_count = 2; + break; default: return AVERROR_DECODER_NOT_FOUND; } diff --git a/libavcodec/hapqa_extract_bsf.c b/libavcodec/hapqa_extract_bsf.c new file mode 100644 index 0000000000000..5c22184813ddf --- /dev/null +++ b/libavcodec/hapqa_extract_bsf.c @@ -0,0 +1,134 @@ +/* + * HAPQA extract bitstream filter + * Copyright (c) 2017 Jokyo Images + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * HAPQA extract bitstream filter + * extract one of the two textures of the HAQA + */ + +#include "avcodec.h" +#include "bsf.h" +#include "bytestream.h" +#include "hap.h" + +typedef struct HapqaExtractContext { + const AVClass *class; + int texture;/* index of the texture to keep (0 for rgb or 1 for alpha) */ +} HapqaExtractContext; + +static int check_texture(HapqaExtractContext *ctx, int section_type) { + if (((ctx->texture == 0)&&((section_type & 0x0F) == 0x0F)) || /* HapQ texture and rgb extract */ + ((ctx->texture == 1)&&((section_type & 0x0F) == 0x01))) /* HapAlphaOnly texture and alpha extract */ + { + return 1; /* the texture is the one to keep */ + } else { + return 0; + } +} + +static int hapqa_extract(AVBSFContext *bsf, AVPacket *pkt) +{ + HapqaExtractContext *ctx = bsf->priv_data; + GetByteContext gbc; + int section_size; + enum HapSectionType section_type; + int start_section_size; + int target_packet_size = 0; + int ret = 0; + + ret = ff_bsf_get_packet_ref(bsf, pkt); + if (ret < 0) + return ret; + + bytestream2_init(&gbc, pkt->data, pkt->size); + ret = ff_hap_parse_section_header(&gbc, §ion_size, §ion_type); + if (ret != 0) + goto fail; + + if ((section_type & 0x0F) != 0x0D) { + av_log(bsf, AV_LOG_ERROR, "Invalid section type for HAPQA %#04x.\n", section_type & 0x0F); + ret = AVERROR_INVALIDDATA; + goto fail; + } + + start_section_size = 4; + + bytestream2_seek(&gbc, start_section_size, SEEK_SET);/* go to start of the first texture */ + + ret = ff_hap_parse_section_header(&gbc, §ion_size, §ion_type); + if (ret != 0) + goto fail; + + target_packet_size = section_size + 4; + + if (check_texture(ctx, section_type) == 0) { /* the texture is not the one to keep */ + start_section_size += 4 + section_size; + bytestream2_seek(&gbc, start_section_size, SEEK_SET);/* go to start of the second texture */ + ret = ff_hap_parse_section_header(&gbc, §ion_size, §ion_type); + if (ret != 0) + goto fail; + + target_packet_size = section_size + 4; + + if (check_texture(ctx, section_type) == 0){ /* the second texture is not the one to keep */ + av_log(bsf, AV_LOG_ERROR, "No valid texture found.\n"); + ret = AVERROR_INVALIDDATA; + goto fail; + } + } + + pkt->data += start_section_size; + pkt->size = target_packet_size; + +fail: + if (ret < 0) + av_packet_unref(pkt); + return ret; +} + +static const enum AVCodecID codec_ids[] = { + AV_CODEC_ID_HAP, AV_CODEC_ID_NONE, +}; + +#define OFFSET(x) offsetof(HapqaExtractContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_BSF_PARAM) +static const AVOption options[] = { + { "texture", "texture to keep", OFFSET(texture), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS, "texture" }, + { "color", "keep HapQ texture", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, FLAGS, "texture" }, + { "alpha", "keep HapAlphaOnly texture", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, FLAGS, "texture" }, + { NULL }, +}; + +static const AVClass hapqa_extract_class = { + .class_name = "hapqa_extract_bsf", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const AVBitStreamFilter ff_hapqa_extract_bsf = { + .name = "hapqa_extract", + .filter = hapqa_extract, + .priv_data_size = sizeof(HapqaExtractContext), + .priv_class = &hapqa_extract_class, + .codec_ids = codec_ids, +}; diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h index f0fb919a7f26c..2f20db82856e1 100644 --- a/libavcodec/hevc.h +++ b/libavcodec/hevc.h @@ -74,19 +74,60 @@ enum HEVCSliceType { HEVC_SLICE_I = 2, }; -/** - * 7.4.2.1 - */ -#define HEVC_MAX_SUB_LAYERS 7 -#define HEVC_MAX_VPS_COUNT 16 -#define HEVC_MAX_SPS_COUNT 32 -#define HEVC_MAX_PPS_COUNT 256 -#define HEVC_MAX_SHORT_TERM_RPS_COUNT 64 -#define HEVC_MAX_CU_SIZE 128 +enum { + // 7.4.3.1: vps_max_layers_minus1 is in [0, 62]. + HEVC_MAX_LAYERS = 63, + // 7.4.3.1: vps_max_sub_layers_minus1 is in [0, 6]. + HEVC_MAX_SUB_LAYERS = 7, + // 7.4.3.1: vps_num_layer_sets_minus1 is in [0, 1023]. + HEVC_MAX_LAYER_SETS = 1024, + + // 7.4.2.1: vps_video_parameter_set_id is u(4). + HEVC_MAX_VPS_COUNT = 16, + // 7.4.3.2.1: sps_seq_parameter_set_id is in [0, 15]. + HEVC_MAX_SPS_COUNT = 16, + // 7.4.3.3.1: pps_pic_parameter_set_id is in [0, 63]. + HEVC_MAX_PPS_COUNT = 64, + + // A.4.2: MaxDpbSize is bounded above by 16. + HEVC_MAX_DPB_SIZE = 16, + // 7.4.3.1: vps_max_dec_pic_buffering_minus1[i] is in [0, MaxDpbSize - 1]. + HEVC_MAX_REFS = HEVC_MAX_DPB_SIZE, + + // 7.4.3.2.1: num_short_term_ref_pic_sets is in [0, 64]. + HEVC_MAX_SHORT_TERM_REF_PIC_SETS = 64, + // 7.4.3.2.1: num_long_term_ref_pics_sps is in [0, 32]. + HEVC_MAX_LONG_TERM_REF_PICS = 32, -#define HEVC_MAX_REFS 16 -#define HEVC_MAX_DPB_SIZE 16 // A.4.1 + // A.3: all profiles require that CtbLog2SizeY is in [4, 6]. + HEVC_MIN_LOG2_CTB_SIZE = 4, + HEVC_MAX_LOG2_CTB_SIZE = 6, + + // E.3.2: cpb_cnt_minus1[i] is in [0, 31]. + HEVC_MAX_CPB_CNT = 32, + + // A.4.1: in table A.6 the highest level allows a MaxLumaPs of 35 651 584. + HEVC_MAX_LUMA_PS = 35651584, + // A.4.1: pic_width_in_luma_samples and pic_height_in_luma_samples are + // constrained to be not greater than sqrt(MaxLumaPs * 8). Hence height/ + // width are bounded above by sqrt(8 * 35651584) = 16888.2 samples. + HEVC_MAX_WIDTH = 16888, + HEVC_MAX_HEIGHT = 16888, + + // A.4.1: table A.6 allows at most 22 tile rows for any level. + HEVC_MAX_TILE_ROWS = 22, + // A.4.1: table A.6 allows at most 20 tile columns for any level. + HEVC_MAX_TILE_COLUMNS = 20, + + // 7.4.7.1: in the worst case (tiles_enabled_flag and + // entropy_coding_sync_enabled_flag are both set), entry points can be + // placed at the beginning of every Ctb row in every tile, giving an + // upper bound of (num_tile_columns_minus1 + 1) * PicHeightInCtbsY - 1. + // Only a stream with very high resolution and perverse parameters could + // get near that, though, so set a lower limit here with the maximum + // possible value for 4K video (at most 135 16x16 Ctb rows). + HEVC_MAX_ENTRY_POINT_OFFSETS = HEVC_MAX_TILE_COLUMNS * 135, +}; -#define HEVC_MAX_LOG2_CTB_SIZE 6 #endif /* AVCODEC_HEVC_H */ diff --git a/libavcodec/hevc_cabac.c b/libavcodec/hevc_cabac.c index 853fd3f72297c..faa36d545935f 100644 --- a/libavcodec/hevc_cabac.c +++ b/libavcodec/hevc_cabac.c @@ -646,8 +646,10 @@ int ff_hevc_cu_qp_delta_abs(HEVCContext *s) suffix_val += 1 << k; k++; } - if (k == CABAC_MAX_BIN) + if (k == CABAC_MAX_BIN) { av_log(s->avctx, AV_LOG_ERROR, "CABAC_MAX_BIN : %d\n", k); + return AVERROR_INVALIDDATA; + } while (k--) suffix_val += get_cabac_bypass(&s->HEVClc->cc) << k; @@ -988,16 +990,19 @@ static av_always_inline int coeff_abs_level_remaining_decode(HEVCContext *s, int while (prefix < CABAC_MAX_BIN && get_cabac_bypass(&s->HEVClc->cc)) prefix++; - if (prefix == CABAC_MAX_BIN) { - av_log(s->avctx, AV_LOG_ERROR, "CABAC_MAX_BIN : %d\n", prefix); - return 0; - } + if (prefix < 3) { for (i = 0; i < rc_rice_param; i++) suffix = (suffix << 1) | get_cabac_bypass(&s->HEVClc->cc); last_coeff_abs_level_remaining = (prefix << rc_rice_param) + suffix; } else { int prefix_minus3 = prefix - 3; + + if (prefix == CABAC_MAX_BIN || prefix_minus3 + rc_rice_param >= 31) { + av_log(s->avctx, AV_LOG_ERROR, "CABAC_MAX_BIN : %d\n", prefix); + return 0; + } + for (i = 0; i < prefix_minus3 + rc_rice_param; i++) suffix = (suffix << 1) | get_cabac_bypass(&s->HEVClc->cc); last_coeff_abs_level_remaining = (((1 << prefix_minus3) + 3 - 1) diff --git a/libavcodec/hevc_filter.c b/libavcodec/hevc_filter.c index b53f4cc72129b..6b9824088c3ce 100644 --- a/libavcodec/hevc_filter.c +++ b/libavcodec/hevc_filter.c @@ -842,9 +842,20 @@ void ff_hevc_deblocking_boundary_strengths(HEVCContext *s, int x0, int y0, void ff_hevc_hls_filter(HEVCContext *s, int x, int y, int ctb_size) { int x_end = x >= s->ps.sps->width - ctb_size; - if (s->avctx->skip_loop_filter < AVDISCARD_ALL) + int skip = 0; + if (s->avctx->skip_loop_filter >= AVDISCARD_ALL || + (s->avctx->skip_loop_filter >= AVDISCARD_NONKEY && !IS_IDR(s)) || + (s->avctx->skip_loop_filter >= AVDISCARD_NONINTRA && + s->sh.slice_type != HEVC_SLICE_I) || + (s->avctx->skip_loop_filter >= AVDISCARD_BIDIR && + s->sh.slice_type == HEVC_SLICE_B) || + (s->avctx->skip_loop_filter >= AVDISCARD_NONREF && + ff_hevc_nal_is_nonref(s->nal_unit_type))) + skip = 1; + + if (!skip) deblocking_filter_CTB(s, x, y); - if (s->ps.sps->sao_enabled) { + if (s->ps.sps->sao_enabled && !skip) { int y_end = y >= s->ps.sps->height - ctb_size; if (y && x) sao_filter_CTB(s, x - ctb_size, y - ctb_size); diff --git a/libavcodec/hevc_mvs.c b/libavcodec/hevc_mvs.c index a8f7876b59b20..fd0dbd9a5613c 100644 --- a/libavcodec/hevc_mvs.c +++ b/libavcodec/hevc_mvs.c @@ -482,7 +482,7 @@ void ff_hevc_luma_mv_merge_mode(HEVCContext *s, int x0, int y0, int nPbW, { int singleMCLFlag = 0; int nCS = 1 << log2_cb_size; - LOCAL_ALIGNED(4, MvField, mergecand_list, [MRG_MAX_NUM_CANDS]); + MvField mergecand_list[MRG_MAX_NUM_CANDS]; int nPbW2 = nPbW; int nPbH2 = nPbH; HEVCLocalContext *lc = s->HEVClc; diff --git a/libavcodec/hevc_parse.c b/libavcodec/hevc_parse.c index 1122a60af3990..b1b27eef09cd2 100644 --- a/libavcodec/hevc_parse.c +++ b/libavcodec/hevc_parse.c @@ -22,7 +22,7 @@ #include "hevc_parse.h" static int hevc_decode_nal_units(const uint8_t *buf, int buf_size, HEVCParamSets *ps, - HEVCSEIContext *sei, int is_nalff, int nal_length_size, + HEVCSEI *sei, int is_nalff, int nal_length_size, int err_recognition, int apply_defdispwin, void *logctx) { int i; @@ -75,7 +75,7 @@ static int hevc_decode_nal_units(const uint8_t *buf, int buf_size, HEVCParamSets } int ff_hevc_decode_extradata(const uint8_t *data, int size, HEVCParamSets *ps, - HEVCSEIContext *sei, int *is_nalff, int *nal_length_size, + HEVCSEI *sei, int *is_nalff, int *nal_length_size, int err_recognition, int apply_defdispwin, void *logctx) { int ret = 0; diff --git a/libavcodec/hevc_parse.h b/libavcodec/hevc_parse.h index 02e1d5b324bf3..4ab96ab1cb68f 100644 --- a/libavcodec/hevc_parse.h +++ b/libavcodec/hevc_parse.h @@ -30,7 +30,7 @@ #include "hevc_sei.h" int ff_hevc_decode_extradata(const uint8_t *data, int size, HEVCParamSets *ps, - HEVCSEIContext *sei, int *is_nalff, int *nal_length_size, + HEVCSEI *sei, int *is_nalff, int *nal_length_size, int err_recognition, int apply_defdispwin, void *logctx); #endif /* AVCODEC_HEVC_PARSE_H */ diff --git a/libavcodec/hevc_parser.c b/libavcodec/hevc_parser.c index dc63c6b95433b..a468682ed335b 100644 --- a/libavcodec/hevc_parser.c +++ b/libavcodec/hevc_parser.c @@ -24,6 +24,7 @@ #include "golomb.h" #include "hevc.h" +#include "hevc_parse.h" #include "hevc_ps.h" #include "hevc_sei.h" #include "h2645_parse.h" @@ -40,9 +41,11 @@ typedef struct HEVCParserContext { H2645Packet pkt; HEVCParamSets ps; - HEVCSEIContext sei; + HEVCSEI sei; SliceHeader sh; + int is_avc; + int nal_length_size; int parsed_extradata; int poc; @@ -54,7 +57,7 @@ static int hevc_parse_slice_header(AVCodecParserContext *s, H2645NAL *nal, { HEVCParserContext *ctx = s->priv_data; HEVCParamSets *ps = &ctx->ps; - HEVCSEIContext *sei = &ctx->sei; + HEVCSEI *sei = &ctx->sei; SliceHeader *sh = &ctx->sh; GetBitContext *gb = &nal->gb; const HEVCWindow *ow; @@ -180,8 +183,7 @@ static int parse_nal_units(AVCodecParserContext *s, const uint8_t *buf, { HEVCParserContext *ctx = s->priv_data; HEVCParamSets *ps = &ctx->ps; - HEVCSEIContext *sei = &ctx->sei; - int is_global = buf == avctx->extradata; + HEVCSEI *sei = &ctx->sei; int ret, i; /* set some sane default values */ @@ -191,8 +193,8 @@ static int parse_nal_units(AVCodecParserContext *s, const uint8_t *buf, ff_hevc_reset_sei(sei); - ret = ff_h2645_packet_split(&ctx->pkt, buf, buf_size, avctx, 0, 0, - AV_CODEC_ID_HEVC, 1); + ret = ff_h2645_packet_split(&ctx->pkt, buf, buf_size, avctx, ctx->is_avc, + ctx->nal_length_size, AV_CODEC_ID_HEVC, 1); if (ret < 0) return ret; @@ -230,12 +232,6 @@ static int parse_nal_units(AVCodecParserContext *s, const uint8_t *buf, case HEVC_NAL_RADL_R: case HEVC_NAL_RASL_N: case HEVC_NAL_RASL_R: - - if (is_global) { - av_log(avctx, AV_LOG_ERROR, "Invalid NAL unit: %d\n", nal->type); - return AVERROR_INVALIDDATA; - } - ret = hevc_parse_slice_header(s, nal, avctx); if (ret) return ret; @@ -243,8 +239,7 @@ static int parse_nal_units(AVCodecParserContext *s, const uint8_t *buf, } } /* didn't find a picture! */ - if (!is_global) - av_log(avctx, AV_LOG_ERROR, "missing picture in access unit\n"); + av_log(avctx, AV_LOG_ERROR, "missing picture in access unit\n"); return -1; } @@ -301,7 +296,9 @@ static int hevc_parse(AVCodecParserContext *s, AVCodecContext *avctx, ParseContext *pc = &ctx->pc; if (avctx->extradata && !ctx->parsed_extradata) { - parse_nal_units(s, avctx->extradata, avctx->extradata_size, avctx); + ff_hevc_decode_extradata(avctx->extradata, avctx->extradata_size, &ctx->ps, &ctx->sei, + &ctx->is_avc, &ctx->nal_length_size, avctx->err_recognition, + 1, avctx); ctx->parsed_extradata = 1; } @@ -359,17 +356,8 @@ static int hevc_split(AVCodecContext *avctx, const uint8_t *buf, int buf_size) static void hevc_parser_close(AVCodecParserContext *s) { HEVCParserContext *ctx = s->priv_data; - int i; - - for (i = 0; i < FF_ARRAY_ELEMS(ctx->ps.vps_list); i++) - av_buffer_unref(&ctx->ps.vps_list[i]); - for (i = 0; i < FF_ARRAY_ELEMS(ctx->ps.sps_list); i++) - av_buffer_unref(&ctx->ps.sps_list[i]); - for (i = 0; i < FF_ARRAY_ELEMS(ctx->ps.pps_list); i++) - av_buffer_unref(&ctx->ps.pps_list[i]); - - ctx->ps.sps = NULL; + ff_hevc_ps_uninit(&ctx->ps); ff_h2645_packet_uninit(&ctx->pkt); ff_hevc_reset_sei(&ctx->sei); diff --git a/libavcodec/hevc_ps.c b/libavcodec/hevc_ps.c index 902917d4ddaab..f877fa572c8c0 100644 --- a/libavcodec/hevc_ps.c +++ b/libavcodec/hevc_ps.c @@ -1061,7 +1061,7 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, } sps->nb_st_rps = get_ue_golomb_long(gb); - if (sps->nb_st_rps > HEVC_MAX_SHORT_TERM_RPS_COUNT) { + if (sps->nb_st_rps > HEVC_MAX_SHORT_TERM_REF_PIC_SETS) { av_log(avctx, AV_LOG_ERROR, "Too many short term RPS: %d.\n", sps->nb_st_rps); return AVERROR_INVALIDDATA; @@ -1075,8 +1075,8 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, sps->long_term_ref_pics_present_flag = get_bits1(gb); if (sps->long_term_ref_pics_present_flag) { sps->num_long_term_ref_pics_sps = get_ue_golomb_long(gb); - if (sps->num_long_term_ref_pics_sps > 31U) { - av_log(avctx, AV_LOG_ERROR, "num_long_term_ref_pics_sps %d is out of range.\n", + if (sps->num_long_term_ref_pics_sps > HEVC_MAX_LONG_TERM_REF_PICS) { + av_log(avctx, AV_LOG_ERROR, "Too many long term ref pics: %d.\n", sps->num_long_term_ref_pics_sps); return AVERROR_INVALIDDATA; } @@ -1100,7 +1100,6 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, skip_bits(gb, 7); //sps_extension_7bits = get_bits(gb, 7); if (sps_extension_flag[0]) { int extended_precision_processing_flag; - int high_precision_offsets_enabled_flag; int cabac_bypass_alignment_enabled_flag; sps->transform_skip_rotation_enabled_flag = get_bits1(gb); @@ -1115,8 +1114,8 @@ int ff_hevc_parse_sps(HEVCSPS *sps, GetBitContext *gb, unsigned int *sps_id, "extended_precision_processing_flag not yet implemented\n"); sps->intra_smoothing_disabled_flag = get_bits1(gb); - high_precision_offsets_enabled_flag = get_bits1(gb); - if (high_precision_offsets_enabled_flag) + sps->high_precision_offsets_enabled_flag = get_bits1(gb); + if (sps->high_precision_offsets_enabled_flag) av_log(avctx, AV_LOG_WARNING, "high_precision_offsets_enabled_flag not yet implemented\n"); @@ -1324,6 +1323,11 @@ static int pps_range_extensions(GetBitContext *gb, AVCodecContext *avctx, pps->log2_sao_offset_scale_luma = get_ue_golomb_long(gb); pps->log2_sao_offset_scale_chroma = get_ue_golomb_long(gb); + if ( pps->log2_sao_offset_scale_luma > FFMAX(sps->bit_depth - 10, 0) + || pps->log2_sao_offset_scale_chroma > FFMAX(sps->bit_depth_chroma - 10, 0) + ) + return AVERROR_INVALIDDATA; + return(0); } @@ -1704,6 +1708,22 @@ int ff_hevc_decode_nal_pps(GetBitContext *gb, AVCodecContext *avctx, return ret; } +void ff_hevc_ps_uninit(HEVCParamSets *ps) +{ + int i; + + for (i = 0; i < FF_ARRAY_ELEMS(ps->vps_list); i++) + av_buffer_unref(&ps->vps_list[i]); + for (i = 0; i < FF_ARRAY_ELEMS(ps->sps_list); i++) + av_buffer_unref(&ps->sps_list[i]); + for (i = 0; i < FF_ARRAY_ELEMS(ps->pps_list); i++) + av_buffer_unref(&ps->pps_list[i]); + + ps->sps = NULL; + ps->pps = NULL; + ps->vps = NULL; +} + int ff_hevc_compute_poc(const HEVCSPS *sps, int pocTid0, int poc_lsb, int nal_unit_type) { int max_poc_lsb = 1 << sps->log2_max_poc_lsb; diff --git a/libavcodec/hevc_ps.h b/libavcodec/hevc_ps.h index 76f8eb31e6ae1..1fbda199e3fe8 100644 --- a/libavcodec/hevc_ps.h +++ b/libavcodec/hevc_ps.h @@ -254,14 +254,14 @@ typedef struct HEVCSPS { ScalingList scaling_list; unsigned int nb_st_rps; - ShortTermRPS st_rps[HEVC_MAX_SHORT_TERM_RPS_COUNT]; + ShortTermRPS st_rps[HEVC_MAX_SHORT_TERM_REF_PIC_SETS]; uint8_t amp_enabled_flag; uint8_t sao_enabled; uint8_t long_term_ref_pics_present_flag; - uint16_t lt_ref_pic_poc_lsb_sps[32]; - uint8_t used_by_curr_pic_lt_sps_flag[32]; + uint16_t lt_ref_pic_poc_lsb_sps[HEVC_MAX_LONG_TERM_REF_PICS]; + uint8_t used_by_curr_pic_lt_sps_flag[HEVC_MAX_LONG_TERM_REF_PICS]; uint8_t num_long_term_ref_pics_sps; struct { @@ -289,6 +289,7 @@ typedef struct HEVCSPS { int implicit_rdpcm_enabled_flag; int explicit_rdpcm_enabled_flag; int intra_smoothing_disabled_flag; + int high_precision_offsets_enabled_flag; int persistent_rice_adaptation_enabled_flag; ///< coded frame dimension in various units @@ -421,6 +422,8 @@ int ff_hevc_decode_nal_sps(GetBitContext *gb, AVCodecContext *avctx, int ff_hevc_decode_nal_pps(GetBitContext *gb, AVCodecContext *avctx, HEVCParamSets *ps); +void ff_hevc_ps_uninit(HEVCParamSets *ps); + int ff_hevc_decode_short_term_rps(GetBitContext *gb, AVCodecContext *avctx, ShortTermRPS *rps, const HEVCSPS *sps, int is_slice_header); diff --git a/libavcodec/hevc_sei.c b/libavcodec/hevc_sei.c index d0f9966a295c7..c59bd4321e272 100644 --- a/libavcodec/hevc_sei.c +++ b/libavcodec/hevc_sei.c @@ -95,10 +95,11 @@ static int decode_nal_sei_frame_packing_arrangement(HEVCSEIFramePacking *s, GetB s->quincunx_subsampling = get_bits1(gb); s->content_interpretation_type = get_bits(gb, 6); - // the following skips spatial_flipping_flag frame0_flipped_flag - // field_views_flag current_frame_is_frame0_flag - // frame0_self_contained_flag frame1_self_contained_flag - skip_bits(gb, 6); + // spatial_flipping_flag, frame0_flipped_flag, field_views_flag + skip_bits(gb, 3); + s->current_frame_is_frame0_flag = get_bits1(gb); + // frame0_self_contained_flag, frame1_self_contained_flag + skip_bits(gb, 2); if (!s->quincunx_subsampling && s->arrangement_type != 5) skip_bits(gb, 16); // frame[01]_grid_position_[xy] @@ -124,7 +125,7 @@ static int decode_nal_sei_display_orientation(HEVCSEIDisplayOrientation *s, GetB return 0; } -static int decode_nal_sei_pic_timing(HEVCSEIContext *s, GetBitContext *gb, const HEVCParamSets *ps, +static int decode_nal_sei_pic_timing(HEVCSEI *s, GetBitContext *gb, const HEVCParamSets *ps, void *logctx, int size) { HEVCSEIPictureTiming *h = &s->picture_timing; @@ -205,7 +206,7 @@ static int decode_registered_user_data_closed_caption(HEVCSEIA53Caption *s, GetB return 0; } -static int decode_nal_sei_user_data_registered_itu_t_t35(HEVCSEIContext *s, GetBitContext *gb, +static int decode_nal_sei_user_data_registered_itu_t_t35(HEVCSEI *s, GetBitContext *gb, int size) { uint32_t country_code; @@ -236,7 +237,7 @@ static int decode_nal_sei_user_data_registered_itu_t_t35(HEVCSEIContext *s, GetB return 0; } -static int decode_nal_sei_active_parameter_sets(HEVCSEIContext *s, GetBitContext *gb, void *logctx) +static int decode_nal_sei_active_parameter_sets(HEVCSEI *s, GetBitContext *gb, void *logctx) { int num_sps_ids_minus1; int i; @@ -272,8 +273,8 @@ static int decode_nal_sei_alternative_transfer(HEVCSEIAlternativeTransfer *s, Ge return 0; } -static int decode_nal_sei_prefix(GetBitContext *gb, HEVCSEIContext *s, const HEVCParamSets *ps, - int type, int size, void *logctx) +static int decode_nal_sei_prefix(GetBitContext *gb, void *logctx, HEVCSEI *s, + const HEVCParamSets *ps, int type, int size) { switch (type) { case 256: // Mismatched value from HM 8.1 @@ -301,8 +302,8 @@ static int decode_nal_sei_prefix(GetBitContext *gb, HEVCSEIContext *s, const HEV } } -static int decode_nal_sei_suffix(GetBitContext *gb, HEVCSEIContext *s, - int type, int size, void *logctx) +static int decode_nal_sei_suffix(GetBitContext *gb, void *logctx, HEVCSEI *s, + int type, int size) { switch (type) { case HEVC_SEI_TYPE_DECODED_PICTURE_HASH: @@ -314,9 +315,8 @@ static int decode_nal_sei_suffix(GetBitContext *gb, HEVCSEIContext *s, } } -static int decode_nal_sei_message(GetBitContext *gb, HEVCSEIContext *s, - const HEVCParamSets *ps, int nal_unit_type, - void *logctx) +static int decode_nal_sei_message(GetBitContext *gb, void *logctx, HEVCSEI *s, + const HEVCParamSets *ps, int nal_unit_type) { int payload_type = 0; int payload_size = 0; @@ -324,18 +324,22 @@ static int decode_nal_sei_message(GetBitContext *gb, HEVCSEIContext *s, av_log(logctx, AV_LOG_DEBUG, "Decoding SEI\n"); while (byte == 0xFF) { + if (get_bits_left(gb) < 16 || payload_type > INT_MAX - 255) + return AVERROR_INVALIDDATA; byte = get_bits(gb, 8); payload_type += byte; } byte = 0xFF; while (byte == 0xFF) { + if (get_bits_left(gb) < 8 + 8LL*payload_size) + return AVERROR_INVALIDDATA; byte = get_bits(gb, 8); payload_size += byte; } if (nal_unit_type == HEVC_NAL_SEI_PREFIX) { - return decode_nal_sei_prefix(gb, s, ps, payload_type, payload_size, logctx); + return decode_nal_sei_prefix(gb, logctx, s, ps, payload_type, payload_size); } else { /* nal_unit_type == NAL_SEI_SUFFIX */ - return decode_nal_sei_suffix(gb, s, payload_type, payload_size, logctx); + return decode_nal_sei_suffix(gb, logctx, s, payload_type, payload_size); } } @@ -344,20 +348,20 @@ static int more_rbsp_data(GetBitContext *gb) return get_bits_left(gb) > 0 && show_bits(gb, 8) != 0x80; } -int ff_hevc_decode_nal_sei(GetBitContext *gb, void *logctx, HEVCSEIContext *s, +int ff_hevc_decode_nal_sei(GetBitContext *gb, void *logctx, HEVCSEI *s, const HEVCParamSets *ps, int type) { int ret; do { - ret = decode_nal_sei_message(gb, s, ps, type, logctx); + ret = decode_nal_sei_message(gb, logctx, s, ps, type); if (ret < 0) return ret; } while (more_rbsp_data(gb)); return 1; } -void ff_hevc_reset_sei(HEVCSEIContext *s) +void ff_hevc_reset_sei(HEVCSEI *s) { s->a53_caption.a53_caption_size = 0; av_freep(&s->a53_caption.a53_caption); diff --git a/libavcodec/hevc_sei.h b/libavcodec/hevc_sei.h index 1b522227ecfa6..e92da25bbf76c 100644 --- a/libavcodec/hevc_sei.h +++ b/libavcodec/hevc_sei.h @@ -23,8 +23,6 @@ #include -#include "libavutil/md5.h" - #include "get_bits.h" /** @@ -60,7 +58,6 @@ typedef enum { } HEVC_SEI_Type; typedef struct HEVCSEIPictureHash { - struct AVMD5 *md5_ctx; uint8_t md5[3][16]; uint8_t is_md5; } HEVCSEIPictureHash; @@ -70,6 +67,7 @@ typedef struct HEVCSEIFramePacking { int arrangement_type; int content_interpretation_type; int quincunx_subsampling; + int current_frame_is_frame0_flag; } HEVCSEIFramePacking; typedef struct HEVCSEIDisplayOrientation { @@ -106,7 +104,7 @@ typedef struct HEVCSEIAlternativeTransfer { int preferred_transfer_characteristics; } HEVCSEIAlternativeTransfer; -typedef struct HEVCSEIContext { +typedef struct HEVCSEI { HEVCSEIPictureHash picture_hash; HEVCSEIFramePacking frame_packing; HEVCSEIDisplayOrientation display_orientation; @@ -116,11 +114,11 @@ typedef struct HEVCSEIContext { HEVCSEIContentLight content_light; int active_seq_parameter_set_id; HEVCSEIAlternativeTransfer alternative_transfer; -} HEVCSEIContext; +} HEVCSEI; struct HEVCParamSets; -int ff_hevc_decode_nal_sei(GetBitContext *gb, void *logctx, HEVCSEIContext *s, +int ff_hevc_decode_nal_sei(GetBitContext *gb, void *logctx, HEVCSEI *s, const struct HEVCParamSets *ps, int type); /** @@ -130,6 +128,6 @@ int ff_hevc_decode_nal_sei(GetBitContext *gb, void *logctx, HEVCSEIContext *s, * * @param s HEVCContext. */ -void ff_hevc_reset_sei(HEVCSEIContext *s); +void ff_hevc_reset_sei(HEVCSEI *s); #endif /* AVCODEC_HEVC_SEI_H */ diff --git a/libavcodec/hevcdec.c b/libavcodec/hevcdec.c index 2e4add2ae30ae..c8877626d2e43 100644 --- a/libavcodec/hevcdec.c +++ b/libavcodec/hevcdec.c @@ -41,6 +41,7 @@ #include "hevc_data.h" #include "hevc_parse.h" #include "hevcdec.h" +#include "hwaccel.h" #include "profiles.h" const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12] = 4, [16] = 5, [24] = 6, [32] = 7, [48] = 8, [64] = 9 }; @@ -150,12 +151,18 @@ static int pred_weight_table(HEVCContext *s, GetBitContext *gb) int luma_log2_weight_denom; luma_log2_weight_denom = get_ue_golomb_long(gb); - if (luma_log2_weight_denom < 0 || luma_log2_weight_denom > 7) + if (luma_log2_weight_denom < 0 || luma_log2_weight_denom > 7) { av_log(s->avctx, AV_LOG_ERROR, "luma_log2_weight_denom %d is invalid\n", luma_log2_weight_denom); + return AVERROR_INVALIDDATA; + } s->sh.luma_log2_weight_denom = av_clip_uintp2(luma_log2_weight_denom, 3); if (s->ps.sps->chroma_format_idc != 0) { - int delta = get_se_golomb(gb); - s->sh.chroma_log2_weight_denom = av_clip_uintp2(s->sh.luma_log2_weight_denom + delta, 3); + int64_t chroma_log2_weight_denom = luma_log2_weight_denom + (int64_t)get_se_golomb(gb); + if (chroma_log2_weight_denom < 0 || chroma_log2_weight_denom > 7) { + av_log(s->avctx, AV_LOG_ERROR, "chroma_log2_weight_denom %"PRId64" is invalid\n", chroma_log2_weight_denom); + return AVERROR_INVALIDDATA; + } + s->sh.chroma_log2_weight_denom = chroma_log2_weight_denom; } for (i = 0; i < s->sh.nb_refs[L0]; i++) { @@ -354,6 +361,7 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) { #define HWACCEL_MAX (CONFIG_HEVC_DXVA2_HWACCEL + \ CONFIG_HEVC_D3D11VA_HWACCEL * 2 + \ + CONFIG_HEVC_NVDEC_HWACCEL + \ CONFIG_HEVC_VAAPI_HWACCEL + \ CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL + \ CONFIG_HEVC_VDPAU_HWACCEL) @@ -375,6 +383,9 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) #if CONFIG_HEVC_VDPAU_HWACCEL *fmt++ = AV_PIX_FMT_VDPAU; #endif +#if CONFIG_HEVC_NVDEC_HWACCEL + *fmt++ = AV_PIX_FMT_CUDA; +#endif #if CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL *fmt++ = AV_PIX_FMT_VIDEOTOOLBOX; #endif @@ -392,6 +403,14 @@ static enum AVPixelFormat get_format(HEVCContext *s, const HEVCSPS *sps) #endif #if CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL *fmt++ = AV_PIX_FMT_VIDEOTOOLBOX; +#endif +#if CONFIG_HEVC_NVDEC_HWACCEL + *fmt++ = AV_PIX_FMT_CUDA; +#endif + break; + case AV_PIX_FMT_YUV420P12: +#if CONFIG_HEVC_NVDEC_HWACCEL + *fmt++ = AV_PIX_FMT_CUDA; #endif break; } @@ -503,13 +522,14 @@ static int hls_slice_header(HEVCContext *s) } ff_hevc_clear_refs(s); + ret = set_sps(s, sps, sps->pix_fmt); + if (ret < 0) + return ret; + pix_fmt = get_format(s, sps); if (pix_fmt < 0) return pix_fmt; - - ret = set_sps(s, sps, pix_fmt); - if (ret < 0) - return ret; + s->avctx->pix_fmt = pix_fmt; s->seq_decode = (s->seq_decode + 1) & 0xff; s->max_ra = INT_MAX; @@ -2638,6 +2658,13 @@ static int set_side_data(HEVCContext *s) if (s->sei.frame_packing.content_interpretation_type == 2) stereo->flags = AV_STEREO3D_FLAG_INVERT; + + if (s->sei.frame_packing.arrangement_type == 5) { + if (s->sei.frame_packing.current_frame_is_frame0_flag) + stereo->view = AV_STEREO3D_VIEW_LEFT; + else + stereo->view = AV_STEREO3D_VIEW_RIGHT; + } } if (s->sei.display_orientation.present && @@ -2816,23 +2843,55 @@ static int decode_nal_unit(HEVCContext *s, const H2645NAL *nal) switch (s->nal_unit_type) { case HEVC_NAL_VPS: + if (s->avctx->hwaccel && s->avctx->hwaccel->decode_params) { + ret = s->avctx->hwaccel->decode_params(s->avctx, + nal->type, + nal->raw_data, + nal->raw_size); + if (ret < 0) + goto fail; + } ret = ff_hevc_decode_nal_vps(gb, s->avctx, &s->ps); if (ret < 0) goto fail; break; case HEVC_NAL_SPS: + if (s->avctx->hwaccel && s->avctx->hwaccel->decode_params) { + ret = s->avctx->hwaccel->decode_params(s->avctx, + nal->type, + nal->raw_data, + nal->raw_size); + if (ret < 0) + goto fail; + } ret = ff_hevc_decode_nal_sps(gb, s->avctx, &s->ps, s->apply_defdispwin); if (ret < 0) goto fail; break; case HEVC_NAL_PPS: + if (s->avctx->hwaccel && s->avctx->hwaccel->decode_params) { + ret = s->avctx->hwaccel->decode_params(s->avctx, + nal->type, + nal->raw_data, + nal->raw_size); + if (ret < 0) + goto fail; + } ret = ff_hevc_decode_nal_pps(gb, s->avctx, &s->ps); if (ret < 0) goto fail; break; case HEVC_NAL_SEI_PREFIX: case HEVC_NAL_SEI_SUFFIX: + if (s->avctx->hwaccel && s->avctx->hwaccel->decode_params) { + ret = s->avctx->hwaccel->decode_params(s->avctx, + nal->type, + nal->raw_data, + nal->raw_size); + if (ret < 0) + goto fail; + } ret = ff_hevc_decode_nal_sei(gb, s->avctx, &s->sei, &s->ps, s->nal_unit_type); if (ret < 0) goto fail; @@ -2857,6 +2916,13 @@ static int decode_nal_unit(HEVCContext *s, const H2645NAL *nal) if (ret < 0) return ret; + if ( + (s->avctx->skip_frame >= AVDISCARD_BIDIR && s->sh.slice_type == HEVC_SLICE_B) || + (s->avctx->skip_frame >= AVDISCARD_NONINTRA && s->sh.slice_type != HEVC_SLICE_I) || + (s->avctx->skip_frame >= AVDISCARD_NONKEY && !IS_IDR(s))) { + break; + } + if (s->sh.first_slice_in_pic_flag) { if (s->max_ra == INT_MAX) { if (s->nal_unit_type == HEVC_NAL_CRA_NUT || IS_BLA(s)) { @@ -2980,7 +3046,14 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length) /* decode the NAL units */ for (i = 0; i < s->pkt.nb_nals; i++) { - ret = decode_nal_unit(s, &s->pkt.nals[i]); + H2645NAL *nal = &s->pkt.nals[i]; + + if (s->avctx->skip_frame >= AVDISCARD_ALL || + (s->avctx->skip_frame >= AVDISCARD_NONREF + && ff_hevc_nal_is_nonref(nal->type))) + continue; + + ret = decode_nal_unit(s, nal); if (ret < 0) { av_log(s->avctx, AV_LOG_WARNING, "Error parsing NAL unit #%d.\n", i); @@ -3035,7 +3108,7 @@ static int verify_md5(HEVCContext *s, AVFrame *frame) int h = (i == 1 || i == 2) ? (height >> desc->log2_chroma_h) : height; uint8_t md5[16]; - av_md5_init(s->sei.picture_hash.md5_ctx); + av_md5_init(s->md5_ctx); for (j = 0; j < h; j++) { const uint8_t *src = frame->data[i] + j * frame->linesize[i]; #if HAVE_BIGENDIAN @@ -3045,9 +3118,9 @@ static int verify_md5(HEVCContext *s, AVFrame *frame) src = s->checksum_buf; } #endif - av_md5_update(s->sei.picture_hash.md5_ctx, src, w << pixel_shift); + av_md5_update(s->md5_ctx, src, w << pixel_shift); } - av_md5_final(s->sei.picture_hash.md5_ctx, md5); + av_md5_final(s->md5_ctx, md5); if (!memcmp(md5, s->sei.picture_hash.md5[i], 16)) { av_log (s->avctx, AV_LOG_DEBUG, "plane %d - correct ", i); @@ -3200,7 +3273,7 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx) pic_arrays_free(s); - av_freep(&s->sei.picture_hash.md5_ctx); + av_freep(&s->md5_ctx); av_freep(&s->cabac_state); @@ -3215,15 +3288,7 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx) av_frame_free(&s->DPB[i].frame); } - for (i = 0; i < FF_ARRAY_ELEMS(s->ps.vps_list); i++) - av_buffer_unref(&s->ps.vps_list[i]); - for (i = 0; i < FF_ARRAY_ELEMS(s->ps.sps_list); i++) - av_buffer_unref(&s->ps.sps_list[i]); - for (i = 0; i < FF_ARRAY_ELEMS(s->ps.pps_list); i++) - av_buffer_unref(&s->ps.pps_list[i]); - s->ps.sps = NULL; - s->ps.pps = NULL; - s->ps.vps = NULL; + ff_hevc_ps_uninit(&s->ps); av_freep(&s->sh.entry_point_offset); av_freep(&s->sh.offset); @@ -3275,8 +3340,8 @@ static av_cold int hevc_init_context(AVCodecContext *avctx) s->max_ra = INT_MAX; - s->sei.picture_hash.md5_ctx = av_md5_alloc(); - if (!s->sei.picture_hash.md5_ctx) + s->md5_ctx = av_md5_alloc(); + if (!s->md5_ctx) goto fail; ff_bswapdsp_init(&s->bdsp); @@ -3470,4 +3535,28 @@ AVCodec ff_hevc_decoder = { AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_EXPORTS_CROPPING, .profiles = NULL_IF_CONFIG_SMALL(ff_hevc_profiles), + .hw_configs = (const AVCodecHWConfigInternal*[]) { +#if CONFIG_HEVC_DXVA2_HWACCEL + HWACCEL_DXVA2(hevc), +#endif +#if CONFIG_HEVC_D3D11VA_HWACCEL + HWACCEL_D3D11VA(hevc), +#endif +#if CONFIG_HEVC_D3D11VA2_HWACCEL + HWACCEL_D3D11VA2(hevc), +#endif +#if CONFIG_HEVC_NVDEC_HWACCEL + HWACCEL_NVDEC(hevc), +#endif +#if CONFIG_HEVC_VAAPI_HWACCEL + HWACCEL_VAAPI(hevc), +#endif +#if CONFIG_HEVC_VDPAU_HWACCEL + HWACCEL_VDPAU(hevc), +#endif +#if CONFIG_HEVC_VIDEOTOOLBOX_HWACCEL + HWACCEL_VIDEOTOOLBOX(hevc), +#endif + NULL + }, }; diff --git a/libavcodec/hevcdec.h b/libavcodec/hevcdec.h index 293beb70832d0..b311edc8aeef3 100644 --- a/libavcodec/hevcdec.h +++ b/libavcodec/hevcdec.h @@ -26,6 +26,7 @@ #include #include "libavutil/buffer.h" +#include "libavutil/md5.h" #include "avcodec.h" #include "bswapdsp.h" @@ -363,7 +364,7 @@ typedef struct HEVCLocalContext { DECLARE_ALIGNED(32, uint8_t, edge_emu_buffer)[(MAX_PB_SIZE + 7) * EDGE_EMU_BUFFER_STRIDE * 2]; /* The extended size between the new edge emu buffer is abused by SAO */ DECLARE_ALIGNED(32, uint8_t, edge_emu_buffer2)[(MAX_PB_SIZE + 7) * EDGE_EMU_BUFFER_STRIDE * 2]; - DECLARE_ALIGNED(32, int16_t, tmp [MAX_PB_SIZE * MAX_PB_SIZE]); + DECLARE_ALIGNED(32, int16_t, tmp)[MAX_PB_SIZE * MAX_PB_SIZE]; int ct_depth; CodingUnit cu; @@ -405,6 +406,8 @@ typedef struct HEVCContext { uint8_t *sao_pixel_buffer_v[3]; HEVCParamSets ps; + HEVCSEI sei; + struct AVMD5 *md5_ctx; AVBufferPool *tab_mvf_pool; AVBufferPool *rpl_tab_pool; @@ -480,8 +483,6 @@ typedef struct HEVCContext { int nal_length_size; ///< Number of bytes used for nal length (1, 2 or 4) int nuh_layer_id; - - HEVCSEIContext sei; } HEVCContext; /** @@ -547,6 +548,26 @@ int ff_hevc_frame_nb_refs(HEVCContext *s); int ff_hevc_set_new_ref(HEVCContext *s, AVFrame **frame, int poc); +static av_always_inline int ff_hevc_nal_is_nonref(enum HEVCNALUnitType type) +{ + switch (type) { + case HEVC_NAL_TRAIL_N: + case HEVC_NAL_TSA_N: + case HEVC_NAL_STSA_N: + case HEVC_NAL_RADL_N: + case HEVC_NAL_RASL_N: + case HEVC_NAL_VCL_N10: + case HEVC_NAL_VCL_N12: + case HEVC_NAL_VCL_N14: + case HEVC_NAL_BLA_N_LP: + case HEVC_NAL_IDR_N_LP: + return 1; + break; + default: break; + } + return 0; +} + /** * Find next frame in output order and put a reference to it in frame. * @return 1 if a frame was output, 0 otherwise diff --git a/libavcodec/hevcdsp.c b/libavcodec/hevcdsp.c index 76ae72b6d4c97..957e40d5ff77d 100644 --- a/libavcodec/hevcdsp.c +++ b/libavcodec/hevcdsp.c @@ -91,7 +91,7 @@ static const int8_t transform[32][32] = { 90, -90, 88, -85, 82, -78, 73, -67, 61, -54, 46, -38, 31, -22, 13, -4 }, }; -DECLARE_ALIGNED(16, const int8_t, ff_hevc_epel_filters[7][4]) = { +DECLARE_ALIGNED(16, const int8_t, ff_hevc_epel_filters)[7][4] = { { -2, 58, 10, -2}, { -4, 54, 16, -2}, { -6, 46, 28, -4}, @@ -101,7 +101,7 @@ DECLARE_ALIGNED(16, const int8_t, ff_hevc_epel_filters[7][4]) = { { -2, 10, 58, -2}, }; -DECLARE_ALIGNED(16, const int8_t, ff_hevc_qpel_filters[3][16]) = { +DECLARE_ALIGNED(16, const int8_t, ff_hevc_qpel_filters)[3][16] = { { -1, 4,-10, 58, 17, -5, 1, 0, -1, 4,-10, 58, 17, -5, 1, 0}, { -1, 4,-11, 40, 40,-11, 4, -1, -1, 4,-11, 40, 40,-11, 4, -1}, { 0, 1, -5, 17, 58,-10, 4, -1, 0, 1, -5, 17, 58,-10, 4, -1} @@ -257,12 +257,12 @@ int i = 0; break; } + if (ARCH_ARM) + ff_hevc_dsp_init_arm(hevcdsp, bit_depth); if (ARCH_PPC) ff_hevc_dsp_init_ppc(hevcdsp, bit_depth); if (ARCH_X86) ff_hevc_dsp_init_x86(hevcdsp, bit_depth); - if (ARCH_ARM) - ff_hevcdsp_init_arm(hevcdsp, bit_depth); if (ARCH_MIPS) ff_hevc_dsp_init_mips(hevcdsp, bit_depth); } diff --git a/libavcodec/hevcdsp.h b/libavcodec/hevcdsp.h index dc48ebca11183..0ae67cba8563c 100644 --- a/libavcodec/hevcdsp.h +++ b/libavcodec/hevcdsp.h @@ -127,8 +127,9 @@ void ff_hevc_dsp_init(HEVCDSPContext *hpc, int bit_depth); extern const int8_t ff_hevc_epel_filters[7][4]; extern const int8_t ff_hevc_qpel_filters[3][16]; +void ff_hevc_dsp_init_arm(HEVCDSPContext *c, const int bit_depth); void ff_hevc_dsp_init_ppc(HEVCDSPContext *c, const int bit_depth); void ff_hevc_dsp_init_x86(HEVCDSPContext *c, const int bit_depth); -void ff_hevcdsp_init_arm(HEVCDSPContext *c, const int bit_depth); void ff_hevc_dsp_init_mips(HEVCDSPContext *c, const int bit_depth); + #endif /* AVCODEC_HEVCDSP_H */ diff --git a/libavcodec/hevcdsp_template.c b/libavcodec/hevcdsp_template.c index e09c661759e50..56cd9e605d313 100644 --- a/libavcodec/hevcdsp_template.c +++ b/libavcodec/hevcdsp_template.c @@ -121,7 +121,7 @@ static void FUNC(dequant)(int16_t *coeffs, int16_t log2_size) } else { for (y = 0; y < size; y++) { for (x = 0; x < size; x++) { - *coeffs = *coeffs << -shift; + *coeffs = *(uint16_t*)coeffs << -shift; coeffs++; } } @@ -915,7 +915,7 @@ static void FUNC(put_hevc_qpel_bi_w_h)(uint8_t *_dst, ptrdiff_t _dststride, uint for (y = 0; y < height; y++) { for (x = 0; x < width; x++) dst[x] = av_clip_pixel(((QPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 + - ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1)); + ((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1)); src += srcstride; dst += dststride; src2 += MAX_PB_SIZE; @@ -970,7 +970,7 @@ static void FUNC(put_hevc_qpel_bi_w_v)(uint8_t *_dst, ptrdiff_t _dststride, uint for (y = 0; y < height; y++) { for (x = 0; x < width; x++) dst[x] = av_clip_pixel(((QPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 + - ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1)); + ((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1)); src += srcstride; dst += dststride; src2 += MAX_PB_SIZE; @@ -1051,7 +1051,7 @@ static void FUNC(put_hevc_qpel_bi_w_hv)(uint8_t *_dst, ptrdiff_t _dststride, uin for (y = 0; y < height; y++) { for (x = 0; x < width; x++) dst[x] = av_clip_pixel(((QPEL_FILTER(tmp, MAX_PB_SIZE) >> 6) * wx1 + src2[x] * wx0 + - ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1)); + ((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1)); tmp += MAX_PB_SIZE; dst += dststride; src2 += MAX_PB_SIZE; @@ -1355,7 +1355,7 @@ static void FUNC(put_hevc_epel_bi_w_h)(uint8_t *_dst, ptrdiff_t _dststride, uint for (y = 0; y < height; y++) { for (x = 0; x < width; x++) dst[x] = av_clip_pixel(((EPEL_FILTER(src, 1) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 + - ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1)); + ((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1)); src += srcstride; dst += dststride; src2 += MAX_PB_SIZE; @@ -1407,7 +1407,7 @@ static void FUNC(put_hevc_epel_bi_w_v)(uint8_t *_dst, ptrdiff_t _dststride, uint for (y = 0; y < height; y++) { for (x = 0; x < width; x++) dst[x] = av_clip_pixel(((EPEL_FILTER(src, srcstride) >> (BIT_DEPTH - 8)) * wx1 + src2[x] * wx0 + - ((ox0 + ox1 + 1) << log2Wd)) >> (log2Wd + 1)); + ((ox0 + ox1 + 1) * (1 << log2Wd))) >> (log2Wd + 1)); src += srcstride; dst += dststride; src2 += MAX_PB_SIZE; diff --git a/libavcodec/huffyuvdec.c b/libavcodec/huffyuvdec.c index 979c4b9d5c11a..66357bfb40353 100644 --- a/libavcodec/huffyuvdec.c +++ b/libavcodec/huffyuvdec.c @@ -919,6 +919,9 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVFrame *const p = data; int table_size = 0, ret; + if (buf_size < (width * height + 7)/8) + return AVERROR_INVALIDDATA; + av_fast_padded_malloc(&s->bitstream_buffer, &s->bitstream_buffer_size, buf_size); diff --git a/libavcodec/huffyuvenc.c b/libavcodec/huffyuvenc.c index 89639b75df05a..8be752844b029 100644 --- a/libavcodec/huffyuvenc.c +++ b/libavcodec/huffyuvenc.c @@ -52,42 +52,30 @@ static inline int sub_left_prediction(HYuvContext *s, uint8_t *dst, const uint8_t *src, int w, int left) { int i; + int min_width = FFMIN(w, 32); + if (s->bps <= 8) { - if (w < 32) { - for (i = 0; i < w; i++) { - const int temp = src[i]; - dst[i] = temp - left; - left = temp; - } - return left; - } else { - for (i = 0; i < 32; i++) { - const int temp = src[i]; - dst[i] = temp - left; - left = temp; - } - s->llvidencdsp.diff_bytes(dst + 32, src + 32, src + 31, w - 32); - return src[w-1]; + for (i = 0; i < min_width; i++) { /* scalar loop before dsp call */ + const int temp = src[i]; + dst[i] = temp - left; + left = temp; } + if (w < 32) + return left; + s->llvidencdsp.diff_bytes(dst + 32, src + 32, src + 31, w - 32); + return src[w-1]; } else { const uint16_t *src16 = (const uint16_t *)src; uint16_t *dst16 = ( uint16_t *)dst; - if (w < 32) { - for (i = 0; i < w; i++) { - const int temp = src16[i]; - dst16[i] = temp - left; - left = temp; - } - return left; - } else { - for (i = 0; i < 16; i++) { - const int temp = src16[i]; - dst16[i] = temp - left; - left = temp; - } - s->hencdsp.diff_int16(dst16 + 16, src16 + 16, src16 + 15, s->n - 1, w - 16); - return src16[w-1]; + for (i = 0; i < min_width; i++) { /* scalar loop before dsp call */ + const int temp = src16[i]; + dst16[i] = temp - left; + left = temp; } + if (w < 32) + return left; + s->hencdsp.diff_int16(dst16 + 32, src16 + 32, src16 + 31, s->n - 1, w - 32); + return src16[w-1]; } } @@ -98,12 +86,13 @@ static inline void sub_left_prediction_bgr32(HYuvContext *s, uint8_t *dst, { int i; int r, g, b, a; + int min_width = FFMIN(w, 8); r = *red; g = *green; b = *blue; a = *alpha; - for (i = 0; i < FFMIN(w, 4); i++) { + for (i = 0; i < min_width; i++) { const int rt = src[i * 4 + R]; const int gt = src[i * 4 + G]; const int bt = src[i * 4 + B]; @@ -118,7 +107,7 @@ static inline void sub_left_prediction_bgr32(HYuvContext *s, uint8_t *dst, a = at; } - s->llvidencdsp.diff_bytes(dst + 16, src + 16, src + 12, w * 4 - 16); + s->llvidencdsp.diff_bytes(dst + 32, src + 32, src + 32 - 4, w * 4 - 32); *red = src[(w - 1) * 4 + R]; *green = src[(w - 1) * 4 + G]; diff --git a/libavcodec/hwaccel.h b/libavcodec/hwaccel.h index 124fbbf1fdf61..3aaa92571c414 100644 --- a/libavcodec/hwaccel.h +++ b/libavcodec/hwaccel.h @@ -19,6 +19,66 @@ #ifndef AVCODEC_HWACCEL_H #define AVCODEC_HWACCEL_H +#include "avcodec.h" +#include "hwaccels.h" + + #define HWACCEL_CAP_ASYNC_SAFE (1 << 0) + +typedef struct AVCodecHWConfigInternal { + /** + * This is the structure which will be returned to the user by + * avcodec_get_hw_config(). + */ + AVCodecHWConfig public; + /** + * If this configuration uses a hwaccel, a pointer to it. + * If not, NULL. + */ + const AVHWAccel *hwaccel; +} AVCodecHWConfigInternal; + + +// These macros are used to simplify AVCodecHWConfigInternal definitions. + +#define HW_CONFIG_HWACCEL(device, frames, ad_hoc, format, device_type_, name) \ + &(const AVCodecHWConfigInternal) { \ + .public = { \ + .pix_fmt = AV_PIX_FMT_ ## format, \ + .methods = (device ? AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX : 0) | \ + (frames ? AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX : 0) | \ + (ad_hoc ? AV_CODEC_HW_CONFIG_METHOD_AD_HOC : 0), \ + .device_type = AV_HWDEVICE_TYPE_ ## device_type_, \ + }, \ + .hwaccel = &name, \ + } + +#define HW_CONFIG_INTERNAL(format) \ + &(const AVCodecHWConfigInternal) { \ + .public = { \ + .pix_fmt = AV_PIX_FMT_ ## format, \ + .methods = AV_CODEC_HW_CONFIG_METHOD_INTERNAL, \ + .device_type = AV_HWDEVICE_TYPE_NONE, \ + }, \ + .hwaccel = NULL, \ + } + +#define HWACCEL_DXVA2(codec) \ + HW_CONFIG_HWACCEL(1, 1, 1, DXVA2_VLD, DXVA2, ff_ ## codec ## _dxva2_hwaccel) +#define HWACCEL_D3D11VA2(codec) \ + HW_CONFIG_HWACCEL(1, 1, 0, D3D11, D3D11VA, ff_ ## codec ## _d3d11va2_hwaccel) +#define HWACCEL_NVDEC(codec) \ + HW_CONFIG_HWACCEL(1, 1, 0, CUDA, CUDA, ff_ ## codec ## _nvdec_hwaccel) +#define HWACCEL_VAAPI(codec) \ + HW_CONFIG_HWACCEL(1, 1, 1, VAAPI, VAAPI, ff_ ## codec ## _vaapi_hwaccel) +#define HWACCEL_VDPAU(codec) \ + HW_CONFIG_HWACCEL(1, 1, 1, VDPAU, VDPAU, ff_ ## codec ## _vdpau_hwaccel) +#define HWACCEL_VIDEOTOOLBOX(codec) \ + HW_CONFIG_HWACCEL(1, 1, 1, VIDEOTOOLBOX, VIDEOTOOLBOX, ff_ ## codec ## _videotoolbox_hwaccel) +#define HWACCEL_D3D11VA(codec) \ + HW_CONFIG_HWACCEL(0, 0, 1, D3D11VA_VLD, NONE, ff_ ## codec ## _d3d11va_hwaccel) +#define HWACCEL_XVMC(codec) \ + HW_CONFIG_HWACCEL(0, 0, 1, XVMC, NONE, ff_ ## codec ## _xvmc_hwaccel) + #endif /* AVCODEC_HWACCEL_H */ diff --git a/libavcodec/hwaccels.h b/libavcodec/hwaccels.h new file mode 100644 index 0000000000000..7d73da86767cf --- /dev/null +++ b/libavcodec/hwaccels.h @@ -0,0 +1,78 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_HWACCELS_H +#define AVCODEC_HWACCELS_H + +#include "avcodec.h" + +extern const AVHWAccel ff_h263_vaapi_hwaccel; +extern const AVHWAccel ff_h263_videotoolbox_hwaccel; +extern const AVHWAccel ff_h264_d3d11va_hwaccel; +extern const AVHWAccel ff_h264_d3d11va2_hwaccel; +extern const AVHWAccel ff_h264_dxva2_hwaccel; +extern const AVHWAccel ff_h264_nvdec_hwaccel; +extern const AVHWAccel ff_h264_vaapi_hwaccel; +extern const AVHWAccel ff_h264_vdpau_hwaccel; +extern const AVHWAccel ff_h264_videotoolbox_hwaccel; +extern const AVHWAccel ff_hevc_d3d11va_hwaccel; +extern const AVHWAccel ff_hevc_d3d11va2_hwaccel; +extern const AVHWAccel ff_hevc_dxva2_hwaccel; +extern const AVHWAccel ff_hevc_nvdec_hwaccel; +extern const AVHWAccel ff_hevc_vaapi_hwaccel; +extern const AVHWAccel ff_hevc_vdpau_hwaccel; +extern const AVHWAccel ff_hevc_videotoolbox_hwaccel; +extern const AVHWAccel ff_mjpeg_nvdec_hwaccel; +extern const AVHWAccel ff_mjpeg_vaapi_hwaccel; +extern const AVHWAccel ff_mpeg1_nvdec_hwaccel; +extern const AVHWAccel ff_mpeg1_vdpau_hwaccel; +extern const AVHWAccel ff_mpeg1_videotoolbox_hwaccel; +extern const AVHWAccel ff_mpeg1_xvmc_hwaccel; +extern const AVHWAccel ff_mpeg2_d3d11va_hwaccel; +extern const AVHWAccel ff_mpeg2_d3d11va2_hwaccel; +extern const AVHWAccel ff_mpeg2_nvdec_hwaccel; +extern const AVHWAccel ff_mpeg2_dxva2_hwaccel; +extern const AVHWAccel ff_mpeg2_vaapi_hwaccel; +extern const AVHWAccel ff_mpeg2_vdpau_hwaccel; +extern const AVHWAccel ff_mpeg2_videotoolbox_hwaccel; +extern const AVHWAccel ff_mpeg2_xvmc_hwaccel; +extern const AVHWAccel ff_mpeg4_nvdec_hwaccel; +extern const AVHWAccel ff_mpeg4_vaapi_hwaccel; +extern const AVHWAccel ff_mpeg4_vdpau_hwaccel; +extern const AVHWAccel ff_mpeg4_videotoolbox_hwaccel; +extern const AVHWAccel ff_vc1_d3d11va_hwaccel; +extern const AVHWAccel ff_vc1_d3d11va2_hwaccel; +extern const AVHWAccel ff_vc1_dxva2_hwaccel; +extern const AVHWAccel ff_vc1_nvdec_hwaccel; +extern const AVHWAccel ff_vc1_vaapi_hwaccel; +extern const AVHWAccel ff_vc1_vdpau_hwaccel; +extern const AVHWAccel ff_vp8_nvdec_hwaccel; +extern const AVHWAccel ff_vp8_vaapi_hwaccel; +extern const AVHWAccel ff_vp9_d3d11va_hwaccel; +extern const AVHWAccel ff_vp9_d3d11va2_hwaccel; +extern const AVHWAccel ff_vp9_dxva2_hwaccel; +extern const AVHWAccel ff_vp9_nvdec_hwaccel; +extern const AVHWAccel ff_vp9_vaapi_hwaccel; +extern const AVHWAccel ff_wmv3_d3d11va_hwaccel; +extern const AVHWAccel ff_wmv3_d3d11va2_hwaccel; +extern const AVHWAccel ff_wmv3_dxva2_hwaccel; +extern const AVHWAccel ff_wmv3_nvdec_hwaccel; +extern const AVHWAccel ff_wmv3_vaapi_hwaccel; +extern const AVHWAccel ff_wmv3_vdpau_hwaccel; + +#endif /* AVCODEC_HWACCELS_H */ diff --git a/libavcodec/idctdsp.c b/libavcodec/idctdsp.c index d596aed1a9e5a..662033bd78076 100644 --- a/libavcodec/idctdsp.c +++ b/libavcodec/idctdsp.c @@ -256,14 +256,20 @@ av_cold void ff_idctdsp_init(IDCTDSPContext *c, AVCodecContext *avctx) c->perm_type = FF_IDCT_PERM_NONE; } else { if (avctx->bits_per_raw_sample == 10 || avctx->bits_per_raw_sample == 9) { - c->idct_put = ff_simple_idct_put_10; - c->idct_add = ff_simple_idct_add_10; - c->idct = ff_simple_idct_10; + /* 10-bit MPEG-4 Simple Studio Profile requires a higher precision IDCT + However, it only uses idct_put */ + if (avctx->codec_id == AV_CODEC_ID_MPEG4 && avctx->profile == FF_PROFILE_MPEG4_SIMPLE_STUDIO) + c->idct_put = ff_simple_idct_put_int32_10bit; + else { + c->idct_put = ff_simple_idct_put_int16_10bit; + c->idct_add = ff_simple_idct_add_int16_10bit; + c->idct = ff_simple_idct_int16_10bit; + } c->perm_type = FF_IDCT_PERM_NONE; } else if (avctx->bits_per_raw_sample == 12) { - c->idct_put = ff_simple_idct_put_12; - c->idct_add = ff_simple_idct_add_12; - c->idct = ff_simple_idct_12; + c->idct_put = ff_simple_idct_put_int16_12bit; + c->idct_add = ff_simple_idct_add_int16_12bit; + c->idct = ff_simple_idct_int16_12bit; c->perm_type = FF_IDCT_PERM_NONE; } else { if (avctx->idct_algo == FF_IDCT_INT) { @@ -279,9 +285,10 @@ av_cold void ff_idctdsp_init(IDCTDSPContext *c, AVCodecContext *avctx) c->perm_type = FF_IDCT_PERM_NONE; #endif /* CONFIG_FAANIDCT */ } else { // accurate/default - c->idct_put = ff_simple_idct_put_8; - c->idct_add = ff_simple_idct_add_8; - c->idct = ff_simple_idct_8; + /* Be sure FF_IDCT_NONE will select this one, since it uses FF_IDCT_PERM_NONE */ + c->idct_put = ff_simple_idct_put_int16_8bit; + c->idct_add = ff_simple_idct_add_int16_8bit; + c->idct = ff_simple_idct_int16_8bit; c->perm_type = FF_IDCT_PERM_NONE; } } diff --git a/libavcodec/imgconvert.c b/libavcodec/imgconvert.c index 1547f18966e09..1fd636c83d8ef 100644 --- a/libavcodec/imgconvert.c +++ b/libavcodec/imgconvert.c @@ -69,10 +69,15 @@ enum AVPixelFormat avcodec_find_best_pix_fmt_of_list(const enum AVPixelFormat *p int i; enum AVPixelFormat best = AV_PIX_FMT_NONE; + int loss; - for(i=0; pix_fmt_list[i] != AV_PIX_FMT_NONE; i++) - best = avcodec_find_best_pix_fmt_of_2(best, pix_fmt_list[i], src_pix_fmt, has_alpha, loss_ptr); + for (i=0; pix_fmt_list[i] != AV_PIX_FMT_NONE; i++) { + loss = loss_ptr ? *loss_ptr : 0; + best = avcodec_find_best_pix_fmt_of_2(best, pix_fmt_list[i], src_pix_fmt, has_alpha, &loss); + } + if (loss_ptr) + *loss_ptr = loss; return best; } diff --git a/libavcodec/indeo5.c b/libavcodec/indeo5.c index 81b4514038ae4..b39cffd9a91be 100644 --- a/libavcodec/indeo5.c +++ b/libavcodec/indeo5.c @@ -324,6 +324,7 @@ static int decode_pic_hdr(IVI45DecContext *ctx, AVCodecContext *avctx) ctx->frame_type = get_bits(&ctx->gb, 3); if (ctx->frame_type >= 5) { av_log(avctx, AV_LOG_ERROR, "Invalid frame type: %d \n", ctx->frame_type); + ctx->frame_type = FRAMETYPE_INTRA; return AVERROR_INVALIDDATA; } diff --git a/libavcodec/internal.h b/libavcodec/internal.h index faa923c11f275..bb92873d7b85c 100644 --- a/libavcodec/internal.h +++ b/libavcodec/internal.h @@ -76,22 +76,20 @@ #endif -#if !FF_API_QUANT_BIAS #define FF_DEFAULT_QUANT_BIAS 999999 -#endif -#if !FF_API_QSCALE_TYPE #define FF_QSCALE_TYPE_MPEG1 0 #define FF_QSCALE_TYPE_MPEG2 1 #define FF_QSCALE_TYPE_H264 2 #define FF_QSCALE_TYPE_VP56 3 -#endif #define FF_SANE_NB_CHANNELS 64U #define FF_SIGNBIT(x) ((x) >> CHAR_BIT * sizeof(x) - 1) -#if HAVE_SIMD_ALIGN_32 +#if HAVE_SIMD_ALIGN_64 +# define STRIDE_ALIGN 64 /* AVX-512 */ +#elif HAVE_SIMD_ALIGN_32 # define STRIDE_ALIGN 32 #elif HAVE_SIMD_ALIGN_16 # define STRIDE_ALIGN 16 @@ -237,21 +235,8 @@ int ff_match_2uint16(const uint16_t (*tab)[2], int size, int a, int b); unsigned int avpriv_toupper4(unsigned int x); -/** - * does needed setup of pkt_pts/pos and such for (re)get_buffer(); - */ -int ff_init_buffer_info(AVCodecContext *s, AVFrame *frame); - - void ff_color_frame(AVFrame *frame, const int color[4]); -extern volatile int ff_avcodec_locked; -int ff_lock_avcodec(AVCodecContext *log_ctx, const AVCodec *codec); -int ff_unlock_avcodec(const AVCodec *codec); - -int avpriv_lock_avformat(void); -int avpriv_unlock_avformat(void); - /** * Maximum size in bytes of extradata. * This value was chosen such that every bit of the buffer is @@ -373,14 +358,16 @@ int ff_set_sar(AVCodecContext *avctx, AVRational sar); int ff_side_data_update_matrix_encoding(AVFrame *frame, enum AVMatrixEncoding matrix_encoding); -#if FF_API_MERGE_SD -int ff_packet_split_and_drop_side_data(AVPacket *pkt); -#endif - /** * Select the (possibly hardware accelerated) pixel format. * This is a wrapper around AVCodecContext.get_format() and should be used * instead of calling get_format() directly. + * + * The list of pixel formats must contain at least one valid entry, and is + * terminated with AV_PIX_FMT_NONE. If it is possible to decode to software, + * the last entry in the list must be the most accurate software format. + * If it is not possible to decode to software, AVCodecContext.sw_pix_fmt + * must be set before calling this function. */ int ff_get_format(AVCodecContext *avctx, const enum AVPixelFormat *fmt); @@ -417,4 +404,10 @@ int ff_alloc_a53_sei(const AVFrame *frame, size_t prefix_len, */ int64_t ff_guess_coded_bitrate(AVCodecContext *avctx); +#if defined(_WIN32) && CONFIG_SHARED && !defined(BUILDING_avcodec) +# define av_export_avcodec __declspec(dllimport) +#else +# define av_export_avcodec +#endif + #endif /* AVCODEC_INTERNAL_H */ diff --git a/libavcodec/ituh263dec.c b/libavcodec/ituh263dec.c index fc95a532ce794..1b57e53cad9ff 100644 --- a/libavcodec/ituh263dec.c +++ b/libavcodec/ituh263dec.c @@ -207,12 +207,27 @@ static int h263_decode_gob_header(MpegEncContext *s) } /** - * Decode the group of blocks / video packet header. + * Decode the group of blocks / video packet header / slice header (MPEG-4 Studio). * @return bit position of the resync_marker, or <0 if none was found */ int ff_h263_resync(MpegEncContext *s){ int left, pos, ret; + /* In MPEG-4 studio mode look for a new slice startcode + * and decode slice header */ + if(s->codec_id==AV_CODEC_ID_MPEG4 && s->studio_profile) { + align_get_bits(&s->gb); + + while (get_bits_left(&s->gb) >= 32 && show_bits_long(&s->gb, 32) != SLICE_START_CODE) { + get_bits(&s->gb, 8); + } + + if (show_bits_long(&s->gb, 32) == SLICE_START_CODE) + return get_bits_count(&s->gb); + else + return -1; + } + if(s->codec_id==AV_CODEC_ID_MPEG4){ skip_bits1(&s->gb); align_get_bits(&s->gb); diff --git a/libavcodec/j2kenc.c b/libavcodec/j2kenc.c index c8d38617327d2..3e542af3c66b6 100644 --- a/libavcodec/j2kenc.c +++ b/libavcodec/j2kenc.c @@ -69,6 +69,7 @@ #include "bytestream.h" #include "jpeg2000.h" #include "libavutil/common.h" +#include "libavutil/pixdesc.h" #include "libavutil/opt.h" #define NMSEDEC_BITS 7 @@ -662,7 +663,8 @@ static void encode_cblk(Jpeg2000EncoderContext *s, Jpeg2000T1Context *t1, Jpeg20 bpno = cblk->nonzerobits - 1; } - ff_mqc_initenc(&t1->mqc, cblk->data); + cblk->data[0] = 0; + ff_mqc_initenc(&t1->mqc, cblk->data + 1); for (passno = 0; bpno >= 0; passno++){ nmsedec=0; @@ -688,7 +690,8 @@ static void encode_cblk(Jpeg2000EncoderContext *s, Jpeg2000T1Context *t1, Jpeg20 cblk->npasses = passno; cblk->ninclpasses = passno; - cblk->passes[passno-1].rate = ff_mqc_flush_to(&t1->mqc, cblk->passes[passno-1].flushed, &cblk->passes[passno-1].flushed_len); + if (passno) + cblk->passes[passno-1].rate = ff_mqc_flush_to(&t1->mqc, cblk->passes[passno-1].flushed, &cblk->passes[passno-1].flushed_len); } /* tier-2 routines: */ @@ -795,7 +798,7 @@ static int encode_packet(Jpeg2000EncoderContext *s, Jpeg2000ResLevel *rlevel, in if (cblk->ninclpasses){ if (s->buf_end - s->buf < cblk->passes[cblk->ninclpasses-1].rate) return -1; - bytestream_put_buffer(&s->buf, cblk->data, cblk->passes[cblk->ninclpasses-1].rate + bytestream_put_buffer(&s->buf, cblk->data + 1, cblk->passes[cblk->ninclpasses-1].rate - cblk->passes[cblk->ninclpasses-1].flushed_len); bytestream_put_buffer(&s->buf, cblk->passes[cblk->ninclpasses-1].flushed, cblk->passes[cblk->ninclpasses-1].flushed_len); @@ -936,6 +939,12 @@ static int encode_tile(Jpeg2000EncoderContext *s, Jpeg2000Tile *tile, int tileno } } } + if (!prec->cblk[cblkno].data) + prec->cblk[cblkno].data = av_malloc(1 + 8192); + if (!prec->cblk[cblkno].passes) + prec->cblk[cblkno].passes = av_malloc_array(JPEG2000_MAX_PASSES, sizeof (*prec->cblk[cblkno].passes)); + if (!prec->cblk[cblkno].data || !prec->cblk[cblkno].passes) + return AVERROR(ENOMEM); encode_cblk(s, &t1, prec->cblk + cblkno, tile, xx1 - xx0, yy1 - yy0, bandpos, codsty->nreslevels - reslevelno - 1); xx0 = xx1; @@ -1150,8 +1159,10 @@ FF_ENABLE_DEPRECATION_WARNINGS } else{ // planar YUV s->planar = 1; s->ncomponents = 3; - avcodec_get_chroma_sub_sample(avctx->pix_fmt, - s->chroma_shift, s->chroma_shift + 1); + ret = av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, + s->chroma_shift, s->chroma_shift + 1); + if (ret) + return ret; } ff_jpeg2000_init_tier1_luts(); diff --git a/libavcodec/jpeg2000.c b/libavcodec/jpeg2000.c index afeb9df27c408..8e90980976e52 100644 --- a/libavcodec/jpeg2000.c +++ b/libavcodec/jpeg2000.c @@ -357,10 +357,8 @@ static int init_prec(Jpeg2000Band *band, comp->reslevel[reslevelno-1].coord[1][0]; } - cblk->zero = 0; cblk->lblock = 3; cblk->length = 0; - memset(cblk->lengthinc, 0, sizeof(cblk->lengthinc)); cblk->npasses = 0; } @@ -543,6 +541,9 @@ int ff_jpeg2000_init_component(Jpeg2000Component *comp, if (!reslevel->band) return AVERROR(ENOMEM); + if (reslevel->num_precincts_x * (uint64_t)reslevel->num_precincts_y * reslevel->nbands > avctx->max_pixels / sizeof(*reslevel->band->prec)) + return AVERROR(ENOMEM); + for (bandno = 0; bandno < reslevel->nbands; bandno++, gbandno++) { ret = init_band(avctx, reslevel, comp, codsty, qntsty, @@ -598,9 +599,21 @@ void ff_jpeg2000_cleanup(Jpeg2000Component *comp, Jpeg2000CodingStyle *codsty) for (precno = 0; precno < reslevel->num_precincts_x * reslevel->num_precincts_y; precno++) { if (band->prec) { Jpeg2000Prec *prec = band->prec + precno; + int nb_code_blocks = prec->nb_codeblocks_height * prec->nb_codeblocks_width; + av_freep(&prec->zerobits); av_freep(&prec->cblkincl); - av_freep(&prec->cblk); + if (prec->cblk) { + int cblkno; + for (cblkno = 0; cblkno < nb_code_blocks; cblkno ++) { + Jpeg2000Cblk *cblk = &prec->cblk[cblkno]; + av_freep(&cblk->data); + av_freep(&cblk->passes); + av_freep(&cblk->lengthinc); + av_freep(&cblk->data_start); + } + av_freep(&prec->cblk); + } } } diff --git a/libavcodec/jpeg2000.h b/libavcodec/jpeg2000.h index 8a022ad9188a8..c429ca5996175 100644 --- a/libavcodec/jpeg2000.h +++ b/libavcodec/jpeg2000.h @@ -165,15 +165,15 @@ typedef struct Jpeg2000Cblk { uint8_t ninclpasses; // number coding of passes included in codestream uint8_t nonzerobits; uint16_t length; - uint16_t lengthinc[JPEG2000_MAX_PASSES]; + uint16_t *lengthinc; uint8_t nb_lengthinc; uint8_t lblock; - uint8_t zero; - uint8_t data[8192]; + uint8_t *data; + size_t data_allocated; int nb_terminations; int nb_terminationsinc; - int data_start[JPEG2000_MAX_PASSES]; - Jpeg2000Pass passes[JPEG2000_MAX_PASSES]; + int *data_start; + Jpeg2000Pass *passes; int coord[2][2]; // border coordinates {{x0, x1}, {y0, y1}} } Jpeg2000Cblk; // code block diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c index 9a5e64e85408a..5414ce565547c 100644 --- a/libavcodec/jpeg2000dec.c +++ b/libavcodec/jpeg2000dec.c @@ -34,6 +34,7 @@ #include "libavutil/imgutils.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" +#include "libavutil/thread.h" #include "avcodec.h" #include "bytestream.h" #include "internal.h" @@ -284,7 +285,7 @@ static int get_siz(Jpeg2000DecoderContext *s) avpriv_request_sample(s->avctx, "Support for image offsets"); return AVERROR_PATCHWELCOME; } - if (av_image_check_size(s->width, s->height, 0, s->avctx)) { + if (av_image_check_size2(s->width, s->height, s->avctx->max_pixels, AV_PIX_FMT_NONE, 0, s->avctx)) { avpriv_request_sample(s->avctx, "Large Dimensions"); return AVERROR_PATCHWELCOME; } @@ -949,6 +950,7 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, for (cblkno = 0; cblkno < nb_code_blocks; cblkno++) { Jpeg2000Cblk *cblk = prec->cblk + cblkno; int incl, newpasses, llen; + void *tmp; if (cblk->npasses) incl = get_bits(s, 1); @@ -988,6 +990,14 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, cblk->nb_lengthinc = 0; cblk->nb_terminationsinc = 0; + av_free(cblk->lengthinc); + cblk->lengthinc = av_mallocz_array(newpasses , sizeof(*cblk->lengthinc)); + if (!cblk->lengthinc) + return AVERROR(ENOMEM); + tmp = av_realloc_array(cblk->data_start, cblk->nb_terminations + newpasses + 1, sizeof(*cblk->data_start)); + if (!tmp) + return AVERROR(ENOMEM); + cblk->data_start = tmp; do { int newpasses1 = 0; @@ -1001,10 +1011,18 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, if ((ret = get_bits(s, av_log2(newpasses1) + cblk->lblock)) < 0) return ret; - if (ret > sizeof(cblk->data)) { + if (ret > cblk->data_allocated) { + size_t new_size = FFMAX(2*cblk->data_allocated, ret); + void *new = av_realloc(cblk->data, new_size); + if (new) { + cblk->data = new; + cblk->data_allocated = new_size; + } + } + if (ret > cblk->data_allocated) { avpriv_request_sample(s->avctx, "Block with lengthinc greater than %"SIZE_SPECIFIER"", - sizeof(cblk->data)); + cblk->data_allocated); return AVERROR_PATCHWELCOME; } cblk->lengthinc[cblk->nb_lengthinc++] = ret; @@ -1029,9 +1047,19 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, nb_code_blocks = prec->nb_codeblocks_height * prec->nb_codeblocks_width; for (cblkno = 0; cblkno < nb_code_blocks; cblkno++) { Jpeg2000Cblk *cblk = prec->cblk + cblkno; + if (!cblk->nb_terminationsinc && !cblk->lengthinc) + continue; for (cwsno = 0; cwsno < cblk->nb_lengthinc; cwsno ++) { + if (cblk->data_allocated < cblk->length + cblk->lengthinc[cwsno] + 4) { + size_t new_size = FFMAX(2*cblk->data_allocated, cblk->length + cblk->lengthinc[cwsno] + 4); + void *new = av_realloc(cblk->data, new_size); + if (new) { + cblk->data = new; + cblk->data_allocated = new_size; + } + } if ( bytestream2_get_bytes_left(&s->g) < cblk->lengthinc[cwsno] - || sizeof(cblk->data) < cblk->length + cblk->lengthinc[cwsno] + 4 + || cblk->data_allocated < cblk->length + cblk->lengthinc[cwsno] + 4 ) { av_log(s->avctx, AV_LOG_ERROR, "Block length %"PRIu16" or lengthinc %d is too large, left %d\n", @@ -1050,6 +1078,7 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, cblk->data_start[cblk->nb_terminations] = cblk->length; } } + av_freep(&cblk->lengthinc); } } return 0; @@ -1981,7 +2010,16 @@ static int jp2_find_codestream(Jpeg2000DecoderContext *s) bytestream2_get_bytes_left(&s->g) >= 8) { atom_size = bytestream2_get_be32u(&s->g); atom = bytestream2_get_be32u(&s->g); - atom_end = bytestream2_tell(&s->g) + atom_size - 8; + if (atom_size == 1) { + if (bytestream2_get_be32u(&s->g)) { + avpriv_request_sample(s->avctx, "Huge atom"); + return 0; + } + atom_size = bytestream2_get_be32u(&s->g); + atom_end = bytestream2_tell(&s->g) + atom_size - 16; + } else { + atom_end = bytestream2_tell(&s->g) + atom_size - 8; + } if (atom == JP2_CODESTREAM) return 1; @@ -2039,13 +2077,13 @@ static int jp2_find_codestream(Jpeg2000DecoderContext *s) } if (colour_depth[1] <= 8) { g = bytestream2_get_byteu(&s->g) << 8 - colour_depth[1]; - r |= r >> colour_depth[1]; + g |= g >> colour_depth[1]; } else { g = bytestream2_get_be16u(&s->g) >> colour_depth[1] - 8; } if (colour_depth[2] <= 8) { b = bytestream2_get_byteu(&s->g) << 8 - colour_depth[2]; - r |= r >> colour_depth[2]; + b |= b >> colour_depth[2]; } else { b = bytestream2_get_be16u(&s->g) >> colour_depth[2] - 8; } @@ -2105,10 +2143,18 @@ static int jp2_find_codestream(Jpeg2000DecoderContext *s) return 0; } +static av_cold void jpeg2000_init_static_data(void) +{ + ff_jpeg2000_init_tier1_luts(); + ff_mqc_init_context_tables(); +} + static av_cold int jpeg2000_decode_init(AVCodecContext *avctx) { + static AVOnce init_static_once = AV_ONCE_INIT; Jpeg2000DecoderContext *s = avctx->priv_data; + ff_thread_once(&init_static_once, jpeg2000_init_static_data); ff_jpeg2000dsp_init(&s->dsp); return 0; @@ -2186,12 +2232,6 @@ static int jpeg2000_decode_frame(AVCodecContext *avctx, void *data, return ret; } -static av_cold void jpeg2000_init_static_data(AVCodec *codec) -{ - ff_jpeg2000_init_tier1_luts(); - ff_mqc_init_context_tables(); -} - #define OFFSET(x) offsetof(Jpeg2000DecoderContext, x) #define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM @@ -2215,7 +2255,6 @@ AVCodec ff_jpeg2000_decoder = { .id = AV_CODEC_ID_JPEG2000, .capabilities = AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_DR1, .priv_data_size = sizeof(Jpeg2000DecoderContext), - .init_static_data = jpeg2000_init_static_data, .init = jpeg2000_decode_init, .decode = jpeg2000_decode_frame, .priv_class = &jpeg2000_class, diff --git a/libavcodec/jpeg2000dsp.c b/libavcodec/jpeg2000dsp.c index 85a12d0e9b715..90e73b1e202de 100644 --- a/libavcodec/jpeg2000dsp.c +++ b/libavcodec/jpeg2000dsp.c @@ -64,9 +64,9 @@ static void ict_int(void *_src0, void *_src1, void *_src2, int csize) int i; for (i = 0; i < csize; i++) { - i0 = *src0 + *src2 + (((26345 * *src2) + (1 << 15)) >> 16); + i0 = *src0 + *src2 + ((int)((26345U * *src2) + (1 << 15)) >> 16); i1 = *src0 - ((int)(((unsigned)i_ict_params[1] * *src1) + (1 << 15)) >> 16) - - (((i_ict_params[2] * *src2) + (1 << 15)) >> 16); + - ((int)(((unsigned)i_ict_params[2] * *src2) + (1 << 15)) >> 16); i2 = *src0 + (2 * *src1) + ((int)((-14942U * *src1) + (1 << 15)) >> 16); *src0++ = i0; *src1++ = i1; diff --git a/libavcodec/jpeg2000dwt.c b/libavcodec/jpeg2000dwt.c index 55dd5e89b524a..ce1678a3d74ed 100644 --- a/libavcodec/jpeg2000dwt.c +++ b/libavcodec/jpeg2000dwt.c @@ -305,22 +305,22 @@ static void dwt_encode97_int(DWTContext *s, int *t) t[i] = (t[i] + ((1<>1)) >> I_PRESHIFT; } -static void sr_1d53(int *p, int i0, int i1) +static void sr_1d53(unsigned *p, int i0, int i1) { int i; if (i1 <= i0 + 1) { if (i0 == 1) - p[1] >>= 1; + p[1] = (int)p[1] >> 1; return; } extend53(p, i0, i1); for (i = (i0 >> 1); i < (i1 >> 1) + 1; i++) - p[2 * i] -= (p[2 * i - 1] + p[2 * i + 1] + 2) >> 2; + p[2 * i] -= (int)(p[2 * i - 1] + p[2 * i + 1] + 2) >> 2; for (i = (i0 >> 1); i < (i1 >> 1); i++) - p[2 * i + 1] += (p[2 * i] + p[2 * i + 2]) >> 1; + p[2 * i + 1] += (int)(p[2 * i] + p[2 * i + 2]) >> 1; } static void dwt_decode53(DWTContext *s, int *t) diff --git a/libavcodec/jpegls.h b/libavcodec/jpegls.h index c8997c786185c..6b89b2afa3dfe 100644 --- a/libavcodec/jpegls.h +++ b/libavcodec/jpegls.h @@ -32,6 +32,8 @@ #include "avcodec.h" #include "internal.h" +#undef near /* This file uses struct member 'near' which in windows.h is defined as empty. */ + typedef struct JpeglsContext { AVCodecContext *avctx; } JpeglsContext; diff --git a/libavcodec/jpeglsdec.c b/libavcodec/jpeglsdec.c index 64505321affe3..5308b744df1fd 100644 --- a/libavcodec/jpeglsdec.c +++ b/libavcodec/jpeglsdec.c @@ -233,6 +233,9 @@ static inline void ls_decode_line(JLSState *state, MJpegDecodeContext *s, while (x < w) { int err, pred; + if (get_bits_left(&s->gb) <= 0) + return; + /* compute gradients */ Ra = x ? R(dst, x - stride) : R(last, x); Rb = R(last, x); @@ -443,6 +446,10 @@ int ff_jpegls_decode_picture(MJpegDecodeContext *s, int near, avpriv_report_missing_feature(s->avctx, "Sample interleaved images"); ret = AVERROR_PATCHWELCOME; goto end; + } else { /* unknown interleaving */ + avpriv_report_missing_feature(s->avctx, "Unknown interleaved images"); + ret = AVERROR_PATCHWELCOME; + goto end; } if (s->xfrm && s->nb_components == 3) { diff --git a/libavcodec/jpegtables.h b/libavcodec/jpegtables.h index 6833b4b1661fa..aa38df40335f6 100644 --- a/libavcodec/jpegtables.h +++ b/libavcodec/jpegtables.h @@ -23,18 +23,18 @@ #include -#include "libavutil/internal.h" +#include "internal.h" -extern av_export const uint8_t avpriv_mjpeg_bits_dc_luminance[]; -extern av_export const uint8_t avpriv_mjpeg_val_dc[]; +extern av_export_avcodec const uint8_t avpriv_mjpeg_bits_dc_luminance[]; +extern av_export_avcodec const uint8_t avpriv_mjpeg_val_dc[]; -extern av_export const uint8_t avpriv_mjpeg_bits_dc_chrominance[]; +extern av_export_avcodec const uint8_t avpriv_mjpeg_bits_dc_chrominance[]; -extern av_export const uint8_t avpriv_mjpeg_bits_ac_luminance[]; -extern av_export const uint8_t avpriv_mjpeg_val_ac_luminance[]; +extern av_export_avcodec const uint8_t avpriv_mjpeg_bits_ac_luminance[]; +extern av_export_avcodec const uint8_t avpriv_mjpeg_val_ac_luminance[]; -extern av_export const uint8_t avpriv_mjpeg_bits_ac_chrominance[]; -extern av_export const uint8_t avpriv_mjpeg_val_ac_chrominance[]; +extern av_export_avcodec const uint8_t avpriv_mjpeg_bits_ac_chrominance[]; +extern av_export_avcodec const uint8_t avpriv_mjpeg_val_ac_chrominance[]; void ff_mjpeg_build_huffman_codes(uint8_t *huff_size, uint16_t *huff_code, const uint8_t *bits_table, diff --git a/libavcodec/kgv1dec.c b/libavcodec/kgv1dec.c index 5359411c76190..a6bd9400ac16f 100644 --- a/libavcodec/kgv1dec.c +++ b/libavcodec/kgv1dec.c @@ -62,6 +62,9 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, h = (buf[1] + 1) * 8; buf += 2; + if (avpkt->size < 2 + w*h / 513) + return AVERROR_INVALIDDATA; + if (w != avctx->width || h != avctx->height) { av_freep(&c->frame_buffer); av_freep(&c->last_frame_buffer); diff --git a/libavcodec/libaomdec.c b/libavcodec/libaomdec.c new file mode 100644 index 0000000000000..6a2de6d47a760 --- /dev/null +++ b/libavcodec/libaomdec.c @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2010, Google, Inc. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AV1 decoder support via libaom + */ + +#include +#include + +#include "libavutil/common.h" +#include "libavutil/imgutils.h" + +#include "avcodec.h" +#include "internal.h" +#include "profiles.h" + +typedef struct AV1DecodeContext { + struct aom_codec_ctx decoder; +} AV1DecodeContext; + +static av_cold int aom_init(AVCodecContext *avctx, + const struct aom_codec_iface *iface) +{ + AV1DecodeContext *ctx = avctx->priv_data; + struct aom_codec_dec_cfg deccfg = { + /* token partitions+1 would be a decent choice */ + .threads = FFMIN(avctx->thread_count, 16) + }; + + av_log(avctx, AV_LOG_INFO, "%s\n", aom_codec_version_str()); + av_log(avctx, AV_LOG_VERBOSE, "%s\n", aom_codec_build_config()); + + if (aom_codec_dec_init(&ctx->decoder, iface, &deccfg, 0) != AOM_CODEC_OK) { + const char *error = aom_codec_error(&ctx->decoder); + av_log(avctx, AV_LOG_ERROR, "Failed to initialize decoder: %s\n", + error); + return AVERROR(EINVAL); + } + + return 0; +} + +static void image_copy_16_to_8(AVFrame *pic, struct aom_image *img) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pic->format); + int i; + + for (i = 0; i < desc->nb_components; i++) { + int w = img->d_w; + int h = img->d_h; + int x, y; + + if (i) { + w = (w + img->x_chroma_shift) >> img->x_chroma_shift; + h = (h + img->y_chroma_shift) >> img->y_chroma_shift; + } + + for (y = 0; y < h; y++) { + uint16_t *src = (uint16_t *)(img->planes[i] + y * img->stride[i]); + uint8_t *dst = pic->data[i] + y * pic->linesize[i]; + for (x = 0; x < w; x++) + *dst++ = *src++; + } + } +} + +// returns 0 on success, AVERROR_INVALIDDATA otherwise +static int set_pix_fmt(AVCodecContext *avctx, struct aom_image *img) +{ + static const enum AVColorRange color_ranges[] = { + AVCOL_RANGE_MPEG, AVCOL_RANGE_JPEG + }; + avctx->color_range = color_ranges[img->range]; + avctx->color_primaries = img->cp; + avctx->colorspace = img->mc; + avctx->color_trc = img->tc; + + switch (img->fmt) { + case AOM_IMG_FMT_I420: + case AOM_IMG_FMT_I42016: + if (img->bit_depth == 8) { + avctx->pix_fmt = img->monochrome ? + AV_PIX_FMT_GRAY8 : AV_PIX_FMT_YUV420P; + avctx->profile = FF_PROFILE_AV1_MAIN; + return 0; + } else if (img->bit_depth == 10) { + avctx->pix_fmt = img->monochrome ? + AV_PIX_FMT_GRAY10 : AV_PIX_FMT_YUV420P10; + avctx->profile = FF_PROFILE_AV1_MAIN; + return 0; + } else if (img->bit_depth == 12) { + avctx->pix_fmt = img->monochrome ? + AV_PIX_FMT_GRAY12 : AV_PIX_FMT_YUV420P12; + avctx->profile = FF_PROFILE_AV1_PROFESSIONAL; + return 0; + } else { + return AVERROR_INVALIDDATA; + } + case AOM_IMG_FMT_I422: + case AOM_IMG_FMT_I42216: + if (img->bit_depth == 8) { + avctx->pix_fmt = AV_PIX_FMT_YUV422P; + avctx->profile = FF_PROFILE_AV1_PROFESSIONAL; + return 0; + } else if (img->bit_depth == 10) { + avctx->pix_fmt = AV_PIX_FMT_YUV422P10; + avctx->profile = FF_PROFILE_AV1_PROFESSIONAL; + return 0; + } else if (img->bit_depth == 12) { + avctx->pix_fmt = AV_PIX_FMT_YUV422P12; + avctx->profile = FF_PROFILE_AV1_PROFESSIONAL; + return 0; + } else { + return AVERROR_INVALIDDATA; + } + case AOM_IMG_FMT_I444: + case AOM_IMG_FMT_I44416: + if (img->bit_depth == 8) { + avctx->pix_fmt = AV_PIX_FMT_YUV444P; + avctx->profile = FF_PROFILE_AV1_HIGH; + return 0; + } else if (img->bit_depth == 10) { + avctx->pix_fmt = AV_PIX_FMT_YUV444P10; + avctx->profile = FF_PROFILE_AV1_HIGH; + return 0; + } else if (img->bit_depth == 12) { + avctx->pix_fmt = AV_PIX_FMT_YUV444P12; + avctx->profile = FF_PROFILE_AV1_PROFESSIONAL; + return 0; + } else { + return AVERROR_INVALIDDATA; + } + + default: + return AVERROR_INVALIDDATA; + } +} + +static int aom_decode(AVCodecContext *avctx, void *data, int *got_frame, + AVPacket *avpkt) +{ + AV1DecodeContext *ctx = avctx->priv_data; + AVFrame *picture = data; + const void *iter = NULL; + struct aom_image *img; + int ret; + + if (aom_codec_decode(&ctx->decoder, avpkt->data, avpkt->size, NULL) != + AOM_CODEC_OK) { + const char *error = aom_codec_error(&ctx->decoder); + const char *detail = aom_codec_error_detail(&ctx->decoder); + + av_log(avctx, AV_LOG_ERROR, "Failed to decode frame: %s\n", error); + if (detail) + av_log(avctx, AV_LOG_ERROR, " Additional information: %s\n", + detail); + return AVERROR_INVALIDDATA; + } + + if ((img = aom_codec_get_frame(&ctx->decoder, &iter))) { + if (img->d_w > img->w || img->d_h > img->h) { + av_log(avctx, AV_LOG_ERROR, "Display dimensions %dx%d exceed storage %dx%d\n", + img->d_w, img->d_h, img->w, img->h); + return AVERROR_EXTERNAL; + } + + if ((ret = set_pix_fmt(avctx, img)) < 0) { + av_log(avctx, AV_LOG_ERROR, "Unsupported output colorspace (%d) / bit_depth (%d)\n", + img->fmt, img->bit_depth); + return ret; + } + + if ((int)img->d_w != avctx->width || (int)img->d_h != avctx->height) { + av_log(avctx, AV_LOG_INFO, "dimension change! %dx%d -> %dx%d\n", + avctx->width, avctx->height, img->d_w, img->d_h); + ret = ff_set_dimensions(avctx, img->d_w, img->d_h); + if (ret < 0) + return ret; + } + if ((ret = ff_get_buffer(avctx, picture, 0)) < 0) + return ret; + if ((img->fmt & AOM_IMG_FMT_HIGHBITDEPTH) && img->bit_depth == 8) + image_copy_16_to_8(picture, img); + else + av_image_copy(picture->data, picture->linesize, (const uint8_t **)img->planes, + img->stride, avctx->pix_fmt, img->d_w, img->d_h); + *got_frame = 1; + } + return avpkt->size; +} + +static av_cold int aom_free(AVCodecContext *avctx) +{ + AV1DecodeContext *ctx = avctx->priv_data; + aom_codec_destroy(&ctx->decoder); + return 0; +} + +static av_cold int av1_init(AVCodecContext *avctx) +{ + return aom_init(avctx, &aom_codec_av1_dx_algo); +} + +AVCodec ff_libaom_av1_decoder = { + .name = "libaom-av1", + .long_name = NULL_IF_CONFIG_SMALL("libaom AV1"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_AV1, + .priv_data_size = sizeof(AV1DecodeContext), + .init = av1_init, + .close = aom_free, + .decode = aom_decode, + .capabilities = AV_CODEC_CAP_AUTO_THREADS | AV_CODEC_CAP_DR1, + .profiles = NULL_IF_CONFIG_SMALL(ff_av1_profiles), + .wrapper_name = "libaom", +}; diff --git a/libavcodec/libaomenc.c b/libavcodec/libaomenc.c new file mode 100644 index 0000000000000..41b05dc1c0508 --- /dev/null +++ b/libavcodec/libaomenc.c @@ -0,0 +1,741 @@ +/* + * Copyright (c) 2010, Google, Inc. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * AV1 encoder support via libaom + */ + +#define AOM_DISABLE_CTRL_TYPECHECKS 1 +#include +#include + +#include "libavutil/avassert.h" +#include "libavutil/base64.h" +#include "libavutil/common.h" +#include "libavutil/mathematics.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avcodec.h" +#include "internal.h" +#include "profiles.h" + +/* + * Portion of struct aom_codec_cx_pkt from aom_encoder.h. + * One encoded frame returned from the library. + */ +struct FrameListData { + void *buf; /**< compressed data buffer */ + size_t sz; /**< length of compressed data */ + int64_t pts; /**< time stamp to show frame + (in timebase units) */ + unsigned long duration; /**< duration to show frame + (in timebase units) */ + uint32_t flags; /**< flags for this frame */ + struct FrameListData *next; +}; + +typedef struct AOMEncoderContext { + AVClass *class; + struct aom_codec_ctx encoder; + struct aom_image rawimg; + struct aom_fixed_buf twopass_stats; + struct FrameListData *coded_frame_list; + int cpu_used; + int auto_alt_ref; + int lag_in_frames; + int error_resilient; + int crf; + int static_thresh; + int drop_threshold; + int noise_sensitivity; +} AOMContext; + +static const char *const ctlidstr[] = { + [AOME_SET_CPUUSED] = "AOME_SET_CPUUSED", + [AOME_SET_CQ_LEVEL] = "AOME_SET_CQ_LEVEL", + [AOME_SET_ENABLEAUTOALTREF] = "AOME_SET_ENABLEAUTOALTREF", + [AOME_SET_STATIC_THRESHOLD] = "AOME_SET_STATIC_THRESHOLD", + [AV1E_SET_COLOR_RANGE] = "AV1E_SET_COLOR_RANGE", + [AV1E_SET_COLOR_PRIMARIES] = "AV1E_SET_COLOR_PRIMARIES", + [AV1E_SET_MATRIX_COEFFICIENTS] = "AV1E_SET_MATRIX_COEFFICIENTS", + [AV1E_SET_TRANSFER_CHARACTERISTICS] = "AV1E_SET_TRANSFER_CHARACTERISTICS", +}; + +static av_cold void log_encoder_error(AVCodecContext *avctx, const char *desc) +{ + AOMContext *ctx = avctx->priv_data; + const char *error = aom_codec_error(&ctx->encoder); + const char *detail = aom_codec_error_detail(&ctx->encoder); + + av_log(avctx, AV_LOG_ERROR, "%s: %s\n", desc, error); + if (detail) + av_log(avctx, AV_LOG_ERROR, " Additional information: %s\n", detail); +} + +static av_cold void dump_enc_cfg(AVCodecContext *avctx, + const struct aom_codec_enc_cfg *cfg) +{ + int width = -30; + int level = AV_LOG_DEBUG; + + av_log(avctx, level, "aom_codec_enc_cfg\n"); + av_log(avctx, level, "generic settings\n" + " %*s%u\n %*s%u\n %*s%u\n %*s%u\n %*s%u\n" + " %*s%u\n %*s%u\n" + " %*s{%u/%u}\n %*s%u\n %*s%d\n %*s%u\n", + width, "g_usage:", cfg->g_usage, + width, "g_threads:", cfg->g_threads, + width, "g_profile:", cfg->g_profile, + width, "g_w:", cfg->g_w, + width, "g_h:", cfg->g_h, + width, "g_bit_depth:", cfg->g_bit_depth, + width, "g_input_bit_depth:", cfg->g_input_bit_depth, + width, "g_timebase:", cfg->g_timebase.num, cfg->g_timebase.den, + width, "g_error_resilient:", cfg->g_error_resilient, + width, "g_pass:", cfg->g_pass, + width, "g_lag_in_frames:", cfg->g_lag_in_frames); + av_log(avctx, level, "rate control settings\n" + " %*s%u\n %*s%d\n %*s%p(%"SIZE_SPECIFIER")\n %*s%u\n", + width, "rc_dropframe_thresh:", cfg->rc_dropframe_thresh, + width, "rc_end_usage:", cfg->rc_end_usage, + width, "rc_twopass_stats_in:", cfg->rc_twopass_stats_in.buf, cfg->rc_twopass_stats_in.sz, + width, "rc_target_bitrate:", cfg->rc_target_bitrate); + av_log(avctx, level, "quantizer settings\n" + " %*s%u\n %*s%u\n", + width, "rc_min_quantizer:", cfg->rc_min_quantizer, + width, "rc_max_quantizer:", cfg->rc_max_quantizer); + av_log(avctx, level, "bitrate tolerance\n" + " %*s%u\n %*s%u\n", + width, "rc_undershoot_pct:", cfg->rc_undershoot_pct, + width, "rc_overshoot_pct:", cfg->rc_overshoot_pct); + av_log(avctx, level, "decoder buffer model\n" + " %*s%u\n %*s%u\n %*s%u\n", + width, "rc_buf_sz:", cfg->rc_buf_sz, + width, "rc_buf_initial_sz:", cfg->rc_buf_initial_sz, + width, "rc_buf_optimal_sz:", cfg->rc_buf_optimal_sz); + av_log(avctx, level, "2 pass rate control settings\n" + " %*s%u\n %*s%u\n %*s%u\n", + width, "rc_2pass_vbr_bias_pct:", cfg->rc_2pass_vbr_bias_pct, + width, "rc_2pass_vbr_minsection_pct:", cfg->rc_2pass_vbr_minsection_pct, + width, "rc_2pass_vbr_maxsection_pct:", cfg->rc_2pass_vbr_maxsection_pct); + av_log(avctx, level, "keyframing settings\n" + " %*s%d\n %*s%u\n %*s%u\n", + width, "kf_mode:", cfg->kf_mode, + width, "kf_min_dist:", cfg->kf_min_dist, + width, "kf_max_dist:", cfg->kf_max_dist); + av_log(avctx, level, "\n"); +} + +static void coded_frame_add(void *list, struct FrameListData *cx_frame) +{ + struct FrameListData **p = list; + + while (*p) + p = &(*p)->next; + *p = cx_frame; + cx_frame->next = NULL; +} + +static av_cold void free_coded_frame(struct FrameListData *cx_frame) +{ + av_freep(&cx_frame->buf); + av_freep(&cx_frame); +} + +static av_cold void free_frame_list(struct FrameListData *list) +{ + struct FrameListData *p = list; + + while (p) { + list = list->next; + free_coded_frame(p); + p = list; + } +} + +static av_cold int codecctl_int(AVCodecContext *avctx, + enum aome_enc_control_id id, int val) +{ + AOMContext *ctx = avctx->priv_data; + char buf[80]; + int width = -30; + int res; + + snprintf(buf, sizeof(buf), "%s:", ctlidstr[id]); + av_log(avctx, AV_LOG_DEBUG, " %*s%d\n", width, buf, val); + + res = aom_codec_control(&ctx->encoder, id, val); + if (res != AOM_CODEC_OK) { + snprintf(buf, sizeof(buf), "Failed to set %s codec control", + ctlidstr[id]); + log_encoder_error(avctx, buf); + return AVERROR(EINVAL); + } + + return 0; +} + +static av_cold int aom_free(AVCodecContext *avctx) +{ + AOMContext *ctx = avctx->priv_data; + + aom_codec_destroy(&ctx->encoder); + av_freep(&ctx->twopass_stats.buf); + av_freep(&avctx->stats_out); + free_frame_list(ctx->coded_frame_list); + return 0; +} + +static int set_pix_fmt(AVCodecContext *avctx, aom_codec_caps_t codec_caps, + struct aom_codec_enc_cfg *enccfg, aom_codec_flags_t *flags, + aom_img_fmt_t *img_fmt) +{ + AOMContext av_unused *ctx = avctx->priv_data; + enccfg->g_bit_depth = enccfg->g_input_bit_depth = 8; + switch (avctx->pix_fmt) { + case AV_PIX_FMT_YUV420P: + enccfg->g_profile = FF_PROFILE_AV1_MAIN; + *img_fmt = AOM_IMG_FMT_I420; + return 0; + case AV_PIX_FMT_YUV422P: + enccfg->g_profile = FF_PROFILE_AV1_PROFESSIONAL; + *img_fmt = AOM_IMG_FMT_I422; + return 0; + case AV_PIX_FMT_YUV444P: + enccfg->g_profile = FF_PROFILE_AV1_HIGH; + *img_fmt = AOM_IMG_FMT_I444; + return 0; + case AV_PIX_FMT_YUV420P10: + case AV_PIX_FMT_YUV420P12: + if (codec_caps & AOM_CODEC_CAP_HIGHBITDEPTH) { + enccfg->g_bit_depth = enccfg->g_input_bit_depth = + avctx->pix_fmt == AV_PIX_FMT_YUV420P10 ? 10 : 12; + enccfg->g_profile = + enccfg->g_bit_depth == 10 ? FF_PROFILE_AV1_MAIN : FF_PROFILE_AV1_PROFESSIONAL; + *img_fmt = AOM_IMG_FMT_I42016; + *flags |= AOM_CODEC_USE_HIGHBITDEPTH; + return 0; + } + break; + case AV_PIX_FMT_YUV422P10: + case AV_PIX_FMT_YUV422P12: + if (codec_caps & AOM_CODEC_CAP_HIGHBITDEPTH) { + enccfg->g_bit_depth = enccfg->g_input_bit_depth = + avctx->pix_fmt == AV_PIX_FMT_YUV422P10 ? 10 : 12; + enccfg->g_profile = FF_PROFILE_AV1_PROFESSIONAL; + *img_fmt = AOM_IMG_FMT_I42216; + *flags |= AOM_CODEC_USE_HIGHBITDEPTH; + return 0; + } + break; + case AV_PIX_FMT_YUV444P10: + case AV_PIX_FMT_YUV444P12: + if (codec_caps & AOM_CODEC_CAP_HIGHBITDEPTH) { + enccfg->g_bit_depth = enccfg->g_input_bit_depth = + avctx->pix_fmt == AV_PIX_FMT_YUV444P10 ? 10 : 12; + enccfg->g_profile = + enccfg->g_bit_depth == 10 ? FF_PROFILE_AV1_HIGH : FF_PROFILE_AV1_PROFESSIONAL; + *img_fmt = AOM_IMG_FMT_I44416; + *flags |= AOM_CODEC_USE_HIGHBITDEPTH; + return 0; + } + break; + default: + break; + } + av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format.\n"); + return AVERROR_INVALIDDATA; +} + +static void set_color_range(AVCodecContext *avctx) +{ + enum aom_color_range aom_cr; + switch (avctx->color_range) { + case AVCOL_RANGE_UNSPECIFIED: + case AVCOL_RANGE_MPEG: aom_cr = AOM_CR_STUDIO_RANGE; break; + case AVCOL_RANGE_JPEG: aom_cr = AOM_CR_FULL_RANGE; break; + default: + av_log(avctx, AV_LOG_WARNING, "Unsupported color range (%d)\n", + avctx->color_range); + return; + } + + codecctl_int(avctx, AV1E_SET_COLOR_RANGE, aom_cr); +} + +static av_cold int aom_init(AVCodecContext *avctx, + const struct aom_codec_iface *iface) +{ + AOMContext *ctx = avctx->priv_data; + struct aom_codec_enc_cfg enccfg = { 0 }; + aom_codec_flags_t flags = 0; + AVCPBProperties *cpb_props; + int res; + aom_img_fmt_t img_fmt; + aom_codec_caps_t codec_caps = aom_codec_get_caps(iface); + + av_log(avctx, AV_LOG_INFO, "%s\n", aom_codec_version_str()); + av_log(avctx, AV_LOG_VERBOSE, "%s\n", aom_codec_build_config()); + + if ((res = aom_codec_enc_config_default(iface, &enccfg, 0)) != AOM_CODEC_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to get config: %s\n", + aom_codec_err_to_string(res)); + return AVERROR(EINVAL); + } + + if (set_pix_fmt(avctx, codec_caps, &enccfg, &flags, &img_fmt)) + return AVERROR(EINVAL); + + if(!avctx->bit_rate) + if(avctx->rc_max_rate || avctx->rc_buffer_size || avctx->rc_initial_buffer_occupancy) { + av_log( avctx, AV_LOG_ERROR, "Rate control parameters set without a bitrate\n"); + return AVERROR(EINVAL); + } + + dump_enc_cfg(avctx, &enccfg); + + enccfg.g_w = avctx->width; + enccfg.g_h = avctx->height; + enccfg.g_timebase.num = avctx->time_base.num; + enccfg.g_timebase.den = avctx->time_base.den; + enccfg.g_threads = avctx->thread_count; + + if (ctx->lag_in_frames >= 0) + enccfg.g_lag_in_frames = ctx->lag_in_frames; + + if (avctx->flags & AV_CODEC_FLAG_PASS1) + enccfg.g_pass = AOM_RC_FIRST_PASS; + else if (avctx->flags & AV_CODEC_FLAG_PASS2) + enccfg.g_pass = AOM_RC_LAST_PASS; + else + enccfg.g_pass = AOM_RC_ONE_PASS; + + if (avctx->rc_min_rate == avctx->rc_max_rate && + avctx->rc_min_rate == avctx->bit_rate && avctx->bit_rate) { + enccfg.rc_end_usage = AOM_CBR; + } else if (ctx->crf >= 0) { + enccfg.rc_end_usage = AOM_CQ; + if (!avctx->bit_rate) + enccfg.rc_end_usage = AOM_Q; + } + + if (avctx->bit_rate) { + enccfg.rc_target_bitrate = av_rescale_rnd(avctx->bit_rate, 1, 1000, + AV_ROUND_NEAR_INF); + } else if (enccfg.rc_end_usage != AOM_Q) { + if (enccfg.rc_end_usage == AOM_CQ) { + enccfg.rc_target_bitrate = 1000000; + } else { + avctx->bit_rate = enccfg.rc_target_bitrate * 1000; + av_log(avctx, AV_LOG_WARNING, + "Neither bitrate nor constrained quality specified, using default bitrate of %dkbit/sec\n", + enccfg.rc_target_bitrate); + } + } + + if (avctx->qmin >= 0) + enccfg.rc_min_quantizer = avctx->qmin; + if (avctx->qmax >= 0) + enccfg.rc_max_quantizer = avctx->qmax; + + if (enccfg.rc_end_usage == AOM_CQ || enccfg.rc_end_usage == AOM_Q) { + if (ctx->crf < enccfg.rc_min_quantizer || ctx->crf > enccfg.rc_max_quantizer) { + av_log(avctx, AV_LOG_ERROR, + "CQ level %d must be between minimum and maximum quantizer value (%d-%d)\n", + ctx->crf, enccfg.rc_min_quantizer, enccfg.rc_max_quantizer); + return AVERROR(EINVAL); + } + } + + enccfg.rc_dropframe_thresh = ctx->drop_threshold; + + // 0-100 (0 => CBR, 100 => VBR) + enccfg.rc_2pass_vbr_bias_pct = round(avctx->qcompress * 100); + if (avctx->bit_rate) + enccfg.rc_2pass_vbr_minsection_pct = + avctx->rc_min_rate * 100LL / avctx->bit_rate; + if (avctx->rc_max_rate) + enccfg.rc_2pass_vbr_maxsection_pct = + avctx->rc_max_rate * 100LL / avctx->bit_rate; + + if (avctx->rc_buffer_size) + enccfg.rc_buf_sz = + avctx->rc_buffer_size * 1000LL / avctx->bit_rate; + if (avctx->rc_initial_buffer_occupancy) + enccfg.rc_buf_initial_sz = + avctx->rc_initial_buffer_occupancy * 1000LL / avctx->bit_rate; + enccfg.rc_buf_optimal_sz = enccfg.rc_buf_sz * 5 / 6; + + // _enc_init() will balk if kf_min_dist differs from max w/AOM_KF_AUTO + if (avctx->keyint_min >= 0 && avctx->keyint_min == avctx->gop_size) + enccfg.kf_min_dist = avctx->keyint_min; + if (avctx->gop_size >= 0) + enccfg.kf_max_dist = avctx->gop_size; + + if (enccfg.g_pass == AOM_RC_FIRST_PASS) + enccfg.g_lag_in_frames = 0; + else if (enccfg.g_pass == AOM_RC_LAST_PASS) { + int decode_size, ret; + + if (!avctx->stats_in) { + av_log(avctx, AV_LOG_ERROR, "No stats file for second pass\n"); + return AVERROR_INVALIDDATA; + } + + ctx->twopass_stats.sz = strlen(avctx->stats_in) * 3 / 4; + ret = av_reallocp(&ctx->twopass_stats.buf, ctx->twopass_stats.sz); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, + "Stat buffer alloc (%"SIZE_SPECIFIER" bytes) failed\n", + ctx->twopass_stats.sz); + ctx->twopass_stats.sz = 0; + return ret; + } + decode_size = av_base64_decode(ctx->twopass_stats.buf, avctx->stats_in, + ctx->twopass_stats.sz); + if (decode_size < 0) { + av_log(avctx, AV_LOG_ERROR, "Stat buffer decode failed\n"); + return AVERROR_INVALIDDATA; + } + + ctx->twopass_stats.sz = decode_size; + enccfg.rc_twopass_stats_in = ctx->twopass_stats; + } + + /* 0-3: For non-zero values the encoder increasingly optimizes for reduced + * complexity playback on low powered devices at the expense of encode + * quality. */ + if (avctx->profile != FF_PROFILE_UNKNOWN) + enccfg.g_profile = avctx->profile; + + enccfg.g_error_resilient = ctx->error_resilient; + + dump_enc_cfg(avctx, &enccfg); + /* Construct Encoder Context */ + res = aom_codec_enc_init(&ctx->encoder, iface, &enccfg, flags); + if (res != AOM_CODEC_OK) { + log_encoder_error(avctx, "Failed to initialize encoder"); + return AVERROR(EINVAL); + } + + // codec control failures are currently treated only as warnings + av_log(avctx, AV_LOG_DEBUG, "aom_codec_control\n"); + codecctl_int(avctx, AOME_SET_CPUUSED, ctx->cpu_used); + if (ctx->auto_alt_ref >= 0) + codecctl_int(avctx, AOME_SET_ENABLEAUTOALTREF, ctx->auto_alt_ref); + + codecctl_int(avctx, AOME_SET_STATIC_THRESHOLD, ctx->static_thresh); + if (ctx->crf >= 0) + codecctl_int(avctx, AOME_SET_CQ_LEVEL, ctx->crf); + + codecctl_int(avctx, AV1E_SET_COLOR_PRIMARIES, avctx->color_primaries); + codecctl_int(avctx, AV1E_SET_MATRIX_COEFFICIENTS, avctx->colorspace); + codecctl_int(avctx, AV1E_SET_TRANSFER_CHARACTERISTICS, avctx->color_trc); + set_color_range(avctx); + + // provide dummy value to initialize wrapper, values will be updated each _encode() + aom_img_wrap(&ctx->rawimg, img_fmt, avctx->width, avctx->height, 1, + (unsigned char*)1); + + if (codec_caps & AOM_CODEC_CAP_HIGHBITDEPTH) + ctx->rawimg.bit_depth = enccfg.g_bit_depth; + + cpb_props = ff_add_cpb_side_data(avctx); + if (!cpb_props) + return AVERROR(ENOMEM); + + if (enccfg.rc_end_usage == AOM_CBR || + enccfg.g_pass != AOM_RC_ONE_PASS) { + cpb_props->max_bitrate = avctx->rc_max_rate; + cpb_props->min_bitrate = avctx->rc_min_rate; + cpb_props->avg_bitrate = avctx->bit_rate; + } + cpb_props->buffer_size = avctx->rc_buffer_size; + + return 0; +} + +static inline void cx_pktcpy(struct FrameListData *dst, + const struct aom_codec_cx_pkt *src) +{ + dst->pts = src->data.frame.pts; + dst->duration = src->data.frame.duration; + dst->flags = src->data.frame.flags; + dst->sz = src->data.frame.sz; + dst->buf = src->data.frame.buf; +} + +/** + * Store coded frame information in format suitable for return from encode2(). + * + * Write information from @a cx_frame to @a pkt + * @return packet data size on success + * @return a negative AVERROR on error + */ +static int storeframe(AVCodecContext *avctx, struct FrameListData *cx_frame, + AVPacket *pkt) +{ + int ret = ff_alloc_packet2(avctx, pkt, cx_frame->sz, 0); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, + "Error getting output packet of size %"SIZE_SPECIFIER".\n", cx_frame->sz); + return ret; + } + memcpy(pkt->data, cx_frame->buf, pkt->size); + pkt->pts = pkt->dts = cx_frame->pts; + + if (!!(cx_frame->flags & AOM_FRAME_IS_KEY)) + pkt->flags |= AV_PKT_FLAG_KEY; + return pkt->size; +} + +/** + * Queue multiple output frames from the encoder, returning the front-most. + * In cases where aom_codec_get_cx_data() returns more than 1 frame append + * the frame queue. Return the head frame if available. + * @return Stored frame size + * @return AVERROR(EINVAL) on output size error + * @return AVERROR(ENOMEM) on coded frame queue data allocation error + */ +static int queue_frames(AVCodecContext *avctx, AVPacket *pkt_out) +{ + AOMContext *ctx = avctx->priv_data; + const struct aom_codec_cx_pkt *pkt; + const void *iter = NULL; + int size = 0; + + if (ctx->coded_frame_list) { + struct FrameListData *cx_frame = ctx->coded_frame_list; + /* return the leading frame if we've already begun queueing */ + size = storeframe(avctx, cx_frame, pkt_out); + if (size < 0) + return size; + ctx->coded_frame_list = cx_frame->next; + free_coded_frame(cx_frame); + } + + /* consume all available output from the encoder before returning. buffers + * are only good through the next aom_codec call */ + while ((pkt = aom_codec_get_cx_data(&ctx->encoder, &iter))) { + switch (pkt->kind) { + case AOM_CODEC_CX_FRAME_PKT: + if (!size) { + struct FrameListData cx_frame; + + /* avoid storing the frame when the list is empty and we haven't yet + * provided a frame for output */ + av_assert0(!ctx->coded_frame_list); + cx_pktcpy(&cx_frame, pkt); + size = storeframe(avctx, &cx_frame, pkt_out); + if (size < 0) + return size; + } else { + struct FrameListData *cx_frame = + av_malloc(sizeof(struct FrameListData)); + + if (!cx_frame) { + av_log(avctx, AV_LOG_ERROR, + "Frame queue element alloc failed\n"); + return AVERROR(ENOMEM); + } + cx_pktcpy(cx_frame, pkt); + cx_frame->buf = av_malloc(cx_frame->sz); + + if (!cx_frame->buf) { + av_log(avctx, AV_LOG_ERROR, + "Data buffer alloc (%"SIZE_SPECIFIER" bytes) failed\n", + cx_frame->sz); + av_freep(&cx_frame); + return AVERROR(ENOMEM); + } + memcpy(cx_frame->buf, pkt->data.frame.buf, pkt->data.frame.sz); + coded_frame_add(&ctx->coded_frame_list, cx_frame); + } + break; + case AOM_CODEC_STATS_PKT: + { + struct aom_fixed_buf *stats = &ctx->twopass_stats; + int err; + if ((err = av_reallocp(&stats->buf, + stats->sz + + pkt->data.twopass_stats.sz)) < 0) { + stats->sz = 0; + av_log(avctx, AV_LOG_ERROR, "Stat buffer realloc failed\n"); + return err; + } + memcpy((uint8_t *)stats->buf + stats->sz, + pkt->data.twopass_stats.buf, pkt->data.twopass_stats.sz); + stats->sz += pkt->data.twopass_stats.sz; + break; + } + case AOM_CODEC_PSNR_PKT: // FIXME add support for AV_CODEC_FLAG_PSNR + case AOM_CODEC_CUSTOM_PKT: + // ignore unsupported/unrecognized packet types + break; + } + } + + return size; +} + +static int aom_encode(AVCodecContext *avctx, AVPacket *pkt, + const AVFrame *frame, int *got_packet) +{ + AOMContext *ctx = avctx->priv_data; + struct aom_image *rawimg = NULL; + int64_t timestamp = 0; + int res, coded_size; + aom_enc_frame_flags_t flags = 0; + + if (frame) { + rawimg = &ctx->rawimg; + rawimg->planes[AOM_PLANE_Y] = frame->data[0]; + rawimg->planes[AOM_PLANE_U] = frame->data[1]; + rawimg->planes[AOM_PLANE_V] = frame->data[2]; + rawimg->stride[AOM_PLANE_Y] = frame->linesize[0]; + rawimg->stride[AOM_PLANE_U] = frame->linesize[1]; + rawimg->stride[AOM_PLANE_V] = frame->linesize[2]; + timestamp = frame->pts; + switch (frame->color_range) { + case AVCOL_RANGE_MPEG: + rawimg->range = AOM_CR_STUDIO_RANGE; + break; + case AVCOL_RANGE_JPEG: + rawimg->range = AOM_CR_FULL_RANGE; + break; + } + + if (frame->pict_type == AV_PICTURE_TYPE_I) + flags |= AOM_EFLAG_FORCE_KF; + } + + res = aom_codec_encode(&ctx->encoder, rawimg, timestamp, + avctx->ticks_per_frame, flags); + if (res != AOM_CODEC_OK) { + log_encoder_error(avctx, "Error encoding frame"); + return AVERROR_INVALIDDATA; + } + coded_size = queue_frames(avctx, pkt); + + if (!frame && avctx->flags & AV_CODEC_FLAG_PASS1) { + size_t b64_size = AV_BASE64_SIZE(ctx->twopass_stats.sz); + + avctx->stats_out = av_malloc(b64_size); + if (!avctx->stats_out) { + av_log(avctx, AV_LOG_ERROR, "Stat buffer alloc (%"SIZE_SPECIFIER" bytes) failed\n", + b64_size); + return AVERROR(ENOMEM); + } + av_base64_encode(avctx->stats_out, b64_size, ctx->twopass_stats.buf, + ctx->twopass_stats.sz); + } + + *got_packet = !!coded_size; + return 0; +} + +static const enum AVPixelFormat av1_pix_fmts[] = { + AV_PIX_FMT_YUV420P, + AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUV444P, + AV_PIX_FMT_NONE +}; + +static const enum AVPixelFormat av1_pix_fmts_highbd[] = { + AV_PIX_FMT_YUV420P, + AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUV420P10, + AV_PIX_FMT_YUV422P10, + AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_YUV420P12, + AV_PIX_FMT_YUV422P12, + AV_PIX_FMT_YUV444P12, + AV_PIX_FMT_NONE +}; + +static av_cold void av1_init_static(AVCodec *codec) +{ + aom_codec_caps_t codec_caps = aom_codec_get_caps(aom_codec_av1_cx()); + if (codec_caps & AOM_CODEC_CAP_HIGHBITDEPTH) + codec->pix_fmts = av1_pix_fmts_highbd; + else + codec->pix_fmts = av1_pix_fmts; +} + +static av_cold int av1_init(AVCodecContext *avctx) +{ + return aom_init(avctx, aom_codec_av1_cx()); +} + +#define OFFSET(x) offsetof(AOMContext, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + { "cpu-used", "Quality/Speed ratio modifier", OFFSET(cpu_used), AV_OPT_TYPE_INT, {.i64 = 1}, -8, 8, VE}, + { "auto-alt-ref", "Enable use of alternate reference " + "frames (2-pass only)", OFFSET(auto_alt_ref), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 2, VE}, + { "lag-in-frames", "Number of frames to look ahead at for " + "alternate reference frame selection", OFFSET(lag_in_frames), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, VE}, + { "error-resilience", "Error resilience configuration", OFFSET(error_resilient), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, VE, "er"}, + { "default", "Improve resiliency against losses of whole frames", 0, AV_OPT_TYPE_CONST, {.i64 = AOM_ERROR_RESILIENT_DEFAULT}, 0, 0, VE, "er"}, + { "partitions", "The frame partitions are independently decodable " + "by the bool decoder, meaning that partitions can be decoded even " + "though earlier partitions have been lost. Note that intra predicition" + " is still done over the partition boundary.", 0, AV_OPT_TYPE_CONST, {.i64 = AOM_ERROR_RESILIENT_PARTITIONS}, 0, 0, VE, "er"}, + { "crf", "Select the quality for constant quality mode", offsetof(AOMContext, crf), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 63, VE }, + { "static-thresh", "A change threshold on blocks below which they will be skipped by the encoder", OFFSET(static_thresh), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, + { "drop-threshold", "Frame drop threshold", offsetof(AOMContext, drop_threshold), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, VE }, + { "noise-sensitivity", "Noise sensitivity", OFFSET(noise_sensitivity), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 4, VE}, + { NULL } +}; + +static const AVCodecDefault defaults[] = { + { "qmin", "-1" }, + { "qmax", "-1" }, + { "g", "-1" }, + { "keyint_min", "-1" }, + { NULL }, +}; + +static const AVClass class_aom = { + .class_name = "libaom-av1 encoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_libaom_av1_encoder = { + .name = "libaom-av1", + .long_name = NULL_IF_CONFIG_SMALL("libaom AV1"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_AV1, + .priv_data_size = sizeof(AOMContext), + .init = av1_init, + .encode2 = aom_encode, + .close = aom_free, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS | AV_CODEC_CAP_EXPERIMENTAL, + .profiles = NULL_IF_CONFIG_SMALL(ff_av1_profiles), + .priv_class = &class_aom, + .defaults = defaults, + .init_static_data = av1_init_static, + .wrapper_name = "libaom", +}; diff --git a/libavcodec/libavcodec.v b/libavcodec/libavcodec.v index 304c2ef4279af..f1d5e5bc776af 100644 --- a/libavcodec/libavcodec.v +++ b/libavcodec/libavcodec.v @@ -1,9 +1,6 @@ LIBAVCODEC_MAJOR { global: av*; - #deprecated, remove after next bump - audio_resample; - audio_resample_close; local: *; }; diff --git a/libavcodec/libcelt_dec.c b/libavcodec/libcelt_dec.c index 878e4cc673cb4..75b438b285519 100644 --- a/libavcodec/libcelt_dec.c +++ b/libavcodec/libcelt_dec.c @@ -137,4 +137,5 @@ AVCodec ff_libcelt_decoder = { .close = libcelt_dec_close, .decode = libcelt_dec_decode, .capabilities = AV_CODEC_CAP_DR1, + .wrapper_name = "libcelt", }; diff --git a/libavcodec/libcodec2.c b/libavcodec/libcodec2.c new file mode 100644 index 0000000000000..1d6bed03833ea --- /dev/null +++ b/libavcodec/libcodec2.c @@ -0,0 +1,213 @@ +/* + * codec2 encoder/decoder using libcodec2 + * Copyright (c) 2017 Tomas Härdin + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "avcodec.h" +#include "libavutil/opt.h" +#include "internal.h" +#include "codec2utils.h" + +typedef struct { + const AVClass *class; + struct CODEC2 *codec; + int mode; +} LibCodec2Context; + +static const AVOption options[] = { + //not AV_OPT_FLAG_DECODING_PARAM since mode should come from the demuxer + //1300 (aka FreeDV 1600) is the most common mode on-the-air, default to it here as well + AVPRIV_CODEC2_AVOPTIONS("codec2 mode", LibCodec2Context, 0, 4 /*CODEC2_MODE_1300*/, AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_ENCODING_PARAM), + { NULL }, +}; + +static const AVClass libcodec2_enc_class = { + .class_name = "libcodec2 encoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const AVClass libcodec2_dec_class = { + .class_name = "libcodec2 decoder", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, +}; + +static av_cold int libcodec2_init_common(AVCodecContext *avctx, int mode) +{ + LibCodec2Context *c2 = avctx->priv_data; + //Grab mode name from options, unless it's some weird number. + const char *modename = mode >= 0 && mode <= AVPRIV_CODEC2_MODE_MAX ? options[mode+1].name : "?"; + + c2->codec = codec2_create(mode); + if (!c2->codec) { + //Out of memory or unsupported mode. The latter seems most likely, + //but we can't tell for sure with the current API. + goto libcodec2_init_common_error; + } + + avctx->frame_size = codec2_samples_per_frame(c2->codec); + avctx->block_align = (codec2_bits_per_frame(c2->codec) + 7) / 8; + + if (avctx->frame_size <= 0 || avctx->block_align <= 0) { + //codec2_create() may succeed for some modes but still fail at codec2_samples_per_frame() + //example is -mode 700C on libcodec2 0.4 + codec2_destroy(c2->codec); + c2->codec = NULL; + goto libcodec2_init_common_error; + } + + codec2_set_natural_or_gray(c2->codec, 1); + + return 0; + +libcodec2_init_common_error: + av_log(avctx, AV_LOG_ERROR, + "Mode %i (%s) not supported with the linked version of libcodec2\n", + mode, modename); + return AVERROR(EINVAL); +} + +static av_cold int libcodec2_init_decoder(AVCodecContext *avctx) +{ + avctx->sample_rate = 8000; + avctx->channels = 1; + avctx->sample_fmt = AV_SAMPLE_FMT_S16; + avctx->channel_layout = AV_CH_LAYOUT_MONO; + + if (avctx->extradata_size != AVPRIV_CODEC2_EXTRADATA_SIZE) { + av_log(avctx, AV_LOG_ERROR, "must have exactly %i bytes of extradata (got %i)\n", + AVPRIV_CODEC2_EXTRADATA_SIZE, avctx->extradata_size); + return AVERROR_INVALIDDATA; + } + + return libcodec2_init_common(avctx, avpriv_codec2_mode_from_extradata(avctx->extradata)); +} + +static av_cold int libcodec2_init_encoder(AVCodecContext *avctx) +{ + LibCodec2Context *c2 = avctx->priv_data; + + //will need to be smarter once we get wideband support + if (avctx->sample_rate != 8000 || + avctx->channels != 1 || + avctx->sample_fmt != AV_SAMPLE_FMT_S16) { + av_log(avctx, AV_LOG_ERROR, "only 8 kHz 16-bit mono allowed\n"); + return AVERROR(EINVAL); + } + + avctx->extradata = av_mallocz(AVPRIV_CODEC2_EXTRADATA_SIZE + AV_INPUT_BUFFER_PADDING_SIZE); + if (!avctx->extradata) { + return AVERROR(ENOMEM); + } + + avctx->extradata_size = AVPRIV_CODEC2_EXTRADATA_SIZE; + avpriv_codec2_make_extradata(avctx->extradata, c2->mode); + + return libcodec2_init_common(avctx, c2->mode); +} + +static av_cold int libcodec2_close(AVCodecContext *avctx) +{ + LibCodec2Context *c2 = avctx->priv_data; + + codec2_destroy(c2->codec); + return 0; +} + +static int libcodec2_decode(AVCodecContext *avctx, void *data, + int *got_frame_ptr, AVPacket *pkt) +{ + LibCodec2Context *c2 = avctx->priv_data; + AVFrame *frame = data; + int ret, nframes, i; + uint8_t *input; + int16_t *output; + + nframes = pkt->size / avctx->block_align; + frame->nb_samples = avctx->frame_size * nframes; + + ret = ff_get_buffer(avctx, frame, 0); + if (ret < 0) { + return ret; + } + + input = pkt->data; + output = (int16_t *)frame->data[0]; + + for (i = 0; i < nframes; i++) { + codec2_decode(c2->codec, output, input); + input += avctx->block_align; + output += avctx->frame_size; + } + + *got_frame_ptr = nframes > 0; + return nframes * avctx->block_align; +} + +static int libcodec2_encode(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr) +{ + LibCodec2Context *c2 = avctx->priv_data; + int16_t *samples = (int16_t *)frame->data[0]; + + int ret = ff_alloc_packet2(avctx, avpkt, avctx->block_align, 0); + if (ret < 0) { + return ret; + } + + codec2_encode(c2->codec, avpkt->data, samples); + *got_packet_ptr = 1; + + return 0; +} + +AVCodec ff_libcodec2_decoder = { + .name = "libcodec2", + .long_name = NULL_IF_CONFIG_SMALL("codec2 decoder using libcodec2"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_CODEC2, + .priv_data_size = sizeof(LibCodec2Context), + .init = libcodec2_init_decoder, + .close = libcodec2_close, + .decode = libcodec2_decode, + .capabilities = 0, + .supported_samplerates = (const int[]){ 8000, 0 }, + .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, + .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_MONO, 0 }, + .priv_class = &libcodec2_dec_class, +}; + +AVCodec ff_libcodec2_encoder = { + .name = "libcodec2", + .long_name = NULL_IF_CONFIG_SMALL("codec2 encoder using libcodec2"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_CODEC2, + .priv_data_size = sizeof(LibCodec2Context), + .init = libcodec2_init_encoder, + .close = libcodec2_close, + .encode2 = libcodec2_encode, + .capabilities = 0, + .supported_samplerates = (const int[]){ 8000, 0 }, + .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, + .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_MONO, 0 }, + .priv_class = &libcodec2_enc_class, +}; diff --git a/libavcodec/libfdk-aacdec.c b/libavcodec/libfdk-aacdec.c index 2857b9453f97a..677b11088b16c 100644 --- a/libavcodec/libfdk-aacdec.c +++ b/libavcodec/libfdk-aacdec.c @@ -79,7 +79,10 @@ static const AVOption fdk_aac_dec_options[] = { }; static const AVClass fdk_aac_dec_class = { - "libfdk-aac decoder", av_default_item_name, fdk_aac_dec_options, LIBAVUTIL_VERSION_INT + .class_name = "libfdk-aac decoder", + .item_name = av_default_item_name, + .option = fdk_aac_dec_options, + .version = LIBAVUTIL_VERSION_INT, }; static int get_stream_info(AVCodecContext *avctx) @@ -382,4 +385,5 @@ AVCodec ff_libfdk_aac_decoder = { .priv_class = &fdk_aac_dec_class, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, + .wrapper_name = "libfdk", }; diff --git a/libavcodec/libfdk-aacenc.c b/libavcodec/libfdk-aacenc.c index 0e2051b468aac..d47137b227a6d 100644 --- a/libavcodec/libfdk-aacenc.c +++ b/libavcodec/libfdk-aacenc.c @@ -54,7 +54,10 @@ static const AVOption aac_enc_options[] = { }; static const AVClass aac_enc_class = { - "libfdk_aac", av_default_item_name, aac_enc_options, LIBAVUTIL_VERSION_INT + .class_name = "libfdk_aac", + .item_name = av_default_item_name, + .option = aac_enc_options, + .version = LIBAVUTIL_VERSION_INT, }; static const char *aac_get_error(AACENC_ERROR err) @@ -425,4 +428,5 @@ AVCodec ff_libfdk_aac_encoder = { .profiles = profiles, .supported_samplerates = aac_sample_rates, .channel_layouts = aac_channel_layout, + .wrapper_name = "libfdk", }; diff --git a/libavcodec/libgsmdec.c b/libavcodec/libgsmdec.c index a503215f679b0..89e1de0fed763 100644 --- a/libavcodec/libgsmdec.c +++ b/libavcodec/libgsmdec.c @@ -135,6 +135,7 @@ AVCodec ff_libgsm_decoder = { .decode = libgsm_decode_frame, .flush = libgsm_flush, .capabilities = AV_CODEC_CAP_DR1, + .wrapper_name = "libgsm", }; #endif #if CONFIG_LIBGSM_MS_DECODER @@ -149,5 +150,6 @@ AVCodec ff_libgsm_ms_decoder = { .decode = libgsm_decode_frame, .flush = libgsm_flush, .capabilities = AV_CODEC_CAP_DR1, + .wrapper_name = "libgsm", }; #endif diff --git a/libavcodec/libgsmenc.c b/libavcodec/libgsmenc.c index e25db95181009..c9e7ba056e1e4 100644 --- a/libavcodec/libgsmenc.c +++ b/libavcodec/libgsmenc.c @@ -126,6 +126,7 @@ AVCodec ff_libgsm_encoder = { .close = libgsm_encode_close, .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, + .wrapper_name = "libgsm", }; #endif #if CONFIG_LIBGSM_MS_ENCODER @@ -139,5 +140,6 @@ AVCodec ff_libgsm_ms_encoder = { .close = libgsm_encode_close, .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, + .wrapper_name = "libgsm", }; #endif diff --git a/libavcodec/libilbc.c b/libavcodec/libilbc.c index c4c054fa5d4f2..9a56cc8785476 100644 --- a/libavcodec/libilbc.c +++ b/libavcodec/libilbc.c @@ -193,4 +193,5 @@ AVCodec ff_libilbc_encoder = { AV_SAMPLE_FMT_NONE }, .defaults = ilbc_encode_defaults, .priv_class = &ilbc_enc_class, + .wrapper_name = "libbilbc", }; diff --git a/libavcodec/libkvazaar.c b/libavcodec/libkvazaar.c index f35b0df61d5e3..41a1bbb45e70a 100644 --- a/libavcodec/libkvazaar.c +++ b/libavcodec/libkvazaar.c @@ -231,7 +231,7 @@ static int libkvazaar_encode(AVCodecContext *avctx, kvz_data_chunk *chunk = NULL; uint64_t written = 0; - retval = ff_alloc_packet(avpkt, len_out); + retval = ff_alloc_packet2(avctx, avpkt, len_out, len_out); if (retval < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to allocate output packet.\n"); goto done; @@ -305,4 +305,6 @@ AVCodec ff_libkvazaar_encoder = { .close = libkvazaar_close, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, + + .wrapper_name = "libkvazaar", }; diff --git a/libavcodec/libmp3lame.c b/libavcodec/libmp3lame.c index 5e26743f297db..ecdd2e334c6d4 100644 --- a/libavcodec/libmp3lame.c +++ b/libavcodec/libmp3lame.c @@ -349,4 +349,5 @@ AVCodec ff_libmp3lame_encoder = { 0 }, .priv_class = &libmp3lame_class, .defaults = libmp3lame_defaults, + .wrapper_name = "libmp3lame", }; diff --git a/libavcodec/libopencore-amr.c b/libavcodec/libopencore-amr.c index 8545ffe1096f4..516f625720ff1 100644 --- a/libavcodec/libopencore-amr.c +++ b/libavcodec/libopencore-amr.c @@ -183,7 +183,10 @@ static const AVOption options[] = { }; static const AVClass amrnb_class = { - "libopencore_amrnb", av_default_item_name, options, LIBAVUTIL_VERSION_INT + .class_name = "libopencore_amrnb", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, }; static av_cold int amr_nb_encode_init(AVCodecContext *avctx) @@ -375,6 +378,7 @@ AVCodec ff_libopencore_amrwb_decoder = { .close = amr_wb_decode_close, .decode = amr_wb_decode_frame, .capabilities = AV_CODEC_CAP_DR1, + .wrapper_name = "libopencore_amrwb", }; #endif /* CONFIG_LIBOPENCORE_AMRWB_DECODER */ diff --git a/libavcodec/libopenh264dec.c b/libavcodec/libopenh264dec.c index d12e7151172a0..b7ed85d17596b 100644 --- a/libavcodec/libopenh264dec.c +++ b/libavcodec/libopenh264dec.c @@ -147,4 +147,5 @@ AVCodec ff_libopenh264_decoder = { .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS | FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, .bsfs = "h264_mp4toannexb", + .wrapper_name = "libopenh264", }; diff --git a/libavcodec/libopenh264enc.c b/libavcodec/libopenh264enc.c index 9c22bf4f30cf1..83c3f0ce208cb 100644 --- a/libavcodec/libopenh264enc.c +++ b/libavcodec/libopenh264enc.c @@ -75,7 +75,10 @@ static const AVOption options[] = { }; static const AVClass class = { - "libopenh264enc", av_default_item_name, options, LIBAVUTIL_VERSION_INT + .class_name = "libvo_amrwbenc", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, }; static av_cold int svc_encode_close(AVCodecContext *avctx) @@ -243,6 +246,10 @@ static int svc_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, sp.iPicWidth = avctx->width; sp.iPicHeight = avctx->height; + if (frame->pict_type == AV_PICTURE_TYPE_I) { + (*s->encoder)->ForceIntraFrame(s->encoder, true); + } + encoded = (*s->encoder)->EncodeFrame(s->encoder, &sp, &fbi); if (encoded != cmResultSuccess) { av_log(avctx, AV_LOG_ERROR, "EncodeFrame failed\n"); @@ -298,4 +305,5 @@ AVCodec ff_libopenh264_encoder = { .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, .priv_class = &class, + .wrapper_name = "libopenh264", }; diff --git a/libavcodec/libopenjpegdec.c b/libavcodec/libopenjpegdec.c index 67d47bd6a0aa1..5e66cd99cc3c7 100644 --- a/libavcodec/libopenjpegdec.c +++ b/libavcodec/libopenjpegdec.c @@ -34,27 +34,7 @@ #include "internal.h" #include "thread.h" -#if HAVE_OPENJPEG_2_3_OPENJPEG_H -# include -#elif HAVE_OPENJPEG_2_2_OPENJPEG_H -# include -#elif HAVE_OPENJPEG_2_1_OPENJPEG_H -# include -#elif HAVE_OPENJPEG_2_0_OPENJPEG_H -# include -#elif HAVE_OPENJPEG_1_5_OPENJPEG_H -# include -#else -# include -#endif - -#if HAVE_OPENJPEG_2_3_OPENJPEG_H || HAVE_OPENJPEG_2_2_OPENJPEG_H || HAVE_OPENJPEG_2_1_OPENJPEG_H || HAVE_OPENJPEG_2_0_OPENJPEG_H -# define OPENJPEG_MAJOR_VERSION 2 -# define OPJ(x) OPJ_##x -#else -# define OPENJPEG_MAJOR_VERSION 1 -# define OPJ(x) x -#endif +#include #define JP2_SIG_TYPE 0x6A502020 #define JP2_SIG_VALUE 0x0D0A870A @@ -97,9 +77,6 @@ static const enum AVPixelFormat libopenjpeg_all_pix_fmts[] = { typedef struct LibOpenJPEGContext { AVClass *class; opj_dparameters_t dec_params; -#if OPENJPEG_MAJOR_VERSION == 1 - opj_event_mgr_t event_mgr; -#endif // OPENJPEG_MAJOR_VERSION == 1 int lowqual; } LibOpenJPEGContext; @@ -118,7 +95,6 @@ static void info_callback(const char *msg, void *data) av_log(data, AV_LOG_DEBUG, "%s", msg); } -#if OPENJPEG_MAJOR_VERSION == 2 typedef struct BufferReader { int pos; int size; @@ -176,7 +152,6 @@ static OPJ_BOOL stream_seek(OPJ_OFF_T nb_bytes, void *user_data) reader->pos = (int)nb_bytes; return OPJ_TRUE; } -#endif // OPENJPEG_MAJOR_VERSION == 2 static inline int libopenjpeg_matches_pix_fmt(const opj_image_t *image, enum AVPixelFormat pix_fmt) { @@ -221,15 +196,15 @@ static inline enum AVPixelFormat libopenjpeg_guess_pix_fmt(const opj_image_t *im int possible_fmts_nb = 0; switch (image->color_space) { - case OPJ(CLRSPC_SRGB): + case OPJ_CLRSPC_SRGB: possible_fmts = libopenjpeg_rgb_pix_fmts; possible_fmts_nb = FF_ARRAY_ELEMS(libopenjpeg_rgb_pix_fmts); break; - case OPJ(CLRSPC_GRAY): + case OPJ_CLRSPC_GRAY: possible_fmts = libopenjpeg_gray_pix_fmts; possible_fmts_nb = FF_ARRAY_ELEMS(libopenjpeg_gray_pix_fmts); break; - case OPJ(CLRSPC_SYCC): + case OPJ_CLRSPC_SYCC: possible_fmts = libopenjpeg_yuv_pix_fmts; possible_fmts_nb = FF_ARRAY_ELEMS(libopenjpeg_yuv_pix_fmts); break; @@ -356,14 +331,9 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, int ispacked = 0; int i; opj_image_t *image = NULL; -#if OPENJPEG_MAJOR_VERSION == 1 - opj_dinfo_t *dec = NULL; - opj_cio_t *stream = NULL; -#else // OPENJPEG_MAJOR_VERSION == 2 BufferReader reader = {0, avpkt->size, avpkt->data}; opj_codec_t *dec = NULL; opj_stream_t *stream = NULL; -#endif // OPENJPEG_MAJOR_VERSION == 1 *got_frame = 0; @@ -371,13 +341,13 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, if ((AV_RB32(buf) == 12) && (AV_RB32(buf + 4) == JP2_SIG_TYPE) && (AV_RB32(buf + 8) == JP2_SIG_VALUE)) { - dec = opj_create_decompress(OPJ(CODEC_JP2)); + dec = opj_create_decompress(OPJ_CODEC_JP2); } else { /* If the AVPacket contains a jp2c box, then skip to * the starting byte of the codestream. */ if (AV_RB32(buf + 4) == AV_RB32("jp2c")) buf += 8; - dec = opj_create_decompress(OPJ(CODEC_J2K)); + dec = opj_create_decompress(OPJ_CODEC_J2K); } if (!dec) { @@ -386,15 +356,6 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, goto done; } -#if OPENJPEG_MAJOR_VERSION == 1 - memset(&ctx->event_mgr, 0, sizeof(ctx->event_mgr)); - ctx->event_mgr.info_handler = info_callback; - ctx->event_mgr.error_handler = error_callback; - ctx->event_mgr.warning_handler = warning_callback; - opj_set_event_mgr((opj_common_ptr) dec, &ctx->event_mgr, avctx); - ctx->dec_params.cp_limit_decoding = LIMIT_TO_MAIN_HEADER; - ctx->dec_params.cp_layer = ctx->lowqual; -#else // OPENJPEG_MAJOR_VERSION == 2 if (!opj_set_error_handler(dec, error_callback, avctx) || !opj_set_warning_handler(dec, warning_callback, avctx) || !opj_set_info_handler(dec, info_callback, avctx)) { @@ -405,16 +366,11 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, ctx->dec_params.cp_layer = ctx->lowqual; ctx->dec_params.cp_reduce = avctx->lowres; -#endif // OPENJPEG_MAJOR_VERSION == 1 // Tie decoder with decoding parameters opj_setup_decoder(dec, &ctx->dec_params); -#if OPENJPEG_MAJOR_VERSION == 1 - stream = opj_cio_open((opj_common_ptr) dec, buf, buf_size); -#else // OPENJPEG_MAJOR_VERSION == 2 stream = opj_stream_default_create(OPJ_STREAM_READ); -#endif // OPENJPEG_MAJOR_VERSION == 1 if (!stream) { av_log(avctx, AV_LOG_ERROR, @@ -423,27 +379,13 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, goto done; } -#if OPENJPEG_MAJOR_VERSION == 1 - // Decode the header only. - image = opj_decode_with_info(dec, stream, NULL); - opj_cio_close(stream); - stream = NULL; - ret = !image; -#else // OPENJPEG_MAJOR_VERSION == 2 opj_stream_set_read_function(stream, stream_read); opj_stream_set_skip_function(stream, stream_skip); opj_stream_set_seek_function(stream, stream_seek); -#if HAVE_OPENJPEG_2_3_OPENJPEG_H || HAVE_OPENJPEG_2_2_OPENJPEG_H || HAVE_OPENJPEG_2_1_OPENJPEG_H opj_stream_set_user_data(stream, &reader, NULL); -#elif HAVE_OPENJPEG_2_0_OPENJPEG_H - opj_stream_set_user_data(stream, &reader); -#else -#error Missing call to opj_stream_set_user_data -#endif opj_stream_set_user_data_length(stream, avpkt->size); // Decode the header only. ret = !opj_read_header(stream, dec, &image); -#endif // OPENJPEG_MAJOR_VERSION == 1 if (ret) { av_log(avctx, AV_LOG_ERROR, "Error decoding codestream header.\n"); @@ -477,25 +419,7 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0) goto done; -#if OPENJPEG_MAJOR_VERSION == 1 - ctx->dec_params.cp_limit_decoding = NO_LIMITATION; - ctx->dec_params.cp_reduce = avctx->lowres; - // Tie decoder with decoding parameters. - opj_setup_decoder(dec, &ctx->dec_params); - stream = opj_cio_open((opj_common_ptr) dec, buf, buf_size); - if (!stream) { - av_log(avctx, AV_LOG_ERROR, - "Codestream could not be opened for reading.\n"); - ret = AVERROR_EXTERNAL; - goto done; - } - opj_image_destroy(image); - // Decode the codestream - image = opj_decode_with_info(dec, stream, NULL); - ret = !image; -#else // OPENJPEG_MAJOR_VERSION == 2 ret = !opj_decode(dec, stream, image); -#endif // OPENJPEG_MAJOR_VERSION == 1 if (ret) { av_log(avctx, AV_LOG_ERROR, "Error decoding codestream.\n"); @@ -556,25 +480,11 @@ static int libopenjpeg_decode_frame(AVCodecContext *avctx, done: opj_image_destroy(image); -#if OPENJPEG_MAJOR_VERSION == 2 opj_stream_destroy(stream); opj_destroy_codec(dec); -#else - opj_cio_close(stream); - opj_destroy_decompress(dec); -#endif return ret; } -static av_cold void libopenjpeg_static_init(AVCodec *codec) -{ - const char *version = opj_version(); - int major, minor; - - if (sscanf(version, "%d.%d", &major, &minor) == 2 && 1000*major + minor <= 1003) - codec->capabilities |= AV_CODEC_CAP_EXPERIMENTAL; -} - #define OFFSET(x) offsetof(LibOpenJPEGContext, x) #define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM @@ -602,5 +512,5 @@ AVCodec ff_libopenjpeg_decoder = { .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS, .max_lowres = 31, .priv_class = &openjpeg_class, - .init_static_data = libopenjpeg_static_init, + .wrapper_name = "libopenjpeg", }; diff --git a/libavcodec/libopenjpegenc.c b/libavcodec/libopenjpegenc.c index 92b4433b04759..7c7d0aa6b2a4c 100644 --- a/libavcodec/libopenjpegenc.c +++ b/libavcodec/libopenjpegenc.c @@ -31,38 +31,11 @@ #include "libavutil/opt.h" #include "avcodec.h" #include "internal.h" - -#if HAVE_OPENJPEG_2_3_OPENJPEG_H -# include -#elif HAVE_OPENJPEG_2_2_OPENJPEG_H -# include -#elif HAVE_OPENJPEG_2_1_OPENJPEG_H -# include -#elif HAVE_OPENJPEG_2_0_OPENJPEG_H -# include -#elif HAVE_OPENJPEG_1_5_OPENJPEG_H -# include -#else -# include -#endif - -#if HAVE_OPENJPEG_2_3_OPENJPEG_H || HAVE_OPENJPEG_2_2_OPENJPEG_H || HAVE_OPENJPEG_2_1_OPENJPEG_H || HAVE_OPENJPEG_2_0_OPENJPEG_H -# define OPENJPEG_MAJOR_VERSION 2 -# define OPJ(x) OPJ_##x -#else -# define OPENJPEG_MAJOR_VERSION 1 -# define OPJ(x) x -#endif +#include typedef struct LibOpenJPEGContext { AVClass *avclass; -#if OPENJPEG_MAJOR_VERSION == 1 - opj_image_t *image; -#endif // OPENJPEG_MAJOR_VERSION == 1 opj_cparameters_t enc_params; -#if OPENJPEG_MAJOR_VERSION == 1 - opj_event_mgr_t event_mgr; -#endif // OPENJPEG_MAJOR_VERSION == 1 int format; int profile; int prog_order; @@ -88,7 +61,6 @@ static void info_callback(const char *msg, void *data) av_log(data, AV_LOG_DEBUG, "%s\n", msg); } -#if OPENJPEG_MAJOR_VERSION == 2 typedef struct PacketWriter { int pos; AVPacket *packet; @@ -158,7 +130,6 @@ static OPJ_BOOL stream_seek(OPJ_OFF_T nb_bytes, void *user_data) writer->pos = (int)nb_bytes; return OPJ_TRUE; } -#endif // OPENJPEG_MAJOR_VERSION == 2 static void cinema_parameters(opj_cparameters_t *p) { @@ -182,7 +153,7 @@ static void cinema_parameters(opj_cparameters_t *p) p->csty |= 0x01; /* The progression order shall be CPRL */ - p->prog_order = OPJ(CPRL); + p->prog_order = OPJ_CPRL; /* No ROI */ p->roi_compno = -1; @@ -206,7 +177,7 @@ static opj_image_t *mj2_create_image(AVCodecContext *avctx, opj_cparameters_t *p int sub_dx[4]; int sub_dy[4]; int numcomps; - OPJ_COLOR_SPACE color_space = OPJ(CLRSPC_UNKNOWN); + OPJ_COLOR_SPACE color_space = OPJ_CLRSPC_UNKNOWN; sub_dx[0] = sub_dx[3] = 1; sub_dy[0] = sub_dy[3] = 1; @@ -220,7 +191,7 @@ static opj_image_t *mj2_create_image(AVCodecContext *avctx, opj_cparameters_t *p case AV_PIX_FMT_YA8: case AV_PIX_FMT_GRAY16: case AV_PIX_FMT_YA16: - color_space = OPJ(CLRSPC_GRAY); + color_space = OPJ_CLRSPC_GRAY; break; case AV_PIX_FMT_RGB24: case AV_PIX_FMT_RGBA: @@ -233,7 +204,7 @@ static opj_image_t *mj2_create_image(AVCodecContext *avctx, opj_cparameters_t *p case AV_PIX_FMT_GBRP14: case AV_PIX_FMT_GBRP16: case AV_PIX_FMT_XYZ12: - color_space = OPJ(CLRSPC_SRGB); + color_space = OPJ_CLRSPC_SRGB; break; case AV_PIX_FMT_YUV410P: case AV_PIX_FMT_YUV411P: @@ -268,7 +239,7 @@ static opj_image_t *mj2_create_image(AVCodecContext *avctx, opj_cparameters_t *p case AV_PIX_FMT_YUVA420P16: case AV_PIX_FMT_YUVA422P16: case AV_PIX_FMT_YUVA444P16: - color_space = OPJ(CLRSPC_SYCC); + color_space = OPJ_CLRSPC_SYCC; break; default: av_log(avctx, AV_LOG_ERROR, @@ -309,7 +280,6 @@ static av_cold int libopenjpeg_encode_init(AVCodecContext *avctx) opj_set_default_encoder_parameters(&ctx->enc_params); -#if HAVE_OPENJPEG_2_3_OPENJPEG_H || HAVE_OPENJPEG_2_2_OPENJPEG_H || HAVE_OPENJPEG_2_1_OPENJPEG_H switch (ctx->cinema_mode) { case OPJ_CINEMA2K_24: ctx->enc_params.rsiz = OPJ_PROFILE_CINEMA_2K; @@ -348,12 +318,8 @@ static av_cold int libopenjpeg_encode_init(AVCodecContext *avctx) if (err) { av_log(avctx, AV_LOG_ERROR, "Invalid parameter pairing: cinema_mode and profile conflict.\n"); - goto fail; + return err; } -#else - ctx->enc_params.cp_rsiz = ctx->profile; - ctx->enc_params.cp_cinema = ctx->cinema_mode; -#endif if (!ctx->numresolution) { ctx->numresolution = 6; @@ -373,23 +339,7 @@ static av_cold int libopenjpeg_encode_init(AVCodecContext *avctx) cinema_parameters(&ctx->enc_params); } -#if OPENJPEG_MAJOR_VERSION == 1 - ctx->image = mj2_create_image(avctx, &ctx->enc_params); - if (!ctx->image) { - av_log(avctx, AV_LOG_ERROR, "Error creating the mj2 image\n"); - err = AVERROR(EINVAL); - goto fail; - } -#endif // OPENJPEG_MAJOR_VERSION == 1 - return 0; - -fail: -#if OPENJPEG_MAJOR_VERSION == 1 - opj_image_destroy(ctx->image); - ctx->image = NULL; -#endif // OPENJPEG_MAJOR_VERSION == 1 - return err; } static int libopenjpeg_copy_packed8(AVCodecContext *avctx, const AVFrame *frame, opj_image_t *image) @@ -602,12 +552,6 @@ static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt, int ret; AVFrame *gbrframe; int cpyresult = 0; -#if OPENJPEG_MAJOR_VERSION == 1 - opj_image_t *image = ctx->image; - opj_cinfo_t *compress = NULL; - opj_cio_t *stream = NULL; - int len; -#else // OPENJPEG_MAJOR_VERSION == 2 PacketWriter writer = { 0 }; opj_codec_t *compress = NULL; opj_stream_t *stream = NULL; @@ -617,7 +561,6 @@ static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt, ret = AVERROR(EINVAL); goto done; } -#endif // OPENJPEG_MAJOR_VERSION == 1 switch (avctx->pix_fmt) { case AV_PIX_FMT_RGB24: @@ -712,11 +655,9 @@ static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt, goto done; } -#if OPENJPEG_MAJOR_VERSION == 2 if ((ret = ff_alloc_packet2(avctx, pkt, 1024, 0)) < 0) { goto done; } -#endif // OPENJPEG_MAJOR_VERSION == 2 compress = opj_create_compress(ctx->format); if (!compress) { @@ -725,10 +666,6 @@ static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt, goto done; } -#if OPENJPEG_MAJOR_VERSION == 1 - opj_setup_encoder(compress, &ctx->enc_params, image); - stream = opj_cio_open((opj_common_ptr) compress, NULL, 0); -#else // OPENJPEG_MAJOR_VERSION == 2 if (!opj_set_error_handler(compress, error_callback, avctx) || !opj_set_warning_handler(compress, warning_callback, avctx) || !opj_set_info_handler(compress, info_callback, avctx)) { @@ -743,43 +680,18 @@ static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt, goto done; } stream = opj_stream_default_create(OPJ_STREAM_WRITE); -#endif // OPENJPEG_MAJOR_VERSION == 1 if (!stream) { av_log(avctx, AV_LOG_ERROR, "Error creating the cio stream\n"); ret = AVERROR(ENOMEM); goto done; } -#if OPENJPEG_MAJOR_VERSION == 1 - memset(&ctx->event_mgr, 0, sizeof(ctx->event_mgr)); - ctx->event_mgr.info_handler = info_callback; - ctx->event_mgr.error_handler = error_callback; - ctx->event_mgr.warning_handler = warning_callback; - opj_set_event_mgr((opj_common_ptr) compress, &ctx->event_mgr, avctx); - if (!opj_encode(compress, stream, image, NULL)) { - av_log(avctx, AV_LOG_ERROR, "Error during the opj encode\n"); - ret = AVERROR_EXTERNAL; - goto done; - } - len = cio_tell(stream); - if ((ret = ff_alloc_packet2(avctx, pkt, len, 0)) < 0) { - goto done; - } - - memcpy(pkt->data, stream->buffer, len); -#else // OPENJPEG_MAJOR_VERSION == 2 writer.packet = pkt; opj_stream_set_write_function(stream, stream_write); opj_stream_set_skip_function(stream, stream_skip); opj_stream_set_seek_function(stream, stream_seek); -#if HAVE_OPENJPEG_2_3_OPENJPEG_H || HAVE_OPENJPEG_2_2_OPENJPEG_H || HAVE_OPENJPEG_2_1_OPENJPEG_H opj_stream_set_user_data(stream, &writer, NULL); -#elif HAVE_OPENJPEG_2_0_OPENJPEG_H - opj_stream_set_user_data(stream, &writer); -#else -#error Missing call to opj_stream_set_user_data -#endif if (!opj_start_compress(compress, image, stream) || !opj_encode(compress, stream) || @@ -790,56 +702,39 @@ static int libopenjpeg_encode_frame(AVCodecContext *avctx, AVPacket *pkt, } av_shrink_packet(pkt, writer.pos); -#endif // OPENJPEG_MAJOR_VERSION == 1 pkt->flags |= AV_PKT_FLAG_KEY; *got_packet = 1; ret = 0; done: -#if OPENJPEG_MAJOR_VERSION == 2 opj_stream_destroy(stream); opj_destroy_codec(compress); opj_image_destroy(image); -#else - opj_cio_close(stream); - opj_destroy_compress(compress); -#endif return ret; } -static av_cold int libopenjpeg_encode_close(AVCodecContext *avctx) -{ -#if OPENJPEG_MAJOR_VERSION == 1 - LibOpenJPEGContext *ctx = avctx->priv_data; - - opj_image_destroy(ctx->image); - ctx->image = NULL; -#endif // OPENJPEG_MAJOR_VERSION == 1 - return 0; -} - #define OFFSET(x) offsetof(LibOpenJPEGContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { - { "format", "Codec Format", OFFSET(format), AV_OPT_TYPE_INT, { .i64 = OPJ(CODEC_JP2) }, OPJ(CODEC_J2K), OPJ(CODEC_JP2), VE, "format" }, - { "j2k", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(CODEC_J2K) }, 0, 0, VE, "format" }, - { "jp2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(CODEC_JP2) }, 0, 0, VE, "format" }, - { "profile", NULL, OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = OPJ(STD_RSIZ) }, OPJ(STD_RSIZ), OPJ(CINEMA4K), VE, "profile" }, - { "jpeg2000", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(STD_RSIZ) }, 0, 0, VE, "profile" }, - { "cinema2k", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(CINEMA2K) }, 0, 0, VE, "profile" }, - { "cinema4k", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(CINEMA4K) }, 0, 0, VE, "profile" }, - { "cinema_mode", "Digital Cinema", OFFSET(cinema_mode), AV_OPT_TYPE_INT, { .i64 = OPJ(OFF) }, OPJ(OFF), OPJ(CINEMA4K_24), VE, "cinema_mode" }, - { "off", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(OFF) }, 0, 0, VE, "cinema_mode" }, - { "2k_24", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(CINEMA2K_24) }, 0, 0, VE, "cinema_mode" }, - { "2k_48", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(CINEMA2K_48) }, 0, 0, VE, "cinema_mode" }, - { "4k_24", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(CINEMA4K_24) }, 0, 0, VE, "cinema_mode" }, - { "prog_order", "Progression Order", OFFSET(prog_order), AV_OPT_TYPE_INT, { .i64 = OPJ(LRCP) }, OPJ(LRCP), OPJ(CPRL), VE, "prog_order" }, - { "lrcp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(LRCP) }, 0, 0, VE, "prog_order" }, - { "rlcp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(RLCP) }, 0, 0, VE, "prog_order" }, - { "rpcl", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(RPCL) }, 0, 0, VE, "prog_order" }, - { "pcrl", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(PCRL) }, 0, 0, VE, "prog_order" }, - { "cprl", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ(CPRL) }, 0, 0, VE, "prog_order" }, + { "format", "Codec Format", OFFSET(format), AV_OPT_TYPE_INT, { .i64 = OPJ_CODEC_JP2 }, OPJ_CODEC_J2K, OPJ_CODEC_JP2, VE, "format" }, + { "j2k", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_CODEC_J2K }, 0, 0, VE, "format" }, + { "jp2", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_CODEC_JP2 }, 0, 0, VE, "format" }, + { "profile", NULL, OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = OPJ_STD_RSIZ }, OPJ_STD_RSIZ, OPJ_CINEMA4K, VE, "profile" }, + { "jpeg2000", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_STD_RSIZ }, 0, 0, VE, "profile" }, + { "cinema2k", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_CINEMA2K }, 0, 0, VE, "profile" }, + { "cinema4k", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_CINEMA4K }, 0, 0, VE, "profile" }, + { "cinema_mode", "Digital Cinema", OFFSET(cinema_mode), AV_OPT_TYPE_INT, { .i64 = OPJ_OFF }, OPJ_OFF, OPJ_CINEMA4K_24, VE, "cinema_mode" }, + { "off", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_OFF }, 0, 0, VE, "cinema_mode" }, + { "2k_24", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_CINEMA2K_24 }, 0, 0, VE, "cinema_mode" }, + { "2k_48", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_CINEMA2K_48 }, 0, 0, VE, "cinema_mode" }, + { "4k_24", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_CINEMA4K_24 }, 0, 0, VE, "cinema_mode" }, + { "prog_order", "Progression Order", OFFSET(prog_order), AV_OPT_TYPE_INT, { .i64 = OPJ_LRCP }, OPJ_LRCP, OPJ_CPRL, VE, "prog_order" }, + { "lrcp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_LRCP }, 0, 0, VE, "prog_order" }, + { "rlcp", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_RLCP }, 0, 0, VE, "prog_order" }, + { "rpcl", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_RPCL }, 0, 0, VE, "prog_order" }, + { "pcrl", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_PCRL }, 0, 0, VE, "prog_order" }, + { "cprl", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = OPJ_CPRL }, 0, 0, VE, "prog_order" }, { "numresolution", NULL, OFFSET(numresolution), AV_OPT_TYPE_INT, { .i64 = 6 }, 0, 33, VE }, { "irreversible", NULL, OFFSET(irreversible), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, { "disto_alloc", NULL, OFFSET(disto_alloc), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, VE }, @@ -862,7 +757,6 @@ AVCodec ff_libopenjpeg_encoder = { .priv_data_size = sizeof(LibOpenJPEGContext), .init = libopenjpeg_encode_init, .encode2 = libopenjpeg_encode_frame, - .close = libopenjpeg_encode_close, .capabilities = AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_INTRA_ONLY, .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB48, @@ -884,4 +778,5 @@ AVCodec ff_libopenjpeg_encoder = { AV_PIX_FMT_NONE }, .priv_class = &openjpeg_class, + .wrapper_name = "libopenjpeg", }; diff --git a/libavcodec/libopusdec.c b/libavcodec/libopusdec.c index e6ca61a78f3fc..2a97811d187cf 100644 --- a/libavcodec/libopusdec.c +++ b/libavcodec/libopusdec.c @@ -24,6 +24,8 @@ #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" +#include "libavutil/ffmath.h" +#include "libavutil/opt.h" #include "avcodec.h" #include "internal.h" @@ -32,11 +34,15 @@ #include "libopus.h" struct libopus_context { + AVClass *class; OpusMSDecoder *dec; int pre_skip; #ifndef OPUS_SET_GAIN union { int i; double d; } gain; #endif +#ifdef OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST + int apply_phase_inv; +#endif }; #define OPUS_HEAD_SIZE 19 @@ -57,8 +63,6 @@ static av_cold int libopus_decode_init(AVCodecContext *avc) avc->sample_rate = 48000; avc->sample_fmt = avc->request_sample_fmt == AV_SAMPLE_FMT_FLT ? AV_SAMPLE_FMT_FLT : AV_SAMPLE_FMT_S16; - avc->channel_layout = avc->channels > 8 ? 0 : - ff_vorbis_channel_layouts[avc->channels - 1]; if (avc->extradata_size >= OPUS_HEAD_SIZE) { opus->pre_skip = AV_RL16(avc->extradata + 10); @@ -82,14 +86,35 @@ static av_cold int libopus_decode_init(AVCodecContext *avc) mapping = mapping_arr; } - if (avc->channels > 2 && avc->channels <= 8) { - const uint8_t *vorbis_offset = ff_vorbis_channel_layout_offsets[avc->channels - 1]; - int ch; + if (channel_map == 1) { + avc->channel_layout = avc->channels > 8 ? 0 : + ff_vorbis_channel_layouts[avc->channels - 1]; + if (avc->channels > 2 && avc->channels <= 8) { + const uint8_t *vorbis_offset = ff_vorbis_channel_layout_offsets[avc->channels - 1]; + int ch; - /* Remap channels from Vorbis order to ffmpeg order */ - for (ch = 0; ch < avc->channels; ch++) - mapping_arr[ch] = mapping[vorbis_offset[ch]]; - mapping = mapping_arr; + /* Remap channels from Vorbis order to ffmpeg order */ + for (ch = 0; ch < avc->channels; ch++) + mapping_arr[ch] = mapping[vorbis_offset[ch]]; + mapping = mapping_arr; + } + } else if (channel_map == 2) { + int ambisonic_order = ff_sqrt(avc->channels) - 1; + if (avc->channels != (ambisonic_order + 1) * (ambisonic_order + 1) && + avc->channels != (ambisonic_order + 1) * (ambisonic_order + 1) + 2) { + av_log(avc, AV_LOG_ERROR, + "Channel mapping 2 is only specified for channel counts" + " which can be written as (n + 1)^2 or (n + 2)^2 + 2" + " for nonnegative integer n\n"); + return AVERROR_INVALIDDATA; + } + if (avc->channels > 227) { + av_log(avc, AV_LOG_ERROR, "Too many channels\n"); + return AVERROR_INVALIDDATA; + } + avc->channel_layout = 0; + } else { + avc->channel_layout = 0; } opus->dec = opus_multistream_decoder_create(avc->sample_rate, avc->channels, @@ -116,6 +141,15 @@ static av_cold int libopus_decode_init(AVCodecContext *avc) } #endif +#ifdef OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST + ret = opus_multistream_decoder_ctl(opus->dec, + OPUS_SET_PHASE_INVERSION_DISABLED(!opus->apply_phase_inv)); + if (ret != OPUS_OK) + av_log(avc, AV_LOG_WARNING, + "Unable to set phase inversion: %s\n", + opus_strerror(ret)); +#endif + /* Decoder delay (in samples) at 48kHz */ avc->delay = avc->internal->skip_samples = opus->pre_skip; @@ -126,7 +160,10 @@ static av_cold int libopus_decode_close(AVCodecContext *avc) { struct libopus_context *opus = avc->priv_data; - opus_multistream_decoder_destroy(opus->dec); + if (opus->dec) { + opus_multistream_decoder_destroy(opus->dec); + opus->dec = NULL; + } return 0; } @@ -189,6 +226,24 @@ static void libopus_flush(AVCodecContext *avc) avc->internal->skip_samples = opus->pre_skip; } + +#define OFFSET(x) offsetof(struct libopus_context, x) +#define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM +static const AVOption libopusdec_options[] = { +#ifdef OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST + { "apply_phase_inv", "Apply intensity stereo phase inversion", OFFSET(apply_phase_inv), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS }, +#endif + { NULL }, +}; + +static const AVClass libopusdec_class = { + .class_name = "libopusdec", + .item_name = av_default_item_name, + .option = libopusdec_options, + .version = LIBAVUTIL_VERSION_INT, +}; + + AVCodec ff_libopus_decoder = { .name = "libopus", .long_name = NULL_IF_CONFIG_SMALL("libopus Opus"), @@ -200,7 +255,10 @@ AVCodec ff_libopus_decoder = { .decode = libopus_decode, .flush = libopus_flush, .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, + .priv_class = &libopusdec_class, + .wrapper_name = "libopus", }; diff --git a/libavcodec/libopusenc.c b/libavcodec/libopusenc.c index 3d88c296d3289..4ae81b0bb2e23 100644 --- a/libavcodec/libopusenc.c +++ b/libavcodec/libopusenc.c @@ -39,6 +39,9 @@ typedef struct LibopusEncOpts { int packet_size; int max_bandwidth; int mapping_family; +#ifdef OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST + int apply_phase_inv; +#endif } LibopusEncOpts; typedef struct LibopusEncContext { @@ -154,6 +157,14 @@ static int libopus_configure_encoder(AVCodecContext *avctx, OpusMSEncoder *enc, "Unable to set maximum bandwidth: %s\n", opus_strerror(ret)); } +#ifdef OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST + ret = opus_multistream_encoder_ctl(enc, + OPUS_SET_PHASE_INVERSION_DISABLED(!opts->apply_phase_inv)); + if (ret != OPUS_OK) + av_log(avctx, AV_LOG_WARNING, + "Unable to set phase inversion: %s\n", + opus_strerror(ret)); +#endif return OPUS_OK; } @@ -530,6 +541,9 @@ static const AVOption libopus_options[] = { { "on", "Use variable bit rate", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, FLAGS, "vbr" }, { "constrained", "Use constrained VBR", 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, 0, 0, FLAGS, "vbr" }, { "mapping_family", "Channel Mapping Family", OFFSET(mapping_family), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, FLAGS, "mapping_family" }, +#ifdef OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST + { "apply_phase_inv", "Apply intensity stereo phase inversion", OFFSET(apply_phase_inv), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS }, +#endif { NULL }, }; @@ -566,4 +580,5 @@ AVCodec ff_libopus_encoder = { .supported_samplerates = libopus_sample_rates, .priv_class = &libopus_class, .defaults = libopus_defaults, + .wrapper_name = "libopus", }; diff --git a/libavcodec/librsvgdec.c b/libavcodec/librsvgdec.c index 77c771003ce04..66977850261f9 100644 --- a/libavcodec/librsvgdec.c +++ b/libavcodec/librsvgdec.c @@ -82,8 +82,10 @@ static int librsvg_decode_frame(AVCodecContext *avctx, void *data, int *got_fram crender = cairo_create(image); - cairo_set_source_rgba(crender, 0.0, 0.0, 0.0, 1.0f); - cairo_paint_with_alpha(crender, 0.0f); + cairo_save(crender); + cairo_set_operator(crender, CAIRO_OPERATOR_CLEAR); + cairo_paint(crender); + cairo_restore(crender); cairo_scale(crender, dimensions.width / (double)unscaled_dimensions.width, dimensions.height / (double)unscaled_dimensions.height); @@ -124,4 +126,5 @@ AVCodec ff_librsvg_decoder = { .decode = librsvg_decode_frame, .priv_data_size = sizeof(LibRSVGContext), .capabilities = AV_CODEC_CAP_LOSSLESS | AV_CODEC_CAP_DR1, + .wrapper_name = "librsvg", }; diff --git a/libavcodec/libshine.c b/libavcodec/libshine.c index f4cf5981bcb79..7056fcd2e3d29 100644 --- a/libavcodec/libshine.c +++ b/libavcodec/libshine.c @@ -146,4 +146,5 @@ AVCodec ff_libshine_encoder = { .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_MONO, AV_CH_LAYOUT_STEREO, 0 }, + .wrapper_name = "libshine", }; diff --git a/libavcodec/libspeexdec.c b/libavcodec/libspeexdec.c index 044883af73860..d67c68c7f9243 100644 --- a/libavcodec/libspeexdec.c +++ b/libavcodec/libspeexdec.c @@ -200,4 +200,5 @@ AVCodec ff_libspeex_decoder = { .decode = libspeex_decode_frame, .flush = libspeex_decode_flush, .capabilities = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1, + .wrapper_name = "libspeex", }; diff --git a/libavcodec/libspeexenc.c b/libavcodec/libspeexenc.c index a2b07a41cbf63..6a37dbc76cc28 100644 --- a/libavcodec/libspeexenc.c +++ b/libavcodec/libspeexenc.c @@ -159,9 +159,9 @@ static av_cold int encode_init(AVCodecContext *avctx) /* sample rate and encoding mode */ switch (avctx->sample_rate) { - case 8000: mode = &speex_nb_mode; break; - case 16000: mode = &speex_wb_mode; break; - case 32000: mode = &speex_uwb_mode; break; + case 8000: mode = speex_lib_get_mode(SPEEX_MODEID_NB); break; + case 16000: mode = speex_lib_get_mode(SPEEX_MODEID_WB); break; + case 32000: mode = speex_lib_get_mode(SPEEX_MODEID_UWB); break; default: av_log(avctx, AV_LOG_ERROR, "Sample rate of %d Hz is not supported. " "Resample to 8, 16, or 32 kHz.\n", avctx->sample_rate); @@ -365,4 +365,5 @@ AVCodec ff_libspeex_encoder = { .supported_samplerates = (const int[]){ 8000, 16000, 32000, 0 }, .priv_class = &speex_class, .defaults = defaults, + .wrapper_name = "libspeex", }; diff --git a/libavcodec/libtheoraenc.c b/libavcodec/libtheoraenc.c index fae55e8f23b02..16966ed433dc0 100644 --- a/libavcodec/libtheoraenc.c +++ b/libavcodec/libtheoraenc.c @@ -208,7 +208,9 @@ static av_cold int encode_init(AVCodecContext* avc_context) av_log(avc_context, AV_LOG_ERROR, "Unsupported pix_fmt\n"); return AVERROR(EINVAL); } - avcodec_get_chroma_sub_sample(avc_context->pix_fmt, &h->uv_hshift, &h->uv_vshift); + ret = av_pix_fmt_get_chroma_sub_sample(avc_context->pix_fmt, &h->uv_hshift, &h->uv_vshift); + if (ret) + return ret; if (avc_context->flags & AV_CODEC_FLAG_QSCALE) { /* Clip global_quality in QP units to the [0 - 10] range @@ -383,4 +385,5 @@ AVCodec ff_libtheora_encoder = { .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_NONE }, + .wrapper_name = "libtheora", }; diff --git a/libavcodec/libtwolame.c b/libavcodec/libtwolame.c index 12d71e7acbb72..030f88868fb5b 100644 --- a/libavcodec/libtwolame.c +++ b/libavcodec/libtwolame.c @@ -226,4 +226,5 @@ AVCodec ff_libtwolame_encoder = { AV_CH_LAYOUT_STEREO, 0 }, .supported_samplerates = twolame_samplerates, + .wrapper_name = "libtwolame", }; diff --git a/libavcodec/libvo-amrwbenc.c b/libavcodec/libvo-amrwbenc.c index 2a15650572d94..77d0ccef15acf 100644 --- a/libavcodec/libvo-amrwbenc.c +++ b/libavcodec/libvo-amrwbenc.c @@ -46,7 +46,10 @@ static const AVOption options[] = { }; static const AVClass amrwb_class = { - "libvo_amrwbenc", av_default_item_name, options, LIBAVUTIL_VERSION_INT + .class_name = "libvo_amrwbenc", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, }; static int get_wb_bitrate_mode(int bitrate, void *log_ctx) @@ -149,4 +152,5 @@ AVCodec ff_libvo_amrwbenc_encoder = { .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, AV_SAMPLE_FMT_NONE }, .priv_class = &amrwb_class, + .wrapper_name = "libvo_amrwbenc", }; diff --git a/libavcodec/libvorbisenc.c b/libavcodec/libvorbisenc.c index 3ca5b55e8e617..f78f872fe2ead 100644 --- a/libavcodec/libvorbisenc.c +++ b/libavcodec/libvorbisenc.c @@ -377,4 +377,5 @@ AVCodec ff_libvorbis_encoder = { AV_SAMPLE_FMT_NONE }, .priv_class = &vorbis_class, .defaults = defaults, + .wrapper_name = "libvorbis", }; diff --git a/libavcodec/libvpx.c b/libavcodec/libvpx.c index 1eca97a081f03..cc055a0032626 100644 --- a/libavcodec/libvpx.c +++ b/libavcodec/libvpx.c @@ -40,9 +40,7 @@ static const enum AVPixelFormat vp9_pix_fmts_highcol[] = { AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, -#if VPX_IMAGE_ABI_VERSION >= 3 AV_PIX_FMT_GBRP, -#endif AV_PIX_FMT_NONE }; @@ -60,88 +58,23 @@ static const enum AVPixelFormat vp9_pix_fmts_highbd[] = { AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV440P12, AV_PIX_FMT_YUV444P12, -#if VPX_IMAGE_ABI_VERSION >= 3 AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, -#endif AV_PIX_FMT_NONE }; #endif av_cold void ff_vp9_init_static(AVCodec *codec) { - if ( vpx_codec_version_major() < 1 - || (vpx_codec_version_major() == 1 && vpx_codec_version_minor() < 3)) - codec->capabilities |= AV_CODEC_CAP_EXPERIMENTAL; codec->pix_fmts = vp9_pix_fmts_def; #if CONFIG_LIBVPX_VP9_ENCODER - if ( vpx_codec_version_major() > 1 - || (vpx_codec_version_major() == 1 && vpx_codec_version_minor() >= 4)) { -#ifdef VPX_CODEC_CAP_HIGHBITDEPTH + { vpx_codec_caps_t codec_caps = vpx_codec_get_caps(vpx_codec_vp9_cx()); if (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH) codec->pix_fmts = vp9_pix_fmts_highbd; else -#endif codec->pix_fmts = vp9_pix_fmts_highcol; } #endif } -#if 0 -enum AVPixelFormat ff_vpx_imgfmt_to_pixfmt(vpx_img_fmt_t img) -{ - switch (img) { - case VPX_IMG_FMT_RGB24: return AV_PIX_FMT_RGB24; - case VPX_IMG_FMT_RGB565: return AV_PIX_FMT_RGB565BE; - case VPX_IMG_FMT_RGB555: return AV_PIX_FMT_RGB555BE; - case VPX_IMG_FMT_UYVY: return AV_PIX_FMT_UYVY422; - case VPX_IMG_FMT_YUY2: return AV_PIX_FMT_YUYV422; - case VPX_IMG_FMT_YVYU: return AV_PIX_FMT_YVYU422; - case VPX_IMG_FMT_BGR24: return AV_PIX_FMT_BGR24; - case VPX_IMG_FMT_ARGB: return AV_PIX_FMT_ARGB; - case VPX_IMG_FMT_ARGB_LE: return AV_PIX_FMT_BGRA; - case VPX_IMG_FMT_RGB565_LE: return AV_PIX_FMT_RGB565LE; - case VPX_IMG_FMT_RGB555_LE: return AV_PIX_FMT_RGB555LE; - case VPX_IMG_FMT_I420: return AV_PIX_FMT_YUV420P; - case VPX_IMG_FMT_I422: return AV_PIX_FMT_YUV422P; - case VPX_IMG_FMT_I444: return AV_PIX_FMT_YUV444P; - case VPX_IMG_FMT_444A: return AV_PIX_FMT_YUVA444P; -#if VPX_IMAGE_ABI_VERSION >= 3 - case VPX_IMG_FMT_I440: return AV_PIX_FMT_YUV440P; - case VPX_IMG_FMT_I42016: return AV_PIX_FMT_YUV420P16BE; - case VPX_IMG_FMT_I42216: return AV_PIX_FMT_YUV422P16BE; - case VPX_IMG_FMT_I44416: return AV_PIX_FMT_YUV444P16BE; -#endif - default: return AV_PIX_FMT_NONE; - } -} - -vpx_img_fmt_t ff_vpx_pixfmt_to_imgfmt(enum AVPixelFormat pix) -{ - switch (pix) { - case AV_PIX_FMT_RGB24: return VPX_IMG_FMT_RGB24; - case AV_PIX_FMT_RGB565BE: return VPX_IMG_FMT_RGB565; - case AV_PIX_FMT_RGB555BE: return VPX_IMG_FMT_RGB555; - case AV_PIX_FMT_UYVY422: return VPX_IMG_FMT_UYVY; - case AV_PIX_FMT_YUYV422: return VPX_IMG_FMT_YUY2; - case AV_PIX_FMT_YVYU422: return VPX_IMG_FMT_YVYU; - case AV_PIX_FMT_BGR24: return VPX_IMG_FMT_BGR24; - case AV_PIX_FMT_ARGB: return VPX_IMG_FMT_ARGB; - case AV_PIX_FMT_BGRA: return VPX_IMG_FMT_ARGB_LE; - case AV_PIX_FMT_RGB565LE: return VPX_IMG_FMT_RGB565_LE; - case AV_PIX_FMT_RGB555LE: return VPX_IMG_FMT_RGB555_LE; - case AV_PIX_FMT_YUV420P: return VPX_IMG_FMT_I420; - case AV_PIX_FMT_YUV422P: return VPX_IMG_FMT_I422; - case AV_PIX_FMT_YUV444P: return VPX_IMG_FMT_I444; - case AV_PIX_FMT_YUVA444P: return VPX_IMG_FMT_444A; -#if VPX_IMAGE_ABI_VERSION >= 3 - case AV_PIX_FMT_YUV440P: return VPX_IMG_FMT_I440; - case AV_PIX_FMT_YUV420P16BE: return VPX_IMG_FMT_I42016; - case AV_PIX_FMT_YUV422P16BE: return VPX_IMG_FMT_I42216; - case AV_PIX_FMT_YUV444P16BE: return VPX_IMG_FMT_I44416; -#endif - default: return VPX_IMG_FMT_NONE; - } -} -#endif diff --git a/libavcodec/libvpxdec.c b/libavcodec/libvpxdec.c index ad0ea3b02aae8..04f27d3396107 100644 --- a/libavcodec/libvpxdec.c +++ b/libavcodec/libvpxdec.c @@ -70,7 +70,6 @@ static av_cold int vpx_init(AVCodecContext *avctx, static int set_pix_fmt(AVCodecContext *avctx, struct vpx_image *img, int has_alpha_channel) { -#if VPX_IMAGE_ABI_VERSION >= 3 static const enum AVColorSpace colorspaces[8] = { AVCOL_SPC_UNSPECIFIED, AVCOL_SPC_BT470BG, AVCOL_SPC_BT709, AVCOL_SPC_SMPTE170M, AVCOL_SPC_SMPTE240M, AVCOL_SPC_BT2020_NCL, AVCOL_SPC_RESERVED, AVCOL_SPC_RGB, @@ -82,7 +81,6 @@ static int set_pix_fmt(AVCodecContext *avctx, struct vpx_image *img, avctx->color_range = color_ranges[img->range]; #endif avctx->colorspace = colorspaces[img->cs]; -#endif if (avctx->codec_id == AV_CODEC_ID_VP8 && img->fmt != VPX_IMG_FMT_I420) return AVERROR_INVALIDDATA; switch (img->fmt) { @@ -97,22 +95,15 @@ static int set_pix_fmt(AVCodecContext *avctx, struct vpx_image *img, avctx->profile = FF_PROFILE_VP9_1; avctx->pix_fmt = AV_PIX_FMT_YUV422P; return 0; -#if VPX_IMAGE_ABI_VERSION >= 3 case VPX_IMG_FMT_I440: avctx->profile = FF_PROFILE_VP9_1; avctx->pix_fmt = AV_PIX_FMT_YUV440P; return 0; -#endif case VPX_IMG_FMT_I444: avctx->profile = FF_PROFILE_VP9_1; -#if VPX_IMAGE_ABI_VERSION >= 3 avctx->pix_fmt = avctx->colorspace == AVCOL_SPC_RGB ? AV_PIX_FMT_GBRP : AV_PIX_FMT_YUV444P; -#else - avctx->pix_fmt = AV_PIX_FMT_YUV444P; -#endif return 0; -#ifdef VPX_IMG_FMT_HIGHBITDEPTH case VPX_IMG_FMT_I42016: avctx->profile = FF_PROFILE_VP9_2; if (img->bit_depth == 10) { @@ -135,7 +126,6 @@ static int set_pix_fmt(AVCodecContext *avctx, struct vpx_image *img, } else { return AVERROR_INVALIDDATA; } -#if VPX_IMAGE_ABI_VERSION >= 3 case VPX_IMG_FMT_I44016: avctx->profile = FF_PROFILE_VP9_3; if (img->bit_depth == 10) { @@ -147,29 +137,19 @@ static int set_pix_fmt(AVCodecContext *avctx, struct vpx_image *img, } else { return AVERROR_INVALIDDATA; } -#endif case VPX_IMG_FMT_I44416: avctx->profile = FF_PROFILE_VP9_3; if (img->bit_depth == 10) { -#if VPX_IMAGE_ABI_VERSION >= 3 avctx->pix_fmt = avctx->colorspace == AVCOL_SPC_RGB ? AV_PIX_FMT_GBRP10 : AV_PIX_FMT_YUV444P10; -#else - avctx->pix_fmt = AV_PIX_FMT_YUV444P10; -#endif return 0; } else if (img->bit_depth == 12) { -#if VPX_IMAGE_ABI_VERSION >= 3 avctx->pix_fmt = avctx->colorspace == AVCOL_SPC_RGB ? AV_PIX_FMT_GBRP12 : AV_PIX_FMT_YUV444P12; -#else - avctx->pix_fmt = AV_PIX_FMT_YUV444P12; -#endif return 0; } else { return AVERROR_INVALIDDATA; } -#endif #endif default: return AVERROR_INVALIDDATA; @@ -252,13 +232,8 @@ static int vpx_decode(AVCodecContext *avctx, } if ((ret = set_pix_fmt(avctx, img, ctx->has_alpha_channel)) < 0) { -#ifdef VPX_IMG_FMT_HIGHBITDEPTH av_log(avctx, AV_LOG_ERROR, "Unsupported output colorspace (%d) / bit_depth (%d)\n", img->fmt, img->bit_depth); -#else - av_log(avctx, AV_LOG_ERROR, "Unsupported output colorspace (%d) / bit_depth (%d)\n", - img->fmt, 8); -#endif return ret; } @@ -314,6 +289,7 @@ AVCodec ff_libvpx_vp8_decoder = { .close = vpx_free, .decode = vpx_decode, .capabilities = AV_CODEC_CAP_AUTO_THREADS | AV_CODEC_CAP_DR1, + .wrapper_name = "libvpx", }; #endif /* CONFIG_LIBVPX_VP8_DECODER */ @@ -335,5 +311,6 @@ AVCodec ff_libvpx_vp9_decoder = { .capabilities = AV_CODEC_CAP_AUTO_THREADS | AV_CODEC_CAP_DR1, .init_static_data = ff_vp9_init_static, .profiles = NULL_IF_CONFIG_SMALL(ff_vp9_profiles), + .wrapper_name = "libvpx", }; #endif /* CONFIG_LIBVPX_VP9_DECODER */ diff --git a/libavcodec/libvpxenc.c b/libavcodec/libvpxenc.c index 64a7459331099..d0bd1e997abd3 100644 --- a/libavcodec/libvpxenc.c +++ b/libavcodec/libvpxenc.c @@ -109,6 +109,8 @@ typedef struct VPxEncoderContext { int vpx_cs; float level; int row_mt; + int tune_content; + int corpus_complexity; } VPxContext; /** String mappings for enum vp8e_enc_control_id */ @@ -130,9 +132,7 @@ static const char *const ctlidstr[] = { [VP9E_SET_TILE_ROWS] = "VP9E_SET_TILE_ROWS", [VP9E_SET_FRAME_PARALLEL_DECODING] = "VP9E_SET_FRAME_PARALLEL_DECODING", [VP9E_SET_AQ_MODE] = "VP9E_SET_AQ_MODE", -#if VPX_ENCODER_ABI_VERSION > 8 [VP9E_SET_COLOR_SPACE] = "VP9E_SET_COLOR_SPACE", -#endif #if VPX_ENCODER_ABI_VERSION >= 11 [VP9E_SET_COLOR_RANGE] = "VP9E_SET_COLOR_RANGE", #endif @@ -143,6 +143,9 @@ static const char *const ctlidstr[] = { #ifdef VPX_CTRL_VP9E_SET_ROW_MT [VP9E_SET_ROW_MT] = "VP9E_SET_ROW_MT", #endif +#ifdef VPX_CTRL_VP9E_SET_TUNE_CONTENT + [VP9E_SET_TUNE_CONTENT] = "VP9E_SET_TUNE_CONTENT", +#endif #endif }; @@ -166,7 +169,7 @@ static av_cold void dump_enc_cfg(AVCodecContext *avctx, av_log(avctx, level, "vpx_codec_enc_cfg\n"); av_log(avctx, level, "generic settings\n" " %*s%u\n %*s%u\n %*s%u\n %*s%u\n %*s%u\n" -#if CONFIG_LIBVPX_VP9_ENCODER && defined(VPX_IMG_FMT_HIGHBITDEPTH) +#if CONFIG_LIBVPX_VP9_ENCODER " %*s%u\n %*s%u\n" #endif " %*s{%u/%u}\n %*s%u\n %*s%d\n %*s%u\n", @@ -175,7 +178,7 @@ static av_cold void dump_enc_cfg(AVCodecContext *avctx, width, "g_profile:", cfg->g_profile, width, "g_w:", cfg->g_w, width, "g_h:", cfg->g_h, -#if CONFIG_LIBVPX_VP9_ENCODER && defined(VPX_IMG_FMT_HIGHBITDEPTH) +#if CONFIG_LIBVPX_VP9_ENCODER width, "g_bit_depth:", cfg->g_bit_depth, width, "g_input_bit_depth:", cfg->g_input_bit_depth, #endif @@ -211,6 +214,10 @@ static av_cold void dump_enc_cfg(AVCodecContext *avctx, width, "rc_2pass_vbr_bias_pct:", cfg->rc_2pass_vbr_bias_pct, width, "rc_2pass_vbr_minsection_pct:", cfg->rc_2pass_vbr_minsection_pct, width, "rc_2pass_vbr_maxsection_pct:", cfg->rc_2pass_vbr_maxsection_pct); +#if VPX_ENCODER_ABI_VERSION >= 14 + av_log(avctx, level, " %*s%u\n", + width, "rc_2pass_vbr_corpus_complexity:", cfg->rc_2pass_vbr_corpus_complexity); +#endif av_log(avctx, level, "keyframing settings\n" " %*s%d\n %*s%u\n %*s%u\n", width, "kf_mode:", cfg->kf_mode, @@ -320,9 +327,7 @@ static int set_pix_fmt(AVCodecContext *avctx, vpx_codec_caps_t codec_caps, vpx_img_fmt_t *img_fmt) { VPxContext av_unused *ctx = avctx->priv_data; -#ifdef VPX_IMG_FMT_HIGHBITDEPTH enccfg->g_bit_depth = enccfg->g_input_bit_depth = 8; -#endif switch (avctx->pix_fmt) { case AV_PIX_FMT_YUV420P: case AV_PIX_FMT_YUVA420P: @@ -333,19 +338,16 @@ static int set_pix_fmt(AVCodecContext *avctx, vpx_codec_caps_t codec_caps, enccfg->g_profile = 1; *img_fmt = VPX_IMG_FMT_I422; return 0; -#if VPX_IMAGE_ABI_VERSION >= 3 case AV_PIX_FMT_YUV440P: enccfg->g_profile = 1; *img_fmt = VPX_IMG_FMT_I440; return 0; case AV_PIX_FMT_GBRP: ctx->vpx_cs = VPX_CS_SRGB; -#endif case AV_PIX_FMT_YUV444P: enccfg->g_profile = 1; *img_fmt = VPX_IMG_FMT_I444; return 0; -#ifdef VPX_IMG_FMT_HIGHBITDEPTH case AV_PIX_FMT_YUV420P10: case AV_PIX_FMT_YUV420P12: if (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH) { @@ -368,7 +370,6 @@ static int set_pix_fmt(AVCodecContext *avctx, vpx_codec_caps_t codec_caps, return 0; } break; -#if VPX_IMAGE_ABI_VERSION >= 3 case AV_PIX_FMT_YUV440P10: case AV_PIX_FMT_YUV440P12: if (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH) { @@ -383,7 +384,6 @@ static int set_pix_fmt(AVCodecContext *avctx, vpx_codec_caps_t codec_caps, case AV_PIX_FMT_GBRP10: case AV_PIX_FMT_GBRP12: ctx->vpx_cs = VPX_CS_SRGB; -#endif case AV_PIX_FMT_YUV444P10: case AV_PIX_FMT_YUV444P12: if (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH) { @@ -396,7 +396,6 @@ static int set_pix_fmt(AVCodecContext *avctx, vpx_codec_caps_t codec_caps, return 0; } break; -#endif default: break; } @@ -404,7 +403,6 @@ static int set_pix_fmt(AVCodecContext *avctx, vpx_codec_caps_t codec_caps, return AVERROR_INVALIDDATA; } -#if VPX_ENCODER_ABI_VERSION > 8 static void set_colorspace(AVCodecContext *avctx) { enum vpx_color_space vpx_cs; @@ -430,7 +428,6 @@ static void set_colorspace(AVCodecContext *avctx) } codecctl_int(avctx, VP9E_SET_COLOR_SPACE, vpx_cs); } -#endif #if VPX_ENCODER_ABI_VERSION >= 11 static void set_color_range(AVCodecContext *avctx) @@ -573,6 +570,14 @@ FF_ENABLE_DEPRECATION_WARNINGS if (avctx->rc_max_rate) enccfg.rc_2pass_vbr_maxsection_pct = avctx->rc_max_rate * 100LL / avctx->bit_rate; +#if CONFIG_LIBVPX_VP9_ENCODER + if (avctx->codec_id == AV_CODEC_ID_VP9) { +#if VPX_ENCODER_ABI_VERSION >= 14 + if (ctx->corpus_complexity >= 0) + enccfg.rc_2pass_vbr_corpus_complexity = ctx->corpus_complexity; +#endif + } +#endif if (avctx->rc_buffer_size) enccfg.rc_buf_sz = @@ -581,15 +586,6 @@ FF_ENABLE_DEPRECATION_WARNINGS enccfg.rc_buf_initial_sz = avctx->rc_initial_buffer_occupancy * 1000LL / avctx->bit_rate; enccfg.rc_buf_optimal_sz = enccfg.rc_buf_sz * 5 / 6; -#if FF_API_MPV_OPT - FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->rc_buffer_aggressivity != 1.0) { - av_log(avctx, AV_LOG_WARNING, "The rc_buffer_aggressivity option is " - "deprecated, use the undershoot-pct private option instead.\n"); - enccfg.rc_undershoot_pct = lrint(avctx->rc_buffer_aggressivity * 100); - } - FF_ENABLE_DEPRECATION_WARNINGS -#endif if (ctx->rc_undershoot_pct >= 0) enccfg.rc_undershoot_pct = ctx->rc_undershoot_pct; if (ctx->rc_overshoot_pct >= 0) @@ -688,15 +684,6 @@ FF_ENABLE_DEPRECATION_WARNINGS codecctl_int(avctx, VP8E_SET_NOISE_SENSITIVITY, ctx->noise_sensitivity); codecctl_int(avctx, VP8E_SET_TOKEN_PARTITIONS, av_log2(avctx->slices)); } -#if FF_API_MPV_OPT - FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->mb_threshold) { - av_log(avctx, AV_LOG_WARNING, "The mb_threshold option is deprecated, " - "use the static-thresh private option instead.\n"); - ctx->static_thresh = avctx->mb_threshold; - } - FF_ENABLE_DEPRECATION_WARNINGS -#endif codecctl_int(avctx, VP8E_SET_STATIC_THRESHOLD, ctx->static_thresh); if (ctx->crf >= 0) codecctl_int(avctx, VP8E_SET_CQ_LEVEL, ctx->crf); @@ -715,9 +702,7 @@ FF_ENABLE_DEPRECATION_WARNINGS codecctl_int(avctx, VP9E_SET_FRAME_PARALLEL_DECODING, ctx->frame_parallel); if (ctx->aq_mode >= 0) codecctl_int(avctx, VP9E_SET_AQ_MODE, ctx->aq_mode); -#if VPX_ENCODER_ABI_VERSION > 8 set_colorspace(avctx); -#endif #if VPX_ENCODER_ABI_VERSION >= 11 set_color_range(avctx); #endif @@ -727,6 +712,10 @@ FF_ENABLE_DEPRECATION_WARNINGS #ifdef VPX_CTRL_VP9E_SET_ROW_MT if (ctx->row_mt >= 0) codecctl_int(avctx, VP9E_SET_ROW_MT, ctx->row_mt); +#endif +#ifdef VPX_CTRL_VP9E_SET_TUNE_CONTENT + if (ctx->tune_content >= 0) + codecctl_int(avctx, VP9E_SET_TUNE_CONTENT, ctx->tune_content); #endif } #endif @@ -736,7 +725,7 @@ FF_ENABLE_DEPRECATION_WARNINGS //provide dummy value to initialize wrapper, values will be updated each _encode() vpx_img_wrap(&ctx->rawimg, img_fmt, avctx->width, avctx->height, 1, (unsigned char*)1); -#if CONFIG_LIBVPX_VP9_ENCODER && defined(VPX_IMG_FMT_HIGHBITDEPTH) +#if CONFIG_LIBVPX_VP9_ENCODER if (avctx->codec_id == AV_CODEC_ID_VP9 && (codec_caps & VPX_CODEC_CAP_HIGHBITDEPTH)) ctx->rawimg.bit_depth = enccfg.g_bit_depth; #endif @@ -1077,11 +1066,6 @@ static int vpx_encode(AVCodecContext *avctx, AVPacket *pkt, #define OFFSET(x) offsetof(VPxContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM -#ifndef VPX_ERROR_RESILIENT_DEFAULT -#define VPX_ERROR_RESILIENT_DEFAULT 1 -#define VPX_ERROR_RESILIENT_PARTITIONS 2 -#endif - #define COMMON_OPTIONS \ { "auto-alt-ref", "Enable use of alternate reference " \ "frames (2-pass only)", OFFSET(auto_alt_ref), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 2, VE}, \ @@ -1157,6 +1141,21 @@ static const AVOption vp9_options[] = { #endif #ifdef VPX_CTRL_VP9E_SET_ROW_MT {"row-mt", "Row based multi-threading", OFFSET(row_mt), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE}, +#endif +#ifdef VPX_CTRL_VP9E_SET_TUNE_CONTENT +#if VPX_ENCODER_ABI_VERSION >= 14 + { "tune-content", "Tune content type", OFFSET(tune_content), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 2, VE, "tune_content" }, +#else + { "tune-content", "Tune content type", OFFSET(tune_content), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, VE, "tune_content" }, +#endif + { "default", "Regular video content", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, VE, "tune_content" }, + { "screen", "Screen capture content", 0, AV_OPT_TYPE_CONST, {.i64 = 1}, 0, 0, VE, "tune_content" }, +#if VPX_ENCODER_ABI_VERSION >= 14 + { "film", "Film content; improves grain retention", 0, AV_OPT_TYPE_CONST, {.i64 = 2}, 0, 0, VE, "tune_content" }, +#endif +#endif +#if VPX_ENCODER_ABI_VERSION >= 14 + { "corpus-complexity", "corpus vbr complexity midpoint", OFFSET(corpus_complexity), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 10000, VE }, #endif LEGACY_OPTIONS { NULL } @@ -1200,6 +1199,7 @@ AVCodec ff_libvpx_vp8_encoder = { .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_NONE }, .priv_class = &class_vp8, .defaults = defaults, + .wrapper_name = "libvpx", }; #endif /* CONFIG_LIBVPX_VP8_ENCODER */ @@ -1230,5 +1230,6 @@ AVCodec ff_libvpx_vp9_encoder = { .priv_class = &class_vp9, .defaults = defaults, .init_static_data = ff_vp9_init_static, + .wrapper_name = "libvpx", }; #endif /* CONFIG_LIBVPX_VP9_ENCODER */ diff --git a/libavcodec/libwavpackenc.c b/libavcodec/libwavpackenc.c index 6d5708985afde..e84b0748936d5 100644 --- a/libavcodec/libwavpackenc.c +++ b/libavcodec/libwavpackenc.c @@ -191,4 +191,5 @@ AVCodec ff_libwavpack_encoder = { .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_SMALL_LAST_FRAME, .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S32, AV_SAMPLE_FMT_NONE }, + .wrapper_name = "libwavpack", }; diff --git a/libavcodec/libwebpenc.c b/libavcodec/libwebpenc.c index 0bcf628e58076..48f45b6320852 100644 --- a/libavcodec/libwebpenc.c +++ b/libavcodec/libwebpenc.c @@ -109,4 +109,5 @@ AVCodec ff_libwebp_encoder = { }, .priv_class = &class, .defaults = libwebp_defaults, + .wrapper_name = "libwebp", }; diff --git a/libavcodec/libwebpenc_animencoder.c b/libavcodec/libwebpenc_animencoder.c index 91bf64ca8b8b0..7f35a0b93913d 100644 --- a/libavcodec/libwebpenc_animencoder.c +++ b/libavcodec/libwebpenc_animencoder.c @@ -148,4 +148,5 @@ AVCodec ff_libwebp_anim_encoder = { }, .priv_class = &class, .defaults = libwebp_defaults, + .wrapper_name = "libwebp", }; diff --git a/libavcodec/libx264.c b/libavcodec/libx264.c index b11ede6198863..12379ff763647 100644 --- a/libavcodec/libx264.c +++ b/libavcodec/libx264.c @@ -279,7 +279,11 @@ static int X264_frame(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame, x264_picture_init( &x4->pic ); x4->pic.img.i_csp = x4->params.i_csp; +#if X264_BUILD >= 153 + if (x4->params.i_bitdepth > 8) +#else if (x264_bit_depth > 8) +#endif x4->pic.img.i_csp |= X264_CSP_HIGH_DEPTH; x4->pic.img.i_plane = avfmt2_num_planes(ctx->pix_fmt); @@ -490,6 +494,9 @@ static av_cold int X264_init(AVCodecContext *avctx) x4->params.p_log_private = avctx; x4->params.i_log_level = X264_LOG_DEBUG; x4->params.i_csp = convert_pix_fmt(avctx->pix_fmt); +#if X264_BUILD >= 153 + x4->params.i_bitdepth = av_pix_fmt_desc_get(avctx->pix_fmt)->comp[0].depth; +#endif PARSE_X264_OPT("weightp", wpredp); @@ -701,24 +708,8 @@ FF_ENABLE_DEPRECATION_WARNINGS if (x4->nal_hrd >= 0) x4->params.i_nal_hrd = x4->nal_hrd; - if (x4->motion_est >= 0) { + if (x4->motion_est >= 0) x4->params.analyse.i_me_method = x4->motion_est; -#if FF_API_MOTION_EST -FF_DISABLE_DEPRECATION_WARNINGS - } else { - if (avctx->me_method == ME_EPZS) - x4->params.analyse.i_me_method = X264_ME_DIA; - else if (avctx->me_method == ME_HEX) - x4->params.analyse.i_me_method = X264_ME_HEX; - else if (avctx->me_method == ME_UMH) - x4->params.analyse.i_me_method = X264_ME_UMH; - else if (avctx->me_method == ME_FULL) - x4->params.analyse.i_me_method = X264_ME_ESA; - else if (avctx->me_method == ME_TESA) - x4->params.analyse.i_me_method = X264_ME_TESA; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - } if (x4->coder >= 0) x4->params.b_cabac = x4->coder; @@ -878,6 +869,24 @@ static const enum AVPixelFormat pix_fmts_10bit[] = { AV_PIX_FMT_NV20, AV_PIX_FMT_NONE }; +static const enum AVPixelFormat pix_fmts_all[] = { + AV_PIX_FMT_YUV420P, + AV_PIX_FMT_YUVJ420P, + AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUVJ422P, + AV_PIX_FMT_YUV444P, + AV_PIX_FMT_YUVJ444P, + AV_PIX_FMT_NV12, + AV_PIX_FMT_NV16, +#ifdef X264_CSP_NV21 + AV_PIX_FMT_NV21, +#endif + AV_PIX_FMT_YUV420P10, + AV_PIX_FMT_YUV422P10, + AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_NV20, + AV_PIX_FMT_NONE +}; #if CONFIG_LIBX264RGB_ENCODER static const enum AVPixelFormat pix_fmts_8bit_rgb[] = { AV_PIX_FMT_BGR0, @@ -889,12 +898,16 @@ static const enum AVPixelFormat pix_fmts_8bit_rgb[] = { static av_cold void X264_init_static(AVCodec *codec) { +#if X264_BUILD < 153 if (x264_bit_depth == 8) codec->pix_fmts = pix_fmts_8bit; else if (x264_bit_depth == 9) codec->pix_fmts = pix_fmts_9bit; else if (x264_bit_depth == 10) codec->pix_fmts = pix_fmts_10bit; +#else + codec->pix_fmts = pix_fmts_all; +#endif } #define OFFSET(x) offsetof(X264Context, x) @@ -958,6 +971,7 @@ static const AVOption options[] = { { "vbr", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = X264_NAL_HRD_VBR}, INT_MIN, INT_MAX, VE, "nal-hrd" }, { "cbr", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = X264_NAL_HRD_CBR}, INT_MIN, INT_MAX, VE, "nal-hrd" }, { "avcintra-class","AVC-Intra class 50/100/200", OFFSET(avcintra_class),AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 200 , VE}, + { "me_method", "Set motion estimation method", OFFSET(motion_est), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, X264_ME_TESA, VE, "motion-est"}, { "motion-est", "Set motion estimation method", OFFSET(motion_est), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, X264_ME_TESA, VE, "motion-est"}, { "dia", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = X264_ME_DIA }, INT_MIN, INT_MAX, VE, "motion-est" }, { "hex", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = X264_ME_HEX }, INT_MIN, INT_MAX, VE, "motion-est" }, @@ -1002,9 +1016,6 @@ static const AVCodecDefault x264_defaults[] = { { "nr", "-1" }, #endif { "me_range", "-1" }, -#if FF_API_MOTION_EST - { "me_method", "-1" }, -#endif { "subq", "-1" }, #if FF_API_PRIVATE_OPT { "b_strategy", "-1" }, @@ -1044,6 +1055,7 @@ AVCodec ff_libx264_encoder = { .init_static_data = X264_init_static, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, + .wrapper_name = "libx264", }; #endif @@ -1068,6 +1080,7 @@ AVCodec ff_libx264rgb_encoder = { .priv_class = &rgbclass, .defaults = x264_defaults, .pix_fmts = pix_fmts_8bit_rgb, + .wrapper_name = "libx264", }; #endif @@ -1094,5 +1107,6 @@ AVCodec ff_libx262_encoder = { .pix_fmts = pix_fmts_8bit, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, + .wrapper_name = "libx264", }; #endif diff --git a/libavcodec/libx265.c b/libavcodec/libx265.c index 784b51c52d40e..c208c0f2d31c3 100644 --- a/libavcodec/libx265.c +++ b/libavcodec/libx265.c @@ -45,6 +45,7 @@ typedef struct libx265Context { int forced_idr; char *preset; char *tune; + char *profile; char *x265_opts; } libx265Context; @@ -114,11 +115,22 @@ static av_cold int libx265_encode_init(AVCodecContext *avctx) ctx->params->sourceHeight = avctx->height; ctx->params->bEnablePsnr = !!(avctx->flags & AV_CODEC_FLAG_PSNR); - if ((avctx->color_primaries <= AVCOL_PRI_BT2020 && + /* Tune the CTU size based on input resolution. */ + if (ctx->params->sourceWidth < 64 || ctx->params->sourceHeight < 64) + ctx->params->maxCUSize = 32; + if (ctx->params->sourceWidth < 32 || ctx->params->sourceHeight < 32) + ctx->params->maxCUSize = 16; + if (ctx->params->sourceWidth < 16 || ctx->params->sourceHeight < 16) { + av_log(avctx, AV_LOG_ERROR, "Image size is too small (%dx%d).\n", + ctx->params->sourceWidth, ctx->params->sourceHeight); + return AVERROR(EINVAL); + } + + if ((avctx->color_primaries <= AVCOL_PRI_SMPTE432 && avctx->color_primaries != AVCOL_PRI_UNSPECIFIED) || - (avctx->color_trc <= AVCOL_TRC_BT2020_12 && + (avctx->color_trc <= AVCOL_TRC_ARIB_STD_B67 && avctx->color_trc != AVCOL_TRC_UNSPECIFIED) || - (avctx->colorspace <= AVCOL_SPC_BT2020_CL && + (avctx->colorspace <= AVCOL_SPC_ICTCP && avctx->colorspace != AVCOL_SPC_UNSPECIFIED)) { ctx->params->vui.bEnableVideoSignalTypePresentFlag = 1; @@ -220,6 +232,18 @@ static av_cold int libx265_encode_init(AVCodecContext *avctx) } } + if (ctx->profile) { + if (ctx->api->param_apply_profile(ctx->params, ctx->profile) < 0) { + int i; + av_log(avctx, AV_LOG_ERROR, "Invalid or incompatible profile set: %s.\n", ctx->profile); + av_log(avctx, AV_LOG_INFO, "Possible profiles:"); + for (i = 0; x265_profile_names[i]; i++) + av_log(avctx, AV_LOG_INFO, " %s", x265_profile_names[i]); + av_log(avctx, AV_LOG_INFO, "\n"); + return AVERROR(EINVAL); + } + } + ctx->encoder = ctx->api->encoder_open(ctx->params); if (!ctx->encoder) { av_log(avctx, AV_LOG_ERROR, "Cannot open libx265 encoder.\n"); @@ -294,7 +318,7 @@ static int libx265_encode_frame(AVCodecContext *avctx, AVPacket *pkt, for (i = 0; i < nnal; i++) payload += nal[i].sizeBytes; - ret = ff_alloc_packet(pkt, payload); + ret = ff_alloc_packet2(avctx, pkt, payload, payload); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n"); return ret; @@ -329,6 +353,13 @@ FF_DISABLE_DEPRECATION_WARNINGS FF_ENABLE_DEPRECATION_WARNINGS #endif +#if X265_BUILD >= 130 + if (x265pic_out.sliceType == X265_TYPE_B) +#else + if (x265pic_out.frameData.sliceType == 'b') +#endif + pkt->flags |= AV_PKT_FLAG_DISPOSABLE; + *got_packet = 1; return 0; } @@ -392,6 +423,7 @@ static const AVOption options[] = { { "forced-idr", "if forcing keyframes, force them as IDR frames", OFFSET(forced_idr),AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, { "preset", "set the x265 preset", OFFSET(preset), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE }, { "tune", "set the x265 tune parameter", OFFSET(tune), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE }, + { "profile", "set the x265 profile", OFFSET(profile), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE }, { "x265-params", "set the x265 configuration using a :-separated list of key=value parameters", OFFSET(x265_opts), AV_OPT_TYPE_STRING, { 0 }, 0, 0, VE }, { NULL } }; @@ -421,4 +453,5 @@ AVCodec ff_libx265_encoder = { .priv_class = &class, .defaults = x265_defaults, .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AUTO_THREADS, + .wrapper_name = "libx265", }; diff --git a/libavcodec/libxavs.c b/libavcodec/libxavs.c index f257e5584d91f..801a05dbb581a 100644 --- a/libavcodec/libxavs.c +++ b/libavcodec/libxavs.c @@ -283,32 +283,6 @@ static av_cold int XAVS_init(AVCodecContext *avctx) if (x4->cplxblur >= 0) x4->params.rc.f_complexity_blur = x4->cplxblur; -#if FF_API_MOTION_EST -FF_DISABLE_DEPRECATION_WARNINGS - if (x4->motion_est < 0) { - switch (avctx->me_method) { - case ME_EPZS: - x4->params.analyse.i_me_method = XAVS_ME_DIA; - break; - case ME_HEX: - x4->params.analyse.i_me_method = XAVS_ME_HEX; - break; - case ME_UMH: - x4->params.analyse.i_me_method = XAVS_ME_UMH; - break; - case ME_FULL: - x4->params.analyse.i_me_method = XAVS_ME_ESA; - break; - case ME_TESA: - x4->params.analyse.i_me_method = XAVS_ME_TESA; - break; - default: - x4->params.analyse.i_me_method = XAVS_ME_HEX; - } - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif - x4->params.i_bframe = avctx->max_b_frames; /* cabac is not included in AVS JiZhun Profile */ x4->params.b_cabac = 0; @@ -465,7 +439,7 @@ static const AVOption options[] = { { "mbtree", "Use macroblock tree ratecontrol.", OFFSET(mbtree), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE}, { "mixed-refs", "One reference per partition, as opposed to one reference per macroblock", OFFSET(mixed_refs), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, VE }, { "fast-pskip", NULL, OFFSET(fast_pskip), AV_OPT_TYPE_BOOL, {.i64 = -1 }, -1, 1, VE}, - { "motion-est", "Set motion estimation method", OFFSET(motion_est), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, XAVS_ME_TESA, VE, "motion-est"}, + { "motion-est", "Set motion estimation method", OFFSET(motion_est), AV_OPT_TYPE_INT, { .i64 = XAVS_ME_DIA }, -1, XAVS_ME_TESA, VE, "motion-est"}, { "dia", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = XAVS_ME_DIA }, INT_MIN, INT_MAX, VE, "motion-est" }, { "hex", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = XAVS_ME_HEX }, INT_MIN, INT_MAX, VE, "motion-est" }, { "umh", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = XAVS_ME_UMH }, INT_MIN, INT_MAX, VE, "motion-est" }, @@ -504,4 +478,5 @@ AVCodec ff_libxavs_encoder = { .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_YUV420P, AV_PIX_FMT_NONE }, .priv_class = &xavs_class, .defaults = xavs_defaults, + .wrapper_name = "libxavs", }; diff --git a/libavcodec/libxvid.c b/libavcodec/libxvid.c index d916f117141eb..cdaae2094e57f 100644 --- a/libavcodec/libxvid.c +++ b/libavcodec/libxvid.c @@ -418,30 +418,6 @@ static av_cold int xvid_encode_init(AVCodecContext *avctx) case 1: x->me_flags |= XVID_ME_ADVANCEDDIAMOND16 | XVID_ME_HALFPELREFINE16; -#if FF_API_MOTION_EST -FF_DISABLE_DEPRECATION_WARNINGS - break; - default: - switch (avctx->me_method) { - case ME_FULL: /* Quality 6 */ - x->me_flags |= XVID_ME_EXTSEARCH16 | - XVID_ME_EXTSEARCH8; - case ME_EPZS: /* Quality 4 */ - x->me_flags |= XVID_ME_ADVANCEDDIAMOND8 | - XVID_ME_HALFPELREFINE8 | - XVID_ME_CHROMA_PVOP | - XVID_ME_CHROMA_BVOP; - case ME_LOG: /* Quality 2 */ - case ME_PHODS: - case ME_X1: - x->me_flags |= XVID_ME_ADVANCEDDIAMOND16 | - XVID_ME_HALFPELREFINE16; - case ME_ZERO: /* Quality 0 */ - default: - break; - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif } /* Decide how we should decide blocks */ @@ -462,11 +438,6 @@ FF_ENABLE_DEPRECATION_WARNINGS } /* Bring in VOL flags from ffmpeg command-line */ -#if FF_API_GMC - if (avctx->flags & CODEC_FLAG_GMC) - x->gmc = 1; -#endif - x->vol_flags = 0; if (x->gmc) { x->vol_flags |= XVID_VOL_GMC; @@ -938,7 +909,7 @@ static const AVOption options[] = { { "frame", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, INT_MIN, INT_MAX, VE, "ssim" }, { "ssim_acc", "SSIM accuracy", OFFSET(ssim_acc), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, 4, VE }, { "gmc", "use GMC", OFFSET(gmc), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, - { "me_quality", "Motion estimation quality", OFFSET(me_quality), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 6, VE }, + { "me_quality", "Motion estimation quality", OFFSET(me_quality), AV_OPT_TYPE_INT, { .i64 = 4 }, 0, 6, VE }, { "mpeg_quant", "Use MPEG quantizers instead of H.263", OFFSET(mpeg_quant), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, { NULL }, }; @@ -963,4 +934,5 @@ AVCodec ff_libxvid_encoder = { .priv_class = &xvid_class, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, + .wrapper_name = "libxvid", }; diff --git a/libavcodec/libzvbi-teletextdec.c b/libavcodec/libzvbi-teletextdec.c index 687b6af1293b0..30d05934305f2 100644 --- a/libavcodec/libzvbi-teletextdec.c +++ b/libavcodec/libzvbi-teletextdec.c @@ -573,4 +573,5 @@ AVCodec ff_libzvbi_teletext_decoder = { .capabilities = AV_CODEC_CAP_DELAY, .flush = teletext_flush, .priv_class= &teletext_class, + .wrapper_name = "libzvbi", }; diff --git a/libavcodec/lossless_videodsp.c b/libavcodec/lossless_videodsp.c index b5b96e612966d..cff94c234ddf1 100644 --- a/libavcodec/lossless_videodsp.c +++ b/libavcodec/lossless_videodsp.c @@ -98,6 +98,16 @@ static int add_left_pred_int16_c(uint16_t *dst, const uint16_t *src, unsigned ma return acc; } +static void add_gradient_pred_c(uint8_t *src, const ptrdiff_t stride, const ptrdiff_t width){ + int A, B, C, i; + + for (i = 0; i < width; i++) { + A = src[i - stride]; + B = src[i - (stride + 1)]; + C = src[i - 1]; + src[i] = (A - B + C + src[i]) & 0xFF; + } +} void ff_llviddsp_init(LLVidDSPContext *c) { @@ -106,6 +116,7 @@ void ff_llviddsp_init(LLVidDSPContext *c) c->add_left_pred = add_left_pred_c; c->add_left_pred_int16 = add_left_pred_int16_c; + c->add_gradient_pred = add_gradient_pred_c; if (ARCH_PPC) ff_llviddsp_init_ppc(c); diff --git a/libavcodec/lossless_videodsp.h b/libavcodec/lossless_videodsp.h index cecf0fe1e5186..8077898d1a7ad 100644 --- a/libavcodec/lossless_videodsp.h +++ b/libavcodec/lossless_videodsp.h @@ -29,7 +29,7 @@ #include "libavutil/cpu.h" typedef struct LLVidDSPContext { - void (*add_bytes)(uint8_t *dst /* align 16 */, uint8_t *src /* align 16 */, + void (*add_bytes)(uint8_t *dst /* align 32 */, uint8_t *src /* align 32 */, ptrdiff_t w); void (*add_median_pred)(uint8_t *dst, const uint8_t *top, const uint8_t *diff, ptrdiff_t w, @@ -39,6 +39,7 @@ typedef struct LLVidDSPContext { int (*add_left_pred_int16)(uint16_t *dst, const uint16_t *src, unsigned mask, ptrdiff_t w, unsigned left); + void (*add_gradient_pred)(uint8_t *src /* align 32 */, const ptrdiff_t stride, const ptrdiff_t width); } LLVidDSPContext; void ff_llviddsp_init(LLVidDSPContext *llviddsp); diff --git a/libavcodec/lossless_videoencdsp.c b/libavcodec/lossless_videoencdsp.c index 5cc4934c0ef6a..ed70329628aec 100644 --- a/libavcodec/lossless_videoencdsp.c +++ b/libavcodec/lossless_videoencdsp.c @@ -74,10 +74,25 @@ static void sub_median_pred_c(uint8_t *dst, const uint8_t *src1, *left_top = lt; } +static void sub_left_predict_c(uint8_t *dst, uint8_t *src, + ptrdiff_t stride, ptrdiff_t width, int height) +{ + int i, j; + uint8_t prev = 0x80; /* Set the initial value */ + for (j = 0; j < height; j++) { + for (i = 0; i < width; i++) { + *dst++ = src[i] - prev; + prev = src[i]; + } + src += stride; + } +} + av_cold void ff_llvidencdsp_init(LLVidEncDSPContext *c) { c->diff_bytes = diff_bytes_c; c->sub_median_pred = sub_median_pred_c; + c->sub_left_predict = sub_left_predict_c; if (ARCH_X86) ff_llvidencdsp_init_x86(c); diff --git a/libavcodec/lossless_videoencdsp.h b/libavcodec/lossless_videoencdsp.h index 3d645b159adfc..faa6c325512c0 100644 --- a/libavcodec/lossless_videoencdsp.h +++ b/libavcodec/lossless_videoencdsp.h @@ -21,6 +21,8 @@ #include +#include "avcodec.h" + typedef struct LLVidEncDSPContext { void (*diff_bytes)(uint8_t *dst /* align 16 */, const uint8_t *src1 /* align 16 */, @@ -33,6 +35,9 @@ typedef struct LLVidEncDSPContext { void (*sub_median_pred)(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, intptr_t w, int *left, int *left_top); + + void (*sub_left_predict)(uint8_t *dst, uint8_t *src, + ptrdiff_t stride, ptrdiff_t width, int height); } LLVidEncDSPContext; void ff_llvidencdsp_init(LLVidEncDSPContext *c); diff --git a/libavcodec/magicyuv.c b/libavcodec/magicyuv.c index 3c1a89077bf56..9c6e1ba1b1483 100644 --- a/libavcodec/magicyuv.c +++ b/libavcodec/magicyuv.c @@ -280,11 +280,9 @@ static int magy_decode_slice10(AVCodecContext *avctx, void *tdata, case GRADIENT: dst = (uint16_t *)p->data[i] + j * sheight * stride; s->llviddsp.add_left_pred_int16(dst, dst, max, width, 0); - left = lefttop = 0; dst += stride; if (interlaced) { s->llviddsp.add_left_pred_int16(dst, dst, max, width, 0); - left = lefttop = 0; dst += stride; } for (k = 1 + interlaced; k < height; k++) { @@ -302,14 +300,13 @@ static int magy_decode_slice10(AVCodecContext *avctx, void *tdata, break; case MEDIAN: dst = (uint16_t *)p->data[i] + j * sheight * stride; - lefttop = left = dst[0]; s->llviddsp.add_left_pred_int16(dst, dst, max, width, 0); dst += stride; if (interlaced) { - lefttop = left = dst[0]; s->llviddsp.add_left_pred_int16(dst, dst, max, width, 0); dst += stride; } + lefttop = left = dst[0]; for (k = 1 + interlaced; k < height; k++) { magicyuv_median_pred16(dst, dst - fake_stride, dst, width, &left, &lefttop, max); lefttop = left = dst[0]; @@ -348,7 +345,7 @@ static int magy_decode_slice(AVCodecContext *avctx, void *tdata, MagicYUVContext *s = avctx->priv_data; int interlaced = s->interlaced; AVFrame *p = s->p; - int i, k, x; + int i, k, x, min_width; GetBitContext gb; uint8_t *dst; @@ -411,36 +408,36 @@ static int magy_decode_slice(AVCodecContext *avctx, void *tdata, case GRADIENT: dst = p->data[i] + j * sheight * stride; s->llviddsp.add_left_pred(dst, dst, width, 0); - left = lefttop = 0; dst += stride; if (interlaced) { s->llviddsp.add_left_pred(dst, dst, width, 0); - left = lefttop = 0; dst += stride; } + min_width = FFMIN(width, 32); for (k = 1 + interlaced; k < height; k++) { top = dst[-fake_stride]; left = top + dst[0]; dst[0] = left; - for (x = 1; x < width; x++) { + for (x = 1; x < min_width; x++) { /* dsp need aligned 32 */ top = dst[x - fake_stride]; lefttop = dst[x - (fake_stride + 1)]; left += top - lefttop + dst[x]; dst[x] = left; } + if (width > 32) + s->llviddsp.add_gradient_pred(dst + 32, fake_stride, width - 32); dst += stride; } break; case MEDIAN: dst = p->data[i] + j * sheight * stride; - lefttop = left = dst[0]; s->llviddsp.add_left_pred(dst, dst, width, 0); dst += stride; if (interlaced) { - lefttop = left = dst[0]; s->llviddsp.add_left_pred(dst, dst, width, 0); dst += stride; } + lefttop = left = dst[0]; for (k = 1 + interlaced; k < height; k++) { s->llviddsp.add_median_pred(dst, dst - fake_stride, dst, width, &left, &lefttop); diff --git a/libavcodec/magicyuvenc.c b/libavcodec/magicyuvenc.c new file mode 100644 index 0000000000000..bbfb8d0c6cf35 --- /dev/null +++ b/libavcodec/magicyuvenc.c @@ -0,0 +1,558 @@ +/* + * MagicYUV encoder + * Copyright (c) 2017 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "libavutil/qsort.h" + +#include "avcodec.h" +#include "bytestream.h" +#include "put_bits.h" +#include "internal.h" +#include "thread.h" +#include "lossless_videoencdsp.h" + +typedef enum Prediction { + LEFT = 1, + GRADIENT, + MEDIAN, +} Prediction; + +typedef struct HuffEntry { + uint8_t sym; + uint8_t len; + uint32_t code; +} HuffEntry; + +typedef struct PTable { + int value; ///< input value + int64_t prob; ///< number of occurences of this value in input +} PTable; + +typedef struct MagicYUVContext { + const AVClass *class; + int frame_pred; + PutBitContext pb; + int planes; + uint8_t format; + AVFrame *p; + int max; + int slice_height; + int nb_slices; + int correlate; + int hshift[4]; + int vshift[4]; + uint8_t *slices[4]; + unsigned slice_pos[4]; + unsigned tables_size; + HuffEntry he[4][256]; + LLVidEncDSPContext llvidencdsp; + void (*predict)(struct MagicYUVContext *s, uint8_t *src, uint8_t *dst, + ptrdiff_t stride, int width, int height); +} MagicYUVContext; + +static void left_predict(MagicYUVContext *s, + uint8_t *src, uint8_t *dst, ptrdiff_t stride, + int width, int height) +{ + uint8_t prev = 0; + int i, j; + + for (i = 0; i < width; i++) { + dst[i] = src[i] - prev; + prev = src[i]; + } + dst += width; + src += stride; + for (j = 1; j < height; j++) { + prev = src[-stride]; + for (i = 0; i < width; i++) { + dst[i] = src[i] - prev; + prev = src[i]; + } + dst += width; + src += stride; + } +} + +static void gradient_predict(MagicYUVContext *s, + uint8_t *src, uint8_t *dst, ptrdiff_t stride, + int width, int height) +{ + int left = 0, top, lefttop; + int i, j; + + for (i = 0; i < width; i++) { + dst[i] = src[i] - left; + left = src[i]; + } + dst += width; + src += stride; + for (j = 1; j < height; j++) { + top = src[-stride]; + left = src[0] - top; + dst[0] = left; + for (i = 1; i < width; i++) { + top = src[i - stride]; + lefttop = src[i - (stride + 1)]; + left = src[i-1]; + dst[i] = (src[i] - top) - left + lefttop; + } + dst += width; + src += stride; + } +} + +static void median_predict(MagicYUVContext *s, + uint8_t *src, uint8_t *dst, ptrdiff_t stride, + int width, int height) +{ + int left = 0, lefttop; + int i, j; + + for (i = 0; i < width; i++) { + dst[i] = src[i] - left; + left = src[i]; + } + dst += width; + src += stride; + for (j = 1; j < height; j++) { + left = lefttop = src[-stride]; + s->llvidencdsp.sub_median_pred(dst, src - stride, src, width, &left, &lefttop); + dst += width; + src += stride; + } +} + +static av_cold int magy_encode_init(AVCodecContext *avctx) +{ + MagicYUVContext *s = avctx->priv_data; + int i; + + switch (avctx->pix_fmt) { + case AV_PIX_FMT_GBRP: + avctx->codec_tag = MKTAG('M', '8', 'R', 'G'); + s->correlate = 1; + s->format = 0x65; + break; + case AV_PIX_FMT_GBRAP: + avctx->codec_tag = MKTAG('M', '8', 'R', 'A'); + s->correlate = 1; + s->format = 0x66; + break; + case AV_PIX_FMT_YUV420P: + avctx->codec_tag = MKTAG('M', '8', 'Y', '0'); + s->hshift[1] = + s->vshift[1] = + s->hshift[2] = + s->vshift[2] = 1; + s->format = 0x69; + break; + case AV_PIX_FMT_YUV422P: + avctx->codec_tag = MKTAG('M', '8', 'Y', '2'); + s->hshift[1] = + s->hshift[2] = 1; + s->format = 0x68; + break; + case AV_PIX_FMT_YUV444P: + avctx->codec_tag = MKTAG('M', '8', 'Y', '4'); + s->format = 0x67; + break; + case AV_PIX_FMT_YUVA444P: + avctx->codec_tag = MKTAG('M', '8', 'Y', 'A'); + s->format = 0x6a; + break; + case AV_PIX_FMT_GRAY8: + avctx->codec_tag = MKTAG('M', '8', 'G', '0'); + s->format = 0x6b; + break; + default: + av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format: %d\n", + avctx->pix_fmt); + return AVERROR_INVALIDDATA; + } + + ff_llvidencdsp_init(&s->llvidencdsp); + + s->planes = av_pix_fmt_count_planes(avctx->pix_fmt); + + s->nb_slices = 1; + + for (i = 0; i < s->planes; i++) { + s->slices[i] = av_malloc(avctx->width * (avctx->height + 2) + + AV_INPUT_BUFFER_PADDING_SIZE); + if (!s->slices[i]) { + av_log(avctx, AV_LOG_ERROR, "Cannot allocate temporary buffer.\n"); + return AVERROR(ENOMEM); + } + } + + switch (s->frame_pred) { + case LEFT: s->predict = left_predict; break; + case GRADIENT: s->predict = gradient_predict; break; + case MEDIAN: s->predict = median_predict; break; + } + + return 0; +} + +static int magy_huff_cmp_len(const void *a, const void *b) +{ + const HuffEntry *aa = a, *bb = b; + return (aa->len - bb->len) * 256 + aa->sym - bb->sym; +} + +static int huff_cmp_sym(const void *a, const void *b) +{ + const HuffEntry *aa = a, *bb = b; + return bb->sym - aa->sym; +} + +static void calculate_codes(HuffEntry *he) +{ + uint32_t code; + int i; + + AV_QSORT(he, 256, HuffEntry, magy_huff_cmp_len); + + code = 1; + for (i = 255; i >= 0; i--) { + he[i].code = code >> (32 - he[i].len); + code += 0x80000000u >> (he[i].len - 1); + } + + AV_QSORT(he, 256, HuffEntry, huff_cmp_sym); +} + +static void count_usage(uint8_t *src, int width, + int height, PTable *counts) +{ + int i, j; + + for (j = 0; j < height; j++) { + for (i = 0; i < width; i++) { + counts[src[i]].prob++; + } + src += width; + } +} + +typedef struct PackageMergerList { + int nitems; ///< number of items in the list and probability ex. 4 + int item_idx[515]; ///< index range for each item in items 0, 2, 5, 9, 13 + int probability[514]; ///< probability of each item 3, 8, 18, 46 + int items[257 * 16]; ///< chain of all individual values that make up items A, B, A, B, C, A, B, C, D, C, D, D, E +} PackageMergerList; + +static int compare_by_prob(const void *a, const void *b) +{ + PTable a_val = *(PTable *)a; + PTable b_val = *(PTable *)b; + return a_val.prob - b_val.prob; +} + +static void magy_huffman_compute_bits(PTable *prob_table, HuffEntry *distincts, + int size, int max_length) +{ + PackageMergerList list_a, list_b, *to = &list_a, *from = &list_b, *temp; + int times, i, j, k; + int nbits[257] = {0}; + int min; + + av_assert0(max_length > 0); + + to->nitems = 0; + from->nitems = 0; + to->item_idx[0] = 0; + from->item_idx[0] = 0; + AV_QSORT(prob_table, size, PTable, compare_by_prob); + + for (times = 0; times <= max_length; times++) { + to->nitems = 0; + to->item_idx[0] = 0; + + j = 0; + k = 0; + + if (times < max_length) { + i = 0; + } + while (i < size || j + 1 < from->nitems) { + to->nitems++; + to->item_idx[to->nitems] = to->item_idx[to->nitems - 1]; + if (i < size && + (j + 1 >= from->nitems || + prob_table[i].prob < + from->probability[j] + from->probability[j + 1])) { + to->items[to->item_idx[to->nitems]++] = prob_table[i].value; + to->probability[to->nitems - 1] = prob_table[i].prob; + i++; + } else { + for (k = from->item_idx[j]; k < from->item_idx[j + 2]; k++) { + to->items[to->item_idx[to->nitems]++] = from->items[k]; + } + to->probability[to->nitems - 1] = + from->probability[j] + from->probability[j + 1]; + j += 2; + } + } + temp = to; + to = from; + from = temp; + } + + min = (size - 1 < from->nitems) ? size - 1 : from->nitems; + for (i = 0; i < from->item_idx[min]; i++) { + nbits[from->items[i]]++; + } + + for (i = 0; i < size; i++) { + distincts[i].sym = i; + distincts[i].len = nbits[i]; + } +} + +static int encode_table(AVCodecContext *avctx, uint8_t *dst, + int width, int height, + PutBitContext *pb, HuffEntry *he) +{ + PTable counts[256] = { {0} }; + int i; + + count_usage(dst, width, height, counts); + + for (i = 0; i < 256; i++) { + counts[i].prob++; + counts[i].value = 255 - i; + } + + magy_huffman_compute_bits(counts, he, 256, 16); + + calculate_codes(he); + + for (i = 0; i < 256; i++) { + put_bits(pb, 1, 0); + put_bits(pb, 7, he[i].len); + } + + return 0; +} + +static int encode_slice(uint8_t *src, uint8_t *dst, int dst_size, + int width, int height, HuffEntry *he, int prediction) +{ + PutBitContext pb; + int i, j; + int count; + + init_put_bits(&pb, dst, dst_size); + + put_bits(&pb, 8, 0); + put_bits(&pb, 8, prediction); + + for (j = 0; j < height; j++) { + for (i = 0; i < width; i++) { + const int idx = src[i]; + put_bits(&pb, he[idx].len, he[idx].code); + } + + src += width; + } + + count = put_bits_count(&pb) & 0x1F; + + if (count) + put_bits(&pb, 32 - count, 0); + + count = put_bits_count(&pb); + + flush_put_bits(&pb); + + return count >> 3; +} + +static int magy_encode_frame(AVCodecContext *avctx, AVPacket *pkt, + const AVFrame *frame, int *got_packet) +{ + MagicYUVContext *s = avctx->priv_data; + PutByteContext pb; + const int width = avctx->width, height = avctx->height; + int pos, slice, i, j, ret = 0; + + ret = ff_alloc_packet2(avctx, pkt, (256 + 4 * s->nb_slices + width * height) * + s->planes + 256, 0); + if (ret < 0) + return ret; + + bytestream2_init_writer(&pb, pkt->data, pkt->size); + bytestream2_put_le32(&pb, MKTAG('M', 'A', 'G', 'Y')); + bytestream2_put_le32(&pb, 32); + bytestream2_put_byte(&pb, 7); + bytestream2_put_byte(&pb, s->format); + bytestream2_put_byte(&pb, 0); + bytestream2_put_byte(&pb, 0); + bytestream2_put_le32(&pb, 0); + + bytestream2_put_le32(&pb, avctx->width); + bytestream2_put_le32(&pb, avctx->height); + bytestream2_put_le32(&pb, avctx->width); + bytestream2_put_le32(&pb, avctx->height); + bytestream2_put_le32(&pb, 0); + + for (i = 0; i < s->planes; i++) { + bytestream2_put_le32(&pb, 0); + for (j = 1; j < s->nb_slices; j++) { + bytestream2_put_le32(&pb, 0); + } + } + + bytestream2_put_byte(&pb, s->planes); + + for (i = 0; i < s->planes; i++) { + for (slice = 0; slice < s->nb_slices; slice++) { + bytestream2_put_byte(&pb, i); + } + } + + if (s->correlate) { + uint8_t *r, *g, *b; + AVFrame *p = av_frame_clone(frame); + + g = p->data[0]; + b = p->data[1]; + r = p->data[2]; + + for (i = 0; i < height; i++) { + s->llvidencdsp.diff_bytes(b, b, g, width); + s->llvidencdsp.diff_bytes(r, r, g, width); + g += p->linesize[0]; + b += p->linesize[1]; + r += p->linesize[2]; + } + + FFSWAP(uint8_t*, p->data[0], p->data[1]); + FFSWAP(int, p->linesize[0], p->linesize[1]); + + for (i = 0; i < s->planes; i++) { + for (slice = 0; slice < s->nb_slices; slice++) { + s->predict(s, p->data[i], s->slices[i], p->linesize[i], + p->width, p->height); + } + } + + av_frame_free(&p); + } else { + for (i = 0; i < s->planes; i++) { + for (slice = 0; slice < s->nb_slices; slice++) { + s->predict(s, frame->data[i], s->slices[i], frame->linesize[i], + AV_CEIL_RSHIFT(frame->width, s->hshift[i]), + AV_CEIL_RSHIFT(frame->height, s->vshift[i])); + } + } + } + + init_put_bits(&s->pb, pkt->data + bytestream2_tell_p(&pb), bytestream2_get_bytes_left_p(&pb)); + + for (i = 0; i < s->planes; i++) { + encode_table(avctx, s->slices[i], + AV_CEIL_RSHIFT(frame->width, s->hshift[i]), + AV_CEIL_RSHIFT(frame->height, s->vshift[i]), + &s->pb, s->he[i]); + } + s->tables_size = (put_bits_count(&s->pb) + 7) >> 3; + bytestream2_skip_p(&pb, s->tables_size); + + for (i = 0; i < s->planes; i++) { + unsigned slice_size; + + s->slice_pos[i] = bytestream2_tell_p(&pb); + slice_size = encode_slice(s->slices[i], pkt->data + bytestream2_tell_p(&pb), + bytestream2_get_bytes_left_p(&pb), + AV_CEIL_RSHIFT(frame->width, s->hshift[i]), + AV_CEIL_RSHIFT(frame->height, s->vshift[i]), + s->he[i], s->frame_pred); + bytestream2_skip_p(&pb, slice_size); + } + + pos = bytestream2_tell_p(&pb); + bytestream2_seek_p(&pb, 32, SEEK_SET); + bytestream2_put_le32(&pb, s->slice_pos[0] - 32); + for (i = 0; i < s->planes; i++) { + bytestream2_put_le32(&pb, s->slice_pos[i] - 32); + } + bytestream2_seek_p(&pb, pos, SEEK_SET); + + pkt->size = bytestream2_tell_p(&pb); + pkt->flags |= AV_PKT_FLAG_KEY; + + *got_packet = 1; + + return 0; +} + +static av_cold int magy_encode_close(AVCodecContext *avctx) +{ + MagicYUVContext *s = avctx->priv_data; + int i; + + for (i = 0; i < s->planes; i++) + av_freep(&s->slices[i]); + + return 0; +} + +#define OFFSET(x) offsetof(MagicYUVContext, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + { "pred", "Prediction method", OFFSET(frame_pred), AV_OPT_TYPE_INT, {.i64=LEFT}, LEFT, MEDIAN, VE, "pred" }, + { "left", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LEFT }, 0, 0, VE, "pred" }, + { "gradient", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = GRADIENT }, 0, 0, VE, "pred" }, + { "median", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MEDIAN }, 0, 0, VE, "pred" }, + { NULL}, +}; + +static const AVClass magicyuv_class = { + .class_name = "magicyuv", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_magicyuv_encoder = { + .name = "magicyuv", + .long_name = NULL_IF_CONFIG_SMALL("MagicYUV video"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_MAGICYUV, + .priv_data_size = sizeof(MagicYUVContext), + .priv_class = &magicyuv_class, + .init = magy_encode_init, + .close = magy_encode_close, + .encode2 = magy_encode_frame, + .capabilities = AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_INTRA_ONLY | AV_CODEC_CAP_EXPERIMENTAL, + .pix_fmts = (const enum AVPixelFormat[]) { + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_YUV422P, + AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_GRAY8, + AV_PIX_FMT_NONE + }, +}; diff --git a/libavcodec/mdct_fixed.c b/libavcodec/mdct_fixed.c index a32cb00ca0360..aabf0c88f8da0 100644 --- a/libavcodec/mdct_fixed.c +++ b/libavcodec/mdct_fixed.c @@ -39,13 +39,13 @@ void ff_mdct_calcw_c(FFTContext *s, FFTDouble *out, const FFTSample *input) /* pre rotation */ for(i=0;i> 6) +# define RSCALE(x, y) ((int)((x) + (unsigned)(y) + 32) >> 6) #else /* FFT_FIXED_32 */ -# define RSCALE(x) ((x) >> 1) +# define RSCALE(x, y) ((int)((x) + (unsigned)(y)) >> 1) #endif /* FFT_FIXED_32 */ #endif @@ -181,13 +181,13 @@ void ff_mdct_calc_c(FFTContext *s, FFTSample *out, const FFTSample *input) /* pre rotation */ for(i=0;iblock_last_index[0 /* FIXME */] = s->fast_dct_quantize(s, temp, 0 /* FIXME */, s->qscale, &i); s->dct_unquantize_inter(s, temp, 0, s->qscale); - ff_simple_idct_8(temp); // FIXME + ff_simple_idct_int16_8bit(temp); // FIXME for (i = 0; i < 64; i++) sum += (temp[i] - bak[i]) * (temp[i] - bak[i]); @@ -977,14 +1011,6 @@ WRAPPER8_16_SQ(quant_psnr8x8_c, quant_psnr16_c) WRAPPER8_16_SQ(rd8x8_c, rd16_c) WRAPPER8_16_SQ(bit8x8_c, bit16_c) -av_cold void ff_me_cmp_init_static(void) -{ - int i; - - for (i = 0; i < 512; i++) - ff_square_tab[i] = (i - 256) * (i - 256); -} - int ff_check_alignment(void) { static int did_fail = 0; diff --git a/libavcodec/me_cmp.h b/libavcodec/me_cmp.h index 0dbbcbb1d9a58..0a589e3c3da1d 100644 --- a/libavcodec/me_cmp.h +++ b/libavcodec/me_cmp.h @@ -23,7 +23,7 @@ #include "avcodec.h" -extern uint32_t ff_square_tab[512]; +extern const uint32_t ff_square_tab[512]; /* minimum alignment rules ;) @@ -79,8 +79,6 @@ typedef struct MECmpContext { me_cmp_func median_sad[6]; } MECmpContext; -void ff_me_cmp_init_static(void); - int ff_check_alignment(void); void ff_me_cmp_init(MECmpContext *c, AVCodecContext *avctx); diff --git a/libavcodec/mediacodec.c b/libavcodec/mediacodec.c index 610bb49a733ba..b0aae43a879d0 100644 --- a/libavcodec/mediacodec.c +++ b/libavcodec/mediacodec.c @@ -26,7 +26,7 @@ #include "mediacodec.h" -#if CONFIG_H264_MEDIACODEC_HWACCEL +#if CONFIG_MEDIACODEC #include @@ -91,7 +91,11 @@ int av_mediacodec_release_buffer(AVMediaCodecBuffer *buffer, int render) MediaCodecDecContext *ctx = buffer->ctx; int released = atomic_fetch_add(&buffer->released, 1); - if (!released) { + if (!released && (ctx->delay_flush || buffer->serial == atomic_load(&ctx->serial))) { + atomic_fetch_sub(&ctx->hw_buffer_count, 1); + av_log(ctx->avctx, AV_LOG_DEBUG, + "Releasing output buffer %zd (%p) ts=%"PRId64" with render=%d [%d pending]\n", + buffer->index, buffer, buffer->pts, render, atomic_load(&ctx->hw_buffer_count)); return ff_AMediaCodec_releaseOutputBuffer(ctx->codec, buffer->index, render); } diff --git a/libavcodec/mediacodec_wrapper.c b/libavcodec/mediacodec_wrapper.c index f34450a6d8fd1..9bf96e9383678 100644 --- a/libavcodec/mediacodec_wrapper.c +++ b/libavcodec/mediacodec_wrapper.c @@ -111,6 +111,8 @@ struct JNIAMediaFormatFields { jmethodID init_id; + jmethodID contains_key_id; + jmethodID get_integer_id; jmethodID get_long_id; jmethodID get_float_id; @@ -132,6 +134,8 @@ static const struct FFJniField jni_amediaformat_mapping[] = { { "android/media/MediaFormat", "", "()V", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, init_id), 1 }, + { "android/media/MediaFormat", "containsKey", "(Ljava/lang/String;)Z", FF_JNI_METHOD,offsetof(struct JNIAMediaFormatFields, contains_key_id), 1 }, + { "android/media/MediaFormat", "getInteger", "(Ljava/lang/String;)I", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, get_integer_id), 1 }, { "android/media/MediaFormat", "getLong", "(Ljava/lang/String;)J", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, get_long_id), 1 }, { "android/media/MediaFormat", "getFloat", "(Ljava/lang/String;)F", FF_JNI_METHOD, offsetof(struct JNIAMediaFormatFields, get_float_id), 1 }, @@ -152,7 +156,7 @@ static const struct FFJniField jni_amediaformat_mapping[] = { static const AVClass amediaformat_class = { .class_name = "amediaformat", .item_name = av_default_item_name, - .version = LIBAVCODEC_VERSION_INT, + .version = LIBAVUTIL_VERSION_INT, }; struct FFAMediaFormat { @@ -264,7 +268,7 @@ static const struct FFJniField jni_amediacodec_mapping[] = { static const AVClass amediacodec_class = { .class_name = "amediacodec", .item_name = av_default_item_name, - .version = LIBAVCODEC_VERSION_INT, + .version = LIBAVUTIL_VERSION_INT, }; struct FFAMediaCodec { @@ -274,6 +278,7 @@ struct FFAMediaCodec { struct JNIAMediaCodecFields jfields; jobject object; + jobject buffer_info; jobject input_buffers; jobject output_buffers; @@ -464,7 +469,12 @@ char *ff_AMediaCodecList_getCodecNameByType(const char *mime, int profile, int e goto done; } - if (strstr(name, "OMX.google")) { + /* Skip software decoders */ + if ( + strstr(name, "OMX.google") || + strstr(name, "OMX.ffmpeg") || + (strstr(name, "OMX.SEC") && strstr(name, ".sw.")) || + !strcmp(name, "OMX.qcom.video.decoder.hevcswvdec")) { av_freep(&name); goto done_with_type; } @@ -737,6 +747,7 @@ int ff_AMediaFormat_getInt32(FFAMediaFormat* format, const char *name, int32_t * JNIEnv *env = NULL; jstring key = NULL; + jboolean contains_key; av_assert0(format != NULL); @@ -748,6 +759,12 @@ int ff_AMediaFormat_getInt32(FFAMediaFormat* format, const char *name, int32_t * goto fail; } + contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key); + if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) { + ret = 0; + goto fail; + } + *out = (*env)->CallIntMethod(env, format->object, format->jfields.get_integer_id, key); if ((ret = ff_jni_exception_check(env, 1, format)) < 0) { ret = 0; @@ -769,6 +786,7 @@ int ff_AMediaFormat_getInt64(FFAMediaFormat* format, const char *name, int64_t * JNIEnv *env = NULL; jstring key = NULL; + jboolean contains_key; av_assert0(format != NULL); @@ -780,6 +798,12 @@ int ff_AMediaFormat_getInt64(FFAMediaFormat* format, const char *name, int64_t * goto fail; } + contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key); + if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) { + ret = 0; + goto fail; + } + *out = (*env)->CallLongMethod(env, format->object, format->jfields.get_long_id, key); if ((ret = ff_jni_exception_check(env, 1, format)) < 0) { ret = 0; @@ -801,6 +825,7 @@ int ff_AMediaFormat_getFloat(FFAMediaFormat* format, const char *name, float *ou JNIEnv *env = NULL; jstring key = NULL; + jboolean contains_key; av_assert0(format != NULL); @@ -812,6 +837,12 @@ int ff_AMediaFormat_getFloat(FFAMediaFormat* format, const char *name, float *ou goto fail; } + contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key); + if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) { + ret = 0; + goto fail; + } + *out = (*env)->CallFloatMethod(env, format->object, format->jfields.get_float_id, key); if ((ret = ff_jni_exception_check(env, 1, format)) < 0) { ret = 0; @@ -833,6 +864,7 @@ int ff_AMediaFormat_getBuffer(FFAMediaFormat* format, const char *name, void** d JNIEnv *env = NULL; jstring key = NULL; + jboolean contains_key; jobject result = NULL; av_assert0(format != NULL); @@ -845,6 +877,12 @@ int ff_AMediaFormat_getBuffer(FFAMediaFormat* format, const char *name, void** d goto fail; } + contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key); + if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) { + ret = 0; + goto fail; + } + result = (*env)->CallObjectMethod(env, format->object, format->jfields.get_bytebuffer_id, key); if ((ret = ff_jni_exception_check(env, 1, format)) < 0) { ret = 0; @@ -884,6 +922,7 @@ int ff_AMediaFormat_getString(FFAMediaFormat* format, const char *name, const ch JNIEnv *env = NULL; jstring key = NULL; + jboolean contains_key; jstring result = NULL; av_assert0(format != NULL); @@ -896,6 +935,12 @@ int ff_AMediaFormat_getString(FFAMediaFormat* format, const char *name, const ch goto fail; } + contains_key = (*env)->CallBooleanMethod(env, format->object, format->jfields.contains_key_id, key); + if (!contains_key || (ret = ff_jni_exception_check(env, 1, format)) < 0) { + ret = 0; + goto fail; + } + result = (*env)->CallObjectMethod(env, format->object, format->jfields.get_string_id, key); if ((ret = ff_jni_exception_check(env, 1, format)) < 0) { ret = 0; @@ -1132,13 +1177,19 @@ static int codec_init_static_fields(FFAMediaCodec *codec) return ret; } -FFAMediaCodec* ff_AMediaCodec_createCodecByName(const char *name) +#define CREATE_CODEC_BY_NAME 0 +#define CREATE_DECODER_BY_TYPE 1 +#define CREATE_ENCODER_BY_TYPE 2 + +static inline FFAMediaCodec *codec_create(int method, const char *arg) { int ret = -1; JNIEnv *env = NULL; FFAMediaCodec *codec = NULL; - jstring codec_name = NULL; + jstring jarg = NULL; jobject object = NULL; + jobject buffer_info = NULL; + jmethodID create_id = NULL; codec = av_mallocz(sizeof(FFAMediaCodec)); if (!codec) { @@ -1156,12 +1207,23 @@ FFAMediaCodec* ff_AMediaCodec_createCodecByName(const char *name) goto fail; } - codec_name = ff_jni_utf_chars_to_jstring(env, name, codec); - if (!codec_name) { + jarg = ff_jni_utf_chars_to_jstring(env, arg, codec); + if (!jarg) { goto fail; } - object = (*env)->CallStaticObjectMethod(env, codec->jfields.mediacodec_class, codec->jfields.create_by_codec_name_id, codec_name); + switch (method) { + case CREATE_CODEC_BY_NAME: create_id = codec->jfields.create_by_codec_name_id; break; + case CREATE_DECODER_BY_TYPE: create_id = codec->jfields.create_decoder_by_type_id; break; + case CREATE_ENCODER_BY_TYPE: create_id = codec->jfields.create_encoder_by_type_id; break; + default: + av_assert0(0); + } + + object = (*env)->CallStaticObjectMethod(env, + codec->jfields.mediacodec_class, + create_id, + jarg); if (ff_jni_exception_check(env, 1, codec) < 0) { goto fail; } @@ -1179,147 +1241,39 @@ FFAMediaCodec* ff_AMediaCodec_createCodecByName(const char *name) codec->has_get_i_o_buffer = 1; } - ret = 0; -fail: - if (codec_name) { - (*env)->DeleteLocalRef(env, codec_name); - } - - if (object) { - (*env)->DeleteLocalRef(env, object); - } - - if (ret < 0) { - ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec); - av_freep(&codec); - } - - return codec; -} - -FFAMediaCodec* ff_AMediaCodec_createDecoderByType(const char *mime) -{ - int ret = -1; - JNIEnv *env = NULL; - FFAMediaCodec *codec = NULL; - jstring mime_type = NULL; - jobject object = NULL; - - codec = av_mallocz(sizeof(FFAMediaCodec)); - if (!codec) { - return NULL; - } - codec->class = &amediacodec_class; - - env = ff_jni_get_env(codec); - if (!env) { - av_freep(&codec); - return NULL; - } - - if (ff_jni_init_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec) < 0) { - goto fail; - } - - mime_type = ff_jni_utf_chars_to_jstring(env, mime, codec); - if (!mime_type) { - goto fail; - } - - object = (*env)->CallStaticObjectMethod(env, codec->jfields.mediacodec_class, codec->jfields.create_decoder_by_type_id, mime_type); + buffer_info = (*env)->NewObject(env, codec->jfields.mediainfo_class, codec->jfields.init_id); if (ff_jni_exception_check(env, 1, codec) < 0) { goto fail; } - codec->object = (*env)->NewGlobalRef(env, object); - if (!codec->object) { - goto fail; - } - - if (codec_init_static_fields(codec) < 0) { + codec->buffer_info = (*env)->NewGlobalRef(env, buffer_info); + if (!codec->buffer_info) { goto fail; } - if (codec->jfields.get_input_buffer_id && codec->jfields.get_output_buffer_id) { - codec->has_get_i_o_buffer = 1; - } - ret = 0; fail: - if (mime_type) { - (*env)->DeleteLocalRef(env, mime_type); + if (jarg) { + (*env)->DeleteLocalRef(env, jarg); } if (object) { (*env)->DeleteLocalRef(env, object); } - if (ret < 0) { - ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec); - av_freep(&codec); - } - - return codec; -} - -FFAMediaCodec* ff_AMediaCodec_createEncoderByType(const char *mime) -{ - int ret = -1; - JNIEnv *env = NULL; - FFAMediaCodec *codec = NULL; - jstring mime_type = NULL; - jobject object = NULL; - - codec = av_mallocz(sizeof(FFAMediaCodec)); - if (!codec) { - return NULL; - } - codec->class = &amediacodec_class; - - env = ff_jni_get_env(codec); - if (!env) { - av_freep(&codec); - return NULL; - } - - if (ff_jni_init_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec) < 0) { - goto fail; - } - - mime_type = ff_jni_utf_chars_to_jstring(env, mime, codec); - if (!mime_type) { - goto fail; - } - - object = (*env)->CallStaticObjectMethod(env, codec->jfields.mediacodec_class, codec->jfields.create_encoder_by_type_id, mime_type); - if (ff_jni_exception_check(env, 1, codec) < 0) { - goto fail; - } - - codec->object = (*env)->NewGlobalRef(env, object); - if (!codec->object) { - goto fail; - } - - if (codec_init_static_fields(codec) < 0) { - goto fail; + if (buffer_info) { + (*env)->DeleteLocalRef(env, buffer_info); } - if (codec->jfields.get_input_buffer_id && codec->jfields.get_output_buffer_id) { - codec->has_get_i_o_buffer = 1; - } - - ret = 0; -fail: - if (mime_type) { - (*env)->DeleteLocalRef(env, mime_type); - } + if (ret < 0) { + if (codec->object) { + (*env)->DeleteGlobalRef(env, codec->object); + } - if (object) { - (*env)->DeleteLocalRef(env, object); - } + if (codec->buffer_info) { + (*env)->DeleteGlobalRef(env, codec->buffer_info); + } - if (ret < 0) { ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec); av_freep(&codec); } @@ -1327,6 +1281,16 @@ FFAMediaCodec* ff_AMediaCodec_createEncoderByType(const char *mime) return codec; } +#define DECLARE_FF_AMEDIACODEC_CREATE_FUNC(name, method) \ +FFAMediaCodec *ff_AMediaCodec_##name(const char *arg) \ +{ \ + return codec_create(method, arg); \ +} \ + +DECLARE_FF_AMEDIACODEC_CREATE_FUNC(createCodecByName, CREATE_CODEC_BY_NAME) +DECLARE_FF_AMEDIACODEC_CREATE_FUNC(createDecoderByType, CREATE_DECODER_BY_TYPE) +DECLARE_FF_AMEDIACODEC_CREATE_FUNC(createEncoderByType, CREATE_ENCODER_BY_TYPE) + int ff_AMediaCodec_delete(FFAMediaCodec* codec) { int ret = 0; @@ -1347,6 +1311,9 @@ int ff_AMediaCodec_delete(FFAMediaCodec* codec) (*env)->DeleteGlobalRef(env, codec->object); codec->object = NULL; + (*env)->DeleteGlobalRef(env, codec->buffer_info); + codec->buffer_info = NULL; + ff_jni_reset_jfields(env, &codec->jfields, jni_amediacodec_mapping, 1, codec); av_freep(&codec); @@ -1514,48 +1481,31 @@ ssize_t ff_AMediaCodec_dequeueOutputBuffer(FFAMediaCodec* codec, FFAMediaCodecBu int ret = 0; JNIEnv *env = NULL; - jobject mediainfo = NULL; - JNI_GET_ENV_OR_RETURN(env, codec, AVERROR_EXTERNAL); - mediainfo = (*env)->NewObject(env, codec->jfields.mediainfo_class, codec->jfields.init_id); + ret = (*env)->CallIntMethod(env, codec->object, codec->jfields.dequeue_output_buffer_id, codec->buffer_info, timeoutUs); if (ff_jni_exception_check(env, 1, codec) < 0) { - ret = AVERROR_EXTERNAL; - goto fail; + return AVERROR_EXTERNAL; } - ret = (*env)->CallIntMethod(env, codec->object, codec->jfields.dequeue_output_buffer_id, mediainfo, timeoutUs); + info->flags = (*env)->GetIntField(env, codec->buffer_info, codec->jfields.flags_id); if (ff_jni_exception_check(env, 1, codec) < 0) { - ret = AVERROR_EXTERNAL; - goto fail; + return AVERROR_EXTERNAL; } - info->flags = (*env)->GetIntField(env, mediainfo, codec->jfields.flags_id); + info->offset = (*env)->GetIntField(env, codec->buffer_info, codec->jfields.offset_id); if (ff_jni_exception_check(env, 1, codec) < 0) { - ret = AVERROR_EXTERNAL; - goto fail; + return AVERROR_EXTERNAL; } - info->offset = (*env)->GetIntField(env, mediainfo, codec->jfields.offset_id); + info->presentationTimeUs = (*env)->GetLongField(env, codec->buffer_info, codec->jfields.presentation_time_us_id); if (ff_jni_exception_check(env, 1, codec) < 0) { - ret = AVERROR_EXTERNAL; - goto fail; + return AVERROR_EXTERNAL; } - info->presentationTimeUs = (*env)->GetLongField(env, mediainfo, codec->jfields.presentation_time_us_id); + info->size = (*env)->GetIntField(env, codec->buffer_info, codec->jfields.size_id); if (ff_jni_exception_check(env, 1, codec) < 0) { - ret = AVERROR_EXTERNAL; - goto fail; - } - - info->size = (*env)->GetIntField(env, mediainfo, codec->jfields.size_id); - if (ff_jni_exception_check(env, 1, codec) < 0) { - ret = AVERROR_EXTERNAL; - goto fail; - } -fail: - if (mediainfo) { - (*env)->DeleteLocalRef(env, mediainfo); + return AVERROR_EXTERNAL; } return ret; diff --git a/libavcodec/mediacodecdec.c b/libavcodec/mediacodecdec.c index 6962ce2474f52..0d4a853f078c0 100644 --- a/libavcodec/mediacodecdec.c +++ b/libavcodec/mediacodecdec.c @@ -25,26 +25,30 @@ #include "libavutil/avassert.h" #include "libavutil/common.h" -#include "libavutil/fifo.h" #include "libavutil/opt.h" #include "libavutil/intreadwrite.h" #include "libavutil/pixfmt.h" +#include "libavutil/internal.h" #include "avcodec.h" +#include "decode.h" #include "h264_parse.h" #include "hevc_parse.h" +#include "hwaccel.h" #include "internal.h" #include "mediacodec_wrapper.h" #include "mediacodecdec_common.h" typedef struct MediaCodecH264DecContext { - MediaCodecDecContext *ctx; + AVClass *avclass; - AVFifoBuffer *fifo; + MediaCodecDecContext *ctx; AVPacket buffered_pkt; + int delay_flush; + } MediaCodecH264DecContext; static av_cold int mediacodec_decode_close(AVCodecContext *avctx) @@ -54,8 +58,6 @@ static av_cold int mediacodec_decode_close(AVCodecContext *avctx) ff_mediacodec_dec_close(avctx, s->ctx); s->ctx = NULL; - av_fifo_free(s->fifo); - av_packet_unref(&s->buffered_pkt); return 0; @@ -182,7 +184,7 @@ static int hevc_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format) int ret; HEVCParamSets ps; - HEVCSEIContext sei; + HEVCSEI sei; const HEVCVPS *vps = NULL; const HEVCPPS *pps = NULL; @@ -256,6 +258,8 @@ static int hevc_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format) } done: + ff_hevc_ps_uninit(&ps); + av_freep(&vps_data); av_freep(&sps_data); av_freep(&pps_data); @@ -264,34 +268,11 @@ static int hevc_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format) } #endif -#if CONFIG_MPEG2_MEDIACODEC_DECODER -static int mpeg2_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format) -{ - int ret = 0; - - if (avctx->extradata) { - ff_AMediaFormat_setBuffer(format, "csd-0", avctx->extradata, avctx->extradata_size); - } - - return ret; -} -#endif - -#if CONFIG_MPEG4_MEDIACODEC_DECODER -static int mpeg4_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format) -{ - int ret = 0; - - if (avctx->extradata) { - ff_AMediaFormat_setBuffer(format, "csd-0", avctx->extradata, avctx->extradata_size); - } - - return ret; -} -#endif - -#if CONFIG_VP8_MEDIACODEC_DECODER || CONFIG_VP9_MEDIACODEC_DECODER -static int vpx_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format) +#if CONFIG_MPEG2_MEDIACODEC_DECODER || \ + CONFIG_MPEG4_MEDIACODEC_DECODER || \ + CONFIG_VP8_MEDIACODEC_DECODER || \ + CONFIG_VP9_MEDIACODEC_DECODER +static int common_set_extradata(AVCodecContext *avctx, FFAMediaFormat *format) { int ret = 0; @@ -342,7 +323,7 @@ static av_cold int mediacodec_decode_init(AVCodecContext *avctx) case AV_CODEC_ID_MPEG2VIDEO: codec_mime = "video/mpeg2"; - ret = mpeg2_set_extradata(avctx, format); + ret = common_set_extradata(avctx, format); if (ret < 0) goto done; break; @@ -351,7 +332,7 @@ static av_cold int mediacodec_decode_init(AVCodecContext *avctx) case AV_CODEC_ID_MPEG4: codec_mime = "video/mp4v-es", - ret = mpeg4_set_extradata(avctx, format); + ret = common_set_extradata(avctx, format); if (ret < 0) goto done; break; @@ -360,7 +341,7 @@ static av_cold int mediacodec_decode_init(AVCodecContext *avctx) case AV_CODEC_ID_VP8: codec_mime = "video/x-vnd.on2.vp8"; - ret = vpx_set_extradata(avctx, format); + ret = common_set_extradata(avctx, format); if (ret < 0) goto done; break; @@ -369,7 +350,7 @@ static av_cold int mediacodec_decode_init(AVCodecContext *avctx) case AV_CODEC_ID_VP9: codec_mime = "video/x-vnd.on2.vp9"; - ret = vpx_set_extradata(avctx, format); + ret = common_set_extradata(avctx, format); if (ret < 0) goto done; break; @@ -389,6 +370,8 @@ static av_cold int mediacodec_decode_init(AVCodecContext *avctx) goto done; } + s->ctx->delay_flush = s->delay_flush; + if ((ret = ff_mediacodec_dec_init(avctx, s->ctx, codec_mime, format)) < 0) { s->ctx = NULL; goto done; @@ -396,12 +379,6 @@ static av_cold int mediacodec_decode_init(AVCodecContext *avctx) av_log(avctx, AV_LOG_INFO, "MediaCodec started successfully, ret = %d\n", ret); - s->fifo = av_fifo_alloc(sizeof(AVPacket)); - if (!s->fifo) { - ret = AVERROR(ENOMEM); - goto done; - } - done: if (format) { ff_AMediaFormat_delete(format); @@ -414,39 +391,34 @@ static av_cold int mediacodec_decode_init(AVCodecContext *avctx) return ret; } - -static int mediacodec_process_data(AVCodecContext *avctx, AVFrame *frame, - int *got_frame, AVPacket *pkt) +static int mediacodec_send_receive(AVCodecContext *avctx, + MediaCodecH264DecContext *s, + AVFrame *frame, bool wait) { - MediaCodecH264DecContext *s = avctx->priv_data; + int ret; - return ff_mediacodec_dec_decode(avctx, s->ctx, frame, got_frame, pkt); + /* send any pending data from buffered packet */ + while (s->buffered_pkt.size) { + ret = ff_mediacodec_dec_send(avctx, s->ctx, &s->buffered_pkt); + if (ret == AVERROR(EAGAIN)) + break; + else if (ret < 0) + return ret; + s->buffered_pkt.size -= ret; + s->buffered_pkt.data += ret; + if (s->buffered_pkt.size <= 0) + av_packet_unref(&s->buffered_pkt); + } + + /* check for new frame */ + return ff_mediacodec_dec_receive(avctx, s->ctx, frame, wait); } -static int mediacodec_decode_frame(AVCodecContext *avctx, void *data, - int *got_frame, AVPacket *avpkt) +static int mediacodec_receive_frame(AVCodecContext *avctx, AVFrame *frame) { MediaCodecH264DecContext *s = avctx->priv_data; - AVFrame *frame = data; int ret; - /* buffer the input packet */ - if (avpkt->size) { - AVPacket input_pkt = { 0 }; - - if (av_fifo_space(s->fifo) < sizeof(input_pkt)) { - ret = av_fifo_realloc2(s->fifo, - av_fifo_size(s->fifo) + sizeof(input_pkt)); - if (ret < 0) - return ret; - } - - ret = av_packet_ref(&input_pkt, avpkt); - if (ret < 0) - return ret; - av_fifo_generic_write(s->fifo, &input_pkt, sizeof(input_pkt), NULL); - } - /* * MediaCodec.flush() discards both input and output buffers, thus we * need to delay the call to this function until the user has released or @@ -469,146 +441,112 @@ static int mediacodec_decode_frame(AVCodecContext *avctx, void *data, */ if (ff_mediacodec_dec_is_flushing(avctx, s->ctx)) { if (!ff_mediacodec_dec_flush(avctx, s->ctx)) { - return avpkt->size; + return AVERROR(EAGAIN); } } - /* process buffered data */ - while (!*got_frame) { - /* prepare the input data */ - if (s->buffered_pkt.size <= 0) { - av_packet_unref(&s->buffered_pkt); - - /* no more data */ - if (av_fifo_size(s->fifo) < sizeof(AVPacket)) { - return avpkt->size ? avpkt->size : - ff_mediacodec_dec_decode(avctx, s->ctx, frame, got_frame, avpkt); - } + /* flush buffered packet and check for new frame */ + ret = mediacodec_send_receive(avctx, s, frame, false); + if (ret != AVERROR(EAGAIN)) + return ret; - av_fifo_generic_read(s->fifo, &s->buffered_pkt, sizeof(s->buffered_pkt), NULL); - } + /* skip fetching new packet if we still have one buffered */ + if (s->buffered_pkt.size > 0) + return mediacodec_send_receive(avctx, s, frame, true); - ret = mediacodec_process_data(avctx, frame, got_frame, &s->buffered_pkt); + /* fetch new packet or eof */ + ret = ff_decode_get_packet(avctx, &s->buffered_pkt); + if (ret == AVERROR_EOF) { + AVPacket null_pkt = { 0 }; + ret = ff_mediacodec_dec_send(avctx, s->ctx, &null_pkt); if (ret < 0) return ret; - - s->buffered_pkt.size -= ret; - s->buffered_pkt.data += ret; } + else if (ret < 0) + return ret; - return avpkt->size; + /* crank decoder with new packet */ + return mediacodec_send_receive(avctx, s, frame, true); } static void mediacodec_decode_flush(AVCodecContext *avctx) { MediaCodecH264DecContext *s = avctx->priv_data; - while (av_fifo_size(s->fifo)) { - AVPacket pkt; - av_fifo_generic_read(s->fifo, &pkt, sizeof(pkt), NULL); - av_packet_unref(&pkt); - } - av_fifo_reset(s->fifo); - av_packet_unref(&s->buffered_pkt); ff_mediacodec_dec_flush(avctx, s->ctx); } -#if CONFIG_H264_MEDIACODEC_DECODER -AVCodec ff_h264_mediacodec_decoder = { - .name = "h264_mediacodec", - .long_name = NULL_IF_CONFIG_SMALL("H.264 Android MediaCodec decoder"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_H264, - .priv_data_size = sizeof(MediaCodecH264DecContext), - .init = mediacodec_decode_init, - .decode = mediacodec_decode_frame, - .flush = mediacodec_decode_flush, - .close = mediacodec_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, - .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS, - .bsfs = "h264_mp4toannexb", +static const AVCodecHWConfigInternal *mediacodec_hw_configs[] = { + &(const AVCodecHWConfigInternal) { + .public = { + .pix_fmt = AV_PIX_FMT_MEDIACODEC, + .methods = AV_CODEC_HW_CONFIG_METHOD_AD_HOC | + AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX, + .device_type = AV_HWDEVICE_TYPE_MEDIACODEC, + }, + .hwaccel = NULL, + }, + NULL +}; + +#define OFFSET(x) offsetof(MediaCodecH264DecContext, x) +#define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM +static const AVOption ff_mediacodec_vdec_options[] = { + { "delay_flush", "Delay flush until hw output buffers are returned to the decoder", + OFFSET(delay_flush), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, VD }, + { NULL } +}; + +#define DECLARE_MEDIACODEC_VCLASS(short_name) \ +static const AVClass ff_##short_name##_mediacodec_dec_class = { \ + .class_name = #short_name "_mediacodec", \ + .item_name = av_default_item_name, \ + .option = ff_mediacodec_vdec_options, \ + .version = LIBAVUTIL_VERSION_INT, \ }; + +#define DECLARE_MEDIACODEC_VDEC(short_name, full_name, codec_id, bsf) \ +DECLARE_MEDIACODEC_VCLASS(short_name) \ +AVCodec ff_##short_name##_mediacodec_decoder = { \ + .name = #short_name "_mediacodec", \ + .long_name = NULL_IF_CONFIG_SMALL(full_name " Android MediaCodec decoder"), \ + .type = AVMEDIA_TYPE_VIDEO, \ + .id = codec_id, \ + .priv_class = &ff_##short_name##_mediacodec_dec_class, \ + .priv_data_size = sizeof(MediaCodecH264DecContext), \ + .init = mediacodec_decode_init, \ + .receive_frame = mediacodec_receive_frame, \ + .flush = mediacodec_decode_flush, \ + .close = mediacodec_decode_close, \ + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \ + .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS, \ + .bsfs = bsf, \ + .hw_configs = mediacodec_hw_configs, \ + .wrapper_name = "mediacodec", \ +}; \ + +#if CONFIG_H264_MEDIACODEC_DECODER +DECLARE_MEDIACODEC_VDEC(h264, "H.264", AV_CODEC_ID_H264, "h264_mp4toannexb") #endif #if CONFIG_HEVC_MEDIACODEC_DECODER -AVCodec ff_hevc_mediacodec_decoder = { - .name = "hevc_mediacodec", - .long_name = NULL_IF_CONFIG_SMALL("H.265 Android MediaCodec decoder"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_HEVC, - .priv_data_size = sizeof(MediaCodecH264DecContext), - .init = mediacodec_decode_init, - .decode = mediacodec_decode_frame, - .flush = mediacodec_decode_flush, - .close = mediacodec_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, - .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS, - .bsfs = "hevc_mp4toannexb", -}; +DECLARE_MEDIACODEC_VDEC(hevc, "H.265", AV_CODEC_ID_HEVC, "hevc_mp4toannexb") #endif #if CONFIG_MPEG2_MEDIACODEC_DECODER -AVCodec ff_mpeg2_mediacodec_decoder = { - .name = "mpeg2_mediacodec", - .long_name = NULL_IF_CONFIG_SMALL("MPEG-2 Android MediaCodec decoder"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_MPEG2VIDEO, - .priv_data_size = sizeof(MediaCodecH264DecContext), - .init = mediacodec_decode_init, - .decode = mediacodec_decode_frame, - .flush = mediacodec_decode_flush, - .close = mediacodec_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, - .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS, -}; +DECLARE_MEDIACODEC_VDEC(mpeg2, "MPEG-2", AV_CODEC_ID_MPEG2VIDEO, NULL) #endif #if CONFIG_MPEG4_MEDIACODEC_DECODER -AVCodec ff_mpeg4_mediacodec_decoder = { - .name = "mpeg4_mediacodec", - .long_name = NULL_IF_CONFIG_SMALL("MPEG-4 Android MediaCodec decoder"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_MPEG4, - .priv_data_size = sizeof(MediaCodecH264DecContext), - .init = mediacodec_decode_init, - .decode = mediacodec_decode_frame, - .flush = mediacodec_decode_flush, - .close = mediacodec_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, - .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS, -}; +DECLARE_MEDIACODEC_VDEC(mpeg4, "MPEG-4", AV_CODEC_ID_MPEG4, NULL) #endif #if CONFIG_VP8_MEDIACODEC_DECODER -AVCodec ff_vp8_mediacodec_decoder = { - .name = "vp8_mediacodec", - .long_name = NULL_IF_CONFIG_SMALL("VP8 Android MediaCodec decoder"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_VP8, - .priv_data_size = sizeof(MediaCodecH264DecContext), - .init = mediacodec_decode_init, - .decode = mediacodec_decode_frame, - .flush = mediacodec_decode_flush, - .close = mediacodec_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, - .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS, -}; +DECLARE_MEDIACODEC_VDEC(vp8, "VP8", AV_CODEC_ID_VP8, NULL) #endif #if CONFIG_VP9_MEDIACODEC_DECODER -AVCodec ff_vp9_mediacodec_decoder = { - .name = "vp9_mediacodec", - .long_name = NULL_IF_CONFIG_SMALL("VP9 Android MediaCodec decoder"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_VP9, - .priv_data_size = sizeof(MediaCodecH264DecContext), - .init = mediacodec_decode_init, - .decode = mediacodec_decode_frame, - .flush = mediacodec_decode_flush, - .close = mediacodec_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING, - .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS, -}; +DECLARE_MEDIACODEC_VDEC(vp9, "VP9", AV_CODEC_ID_VP9, NULL) #endif diff --git a/libavcodec/mediacodecdec_common.c b/libavcodec/mediacodecdec_common.c index afa054f83e465..e59cf19aad8a0 100644 --- a/libavcodec/mediacodecdec_common.c +++ b/libavcodec/mediacodecdec_common.c @@ -24,6 +24,7 @@ #include #include "libavutil/common.h" +#include "libavutil/hwcontext_mediacodec.h" #include "libavutil/mem.h" #include "libavutil/log.h" #include "libavutil/pixfmt.h" @@ -177,11 +178,16 @@ static void mediacodec_buffer_release(void *opaque, uint8_t *data) MediaCodecDecContext *ctx = buffer->ctx; int released = atomic_load(&buffer->released); - if (!released) { + if (!released && (ctx->delay_flush || buffer->serial == atomic_load(&ctx->serial))) { + atomic_fetch_sub(&ctx->hw_buffer_count, 1); + av_log(ctx->avctx, AV_LOG_DEBUG, + "Releasing output buffer %zd (%p) ts=%"PRId64" on free() [%d pending]\n", + buffer->index, buffer, buffer->pts, atomic_load(&ctx->hw_buffer_count)); ff_AMediaCodec_releaseOutputBuffer(ctx->codec, buffer->index, 0); } - ff_mediacodec_dec_unref(ctx); + if (ctx->delay_flush) + ff_mediacodec_dec_unref(ctx); av_freep(&buffer); } @@ -199,6 +205,7 @@ static int mediacodec_wrap_hw_buffer(AVCodecContext *avctx, frame->width = avctx->width; frame->height = avctx->height; frame->format = avctx->pix_fmt; + frame->sample_aspect_ratio = avctx->sample_aspect_ratio; if (avctx->pkt_timebase.num && avctx->pkt_timebase.den) { frame->pts = av_rescale_q(info->presentationTimeUs, @@ -235,13 +242,20 @@ FF_ENABLE_DEPRECATION_WARNINGS } buffer->ctx = s; - ff_mediacodec_dec_ref(s); + buffer->serial = atomic_load(&s->serial); + if (s->delay_flush) + ff_mediacodec_dec_ref(s); buffer->index = index; buffer->pts = info->presentationTimeUs; frame->data[3] = (uint8_t *)buffer; + atomic_fetch_add(&s->hw_buffer_count, 1); + av_log(avctx, AV_LOG_DEBUG, + "Wrapping output buffer %zd (%p) ts=%"PRId64" [%d pending]\n", + buffer->index, buffer, buffer->pts, atomic_load(&s->hw_buffer_count)); + return 0; fail: av_freep(buffer); @@ -296,7 +310,7 @@ FF_ENABLE_DEPRECATION_WARNINGS #endif frame->pkt_dts = AV_NOPTS_VALUE; - av_log(avctx, AV_LOG_DEBUG, + av_log(avctx, AV_LOG_TRACE, "Frame: width=%d stride=%d height=%d slice-height=%d " "crop-top=%d crop-bottom=%d crop-left=%d crop-right=%d encoder=%s\n" "destination linesizes=%d,%d,%d\n" , @@ -338,11 +352,22 @@ FF_ENABLE_DEPRECATION_WARNINGS return ret; } +#define AMEDIAFORMAT_GET_INT32(name, key, mandatory) do { \ + int32_t value = 0; \ + if (ff_AMediaFormat_getInt32(s->format, key, &value)) { \ + (name) = value; \ + } else if (mandatory) { \ + av_log(avctx, AV_LOG_ERROR, "Could not get %s from format %s\n", key, format); \ + ret = AVERROR_EXTERNAL; \ + goto fail; \ + } \ +} while (0) \ + static int mediacodec_dec_parse_format(AVCodecContext *avctx, MediaCodecDecContext *s) { + int ret = 0; int width = 0; int height = 0; - int32_t value = 0; char *format = NULL; if (!s->format) { @@ -355,40 +380,16 @@ static int mediacodec_dec_parse_format(AVCodecContext *avctx, MediaCodecDecConte return AVERROR_EXTERNAL; } av_log(avctx, AV_LOG_DEBUG, "Parsing MediaFormat %s\n", format); - av_freep(&format); /* Mandatory fields */ - if (!ff_AMediaFormat_getInt32(s->format, "width", &value)) { - format = ff_AMediaFormat_toString(s->format); - av_log(avctx, AV_LOG_ERROR, "Could not get %s from format %s\n", "width", format); - av_freep(&format); - return AVERROR_EXTERNAL; - } - s->width = value; + AMEDIAFORMAT_GET_INT32(s->width, "width", 1); + AMEDIAFORMAT_GET_INT32(s->height, "height", 1); - if (!ff_AMediaFormat_getInt32(s->format, "height", &value)) { - format = ff_AMediaFormat_toString(s->format); - av_log(avctx, AV_LOG_ERROR, "Could not get %s from format %s\n", "height", format); - av_freep(&format); - return AVERROR_EXTERNAL; - } - s->height = value; + AMEDIAFORMAT_GET_INT32(s->stride, "stride", 0); + s->stride = s->stride > 0 ? s->stride : s->width; - if (!ff_AMediaFormat_getInt32(s->format, "stride", &value)) { - format = ff_AMediaFormat_toString(s->format); - av_log(avctx, AV_LOG_ERROR, "Could not get %s from format %s\n", "stride", format); - av_freep(&format); - return AVERROR_EXTERNAL; - } - s->stride = value > 0 ? value : s->width; - - if (!ff_AMediaFormat_getInt32(s->format, "slice-height", &value)) { - format = ff_AMediaFormat_toString(s->format); - av_log(avctx, AV_LOG_ERROR, "Could not get %s from format %s\n", "slice-height", format); - av_freep(&format); - return AVERROR_EXTERNAL; - } - s->slice_height = value > 0 ? value : s->height; + AMEDIAFORMAT_GET_INT32(s->slice_height, "slice-height", 0); + s->slice_height = s->slice_height > 0 ? s->slice_height : s->height; if (strstr(s->codec_name, "OMX.Nvidia.")) { s->slice_height = FFALIGN(s->height, 16); @@ -397,46 +398,46 @@ static int mediacodec_dec_parse_format(AVCodecContext *avctx, MediaCodecDecConte s->stride = avctx->width; } - if (!ff_AMediaFormat_getInt32(s->format, "color-format", &value)) { - format = ff_AMediaFormat_toString(s->format); - av_log(avctx, AV_LOG_ERROR, "Could not get %s from format %s\n", "color-format", format); - av_freep(&format); - return AVERROR_EXTERNAL; - } - s->color_format = value; - - s->pix_fmt = avctx->pix_fmt = mcdec_map_color_format(avctx, s, value); + AMEDIAFORMAT_GET_INT32(s->color_format, "color-format", 1); + avctx->pix_fmt = mcdec_map_color_format(avctx, s, s->color_format); if (avctx->pix_fmt == AV_PIX_FMT_NONE) { av_log(avctx, AV_LOG_ERROR, "Output color format is not supported\n"); - return AVERROR(EINVAL); + ret = AVERROR(EINVAL); + goto fail; } /* Optional fields */ - if (ff_AMediaFormat_getInt32(s->format, "crop-top", &value)) - s->crop_top = value; - - if (ff_AMediaFormat_getInt32(s->format, "crop-bottom", &value)) - s->crop_bottom = value; - - if (ff_AMediaFormat_getInt32(s->format, "crop-left", &value)) - s->crop_left = value; - - if (ff_AMediaFormat_getInt32(s->format, "crop-right", &value)) - s->crop_right = value; + AMEDIAFORMAT_GET_INT32(s->crop_top, "crop-top", 0); + AMEDIAFORMAT_GET_INT32(s->crop_bottom, "crop-bottom", 0); + AMEDIAFORMAT_GET_INT32(s->crop_left, "crop-left", 0); + AMEDIAFORMAT_GET_INT32(s->crop_right, "crop-right", 0); width = s->crop_right + 1 - s->crop_left; height = s->crop_bottom + 1 - s->crop_top; + AMEDIAFORMAT_GET_INT32(s->display_width, "display-width", 0); + AMEDIAFORMAT_GET_INT32(s->display_height, "display-height", 0); + + if (s->display_width && s->display_height) { + AVRational sar = av_div_q( + (AVRational){ s->display_width, s->display_height }, + (AVRational){ width, height }); + ff_set_sar(avctx, sar); + } + av_log(avctx, AV_LOG_INFO, "Output crop parameters top=%d bottom=%d left=%d right=%d, " "resulting dimensions width=%d height=%d\n", s->crop_top, s->crop_bottom, s->crop_left, s->crop_right, width, height); + av_freep(&format); return ff_set_dimensions(avctx, width, height); +fail: + av_freep(&format); + return ret; } - static int mediacodec_dec_flush_codec(AVCodecContext *avctx, MediaCodecDecContext *s) { FFAMediaCodec *codec = s->codec; @@ -447,6 +448,8 @@ static int mediacodec_dec_flush_codec(AVCodecContext *avctx, MediaCodecDecContex s->draining = 0; s->flushing = 0; s->eos = 0; + atomic_fetch_add(&s->serial, 1); + atomic_init(&s->hw_buffer_count, 0); status = ff_AMediaCodec_flush(codec); if (status < 0) { @@ -470,13 +473,27 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s, AV_PIX_FMT_NONE, }; + s->avctx = avctx; atomic_init(&s->refcount, 1); + atomic_init(&s->hw_buffer_count, 0); + atomic_init(&s->serial, 1); pix_fmt = ff_get_format(avctx, pix_fmts); if (pix_fmt == AV_PIX_FMT_MEDIACODEC) { AVMediaCodecContext *user_ctx = avctx->hwaccel_context; - if (user_ctx && user_ctx->surface) { + if (avctx->hw_device_ctx) { + AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)(avctx->hw_device_ctx->data); + if (device_ctx->type == AV_HWDEVICE_TYPE_MEDIACODEC) { + if (device_ctx->hwctx) { + AVMediaCodecDeviceContext *mediacodec_ctx = (AVMediaCodecDeviceContext *)device_ctx->hwctx; + s->surface = ff_mediacodec_surface_ref(mediacodec_ctx->surface, avctx); + av_log(avctx, AV_LOG_INFO, "Using surface %p\n", s->surface); + } + } + } + + if (!s->surface && user_ctx && user_ctx->surface) { s->surface = ff_mediacodec_surface_ref(user_ctx->surface, avctx); av_log(avctx, AV_LOG_INFO, "Using surface %p\n", s->surface); } @@ -543,23 +560,17 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx, MediaCodecDecContext *s, return ret; } -int ff_mediacodec_dec_decode(AVCodecContext *avctx, MediaCodecDecContext *s, - AVFrame *frame, int *got_frame, - AVPacket *pkt) +int ff_mediacodec_dec_send(AVCodecContext *avctx, MediaCodecDecContext *s, + AVPacket *pkt) { - int ret; int offset = 0; int need_draining = 0; uint8_t *data; ssize_t index; size_t size; FFAMediaCodec *codec = s->codec; - FFAMediaCodecBufferInfo info = { 0 }; - int status; - int64_t input_dequeue_timeout_us = INPUT_DEQUEUE_TIMEOUT_US; - int64_t output_dequeue_timeout_us = OUTPUT_DEQUEUE_TIMEOUT_US; if (s->flushing) { av_log(avctx, AV_LOG_ERROR, "Decoder is flushing and cannot accept new buffer " @@ -572,13 +583,14 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx, MediaCodecDecContext *s, } if (s->draining && s->eos) { - return 0; + return AVERROR_EOF; } while (offset < pkt->size || (need_draining && !s->draining)) { index = ff_AMediaCodec_dequeueInputBuffer(codec, input_dequeue_timeout_us); if (ff_AMediaCodec_infoTryAgainLater(codec, index)) { + av_log(avctx, AV_LOG_TRACE, "No input buffer available, try again later\n"); break; } @@ -609,13 +621,15 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx, MediaCodecDecContext *s, return AVERROR_EXTERNAL; } + av_log(avctx, AV_LOG_TRACE, + "Queued input buffer %zd size=%zd ts=%"PRIi64"\n", index, size, pts); + s->draining = 1; break; } else { int64_t pts = pkt->pts; size = FFMIN(pkt->size - offset, size); - memcpy(data, pkt->data + offset, size); offset += size; @@ -628,14 +642,38 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx, MediaCodecDecContext *s, av_log(avctx, AV_LOG_ERROR, "Failed to queue input buffer (status = %d)\n", status); return AVERROR_EXTERNAL; } + + av_log(avctx, AV_LOG_TRACE, + "Queued input buffer %zd size=%zd ts=%"PRIi64"\n", index, size, pts); } } - if (need_draining || s->draining) { + if (offset == 0) + return AVERROR(EAGAIN); + return offset; +} + +int ff_mediacodec_dec_receive(AVCodecContext *avctx, MediaCodecDecContext *s, + AVFrame *frame, bool wait) +{ + int ret; + uint8_t *data; + ssize_t index; + size_t size; + FFAMediaCodec *codec = s->codec; + FFAMediaCodecBufferInfo info = { 0 }; + int status; + int64_t output_dequeue_timeout_us = OUTPUT_DEQUEUE_TIMEOUT_US; + + if (s->draining && s->eos) { + return AVERROR_EOF; + } + + if (s->draining) { /* If the codec is flushing or need to be flushed, block for a fair * amount of time to ensure we got a frame */ output_dequeue_timeout_us = OUTPUT_DEQUEUE_BLOCK_TIMEOUT_US; - } else if (s->output_buffer_count == 0) { + } else if (s->output_buffer_count == 0 || !wait) { /* If the codec hasn't produced any frames, do not block so we * can push data to it as fast as possible, and get the first * frame */ @@ -644,9 +682,7 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx, MediaCodecDecContext *s, index = ff_AMediaCodec_dequeueOutputBuffer(codec, &info, output_dequeue_timeout_us); if (index >= 0) { - int ret; - - av_log(avctx, AV_LOG_DEBUG, "Got output buffer %zd" + av_log(avctx, AV_LOG_TRACE, "Got output buffer %zd" " offset=%" PRIi32 " size=%" PRIi32 " ts=%" PRIi64 " flags=%" PRIu32 "\n", index, info.offset, info.size, info.presentationTimeUs, info.flags); @@ -674,8 +710,8 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx, MediaCodecDecContext *s, } } - *got_frame = 1; s->output_buffer_count++; + return 0; } else { status = ff_AMediaCodec_releaseOutputBuffer(codec, index, 0); if (status < 0) { @@ -718,14 +754,14 @@ int ff_mediacodec_dec_decode(AVCodecContext *avctx, MediaCodecDecContext *s, "while draining remaining frames, output will probably lack frames\n", output_dequeue_timeout_us / 1000); } else { - av_log(avctx, AV_LOG_DEBUG, "No output buffer available, try again later\n"); + av_log(avctx, AV_LOG_TRACE, "No output buffer available, try again later\n"); } } else { av_log(avctx, AV_LOG_ERROR, "Failed to dequeue output buffer (status=%zd)\n", index); return AVERROR_EXTERNAL; } - return offset; + return AVERROR(EAGAIN); } int ff_mediacodec_dec_flush(AVCodecContext *avctx, MediaCodecDecContext *s) @@ -757,45 +793,3 @@ int ff_mediacodec_dec_is_flushing(AVCodecContext *avctx, MediaCodecDecContext *s { return s->flushing; } - -AVHWAccel ff_h264_mediacodec_hwaccel = { - .name = "mediacodec", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_H264, - .pix_fmt = AV_PIX_FMT_MEDIACODEC, -}; - -AVHWAccel ff_hevc_mediacodec_hwaccel = { - .name = "mediacodec", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_HEVC, - .pix_fmt = AV_PIX_FMT_MEDIACODEC, -}; - -AVHWAccel ff_mpeg2_mediacodec_hwaccel = { - .name = "mediacodec", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_MPEG2VIDEO, - .pix_fmt = AV_PIX_FMT_MEDIACODEC, -}; - -AVHWAccel ff_mpeg4_mediacodec_hwaccel = { - .name = "mediacodec", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_MPEG4, - .pix_fmt = AV_PIX_FMT_MEDIACODEC, -}; - -AVHWAccel ff_vp8_mediacodec_hwaccel = { - .name = "mediacodec", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_VP8, - .pix_fmt = AV_PIX_FMT_MEDIACODEC, -}; - -AVHWAccel ff_vp9_mediacodec_hwaccel = { - .name = "mediacodec", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_VP9, - .pix_fmt = AV_PIX_FMT_MEDIACODEC, -}; diff --git a/libavcodec/mediacodecdec_common.h b/libavcodec/mediacodecdec_common.h index 10f38277b54db..023d4c5fa738a 100644 --- a/libavcodec/mediacodecdec_common.h +++ b/libavcodec/mediacodecdec_common.h @@ -25,6 +25,7 @@ #include #include +#include #include #include "libavutil/frame.h" @@ -35,7 +36,9 @@ typedef struct MediaCodecDecContext { + AVCodecContext *avctx; atomic_int refcount; + atomic_int hw_buffer_count; char *codec_name; @@ -54,14 +57,18 @@ typedef struct MediaCodecDecContext { int stride; int slice_height; int color_format; - enum AVPixelFormat pix_fmt; int crop_top; int crop_bottom; int crop_left; int crop_right; + int display_width; + int display_height; uint64_t output_buffer_count; + bool delay_flush; + atomic_int serial; + } MediaCodecDecContext; int ff_mediacodec_dec_init(AVCodecContext *avctx, @@ -69,11 +76,14 @@ int ff_mediacodec_dec_init(AVCodecContext *avctx, const char *mime, FFAMediaFormat *format); -int ff_mediacodec_dec_decode(AVCodecContext *avctx, - MediaCodecDecContext *s, - AVFrame *frame, - int *got_frame, - AVPacket *pkt); +int ff_mediacodec_dec_send(AVCodecContext *avctx, + MediaCodecDecContext *s, + AVPacket *pkt); + +int ff_mediacodec_dec_receive(AVCodecContext *avctx, + MediaCodecDecContext *s, + AVFrame *frame, + bool wait); int ff_mediacodec_dec_flush(AVCodecContext *avctx, MediaCodecDecContext *s); @@ -90,6 +100,7 @@ typedef struct MediaCodecBuffer { ssize_t index; int64_t pts; atomic_int released; + int serial; } MediaCodecBuffer; diff --git a/libavcodec/mips/h264chroma_msa.c b/libavcodec/mips/h264chroma_msa.c index b8fcf6d012f47..4c257611947ab 100644 --- a/libavcodec/mips/h264chroma_msa.c +++ b/libavcodec/mips/h264chroma_msa.c @@ -839,12 +839,11 @@ static void avc_chroma_hv_8w_msa(uint8_t *src, uint8_t *dst, int32_t stride, } } -static void avc_chroma_hz_and_aver_dst_2x2_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1) +static void avc_chroma_hz_and_aver_dst_2x2_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) { uint16_t out0, out1; - uint32_t load0, load1; v16i8 src0, src1; v16u8 dst_data = { 0 }; v8u16 res_r; @@ -856,12 +855,13 @@ static void avc_chroma_hz_and_aver_dst_2x2_msa(uint8_t *src, int32_t src_stride, mask = LD_SB(&chroma_mask_arr[0]); - LD_SB2(src, src_stride, src0, src1); + LD_SB2(src, stride, src0, src1); - load0 = LW(dst); - load1 = LW(dst + dst_stride); + out0 = LH(dst); + out1 = LH(dst + stride); - INSERT_W2_UB(load0, load1, dst_data); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 0, out0); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 2, out1); src0 = __msa_vshf_b(mask, src1, src0); @@ -877,30 +877,34 @@ static void avc_chroma_hz_and_aver_dst_2x2_msa(uint8_t *src, int32_t src_stride, out1 = __msa_copy_u_h((v8i16) dst_data, 2); SH(out0, dst); - dst += dst_stride; + dst += stride; SH(out1, dst); } -static void avc_chroma_hz_and_aver_dst_2x4_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1) +static void avc_chroma_hz_and_aver_dst_2x4_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) { + uint16_t tp0, tp1, tp2, tp3; v16u8 src0, src1, src2, src3; - v16u8 dst0, dst1, dst2, dst3; + v16u8 dst0, dst_data = { 0 }; v8u16 res_r; - v16i8 res, mask; + v16i8 mask; v16i8 coeff_vec0 = __msa_fill_b(coeff0); v16i8 coeff_vec1 = __msa_fill_b(coeff1); v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); mask = LD_SB(&chroma_mask_arr[64]); - LD_UB4(src, src_stride, src0, src1, src2, src3); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 1, (v8i16) dst1); - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 2, (v8i16) dst2); - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 3, (v8i16) dst3); + LD_UB4(src, stride, src0, src1, src2, src3); + tp0 = LH(dst); + tp1 = LH(dst + stride); + tp2 = LH(dst + 2 * stride); + tp3 = LH(dst + 3 * stride); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 0, tp0); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 1, tp1); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 2, tp2); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 3, tp3); VSHF_B2_UB(src0, src1, src2, src3, mask, mask, src0, src2); @@ -911,75 +915,26 @@ static void avc_chroma_hz_and_aver_dst_2x4_msa(uint8_t *src, int32_t src_stride, res_r = (v8u16) __msa_srari_h((v8i16) res_r, 6); res_r = __msa_sat_u_h(res_r, 7); - res = __msa_pckev_b((v16i8) res_r, (v16i8) res_r); - dst0 = __msa_aver_u_b((v16u8) res, dst0); - - ST2x4_UB(dst0, 0, dst, dst_stride); -} - -static void avc_chroma_hz_and_aver_dst_2x8_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1) -{ - v16u8 src0, src1, src2, src3, src4, src5, src6, src7; - v16u8 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; - v8u16 res0_r, res1_r; - v16u8 res0, res1, mask; - v16i8 coeff_vec0 = __msa_fill_b(coeff0); - v16i8 coeff_vec1 = __msa_fill_b(coeff1); - v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); - - mask = LD_UB(&chroma_mask_arr[64]); - - LD_UB8(src, src_stride, src0, src1, src2, src3, src4, src5, src6, src7); - LD_UB8(dst, dst_stride, dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7); - - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 1, (v8i16) dst1); - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 2, (v8i16) dst2); - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 3, (v8i16) dst3); - - dst4 = (v16u8) __msa_insve_h((v8i16) dst4, 1, (v8i16) dst5); - dst4 = (v16u8) __msa_insve_h((v8i16) dst4, 2, (v8i16) dst6); - dst4 = (v16u8) __msa_insve_h((v8i16) dst4, 3, (v8i16) dst7); - - VSHF_B2_UB(src0, src1, src2, src3, mask, mask, src0, src2); - VSHF_B2_UB(src4, src5, src6, src7, mask, mask, src4, src6); - ILVR_D2_UB(src2, src0, src6, src4, src0, src4); - DOTP_UB2_UH(src0, src4, coeff_vec, coeff_vec, res0_r, res1_r); - - res0_r <<= 3; - res1_r <<= 3; - - SRARI_H2_UH(res0_r, res1_r, 6); - SAT_UH2_UH(res0_r, res1_r, 7); - PCKEV_B2_UB(res0_r, res0_r, res1_r, res1_r, res0, res1); - AVER_UB2_UB(res0, dst0, res1, dst4, dst0, dst4); + dst0 = (v16u8) __msa_pckev_b((v16i8) res_r, (v16i8) res_r); + dst0 = __msa_aver_u_b(dst0, dst_data); - ST2x4_UB(dst0, 0, dst, dst_stride); - dst += (4 * dst_stride); - ST2x4_UB(dst4, 0, dst, dst_stride); + ST2x4_UB(dst0, 0, dst, stride); } -static void avc_chroma_hz_and_aver_dst_2w_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1, - int32_t height) +static void avc_chroma_hz_and_aver_dst_2w_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1, int32_t height) { if (2 == height) { - avc_chroma_hz_and_aver_dst_2x2_msa(src, src_stride, dst, dst_stride, - coeff0, coeff1); + avc_chroma_hz_and_aver_dst_2x2_msa(src, dst, stride, coeff0, coeff1); } else if (4 == height) { - avc_chroma_hz_and_aver_dst_2x4_msa(src, src_stride, dst, dst_stride, - coeff0, coeff1); - } else if (8 == height) { - avc_chroma_hz_and_aver_dst_2x8_msa(src, src_stride, dst, dst_stride, - coeff0, coeff1); + avc_chroma_hz_and_aver_dst_2x4_msa(src, dst, stride, coeff0, coeff1); } } -static void avc_chroma_hz_and_aver_dst_4x2_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1) +static void avc_chroma_hz_and_aver_dst_4x2_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) { uint32_t load0, load1; v16i8 src0, src1; @@ -992,10 +947,9 @@ static void avc_chroma_hz_and_aver_dst_4x2_msa(uint8_t *src, int32_t src_stride, mask = LD_SB(&chroma_mask_arr[0]); - LD_SB2(src, src_stride, src0, src1); + LD_SB2(src, stride, src0, src1); - load0 = LW(dst); - load1 = LW(dst + dst_stride); + LW2(dst, stride, load0, load1); INSERT_W2_UB(load0, load1, dst_data); @@ -1008,128 +962,187 @@ static void avc_chroma_hz_and_aver_dst_4x2_msa(uint8_t *src, int32_t src_stride, res = __msa_pckev_b((v16i8) res_r, (v16i8) res_r); dst_data = __msa_aver_u_b((v16u8) res, dst_data); - ST4x2_UB(dst_data, dst, dst_stride); + ST4x2_UB(dst_data, dst, stride); } -static void avc_chroma_hz_and_aver_dst_4x4multiple_msa(uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - uint32_t coeff0, - uint32_t coeff1, - int32_t height) +static void avc_chroma_hz_and_aver_dst_4x4_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) { - uint32_t load0, load1; - uint32_t row; + uint32_t tp0, tp1, tp2, tp3; v16u8 src0, src1, src2, src3; - v16u8 dst0 = { 0 }; - v16u8 dst1 = { 0 }; + v16u8 out, dst_data = { 0 }; + v16i8 mask; v8u16 res0_r, res1_r; - v16u8 res0, res1, mask; v16i8 coeff_vec0 = __msa_fill_b(coeff0); v16i8 coeff_vec1 = __msa_fill_b(coeff1); v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); - mask = LD_UB(&chroma_mask_arr[0]); - - for (row = (height >> 2); row--;) { - LD_UB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); - - load0 = LW(dst); - load1 = LW(dst + dst_stride); - - INSERT_W2_UB(load0, load1, dst0); - - load0 = LW(dst + 2 * dst_stride); - load1 = LW(dst + 3 * dst_stride); - - INSERT_W2_UB(load0, load1, dst1); + mask = LD_SB(&chroma_mask_arr[0]); - VSHF_B2_UB(src0, src1, src2, src3, mask, mask, src0, src2); - DOTP_UB2_UH(src0, src2, coeff_vec, coeff_vec, res0_r, res1_r); + LD_UB4(src, stride, src0, src1, src2, src3); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst_data); + VSHF_B2_UB(src0, src1, src2, src3, mask, mask, src0, src2); + DOTP_UB2_UH(src0, src2, coeff_vec, coeff_vec, res0_r, res1_r); + res0_r <<= 3; + res1_r <<= 3; + SRARI_H2_UH(res0_r, res1_r, 6); + SAT_UH2_UH(res0_r, res1_r, 7); + out = (v16u8) __msa_pckev_b((v16i8) res1_r, (v16i8) res0_r); + out = __msa_aver_u_b(out, dst_data); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); +} - res0_r <<= 3; - res1_r <<= 3; +static void avc_chroma_hz_and_aver_dst_4x8_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) +{ + uint32_t tp0, tp1, tp2, tp3; + v16u8 src0, src1, src2, src3, src4, src5, src6, src7, out0, out1; + v16u8 dst0 = { 0 }, dst1 = { 0 }; + v16i8 mask; + v8u16 res0, res1, res2, res3; + v16i8 coeff_vec0 = __msa_fill_b(coeff0); + v16i8 coeff_vec1 = __msa_fill_b(coeff1); + v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); - SRARI_H2_UH(res0_r, res1_r, 6); - SAT_UH2_UH(res0_r, res1_r, 7); - PCKEV_B2_UB(res0_r, res0_r, res1_r, res1_r, res0, res1); - AVER_UB2_UB(res0, dst0, res1, dst1, dst0, dst1); + mask = LD_SB(&chroma_mask_arr[0]); - ST4x4_UB(dst0, dst1, 0, 1, 0, 1, dst, dst_stride); - dst += (4 * dst_stride); - } + LD_UB8(src, stride, src0, src1, src2, src3, src4, src5, src6, src7); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + LW4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst1); + VSHF_B2_UB(src0, src1, src2, src3, mask, mask, src0, src2); + VSHF_B2_UB(src4, src5, src6, src7, mask, mask, src4, src6); + DOTP_UB2_UH(src0, src2, coeff_vec, coeff_vec, res0, res1); + DOTP_UB2_UH(src4, src6, coeff_vec, coeff_vec, res2, res3); + SLLI_4V(res0, res1, res2, res3, 3); + SRARI_H4_UH(res0, res1, res2, res3, 6); + SAT_UH4_UH(res0, res1, res2, res3, 7); + PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); + AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); + ST4x8_UB(out0, out1, dst, stride); } -static void avc_chroma_hz_and_aver_dst_4w_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1, - int32_t height) +static void avc_chroma_hz_and_aver_dst_4w_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1, int32_t height) { if (2 == height) { - avc_chroma_hz_and_aver_dst_4x2_msa(src, src_stride, dst, dst_stride, - coeff0, coeff1); - } else { - avc_chroma_hz_and_aver_dst_4x4multiple_msa(src, src_stride, - dst, dst_stride, - coeff0, coeff1, height); + avc_chroma_hz_and_aver_dst_4x2_msa(src, dst, stride, coeff0, coeff1); + } else if (4 == height) { + avc_chroma_hz_and_aver_dst_4x4_msa(src, dst, stride, coeff0, coeff1); + } else if (8 == height) { + avc_chroma_hz_and_aver_dst_4x8_msa(src, dst, stride, coeff0, coeff1); } } -static void avc_chroma_hz_and_aver_dst_8w_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1, - int32_t height) +static void avc_chroma_hz_and_aver_dst_8x4_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) { - uint32_t row; + uint64_t tp0, tp1, tp2, tp3; v16u8 src0, src1, src2, src3, out0, out1; + v16u8 dst0 = { 0 }, dst1 = { 0 }; v8u16 res0, res1, res2, res3; - v16u8 dst0, dst1, dst2, dst3; v16i8 mask; v16i8 coeff_vec0 = __msa_fill_b(coeff0); v16i8 coeff_vec1 = __msa_fill_b(coeff1); v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); mask = LD_SB(&chroma_mask_arr[32]); + LD_UB4(src, stride, src0, src1, src2, src3); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + VSHF_B2_UB(src0, src0, src1, src1, mask, mask, src0, src1); + VSHF_B2_UB(src2, src2, src3, src3, mask, mask, src2, src3); + DOTP_UB4_UH(src0, src1, src2, src3, coeff_vec, coeff_vec, coeff_vec, + coeff_vec, res0, res1, res2, res3); + SLLI_4V(res0, res1, res2, res3, 3); + SRARI_H4_UH(res0, res1, res2, res3, 6); + SAT_UH4_UH(res0, res1, res2, res3, 7); + PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); + AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, stride); +} - for (row = height >> 2; row--;) { - LD_UB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - VSHF_B2_UB(src0, src0, src1, src1, mask, mask, src0, src1); - VSHF_B2_UB(src2, src2, src3, src3, mask, mask, src2, src3); - DOTP_UB4_UH(src0, src1, src2, src3, coeff_vec, coeff_vec, coeff_vec, - coeff_vec, res0, res1, res2, res3); - SLLI_4V(res0, res1, res2, res3, 3); - SRARI_H4_UH(res0, res1, res2, res3, 6); - SAT_UH4_UH(res0, res1, res2, res3, 7); - PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); - PCKEV_D2_UB(dst1, dst0, dst3, dst2, dst0, dst1); - AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); +static void avc_chroma_hz_and_aver_dst_8x8_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) +{ + uint64_t tp0, tp1, tp2, tp3; + v16u8 src0, src1, src2, src3, src4, src5, src6, src7; + v16u8 out0, out1, out2, out3; + v16u8 dst0 = { 0 }, dst1 = { 0 }, dst2 = { 0 }, dst3 = { 0 }; + v8u16 res0, res1, res2, res3, res4, res5, res6, res7; + v16i8 mask; + v16i8 coeff_vec0 = __msa_fill_b(coeff0); + v16i8 coeff_vec1 = __msa_fill_b(coeff1); + v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); + + mask = LD_SB(&chroma_mask_arr[32]); + + LD_UB8(src, stride, src0, src1, src2, src3, src4, src5, src6, src7); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + LD4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst2); + INSERT_D2_UB(tp2, tp3, dst3); + VSHF_B2_UB(src0, src0, src1, src1, mask, mask, src0, src1); + VSHF_B2_UB(src2, src2, src3, src3, mask, mask, src2, src3); + VSHF_B2_UB(src4, src4, src5, src5, mask, mask, src4, src5); + VSHF_B2_UB(src6, src6, src7, src7, mask, mask, src6, src7); + DOTP_UB4_UH(src0, src1, src2, src3, coeff_vec, coeff_vec, coeff_vec, + coeff_vec, res0, res1, res2, res3); + DOTP_UB4_UH(src4, src5, src6, src7, coeff_vec, coeff_vec, coeff_vec, + coeff_vec, res4, res5, res6, res7); + SLLI_4V(res0, res1, res2, res3, 3); + SLLI_4V(res4, res5, res6, res7, 3); + SRARI_H4_UH(res0, res1, res2, res3, 6); + SRARI_H4_UH(res4, res5, res6, res7, 6); + SAT_UH4_UH(res0, res1, res2, res3, 7); + SAT_UH4_UH(res4, res5, res6, res7, 7); + PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); + PCKEV_B2_UB(res5, res4, res7, res6, out2, out3); + AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); + AVER_UB2_UB(out2, dst2, out3, dst3, out2, out3); + ST8x8_UB(out0, out1, out2, out3, dst, stride); +} + +static void avc_chroma_hz_and_aver_dst_8w_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1, int32_t height) +{ + if (4 == height) { + avc_chroma_hz_and_aver_dst_8x4_msa(src, dst, stride, coeff0, coeff1); + } else if (8 == height) { + avc_chroma_hz_and_aver_dst_8x8_msa(src, dst, stride, coeff0, coeff1); } } -static void avc_chroma_vt_and_aver_dst_2x2_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1) +static void avc_chroma_vt_and_aver_dst_2x2_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) { uint16_t out0, out1; - uint32_t load0, load1; v16i8 src0, src1, src2, tmp0, tmp1, res; v16u8 dst_data = { 0 }; + v8i16 out; v8u16 res_r; v16i8 coeff_vec0 = __msa_fill_b(coeff0); v16i8 coeff_vec1 = __msa_fill_b(coeff1); v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); - LD_SB3(src, src_stride, src0, src1, src2); - load0 = LW(dst); - load1 = LW(dst + dst_stride); + LD_SB3(src, stride, src0, src1, src2); + out0 = LH(dst); + out1 = LH(dst + stride); - INSERT_W2_UB(load0, load1, dst_data); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 0, out0); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 2, out1); ILVR_B2_SB(src1, src0, src2, src1, tmp0, tmp1); @@ -1139,20 +1152,20 @@ static void avc_chroma_vt_and_aver_dst_2x2_msa(uint8_t *src, int32_t src_stride, res_r = (v8u16) __msa_srari_h((v8i16) res_r, 6); res_r = __msa_sat_u_h(res_r, 7); res = __msa_pckev_b((v16i8) res_r, (v16i8) res_r); - dst_data = __msa_aver_u_b((v16u8) res, dst_data); - out0 = __msa_copy_u_h((v8i16) dst_data, 0); - out1 = __msa_copy_u_h((v8i16) dst_data, 2); + out = (v8i16) __msa_aver_u_b((v16u8) res, dst_data); + out0 = __msa_copy_u_h(out, 0); + out1 = __msa_copy_u_h(out, 2); SH(out0, dst); - dst += dst_stride; + dst += stride; SH(out1, dst); } -static void avc_chroma_vt_and_aver_dst_2x4_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1) +static void avc_chroma_vt_and_aver_dst_2x4_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) { - uint32_t load0, load1; + uint16_t tp0, tp1, tp2, tp3; v16i8 src0, src1, src2, src3, src4; v16u8 tmp0, tmp1, tmp2, tmp3; v8u16 res_r; @@ -1162,19 +1175,16 @@ static void avc_chroma_vt_and_aver_dst_2x4_msa(uint8_t *src, int32_t src_stride, v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); v16u8 dst_data = { 0 }; - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - - load0 = LW(dst); - load1 = LW(dst + dst_stride); - - dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 0, load0); - dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 1, load1); - - load0 = LW(dst + 2 * dst_stride); - load1 = LW(dst + 3 * dst_stride); + LD_SB5(src, stride, src0, src1, src2, src3, src4); - dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 2, load0); - dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 3, load1); + tp0 = LH(dst); + tp1 = LH(dst + stride); + tp2 = LH(dst + 2 * stride); + tp3 = LH(dst + 3 * stride); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 0, tp0); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 1, tp1); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 2, tp2); + dst_data = (v16u8) __msa_insert_h((v8i16) dst_data, 3, tp3); ILVR_B4_UB(src1, src0, src2, src1, src3, src2, src4, src3, tmp0, tmp1, tmp2, tmp3); @@ -1190,102 +1200,26 @@ static void avc_chroma_vt_and_aver_dst_2x4_msa(uint8_t *src, int32_t src_stride, res = (v8i16) __msa_pckev_b((v16i8) res_r, (v16i8) res_r); res = (v8i16) __msa_aver_u_b((v16u8) res, dst_data); - ST2x4_UB(res, 0, dst, dst_stride); - dst += (4 * dst_stride); -} - -static void avc_chroma_vt_and_aver_dst_2x8_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1) -{ - uint32_t load0, load1, load2, load3; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; - v16u8 tmp0, tmp1, tmp2, tmp3; - v8i16 res; - v8u16 res_r; - v16i8 coeff_vec0 = __msa_fill_b(coeff0); - v16i8 coeff_vec1 = __msa_fill_b(coeff1); - v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); - v16u8 dst_data0 = { 0 }; - v16u8 dst_data1 = { 0 }; - - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); - LD_SB4(src, src_stride, src5, src6, src7, src8); - - LW4(dst, dst_stride, load0, load1, load2, load3); - - dst_data0 = (v16u8) __msa_insert_h((v8i16) dst_data0, 0, load0); - dst_data0 = (v16u8) __msa_insert_h((v8i16) dst_data0, 1, load1); - dst_data0 = (v16u8) __msa_insert_h((v8i16) dst_data0, 2, load2); - dst_data0 = (v16u8) __msa_insert_h((v8i16) dst_data0, 3, load3); - - LW4(dst + 4 * dst_stride, dst_stride, load0, load1, load2, load3); - - dst_data1 = (v16u8) __msa_insert_h((v8i16) dst_data1, 0, load0); - dst_data1 = (v16u8) __msa_insert_h((v8i16) dst_data1, 1, load1); - dst_data1 = (v16u8) __msa_insert_h((v8i16) dst_data1, 2, load2); - dst_data1 = (v16u8) __msa_insert_h((v8i16) dst_data1, 3, load3); - - ILVR_B4_UB(src1, src0, src2, src1, src3, src2, src4, src3, - tmp0, tmp1, tmp2, tmp3); - - ILVR_W2_UB(tmp1, tmp0, tmp3, tmp2, tmp0, tmp2); - - tmp0 = (v16u8) __msa_ilvr_d((v2i64) tmp2, (v2i64) tmp0); - - res_r = __msa_dotp_u_h(tmp0, coeff_vec); - res_r <<= 3; - res_r = (v8u16) __msa_srari_h((v8i16) res_r, 6); - res_r = __msa_sat_u_h(res_r, 7); - - res = (v8i16) __msa_pckev_b((v16i8) res_r, (v16i8) res_r); - res = (v8i16) __msa_aver_u_b((v16u8) res, dst_data0); - - ST2x4_UB(res, 0, dst, dst_stride); - dst += (4 * dst_stride); - - ILVR_B4_UB(src5, src4, src6, src5, src7, src6, src8, src7, - tmp0, tmp1, tmp2, tmp3); - - ILVR_W2_UB(tmp1, tmp0, tmp3, tmp2, tmp0, tmp2); - - tmp0 = (v16u8) __msa_ilvr_d((v2i64) tmp2, (v2i64) tmp0); - - res_r = __msa_dotp_u_h(tmp0, coeff_vec); - res_r <<= 3; - res_r = (v8u16) __msa_srari_h((v8i16) res_r, 6); - res_r = __msa_sat_u_h(res_r, 7); - - res = (v8i16) __msa_pckev_b((v16i8) res_r, (v16i8) res_r); - res = (v8i16) __msa_aver_u_b((v16u8) res, dst_data1); - - ST2x4_UB(res, 0, dst, dst_stride); + ST2x4_UB(res, 0, dst, stride); } -static void avc_chroma_vt_and_aver_dst_2w_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1, - int32_t height) +static void avc_chroma_vt_and_aver_dst_2w_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1, int32_t height) { if (2 == height) { - avc_chroma_vt_and_aver_dst_2x2_msa(src, src_stride, dst, dst_stride, - coeff0, coeff1); + avc_chroma_vt_and_aver_dst_2x2_msa(src, dst, stride, coeff0, coeff1); } else if (4 == height) { - avc_chroma_vt_and_aver_dst_2x4_msa(src, src_stride, dst, dst_stride, - coeff0, coeff1); - } else if (8 == height) { - avc_chroma_vt_and_aver_dst_2x8_msa(src, src_stride, dst, dst_stride, - coeff0, coeff1); + avc_chroma_vt_and_aver_dst_2x4_msa(src, dst, stride, coeff0, coeff1); } } -static void avc_chroma_vt_and_aver_dst_4x2_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1) +static void avc_chroma_vt_and_aver_dst_4x2_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) { uint32_t load0, load1; - v16i8 src0, src1, src2, tmp0, tmp1; + v16u8 src0, src1, src2, tmp0, tmp1; v16u8 dst_data = { 0 }; v8u16 res_r; v16u8 res; @@ -1293,140 +1227,196 @@ static void avc_chroma_vt_and_aver_dst_4x2_msa(uint8_t *src, int32_t src_stride, v16i8 coeff_vec1 = __msa_fill_b(coeff1); v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); - LD_SB3(src, src_stride, src0, src1, src2); + LD_UB3(src, stride, src0, src1, src2); - load0 = LW(dst); - load1 = LW(dst + dst_stride); + LW2(dst, stride, load0, load1); INSERT_W2_UB(load0, load1, dst_data); - ILVR_B2_SB(src1, src0, src2, src1, tmp0, tmp1); + ILVR_B2_UB(src1, src0, src2, src1, tmp0, tmp1); - tmp0 = (v16i8) __msa_ilvr_d((v2i64) tmp1, (v2i64) tmp0); + tmp0 = (v16u8) __msa_ilvr_d((v2i64) tmp1, (v2i64) tmp0); - res_r = __msa_dotp_u_h((v16u8) tmp0, coeff_vec); + res_r = __msa_dotp_u_h(tmp0, coeff_vec); res_r <<= 3; res_r = (v8u16) __msa_srari_h((v8i16) res_r, 6); res_r = __msa_sat_u_h(res_r, 7); res = (v16u8) __msa_pckev_b((v16i8) res_r, (v16i8) res_r); res = __msa_aver_u_b(res, dst_data); - ST4x2_UB(res, dst, dst_stride); + ST4x2_UB(res, dst, stride); } -static void avc_chroma_vt_and_aver_dst_4x4mul_msa(uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - uint32_t coeff0, - uint32_t coeff1, - int32_t height) +static void avc_chroma_vt_and_aver_dst_4x4_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) { - uint32_t load0, load1, row; - v16i8 src0, src1, src2, src3, src4; + uint32_t tp0, tp1, tp2, tp3; + v16u8 src0, src1, src2, src3, src4; v16u8 tmp0, tmp1, tmp2, tmp3; v16u8 dst0 = { 0 }; - v16u8 dst1 = { 0 }; v8u16 res0_r, res1_r; - v16u8 res0, res1; + v16u8 out; v16i8 coeff_vec0 = __msa_fill_b(coeff0); v16i8 coeff_vec1 = __msa_fill_b(coeff1); v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); - src0 = LD_SB(src); - src += src_stride; - - for (row = (height >> 2); row--;) { - LD_SB4(src, src_stride, src1, src2, src3, src4); - src += (4 * src_stride); - - load0 = LW(dst); - load1 = LW(dst + dst_stride); - - INSERT_W2_UB(load0, load1, dst0); - load0 = LW(dst + 2 * dst_stride); - load1 = LW(dst + 3 * dst_stride); - INSERT_W2_UB(load0, load1, dst1); - - ILVR_B4_UB(src1, src0, src2, src1, src3, src2, src4, src3, - tmp0, tmp1, tmp2, tmp3); - ILVR_D2_UB(tmp1, tmp0, tmp3, tmp2, tmp0, tmp2); - DOTP_UB2_UH(tmp0, tmp2, coeff_vec, coeff_vec, res0_r, res1_r); - - res0_r <<= 3; - res1_r <<= 3; + LD_UB5(src, stride, src0, src1, src2, src3, src4); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + ILVR_B4_UB(src1, src0, src2, src1, src3, src2, src4, src3, tmp0, tmp1, tmp2, + tmp3); + ILVR_D2_UB(tmp1, tmp0, tmp3, tmp2, tmp0, tmp2); + DOTP_UB2_UH(tmp0, tmp2, coeff_vec, coeff_vec, res0_r, res1_r); + res0_r <<= 3; + res1_r <<= 3; + SRARI_H2_UH(res0_r, res1_r, 6); + SAT_UH2_UH(res0_r, res1_r, 7); + out = (v16u8) __msa_pckev_b((v16i8) res1_r, (v16i8) res0_r); + out = __msa_aver_u_b(out, dst0); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); +} - SRARI_H2_UH(res0_r, res1_r, 6); - SAT_UH2_UH(res0_r, res1_r, 7); - PCKEV_B2_UB(res0_r, res0_r, res1_r, res1_r, res0, res1); - AVER_UB2_UB(res0, dst0, res1, dst1, res0, res1); +static void avc_chroma_vt_and_aver_dst_4x8_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) +{ + uint32_t tp0, tp1, tp2, tp3; + v16u8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16u8 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, out0, out1; + v16u8 dst0 = { 0 }, dst1 = { 0 }; + v8u16 res0, res1, res2, res3; + v16i8 coeff_vec0 = __msa_fill_b(coeff0); + v16i8 coeff_vec1 = __msa_fill_b(coeff1); + v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); - ST4x4_UB(res0, res1, 0, 1, 0, 1, dst, dst_stride); - dst += (4 * dst_stride); - src0 = src4; - } + LD_UB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + LD_UB4(src, stride, src5, src6, src7, src8); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + LW4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst1); + ILVR_B4_UB(src1, src0, src2, src1, src3, src2, src4, src3, tmp0, tmp1, tmp2, + tmp3); + ILVR_B4_UB(src5, src4, src6, src5, src7, src6, src8, src7, tmp4, tmp5, tmp6, + tmp7); + ILVR_D2_UB(tmp1, tmp0, tmp3, tmp2, tmp0, tmp2); + ILVR_D2_UB(tmp5, tmp4, tmp7, tmp6, tmp4, tmp6); + DOTP_UB2_UH(tmp0, tmp2, coeff_vec, coeff_vec, res0, res1); + DOTP_UB2_UH(tmp4, tmp6, coeff_vec, coeff_vec, res2, res3); + SLLI_4V(res0, res1, res2, res3, 3); + SRARI_H4_UH(res0, res1, res2, res3, 6); + SAT_UH4_UH(res0, res1, res2, res3, 7); + PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); + AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); + ST4x8_UB(out0, out1, dst, stride); } -static void avc_chroma_vt_and_aver_dst_4w_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1, - int32_t height) +static void avc_chroma_vt_and_aver_dst_4w_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1, int32_t height) { if (2 == height) { - avc_chroma_vt_and_aver_dst_4x2_msa(src, src_stride, dst, dst_stride, - coeff0, coeff1); - } else { - avc_chroma_vt_and_aver_dst_4x4mul_msa(src, src_stride, dst, dst_stride, - coeff0, coeff1, height); + avc_chroma_vt_and_aver_dst_4x2_msa(src, dst, stride, coeff0, coeff1); + } else if (4 == height) { + avc_chroma_vt_and_aver_dst_4x4_msa(src, dst, stride, coeff0, coeff1); + } else if (8 == height) { + avc_chroma_vt_and_aver_dst_4x8_msa(src, dst, stride, coeff0, coeff1); } } -static void avc_chroma_vt_and_aver_dst_8w_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coeff0, uint32_t coeff1, - int32_t height) +static void avc_chroma_vt_and_aver_dst_8x4_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) { - uint32_t row; + uint64_t tp0, tp1, tp2, tp3; v16u8 src0, src1, src2, src3, src4; v16u8 out0, out1; v8u16 res0, res1, res2, res3; - v16u8 dst0, dst1, dst2, dst3; + v16u8 dst0 = { 0 }, dst1 = { 0 }; v16i8 coeff_vec0 = __msa_fill_b(coeff0); v16i8 coeff_vec1 = __msa_fill_b(coeff1); v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); - src0 = LD_UB(src); - src += src_stride; - - for (row = height >> 2; row--;) { - LD_UB4(src, src_stride, src1, src2, src3, src4); - src += (4 * src_stride); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - ILVR_B4_UB(src1, src0, src2, src1, src3, src2, src4, src3, - src0, src1, src2, src3); - DOTP_UB4_UH(src0, src1, src2, src3, coeff_vec, coeff_vec, coeff_vec, - coeff_vec, res0, res1, res2, res3); - SLLI_4V(res0, res1, res2, res3, 3); - SRARI_H4_UH(res0, res1, res2, res3, 6); - SAT_UH4_UH(res0, res1, res2, res3, 7); - PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); - PCKEV_D2_UB(dst1, dst0, dst3, dst2, dst0, dst1); - AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); + LD_UB5(src, stride, src0, src1, src2, src3, src4); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + ILVR_B4_UB(src1, src0, src2, src1, src3, src2, src4, src3, + src0, src1, src2, src3); + DOTP_UB4_UH(src0, src1, src2, src3, coeff_vec, coeff_vec, coeff_vec, + coeff_vec, res0, res1, res2, res3); + SLLI_4V(res0, res1, res2, res3, 3); + SRARI_H4_UH(res0, res1, res2, res3, 6); + SAT_UH4_UH(res0, res1, res2, res3, 7); + PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); + AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); + ST8x4_UB(out0, out1, dst, stride); +} + +static void avc_chroma_vt_and_aver_dst_8x8_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1) +{ + uint64_t tp0, tp1, tp2, tp3; + v16u8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16u8 out0, out1, out2, out3; + v16u8 dst0 = { 0 }, dst1 = { 0 }, dst2 = { 0 }, dst3 = { 0 }; + v8u16 res0, res1, res2, res3, res4, res5, res6, res7; + v16i8 coeff_vec0 = __msa_fill_b(coeff0); + v16i8 coeff_vec1 = __msa_fill_b(coeff1); + v16u8 coeff_vec = (v16u8) __msa_ilvr_b(coeff_vec0, coeff_vec1); + + LD_UB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + LD_UB4(src, stride, src5, src6, src7, src8); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + LD4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst2); + INSERT_D2_UB(tp2, tp3, dst3); + ILVR_B4_UB(src1, src0, src2, src1, src3, src2, src4, src3, + src0, src1, src2, src3); + ILVR_B4_UB(src5, src4, src6, src5, src7, src6, src8, src7, + src4, src5, src6, src7); + DOTP_UB4_UH(src0, src1, src2, src3, coeff_vec, coeff_vec, coeff_vec, + coeff_vec, res0, res1, res2, res3); + DOTP_UB4_UH(src4, src5, src6, src7, coeff_vec, coeff_vec, coeff_vec, + coeff_vec, res4, res5, res6, res7); + SLLI_4V(res0, res1, res2, res3, 3); + SLLI_4V(res4, res5, res6, res7, 3); + SRARI_H4_UH(res0, res1, res2, res3, 6); + SRARI_H4_UH(res4, res5, res6, res7, 6); + SAT_UH4_UH(res0, res1, res2, res3, 7); + SAT_UH4_UH(res0, res1, res2, res3, 7); + PCKEV_B2_UB(res1, res0, res3, res2, out0, out1); + PCKEV_B2_UB(res5, res4, res7, res6, out2, out3); + AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); + AVER_UB2_UB(out2, dst2, out3, dst3, out2, out3); + ST8x8_UB(out0, out1, out2, out3, dst, stride); +} - dst += (4 * dst_stride); - src0 = src4; +static void avc_chroma_vt_and_aver_dst_8w_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coeff0, + uint32_t coeff1, int32_t height) +{ + if (4 == height) { + avc_chroma_vt_and_aver_dst_8x4_msa(src, dst, stride, coeff0, coeff1); + } else if (8 == height) { + avc_chroma_vt_and_aver_dst_8x8_msa(src, dst, stride, coeff0, coeff1); } } -static void avc_chroma_hv_and_aver_dst_2x2_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, +static void avc_chroma_hv_and_aver_dst_2x2_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coef_hor0, uint32_t coef_hor1, uint32_t coef_ver0, uint32_t coef_ver1) { uint16_t out0, out1; - v16u8 dst0, dst1; + v16u8 dst0 = { 0 }; v16u8 src0, src1, src2; v8u16 res_hz0, res_hz1, res_vt0, res_vt1; v16i8 res, mask; @@ -1438,8 +1428,11 @@ static void avc_chroma_hv_and_aver_dst_2x2_msa(uint8_t *src, int32_t src_stride, mask = LD_SB(&chroma_mask_arr[48]); - LD_UB3(src, src_stride, src0, src1, src2); - LD_UB2(dst, dst_stride, dst0, dst1); + LD_UB3(src, stride, src0, src1, src2); + out0 = LH(dst); + out1 = LH(dst + stride); + dst0 = (v16u8) __msa_insert_h((v8i16) dst0, 0, out0); + dst0 = (v16u8) __msa_insert_h((v8i16) dst0, 1, out1); VSHF_B2_UB(src0, src1, src1, src2, mask, mask, src0, src1); DOTP_UB2_UH(src0, src1, coeff_hz_vec, coeff_hz_vec, res_hz0, res_hz1); MUL2(res_hz0, coeff_vt_vec1, res_hz1, coeff_vt_vec0, res_vt0, res_vt1); @@ -1448,67 +1441,26 @@ static void avc_chroma_hv_and_aver_dst_2x2_msa(uint8_t *src, int32_t src_stride, res_vt0 = (v8u16) __msa_srari_h((v8i16) res_vt0, 6); res_vt0 = __msa_sat_u_h(res_vt0, 7); res = __msa_pckev_b((v16i8) res_vt0, (v16i8) res_vt0); - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 1, (v8i16) dst1); dst0 = __msa_aver_u_b((v16u8) res, dst0); out0 = __msa_copy_u_h((v8i16) dst0, 0); out1 = __msa_copy_u_h((v8i16) dst0, 1); SH(out0, dst); - dst += dst_stride; + dst += stride; SH(out1, dst); } -static void avc_chroma_hv_and_aver_dst_2x4_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, +static void avc_chroma_hv_and_aver_dst_2x4_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coef_hor0, uint32_t coef_hor1, uint32_t coef_ver0, uint32_t coef_ver1) { + uint16_t tp0, tp1, tp2, tp3; v16u8 src0, src1, src2, src3, src4; v16u8 tmp0, tmp1, tmp2, tmp3; - v16u8 dst0, dst1, dst2, dst3; - v8u16 res_hz0, res_hz1, res_vt0, res_vt1; - v16i8 res, mask; - v16i8 coeff_hz_vec0 = __msa_fill_b(coef_hor0); - v16i8 coeff_hz_vec1 = __msa_fill_b(coef_hor1); - v16u8 coeff_hz_vec = (v16u8) __msa_ilvr_b(coeff_hz_vec0, coeff_hz_vec1); - v8u16 coeff_vt_vec0 = (v8u16) __msa_fill_h(coef_ver0); - v8u16 coeff_vt_vec1 = (v8u16) __msa_fill_h(coef_ver1); - - mask = LD_SB(&chroma_mask_arr[48]); - - LD_UB5(src, src_stride, src0, src1, src2, src3, src4); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - VSHF_B2_UB(src0, src1, src2, src3, mask, mask, tmp0, tmp1); - VSHF_B2_UB(src1, src2, src3, src4, mask, mask, tmp2, tmp3); - ILVR_D2_UB(tmp1, tmp0, tmp3, tmp2, src0, src1); - DOTP_UB2_UH(src0, src1, coeff_hz_vec, coeff_hz_vec, res_hz0, res_hz1); - MUL2(res_hz0, coeff_vt_vec1, res_hz1, coeff_vt_vec0, res_vt0, res_vt1); - - res_vt0 += res_vt1; - res_vt0 = (v8u16) __msa_srari_h((v8i16) res_vt0, 6); - res_vt0 = __msa_sat_u_h(res_vt0, 7); - res = __msa_pckev_b((v16i8) res_vt0, (v16i8) res_vt0); - - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 1, (v8i16) dst1); - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 2, (v8i16) dst2); - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 3, (v8i16) dst3); - dst0 = __msa_aver_u_b((v16u8) res, dst0); - - ST2x4_UB(dst0, 0, dst, dst_stride); -} - -static void avc_chroma_hv_and_aver_dst_2x8_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coef_hor0, - uint32_t coef_hor1, - uint32_t coef_ver0, - uint32_t coef_ver1) -{ - v16u8 src0, src1, src2, src3, src4, src5, src6, src7, src8; - v16u8 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; - v16u8 tmp0, tmp1, tmp2, tmp3; + v16u8 dst0 = { 0 }; v8u16 res_hz0, res_hz1, res_vt0, res_vt1; v16i8 res, mask; v16i8 coeff_hz_vec0 = __msa_fill_b(coef_hor0); @@ -1519,26 +1471,18 @@ static void avc_chroma_hv_and_aver_dst_2x8_msa(uint8_t *src, int32_t src_stride, mask = LD_SB(&chroma_mask_arr[48]); - LD_UB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); - LD_UB4(src, src_stride, src5, src6, src7, src8); - - LD_UB8(dst, dst_stride, dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7); - - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 1, (v8i16) dst1); - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 2, (v8i16) dst2); - dst0 = (v16u8) __msa_insve_h((v8i16) dst0, 3, (v8i16) dst3); - - dst4 = (v16u8) __msa_insve_h((v8i16) dst4, 1, (v8i16) dst5); - dst4 = (v16u8) __msa_insve_h((v8i16) dst4, 2, (v8i16) dst6); - dst4 = (v16u8) __msa_insve_h((v8i16) dst4, 3, (v8i16) dst7); - + LD_UB5(src, stride, src0, src1, src2, src3, src4); + tp0 = LH(dst); + tp1 = LH(dst + stride); + tp2 = LH(dst + 2 * stride); + tp3 = LH(dst + 3 * stride); + dst0 = (v16u8) __msa_insert_h((v8i16) dst0, 0, tp0); + dst0 = (v16u8) __msa_insert_h((v8i16) dst0, 1, tp1); + dst0 = (v16u8) __msa_insert_h((v8i16) dst0, 2, tp2); + dst0 = (v16u8) __msa_insert_h((v8i16) dst0, 3, tp3); VSHF_B2_UB(src0, src1, src2, src3, mask, mask, tmp0, tmp1); VSHF_B2_UB(src1, src2, src3, src4, mask, mask, tmp2, tmp3); ILVR_D2_UB(tmp1, tmp0, tmp3, tmp2, src0, src1); - VSHF_B2_UB(src4, src5, src6, src7, mask, mask, tmp0, tmp1); - VSHF_B2_UB(src5, src6, src7, src8, mask, mask, tmp2, tmp3); - ILVR_D2_UB(tmp1, tmp0, tmp3, tmp2, src4, src5); DOTP_UB2_UH(src0, src1, coeff_hz_vec, coeff_hz_vec, res_hz0, res_hz1); MUL2(res_hz0, coeff_vt_vec1, res_hz1, coeff_vt_vec0, res_vt0, res_vt1); @@ -1548,23 +1492,11 @@ static void avc_chroma_hv_and_aver_dst_2x8_msa(uint8_t *src, int32_t src_stride, res = __msa_pckev_b((v16i8) res_vt0, (v16i8) res_vt0); dst0 = __msa_aver_u_b((v16u8) res, dst0); - ST2x4_UB(dst0, 0, dst, dst_stride); - dst += (4 * dst_stride); - - DOTP_UB2_UH(src4, src5, coeff_hz_vec, coeff_hz_vec, res_hz0, res_hz1); - MUL2(res_hz0, coeff_vt_vec1, res_hz1, coeff_vt_vec0, res_vt0, res_vt1); - - res_vt0 += res_vt1; - res_vt0 = (v8u16) __msa_srari_h((v8i16) res_vt0, 6); - res_vt0 = __msa_sat_u_h(res_vt0, 7); - res = __msa_pckev_b((v16i8) res_vt0, (v16i8) res_vt0); - dst4 = __msa_aver_u_b((v16u8) res, dst4); - - ST2x4_UB(dst4, 0, dst, dst_stride); + ST2x4_UB(dst0, 0, dst, stride); } -static void avc_chroma_hv_and_aver_dst_2w_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, +static void avc_chroma_hv_and_aver_dst_2w_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coef_hor0, uint32_t coef_hor1, uint32_t coef_ver0, @@ -1572,31 +1504,26 @@ static void avc_chroma_hv_and_aver_dst_2w_msa(uint8_t *src, int32_t src_stride, int32_t height) { if (2 == height) { - avc_chroma_hv_and_aver_dst_2x2_msa(src, src_stride, dst, dst_stride, - coef_hor0, coef_hor1, - coef_ver0, coef_ver1); + avc_chroma_hv_and_aver_dst_2x2_msa(src, dst, stride, coef_hor0, + coef_hor1, coef_ver0, coef_ver1); } else if (4 == height) { - avc_chroma_hv_and_aver_dst_2x4_msa(src, src_stride, dst, dst_stride, - coef_hor0, coef_hor1, - coef_ver0, coef_ver1); - } else if (8 == height) { - avc_chroma_hv_and_aver_dst_2x8_msa(src, src_stride, dst, dst_stride, - coef_hor0, coef_hor1, - coef_ver0, coef_ver1); + avc_chroma_hv_and_aver_dst_2x4_msa(src, dst, stride, coef_hor0, + coef_hor1, coef_ver0, coef_ver1); } } -static void avc_chroma_hv_and_aver_dst_4x2_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, +static void avc_chroma_hv_and_aver_dst_4x2_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coef_hor0, uint32_t coef_hor1, uint32_t coef_ver0, uint32_t coef_ver1) { + uint32_t tp0, tp1; v16u8 src0, src1, src2; - v16u8 dst0, dst1; + v16u8 dst0, dst_data = { 0 }; v8u16 res_hz0, res_hz1, res_vt0, res_vt1; - v16i8 res, mask; + v16i8 mask; v16i8 coeff_hz_vec0 = __msa_fill_b(coef_hor0); v16i8 coeff_hz_vec1 = __msa_fill_b(coef_hor1); v16u8 coeff_hz_vec = (v16u8) __msa_ilvr_b(coeff_hz_vec0, coeff_hz_vec1); @@ -1605,8 +1532,9 @@ static void avc_chroma_hv_and_aver_dst_4x2_msa(uint8_t *src, int32_t src_stride, mask = LD_SB(&chroma_mask_arr[0]); - LD_UB3(src, src_stride, src0, src1, src2); - LD_UB2(dst, dst_stride, dst0, dst1); + LD_UB3(src, stride, src0, src1, src2); + LW2(dst, stride, tp0, tp1); + INSERT_W2_UB(tp0, tp1, dst_data); VSHF_B2_UB(src0, src1, src1, src2, mask, mask, src0, src1); DOTP_UB2_UH(src0, src1, coeff_hz_vec, coeff_hz_vec, res_hz0, res_hz1); MUL2(res_hz0, coeff_vt_vec1, res_hz1, coeff_vt_vec0, res_vt0, res_vt1); @@ -1614,26 +1542,22 @@ static void avc_chroma_hv_and_aver_dst_4x2_msa(uint8_t *src, int32_t src_stride, res_vt0 += res_vt1; res_vt0 = (v8u16) __msa_srari_h((v8i16) res_vt0, 6); res_vt0 = __msa_sat_u_h(res_vt0, 7); - res = __msa_pckev_b((v16i8) res_vt0, (v16i8) res_vt0); - dst0 = (v16u8) __msa_insve_w((v4i32) dst0, 1, (v4i32) dst1); - dst0 = __msa_aver_u_b((v16u8) res, dst0); + dst0 = (v16u8) __msa_pckev_b((v16i8) res_vt0, (v16i8) res_vt0); + dst0 = __msa_aver_u_b(dst0, dst_data); - ST4x2_UB(dst0, dst, dst_stride); + ST4x2_UB(dst0, dst, stride); } -static void avc_chroma_hv_and_aver_dst_4x4mul_msa(uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - uint32_t coef_hor0, - uint32_t coef_hor1, - uint32_t coef_ver0, - uint32_t coef_ver1, - int32_t height) +static void avc_chroma_hv_and_aver_dst_4x4_msa(uint8_t *src, uint8_t *dst, + int32_t stride, + uint32_t coef_hor0, + uint32_t coef_hor1, + uint32_t coef_ver0, + uint32_t coef_ver1) { - uint32_t row; + uint32_t tp0, tp1, tp2, tp3; v16u8 src0, src1, src2, src3, src4; - v16u8 dst0, dst1, dst2, dst3; + v16u8 out, dst_data = { 0 }; v8u16 res_hz0, res_hz1, res_hz2, res_hz3; v8u16 res_vt0, res_vt1, res_vt2, res_vt3; v16i8 mask; @@ -1642,45 +1566,78 @@ static void avc_chroma_hv_and_aver_dst_4x4mul_msa(uint8_t *src, v16u8 coeff_hz_vec = (v16u8) __msa_ilvr_b(coeff_hz_vec0, coeff_hz_vec1); v8u16 coeff_vt_vec0 = (v8u16) __msa_fill_h(coef_ver0); v8u16 coeff_vt_vec1 = (v8u16) __msa_fill_h(coef_ver1); - v16u8 res0, res1; mask = LD_SB(&chroma_mask_arr[0]); - src0 = LD_UB(src); - src += src_stride; - - for (row = (height >> 2); row--;) { - LD_UB4(src, src_stride, src1, src2, src3, src4); - src += (4 * src_stride); - - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - - VSHF_B2_UB(src0, src1, src1, src2, mask, mask, src0, src1); - VSHF_B2_UB(src2, src3, src3, src4, mask, mask, src2, src3); - DOTP_UB4_UH(src0, src1, src2, src3, coeff_hz_vec, coeff_hz_vec, - coeff_hz_vec, coeff_hz_vec, res_hz0, res_hz1, res_hz2, - res_hz3); - MUL4(res_hz0, coeff_vt_vec1, res_hz1, coeff_vt_vec0, res_hz2, - coeff_vt_vec1, res_hz3, coeff_vt_vec0, res_vt0, res_vt1, res_vt2, - res_vt3); - ADD2(res_vt0, res_vt1, res_vt2, res_vt3, res_vt0, res_vt1); - SRARI_H2_UH(res_vt0, res_vt1, 6); - SAT_UH2_UH(res_vt0, res_vt1, 7); - PCKEV_B2_UB(res_vt0, res_vt0, res_vt1, res_vt1, res0, res1); - - dst0 = (v16u8) __msa_insve_w((v4i32) dst0, 1, (v4i32) dst1); - dst1 = (v16u8) __msa_insve_w((v4i32) dst2, 1, (v4i32) dst3); - - AVER_UB2_UB(res0, dst0, res1, dst1, dst0, dst1); - - ST4x4_UB(dst0, dst1, 0, 1, 0, 1, dst, dst_stride); - dst += (4 * dst_stride); - src0 = src4; - } + LD_UB5(src, stride, src0, src1, src2, src3, src4); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst_data); + VSHF_B2_UB(src0, src1, src1, src2, mask, mask, src0, src1); + VSHF_B2_UB(src2, src3, src3, src4, mask, mask, src2, src3); + DOTP_UB4_UH(src0, src1, src2, src3, coeff_hz_vec, coeff_hz_vec, + coeff_hz_vec, coeff_hz_vec, res_hz0, res_hz1, res_hz2, + res_hz3); + MUL4(res_hz0, coeff_vt_vec1, res_hz1, coeff_vt_vec0, res_hz2, coeff_vt_vec1, + res_hz3, coeff_vt_vec0, res_vt0, res_vt1, res_vt2, res_vt3); + ADD2(res_vt0, res_vt1, res_vt2, res_vt3, res_vt0, res_vt1); + SRARI_H2_UH(res_vt0, res_vt1, 6); + SAT_UH2_UH(res_vt0, res_vt1, 7); + out = (v16u8) __msa_pckev_b((v16i8) res_vt1, (v16i8) res_vt0); + out = __msa_aver_u_b(out, dst_data); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); +} + +static void avc_chroma_hv_and_aver_dst_4x8_msa(uint8_t *src, uint8_t *dst, + int32_t stride, + uint32_t coef_hor0, + uint32_t coef_hor1, + uint32_t coef_ver0, + uint32_t coef_ver1) +{ + uint32_t tp0, tp1, tp2, tp3; + v16u8 src0, src1, src2, src3, src4, src5, src6, src7, src8, res0, res1; + v16u8 dst0 = { 0 }, dst1 = { 0 }; + v8u16 res_hz0, res_hz1, res_hz2, res_hz3, res_hz4, res_hz5, res_hz6, res_hz7; + v8u16 res_vt0, res_vt1, res_vt2, res_vt3, res_vt4, res_vt5, res_vt6, res_vt7; + v16i8 mask; + v16i8 coeff_hz_vec0 = __msa_fill_b(coef_hor0); + v16i8 coeff_hz_vec1 = __msa_fill_b(coef_hor1); + v16u8 coeff_hz_vec = (v16u8) __msa_ilvr_b(coeff_hz_vec0, coeff_hz_vec1); + v8u16 coeff_vt_vec0 = (v8u16) __msa_fill_h(coef_ver0); + v8u16 coeff_vt_vec1 = (v8u16) __msa_fill_h(coef_ver1); + + mask = LD_SB(&chroma_mask_arr[0]); + + LD_UB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + LD_UB4(src, stride, src5, src6, src7, src8); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + LW4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst1); + VSHF_B2_UB(src0, src1, src1, src2, mask, mask, src0, src1); + VSHF_B2_UB(src2, src3, src3, src4, mask, mask, src2, src3); + VSHF_B2_UB(src4, src5, src5, src6, mask, mask, src4, src5); + VSHF_B2_UB(src6, src7, src7, src8, mask, mask, src6, src7); + DOTP_UB4_UH(src0, src1, src2, src3, coeff_hz_vec, coeff_hz_vec, + coeff_hz_vec, coeff_hz_vec, res_hz0, res_hz1, res_hz2, res_hz3); + DOTP_UB4_UH(src4, src5, src6, src7, coeff_hz_vec, coeff_hz_vec, + coeff_hz_vec, coeff_hz_vec, res_hz4, res_hz5, res_hz6, res_hz7); + MUL4(res_hz0, coeff_vt_vec1, res_hz1, coeff_vt_vec0, res_hz2, coeff_vt_vec1, + res_hz3, coeff_vt_vec0, res_vt0, res_vt1, res_vt2, res_vt3); + MUL4(res_hz4, coeff_vt_vec1, res_hz5, coeff_vt_vec0, res_hz6, coeff_vt_vec1, + res_hz7, coeff_vt_vec0, res_vt4, res_vt5, res_vt6, res_vt7); + ADD2(res_vt0, res_vt1, res_vt2, res_vt3, res_vt0, res_vt1); + ADD2(res_vt4, res_vt5, res_vt6, res_vt7, res_vt2, res_vt3); + SRARI_H4_UH(res_vt0, res_vt1, res_vt2, res_vt3, 6); + SAT_UH4_UH(res_vt0, res_vt1, res_vt2, res_vt3, 7); + PCKEV_B2_UB(res_vt1, res_vt0, res_vt3, res_vt2, res0, res1); + AVER_UB2_UB(res0, dst0, res1, dst1, res0, res1); + ST4x8_UB(res0, res1, dst, stride); } -static void avc_chroma_hv_and_aver_dst_4w_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, +static void avc_chroma_hv_and_aver_dst_4w_msa(uint8_t *src, uint8_t *dst, + int32_t stride, uint32_t coef_hor0, uint32_t coef_hor1, uint32_t coef_ver0, @@ -1688,30 +1645,30 @@ static void avc_chroma_hv_and_aver_dst_4w_msa(uint8_t *src, int32_t src_stride, int32_t height) { if (2 == height) { - avc_chroma_hv_and_aver_dst_4x2_msa(src, src_stride, dst, dst_stride, - coef_hor0, coef_hor1, - coef_ver0, coef_ver1); - } else { - avc_chroma_hv_and_aver_dst_4x4mul_msa(src, src_stride, dst, dst_stride, - coef_hor0, coef_hor1, - coef_ver0, coef_ver1, height); + avc_chroma_hv_and_aver_dst_4x2_msa(src, dst, stride, coef_hor0, + coef_hor1, coef_ver0, coef_ver1); + } else if (4 == height) { + avc_chroma_hv_and_aver_dst_4x4_msa(src, dst, stride, coef_hor0, + coef_hor1, coef_ver0, coef_ver1); + } else if (8 == height) { + avc_chroma_hv_and_aver_dst_4x8_msa(src, dst, stride, coef_hor0, + coef_hor1, coef_ver0, coef_ver1); } } -static void avc_chroma_hv_and_aver_dst_8w_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - uint32_t coef_hor0, - uint32_t coef_hor1, - uint32_t coef_ver0, - uint32_t coef_ver1, - int32_t height) +static void avc_chroma_hv_and_aver_dst_8x4_msa(uint8_t *src, uint8_t *dst, + int32_t stride, + uint32_t coef_hor0, + uint32_t coef_hor1, + uint32_t coef_ver0, + uint32_t coef_ver1) { - uint32_t row; + uint64_t tp0, tp1, tp2, tp3; v16u8 src0, src1, src2, src3, src4, out0, out1; v8u16 res_hz0, res_hz1, res_hz2; v8u16 res_hz3, res_hz4; v8u16 res_vt0, res_vt1, res_vt2, res_vt3; - v16u8 dst0, dst1, dst2, dst3; + v16u8 dst0 = { 0 }, dst1 = { 0 }; v16i8 mask; v16i8 coeff_hz_vec0 = __msa_fill_b(coef_hor0); v16i8 coeff_hz_vec1 = __msa_fill_b(coef_hor1); @@ -1722,197 +1679,226 @@ static void avc_chroma_hv_and_aver_dst_8w_msa(uint8_t *src, int32_t src_stride, mask = LD_SB(&chroma_mask_arr[32]); src0 = LD_UB(src); - src += src_stride; + src += stride; + src0 = (v16u8) __msa_vshf_b(mask, (v16i8) src0, (v16i8) src0); + res_hz0 = __msa_dotp_u_h(src0, coeff_hz_vec); + LD_UB4(src, stride, src1, src2, src3, src4); + src += (4 * stride); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + VSHF_B2_UB(src1, src1, src2, src2, mask, mask, src1, src2); + VSHF_B2_UB(src3, src3, src4, src4, mask, mask, src3, src4); + DOTP_UB4_UH(src1, src2, src3, src4, coeff_hz_vec, coeff_hz_vec, + coeff_hz_vec, coeff_hz_vec, res_hz1, res_hz2, res_hz3, res_hz4); + MUL4(res_hz1, coeff_vt_vec0, res_hz2, coeff_vt_vec0, res_hz3, coeff_vt_vec0, + res_hz4, coeff_vt_vec0, res_vt0, res_vt1, res_vt2, res_vt3); + res_vt0 += (res_hz0 * coeff_vt_vec1); + res_vt1 += (res_hz1 * coeff_vt_vec1); + res_vt2 += (res_hz2 * coeff_vt_vec1); + res_vt3 += (res_hz3 * coeff_vt_vec1); + SRARI_H4_UH(res_vt0, res_vt1, res_vt2, res_vt3, 6); + SAT_UH4_UH(res_vt0, res_vt1, res_vt2, res_vt3, 7); + PCKEV_B2_UB(res_vt1, res_vt0, res_vt3, res_vt2, out0, out1); + AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); + ST8x4_UB(out0, out1, dst, stride); +} + +static void avc_chroma_hv_and_aver_dst_8x8_msa(uint8_t *src, uint8_t *dst, + int32_t stride, + uint32_t coef_hor0, + uint32_t coef_hor1, + uint32_t coef_ver0, + uint32_t coef_ver1) +{ + uint64_t tp0, tp1, tp2, tp3; + v16u8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16u8 out0, out1, out2, out3; + v16u8 dst0 = { 0 }, dst1 = { 0 }, dst2 = { 0 }, dst3 = { 0 }; + v8u16 res_hz0, res_hz1, res_hz2, res_hz3, res_hz4; + v8u16 res_hz5, res_hz6, res_hz7, res_hz8; + v8u16 res_vt0, res_vt1, res_vt2, res_vt3; + v8u16 res_vt4, res_vt5, res_vt6, res_vt7; + v16i8 mask; + v16i8 coeff_hz_vec0 = __msa_fill_b(coef_hor0); + v16i8 coeff_hz_vec1 = __msa_fill_b(coef_hor1); + v16u8 coeff_hz_vec = (v16u8) __msa_ilvr_b(coeff_hz_vec0, coeff_hz_vec1); + v8u16 coeff_vt_vec0 = (v8u16) __msa_fill_h(coef_ver0); + v8u16 coeff_vt_vec1 = (v8u16) __msa_fill_h(coef_ver1); + mask = LD_SB(&chroma_mask_arr[32]); + + LD_UB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + LD_UB4(src, stride, src5, src6, src7, src8); src0 = (v16u8) __msa_vshf_b(mask, (v16i8) src0, (v16i8) src0); + VSHF_B2_UB(src1, src1, src2, src2, mask, mask, src1, src2); + VSHF_B2_UB(src3, src3, src4, src4, mask, mask, src3, src4); + VSHF_B2_UB(src5, src5, src6, src6, mask, mask, src5, src6); + VSHF_B2_UB(src7, src7, src8, src8, mask, mask, src7, src8); res_hz0 = __msa_dotp_u_h(src0, coeff_hz_vec); + DOTP_UB4_UH(src1, src2, src3, src4, coeff_hz_vec, coeff_hz_vec, + coeff_hz_vec, coeff_hz_vec, res_hz1, res_hz2, res_hz3, + res_hz4); + DOTP_UB4_UH(src5, src6, src7, src8, coeff_hz_vec, coeff_hz_vec, + coeff_hz_vec, coeff_hz_vec, res_hz5, res_hz6, res_hz7, res_hz8); + MUL4(res_hz1, coeff_vt_vec0, res_hz2, coeff_vt_vec0, res_hz3, + coeff_vt_vec0, res_hz4, coeff_vt_vec0, res_vt0, res_vt1, res_vt2, + res_vt3); + MUL4(res_hz5, coeff_vt_vec0, res_hz6, coeff_vt_vec0, res_hz7, + coeff_vt_vec0, res_hz8, coeff_vt_vec0, res_vt4, res_vt5, res_vt6, + res_vt7); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + LD4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst2); + INSERT_D2_UB(tp2, tp3, dst3); + res_vt0 += (res_hz0 * coeff_vt_vec1); + res_vt1 += (res_hz1 * coeff_vt_vec1); + res_vt2 += (res_hz2 * coeff_vt_vec1); + res_vt3 += (res_hz3 * coeff_vt_vec1); + res_vt4 += (res_hz4 * coeff_vt_vec1); + res_vt5 += (res_hz5 * coeff_vt_vec1); + res_vt6 += (res_hz6 * coeff_vt_vec1); + res_vt7 += (res_hz7 * coeff_vt_vec1); + SRARI_H4_UH(res_vt0, res_vt1, res_vt2, res_vt3, 6); + SRARI_H4_UH(res_vt4, res_vt5, res_vt6, res_vt7, 6); + SAT_UH4_UH(res_vt0, res_vt1, res_vt2, res_vt3, 7); + SAT_UH4_UH(res_vt4, res_vt5, res_vt6, res_vt7, 7); + PCKEV_B2_UB(res_vt1, res_vt0, res_vt3, res_vt2, out0, out1); + PCKEV_B2_UB(res_vt5, res_vt4, res_vt7, res_vt6, out2, out3); + AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); + AVER_UB2_UB(out2, dst2, out3, dst3, out2, out3); + ST8x8_UB(out0, out1, out2, out3, dst, stride); +} - for (row = (height >> 2); row--;) { - LD_UB4(src, src_stride, src1, src2, src3, src4); - src += (4 * src_stride); - - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - VSHF_B2_UB(src1, src1, src2, src2, mask, mask, src1, src2); - VSHF_B2_UB(src3, src3, src4, src4, mask, mask, src3, src4); - DOTP_UB4_UH(src1, src2, src3, src4, coeff_hz_vec, coeff_hz_vec, - coeff_hz_vec, coeff_hz_vec, res_hz1, res_hz2, res_hz3, - res_hz4); - MUL4(res_hz1, coeff_vt_vec0, res_hz2, coeff_vt_vec0, res_hz3, - coeff_vt_vec0, res_hz4, coeff_vt_vec0, res_vt0, res_vt1, res_vt2, - res_vt3); - - res_vt0 += (res_hz0 * coeff_vt_vec1); - res_vt1 += (res_hz1 * coeff_vt_vec1); - res_vt2 += (res_hz2 * coeff_vt_vec1); - res_vt3 += (res_hz3 * coeff_vt_vec1); - - SRARI_H4_UH(res_vt0, res_vt1, res_vt2, res_vt3, 6); - SAT_UH4_UH(res_vt0, res_vt1, res_vt2, res_vt3, 7); - - PCKEV_B2_UB(res_vt1, res_vt0, res_vt3, res_vt2, out0, out1); - PCKEV_D2_UB(dst1, dst0, dst3, dst2, dst0, dst1); - AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); - ST8x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); - - res_hz0 = res_hz4; +static void avc_chroma_hv_and_aver_dst_8w_msa(uint8_t *src, uint8_t *dst, + int32_t stride, + uint32_t coef_hor0, + uint32_t coef_hor1, + uint32_t coef_ver0, + uint32_t coef_ver1, + int32_t height) +{ + if (4 == height) { + avc_chroma_hv_and_aver_dst_8x4_msa(src, dst, stride, coef_hor0, + coef_hor1, coef_ver0, coef_ver1); + } else if (8 == height) { + avc_chroma_hv_and_aver_dst_8x8_msa(src, dst, stride, coef_hor0, + coef_hor1, coef_ver0, coef_ver1); } } -static void copy_width8_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, +static void copy_width4_msa(uint8_t *src, uint8_t *dst, int32_t stride, int32_t height) { - int32_t cnt; - uint64_t out0, out1, out2, out3, out4, out5, out6, out7; - v16u8 src0, src1, src2, src3, src4, src5, src6, src7; + uint32_t tp0, tp1, tp2, tp3, tp4, tp5, tp6, tp7; - if (0 == height % 12) { - for (cnt = (height / 12); cnt--;) { - LD_UB8(src, src_stride, - src0, src1, src2, src3, src4, src5, src6, src7); - src += (8 * src_stride); - - out0 = __msa_copy_u_d((v2i64) src0, 0); - out1 = __msa_copy_u_d((v2i64) src1, 0); - out2 = __msa_copy_u_d((v2i64) src2, 0); - out3 = __msa_copy_u_d((v2i64) src3, 0); - out4 = __msa_copy_u_d((v2i64) src4, 0); - out5 = __msa_copy_u_d((v2i64) src5, 0); - out6 = __msa_copy_u_d((v2i64) src6, 0); - out7 = __msa_copy_u_d((v2i64) src7, 0); - - SD4(out0, out1, out2, out3, dst, dst_stride); - dst += (4 * dst_stride); - SD4(out4, out5, out6, out7, dst, dst_stride); - dst += (4 * dst_stride); - - LD_UB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); - - out0 = __msa_copy_u_d((v2i64) src0, 0); - out1 = __msa_copy_u_d((v2i64) src1, 0); - out2 = __msa_copy_u_d((v2i64) src2, 0); - out3 = __msa_copy_u_d((v2i64) src3, 0); - - SD4(out0, out1, out2, out3, dst, dst_stride); - dst += (4 * dst_stride); - } - } else if (0 == height % 8) { - for (cnt = height >> 3; cnt--;) { - LD_UB8(src, src_stride, - src0, src1, src2, src3, src4, src5, src6, src7); - src += (8 * src_stride); - - out0 = __msa_copy_u_d((v2i64) src0, 0); - out1 = __msa_copy_u_d((v2i64) src1, 0); - out2 = __msa_copy_u_d((v2i64) src2, 0); - out3 = __msa_copy_u_d((v2i64) src3, 0); - out4 = __msa_copy_u_d((v2i64) src4, 0); - out5 = __msa_copy_u_d((v2i64) src5, 0); - out6 = __msa_copy_u_d((v2i64) src6, 0); - out7 = __msa_copy_u_d((v2i64) src7, 0); - - SD4(out0, out1, out2, out3, dst, dst_stride); - dst += (4 * dst_stride); - SD4(out4, out5, out6, out7, dst, dst_stride); - dst += (4 * dst_stride); - } - } else if (0 == height % 4) { - for (cnt = (height / 4); cnt--;) { - LD_UB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); - out0 = __msa_copy_u_d((v2i64) src0, 0); - out1 = __msa_copy_u_d((v2i64) src1, 0); - out2 = __msa_copy_u_d((v2i64) src2, 0); - out3 = __msa_copy_u_d((v2i64) src3, 0); - - SD4(out0, out1, out2, out3, dst, dst_stride); - dst += (4 * dst_stride); - } - } else if (0 == height % 2) { - for (cnt = (height / 2); cnt--;) { - LD_UB2(src, src_stride, src0, src1); - src += (2 * src_stride); - out0 = __msa_copy_u_d((v2i64) src0, 0); - out1 = __msa_copy_u_d((v2i64) src1, 0); - - SD(out0, dst); - dst += dst_stride; - SD(out1, dst); - dst += dst_stride; - } + if (8 == height) { + LW4(src, stride, tp0, tp1, tp2, tp3); + src += 4 * stride; + LW4(src, stride, tp4, tp5, tp6, tp7); + SW4(tp0, tp1, tp2, tp3, dst, stride); + dst += 4 * stride; + SW4(tp4, tp5, tp6, tp7, dst, stride); + } else if (4 == height) { + LW4(src, stride, tp0, tp1, tp2, tp3); + SW4(tp0, tp1, tp2, tp3, dst, stride); + } else if (2 == height) { + LW2(src, stride, tp0, tp1); + SW(tp0, dst); + dst += stride; + SW(tp1, dst); } } -static void avg_width4_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - int32_t height) +static void copy_width8_msa(uint8_t *src, uint8_t *dst, int32_t stride, + int32_t height) { - int32_t cnt; - uint32_t out0, out1, out2, out3; - v16u8 src0, src1, src2, src3; - v16u8 dst0, dst1, dst2, dst3; - - if (0 == (height % 4)) { - for (cnt = (height / 4); cnt--;) { - LD_UB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); - - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - - AVER_UB4_UB(src0, dst0, src1, dst1, src2, dst2, src3, dst3, - dst0, dst1, dst2, dst3); - - out0 = __msa_copy_u_w((v4i32) dst0, 0); - out1 = __msa_copy_u_w((v4i32) dst1, 0); - out2 = __msa_copy_u_w((v4i32) dst2, 0); - out3 = __msa_copy_u_w((v4i32) dst3, 0); - SW4(out0, out1, out2, out3, dst, dst_stride); - dst += (4 * dst_stride); - } - } else if (0 == (height % 2)) { - for (cnt = (height / 2); cnt--;) { - LD_UB2(src, src_stride, src0, src1); - src += (2 * src_stride); - - LD_UB2(dst, dst_stride, dst0, dst1); + uint64_t src0, src1, src2, src3, src4, src5, src6, src7; - AVER_UB2_UB(src0, dst0, src1, dst1, dst0, dst1); + if (8 == height) { + LD4(src, stride, src0, src1, src2, src3); + src += 4 * stride; + LD4(src, stride, src4, src5, src6, src7); + SD4(src0, src1, src2, src3, dst, stride); + dst += 4 * stride; + SD4(src4, src5, src6, src7, dst, stride); + } else if (4 == height) { + LD4(src, stride, src0, src1, src2, src3); + SD4(src0, src1, src2, src3, dst, stride); + } +} - out0 = __msa_copy_u_w((v4i32) dst0, 0); - out1 = __msa_copy_u_w((v4i32) dst1, 0); - SW(out0, dst); - dst += dst_stride; - SW(out1, dst); - dst += dst_stride; - } +static void avg_width4_msa(uint8_t *src, uint8_t *dst, int32_t stride, + int32_t height) +{ + uint32_t tp0, tp1, tp2, tp3; + v16u8 src0 = { 0 }, src1 = { 0 }, dst0 = { 0 }, dst1 = { 0 }; + + if (8 == height) { + LW4(src, stride, tp0, tp1, tp2, tp3); + src += 4 * stride; + INSERT_W4_UB(tp0, tp1, tp2, tp3, src0); + LW4(src, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, src1); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + LW4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst1); + AVER_UB2_UB(src0, dst0, src1, dst1, dst0, dst1); + ST4x8_UB(dst0, dst1, dst, stride); + } else if (4 == height) { + LW4(src, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, src0); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + dst0 = __msa_aver_u_b(src0, dst0); + ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); + } else if (2 == height) { + LW2(src, stride, tp0, tp1); + INSERT_W2_UB(tp0, tp1, src0); + LW2(dst, stride, tp0, tp1); + INSERT_W2_UB(tp0, tp1, dst0); + dst0 = __msa_aver_u_b(src0, dst0); + ST4x2_UB(dst0, dst, stride); } } -static void avg_width8_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, +static void avg_width8_msa(uint8_t *src, uint8_t *dst, int32_t stride, int32_t height) { - int32_t cnt; - uint64_t out0, out1, out2, out3; - v16u8 src0, src1, src2, src3; - v16u8 dst0, dst1, dst2, dst3; - - for (cnt = (height / 4); cnt--;) { - LD_UB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - - AVER_UB4_UB(src0, dst0, src1, dst1, src2, dst2, src3, dst3, - dst0, dst1, dst2, dst3); - - out0 = __msa_copy_u_d((v2i64) dst0, 0); - out1 = __msa_copy_u_d((v2i64) dst1, 0); - out2 = __msa_copy_u_d((v2i64) dst2, 0); - out3 = __msa_copy_u_d((v2i64) dst3, 0); - SD4(out0, out1, out2, out3, dst, dst_stride); - dst += (4 * dst_stride); + uint64_t tp0, tp1, tp2, tp3, tp4, tp5, tp6, tp7; + v16u8 src0 = { 0 }, src1 = { 0 }, src2 = { 0 }, src3 = { 0 }; + v16u8 dst0 = { 0 }, dst1 = { 0 }, dst2 = { 0 }, dst3 = { 0 }; + + if (8 == height) { + LD4(src, stride, tp0, tp1, tp2, tp3); + src += 4 * stride; + LD4(src, stride, tp4, tp5, tp6, tp7); + INSERT_D2_UB(tp0, tp1, src0); + INSERT_D2_UB(tp2, tp3, src1); + INSERT_D2_UB(tp4, tp5, src2); + INSERT_D2_UB(tp6, tp7, src3); + LD4(dst, stride, tp0, tp1, tp2, tp3); + LD4(dst + 4 * stride, stride, tp4, tp5, tp6, tp7); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + INSERT_D2_UB(tp4, tp5, dst2); + INSERT_D2_UB(tp6, tp7, dst3); + AVER_UB4_UB(src0, dst0, src1, dst1, src2, dst2, src3, dst3, dst0, dst1, + dst2, dst3); + ST8x8_UB(dst0, dst1, dst2, dst3, dst, stride); + } else if (4 == height) { + LD4(src, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, src0); + INSERT_D2_UB(tp2, tp3, src1); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + AVER_UB2_UB(src0, dst0, src1, dst1, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, stride); } } @@ -1928,15 +1914,13 @@ void ff_put_h264_chroma_mc8_msa(uint8_t *dst, uint8_t *src, } else if (y) { avc_chroma_vt_8w_msa(src, dst, stride, y, (8 - y), height); } else { - copy_width8_msa(src, stride, dst, stride, height); + copy_width8_msa(src, dst, stride, height); } } void ff_put_h264_chroma_mc4_msa(uint8_t *dst, uint8_t *src, ptrdiff_t stride, int height, int x, int y) { - int32_t cnt; - av_assert2(x < 8 && y < 8 && x >= 0 && y >= 0); if (x && y) { @@ -1946,12 +1930,7 @@ void ff_put_h264_chroma_mc4_msa(uint8_t *dst, uint8_t *src, } else if (y) { avc_chroma_vt_4w_msa(src, dst, stride, y, (8 - y), height); } else { - for (cnt = height; cnt--;) { - *((uint32_t *) dst) = *((uint32_t *) src); - - src += stride; - dst += stride; - } + copy_width4_msa(src, dst, stride, height); } } @@ -1985,17 +1964,14 @@ void ff_avg_h264_chroma_mc8_msa(uint8_t *dst, uint8_t *src, if (x && y) { - avc_chroma_hv_and_aver_dst_8w_msa(src, stride, dst, - stride, x, (8 - x), y, + avc_chroma_hv_and_aver_dst_8w_msa(src, dst, stride, x, (8 - x), y, (8 - y), height); } else if (x) { - avc_chroma_hz_and_aver_dst_8w_msa(src, stride, dst, - stride, x, (8 - x), height); + avc_chroma_hz_and_aver_dst_8w_msa(src, dst, stride, x, (8 - x), height); } else if (y) { - avc_chroma_vt_and_aver_dst_8w_msa(src, stride, dst, - stride, y, (8 - y), height); + avc_chroma_vt_and_aver_dst_8w_msa(src, dst, stride, y, (8 - y), height); } else { - avg_width8_msa(src, stride, dst, stride, height); + avg_width8_msa(src, dst, stride, height); } } @@ -2005,17 +1981,14 @@ void ff_avg_h264_chroma_mc4_msa(uint8_t *dst, uint8_t *src, av_assert2(x < 8 && y < 8 && x >= 0 && y >= 0); if (x && y) { - avc_chroma_hv_and_aver_dst_4w_msa(src, stride, dst, - stride, x, (8 - x), y, + avc_chroma_hv_and_aver_dst_4w_msa(src, dst, stride, x, (8 - x), y, (8 - y), height); } else if (x) { - avc_chroma_hz_and_aver_dst_4w_msa(src, stride, dst, - stride, x, (8 - x), height); + avc_chroma_hz_and_aver_dst_4w_msa(src, dst, stride, x, (8 - x), height); } else if (y) { - avc_chroma_vt_and_aver_dst_4w_msa(src, stride, dst, - stride, y, (8 - y), height); + avc_chroma_vt_and_aver_dst_4w_msa(src, dst, stride, y, (8 - y), height); } else { - avg_width4_msa(src, stride, dst, stride, height); + avg_width4_msa(src, dst, stride, height); } } @@ -2027,15 +2000,12 @@ void ff_avg_h264_chroma_mc2_msa(uint8_t *dst, uint8_t *src, av_assert2(x < 8 && y < 8 && x >= 0 && y >= 0); if (x && y) { - avc_chroma_hv_and_aver_dst_2w_msa(src, stride, dst, - stride, x, (8 - x), y, + avc_chroma_hv_and_aver_dst_2w_msa(src, dst, stride, x, (8 - x), y, (8 - y), height); } else if (x) { - avc_chroma_hz_and_aver_dst_2w_msa(src, stride, dst, - stride, x, (8 - x), height); + avc_chroma_hz_and_aver_dst_2w_msa(src, dst, stride, x, (8 - x), height); } else if (y) { - avc_chroma_vt_and_aver_dst_2w_msa(src, stride, dst, - stride, y, (8 - y), height); + avc_chroma_vt_and_aver_dst_2w_msa(src, dst, stride, y, (8 - y), height); } else { for (cnt = height; cnt--;) { dst[0] = (dst[0] + src[0] + 1) >> 1; diff --git a/libavcodec/mips/h264qpel_msa.c b/libavcodec/mips/h264qpel_msa.c index a22a4828c6bb9..9c779bdd4f407 100644 --- a/libavcodec/mips/h264qpel_msa.c +++ b/libavcodec/mips/h264qpel_msa.c @@ -21,31 +21,7 @@ #include "libavutil/mips/generic_macros_msa.h" #include "h264dsp_mips.h" -#define AVC_CALC_DPADD_H_6PIX_2COEFF_SH(in0, in1, in2, in3, in4, in5) \ -( { \ - v4i32 tmp0_m, tmp1_m; \ - v8i16 out0_m, out1_m, out2_m, out3_m; \ - v8i16 minus5h_m = __msa_ldi_h(-5); \ - v8i16 plus20h_m = __msa_ldi_h(20); \ - \ - ILVRL_H2_SW(in5, in0, tmp0_m, tmp1_m); \ - \ - tmp0_m = __msa_hadd_s_w((v8i16) tmp0_m, (v8i16) tmp0_m); \ - tmp1_m = __msa_hadd_s_w((v8i16) tmp1_m, (v8i16) tmp1_m); \ - \ - ILVRL_H2_SH(in1, in4, out0_m, out1_m); \ - DPADD_SH2_SW(out0_m, out1_m, minus5h_m, minus5h_m, tmp0_m, tmp1_m); \ - ILVRL_H2_SH(in2, in3, out2_m, out3_m); \ - DPADD_SH2_SW(out2_m, out3_m, plus20h_m, plus20h_m, tmp0_m, tmp1_m); \ - \ - SRARI_W2_SW(tmp0_m, tmp1_m, 10); \ - SAT_SW2_SW(tmp0_m, tmp1_m, 7); \ - out0_m = __msa_pckev_h((v8i16) tmp1_m, (v8i16) tmp0_m); \ - \ - out0_m; \ -} ) - -static const uint8_t luma_mask_arr[16 * 8] = { +static const uint8_t luma_mask_arr[16 * 6] __attribute__((aligned(0x40))) = { /* 8 width cases */ 0, 5, 1, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 1, 4, 2, 5, 3, 6, 4, 7, 5, 8, 6, 9, 7, 10, 8, 11, @@ -55,9 +31,6 @@ static const uint8_t luma_mask_arr[16 * 8] = { 0, 5, 1, 6, 2, 7, 3, 8, 16, 21, 17, 22, 18, 23, 19, 24, 1, 4, 2, 5, 3, 6, 4, 7, 17, 20, 18, 21, 19, 22, 20, 23, 2, 3, 3, 4, 4, 5, 5, 6, 18, 19, 19, 20, 20, 21, 21, 22, - - 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 24, 25, - 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 24, 25, 26 }; #define AVC_CALC_DPADD_B_6PIX_2COEFF_SH(vec0, vec1, vec2, vec3, vec4, vec5, \ @@ -75,60 +48,6 @@ static const uint8_t luma_mask_arr[16 * 8] = { DPADD_SB2_SH(tmp0_m, tmp1_m, plus20b_m, plus20b_m, out1, out2); \ } -#define AVC_CALC_DPADD_B_6PIX_2COEFF_R_SH(vec0, vec1, vec2, vec3, vec4, vec5) \ -( { \ - v8i16 tmp1_m; \ - v16i8 tmp0_m, tmp2_m; \ - v16i8 minus5b_m = __msa_ldi_b(-5); \ - v16i8 plus20b_m = __msa_ldi_b(20); \ - \ - tmp1_m = (v8i16) __msa_ilvr_b((v16i8) vec5, (v16i8) vec0); \ - tmp1_m = __msa_hadd_s_h((v16i8) tmp1_m, (v16i8) tmp1_m); \ - \ - ILVR_B2_SB(vec4, vec1, vec3, vec2, tmp0_m, tmp2_m); \ - DPADD_SB2_SH(tmp0_m, tmp2_m, minus5b_m, plus20b_m, tmp1_m, tmp1_m); \ - \ - tmp1_m; \ -} ) - -#define AVC_CALC_DPADD_H_6PIX_2COEFF_R_SH(vec0, vec1, vec2, vec3, vec4, vec5) \ -( { \ - v4i32 tmp1_m; \ - v8i16 tmp2_m, tmp3_m; \ - v8i16 minus5h_m = __msa_ldi_h(-5); \ - v8i16 plus20h_m = __msa_ldi_h(20); \ - \ - tmp1_m = (v4i32) __msa_ilvr_h((v8i16) vec5, (v8i16) vec0); \ - tmp1_m = __msa_hadd_s_w((v8i16) tmp1_m, (v8i16) tmp1_m); \ - \ - ILVR_H2_SH(vec1, vec4, vec2, vec3, tmp2_m, tmp3_m); \ - DPADD_SH2_SW(tmp2_m, tmp3_m, minus5h_m, plus20h_m, tmp1_m, tmp1_m); \ - \ - tmp1_m = __msa_srari_w(tmp1_m, 10); \ - tmp1_m = __msa_sat_s_w(tmp1_m, 7); \ - \ - tmp2_m = __msa_pckev_h((v8i16) tmp1_m, (v8i16) tmp1_m); \ - \ - tmp2_m; \ -} ) - -#define AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src0, src1, \ - mask0, mask1, mask2) \ -( { \ - v8i16 hz_out_m; \ - v16i8 vec0_m, vec1_m, vec2_m; \ - v16i8 minus5b_m = __msa_ldi_b(-5); \ - v16i8 plus20b_m = __msa_ldi_b(20); \ - \ - vec0_m = __msa_vshf_b((v16i8) mask0, (v16i8) src1, (v16i8) src0); \ - hz_out_m = __msa_hadd_s_h(vec0_m, vec0_m); \ - \ - VSHF_B2_SB(src0, src1, src0, src1, mask1, mask2, vec1_m, vec2_m); \ - DPADD_SB2_SH(vec1_m, vec2_m, minus5b_m, plus20b_m, hz_out_m, hz_out_m); \ - \ - hz_out_m; \ -} ) - #define AVC_HORZ_FILTER_SH(in0, in1, mask0, mask1, mask2) \ ( { \ v8i16 out0_m; \ @@ -171,258 +90,293 @@ static const uint8_t luma_mask_arr[16 * 8] = { out0_m; \ } ) -static void avc_luma_mid_4w_msa(const uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - int32_t height) +static void avc_luma_hv_qrt_4x4_msa(const uint8_t *src_x, const uint8_t *src_y, + uint8_t *dst, int32_t stride) { - uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4; - v16i8 mask0, mask1, mask2; - v8i16 hz_out0, hz_out1, hz_out2, hz_out3; - v8i16 hz_out4, hz_out5, hz_out6, hz_out7, hz_out8; - v8i16 dst0, dst1, dst2, dst3; - - LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); - - XORI_B5_128_SB(src0, src1, src2, src3, src4); - - hz_out0 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src0, src1, - mask0, mask1, mask2); - hz_out2 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src2, src3, - mask0, mask1, mask2); + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + v16u8 out; + v16i8 src_hz0, src_hz1, src_hz2, src_hz3, src_vt7, src_vt8; + v16i8 src_vt0, src_vt1, src_vt2, src_vt3, src_vt4, src_vt5, src_vt6; + v16i8 src_vt10_r, src_vt32_r, src_vt54_r, src_vt76_r; + v16i8 mask0, mask1, mask2, filt0, filt1, filt2; + v8i16 hz_out0, hz_out1, vt_out0, vt_out1, out0, out1; - PCKOD_D2_SH(hz_out0, hz_out0, hz_out2, hz_out2, hz_out1, hz_out3); + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); - hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); + LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); + LD_SB5(src_y, stride, src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); + src_y += (5 * stride); - XORI_B4_128_SB(src0, src1, src2, src3); + src_vt0 = (v16i8) __msa_insve_w((v4i32) src_vt0, 1, (v4i32) src_vt1); + src_vt1 = (v16i8) __msa_insve_w((v4i32) src_vt1, 1, (v4i32) src_vt2); + src_vt2 = (v16i8) __msa_insve_w((v4i32) src_vt2, 1, (v4i32) src_vt3); + src_vt3 = (v16i8) __msa_insve_w((v4i32) src_vt3, 1, (v4i32) src_vt4); - hz_out5 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src0, src1, - mask0, mask1, - mask2); - hz_out7 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src2, src3, - mask0, mask1, - mask2); + XORI_B4_128_SB(src_vt0, src_vt1, src_vt2, src_vt3); - PCKOD_D2_SH(hz_out5, hz_out5, hz_out7, hz_out7, hz_out6, hz_out8); + LD_SB4(src_x, stride, src_hz0, src_hz1, src_hz2, src_hz3); + XORI_B4_128_SB(src_hz0, src_hz1, src_hz2, src_hz3); + hz_out0 = AVC_HORZ_FILTER_SH(src_hz0, src_hz1, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src_hz2, src_hz3, mask0, mask1, mask2); - dst0 = AVC_CALC_DPADD_H_6PIX_2COEFF_R_SH(hz_out0, hz_out1, hz_out2, - hz_out3, hz_out4, hz_out5); - dst1 = AVC_CALC_DPADD_H_6PIX_2COEFF_R_SH(hz_out1, hz_out2, hz_out3, - hz_out4, hz_out5, hz_out6); - dst2 = AVC_CALC_DPADD_H_6PIX_2COEFF_R_SH(hz_out2, hz_out3, hz_out4, - hz_out5, hz_out6, hz_out7); - dst3 = AVC_CALC_DPADD_H_6PIX_2COEFF_R_SH(hz_out3, hz_out4, hz_out5, - hz_out6, hz_out7, hz_out8); + SRARI_H2_SH(hz_out0, hz_out1, 5); + SAT_SH2_SH(hz_out0, hz_out1, 7); - PCKEV_B2_SB(dst1, dst0, dst3, dst2, src0, src1); - XORI_B2_128_SB(src0, src1); + LD_SB4(src_y, stride, src_vt5, src_vt6, src_vt7, src_vt8); - ST4x4_UB(src0, src1, 0, 2, 0, 2, dst, dst_stride); + src_vt4 = (v16i8) __msa_insve_w((v4i32) src_vt4, 1, (v4i32) src_vt5); + src_vt5 = (v16i8) __msa_insve_w((v4i32) src_vt5, 1, (v4i32) src_vt6); + src_vt6 = (v16i8) __msa_insve_w((v4i32) src_vt6, 1, (v4i32) src_vt7); + src_vt7 = (v16i8) __msa_insve_w((v4i32) src_vt7, 1, (v4i32) src_vt8); - dst += (4 * dst_stride); + XORI_B4_128_SB(src_vt4, src_vt5, src_vt6, src_vt7); + ILVR_B2_SB(src_vt1, src_vt0, src_vt3, src_vt2, src_vt10_r, src_vt32_r); + ILVR_B2_SB(src_vt5, src_vt4, src_vt7, src_vt6, src_vt54_r, src_vt76_r); + vt_out0 = AVC_DOT_SH3_SH(src_vt10_r, src_vt32_r, src_vt54_r, filt0, filt1, + filt2); + vt_out1 = AVC_DOT_SH3_SH(src_vt32_r, src_vt54_r, src_vt76_r, filt0, filt1, + filt2); + SRARI_H2_SH(vt_out0, vt_out1, 5); + SAT_SH2_SH(vt_out0, vt_out1, 7); + + out0 = __msa_srari_h((hz_out0 + vt_out0), 1); + out1 = __msa_srari_h((hz_out1 + vt_out1), 1); - hz_out0 = hz_out4; - hz_out1 = hz_out5; - hz_out2 = hz_out6; - hz_out3 = hz_out7; - hz_out4 = hz_out8; - } + SAT_SH2_SH(out0, out1, 7); + out = PCKEV_XORI128_UB(out0, out1); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); } -static void avc_luma_mid_8w_msa(const uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - int32_t height) +static void avc_luma_hv_qrt_8x8_msa(const uint8_t *src_x, const uint8_t *src_y, + uint8_t *dst, int32_t stride) { - uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4; - v16i8 mask0, mask1, mask2; - v8i16 hz_out0, hz_out1, hz_out2, hz_out3; - v8i16 hz_out4, hz_out5, hz_out6, hz_out7, hz_out8; - v8i16 dst0, dst1, dst2, dst3; + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; v16u8 out0, out1; + v16i8 src_hz0, src_hz1, src_hz2, src_hz3, mask0, mask1, mask2; + v16i8 src_vt0, src_vt1, src_vt2, src_vt3, src_vt4, src_vt5, src_vt6; + v16i8 src_vt7, src_vt8, src_vt9, src_vt10, src_vt11, src_vt12; + v16i8 src_vt10_r, src_vt21_r, src_vt32_r, src_vt43_r, src_vt54_r; + v16i8 src_vt65_r, src_vt76_r, src_vt87_r, src_vt98_r, src_vt109_r; + v16i8 src_vt1110_r, src_vt1211_r, filt0, filt1, filt2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, vt_out0, vt_out1, vt_out2; + v8i16 vt_out3, tmp0, tmp1, tmp2, tmp3; - LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - XORI_B5_128_SB(src0, src1, src2, src3, src4); - src += (5 * src_stride); + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + LD_SB5(src_y, stride, src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); + src_y += (5 * stride); - hz_out0 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); - hz_out1 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); - hz_out2 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); - hz_out3 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); - hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); + XORI_B5_128_SB(src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src, src_stride, src0, src1, src2, src3); - XORI_B4_128_SB(src0, src1, src2, src3); - src += (4 * src_stride); - - hz_out5 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); - hz_out6 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); - hz_out7 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); - hz_out8 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); - dst0 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out0, hz_out1, hz_out2, - hz_out3, hz_out4, hz_out5); - dst1 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out1, hz_out2, hz_out3, - hz_out4, hz_out5, hz_out6); - dst2 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out2, hz_out3, hz_out4, - hz_out5, hz_out6, hz_out7); - dst3 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out3, hz_out4, hz_out5, - hz_out6, hz_out7, hz_out8); - out0 = PCKEV_XORI128_UB(dst0, dst1); - out1 = PCKEV_XORI128_UB(dst2, dst3); - ST8x4_UB(out0, out1, dst, dst_stride); - - dst += (4 * dst_stride); - hz_out3 = hz_out7; - hz_out1 = hz_out5; - hz_out5 = hz_out4; - hz_out4 = hz_out8; - hz_out2 = hz_out6; - hz_out0 = hz_out5; - } -} + LD_SB4(src_x, stride, src_hz0, src_hz1, src_hz2, src_hz3); + XORI_B4_128_SB(src_hz0, src_hz1, src_hz2, src_hz3); + src_x += (4 * stride); + + hz_out0 = AVC_HORZ_FILTER_SH(src_hz0, src_hz0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src_hz1, src_hz1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src_hz2, src_hz2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src_hz3, src_hz3, mask0, mask1, mask2); + + SRARI_H4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 5); + SAT_SH4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 7); + + LD_SB4(src_y, stride, src_vt5, src_vt6, src_vt7, src_vt8); + src_y += (4 * stride); + XORI_B4_128_SB(src_vt5, src_vt6, src_vt7, src_vt8); + + ILVR_B4_SB(src_vt1, src_vt0, src_vt2, src_vt1, src_vt3, src_vt2, src_vt4, + src_vt3, src_vt10_r, src_vt21_r, src_vt32_r, src_vt43_r); + ILVR_B4_SB(src_vt5, src_vt4, src_vt6, src_vt5, src_vt7, src_vt6, src_vt8, + src_vt7, src_vt54_r, src_vt65_r, src_vt76_r, src_vt87_r); + vt_out0 = AVC_DOT_SH3_SH(src_vt10_r, src_vt32_r, src_vt54_r, filt0, filt1, + filt2); + vt_out1 = AVC_DOT_SH3_SH(src_vt21_r, src_vt43_r, src_vt65_r, filt0, filt1, + filt2); + vt_out2 = AVC_DOT_SH3_SH(src_vt32_r, src_vt54_r, src_vt76_r, filt0, filt1, + filt2); + vt_out3 = AVC_DOT_SH3_SH(src_vt43_r, src_vt65_r, src_vt87_r, filt0, filt1, + filt2); + SRARI_H4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 5); + SAT_SH4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 7); + + tmp0 = __msa_srari_h((hz_out0 + vt_out0), 1); + tmp1 = __msa_srari_h((hz_out1 + vt_out1), 1); + tmp2 = __msa_srari_h((hz_out2 + vt_out2), 1); + tmp3 = __msa_srari_h((hz_out3 + vt_out3), 1); + + LD_SB4(src_x, stride, src_hz0, src_hz1, src_hz2, src_hz3); + XORI_B4_128_SB(src_hz0, src_hz1, src_hz2, src_hz3); -static void avc_luma_mid_16w_msa(const uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - int32_t height) -{ - uint32_t multiple8_cnt; + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + ST8x4_UB(out0, out1, dst, stride); + dst += (4 * stride); - for (multiple8_cnt = 2; multiple8_cnt--;) { - avc_luma_mid_8w_msa(src, src_stride, dst, dst_stride, height); - src += 8; - dst += 8; - } + LD_SB4(src_y, stride, src_vt9, src_vt10, src_vt11, src_vt12); + XORI_B4_128_SB(src_vt9, src_vt10, src_vt11, src_vt12); + + hz_out0 = AVC_HORZ_FILTER_SH(src_hz0, src_hz0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src_hz1, src_hz1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src_hz2, src_hz2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src_hz3, src_hz3, mask0, mask1, mask2); + + SRARI_H4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 5); + SAT_SH4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 7); + + ILVR_B4_SB(src_vt9, src_vt8, src_vt10, src_vt9, src_vt11, src_vt10, + src_vt12, src_vt11, src_vt98_r, src_vt109_r, src_vt1110_r, + src_vt1211_r); + vt_out0 = AVC_DOT_SH3_SH(src_vt54_r, src_vt76_r, src_vt98_r, filt0, filt1, + filt2); + vt_out1 = AVC_DOT_SH3_SH(src_vt65_r, src_vt87_r, src_vt109_r, filt0, filt1, + filt2); + vt_out2 = AVC_DOT_SH3_SH(src_vt76_r, src_vt98_r, src_vt1110_r, filt0, filt1, + filt2); + vt_out3 = AVC_DOT_SH3_SH(src_vt87_r, src_vt109_r, src_vt1211_r, filt0, + filt1, filt2); + SRARI_H4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 5); + SAT_SH4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 7); + + tmp0 = __msa_srari_h((hz_out0 + vt_out0), 1); + tmp1 = __msa_srari_h((hz_out1 + vt_out1), 1); + tmp2 = __msa_srari_h((hz_out2 + vt_out2), 1); + tmp3 = __msa_srari_h((hz_out3 + vt_out3), 1); + + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + ST8x4_UB(out0, out1, dst, stride); + dst += (4 * stride); } -static void avc_luma_midh_qrt_4w_msa(const uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - int32_t height, uint8_t horiz_offset) +static void avc_luma_hv_qrt_16x16_msa(const uint8_t *src_x, + const uint8_t *src_y, uint8_t *dst, + int32_t stride) { - uint32_t row; - v16i8 src0, src1, src2, src3, src4, src5, src6; - v8i16 vt_res0, vt_res1, vt_res2, vt_res3; - v4i32 hz_res0, hz_res1; - v8i16 dst0, dst1; - v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5; - v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; - v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; - v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; - v8i16 minus5h = __msa_ldi_h(-5); - v8i16 plus20h = __msa_ldi_h(20); - v8i16 zeros = { 0 }; - v16u8 out; + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + const uint8_t *src_x_tmp = src_x; + const uint8_t *src_y_tmp = src_y; + uint8_t *dst_tmp = dst; + uint32_t multiple8_cnt, loop_cnt; + v16u8 tmp0, tmp1; + v16i8 src_hz0, src_hz1, src_hz2, src_hz3, mask0, mask1, mask2; + v16i8 src_vt0, src_vt1, src_vt2, src_vt3, src_vt4, src_vt5, src_vt6; + v16i8 src_vt7, src_vt8; + v16i8 src_vt10_r, src_vt21_r, src_vt32_r, src_vt43_r, src_vt54_r; + v16i8 src_vt65_r, src_vt76_r, src_vt87_r, filt0, filt1, filt2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, vt_out0, vt_out1, vt_out2; + v8i16 vt_out3, out0, out1, out2, out3; - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); - XORI_B5_128_SB(src0, src1, src2, src3, src4); + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); - for (row = (height >> 1); row--;) { - LD_SB2(src, src_stride, src5, src6); - src += (2 * src_stride); + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); - XORI_B2_128_SB(src5, src6); - AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src0, src1, src2, src3, src4, src5, - vt_res0, vt_res1); - AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src1, src2, src3, src4, src5, src6, - vt_res2, vt_res3); - VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, - mask0, mask1, mask2, shf_vec0, shf_vec1, shf_vec2); - VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, - mask0, mask1, mask2, shf_vec3, shf_vec4, shf_vec5); - hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); - DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); - hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); - DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + for (multiple8_cnt = 2; multiple8_cnt--;) { + src_x = src_x_tmp; + src_y = src_y_tmp; + dst = dst_tmp; - SRARI_W2_SW(hz_res0, hz_res1, 10); - SAT_SW2_SW(hz_res0, hz_res1, 7); + LD_SB5(src_y, stride, src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); + src_y += (5 * stride); - dst0 = __msa_srari_h(shf_vec2, 5); - dst1 = __msa_srari_h(shf_vec5, 5); + XORI_B5_128_SB(src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); - SAT_SH2_SH(dst0, dst1, 7); + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src_x, stride, src_hz0, src_hz1, src_hz2, src_hz3); + XORI_B4_128_SB(src_hz0, src_hz1, src_hz2, src_hz3); + src_x += (4 * stride); + + hz_out0 = AVC_HORZ_FILTER_SH(src_hz0, src_hz0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src_hz1, src_hz1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src_hz2, src_hz2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src_hz3, src_hz3, mask0, mask1, mask2); + SRARI_H4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 5); + SAT_SH4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 7); + + LD_SB4(src_y, stride, src_vt5, src_vt6, src_vt7, src_vt8); + src_y += (4 * stride); + + XORI_B4_128_SB(src_vt5, src_vt6, src_vt7, src_vt8); + ILVR_B4_SB(src_vt1, src_vt0, src_vt2, src_vt1, src_vt3, src_vt2, + src_vt4, src_vt3, src_vt10_r, src_vt21_r, src_vt32_r, + src_vt43_r); + ILVR_B4_SB(src_vt5, src_vt4, src_vt6, src_vt5, src_vt7, src_vt6, + src_vt8, src_vt7, src_vt54_r, src_vt65_r, src_vt76_r, + src_vt87_r); + vt_out0 = AVC_DOT_SH3_SH(src_vt10_r, src_vt32_r, src_vt54_r, filt0, + filt1, filt2); + vt_out1 = AVC_DOT_SH3_SH(src_vt21_r, src_vt43_r, src_vt65_r, filt0, + filt1, filt2); + vt_out2 = AVC_DOT_SH3_SH(src_vt32_r, src_vt54_r, src_vt76_r, filt0, + filt1, filt2); + vt_out3 = AVC_DOT_SH3_SH(src_vt43_r, src_vt65_r, src_vt87_r, filt0, + filt1, filt2); + SRARI_H4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 5); + SAT_SH4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 7); + + out0 = __msa_srari_h((hz_out0 + vt_out0), 1); + out1 = __msa_srari_h((hz_out1 + vt_out1), 1); + out2 = __msa_srari_h((hz_out2 + vt_out2), 1); + out3 = __msa_srari_h((hz_out3 + vt_out3), 1); + + SAT_SH4_SH(out0, out1, out2, out3, 7); + tmp0 = PCKEV_XORI128_UB(out0, out1); + tmp1 = PCKEV_XORI128_UB(out2, out3); + ST8x4_UB(tmp0, tmp1, dst, stride); + dst += (4 * stride); - if (horiz_offset) { - dst0 = __msa_ilvod_h(zeros, dst0); - dst1 = __msa_ilvod_h(zeros, dst1); - } else { - ILVEV_H2_SH(dst0, zeros, dst1, zeros, dst0, dst1); + src_vt0 = src_vt4; + src_vt1 = src_vt5; + src_vt2 = src_vt6; + src_vt3 = src_vt7; + src_vt4 = src_vt8; } - hz_res0 = __msa_aver_s_w(hz_res0, (v4i32) dst0); - hz_res1 = __msa_aver_s_w(hz_res1, (v4i32) dst1); - dst0 = __msa_pckev_h((v8i16) hz_res1, (v8i16) hz_res0); - - out = PCKEV_XORI128_UB(dst0, dst0); - ST4x2_UB(out, dst, dst_stride); - - dst += (2 * dst_stride); - - src0 = src2; - src1 = src3; - src2 = src4; - src3 = src5; - src4 = src6; - } -} - -static void avc_luma_midh_qrt_8w_msa(const uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - int32_t height, uint8_t horiz_offset) -{ - uint32_t multiple8_cnt; - - for (multiple8_cnt = 2; multiple8_cnt--;) { - avc_luma_midh_qrt_4w_msa(src, src_stride, dst, dst_stride, height, - horiz_offset); - - src += 4; - dst += 4; + src_x_tmp += 8; + src_y_tmp += 8; + dst_tmp += 8; } } -static void avc_luma_midh_qrt_16w_msa(const uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - int32_t height, uint8_t horiz_offset) +static void avc_luma_hv_qrt_and_aver_dst_4x4_msa(const uint8_t *src_x, + const uint8_t *src_y, + uint8_t *dst, + int32_t stride) { - uint32_t multiple8_cnt; - - for (multiple8_cnt = 4; multiple8_cnt--;) { - avc_luma_midh_qrt_4w_msa(src, src_stride, dst, dst_stride, height, - horiz_offset); - - src += 4; - dst += 4; - } -} + uint32_t tp0, tp1, tp2, tp3; + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + v16u8 res, dst0 = { 0 }; + v16i8 src_hz0, src_hz1, src_hz2, src_hz3, src_vt7, src_vt8; + v16i8 src_vt0, src_vt1, src_vt2, src_vt3, src_vt4, src_vt5, src_vt6; + v16i8 src_vt10_r, src_vt32_r, src_vt54_r, src_vt76_r; + v16i8 mask0, mask1, mask2, filt0, filt1, filt2; + v8i16 hz_out0, hz_out1, vt_out0, vt_out1, res0, res1; -static void avc_luma_hv_qrt_4w_msa(const uint8_t *src_x, const uint8_t *src_y, - int32_t src_stride, uint8_t *dst, - int32_t dst_stride, int32_t height) -{ - uint32_t loop_cnt; - v16i8 src_hz0, src_hz1, src_hz2, src_hz3; - v16i8 src_vt0, src_vt1, src_vt2, src_vt3, src_vt4; - v16i8 src_vt5, src_vt6, src_vt7, src_vt8; - v16i8 mask0, mask1, mask2; - v8i16 hz_out0, hz_out1, vert_out0, vert_out1; - v8i16 out0, out1; - v16u8 out; + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); - LD_SB5(src_y, src_stride, src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); - src_y += (5 * src_stride); + LD_SB5(src_y, stride, src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); + src_y += (5 * stride); src_vt0 = (v16i8) __msa_insve_w((v4i32) src_vt0, 1, (v4i32) src_vt1); src_vt1 = (v16i8) __msa_insve_w((v4i32) src_vt1, 1, (v4i32) src_vt2); @@ -431,641 +385,1893 @@ static void avc_luma_hv_qrt_4w_msa(const uint8_t *src_x, const uint8_t *src_y, XORI_B4_128_SB(src_vt0, src_vt1, src_vt2, src_vt3); - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src_x, src_stride, src_hz0, src_hz1, src_hz2, src_hz3); - src_x += (4 * src_stride); - - XORI_B4_128_SB(src_hz0, src_hz1, src_hz2, src_hz3); - - hz_out0 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src_hz0, - src_hz1, mask0, - mask1, mask2); - hz_out1 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src_hz2, - src_hz3, mask0, - mask1, mask2); - - SRARI_H2_SH(hz_out0, hz_out1, 5); - SAT_SH2_SH(hz_out0, hz_out1, 7); - - LD_SB4(src_y, src_stride, src_vt5, src_vt6, src_vt7, src_vt8); - src_y += (4 * src_stride); + LD_SB4(src_x, stride, src_hz0, src_hz1, src_hz2, src_hz3); + XORI_B4_128_SB(src_hz0, src_hz1, src_hz2, src_hz3); + hz_out0 = AVC_HORZ_FILTER_SH(src_hz0, src_hz1, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src_hz2, src_hz3, mask0, mask1, mask2); - src_vt4 = (v16i8) __msa_insve_w((v4i32) src_vt4, 1, (v4i32) src_vt5); - src_vt5 = (v16i8) __msa_insve_w((v4i32) src_vt5, 1, (v4i32) src_vt6); - src_vt6 = (v16i8) __msa_insve_w((v4i32) src_vt6, 1, (v4i32) src_vt7); - src_vt7 = (v16i8) __msa_insve_w((v4i32) src_vt7, 1, (v4i32) src_vt8); + SRARI_H2_SH(hz_out0, hz_out1, 5); + SAT_SH2_SH(hz_out0, hz_out1, 7); - XORI_B4_128_SB(src_vt4, src_vt5, src_vt6, src_vt7); + LD_SB4(src_y, stride, src_vt5, src_vt6, src_vt7, src_vt8); - /* filter calc */ - vert_out0 = AVC_CALC_DPADD_B_6PIX_2COEFF_R_SH(src_vt0, src_vt1, - src_vt2, src_vt3, - src_vt4, src_vt5); - vert_out1 = AVC_CALC_DPADD_B_6PIX_2COEFF_R_SH(src_vt2, src_vt3, - src_vt4, src_vt5, - src_vt6, src_vt7); + src_vt4 = (v16i8) __msa_insve_w((v4i32) src_vt4, 1, (v4i32) src_vt5); + src_vt5 = (v16i8) __msa_insve_w((v4i32) src_vt5, 1, (v4i32) src_vt6); + src_vt6 = (v16i8) __msa_insve_w((v4i32) src_vt6, 1, (v4i32) src_vt7); + src_vt7 = (v16i8) __msa_insve_w((v4i32) src_vt7, 1, (v4i32) src_vt8); - SRARI_H2_SH(vert_out0, vert_out1, 5); - SAT_SH2_SH(vert_out0, vert_out1, 7); + XORI_B4_128_SB(src_vt4, src_vt5, src_vt6, src_vt7); + ILVR_B2_SB(src_vt1, src_vt0, src_vt3, src_vt2, src_vt10_r, src_vt32_r); + ILVR_B2_SB(src_vt5, src_vt4, src_vt7, src_vt6, src_vt54_r, src_vt76_r); + vt_out0 = AVC_DOT_SH3_SH(src_vt10_r, src_vt32_r, src_vt54_r, filt0, filt1, + filt2); + vt_out1 = AVC_DOT_SH3_SH(src_vt32_r, src_vt54_r, src_vt76_r, filt0, filt1, + filt2); + SRARI_H2_SH(vt_out0, vt_out1, 5); + SAT_SH2_SH(vt_out0, vt_out1, 7); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); - out0 = __msa_srari_h((hz_out0 + vert_out0), 1); - out1 = __msa_srari_h((hz_out1 + vert_out1), 1); + res1 = __msa_srari_h((hz_out1 + vt_out1), 1); + res0 = __msa_srari_h((hz_out0 + vt_out0), 1); - SAT_SH2_SH(out0, out1, 7); - out = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); + SAT_SH2_SH(res0, res1, 7); + res = PCKEV_XORI128_UB(res0, res1); + dst0 = __msa_aver_u_b(res, dst0); - src_vt3 = src_vt7; - src_vt1 = src_vt5; - src_vt0 = src_vt4; - src_vt4 = src_vt8; - src_vt2 = src_vt6; - } + ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); } -static void avc_luma_hv_qrt_8w_msa(const uint8_t *src_x, const uint8_t *src_y, - int32_t src_stride, uint8_t *dst, - int32_t dst_stride, int32_t height) +static void avc_luma_hv_qrt_and_aver_dst_8x8_msa(const uint8_t *src_x, + const uint8_t *src_y, + uint8_t *dst, + int32_t stride) { - uint32_t loop_cnt; - v16i8 src_hz0, src_hz1, src_hz2, src_hz3; - v16i8 src_vt0, src_vt1, src_vt2, src_vt3, src_vt4; - v16i8 src_vt5, src_vt6, src_vt7, src_vt8; - v16i8 mask0, mask1, mask2; - v8i16 hz_out0, hz_out1, hz_out2, hz_out3; - v8i16 vert_out0, vert_out1, vert_out2, vert_out3; - v8i16 out0, out1, out2, out3; - v16u8 tmp0, tmp1; + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + uint64_t tp0, tp1, tp2, tp3; + v16u8 out0, out1, dst0 = { 0 }, dst1 = { 0 }; + v16i8 src_hz0, src_hz1, src_hz2, src_hz3, src_vt0, src_vt1, src_vt2; + v16i8 src_vt3, src_vt4, src_vt5, src_vt6, src_vt7, src_vt8; + v16i8 src_vt9, src_vt10, src_vt11, src_vt12, mask0, mask1, mask2; + v16i8 src_vt10_r, src_vt21_r, src_vt32_r, src_vt43_r, src_vt54_r; + v16i8 src_vt65_r, src_vt76_r, src_vt87_r, src_vt98_r, src_vt109_r; + v16i8 src_vt1110_r, src_vt1211_r, filt0, filt1, filt2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, vt_out0, vt_out1, vt_out2; + v8i16 vt_out3, tmp0, tmp1, tmp2, tmp3; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); - LD_SB5(src_y, src_stride, src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); - src_y += (5 * src_stride); + LD_SB5(src_y, stride, src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); + src_y += (5 * stride); - src_vt0 = (v16i8) __msa_insve_d((v2i64) src_vt0, 1, (v2i64) src_vt1); - src_vt1 = (v16i8) __msa_insve_d((v2i64) src_vt1, 1, (v2i64) src_vt2); - src_vt2 = (v16i8) __msa_insve_d((v2i64) src_vt2, 1, (v2i64) src_vt3); - src_vt3 = (v16i8) __msa_insve_d((v2i64) src_vt3, 1, (v2i64) src_vt4); + XORI_B5_128_SB(src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); - XORI_B4_128_SB(src_vt0, src_vt1, src_vt2, src_vt3); + LD_SB4(src_x, stride, src_hz0, src_hz1, src_hz2, src_hz3); + XORI_B4_128_SB(src_hz0, src_hz1, src_hz2, src_hz3); + src_x += (4 * stride); + + hz_out0 = AVC_HORZ_FILTER_SH(src_hz0, src_hz0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src_hz1, src_hz1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src_hz2, src_hz2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src_hz3, src_hz3, mask0, mask1, mask2); + + SRARI_H4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 5); + SAT_SH4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 7); + + LD_SB4(src_y, stride, src_vt5, src_vt6, src_vt7, src_vt8); + src_y += (4 * stride); + XORI_B4_128_SB(src_vt5, src_vt6, src_vt7, src_vt8); + + ILVR_B4_SB(src_vt1, src_vt0, src_vt2, src_vt1, src_vt3, src_vt2, src_vt4, + src_vt3, src_vt10_r, src_vt21_r, src_vt32_r, src_vt43_r); + ILVR_B4_SB(src_vt5, src_vt4, src_vt6, src_vt5, src_vt7, src_vt6, src_vt8, + src_vt7, src_vt54_r, src_vt65_r, src_vt76_r, src_vt87_r); + vt_out0 = AVC_DOT_SH3_SH(src_vt10_r, src_vt32_r, src_vt54_r, filt0, filt1, + filt2); + vt_out1 = AVC_DOT_SH3_SH(src_vt21_r, src_vt43_r, src_vt65_r, filt0, filt1, + filt2); + vt_out2 = AVC_DOT_SH3_SH(src_vt32_r, src_vt54_r, src_vt76_r, filt0, filt1, + filt2); + vt_out3 = AVC_DOT_SH3_SH(src_vt43_r, src_vt65_r, src_vt87_r, filt0, filt1, + filt2); + SRARI_H4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 5); + SAT_SH4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 7); + + tmp0 = __msa_srari_h((hz_out0 + vt_out0), 1); + tmp1 = __msa_srari_h((hz_out1 + vt_out1), 1); + tmp2 = __msa_srari_h((hz_out2 + vt_out2), 1); + tmp3 = __msa_srari_h((hz_out3 + vt_out3), 1); + + LD_SB4(src_x, stride, src_hz0, src_hz1, src_hz2, src_hz3); + XORI_B4_128_SB(src_hz0, src_hz1, src_hz2, src_hz3); - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src_x, src_stride, src_hz0, src_hz1, src_hz2, src_hz3); - XORI_B4_128_SB(src_hz0, src_hz1, src_hz2, src_hz3); - src_x += (4 * src_stride); - - hz_out0 = AVC_HORZ_FILTER_SH(src_hz0, src_hz0, mask0, mask1, mask2); - hz_out1 = AVC_HORZ_FILTER_SH(src_hz1, src_hz1, mask0, mask1, mask2); - hz_out2 = AVC_HORZ_FILTER_SH(src_hz2, src_hz2, mask0, mask1, mask2); - hz_out3 = AVC_HORZ_FILTER_SH(src_hz3, src_hz3, mask0, mask1, mask2); - - SRARI_H4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 5); - SAT_SH4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 7); - - LD_SB4(src_y, src_stride, src_vt5, src_vt6, src_vt7, src_vt8); - src_y += (4 * src_stride); - - src_vt4 = (v16i8) __msa_insve_d((v2i64) src_vt4, 1, (v2i64) src_vt5); - src_vt5 = (v16i8) __msa_insve_d((v2i64) src_vt5, 1, (v2i64) src_vt6); - src_vt6 = (v16i8) __msa_insve_d((v2i64) src_vt6, 1, (v2i64) src_vt7); - src_vt7 = (v16i8) __msa_insve_d((v2i64) src_vt7, 1, (v2i64) src_vt8); - - XORI_B4_128_SB(src_vt4, src_vt5, src_vt6, src_vt7); - - /* filter calc */ - AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src_vt0, src_vt1, src_vt2, src_vt3, - src_vt4, src_vt5, vert_out0, vert_out1); - AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src_vt2, src_vt3, src_vt4, src_vt5, - src_vt6, src_vt7, vert_out2, vert_out3); - - SRARI_H4_SH(vert_out0, vert_out1, vert_out2, vert_out3, 5); - SAT_SH4_SH(vert_out0, vert_out1, vert_out2, vert_out3, 7); - - out0 = __msa_srari_h((hz_out0 + vert_out0), 1); - out1 = __msa_srari_h((hz_out1 + vert_out1), 1); - out2 = __msa_srari_h((hz_out2 + vert_out2), 1); - out3 = __msa_srari_h((hz_out3 + vert_out3), 1); - - SAT_SH4_SH(out0, out1, out2, out3, 7); - tmp0 = PCKEV_XORI128_UB(out0, out1); - tmp1 = PCKEV_XORI128_UB(out2, out3); - ST8x4_UB(tmp0, tmp1, dst, dst_stride); - - dst += (4 * dst_stride); - src_vt3 = src_vt7; - src_vt1 = src_vt5; - src_vt5 = src_vt4; - src_vt4 = src_vt8; - src_vt2 = src_vt6; - src_vt0 = src_vt5; - } -} + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); -static void avc_luma_hv_qrt_16w_msa(const uint8_t *src_x, const uint8_t *src_y, - int32_t src_stride, uint8_t *dst, - int32_t dst_stride, int32_t height) -{ - uint32_t multiple8_cnt; + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, stride); + dst += (4 * stride); - for (multiple8_cnt = 2; multiple8_cnt--;) { - avc_luma_hv_qrt_8w_msa(src_x, src_y, src_stride, dst, dst_stride, - height); + LD_SB4(src_y, stride, src_vt9, src_vt10, src_vt11, src_vt12); + XORI_B4_128_SB(src_vt9, src_vt10, src_vt11, src_vt12); + + hz_out0 = AVC_HORZ_FILTER_SH(src_hz0, src_hz0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src_hz1, src_hz1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src_hz2, src_hz2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src_hz3, src_hz3, mask0, mask1, mask2); + + SRARI_H4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 5); + SAT_SH4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 7); + + ILVR_B4_SB(src_vt9, src_vt8, src_vt10, src_vt9, src_vt11, src_vt10, + src_vt12, src_vt11, src_vt98_r, src_vt109_r, src_vt1110_r, + src_vt1211_r); + vt_out0 = AVC_DOT_SH3_SH(src_vt54_r, src_vt76_r, src_vt98_r, filt0, filt1, + filt2); + vt_out1 = AVC_DOT_SH3_SH(src_vt65_r, src_vt87_r, src_vt109_r, filt0, filt1, + filt2); + vt_out2 = AVC_DOT_SH3_SH(src_vt76_r, src_vt98_r, src_vt1110_r, filt0, filt1, + filt2); + vt_out3 = AVC_DOT_SH3_SH(src_vt87_r, src_vt109_r, src_vt1211_r, filt0, + filt1, filt2); + SRARI_H4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 5); + SAT_SH4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 7); + + tmp0 = __msa_srari_h((hz_out0 + vt_out0), 1); + tmp1 = __msa_srari_h((hz_out1 + vt_out1), 1); + tmp2 = __msa_srari_h((hz_out2 + vt_out2), 1); + tmp3 = __msa_srari_h((hz_out3 + vt_out3), 1); - src_x += 8; - src_y += 8; - dst += 8; - } + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, stride); + dst += (4 * stride); } -static void avc_luma_hz_and_aver_dst_4x4_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride) +static void avc_luma_hv_qrt_and_aver_dst_16x16_msa(const uint8_t *src_x, + const uint8_t *src_y, + uint8_t *dst, + int32_t stride) { - v16i8 src0, src1, src2, src3; - v16u8 dst0, dst1, dst2, dst3, res; - v8i16 res0, res1; - v16i8 mask0, mask1, mask2; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v16i8 minus5b = __msa_ldi_b(-5); - v16i8 plus20b = __msa_ldi_b(20); + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + const uint8_t *src_x_tmp = src_x; + const uint8_t *src_y_tmp = src_y; + uint8_t *dst_tmp = dst; + uint32_t multiple8_cnt, loop_cnt; + uint64_t tp0, tp1, tp2, tp3; + v16u8 tmp0, tmp1, dst0 = { 0 }, dst1 = { 0 }; + v16i8 src_hz0, src_hz1, src_hz2, src_hz3, mask0, mask1, mask2; + v16i8 src_vt0, src_vt1, src_vt2, src_vt3, src_vt4, src_vt5, src_vt6; + v16i8 src_vt7, src_vt8; + v16i8 src_vt10_r, src_vt21_r, src_vt32_r, src_vt43_r, src_vt54_r; + v16i8 src_vt65_r, src_vt76_r, src_vt87_r, filt0, filt1, filt2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, vt_out0, vt_out1, vt_out2; + v8i16 vt_out3, out0, out1, out2, out3; - LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); - LD_SB4(src, src_stride, src0, src1, src2, src3); + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0, vec1); - HADD_SB2_SH(vec0, vec1, res0, res1); - VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec2, vec3); - DPADD_SB2_SH(vec2, vec3, minus5b, minus5b, res0, res1); - VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec4, vec5); - DPADD_SB2_SH(vec4, vec5, plus20b, plus20b, res0, res1); - SRARI_H2_SH(res0, res1, 5); - SAT_SH2_SH(res0, res1, 7); - res = PCKEV_XORI128_UB(res0, res1); - ILVR_W2_UB(dst1, dst0, dst3, dst2, dst0, dst1); + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); - dst0 = (v16u8) __msa_pckev_d((v2i64) dst1, (v2i64) dst0); - res = __msa_aver_u_b(res, dst0); + for (multiple8_cnt = 2; multiple8_cnt--;) { + src_x = src_x_tmp; + src_y = src_y_tmp; + dst = dst_tmp; - ST4x4_UB(res, res, 0, 1, 2, 3, dst, dst_stride); -} + LD_SB5(src_y, stride, src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); + src_y += (5 * stride); -static void avc_luma_hz_and_aver_dst_8x8_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride) -{ - uint32_t loop_cnt; - v16i8 src0, src1, src2, src3; - v16u8 dst0, dst1, dst2, dst3; - v8i16 res0, res1, res2, res3; - v16i8 mask0, mask1, mask2; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v16i8 vec6, vec7, vec8, vec9, vec10, vec11; - v16i8 minus5b = __msa_ldi_b(-5); - v16i8 plus20b = __msa_ldi_b(20); + XORI_B5_128_SB(src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); - LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src_x, stride, src_hz0, src_hz1, src_hz2, src_hz3); + XORI_B4_128_SB(src_hz0, src_hz1, src_hz2, src_hz3); + src_x += (4 * stride); + + hz_out0 = AVC_HORZ_FILTER_SH(src_hz0, src_hz0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src_hz1, src_hz1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src_hz2, src_hz2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src_hz3, src_hz3, mask0, mask1, mask2); + SRARI_H4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 5); + SAT_SH4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 7); + + LD_SB4(src_y, stride, src_vt5, src_vt6, src_vt7, src_vt8); + src_y += (4 * stride); + + XORI_B4_128_SB(src_vt5, src_vt6, src_vt7, src_vt8); + ILVR_B4_SB(src_vt1, src_vt0, src_vt2, src_vt1, src_vt3, src_vt2, + src_vt4, src_vt3, src_vt10_r, src_vt21_r, src_vt32_r, + src_vt43_r); + ILVR_B4_SB(src_vt5, src_vt4, src_vt6, src_vt5, src_vt7, src_vt6, + src_vt8, src_vt7, src_vt54_r, src_vt65_r, src_vt76_r, + src_vt87_r); + vt_out0 = AVC_DOT_SH3_SH(src_vt10_r, src_vt32_r, src_vt54_r, filt0, + filt1, filt2); + vt_out1 = AVC_DOT_SH3_SH(src_vt21_r, src_vt43_r, src_vt65_r, filt0, + filt1, filt2); + vt_out2 = AVC_DOT_SH3_SH(src_vt32_r, src_vt54_r, src_vt76_r, filt0, + filt1, filt2); + vt_out3 = AVC_DOT_SH3_SH(src_vt43_r, src_vt65_r, src_vt87_r, filt0, + filt1, filt2); + SRARI_H4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 5); + SAT_SH4_SH(vt_out0, vt_out1, vt_out2, vt_out3, 7); + + out0 = __msa_srari_h((hz_out0 + vt_out0), 1); + out1 = __msa_srari_h((hz_out1 + vt_out1), 1); + out2 = __msa_srari_h((hz_out2 + vt_out2), 1); + out3 = __msa_srari_h((hz_out3 + vt_out3), 1); + + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + + SAT_SH4_SH(out0, out1, out2, out3, 7); + tmp0 = PCKEV_XORI128_UB(out0, out1); + tmp1 = PCKEV_XORI128_UB(out2, out3); + AVER_UB2_UB(tmp0, dst0, tmp1, dst1, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, stride); + dst += (4 * stride); - for (loop_cnt = 2; loop_cnt--;) { - LD_SB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); - - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - - XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); - VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); - HADD_SB4_SH(vec0, vec1, vec2, vec3, res0, res1, res2, res3); - VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec4, vec5); - VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec6, vec7); - DPADD_SB4_SH(vec4, vec5, vec6, vec7, minus5b, minus5b, minus5b, minus5b, - res0, res1, res2, res3); - VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec8, vec9); - VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec10, vec11); - DPADD_SB4_SH(vec8, vec9, vec10, vec11, plus20b, plus20b, plus20b, - plus20b, res0, res1, res2, res3); - SRARI_H4_SH(res0, res1, res2, res3, 5); - SAT_SH4_SH(res0, res1, res2, res3, 7); - ILVR_D2_UB(dst1, dst0, dst3, dst2, dst0, dst1); - CONVERT_UB_AVG_ST8x4_UB(res0, res1, res2, res3, dst0, dst1, - dst, dst_stride); + src_vt0 = src_vt4; + src_vt1 = src_vt5; + src_vt2 = src_vt6; + src_vt3 = src_vt7; + src_vt4 = src_vt8; + } - dst += (4 * dst_stride); + src_x_tmp += 8; + src_y_tmp += 8; + dst_tmp += 8; } } -static void avc_luma_hz_and_aver_dst_16x16_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride) +void ff_put_h264_qpel16_mc00_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) { - uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7; - v16u8 dst0, dst1, dst2, dst3; - v16i8 mask0, mask1, mask2; - v8i16 res0, res1, res2, res3, res4, res5, res6, res7; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v16i8 vec6, vec7, vec8, vec9, vec10, vec11; - v16i8 minus5b = __msa_ldi_b(-5); - v16i8 plus20b = __msa_ldi_b(20); + v16u8 src0, src1, src2, src3, src4, src5, src6, src7; + v16u8 src8, src9, src10, src11, src12, src13, src14, src15; - LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + LD_UB8(src, stride, src0, src1, src2, src3, src4, src5, src6, src7); + src += (8 * stride); + LD_UB8(src, stride, src8, src9, src10, src11, src12, src13, src14, src15); - for (loop_cnt = 4; loop_cnt--;) { - LD_SB2(src, 8, src0, src1); - src += src_stride; - LD_SB2(src, 8, src2, src3); - src += src_stride; + ST_UB8(src0, src1, src2, src3, src4, src5, src6, src7, dst, stride); + dst += (8 * stride); + ST_UB8(src8, src9, src10, src11, src12, src13, src14, src15, dst, stride); +} - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); +void ff_put_h264_qpel8_mc00_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + uint64_t src0, src1, src2, src3, src4, src5, src6, src7; - XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec3); - VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec6, vec9); - VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec1, vec4); - VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec7, vec10); - VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec2, vec5); - VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec8, vec11); - HADD_SB4_SH(vec0, vec3, vec6, vec9, res0, res1, res2, res3); - DPADD_SB4_SH(vec1, vec4, vec7, vec10, minus5b, minus5b, minus5b, - minus5b, res0, res1, res2, res3); - DPADD_SB4_SH(vec2, vec5, vec8, vec11, plus20b, plus20b, plus20b, - plus20b, res0, res1, res2, res3); - LD_SB2(src, 8, src4, src5); - src += src_stride; - LD_SB2(src, 8, src6, src7); - src += src_stride; - XORI_B4_128_SB(src4, src5, src6, src7); - VSHF_B2_SB(src4, src4, src5, src5, mask0, mask0, vec0, vec3); - VSHF_B2_SB(src6, src6, src7, src7, mask0, mask0, vec6, vec9); - VSHF_B2_SB(src4, src4, src5, src5, mask1, mask1, vec1, vec4); - VSHF_B2_SB(src6, src6, src7, src7, mask1, mask1, vec7, vec10); - VSHF_B2_SB(src4, src4, src5, src5, mask2, mask2, vec2, vec5); - VSHF_B2_SB(src6, src6, src7, src7, mask2, mask2, vec8, vec11); - HADD_SB4_SH(vec0, vec3, vec6, vec9, res4, res5, res6, res7); - DPADD_SB4_SH(vec1, vec4, vec7, vec10, minus5b, minus5b, minus5b, - minus5b, res4, res5, res6, res7); - DPADD_SB4_SH(vec2, vec5, vec8, vec11, plus20b, plus20b, plus20b, - plus20b, res4, res5, res6, res7); - SRARI_H4_SH(res0, res1, res2, res3, 5); - SRARI_H4_SH(res4, res5, res6, res7, 5); - SAT_SH4_SH(res0, res1, res2, res3, 7); - SAT_SH4_SH(res4, res5, res6, res7, 7); - PCKEV_B4_SB(res1, res0, res3, res2, res5, res4, res7, res6, - vec0, vec1, vec2, vec3); - XORI_B4_128_SB(vec0, vec1, vec2, vec3); - AVER_UB4_UB(vec0, dst0, vec1, dst1, vec2, dst2, vec3, dst3, - dst0, dst1, dst2, dst3); - ST_UB4(dst0, dst1, dst2, dst3, dst, dst_stride); - dst += (4 * dst_stride); - } + LD4(src, stride, src0, src1, src2, src3); + src += 4 * stride; + LD4(src, stride, src4, src5, src6, src7); + SD4(src0, src1, src2, src3, dst, stride); + dst += 4 * stride; + SD4(src4, src5, src6, src7, dst, stride); } -static void avc_luma_hz_qrt_and_aver_dst_4x4_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - uint8_t hor_offset) +void ff_avg_h264_qpel16_mc00_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) { - uint8_t slide; - v16i8 src0, src1, src2, src3; - v16u8 dst0, dst1, dst2, dst3; - v16i8 mask0, mask1, mask2; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 out0, out1; - v16i8 minus5b = __msa_ldi_b(-5); - v16i8 plus20b = __msa_ldi_b(20); - v16u8 res0, res1; + v16u8 src0, src1, src2, src3, src4, src5, src6, src7; + v16u8 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; - LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); + LD_UB8(src, stride, src0, src1, src2, src3, src4, src5, src6, src7); + src += (8 * stride); + LD_UB8(dst, stride, dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7); - if (hor_offset) { - slide = 3; - } else { - slide = 2; - } + AVER_UB4_UB(src0, dst0, src1, dst1, src2, dst2, src3, dst3, dst0, dst1, + dst2, dst3); + AVER_UB4_UB(src4, dst4, src5, dst5, src6, dst6, src7, dst7, dst4, dst5, + dst6, dst7); + ST_UB8(dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst, stride); + dst += (8 * stride); - LD_SB4(src, src_stride, src0, src1, src2, src3); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); + LD_UB8(src, stride, src0, src1, src2, src3, src4, src5, src6, src7); + LD_UB8(dst, stride, dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7); - XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0, vec1); - HADD_SB2_SH(vec0, vec1, out0, out1); - VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec2, vec3); - DPADD_SB2_SH(vec2, vec3, minus5b, minus5b, out0, out1); - VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec4, vec5); - DPADD_SB2_SH(vec4, vec5, plus20b, plus20b, out0, out1); - SRARI_H2_SH(out0, out1, 5); - SAT_SH2_SH(out0, out1, 7); + AVER_UB4_UB(src0, dst0, src1, dst1, src2, dst2, src3, dst3, dst0, dst1, + dst2, dst3); + AVER_UB4_UB(src4, dst4, src5, dst5, src6, dst6, src7, dst7, dst4, dst5, + dst6, dst7); + ST_UB8(dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst, stride); +} - PCKEV_B2_UB(out0, out0, out1, out1, res0, res1); +void ff_avg_h264_qpel8_mc00_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + uint64_t tp0, tp1, tp2, tp3, tp4, tp5, tp6, tp7; + v16u8 src0 = { 0 }, src1 = { 0 }, src2 = { 0 }, src3 = { 0 }; + v16u8 dst0 = { 0 }, dst1 = { 0 }, dst2 = { 0 }, dst3 = { 0 }; - src0 = __msa_sld_b(src0, src0, slide); - src1 = __msa_sld_b(src1, src1, slide); - src2 = __msa_sld_b(src2, src2, slide); - src3 = __msa_sld_b(src3, src3, slide); - src0 = (v16i8) __msa_insve_w((v4i32) src0, 1, (v4i32) src1); - src1 = (v16i8) __msa_insve_w((v4i32) src2, 1, (v4i32) src3); - res0 = (v16u8) __msa_aver_s_b((v16i8) res0, src0); - res1 = (v16u8) __msa_aver_s_b((v16i8) res1, src1); + LD4(src, stride, tp0, tp1, tp2, tp3); + src += 4 * stride; + LD4(src, stride, tp4, tp5, tp6, tp7); + INSERT_D2_UB(tp0, tp1, src0); + INSERT_D2_UB(tp2, tp3, src1); + INSERT_D2_UB(tp4, tp5, src2); + INSERT_D2_UB(tp6, tp7, src3); + + LD4(dst, stride, tp0, tp1, tp2, tp3); + LD4(dst + 4 * stride, stride, tp4, tp5, tp6, tp7); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + INSERT_D2_UB(tp4, tp5, dst2); + INSERT_D2_UB(tp6, tp7, dst3); + + AVER_UB4_UB(src0, dst0, src1, dst1, src2, dst2, src3, dst3, dst0, dst1, + dst2, dst3); + + ST8x8_UB(dst0, dst1, dst2, dst3, dst, stride); +} - XORI_B2_128_UB(res0, res1); +void ff_avg_h264_qpel4_mc00_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + uint32_t tp0, tp1, tp2, tp3; + v16u8 src0 = { 0 }, dst0 = { 0 }; - dst0 = (v16u8) __msa_insve_w((v4i32) dst0, 1, (v4i32) dst1); - dst1 = (v16u8) __msa_insve_w((v4i32) dst2, 1, (v4i32) dst3); + LW4(src, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, src0); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); - AVER_UB2_UB(res0, dst0, res1, dst1, dst0, dst1); + dst0 = __msa_aver_u_b(src0, dst0); - ST4x4_UB(dst0, dst1, 0, 1, 0, 1, dst, dst_stride); + ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); } -static void avc_luma_hz_qrt_and_aver_dst_8x8_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - uint8_t hor_offset) +void ff_put_h264_qpel16_mc10_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) { - uint8_t slide; uint32_t loop_cnt; - v16i8 src0, src1, src2, src3; - v16i8 mask0, mask1, mask2; - v16u8 dst0, dst1, dst2, dst3; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v16i8 vec6, vec7, vec8, vec9, vec10, vec11; - v8i16 out0, out1, out2, out3; + v16i8 dst0, dst1, dst2, dst3, src0, src1, src2, src3, src4, src5, src6; + v16i8 mask0, mask1, mask2, mask3, mask4, mask5, src7, vec11; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; + v8i16 res0, res1, res2, res3, res4, res5, res6, res7; v16i8 minus5b = __msa_ldi_b(-5); v16i8 plus20b = __msa_ldi_b(20); - v16i8 res0, res1, res2, res3; LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + mask3 = mask0 + 8; + mask4 = mask1 + 8; + mask5 = mask2 + 8; + src -= 2; - if (hor_offset) { - slide = 3; - } else { - slide = 2; - } + for (loop_cnt = 4; loop_cnt--;) { + LD_SB2(src, 16, src0, src1); + src += stride; + LD_SB2(src, 16, src2, src3); + src += stride; + LD_SB2(src, 16, src4, src5); + src += stride; + LD_SB2(src, 16, src6, src7); + src += stride; - for (loop_cnt = 2; loop_cnt--;) { - LD_SB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); - - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - - XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); - VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); - HADD_SB4_SH(vec0, vec1, vec2, vec3, out0, out1, out2, out3); - VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec4, vec5); - VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec6, vec7); - DPADD_SB4_SH(vec4, vec5, vec6, vec7, minus5b, minus5b, minus5b, minus5b, - out0, out1, out2, out3); - VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec8, vec9); - VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec10, vec11); - DPADD_SB4_SH(vec8, vec9, vec10, vec11, plus20b, plus20b, plus20b, - plus20b, out0, out1, out2, out3); - - src0 = __msa_sld_b(src0, src0, slide); - src1 = __msa_sld_b(src1, src1, slide); - src2 = __msa_sld_b(src2, src2, slide); - src3 = __msa_sld_b(src3, src3, slide); - - SRARI_H4_SH(out0, out1, out2, out3, 5); - SAT_SH4_SH(out0, out1, out2, out3, 7); - - PCKEV_B4_SB(out0, out0, out1, out1, out2, out2, out3, out3, - res0, res1, res2, res3); - - res0 = __msa_aver_s_b(res0, src0); - res1 = __msa_aver_s_b(res1, src1); - res2 = __msa_aver_s_b(res2, src2); - res3 = __msa_aver_s_b(res3, src3); - - XORI_B4_128_SB(res0, res1, res2, res3); - AVER_ST8x4_UB(res0, dst0, res1, dst1, res2, dst2, res3, dst3, - dst, dst_stride); - - dst += (4 * dst_stride); + XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask3, vec0, vec3); + VSHF_B2_SB(src2, src2, src2, src3, mask0, mask3, vec6, vec9); + VSHF_B2_SB(src0, src0, src0, src1, mask1, mask4, vec1, vec4); + VSHF_B2_SB(src2, src2, src2, src3, mask1, mask4, vec7, vec10); + VSHF_B2_SB(src0, src0, src0, src1, mask2, mask5, vec2, vec5); + VSHF_B2_SB(src2, src2, src2, src3, mask2, mask5, vec8, vec11); + HADD_SB4_SH(vec0, vec3, vec6, vec9, res0, res1, res2, res3); + DPADD_SB4_SH(vec1, vec4, vec7, vec10, minus5b, minus5b, minus5b, + minus5b, res0, res1, res2, res3); + DPADD_SB4_SH(vec2, vec5, vec8, vec11, plus20b, plus20b, plus20b, + plus20b, res0, res1, res2, res3); + VSHF_B2_SB(src4, src4, src4, src5, mask0, mask3, vec0, vec3); + VSHF_B2_SB(src6, src6, src6, src7, mask0, mask3, vec6, vec9); + VSHF_B2_SB(src4, src4, src4, src5, mask1, mask4, vec1, vec4); + VSHF_B2_SB(src6, src6, src6, src7, mask1, mask4, vec7, vec10); + VSHF_B2_SB(src4, src4, src4, src5, mask2, mask5, vec2, vec5); + VSHF_B2_SB(src6, src6, src6, src7, mask2, mask5, vec8, vec11); + HADD_SB4_SH(vec0, vec3, vec6, vec9, res4, res5, res6, res7); + DPADD_SB4_SH(vec1, vec4, vec7, vec10, minus5b, minus5b, minus5b, + minus5b, res4, res5, res6, res7); + DPADD_SB4_SH(vec2, vec5, vec8, vec11, plus20b, plus20b, plus20b, + plus20b, res4, res5, res6, res7); + SLDI_B2_SB(src1, src3, src0, src2, src0, src2, 2); + SLDI_B2_SB(src5, src7, src4, src6, src4, src6, 2); + SRARI_H4_SH(res0, res1, res2, res3, 5); + SRARI_H4_SH(res4, res5, res6, res7, 5); + SAT_SH4_SH(res0, res1, res2, res3, 7); + SAT_SH4_SH(res4, res5, res6, res7, 7); + PCKEV_B2_SB(res1, res0, res3, res2, dst0, dst1); + PCKEV_B2_SB(res5, res4, res7, res6, dst2, dst3); + dst0 = __msa_aver_s_b(dst0, src0); + dst1 = __msa_aver_s_b(dst1, src2); + dst2 = __msa_aver_s_b(dst2, src4); + dst3 = __msa_aver_s_b(dst3, src6); + XORI_B4_128_SB(dst0, dst1, dst2, dst3); + ST_SB4(dst0, dst1, dst2, dst3, dst, stride); + dst += (4 * stride); } } -static void avc_luma_hz_qrt_and_aver_dst_16x16_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - uint8_t hor_offset) +void ff_put_h264_qpel16_mc30_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) { uint32_t loop_cnt; - v16i8 out0, out1; - v16i8 src0, src1, src2, src3; - v16i8 mask0, mask1, mask2, vshf; - v16u8 dst0, dst1; - v8i16 res0, res1, res2, res3; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v16i8 vec6, vec7, vec8, vec9, vec10, vec11; + v16i8 dst0, dst1, dst2, dst3, src0, src1, src2, src3, src4, src5, src6; + v16i8 mask0, mask1, mask2, mask3, mask4, mask5, src7, vec11; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; + v8i16 res0, res1, res2, res3, res4, res5, res6, res7; v16i8 minus5b = __msa_ldi_b(-5); v16i8 plus20b = __msa_ldi_b(20); LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + mask3 = mask0 + 8; + mask4 = mask1 + 8; + mask5 = mask2 + 8; + src -= 2; - if (hor_offset) { - vshf = LD_SB(&luma_mask_arr[16 + 96]); - } else { - vshf = LD_SB(&luma_mask_arr[96]); - } - - for (loop_cnt = 8; loop_cnt--;) { - LD_SB2(src, 8, src0, src1); - src += src_stride; - LD_SB2(src, 8, src2, src3); - src += src_stride; - - LD_UB2(dst, dst_stride, dst0, dst1); + for (loop_cnt = 4; loop_cnt--;) { + LD_SB2(src, 16, src0, src1); + src += stride; + LD_SB2(src, 16, src2, src3); + src += stride; + LD_SB2(src, 16, src4, src5); + src += stride; + LD_SB2(src, 16, src6, src7); + src += stride; - XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec3); - VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec6, vec9); - VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec1, vec4); - VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec7, vec10); - VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec2, vec5); - VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec8, vec11); + XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask3, vec0, vec3); + VSHF_B2_SB(src2, src2, src2, src3, mask0, mask3, vec6, vec9); + VSHF_B2_SB(src0, src0, src0, src1, mask1, mask4, vec1, vec4); + VSHF_B2_SB(src2, src2, src2, src3, mask1, mask4, vec7, vec10); + VSHF_B2_SB(src0, src0, src0, src1, mask2, mask5, vec2, vec5); + VSHF_B2_SB(src2, src2, src2, src3, mask2, mask5, vec8, vec11); HADD_SB4_SH(vec0, vec3, vec6, vec9, res0, res1, res2, res3); DPADD_SB4_SH(vec1, vec4, vec7, vec10, minus5b, minus5b, minus5b, minus5b, res0, res1, res2, res3); DPADD_SB4_SH(vec2, vec5, vec8, vec11, plus20b, plus20b, plus20b, plus20b, res0, res1, res2, res3); - VSHF_B2_SB(src0, src1, src2, src3, vshf, vshf, src0, src2); + VSHF_B2_SB(src4, src4, src4, src5, mask0, mask3, vec0, vec3); + VSHF_B2_SB(src6, src6, src6, src7, mask0, mask3, vec6, vec9); + VSHF_B2_SB(src4, src4, src4, src5, mask1, mask4, vec1, vec4); + VSHF_B2_SB(src6, src6, src6, src7, mask1, mask4, vec7, vec10); + VSHF_B2_SB(src4, src4, src4, src5, mask2, mask5, vec2, vec5); + VSHF_B2_SB(src6, src6, src6, src7, mask2, mask5, vec8, vec11); + HADD_SB4_SH(vec0, vec3, vec6, vec9, res4, res5, res6, res7); + DPADD_SB4_SH(vec1, vec4, vec7, vec10, minus5b, minus5b, minus5b, + minus5b, res4, res5, res6, res7); + DPADD_SB4_SH(vec2, vec5, vec8, vec11, plus20b, plus20b, plus20b, + plus20b, res4, res5, res6, res7); + SLDI_B2_SB(src1, src3, src0, src2, src0, src2, 3); + SLDI_B2_SB(src5, src7, src4, src6, src4, src6, 3); SRARI_H4_SH(res0, res1, res2, res3, 5); + SRARI_H4_SH(res4, res5, res6, res7, 5); SAT_SH4_SH(res0, res1, res2, res3, 7); - PCKEV_B2_SB(res1, res0, res3, res2, out0, out1); - - out0 = __msa_aver_s_b(out0, src0); - out1 = __msa_aver_s_b(out1, src2); - - XORI_B2_128_SB(out0, out1); - AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); - ST_UB2(dst0, dst1, dst, dst_stride); - dst += (2 * dst_stride); + SAT_SH4_SH(res4, res5, res6, res7, 7); + PCKEV_B2_SB(res1, res0, res3, res2, dst0, dst1); + PCKEV_B2_SB(res5, res4, res7, res6, dst2, dst3); + dst0 = __msa_aver_s_b(dst0, src0); + dst1 = __msa_aver_s_b(dst1, src2); + dst2 = __msa_aver_s_b(dst2, src4); + dst3 = __msa_aver_s_b(dst3, src6); + XORI_B4_128_SB(dst0, dst1, dst2, dst3); + ST_SB4(dst0, dst1, dst2, dst3, dst, stride); + dst += (4 * stride); } } -static void avc_luma_vt_and_aver_dst_4x4_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride) -{ +void ff_put_h264_qpel8_mc10_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, mask0, mask1, mask2; + v16i8 tmp0, tmp1, tmp2, tmp3, vec11; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; + v8i16 res0, res1, res2, res3, res4, res5, res6, res7; + v16i8 minus5b = __msa_ldi_b(-5); + v16i8 plus20b = __msa_ldi_b(20); + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + LD_SB8(src - 2, stride, src0, src1, src2, src3, src4, src5, src6, src7); + XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + HADD_SB4_SH(vec0, vec1, vec2, vec3, res0, res1, res2, res3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec4, vec5); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, minus5b, minus5b, minus5b, minus5b, + res0, res1, res2, res3); + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec8, vec9); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec10, vec11); + DPADD_SB4_SH(vec8, vec9, vec10, vec11, plus20b, plus20b, plus20b, plus20b, + res0, res1, res2, res3); + VSHF_B2_SB(src4, src4, src5, src5, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src6, src6, src7, src7, mask0, mask0, vec2, vec3); + HADD_SB4_SH(vec0, vec1, vec2, vec3, res4, res5, res6, res7); + VSHF_B2_SB(src4, src4, src5, src5, mask1, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src7, src7, mask1, mask1, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, minus5b, minus5b, minus5b, minus5b, + res4, res5, res6, res7); + VSHF_B2_SB(src4, src4, src5, src5, mask2, mask2, vec8, vec9); + VSHF_B2_SB(src6, src6, src7, src7, mask2, mask2, vec10, vec11); + DPADD_SB4_SH(vec8, vec9, vec10, vec11, plus20b, plus20b, plus20b, plus20b, + res4, res5, res6, res7); + SLDI_B2_SB(src0, src1, src0, src1, src0, src1, 2); + SLDI_B2_SB(src2, src3, src2, src3, src2, src3, 2); + SLDI_B2_SB(src4, src5, src4, src5, src4, src5, 2); + SLDI_B2_SB(src6, src7, src6, src7, src6, src7, 2); + PCKEV_D2_SB(src1, src0, src3, src2, src0, src1); + PCKEV_D2_SB(src5, src4, src7, src6, src4, src5); + SRARI_H4_SH(res0, res1, res2, res3, 5); + SRARI_H4_SH(res4, res5, res6, res7, 5); + SAT_SH4_SH(res0, res1, res2, res3, 7); + SAT_SH4_SH(res4, res5, res6, res7, 7); + PCKEV_B2_SB(res1, res0, res3, res2, tmp0, tmp1); + PCKEV_B2_SB(res5, res4, res7, res6, tmp2, tmp3); + tmp0 = __msa_aver_s_b(tmp0, src0); + tmp1 = __msa_aver_s_b(tmp1, src1); + tmp2 = __msa_aver_s_b(tmp2, src4); + tmp3 = __msa_aver_s_b(tmp3, src5); + XORI_B4_128_SB(tmp0, tmp1, tmp2, tmp3); + ST8x8_UB(tmp0, tmp1, tmp2, tmp3, dst, stride); +} + +void ff_put_h264_qpel8_mc30_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, mask0, mask1, mask2; + v16i8 tmp0, tmp1, tmp2, tmp3, vec11; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; + v8i16 res0, res1, res2, res3, res4, res5, res6, res7; + v16i8 minus5b = __msa_ldi_b(-5); + v16i8 plus20b = __msa_ldi_b(20); + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + LD_SB8(src - 2, stride, src0, src1, src2, src3, src4, src5, src6, src7); + XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + HADD_SB4_SH(vec0, vec1, vec2, vec3, res0, res1, res2, res3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec4, vec5); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, minus5b, minus5b, minus5b, minus5b, + res0, res1, res2, res3); + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec8, vec9); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec10, vec11); + DPADD_SB4_SH(vec8, vec9, vec10, vec11, plus20b, plus20b, plus20b, plus20b, + res0, res1, res2, res3); + VSHF_B2_SB(src4, src4, src5, src5, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src6, src6, src7, src7, mask0, mask0, vec2, vec3); + HADD_SB4_SH(vec0, vec1, vec2, vec3, res4, res5, res6, res7); + VSHF_B2_SB(src4, src4, src5, src5, mask1, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src7, src7, mask1, mask1, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, minus5b, minus5b, minus5b, minus5b, + res4, res5, res6, res7); + VSHF_B2_SB(src4, src4, src5, src5, mask2, mask2, vec8, vec9); + VSHF_B2_SB(src6, src6, src7, src7, mask2, mask2, vec10, vec11); + DPADD_SB4_SH(vec8, vec9, vec10, vec11, plus20b, plus20b, plus20b, plus20b, + res4, res5, res6, res7); + SLDI_B2_SB(src0, src1, src0, src1, src0, src1, 3); + SLDI_B2_SB(src2, src3, src2, src3, src2, src3, 3); + SLDI_B2_SB(src4, src5, src4, src5, src4, src5, 3); + SLDI_B2_SB(src6, src7, src6, src7, src6, src7, 3); + PCKEV_D2_SB(src1, src0, src3, src2, src0, src1); + PCKEV_D2_SB(src5, src4, src7, src6, src4, src5); + SRARI_H4_SH(res0, res1, res2, res3, 5); + SRARI_H4_SH(res4, res5, res6, res7, 5); + SAT_SH4_SH(res0, res1, res2, res3, 7); + SAT_SH4_SH(res4, res5, res6, res7, 7); + PCKEV_B2_SB(res1, res0, res3, res2, tmp0, tmp1); + PCKEV_B2_SB(res5, res4, res7, res6, tmp2, tmp3); + tmp0 = __msa_aver_s_b(tmp0, src0); + tmp1 = __msa_aver_s_b(tmp1, src1); + tmp2 = __msa_aver_s_b(tmp2, src4); + tmp3 = __msa_aver_s_b(tmp3, src5); + XORI_B4_128_SB(tmp0, tmp1, tmp2, tmp3); + ST8x8_UB(tmp0, tmp1, tmp2, tmp3, dst, stride); +} + +void ff_put_h264_qpel4_mc10_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + v16i8 src0, src1, src2, src3, res, mask0, mask1, mask2; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v8i16 res0, res1; + v16i8 minus5b = __msa_ldi_b(-5); + v16i8 plus20b = __msa_ldi_b(20); + + LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); + LD_SB4(src - 2, stride, src0, src1, src2, src3); + XORI_B4_128_SB(src0, src1, src2, src3); + VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0, vec1); + HADD_SB2_SH(vec0, vec1, res0, res1); + VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec2, vec3); + DPADD_SB2_SH(vec2, vec3, minus5b, minus5b, res0, res1); + VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec4, vec5); + DPADD_SB2_SH(vec4, vec5, plus20b, plus20b, res0, res1); + SRARI_H2_SH(res0, res1, 5); + SAT_SH2_SH(res0, res1, 7); + res = __msa_pckev_b((v16i8) res1, (v16i8) res0); + SLDI_B2_SB(src0, src1, src0, src1, src0, src1, 2); + SLDI_B2_SB(src2, src3, src2, src3, src2, src3, 2); + src0 = (v16i8) __msa_insve_w((v4i32) src0, 1, (v4i32) src1); + src1 = (v16i8) __msa_insve_w((v4i32) src2, 1, (v4i32) src3); + src0 = (v16i8) __msa_insve_d((v2i64) src0, 1, (v2i64) src1); + res = __msa_aver_s_b(res, src0); + res = (v16i8) __msa_xori_b((v16u8) res, 128); + ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); +} + +void ff_put_h264_qpel4_mc30_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + v16i8 src0, src1, src2, src3, res, mask0, mask1, mask2; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v8i16 res0, res1; + v16i8 minus5b = __msa_ldi_b(-5); + v16i8 plus20b = __msa_ldi_b(20); + + LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); + LD_SB4(src - 2, stride, src0, src1, src2, src3); + XORI_B4_128_SB(src0, src1, src2, src3); + VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0, vec1); + HADD_SB2_SH(vec0, vec1, res0, res1); + VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec2, vec3); + DPADD_SB2_SH(vec2, vec3, minus5b, minus5b, res0, res1); + VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec4, vec5); + DPADD_SB2_SH(vec4, vec5, plus20b, plus20b, res0, res1); + SRARI_H2_SH(res0, res1, 5); + SAT_SH2_SH(res0, res1, 7); + res = __msa_pckev_b((v16i8) res1, (v16i8) res0); + SLDI_B2_SB(src0, src1, src0, src1, src0, src1, 3); + SLDI_B2_SB(src2, src3, src2, src3, src2, src3, 3); + src0 = (v16i8) __msa_insve_w((v4i32) src0, 1, (v4i32) src1); + src1 = (v16i8) __msa_insve_w((v4i32) src2, 1, (v4i32) src3); + src0 = (v16i8) __msa_insve_d((v2i64) src0, 1, (v2i64) src1); + res = __msa_aver_s_b(res, src0); + res = (v16i8) __msa_xori_b((v16u8) res, 128); + ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); +} + +void ff_put_h264_qpel16_mc20_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + uint32_t loop_cnt; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, mask0, mask1, mask2; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; + v16i8 vec11; + v8i16 res0, res1, res2, res3, res4, res5, res6, res7; + v16i8 minus5b = __msa_ldi_b(-5); + v16i8 plus20b = __msa_ldi_b(20); + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + src -= 2; + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB2(src, 8, src0, src1); + src += stride; + LD_SB2(src, 8, src2, src3); + src += stride; + LD_SB2(src, 8, src4, src5); + src += stride; + LD_SB2(src, 8, src6, src7); + src += stride; + + XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec3); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec6, vec9); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec1, vec4); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec7, vec10); + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec2, vec5); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec8, vec11); + HADD_SB4_SH(vec0, vec3, vec6, vec9, res0, res1, res2, res3); + DPADD_SB4_SH(vec1, vec4, vec7, vec10, minus5b, minus5b, minus5b, + minus5b, res0, res1, res2, res3); + DPADD_SB4_SH(vec2, vec5, vec8, vec11, plus20b, plus20b, plus20b, + plus20b, res0, res1, res2, res3); + VSHF_B2_SB(src4, src4, src5, src5, mask0, mask0, vec0, vec3); + VSHF_B2_SB(src6, src6, src7, src7, mask0, mask0, vec6, vec9); + VSHF_B2_SB(src4, src4, src5, src5, mask1, mask1, vec1, vec4); + VSHF_B2_SB(src6, src6, src7, src7, mask1, mask1, vec7, vec10); + VSHF_B2_SB(src4, src4, src5, src5, mask2, mask2, vec2, vec5); + VSHF_B2_SB(src6, src6, src7, src7, mask2, mask2, vec8, vec11); + HADD_SB4_SH(vec0, vec3, vec6, vec9, res4, res5, res6, res7); + DPADD_SB4_SH(vec1, vec4, vec7, vec10, minus5b, minus5b, minus5b, + minus5b, res4, res5, res6, res7); + DPADD_SB4_SH(vec2, vec5, vec8, vec11, plus20b, plus20b, plus20b, + plus20b, res4, res5, res6, res7); + SRARI_H4_SH(res0, res1, res2, res3, 5); + SRARI_H4_SH(res4, res5, res6, res7, 5); + SAT_SH4_SH(res0, res1, res2, res3, 7); + SAT_SH4_SH(res4, res5, res6, res7, 7); + PCKEV_B4_SB(res1, res0, res3, res2, res5, res4, res7, res6, vec0, vec1, + vec2, vec3); + XORI_B4_128_SB(vec0, vec1, vec2, vec3); + ST_SB4(vec0, vec1, vec2, vec3, dst, stride); + dst += (4 * stride); + } +} + +void ff_put_h264_qpel8_mc20_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + v16u8 out0, out1, out2, out3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, mask0, mask1, mask2; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; + v16i8 vec11; + v8i16 res0, res1, res2, res3, res4, res5, res6, res7; + v16i8 minus5b = __msa_ldi_b(-5); + v16i8 plus20b = __msa_ldi_b(20); + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + LD_SB8(src - 2, stride, src0, src1, src2, src3, src4, src5, src6, src7); + XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + HADD_SB4_SH(vec0, vec1, vec2, vec3, res0, res1, res2, res3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec4, vec5); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, minus5b, minus5b, minus5b, minus5b, + res0, res1, res2, res3); + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec8, vec9); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec10, vec11); + DPADD_SB4_SH(vec8, vec9, vec10, vec11, plus20b, plus20b, plus20b, + plus20b, res0, res1, res2, res3); + VSHF_B2_SB(src4, src4, src5, src5, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src6, src6, src7, src7, mask0, mask0, vec2, vec3); + HADD_SB4_SH(vec0, vec1, vec2, vec3, res4, res5, res6, res7); + VSHF_B2_SB(src4, src4, src5, src5, mask1, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src7, src7, mask1, mask1, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, minus5b, minus5b, minus5b, minus5b, + res4, res5, res6, res7); + VSHF_B2_SB(src4, src4, src5, src5, mask2, mask2, vec8, vec9); + VSHF_B2_SB(src6, src6, src7, src7, mask2, mask2, vec10, vec11); + DPADD_SB4_SH(vec8, vec9, vec10, vec11, plus20b, plus20b, plus20b, + plus20b, res4, res5, res6, res7); + SRARI_H4_SH(res0, res1, res2, res3, 5); + SRARI_H4_SH(res4, res5, res6, res7, 5); + SAT_SH4_SH(res0, res1, res2, res3, 7); + SAT_SH4_SH(res4, res5, res6, res7, 7); + out0 = PCKEV_XORI128_UB(res0, res1); + out1 = PCKEV_XORI128_UB(res2, res3); + out2 = PCKEV_XORI128_UB(res4, res5); + out3 = PCKEV_XORI128_UB(res6, res7); + ST8x8_UB(out0, out1, out2, out3, dst, stride); +} + +void ff_put_h264_qpel4_mc20_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + v16u8 out; + v16i8 src0, src1, src2, src3, mask0, mask1, mask2; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v8i16 res0, res1; + v16i8 minus5b = __msa_ldi_b(-5); + v16i8 plus20b = __msa_ldi_b(20); + + LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); + LD_SB4(src - 2, stride, src0, src1, src2, src3); + XORI_B4_128_SB(src0, src1, src2, src3); + VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0, vec1); + HADD_SB2_SH(vec0, vec1, res0, res1); + VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec2, vec3); + DPADD_SB2_SH(vec2, vec3, minus5b, minus5b, res0, res1); + VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec4, vec5); + DPADD_SB2_SH(vec4, vec5, plus20b, plus20b, res0, res1); + SRARI_H2_SH(res0, res1, 5); + SAT_SH2_SH(res0, res1, 7); + out = PCKEV_XORI128_UB(res0, res1); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); +} + +void ff_put_h264_qpel16_mc01_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + int32_t loop_cnt; + int16_t filt_const0 = 0xfb01; + int16_t filt_const1 = 0x1414; + int16_t filt_const2 = 0x1fb; + v16u8 res0, res1, res2, res3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; + v16i8 src87_r, src10_l, src32_l, src54_l, src76_l, src21_l, src43_l; + v16i8 src65_l, src87_l, filt0, filt1, filt2; + v8i16 out0_r, out1_r, out2_r, out3_r, out0_l, out1_l, out2_l, out3_l; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); + + src -= (stride * 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + + XORI_B5_128_SB(src0, src1, src2, src3, src4); + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVL_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_l, src21_l, + src32_l, src43_l); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src, stride, src5, src6, src7, src8); + src += (4 * stride); + + XORI_B4_128_SB(src5, src6, src7, src8); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, + src65_r, src76_r, src87_r); + ILVL_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_l, + src65_l, src76_l, src87_l); + out0_r = AVC_DOT_SH3_SH(src10_r, src32_r, src54_r, filt0, filt1, filt2); + out1_r = AVC_DOT_SH3_SH(src21_r, src43_r, src65_r, filt0, filt1, filt2); + out2_r = AVC_DOT_SH3_SH(src32_r, src54_r, src76_r, filt0, filt1, filt2); + out3_r = AVC_DOT_SH3_SH(src43_r, src65_r, src87_r, filt0, filt1, filt2); + out0_l = AVC_DOT_SH3_SH(src10_l, src32_l, src54_l, filt0, filt1, filt2); + out1_l = AVC_DOT_SH3_SH(src21_l, src43_l, src65_l, filt0, filt1, filt2); + out2_l = AVC_DOT_SH3_SH(src32_l, src54_l, src76_l, filt0, filt1, filt2); + out3_l = AVC_DOT_SH3_SH(src43_l, src65_l, src87_l, filt0, filt1, filt2); + SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 5); + SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); + SRARI_H4_SH(out0_l, out1_l, out2_l, out3_l, 5); + SAT_SH4_SH(out0_l, out1_l, out2_l, out3_l, 7); + PCKEV_B4_UB(out0_l, out0_r, out1_l, out1_r, out2_l, out2_r, out3_l, + out3_r, res0, res1, res2, res3); + res0 = (v16u8) __msa_aver_s_b((v16i8) res0, src2); + res1 = (v16u8) __msa_aver_s_b((v16i8) res1, src3); + res2 = (v16u8) __msa_aver_s_b((v16i8) res2, src4); + res3 = (v16u8) __msa_aver_s_b((v16i8) res3, src5); + XORI_B4_128_UB(res0, res1, res2, res3); + ST_UB4(res0, res1, res2, res3, dst, stride); + dst += (4 * stride); + + src10_r = src54_r; + src32_r = src76_r; + src21_r = src65_r; + src43_r = src87_r; + src10_l = src54_l; + src32_l = src76_l; + src21_l = src65_l; + src43_l = src87_l; + src2 = src6; + src3 = src7; + src4 = src8; + } +} + +void ff_put_h264_qpel16_mc03_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + int32_t loop_cnt; + int16_t filt_const0 = 0xfb01; + int16_t filt_const1 = 0x1414; + int16_t filt_const2 = 0x1fb; + v16u8 res0, res1, res2, res3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; + v16i8 src87_r, src10_l, src32_l, src54_l, src76_l, src21_l, src43_l; + v16i8 src65_l, src87_l, filt0, filt1, filt2; + v8i16 out0_r, out1_r, out2_r, out3_r, out0_l, out1_l, out2_l, out3_l; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); + + src -= (stride * 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + + XORI_B5_128_SB(src0, src1, src2, src3, src4); + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVL_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_l, src21_l, + src32_l, src43_l); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src, stride, src5, src6, src7, src8); + src += (4 * stride); + + XORI_B4_128_SB(src5, src6, src7, src8); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, + src65_r, src76_r, src87_r); + ILVL_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_l, + src65_l, src76_l, src87_l); + out0_r = AVC_DOT_SH3_SH(src10_r, src32_r, src54_r, filt0, filt1, filt2); + out1_r = AVC_DOT_SH3_SH(src21_r, src43_r, src65_r, filt0, filt1, filt2); + out2_r = AVC_DOT_SH3_SH(src32_r, src54_r, src76_r, filt0, filt1, filt2); + out3_r = AVC_DOT_SH3_SH(src43_r, src65_r, src87_r, filt0, filt1, filt2); + out0_l = AVC_DOT_SH3_SH(src10_l, src32_l, src54_l, filt0, filt1, filt2); + out1_l = AVC_DOT_SH3_SH(src21_l, src43_l, src65_l, filt0, filt1, filt2); + out2_l = AVC_DOT_SH3_SH(src32_l, src54_l, src76_l, filt0, filt1, filt2); + out3_l = AVC_DOT_SH3_SH(src43_l, src65_l, src87_l, filt0, filt1, filt2); + SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 5); + SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); + SRARI_H4_SH(out0_l, out1_l, out2_l, out3_l, 5); + SAT_SH4_SH(out0_l, out1_l, out2_l, out3_l, 7); + PCKEV_B4_UB(out0_l, out0_r, out1_l, out1_r, out2_l, out2_r, out3_l, + out3_r, res0, res1, res2, res3); + res0 = (v16u8) __msa_aver_s_b((v16i8) res0, src3); + res1 = (v16u8) __msa_aver_s_b((v16i8) res1, src4); + res2 = (v16u8) __msa_aver_s_b((v16i8) res2, src5); + res3 = (v16u8) __msa_aver_s_b((v16i8) res3, src6); + XORI_B4_128_UB(res0, res1, res2, res3); + ST_UB4(res0, res1, res2, res3, dst, stride); + dst += (4 * stride); + + src10_r = src54_r; + src32_r = src76_r; + src21_r = src65_r; + src43_r = src87_r; + src10_l = src54_l; + src32_l = src76_l; + src21_l = src65_l; + src43_l = src87_l; + src3 = src7; + src4 = src8; + } +} + +void ff_put_h264_qpel8_mc01_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 src11, src12, src10_r, src32_r, src54_r, src65_r, src76_r, src98_r; + v16i8 src21_r, src43_r, src87_r, src109_r, src1211_r, src1110_r; + v16i8 tmp0, tmp1, tmp2, tmp3, filt0, filt1, filt2, out0, out1, out2, out3; + v8i16 out0_r, out1_r, out2_r, out3_r, out4_r, out5_r, out6_r, out7_r; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); + + src -= (stride * 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + LD_SB8(src, stride, src5, src6, src7, src8, src9, src10, src11, src12); + XORI_B8_128_SB(src5, src6, src7, src8, src9, src10, src11, src12); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, src65_r, + src76_r, src87_r); + ILVR_B4_SB(src9, src8, src10, src9, src11, src10, src12, src11, src98_r, + src109_r, src1110_r, src1211_r); + out0_r = AVC_DOT_SH3_SH(src10_r, src32_r, src54_r, filt0, filt1, filt2); + out1_r = AVC_DOT_SH3_SH(src21_r, src43_r, src65_r, filt0, filt1, filt2); + out2_r = AVC_DOT_SH3_SH(src32_r, src54_r, src76_r, filt0, filt1, filt2); + out3_r = AVC_DOT_SH3_SH(src43_r, src65_r, src87_r, filt0, filt1, filt2); + out4_r = AVC_DOT_SH3_SH(src54_r, src76_r, src98_r, filt0, filt1, filt2); + out5_r = AVC_DOT_SH3_SH(src65_r, src87_r, src109_r, filt0, filt1, filt2); + out6_r = AVC_DOT_SH3_SH(src76_r, src98_r, src1110_r, filt0, filt1, filt2); + out7_r = AVC_DOT_SH3_SH(src87_r, src109_r, src1211_r, filt0, filt1, filt2); + PCKEV_D2_SB(src3, src2, src5, src4, tmp0, tmp1); + PCKEV_D2_SB(src7, src6, src9, src8, tmp2, tmp3); + SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 5); + SRARI_H4_SH(out4_r, out5_r, out6_r, out7_r, 5); + SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); + SAT_SH4_SH(out4_r, out5_r, out6_r, out7_r, 7); + PCKEV_B2_SB(out1_r, out0_r, out3_r, out2_r, out0, out1); + PCKEV_B2_SB(out5_r, out4_r, out7_r, out6_r, out2, out3); + out0 = __msa_aver_s_b(out0, tmp0); + out1 = __msa_aver_s_b(out1, tmp1); + out2 = __msa_aver_s_b(out2, tmp2); + out3 = __msa_aver_s_b(out3, tmp3); + XORI_B4_128_SB(out0, out1, out2, out3); + ST8x8_UB(out0, out1, out2, out3, dst, stride); +} + +void ff_put_h264_qpel8_mc03_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 src11, src12, src10_r, src32_r, src54_r, src65_r, src76_r, src98_r; + v16i8 src21_r, src43_r, src87_r, src109_r, src1211_r, src1110_r; + v16i8 filt0, filt1, filt2, out0, out1, out2, out3, tmp0, tmp1, tmp2, tmp3; + v8i16 out0_r, out1_r, out2_r, out3_r, out4_r, out5_r, out6_r, out7_r; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); + + src -= (stride * 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + LD_SB8(src, stride, src5, src6, src7, src8, src9, src10, src11, src12); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B8_128_SB(src5, src6, src7, src8, src9, src10, src11, src12); + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, src65_r, + src76_r, src87_r); + ILVR_B4_SB(src9, src8, src10, src9, src11, src10, src12, src11, src98_r, + src109_r, src1110_r, src1211_r); + out0_r = AVC_DOT_SH3_SH(src10_r, src32_r, src54_r, filt0, filt1, filt2); + out1_r = AVC_DOT_SH3_SH(src21_r, src43_r, src65_r, filt0, filt1, filt2); + out2_r = AVC_DOT_SH3_SH(src32_r, src54_r, src76_r, filt0, filt1, filt2); + out3_r = AVC_DOT_SH3_SH(src43_r, src65_r, src87_r, filt0, filt1, filt2); + out4_r = AVC_DOT_SH3_SH(src54_r, src76_r, src98_r, filt0, filt1, filt2); + out5_r = AVC_DOT_SH3_SH(src65_r, src87_r, src109_r, filt0, filt1, filt2); + out6_r = AVC_DOT_SH3_SH(src76_r, src98_r, src1110_r, filt0, filt1, filt2); + out7_r = AVC_DOT_SH3_SH(src87_r, src109_r, src1211_r, filt0, filt1, filt2); + PCKEV_D2_SB(src4, src3, src6, src5, tmp0, tmp1); + PCKEV_D2_SB(src8, src7, src10, src9, tmp2, tmp3); + SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 5); + SRARI_H4_SH(out4_r, out5_r, out6_r, out7_r, 5); + SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); + SAT_SH4_SH(out4_r, out5_r, out6_r, out7_r, 7); + PCKEV_B2_SB(out1_r, out0_r, out3_r, out2_r, out0, out1); + PCKEV_B2_SB(out5_r, out4_r, out7_r, out6_r, out2, out3); + out0 = __msa_aver_s_b(out0, tmp0); + out1 = __msa_aver_s_b(out1, tmp1); + out2 = __msa_aver_s_b(out2, tmp2); + out3 = __msa_aver_s_b(out3, tmp3); + XORI_B4_128_SB(out0, out1, out2, out3); + ST8x8_UB(out0, out1, out2, out3, dst, stride); +} + +void ff_put_h264_qpel4_mc01_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ int16_t filt_const0 = 0xfb01; int16_t filt_const1 = 0x1414; int16_t filt_const2 = 0x1fb; - v16u8 dst0, dst1, dst2, dst3; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; + v16i8 src87_r, src2110, src4332, src6554, src8776, filt0, filt1, filt2; + v8i16 out10, out32; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); + + src -= (stride * 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVR_D2_SB(src21_r, src10_r, src43_r, src32_r, src2110, src4332); + XORI_B2_128_SB(src2110, src4332); + LD_SB4(src, stride, src5, src6, src7, src8); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, src65_r, + src76_r, src87_r); + ILVR_D2_SB(src65_r, src54_r, src87_r, src76_r, src6554, src8776); + XORI_B2_128_SB(src6554, src8776); + out10 = AVC_DOT_SH3_SH(src2110, src4332, src6554, filt0, filt1, filt2); + out32 = AVC_DOT_SH3_SH(src4332, src6554, src8776, filt0, filt1, filt2); + SRARI_H2_SH(out10, out32, 5); + SAT_SH2_SH(out10, out32, 7); + out = PCKEV_XORI128_UB(out10, out32); + src32_r = (v16i8) __msa_insve_w((v4i32) src2, 1, (v4i32) src3); + src54_r = (v16i8) __msa_insve_w((v4i32) src4, 1, (v4i32) src5); + src32_r = (v16i8) __msa_insve_d((v2i64) src32_r, 1, (v2i64) src54_r); + out = __msa_aver_u_b(out, (v16u8) src32_r); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); +} + +void ff_put_h264_qpel4_mc03_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + int16_t filt_const0 = 0xfb01; + int16_t filt_const1 = 0x1414; + int16_t filt_const2 = 0x1fb; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; + v16i8 src87_r, src2110, src4332, src6554, src8776, filt0, filt1, filt2; + v8i16 out10, out32; + + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); + + src -= (stride * 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVR_D2_SB(src21_r, src10_r, src43_r, src32_r, src2110, src4332); + XORI_B2_128_SB(src2110, src4332); + LD_SB4(src, stride, src5, src6, src7, src8); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, src65_r, + src76_r, src87_r); + ILVR_D2_SB(src65_r, src54_r, src87_r, src76_r, src6554, src8776); + XORI_B2_128_SB(src6554, src8776); + out10 = AVC_DOT_SH3_SH(src2110, src4332, src6554, filt0, filt1, filt2); + out32 = AVC_DOT_SH3_SH(src4332, src6554, src8776, filt0, filt1, filt2); + SRARI_H2_SH(out10, out32, 5); + SAT_SH2_SH(out10, out32, 7); + out = PCKEV_XORI128_UB(out10, out32); + src32_r = (v16i8) __msa_insve_w((v4i32) src3, 1, (v4i32) src4); + src54_r = (v16i8) __msa_insve_w((v4i32) src5, 1, (v4i32) src6); + src32_r = (v16i8) __msa_insve_d((v2i64) src32_r, 1, (v2i64) src54_r); + out = __msa_aver_u_b(out, (v16u8) src32_r); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); +} + +void ff_put_h264_qpel16_mc11_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + avc_luma_hv_qrt_16x16_msa(src - 2, src - (stride * 2), dst, stride); +} + +void ff_put_h264_qpel16_mc31_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + avc_luma_hv_qrt_16x16_msa(src - 2, src - (stride * 2) + 1, dst, stride); +} + +void ff_put_h264_qpel16_mc13_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + avc_luma_hv_qrt_16x16_msa(src + stride - 2, src - (stride * 2), dst, + stride); +} + +void ff_put_h264_qpel16_mc33_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + avc_luma_hv_qrt_16x16_msa(src + stride - 2, src - (stride * 2) + 1, dst, + stride); +} + +void ff_put_h264_qpel8_mc11_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + avc_luma_hv_qrt_8x8_msa(src - 2, src - (stride * 2), dst, stride); +} + +void ff_put_h264_qpel8_mc31_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + avc_luma_hv_qrt_8x8_msa(src - 2, src - (stride * 2) + 1, dst, stride); +} + +void ff_put_h264_qpel8_mc13_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + avc_luma_hv_qrt_8x8_msa(src + stride - 2, src - (stride * 2), dst, stride); +} + +void ff_put_h264_qpel8_mc33_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + avc_luma_hv_qrt_8x8_msa(src + stride - 2, src - (stride * 2) + 1, dst, + stride); +} + + +void ff_put_h264_qpel4_mc11_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + avc_luma_hv_qrt_4x4_msa(src - 2, src - (stride * 2), dst, stride); +} + +void ff_put_h264_qpel4_mc31_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + avc_luma_hv_qrt_4x4_msa(src - 2, src - (stride * 2) + 1, dst, stride); +} + +void ff_put_h264_qpel4_mc13_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + avc_luma_hv_qrt_4x4_msa(src + stride - 2, src - (stride * 2), dst, stride); +} + +void ff_put_h264_qpel4_mc33_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + avc_luma_hv_qrt_4x4_msa(src + stride - 2, src - (stride * 2) + 1, dst, + stride); +} + +void ff_put_h264_qpel16_mc21_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + uint8_t *dst_tmp = dst; + const uint8_t *src_tmp = src - (2 * stride) - 2; + uint32_t multiple8_cnt, loop_cnt; + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, mask0, mask1; + v16i8 mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r, hz_out10_l, hz_out21_l; + v8i16 hz_out32_l, hz_out43_l, hz_out54_l, hz_out65_l, hz_out76_l; + v8i16 hz_out87_l, filt0, filt1, filt2; + v4i32 tmp0, tmp1; + + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + + for (multiple8_cnt = 2; multiple8_cnt--;) { + dst = dst_tmp; + src = src_tmp; + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + src += (5 * stride); + + hz_out0 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src, stride, src5, src6, src7, src8); + src += (4 * stride); + + XORI_B4_128_SB(src5, src6, src7, src8); + + hz_out5 = AVC_HORZ_FILTER_SH(src5, src5, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src6, src6, mask0, mask1, mask2); + hz_out7 = AVC_HORZ_FILTER_SH(src7, src7, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src8, src8, mask0, mask1, mask2); + + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, + hz_out4, hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, + hz_out43_r); + ILVL_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, + hz_out4, hz_out3, hz_out10_l, hz_out21_l, hz_out32_l, + hz_out43_l); + ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, + hz_out8, hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, + hz_out87_r); + ILVL_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, + hz_out8, hz_out7, hz_out54_l, hz_out65_l, hz_out76_l, + hz_out87_l); + + tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, + filt1, filt2); + dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, + filt1, filt2); + dst2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, + filt1, filt2); + dst4 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, + filt1, filt2); + dst6 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + + dst1 = __msa_srari_h(hz_out2, 5); + dst3 = __msa_srari_h(hz_out3, 5); + dst5 = __msa_srari_h(hz_out4, 5); + dst7 = __msa_srari_h(hz_out5, 5); + SAT_SH4_SH(dst1, dst3, dst5, dst7, 7); + + dst0 = __msa_aver_s_h(dst0, dst1); + dst1 = __msa_aver_s_h(dst2, dst3); + dst2 = __msa_aver_s_h(dst4, dst5); + dst3 = __msa_aver_s_h(dst6, dst7); + + out0 = PCKEV_XORI128_UB(dst0, dst1); + out1 = PCKEV_XORI128_UB(dst2, dst3); + ST8x4_UB(out0, out1, dst, stride); + dst += (4 * stride); + + hz_out0 = hz_out4; + hz_out1 = hz_out5; + hz_out2 = hz_out6; + hz_out3 = hz_out7; + hz_out4 = hz_out8; + } + + src_tmp += 8; + dst_tmp += 8; + } +} + +void ff_put_h264_qpel16_mc23_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + uint8_t *dst_tmp = dst; + const uint8_t *src_tmp = src - (2 * stride) - 2; + uint32_t multiple8_cnt, loop_cnt; + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, mask0, mask1; + v16i8 mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r, hz_out10_l, hz_out21_l; + v8i16 hz_out32_l, hz_out43_l, hz_out54_l, hz_out65_l, hz_out76_l; + v8i16 hz_out87_l, filt0, filt1, filt2; + v4i32 tmp0, tmp1; + + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + + for (multiple8_cnt = 2; multiple8_cnt--;) { + dst = dst_tmp; + src = src_tmp; + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + src += (5 * stride); + + hz_out0 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src, stride, src5, src6, src7, src8); + src += (4 * stride); + + XORI_B4_128_SB(src5, src6, src7, src8); + + hz_out5 = AVC_HORZ_FILTER_SH(src5, src5, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src6, src6, mask0, mask1, mask2); + hz_out7 = AVC_HORZ_FILTER_SH(src7, src7, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src8, src8, mask0, mask1, mask2); + + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, + hz_out4, hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, + hz_out43_r); + ILVL_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, + hz_out4, hz_out3, hz_out10_l, hz_out21_l, hz_out32_l, + hz_out43_l); + ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, + hz_out8, hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, + hz_out87_r); + ILVL_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, + hz_out8, hz_out7, hz_out54_l, hz_out65_l, hz_out76_l, + hz_out87_l); + + tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, + filt1, filt2); + dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, + filt1, filt2); + dst2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, + filt1, filt2); + dst4 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, + filt1, filt2); + dst6 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + + dst1 = __msa_srari_h(hz_out3, 5); + dst3 = __msa_srari_h(hz_out4, 5); + dst5 = __msa_srari_h(hz_out5, 5); + dst7 = __msa_srari_h(hz_out6, 5); + SAT_SH4_SH(dst1, dst3, dst5, dst7, 7); + + dst0 = __msa_aver_s_h(dst0, dst1); + dst1 = __msa_aver_s_h(dst2, dst3); + dst2 = __msa_aver_s_h(dst4, dst5); + dst3 = __msa_aver_s_h(dst6, dst7); + + out0 = PCKEV_XORI128_UB(dst0, dst1); + out1 = PCKEV_XORI128_UB(dst2, dst3); + ST8x4_UB(out0, out1, dst, stride); + dst += (4 * stride); + + hz_out0 = hz_out4; + hz_out1 = hz_out5; + hz_out2 = hz_out6; + hz_out3 = hz_out7; + hz_out4 = hz_out8; + } + + src_tmp += 8; + dst_tmp += 8; + } +} + +void ff_put_h264_qpel8_mc21_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 src11, src12, mask0, mask1, mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, hz_out9, hz_out10, hz_out11, hz_out12; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r, hz_out89_r, hz_out910_r; + v8i16 hz_out1110_r, hz_out1211_r, dst0, dst1, dst2, dst3; + v8i16 hz_out10_l, hz_out21_l, hz_out32_l, hz_out43_l, hz_out54_l; + v8i16 hz_out65_l, hz_out76_l, hz_out87_l, hz_out89_l, hz_out910_l; + v8i16 hz_out1110_l, hz_out1211_l, filt0, filt1, filt2; + v4i32 tmp0, tmp1; + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); + + src -= ((2 * stride) + 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + src += (5 * stride); + + hz_out0 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); + + LD_SB4(src, stride, src5, src6, src7, src8); + src += (4 * stride); + XORI_B4_128_SB(src5, src6, src7, src8); + + hz_out5 = AVC_HORZ_FILTER_SH(src5, src5, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src6, src6, mask0, mask1, mask2); + hz_out7 = AVC_HORZ_FILTER_SH(src7, src7, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src8, src8, mask0, mask1, mask2); + + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r); + ILVL_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_l, hz_out21_l, hz_out32_l, hz_out43_l); + ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, hz_out87_r); + ILVL_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_l, hz_out65_l, hz_out76_l, hz_out87_l); + + tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, filt1, + filt2); + dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, filt1, + filt2); + dst1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, filt1, + filt2); + dst2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, filt1, + filt2); + dst3 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + + SRARI_H4_SH(hz_out2, hz_out3, hz_out4, hz_out5, 5); + SAT_SH4_SH(hz_out2, hz_out3, hz_out4, hz_out5, 7); + + dst0 = __msa_aver_s_h(dst0, hz_out2); + dst1 = __msa_aver_s_h(dst1, hz_out3); + dst2 = __msa_aver_s_h(dst2, hz_out4); + dst3 = __msa_aver_s_h(dst3, hz_out5); + + out0 = PCKEV_XORI128_UB(dst0, dst1); + out1 = PCKEV_XORI128_UB(dst2, dst3); + ST8x4_UB(out0, out1, dst, stride); + dst += (4 * stride); + + LD_SB4(src, stride, src9, src10, src11, src12); + XORI_B4_128_SB(src9, src10, src11, src12); + hz_out9 = AVC_HORZ_FILTER_SH(src9, src9, mask0, mask1, mask2); + hz_out10 = AVC_HORZ_FILTER_SH(src10, src10, mask0, mask1, mask2); + hz_out11 = AVC_HORZ_FILTER_SH(src11, src11, mask0, mask1, mask2); + hz_out12 = AVC_HORZ_FILTER_SH(src12, src12, mask0, mask1, mask2); + ILVR_H4_SH(hz_out9, hz_out8, hz_out10, hz_out9, hz_out11, hz_out10, + hz_out12, hz_out11, hz_out89_r, hz_out910_r, hz_out1110_r, + hz_out1211_r); + ILVL_H4_SH(hz_out9, hz_out8, hz_out10, hz_out9, hz_out11, hz_out10, + hz_out12, hz_out11, hz_out89_l, hz_out910_l, hz_out1110_l, + hz_out1211_l); + tmp0 = AVC_DOT_SW3_SW(hz_out54_r, hz_out76_r, hz_out89_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out54_l, hz_out76_l, hz_out89_l, filt0, filt1, + filt2); + dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out65_r, hz_out87_r, hz_out910_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out65_l, hz_out87_l, hz_out910_l, filt0, filt1, + filt2); + dst1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out76_r, hz_out89_r, hz_out1110_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out76_l, hz_out89_l, hz_out1110_l, filt0, filt1, + filt2); + dst2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out87_r, hz_out910_r, hz_out1211_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out87_l, hz_out910_l, hz_out1211_l, filt0, filt1, + filt2); + dst3 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + + SRARI_H4_SH(hz_out6, hz_out7, hz_out8, hz_out9, 5); + SAT_SH4_SH(hz_out6, hz_out7, hz_out8, hz_out9, 7); + + dst0 = __msa_aver_s_h(dst0, hz_out6); + dst1 = __msa_aver_s_h(dst1, hz_out7); + dst2 = __msa_aver_s_h(dst2, hz_out8); + dst3 = __msa_aver_s_h(dst3, hz_out9); + + out0 = PCKEV_XORI128_UB(dst0, dst1); + out1 = PCKEV_XORI128_UB(dst2, dst3); + ST8x4_UB(out0, out1, dst, stride); +} + +void ff_put_h264_qpel8_mc23_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 src11, src12, mask0, mask1, mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, hz_out9, hz_out10, hz_out11, hz_out12; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r, hz_out89_r, hz_out910_r; + v8i16 hz_out1110_r, hz_out1211_r, dst0, dst1, dst2, dst3; + v8i16 hz_out10_l, hz_out21_l, hz_out32_l, hz_out43_l, hz_out54_l; + v8i16 hz_out65_l, hz_out76_l, hz_out87_l, hz_out89_l, hz_out910_l; + v8i16 hz_out1110_l, hz_out1211_l, filt0, filt1, filt2; + v4i32 tmp0, tmp1; + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); + + src -= ((2 * stride) + 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + src += (5 * stride); + + hz_out0 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); + + LD_SB4(src, stride, src5, src6, src7, src8); + src += (4 * stride); + XORI_B4_128_SB(src5, src6, src7, src8); + + hz_out5 = AVC_HORZ_FILTER_SH(src5, src5, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src6, src6, mask0, mask1, mask2); + hz_out7 = AVC_HORZ_FILTER_SH(src7, src7, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src8, src8, mask0, mask1, mask2); + + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r); + ILVL_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_l, hz_out21_l, hz_out32_l, hz_out43_l); + ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, hz_out87_r); + ILVL_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_l, hz_out65_l, hz_out76_l, hz_out87_l); + + tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, filt1, + filt2); + dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, filt1, + filt2); + dst1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, filt1, + filt2); + dst2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, filt1, + filt2); + dst3 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + + SRARI_H4_SH(hz_out3, hz_out4, hz_out5, hz_out6, 5); + SAT_SH4_SH(hz_out3, hz_out4, hz_out5, hz_out6, 7); + + dst0 = __msa_aver_s_h(dst0, hz_out3); + dst1 = __msa_aver_s_h(dst1, hz_out4); + dst2 = __msa_aver_s_h(dst2, hz_out5); + dst3 = __msa_aver_s_h(dst3, hz_out6); + + out0 = PCKEV_XORI128_UB(dst0, dst1); + out1 = PCKEV_XORI128_UB(dst2, dst3); + ST8x4_UB(out0, out1, dst, stride); + dst += (4 * stride); + + LD_SB4(src, stride, src9, src10, src11, src12); + XORI_B4_128_SB(src9, src10, src11, src12); + hz_out9 = AVC_HORZ_FILTER_SH(src9, src9, mask0, mask1, mask2); + hz_out10 = AVC_HORZ_FILTER_SH(src10, src10, mask0, mask1, mask2); + hz_out11 = AVC_HORZ_FILTER_SH(src11, src11, mask0, mask1, mask2); + hz_out12 = AVC_HORZ_FILTER_SH(src12, src12, mask0, mask1, mask2); + ILVR_H4_SH(hz_out9, hz_out8, hz_out10, hz_out9, hz_out11, hz_out10, + hz_out12, hz_out11, hz_out89_r, hz_out910_r, hz_out1110_r, + hz_out1211_r); + ILVL_H4_SH(hz_out9, hz_out8, hz_out10, hz_out9, hz_out11, hz_out10, + hz_out12, hz_out11, hz_out89_l, hz_out910_l, hz_out1110_l, + hz_out1211_l); + tmp0 = AVC_DOT_SW3_SW(hz_out54_r, hz_out76_r, hz_out89_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out54_l, hz_out76_l, hz_out89_l, filt0, filt1, + filt2); + dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out65_r, hz_out87_r, hz_out910_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out65_l, hz_out87_l, hz_out910_l, filt0, filt1, + filt2); + dst1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out76_r, hz_out89_r, hz_out1110_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out76_l, hz_out89_l, hz_out1110_l, filt0, filt1, + filt2); + dst2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out87_r, hz_out910_r, hz_out1211_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out87_l, hz_out910_l, hz_out1211_l, filt0, filt1, + filt2); + dst3 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + + SRARI_H4_SH(hz_out7, hz_out8, hz_out9, hz_out10, 5); + SAT_SH4_SH(hz_out7, hz_out8, hz_out9, hz_out10, 7); + + dst0 = __msa_aver_s_h(dst0, hz_out7); + dst1 = __msa_aver_s_h(dst1, hz_out8); + dst2 = __msa_aver_s_h(dst2, hz_out9); + dst3 = __msa_aver_s_h(dst3, hz_out10); + + out0 = PCKEV_XORI128_UB(dst0, dst1); + out1 = PCKEV_XORI128_UB(dst2, dst3); + ST8x4_UB(out0, out1, dst, stride); +} + +void ff_put_h264_qpel4_mc21_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; + v16u8 res; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; - v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; - v16i8 src87_r, src2110, src4332, src6554, src8776; - v8i16 out10, out32; - v16i8 filt0, filt1, filt2; + v16i8 mask0, mask1, mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, dst0, dst1, filt0, filt1, filt2; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r; + v4i32 tmp0, tmp1; + + LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); + + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); + + src -= ((2 * stride) + 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + LD_SB4(src, stride, src5, src6, src7, src8); + + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B4_128_SB(src5, src6, src7, src8); + + hz_out0 = AVC_HORZ_FILTER_SH(src0, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src5, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src6, src7, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src8, src8, mask0, mask1, mask2); + PCKOD_D2_SH(hz_out0, hz_out0, hz_out2, hz_out2, hz_out1, hz_out3); + PCKOD_D2_SH(hz_out4, hz_out4, hz_out6, hz_out6, hz_out5, hz_out7); + + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r); + ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, hz_out87_r); + + tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, filt1, + filt2); + dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, filt1, + filt2); + dst1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + + SRARI_H2_SH(hz_out2, hz_out4, 5); + SAT_SH2_SH(hz_out2, hz_out4, 7); + + dst0 = __msa_aver_s_h(dst0, hz_out2); + dst1 = __msa_aver_s_h(dst1, hz_out4); + + res = PCKEV_XORI128_UB(dst0, dst1); + ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); +} + +void ff_put_h264_qpel4_mc23_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; v16u8 res; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 mask0, mask1, mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, dst0, dst1, filt0, filt1, filt2; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r; + v4i32 tmp0, tmp1; - filt0 = (v16i8) __msa_fill_h(filt_const0); - filt1 = (v16i8) __msa_fill_h(filt_const1); - filt2 = (v16i8) __msa_fill_h(filt_const2); + LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); - ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, - src10_r, src21_r, src32_r, src43_r); - ILVR_D2_SB(src21_r, src10_r, src43_r, src32_r, src2110, src4332); - XORI_B2_128_SB(src2110, src4332); - LD_SB4(src, src_stride, src5, src6, src7, src8); - ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, - src54_r, src65_r, src76_r, src87_r); - ILVR_D2_SB(src65_r, src54_r, src87_r, src76_r, src6554, src8776); - XORI_B2_128_SB(src6554, src8776); - out10 = DPADD_SH3_SH(src2110, src4332, src6554, filt0, filt1, filt2); - out32 = DPADD_SH3_SH(src4332, src6554, src8776, filt0, filt1, filt2); - SRARI_H2_SH(out10, out32, 5); - SAT_SH2_SH(out10, out32, 7); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - res = PCKEV_XORI128_UB(out10, out32); + src -= ((2 * stride) + 2); - ILVR_W2_UB(dst1, dst0, dst3, dst2, dst0, dst1); + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + LD_SB4(src, stride, src5, src6, src7, src8); - dst0 = (v16u8) __msa_pckev_d((v2i64) dst1, (v2i64) dst0); - dst0 = __msa_aver_u_b(res, dst0); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B4_128_SB(src5, src6, src7, src8); - ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, dst_stride); -} + hz_out0 = AVC_HORZ_FILTER_SH(src0, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src5, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src6, src7, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src8, src8, mask0, mask1, mask2); + PCKOD_D2_SH(hz_out0, hz_out0, hz_out2, hz_out2, hz_out1, hz_out3); + PCKOD_D2_SH(hz_out4, hz_out4, hz_out6, hz_out6, hz_out5, hz_out7); -static void avc_luma_vt_and_aver_dst_8x8_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride) -{ - int32_t loop_cnt; - int16_t filt_const0 = 0xfb01; - int16_t filt_const1 = 0x1414; - int16_t filt_const2 = 0x1fb; - v16u8 dst0, dst1, dst2, dst3; - v16i8 src0, src1, src2, src3, src4, src7, src8, src9, src10; - v16i8 src10_r, src32_r, src76_r, src98_r; - v16i8 src21_r, src43_r, src87_r, src109_r; - v8i16 out0, out1, out2, out3; - v16i8 filt0, filt1, filt2; + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r); + ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, hz_out87_r); - filt0 = (v16i8) __msa_fill_h(filt_const0); - filt1 = (v16i8) __msa_fill_h(filt_const1); - filt2 = (v16i8) __msa_fill_h(filt_const2); + tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, filt1, + filt2); + dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, filt1, + filt2); + dst1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + + PCKEV_D2_SH(hz_out4, hz_out3, hz_out6, hz_out5, hz_out0, hz_out1); + SRARI_H2_SH(hz_out0, hz_out1, 5); + SAT_SH2_SH(hz_out0, hz_out1, 7); - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); + dst0 = __msa_aver_s_h(dst0, hz_out0); + dst1 = __msa_aver_s_h(dst1, hz_out1); - XORI_B5_128_SB(src0, src1, src2, src3, src4); - ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, - src10_r, src21_r, src32_r, src43_r); - - for (loop_cnt = 2; loop_cnt--;) { - LD_SB4(src, src_stride, src7, src8, src9, src10); - src += (4 * src_stride); - - XORI_B4_128_SB(src7, src8, src9, src10); - ILVR_B4_SB(src7, src4, src8, src7, src9, src8, src10, src9, - src76_r, src87_r, src98_r, src109_r); - out0 = DPADD_SH3_SH(src10_r, src32_r, src76_r, filt0, filt1, filt2); - out1 = DPADD_SH3_SH(src21_r, src43_r, src87_r, filt0, filt1, filt2); - out2 = DPADD_SH3_SH(src32_r, src76_r, src98_r, filt0, filt1, filt2); - out3 = DPADD_SH3_SH(src43_r, src87_r, src109_r, filt0, filt1, filt2); - SRARI_H4_SH(out0, out1, out2, out3, 5); - SAT_SH4_SH(out0, out1, out2, out3, 7); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - ILVR_D2_UB(dst1, dst0, dst3, dst2, dst0, dst1); - CONVERT_UB_AVG_ST8x4_UB(out0, out1, out2, out3, dst0, dst1, - dst, dst_stride); - dst += (4 * dst_stride); - - src10_r = src76_r; - src32_r = src98_r; - src21_r = src87_r; - src43_r = src109_r; - src4 = src10; - } + res = PCKEV_XORI128_UB(dst0, dst1); + ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); } -static void avc_luma_vt_and_aver_dst_16x16_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride) +void ff_put_h264_qpel16_mc02_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) { int32_t loop_cnt; int16_t filt_const0 = 0xfb01; int16_t filt_const1 = 0x1414; int16_t filt_const2 = 0x1fb; - v16u8 dst0, dst1, dst2, dst3; + v16u8 res0, res1, res2, res3; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; v16i8 src87_r, src10_l, src32_l, src54_l, src76_l, src21_l, src43_l; - v16i8 src65_l, src87_l; + v16i8 src65_l, src87_l, filt0, filt1, filt2; v8i16 out0_r, out1_r, out2_r, out3_r, out0_l, out1_l, out2_l, out3_l; - v16i8 filt0, filt1, filt2; - v16u8 res0, res1, res2, res3; filt0 = (v16i8) __msa_fill_h(filt_const0); filt1 = (v16i8) __msa_fill_h(filt_const1); filt2 = (v16i8) __msa_fill_h(filt_const2); + src -= (stride * 2); - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); XORI_B5_128_SB(src0, src1, src2, src3, src4); - ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, - src10_r, src21_r, src32_r, src43_r); - ILVL_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, - src10_l, src21_l, src32_l, src43_l); + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVL_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_l, src21_l, + src32_l, src43_l); for (loop_cnt = 4; loop_cnt--;) { - LD_SB4(src, src_stride, src5, src6, src7, src8); - src += (4 * src_stride); + LD_SB4(src, stride, src5, src6, src7, src8); + src += (4 * stride); XORI_B4_128_SB(src5, src6, src7, src8); - ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, - src54_r, src65_r, src76_r, src87_r); - ILVL_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, - src54_l, src65_l, src76_l, src87_l); - out0_r = DPADD_SH3_SH(src10_r, src32_r, src54_r, filt0, filt1, filt2); - out1_r = DPADD_SH3_SH(src21_r, src43_r, src65_r, filt0, filt1, filt2); - out2_r = DPADD_SH3_SH(src32_r, src54_r, src76_r, filt0, filt1, filt2); - out3_r = DPADD_SH3_SH(src43_r, src65_r, src87_r, filt0, filt1, filt2); - out0_l = DPADD_SH3_SH(src10_l, src32_l, src54_l, filt0, filt1, filt2); - out1_l = DPADD_SH3_SH(src21_l, src43_l, src65_l, filt0, filt1, filt2); - out2_l = DPADD_SH3_SH(src32_l, src54_l, src76_l, filt0, filt1, filt2); - out3_l = DPADD_SH3_SH(src43_l, src65_l, src87_l, filt0, filt1, filt2); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, + src65_r, src76_r, src87_r); + ILVL_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_l, + src65_l, src76_l, src87_l); + out0_r = AVC_DOT_SH3_SH(src10_r, src32_r, src54_r, filt0, filt1, filt2); + out1_r = AVC_DOT_SH3_SH(src21_r, src43_r, src65_r, filt0, filt1, filt2); + out2_r = AVC_DOT_SH3_SH(src32_r, src54_r, src76_r, filt0, filt1, filt2); + out3_r = AVC_DOT_SH3_SH(src43_r, src65_r, src87_r, filt0, filt1, filt2); + out0_l = AVC_DOT_SH3_SH(src10_l, src32_l, src54_l, filt0, filt1, filt2); + out1_l = AVC_DOT_SH3_SH(src21_l, src43_l, src65_l, filt0, filt1, filt2); + out2_l = AVC_DOT_SH3_SH(src32_l, src54_l, src76_l, filt0, filt1, filt2); + out3_l = AVC_DOT_SH3_SH(src43_l, src65_l, src87_l, filt0, filt1, filt2); SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 5); - SRARI_H4_SH(out0_l, out1_l, out2_l, out3_l, 5); SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); + SRARI_H4_SH(out0_l, out1_l, out2_l, out3_l, 5); SAT_SH4_SH(out0_l, out1_l, out2_l, out3_l, 7); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); PCKEV_B4_UB(out0_l, out0_r, out1_l, out1_r, out2_l, out2_r, out3_l, out3_r, res0, res1, res2, res3); XORI_B4_128_UB(res0, res1, res2, res3); - AVER_UB4_UB(res0, dst0, res1, dst1, res2, dst2, res3, dst3, - res0, res1, res2, res3); - ST_UB4(res0, res1, res2, res3, dst, dst_stride); - dst += (4 * dst_stride); + ST_UB4(res0, res1, res2, res3, dst, stride); + dst += (4 * stride); src10_r = src54_r; src32_r = src76_r; @@ -1079,423 +2285,324 @@ static void avc_luma_vt_and_aver_dst_16x16_msa(const uint8_t *src, } } -static void avc_luma_vt_qrt_and_aver_dst_4x4_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - uint8_t ver_offset) -{ - int16_t filt_const0 = 0xfb01; - int16_t filt_const1 = 0x1414; - int16_t filt_const2 = 0x1fb; - v16u8 dst0, dst1, dst2, dst3; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; - v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; - v16i8 src87_r, src2110, src4332, src6554, src8776; - v8i16 out10, out32; - v16i8 filt0, filt1, filt2; - v16u8 res; - - filt0 = (v16i8) __msa_fill_h(filt_const0); - filt1 = (v16i8) __msa_fill_h(filt_const1); - filt2 = (v16i8) __msa_fill_h(filt_const2); - - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); - - ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, - src10_r, src21_r, src32_r, src43_r); - ILVR_D2_SB(src21_r, src10_r, src43_r, src32_r, src2110, src4332); - XORI_B2_128_SB(src2110, src4332); - LD_SB4(src, src_stride, src5, src6, src7, src8); - ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, - src54_r, src65_r, src76_r, src87_r); - ILVR_D2_SB(src65_r, src54_r, src87_r, src76_r, src6554, src8776); - XORI_B2_128_SB(src6554, src8776); - out10 = DPADD_SH3_SH(src2110, src4332, src6554, filt0, filt1, filt2); - out32 = DPADD_SH3_SH(src4332, src6554, src8776, filt0, filt1, filt2); - SRARI_H2_SH(out10, out32, 5); - SAT_SH2_SH(out10, out32, 7); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - res = PCKEV_XORI128_UB(out10, out32); - - if (ver_offset) { - src32_r = (v16i8) __msa_insve_w((v4i32) src3, 1, (v4i32) src4); - src54_r = (v16i8) __msa_insve_w((v4i32) src5, 1, (v4i32) src6); - } else { - src32_r = (v16i8) __msa_insve_w((v4i32) src2, 1, (v4i32) src3); - src54_r = (v16i8) __msa_insve_w((v4i32) src4, 1, (v4i32) src5); - } - - src32_r = (v16i8) __msa_insve_d((v2i64) src32_r, 1, (v2i64) src54_r); - res = __msa_aver_u_b(res, (v16u8) src32_r); - - ILVR_W2_UB(dst1, dst0, dst3, dst2, dst0, dst1); - - dst0 = (v16u8) __msa_pckev_d((v2i64) dst1, (v2i64) dst0); - dst0 = __msa_aver_u_b(res, dst0); - - ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, dst_stride); -} - -static void avc_luma_vt_qrt_and_aver_dst_8x8_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - uint8_t ver_offset) +void ff_put_h264_qpel8_mc02_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) { - int32_t loop_cnt; - int16_t filt_const0 = 0xfb01; - int16_t filt_const1 = 0x1414; - int16_t filt_const2 = 0x1fb; - v16u8 dst0, dst1, dst2, dst3; - v16i8 src0, src1, src2, src3, src4, src7, src8, src9, src10; - v16i8 src10_r, src32_r, src76_r, src98_r; - v16i8 src21_r, src43_r, src87_r, src109_r; - v8i16 out0_r, out1_r, out2_r, out3_r; - v16i8 res0, res1; - v16u8 vec0, vec1; + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + v16u8 out0, out1, out2, out3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 src11, src12, src10_r, src21_r, src32_r, src43_r, src76_r, src87_r; + v16i8 src98_r, src109_r, src89_r, src910_r, src1110_r, src1211_r; v16i8 filt0, filt1, filt2; + v8i16 out0_r, out1_r, out2_r, out3_r, out4_r, out5_r, out6_r, out7_r; filt0 = (v16i8) __msa_fill_h(filt_const0); filt1 = (v16i8) __msa_fill_h(filt_const1); filt2 = (v16i8) __msa_fill_h(filt_const2); - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); - - XORI_B5_128_SB(src0, src1, src2, src3, src4); - ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, - src10_r, src21_r, src32_r, src43_r); - - for (loop_cnt = 2; loop_cnt--;) { - LD_SB4(src, src_stride, src7, src8, src9, src10); - src += (4 * src_stride); - - XORI_B4_128_SB(src7, src8, src9, src10); - ILVR_B4_SB(src7, src4, src8, src7, src9, src8, src10, src9, - src76_r, src87_r, src98_r, src109_r); - out0_r = DPADD_SH3_SH(src10_r, src32_r, src76_r, filt0, filt1, filt2); - out1_r = DPADD_SH3_SH(src21_r, src43_r, src87_r, filt0, filt1, filt2); - out2_r = DPADD_SH3_SH(src32_r, src76_r, src98_r, filt0, filt1, filt2); - out3_r = DPADD_SH3_SH(src43_r, src87_r, src109_r, filt0, filt1, filt2); - SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 5); - SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); - PCKEV_B2_SB(out1_r, out0_r, out3_r, out2_r, res0, res1); - - if (ver_offset) { - PCKEV_D2_SB(src4, src3, src8, src7, src10_r, src32_r); - } else { - PCKEV_D2_SB(src3, src2, src7, src4, src10_r, src32_r); - } - - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - ILVR_D2_UB(dst1, dst0, dst3, dst2, dst0, dst1); - - vec0 = (v16u8) __msa_aver_s_b(res0, src10_r); - vec1 = (v16u8) __msa_aver_s_b(res1, src32_r); - - XORI_B2_128_UB(vec0, vec1); - AVER_UB2_UB(vec0, dst0, vec1, dst1, vec0, vec1); - ST8x4_UB(vec0, vec1, dst, dst_stride); - dst += (4 * dst_stride); + src -= (stride * 2); - src10_r = src76_r; - src32_r = src98_r; - src21_r = src87_r; - src43_r = src109_r; - src2 = src8; - src3 = src9; - src4 = src10; - } + LD_SB8(src, stride, src0, src1, src2, src3, src4, src5, src6, src7); + src += (8 * stride); + LD_SB5(src, stride, src8, src9, src10, src11, src12); + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src76_r, src87_r, + src98_r, src109_r); + ILVR_B4_SB(src9, src8, src10, src9, src11, src10, src12, src11, src89_r, + src910_r, src1110_r, src1211_r); + XORI_B4_128_SB(src10_r, src21_r, src32_r, src43_r); + XORI_B4_128_SB(src76_r, src87_r, src98_r, src109_r); + XORI_B4_128_SB(src89_r, src910_r, src1110_r, src1211_r); + out0_r = AVC_DOT_SH3_SH(src10_r, src32_r, src76_r, filt0, filt1, filt2); + out1_r = AVC_DOT_SH3_SH(src21_r, src43_r, src87_r, filt0, filt1, filt2); + out2_r = AVC_DOT_SH3_SH(src32_r, src76_r, src98_r, filt0, filt1, filt2); + out3_r = AVC_DOT_SH3_SH(src43_r, src87_r, src109_r, filt0, filt1, filt2); + out4_r = AVC_DOT_SH3_SH(src76_r, src98_r, src89_r, filt0, filt1, filt2); + out5_r = AVC_DOT_SH3_SH(src87_r, src109_r, src910_r, filt0, filt1, filt2); + out6_r = AVC_DOT_SH3_SH(src98_r, src89_r, src1110_r, filt0, filt1, filt2); + out7_r = AVC_DOT_SH3_SH(src109_r, src910_r, src1211_r, filt0, filt1, filt2); + SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 5); + SRARI_H4_SH(out4_r, out5_r, out6_r, out7_r, 5); + SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); + SAT_SH4_SH(out4_r, out5_r, out6_r, out7_r, 7); + out0 = PCKEV_XORI128_UB(out0_r, out1_r); + out1 = PCKEV_XORI128_UB(out2_r, out3_r); + out2 = PCKEV_XORI128_UB(out4_r, out5_r); + out3 = PCKEV_XORI128_UB(out6_r, out7_r); + ST8x8_UB(out0, out1, out2, out3, dst, stride); } -static void avc_luma_vt_qrt_and_aver_dst_16x16_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - uint8_t ver_offset) +void ff_put_h264_qpel4_mc02_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) { - int32_t loop_cnt; - int16_t filt_const0 = 0xfb01; - int16_t filt_const1 = 0x1414; - int16_t filt_const2 = 0x1fb; - v16u8 dst0, dst1, dst2, dst3; + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + v16u8 out; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; - v16i8 src87_r, src10_l, src32_l, src54_l, src76_l, src21_l, src43_l; - v16i8 src65_l, src87_l; - v8i16 out0_r, out1_r, out2_r, out3_r, out0_l, out1_l, out2_l, out3_l; - v16i8 out0, out1, out2, out3; - v16i8 filt0, filt1, filt2; - v16u8 res0, res1, res2, res3; + v16i8 src87_r, src2110, src4332, src6554, src8776, filt0, filt1, filt2; + v8i16 out10, out32; filt0 = (v16i8) __msa_fill_h(filt_const0); - filt1 = (v16i8) __msa_fill_h(filt_const1); - filt2 = (v16i8) __msa_fill_h(filt_const2); - - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); - - XORI_B5_128_SB(src0, src1, src2, src3, src4); - ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, - src10_r, src21_r, src32_r, src43_r); - ILVL_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, - src10_l, src21_l, src32_l, src43_l); - - for (loop_cnt = 4; loop_cnt--;) { - LD_SB4(src, src_stride, src5, src6, src7, src8); - src += (4 * src_stride); - - XORI_B4_128_SB(src5, src6, src7, src8); - ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, - src54_r, src65_r, src76_r, src87_r); - ILVL_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, - src54_l, src65_l, src76_l, src87_l); - out0_r = DPADD_SH3_SH(src10_r, src32_r, src54_r, filt0, filt1, filt2); - out1_r = DPADD_SH3_SH(src21_r, src43_r, src65_r, filt0, filt1, filt2); - out2_r = DPADD_SH3_SH(src32_r, src54_r, src76_r, filt0, filt1, filt2); - out3_r = DPADD_SH3_SH(src43_r, src65_r, src87_r, filt0, filt1, filt2); - out0_l = DPADD_SH3_SH(src10_l, src32_l, src54_l, filt0, filt1, filt2); - out1_l = DPADD_SH3_SH(src21_l, src43_l, src65_l, filt0, filt1, filt2); - out2_l = DPADD_SH3_SH(src32_l, src54_l, src76_l, filt0, filt1, filt2); - out3_l = DPADD_SH3_SH(src43_l, src65_l, src87_l, filt0, filt1, filt2); - SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 5); - SRARI_H4_SH(out0_l, out1_l, out2_l, out3_l, 5); - SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); - SAT_SH4_SH(out0_l, out1_l, out2_l, out3_l, 7); - PCKEV_B4_SB(out0_l, out0_r, out1_l, out1_r, out2_l, out2_r, out3_l, - out3_r, out0, out1, out2, out3); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - - if (ver_offset) { - res0 = (v16u8) __msa_aver_s_b(out0, src3); - res1 = (v16u8) __msa_aver_s_b(out1, src4); - res2 = (v16u8) __msa_aver_s_b(out2, src5); - res3 = (v16u8) __msa_aver_s_b(out3, src6); - } else { - res0 = (v16u8) __msa_aver_s_b(out0, src2); - res1 = (v16u8) __msa_aver_s_b(out1, src3); - res2 = (v16u8) __msa_aver_s_b(out2, src4); - res3 = (v16u8) __msa_aver_s_b(out3, src5); - } - - XORI_B4_128_UB(res0, res1, res2, res3); - AVER_UB4_UB(res0, dst0, res1, dst1, res2, dst2, res3, dst3, - dst0, dst1, dst2, dst3); - ST_UB4(dst0, dst1, dst2, dst3, dst, dst_stride); - dst += (4 * dst_stride); - - src10_r = src54_r; - src32_r = src76_r; - src21_r = src65_r; - src43_r = src87_r; - src10_l = src54_l; - src32_l = src76_l; - src21_l = src65_l; - src43_l = src87_l; - src2 = src6; - src3 = src7; - src4 = src8; - } -} - -static void avc_luma_mid_and_aver_dst_4x4_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride) -{ - v16i8 src0, src1, src2, src3, src4; - v16i8 mask0, mask1, mask2; - v8i16 hz_out0, hz_out1, hz_out2, hz_out3; - v8i16 hz_out4, hz_out5, hz_out6, hz_out7, hz_out8; - v8i16 res0, res1, res2, res3; - v16u8 dst0, dst1, dst2, dst3; - v16u8 tmp0, tmp1, tmp2, tmp3; - - LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); - XORI_B5_128_SB(src0, src1, src2, src3, src4); + src -= (stride * 2); - hz_out0 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src0, src1, - mask0, mask1, mask2); - hz_out2 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src2, src3, - mask0, mask1, mask2); + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + LD_SB4(src, stride, src5, src6, src7, src8); - PCKOD_D2_SH(hz_out0, hz_out0, hz_out2, hz_out2, hz_out1, hz_out3); + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, src65_r, + src76_r, src87_r); + ILVR_D4_SB(src21_r, src10_r, src43_r, src32_r, src65_r, src54_r, src87_r, + src76_r, src2110, src4332, src6554, src8776); + XORI_B4_128_SB(src2110, src4332, src6554, src8776); + out10 = AVC_DOT_SH3_SH(src2110, src4332, src6554, filt0, filt1, filt2); + out32 = AVC_DOT_SH3_SH(src4332, src6554, src8776, filt0, filt1, filt2); + SRARI_H2_SH(out10, out32, 5); + SAT_SH2_SH(out10, out32, 7); + out = PCKEV_XORI128_UB(out10, out32); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); +} - hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); +void ff_put_h264_qpel16_mc12_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) +{ + uint32_t row; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 src11; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, dst0, dst1, dst2, dst3, mask3; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v8i16 shf_vec7, shf_vec8, shf_vec9, shf_vec10, shf_vec11, mask4, mask5; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; + v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; + v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; + v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; + v8i16 minus5h = __msa_ldi_h(-5); + v8i16 plus20h = __msa_ldi_h(20); - LD_SB4(src, src_stride, src0, src1, src2, src3); - XORI_B4_128_SB(src0, src1, src2, src3); + mask3 = mask0 + 4; + mask4 = mask1 + 4; + mask5 = mask2 + 4; - hz_out5 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src0, src1, - mask0, mask1, mask2); - hz_out7 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src2, src3, - mask0, mask1, mask2); + src -= ((2 * stride) + 2); - PCKOD_D2_SH(hz_out5, hz_out5, hz_out7, hz_out7, hz_out6, hz_out8); + LD_SB5(src, stride, src0, src1, src2, src3, src4); + LD_SB5(src + 8, stride, src7, src8, src9, src10, src11); + src += (5 * stride); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B5_128_SB(src7, src8, src9, src10, src11); - res0 = AVC_CALC_DPADD_H_6PIX_2COEFF_R_SH(hz_out0, hz_out1, hz_out2, - hz_out3, hz_out4, hz_out5); - res1 = AVC_CALC_DPADD_H_6PIX_2COEFF_R_SH(hz_out1, hz_out2, hz_out3, - hz_out4, hz_out5, hz_out6); - res2 = AVC_CALC_DPADD_H_6PIX_2COEFF_R_SH(hz_out2, hz_out3, hz_out4, - hz_out5, hz_out6, hz_out7); - res3 = AVC_CALC_DPADD_H_6PIX_2COEFF_R_SH(hz_out3, hz_out4, hz_out5, - hz_out6, hz_out7, hz_out8); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - tmp0 = PCKEV_XORI128_UB(res0, res1); - tmp1 = PCKEV_XORI128_UB(res2, res3); - PCKEV_D2_UB(dst1, dst0, dst3, dst2, tmp2, tmp3); - AVER_UB2_UB(tmp0, tmp2, tmp1, tmp3, tmp0, tmp1); + for (row = 16; row--;) { + LD_SB2(src, 8, src5, src6); + src += stride; + XORI_B2_128_SB(src5, src6); - ST4x4_UB(tmp0, tmp1, 0, 2, 0, 2, dst, dst_stride); + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src0, src1, src2, src3, src4, src5, + vt_res0, vt_res1); + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src7, src8, src9, src10, src11, src6, + vt_res2, vt_res3); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask3, + mask4, mask5, shf_vec6, shf_vec7, shf_vec8); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask3, + mask4, mask5, shf_vec9, shf_vec10, shf_vec11); + hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); + hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + hz_res2 = __msa_hadd_s_w(shf_vec6, shf_vec6); + hz_res3 = __msa_hadd_s_w(shf_vec9, shf_vec9); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); + DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + DPADD_SH2_SW(shf_vec7, shf_vec8, minus5h, plus20h, hz_res2, hz_res2); + DPADD_SH2_SW(shf_vec10, shf_vec11, minus5h, plus20h, hz_res3, hz_res3); + SRARI_W4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 10); + SAT_SW4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 7); + dst0 = __msa_srari_h(shf_vec2, 5); + dst1 = __msa_srari_h(shf_vec5, 5); + dst2 = __msa_srari_h(shf_vec8, 5); + dst3 = __msa_srari_h(shf_vec11, 5); + SAT_SH4_SH(dst0, dst1, dst2, dst3, 7); + PCKEV_H2_SH(dst2, dst0, dst3, dst1, dst0, dst1); + PCKEV_H2_SH(hz_res2, hz_res0, hz_res3, hz_res1, dst2, dst3); + dst0 = __msa_aver_s_h(dst2, dst0); + dst1 = __msa_aver_s_h(dst3, dst1); + out = PCKEV_XORI128_UB(dst0, dst1); + ST_UB(out, dst); + dst += stride; + + src0 = src1; + src1 = src2; + src2 = src3; + src3 = src4; + src4 = src5; + src7 = src8; + src8 = src9; + src9 = src10; + src10 = src11; + src11 = src6; + } } -static void avc_luma_mid_and_aver_dst_8w_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - int32_t height) +void ff_put_h264_qpel16_mc32_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) { - uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4; - v16i8 mask0, mask1, mask2; - v8i16 hz_out0, hz_out1, hz_out2, hz_out3; - v8i16 hz_out4, hz_out5, hz_out6, hz_out7, hz_out8; - v16u8 dst0, dst1, dst2, dst3; - v8i16 res0, res1, res2, res3; + uint32_t row; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 src11; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, dst0, dst1, dst2, dst3, mask3; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v8i16 shf_vec7, shf_vec8, shf_vec9, shf_vec10, shf_vec11, mask4, mask5; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; + v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; + v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; + v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; + v8i16 minus5h = __msa_ldi_h(-5); + v8i16 plus20h = __msa_ldi_h(20); - LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + mask3 = mask0 + 4; + mask4 = mask1 + 4; + mask5 = mask2 + 4; + + src -= ((2 * stride) + 2); - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); + LD_SB5(src, stride, src0, src1, src2, src3, src4); + LD_SB5(src + 8, stride, src7, src8, src9, src10, src11); + src += (5 * stride); XORI_B5_128_SB(src0, src1, src2, src3, src4); - src += (5 * src_stride); + XORI_B5_128_SB(src7, src8, src9, src10, src11); - hz_out0 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); - hz_out1 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); - hz_out2 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); - hz_out3 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); - hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); + for (row = 16; row--;) { + LD_SB2(src, 8, src5, src6); + src += stride; + XORI_B2_128_SB(src5, src6); - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src, src_stride, src0, src1, src2, src3); - XORI_B4_128_SB(src0, src1, src2, src3); - src += (4 * src_stride); - - hz_out5 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); - hz_out6 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); - hz_out7 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); - hz_out8 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); - - res0 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out0, hz_out1, hz_out2, - hz_out3, hz_out4, hz_out5); - res1 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out1, hz_out2, hz_out3, - hz_out4, hz_out5, hz_out6); - res2 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out2, hz_out3, hz_out4, - hz_out5, hz_out6, hz_out7); - res3 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out3, hz_out4, hz_out5, - hz_out6, hz_out7, hz_out8); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - ILVR_D2_UB(dst1, dst0, dst3, dst2, dst0, dst1); - CONVERT_UB_AVG_ST8x4_UB(res0, res1, res2, res3, dst0, dst1, - dst, dst_stride); - - dst += (4 * dst_stride); - hz_out3 = hz_out7; - hz_out1 = hz_out5; - hz_out5 = hz_out4; - hz_out4 = hz_out8; - hz_out2 = hz_out6; - hz_out0 = hz_out5; + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src0, src1, src2, src3, src4, src5, + vt_res0, vt_res1); + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src7, src8, src9, src10, src11, src6, + vt_res2, vt_res3); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask3, + mask4, mask5, shf_vec6, shf_vec7, shf_vec8); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask3, + mask4, mask5, shf_vec9, shf_vec10, shf_vec11); + hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); + hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + hz_res2 = __msa_hadd_s_w(shf_vec6, shf_vec6); + hz_res3 = __msa_hadd_s_w(shf_vec9, shf_vec9); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); + DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + DPADD_SH2_SW(shf_vec7, shf_vec8, minus5h, plus20h, hz_res2, hz_res2); + DPADD_SH2_SW(shf_vec10, shf_vec11, minus5h, plus20h, hz_res3, hz_res3); + SRARI_W4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 10); + SAT_SW4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 7); + dst0 = __msa_srari_h(shf_vec2, 5); + dst1 = __msa_srari_h(shf_vec5, 5); + dst2 = __msa_srari_h(shf_vec8, 5); + dst3 = __msa_srari_h(shf_vec11, 5); + SAT_SH4_SH(dst0, dst1, dst2, dst3, 7); + dst0 = __msa_pckod_h(dst2, dst0); + dst1 = __msa_pckod_h(dst3, dst1); + PCKEV_H2_SH(hz_res2, hz_res0, hz_res3, hz_res1, dst2, dst3); + dst0 = __msa_aver_s_h(dst2, dst0); + dst1 = __msa_aver_s_h(dst3, dst1); + out = PCKEV_XORI128_UB(dst0, dst1); + ST_UB(out, dst); + dst += stride; + + src0 = src1; + src1 = src2; + src2 = src3; + src3 = src4; + src4 = src5; + src7 = src8; + src8 = src9; + src9 = src10; + src10 = src11; + src11 = src6; } } -static void avc_luma_mid_and_aver_dst_16x16_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride) -{ - avc_luma_mid_and_aver_dst_8w_msa(src, src_stride, dst, dst_stride, 16); - avc_luma_mid_and_aver_dst_8w_msa(src + 8, src_stride, dst + 8, dst_stride, - 16); -} - -static void avc_luma_midh_qrt_and_aver_dst_4w_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - int32_t height, - uint8_t horiz_offset) +void ff_put_h264_qpel8_mc12_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) { uint32_t row; + v16u8 out; v16i8 src0, src1, src2, src3, src4, src5, src6; - v16u8 dst0, dst1, res; - v8i16 vt_res0, vt_res1, vt_res2, vt_res3; - v4i32 hz_res0, hz_res1; - v8i16 res0, res1; - v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, dst0, dst1, dst2, dst3; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v8i16 shf_vec7, shf_vec8, shf_vec9, shf_vec10, shf_vec11; + v8i16 mask3, mask4, mask5; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; v8i16 minus5h = __msa_ldi_h(-5); v8i16 plus20h = __msa_ldi_h(20); - v8i16 zeros = { 0 }; - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); + mask3 = mask0 + 4; + mask4 = mask1 + 4; + mask5 = mask2 + 4; - XORI_B5_128_SB(src0, src1, src2, src3, src4); + src -= ((2 * stride) + 2); - for (row = (height >> 1); row--;) { - LD_SB2(src, src_stride, src5, src6); - src += (2 * src_stride); + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + for (row = 4; row--;) { + LD_SB2(src, stride, src5, src6); + src += (2 * stride); XORI_B2_128_SB(src5, src6); - LD_UB2(dst, dst_stride, dst0, dst1); - - dst0 = (v16u8) __msa_ilvr_w((v4i32) dst1, (v4i32) dst0); AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src0, src1, src2, src3, src4, src5, vt_res0, vt_res1); AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src1, src2, src3, src4, src5, src6, vt_res2, vt_res3); - VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, - mask0, mask1, mask2, shf_vec0, shf_vec1, shf_vec2); - VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, - mask0, mask1, mask2, shf_vec3, shf_vec4, shf_vec5); - + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask3, + mask4, mask5, shf_vec6, shf_vec7, shf_vec8); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask3, + mask4, mask5, shf_vec9, shf_vec10, shf_vec11); hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); - DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); - hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + hz_res2 = __msa_hadd_s_w(shf_vec6, shf_vec6); + hz_res3 = __msa_hadd_s_w(shf_vec9, shf_vec9); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); - - SRARI_W2_SW(hz_res0, hz_res1, 10); - SAT_SW2_SW(hz_res0, hz_res1, 7); - - res0 = __msa_srari_h(shf_vec2, 5); - res1 = __msa_srari_h(shf_vec5, 5); - - SAT_SH2_SH(res0, res1, 7); - - if (horiz_offset) { - res0 = __msa_ilvod_h(zeros, res0); - res1 = __msa_ilvod_h(zeros, res1); - } else { - ILVEV_H2_SH(res0, zeros, res1, zeros, res0, res1); - } - hz_res0 = __msa_aver_s_w(hz_res0, (v4i32) res0); - hz_res1 = __msa_aver_s_w(hz_res1, (v4i32) res1); - res0 = __msa_pckev_h((v8i16) hz_res1, (v8i16) hz_res0); - - res = PCKEV_XORI128_UB(res0, res0); - - dst0 = __msa_aver_u_b(res, dst0); - - ST4x2_UB(dst0, dst, dst_stride); - dst += (2 * dst_stride); + DPADD_SH2_SW(shf_vec7, shf_vec8, minus5h, plus20h, hz_res2, hz_res2); + DPADD_SH2_SW(shf_vec10, shf_vec11, minus5h, plus20h, hz_res3, hz_res3); + SRARI_W4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 10); + SAT_SW4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 7); + dst0 = __msa_srari_h(shf_vec2, 5); + dst1 = __msa_srari_h(shf_vec5, 5); + dst2 = __msa_srari_h(shf_vec8, 5); + dst3 = __msa_srari_h(shf_vec11, 5); + SAT_SH4_SH(dst0, dst1, dst2, dst3, 7); + PCKEV_H2_SH(dst2, dst0, dst3, dst1, dst0, dst1); + PCKEV_H2_SH(hz_res2, hz_res0, hz_res3, hz_res1, dst2, dst3); + dst0 = __msa_aver_s_h(dst2, dst0); + dst1 = __msa_aver_s_h(dst3, dst1); + out = PCKEV_XORI128_UB(dst0, dst1); + ST8x2_UB(out, dst, stride); + dst += (2 * stride); src0 = src2; src1 = src3; @@ -1505,495 +2612,544 @@ static void avc_luma_midh_qrt_and_aver_dst_4w_msa(const uint8_t *src, } } -static void avc_luma_midh_qrt_and_aver_dst_8w_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - int32_t height, - uint8_t horiz_offset) -{ - uint32_t multiple8_cnt; - - for (multiple8_cnt = 2; multiple8_cnt--;) { - avc_luma_midh_qrt_and_aver_dst_4w_msa(src, src_stride, dst, dst_stride, - height, horiz_offset); - - src += 4; - dst += 4; - } -} - -static void avc_luma_midh_qrt_and_aver_dst_16w_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - int32_t height, - uint8_t horiz_offset) +void ff_put_h264_qpel8_mc32_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) { - uint32_t multiple8_cnt; - - for (multiple8_cnt = 4; multiple8_cnt--;) { - avc_luma_midh_qrt_and_aver_dst_4w_msa(src, src_stride, dst, dst_stride, - height, horiz_offset); - - src += 4; - dst += 4; - } -} + uint32_t row; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, dst0, dst1, dst2, dst3; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v8i16 shf_vec7, shf_vec8, shf_vec9, shf_vec10, shf_vec11; + v8i16 mask3, mask4, mask5; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; + v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; + v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; + v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; + v8i16 minus5h = __msa_ldi_h(-5); + v8i16 plus20h = __msa_ldi_h(20); -static void avc_luma_midv_qrt_and_aver_dst_4w_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - int32_t height, - uint8_t ver_offset) -{ - int32_t loop_cnt; - int32_t out0, out1; - v16i8 src0, src1, src2, src3, src4; - v16u8 dst0, dst1; - v16i8 mask0, mask1, mask2; - v8i16 hz_out0, hz_out1, hz_out2, hz_out3; - v8i16 hz_out4, hz_out5, hz_out6; - v8i16 res0, res1, res2, res3; - v16u8 vec0, vec1; + mask3 = mask0 + 4; + mask4 = mask1 + 4; + mask5 = mask2 + 4; - LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - src += (5 * src_stride); + src -= ((2 * stride) + 2); + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); XORI_B5_128_SB(src0, src1, src2, src3, src4); - hz_out0 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src0, src1, - mask0, mask1, mask2); - hz_out2 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src2, src3, - mask0, mask1, mask2); - - PCKOD_D2_SH(hz_out0, hz_out0, hz_out2, hz_out2, hz_out1, hz_out3); - - hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); - - for (loop_cnt = (height >> 1); loop_cnt--;) { - LD_SB2(src, src_stride, src0, src1); - src += (2 * src_stride); - - XORI_B2_128_SB(src0, src1); - LD_UB2(dst, dst_stride, dst0, dst1); - hz_out5 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src0, src1, - mask0, mask1, - mask2); - hz_out6 = (v8i16) __msa_pckod_d((v2i64) hz_out5, (v2i64) hz_out5); - res0 = AVC_CALC_DPADD_H_6PIX_2COEFF_R_SH(hz_out0, hz_out1, hz_out2, - hz_out3, hz_out4, hz_out5); - res2 = AVC_CALC_DPADD_H_6PIX_2COEFF_R_SH(hz_out1, hz_out2, hz_out3, - hz_out4, hz_out5, hz_out6); - - if (ver_offset) { - res1 = __msa_srari_h(hz_out3, 5); - res3 = __msa_srari_h(hz_out4, 5); - } else { - res1 = __msa_srari_h(hz_out2, 5); - res3 = __msa_srari_h(hz_out3, 5); - } - - SAT_SH2_SH(res1, res3, 7); - - res0 = __msa_aver_s_h(res0, res1); - res1 = __msa_aver_s_h(res2, res3); - - vec0 = PCKEV_XORI128_UB(res0, res0); - vec1 = PCKEV_XORI128_UB(res1, res1); + for (row = 4; row--;) { + LD_SB2(src, stride, src5, src6); + src += (2 * stride); + XORI_B2_128_SB(src5, src6); - AVER_UB2_UB(vec0, dst0, vec1, dst1, dst0, dst1); + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src0, src1, src2, src3, src4, src5, + vt_res0, vt_res1); + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src1, src2, src3, src4, src5, src6, + vt_res2, vt_res3); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask3, + mask4, mask5, shf_vec6, shf_vec7, shf_vec8); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask3, + mask4, mask5, shf_vec9, shf_vec10, shf_vec11); + hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); + hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + hz_res2 = __msa_hadd_s_w(shf_vec6, shf_vec6); + hz_res3 = __msa_hadd_s_w(shf_vec9, shf_vec9); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); + DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + DPADD_SH2_SW(shf_vec7, shf_vec8, minus5h, plus20h, hz_res2, hz_res2); + DPADD_SH2_SW(shf_vec10, shf_vec11, minus5h, plus20h, hz_res3, hz_res3); + SRARI_W4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 10); + SAT_SW4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 7); + dst0 = __msa_srari_h(shf_vec2, 5); + dst1 = __msa_srari_h(shf_vec5, 5); + dst2 = __msa_srari_h(shf_vec8, 5); + dst3 = __msa_srari_h(shf_vec11, 5); + SAT_SH4_SH(dst0, dst1, dst2, dst3, 7); + dst0 = __msa_pckod_h(dst2, dst0); + dst1 = __msa_pckod_h(dst3, dst1); + PCKEV_H2_SH(hz_res2, hz_res0, hz_res3, hz_res1, dst2, dst3); + dst0 = __msa_aver_s_h(dst2, dst0); + dst1 = __msa_aver_s_h(dst3, dst1); + out = PCKEV_XORI128_UB(dst0, dst1); + ST8x2_UB(out, dst, stride); + dst += (2 * stride); - out0 = __msa_copy_u_w((v4i32) dst0, 0); - out1 = __msa_copy_u_w((v4i32) dst1, 0); - SW(out0, dst); - dst += dst_stride; - SW(out1, dst); - dst += dst_stride; - - hz_out0 = hz_out2; - hz_out1 = hz_out3; - hz_out2 = hz_out4; - hz_out3 = hz_out5; - hz_out4 = hz_out6; + src0 = src2; + src1 = src3; + src2 = src4; + src3 = src5; + src4 = src6; } } -static void avc_luma_midv_qrt_and_aver_dst_8w_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - int32_t height, - uint8_t vert_offset) +void ff_put_h264_qpel4_mc12_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) { - int32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4; - v16u8 dst0, dst1, dst2, dst3; - v16i8 mask0, mask1, mask2; - v8i16 hz_out0, hz_out1, hz_out2, hz_out3; - v8i16 hz_out4, hz_out5, hz_out6, hz_out7, hz_out8; - v8i16 res0, res1, res2, res3; - v8i16 res4, res5, res6, res7; - - LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); - - LD_SB5(src, src_stride, src0, src1, src2, src3, src4); - XORI_B5_128_SB(src0, src1, src2, src3, src4); - src += (5 * src_stride); - - hz_out0 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); - hz_out1 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); - hz_out2 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); - hz_out3 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); - hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); - - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src, src_stride, src0, src1, src2, src3); - XORI_B4_128_SB(src0, src1, src2, src3); - src += (4 * src_stride); - - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - - hz_out5 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); - hz_out6 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); - hz_out7 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); - hz_out8 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); - - res0 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out0, hz_out1, hz_out2, - hz_out3, hz_out4, hz_out5); - res2 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out1, hz_out2, hz_out3, - hz_out4, hz_out5, hz_out6); - res4 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out2, hz_out3, hz_out4, - hz_out5, hz_out6, hz_out7); - res6 = AVC_CALC_DPADD_H_6PIX_2COEFF_SH(hz_out3, hz_out4, hz_out5, - hz_out6, hz_out7, hz_out8); - - if (vert_offset) { - res1 = __msa_srari_h(hz_out3, 5); - res3 = __msa_srari_h(hz_out4, 5); - res5 = __msa_srari_h(hz_out5, 5); - res7 = __msa_srari_h(hz_out6, 5); - } else { - res1 = __msa_srari_h(hz_out2, 5); - res3 = __msa_srari_h(hz_out3, 5); - res5 = __msa_srari_h(hz_out4, 5); - res7 = __msa_srari_h(hz_out5, 5); - } + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 src10_r, src21_r, src32_r, src43_r, src54_r, src65_r, src76_r; + v16i8 src87_r, src10_l, src21_l, src32_l, src43_l, src54_l, src65_l; + v16i8 src76_l, src87_l, filt0, filt1, filt2; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, dst0, dst1, dst2, dst3, shf_vec7; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; + v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; + v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; + v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; + v8i16 minus5h = __msa_ldi_h(-5); + v8i16 plus20h = __msa_ldi_h(20); + v8i16 zeros = { 0 }; - SAT_SH4_SH(res1, res3, res5, res7, 7); - - res0 = __msa_aver_s_h(res0, res1); - res1 = __msa_aver_s_h(res2, res3); - res2 = __msa_aver_s_h(res4, res5); - res3 = __msa_aver_s_h(res6, res7); - ILVR_D2_UB(dst1, dst0, dst3, dst2, dst0, dst1); - CONVERT_UB_AVG_ST8x4_UB(res0, res1, res2, res3, dst0, dst1, - dst, dst_stride); - dst += (4 * dst_stride); - - hz_out0 = hz_out4; - hz_out1 = hz_out5; - hz_out2 = hz_out6; - hz_out3 = hz_out7; - hz_out4 = hz_out8; - } -} + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); -static void avc_luma_midv_qrt_and_aver_dst_16w_msa(const uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - int32_t height, - uint8_t vert_offset) -{ - int32_t multiple8_cnt; + src -= ((2 * stride) + 2); - for (multiple8_cnt = 2; multiple8_cnt--;) { - avc_luma_midv_qrt_and_aver_dst_8w_msa(src, src_stride, dst, dst_stride, - height, vert_offset); + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + LD_SB4(src, stride, src5, src6, src7, src8); + XORI_B4_128_SB(src5, src6, src7, src8); - src += 8; - dst += 8; - } + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, src65_r, + src76_r, src87_r); + ILVL_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_l, src21_l, + src32_l, src43_l); + ILVL_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_l, src65_l, + src76_l, src87_l); + vt_res0 = AVC_DOT_SH3_SH(src10_r, src32_r, src54_r, filt0, filt1, filt2); + vt_res1 = AVC_DOT_SH3_SH(src10_l, src32_l, src54_l, filt0, filt1, filt2); + vt_res2 = AVC_DOT_SH3_SH(src21_r, src43_r, src65_r, filt0, filt1, filt2); + vt_res3 = AVC_DOT_SH3_SH(src21_l, src43_l, src65_l, filt0, filt1, filt2); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); + hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + + vt_res0 = AVC_DOT_SH3_SH(src32_r, src54_r, src76_r, filt0, filt1, filt2); + vt_res1 = AVC_DOT_SH3_SH(src32_l, src54_l, src76_l, filt0, filt1, filt2); + vt_res2 = AVC_DOT_SH3_SH(src43_r, src65_r, src87_r, filt0, filt1, filt2); + vt_res3 = AVC_DOT_SH3_SH(src43_l, src65_l, src87_l, filt0, filt1, filt2); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec6); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec7); + hz_res2 = __msa_hadd_s_w(shf_vec0, shf_vec0); + DPADD_SH2_SW(shf_vec1, shf_vec6, minus5h, plus20h, hz_res2, hz_res2); + hz_res3 = __msa_hadd_s_w(shf_vec3, shf_vec3); + DPADD_SH2_SW(shf_vec4, shf_vec7, minus5h, plus20h, hz_res3, hz_res3); + + SRARI_W2_SW(hz_res0, hz_res1, 10); + SAT_SW2_SW(hz_res0, hz_res1, 7); + SRARI_W2_SW(hz_res2, hz_res3, 10); + SAT_SW2_SW(hz_res2, hz_res3, 7); + + dst0 = __msa_srari_h(shf_vec2, 5); + dst1 = __msa_srari_h(shf_vec5, 5); + dst2 = __msa_srari_h(shf_vec6, 5); + dst3 = __msa_srari_h(shf_vec7, 5); + + SAT_SH2_SH(dst0, dst1, 7); + SAT_SH2_SH(dst2, dst3, 7); + ILVEV_H2_SH(dst0, zeros, dst1, zeros, dst0, dst1); + ILVEV_H2_SH(dst2, zeros, dst3, zeros, dst2, dst3); + + hz_res0 = __msa_aver_s_w(hz_res0, (v4i32) dst0); + hz_res1 = __msa_aver_s_w(hz_res1, (v4i32) dst1); + hz_res2 = __msa_aver_s_w(hz_res2, (v4i32) dst2); + hz_res3 = __msa_aver_s_w(hz_res3, (v4i32) dst3); + + PCKEV_H2_SH(hz_res1, hz_res0, hz_res3, hz_res2, dst0, dst2); + out = PCKEV_XORI128_UB(dst0, dst2); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); } -static void avc_luma_hv_qrt_and_aver_dst_4x4_msa(const uint8_t *src_x, - const uint8_t *src_y, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride) +void ff_put_h264_qpel4_mc32_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) { - v16i8 src_hz0, src_hz1, src_hz2, src_hz3; - v16u8 dst0, dst1, dst2, dst3; - v16i8 src_vt0, src_vt1, src_vt2, src_vt3, src_vt4; - v16i8 src_vt5, src_vt6, src_vt7, src_vt8; - v16i8 mask0, mask1, mask2; - v8i16 hz_out0, hz_out1, vert_out0, vert_out1; - v8i16 res0, res1; - v16u8 res; - - LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); - LD_SB5(src_y, src_stride, src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); - src_y += (5 * src_stride); - - src_vt0 = (v16i8) __msa_insve_w((v4i32) src_vt0, 1, (v4i32) src_vt1); - src_vt1 = (v16i8) __msa_insve_w((v4i32) src_vt1, 1, (v4i32) src_vt2); - src_vt2 = (v16i8) __msa_insve_w((v4i32) src_vt2, 1, (v4i32) src_vt3); - src_vt3 = (v16i8) __msa_insve_w((v4i32) src_vt3, 1, (v4i32) src_vt4); - - XORI_B4_128_SB(src_vt0, src_vt1, src_vt2, src_vt3); - LD_SB4(src_x, src_stride, src_hz0, src_hz1, src_hz2, src_hz3); - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - XORI_B4_128_SB(src_hz0, src_hz1, src_hz2, src_hz3); - hz_out0 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src_hz0, src_hz1, - mask0, mask1, mask2); - hz_out1 = AVC_XOR_VSHF_B_AND_APPLY_6TAP_HORIZ_FILT_SH(src_hz2, src_hz3, - mask0, mask1, mask2); - SRARI_H2_SH(hz_out0, hz_out1, 5); - SAT_SH2_SH(hz_out0, hz_out1, 7); - LD_SB4(src_y, src_stride, src_vt5, src_vt6, src_vt7, src_vt8); - - src_vt4 = (v16i8) __msa_insve_w((v4i32) src_vt4, 1, (v4i32) src_vt5); - src_vt5 = (v16i8) __msa_insve_w((v4i32) src_vt5, 1, (v4i32) src_vt6); - src_vt6 = (v16i8) __msa_insve_w((v4i32) src_vt6, 1, (v4i32) src_vt7); - src_vt7 = (v16i8) __msa_insve_w((v4i32) src_vt7, 1, (v4i32) src_vt8); - - XORI_B4_128_SB(src_vt4, src_vt5, src_vt6, src_vt7); - - /* filter calc */ - vert_out0 = AVC_CALC_DPADD_B_6PIX_2COEFF_R_SH(src_vt0, src_vt1, src_vt2, - src_vt3, src_vt4, src_vt5); - vert_out1 = AVC_CALC_DPADD_B_6PIX_2COEFF_R_SH(src_vt2, src_vt3, src_vt4, - src_vt5, src_vt6, src_vt7); - SRARI_H2_SH(vert_out0, vert_out1, 5); - SAT_SH2_SH(vert_out0, vert_out1, 7); + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 src10_r, src21_r, src32_r, src43_r, src54_r, src65_r, src76_r; + v16i8 src87_r, src10_l, src21_l, src32_l, src43_l, src54_l, src65_l; + v16i8 src76_l, src87_l, filt0, filt1, filt2; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, dst0, dst1, dst2, dst3, shf_vec7; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; + v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; + v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; + v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; + v8i16 minus5h = __msa_ldi_h(-5); + v8i16 plus20h = __msa_ldi_h(20); + v8i16 zeros = { 0 }; - res1 = __msa_srari_h((hz_out1 + vert_out1), 1); - res0 = __msa_srari_h((hz_out0 + vert_out0), 1); + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); - SAT_SH2_SH(res0, res1, 7); - res = PCKEV_XORI128_UB(res0, res1); + src -= ((2 * stride) + 2); - dst0 = (v16u8) __msa_insve_w((v4i32) dst0, 1, (v4i32) dst1); - dst1 = (v16u8) __msa_insve_w((v4i32) dst2, 1, (v4i32) dst3); - dst0 = (v16u8) __msa_insve_d((v2i64) dst0, 1, (v2i64) dst1); - dst0 = __msa_aver_u_b(res, dst0); + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + LD_SB4(src, stride, src5, src6, src7, src8); + XORI_B4_128_SB(src5, src6, src7, src8); - ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, dst_stride); + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, src65_r, + src76_r, src87_r); + ILVL_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_l, src21_l, + src32_l, src43_l); + ILVL_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_l, src65_l, + src76_l, src87_l); + + vt_res0 = AVC_DOT_SH3_SH(src10_r, src32_r, src54_r, filt0, filt1, filt2); + vt_res1 = AVC_DOT_SH3_SH(src10_l, src32_l, src54_l, filt0, filt1, filt2); + vt_res2 = AVC_DOT_SH3_SH(src21_r, src43_r, src65_r, filt0, filt1, filt2); + vt_res3 = AVC_DOT_SH3_SH(src21_l, src43_l, src65_l, filt0, filt1, filt2); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); + hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + + vt_res0 = AVC_DOT_SH3_SH(src32_r, src54_r, src76_r, filt0, filt1, filt2); + vt_res1 = AVC_DOT_SH3_SH(src32_l, src54_l, src76_l, filt0, filt1, filt2); + vt_res2 = AVC_DOT_SH3_SH(src43_r, src65_r, src87_r, filt0, filt1, filt2); + vt_res3 = AVC_DOT_SH3_SH(src43_l, src65_l, src87_l, filt0, filt1, filt2); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec6); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec7); + hz_res2 = __msa_hadd_s_w(shf_vec0, shf_vec0); + DPADD_SH2_SW(shf_vec1, shf_vec6, minus5h, plus20h, hz_res2, hz_res2); + hz_res3 = __msa_hadd_s_w(shf_vec3, shf_vec3); + DPADD_SH2_SW(shf_vec4, shf_vec7, minus5h, plus20h, hz_res3, hz_res3); + + SRARI_W2_SW(hz_res0, hz_res1, 10); + SAT_SW2_SW(hz_res0, hz_res1, 7); + SRARI_W2_SW(hz_res2, hz_res3, 10); + SAT_SW2_SW(hz_res2, hz_res3, 7); + + dst0 = __msa_srari_h(shf_vec2, 5); + dst1 = __msa_srari_h(shf_vec5, 5); + dst2 = __msa_srari_h(shf_vec6, 5); + dst3 = __msa_srari_h(shf_vec7, 5); + + SAT_SH2_SH(dst0, dst1, 7); + SAT_SH2_SH(dst2, dst3, 7); + + dst0 = __msa_ilvod_h(zeros, dst0); + dst1 = __msa_ilvod_h(zeros, dst1); + dst2 = __msa_ilvod_h(zeros, dst2); + dst3 = __msa_ilvod_h(zeros, dst3); + + hz_res0 = __msa_aver_s_w(hz_res0, (v4i32) dst0); + hz_res1 = __msa_aver_s_w(hz_res1, (v4i32) dst1); + hz_res2 = __msa_aver_s_w(hz_res2, (v4i32) dst2); + hz_res3 = __msa_aver_s_w(hz_res3, (v4i32) dst3); + + PCKEV_H2_SH(hz_res1, hz_res0, hz_res3, hz_res2, dst0, dst2); + out = PCKEV_XORI128_UB(dst0, dst2); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); } -static void avc_luma_hv_qrt_and_aver_dst_8x8_msa(const uint8_t *src_x, - const uint8_t *src_y, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride) +void ff_put_h264_qpel16_mc22_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) { - uint32_t loop_cnt; - v16i8 src_hz0, src_hz1, src_hz2, src_hz3; - v16u8 dst0, dst1, dst2, dst3; - v16i8 src_vt0, src_vt1, src_vt2, src_vt3; - v16i8 src_vt4, src_vt5, src_vt6, src_vt7, src_vt8; - v16i8 mask0, mask1, mask2; - v8i16 hz_out0, hz_out1, hz_out2, hz_out3; - v8i16 vert_out0, vert_out1, vert_out2, vert_out3; - v8i16 out0, out1, out2, out3; + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; + const uint8_t *src_tmp = src - (2 * stride) - 2; + uint8_t *dst_tmp = dst; + uint32_t multiple8_cnt, loop_cnt; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, mask0, mask1, mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, dst0, dst1, dst2, dst3; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r, hz_out10_l, hz_out21_l; + v8i16 hz_out32_l, hz_out43_l, hz_out54_l, hz_out65_l, hz_out76_l; + v8i16 hz_out87_l, filt0, filt1, filt2; + v4i32 tmp0, tmp1; + + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); - LD_SB5(src_y, src_stride, src_vt0, src_vt1, src_vt2, src_vt3, src_vt4); - src_y += (5 * src_stride); + for (multiple8_cnt = 2; multiple8_cnt--;) { + src = src_tmp; + dst = dst_tmp; - src_vt0 = (v16i8) __msa_insve_d((v2i64) src_vt0, 1, (v2i64) src_vt1); - src_vt1 = (v16i8) __msa_insve_d((v2i64) src_vt1, 1, (v2i64) src_vt2); - src_vt2 = (v16i8) __msa_insve_d((v2i64) src_vt2, 1, (v2i64) src_vt3); - src_vt3 = (v16i8) __msa_insve_d((v2i64) src_vt3, 1, (v2i64) src_vt4); + LD_SB5(src, stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + src += (5 * stride); - XORI_B4_128_SB(src_vt0, src_vt1, src_vt2, src_vt3); + hz_out0 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); - for (loop_cnt = 2; loop_cnt--;) { - LD_SB4(src_x, src_stride, src_hz0, src_hz1, src_hz2, src_hz3); - XORI_B4_128_SB(src_hz0, src_hz1, src_hz2, src_hz3); - src_x += (4 * src_stride); - - LD_UB4(dst, dst_stride, dst0, dst1, dst2, dst3); - hz_out0 = AVC_HORZ_FILTER_SH(src_hz0, src_hz0, mask0, mask1, mask2); - hz_out1 = AVC_HORZ_FILTER_SH(src_hz1, src_hz1, mask0, mask1, mask2); - hz_out2 = AVC_HORZ_FILTER_SH(src_hz2, src_hz2, mask0, mask1, mask2); - hz_out3 = AVC_HORZ_FILTER_SH(src_hz3, src_hz3, mask0, mask1, mask2); - SRARI_H4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 5); - SAT_SH4_SH(hz_out0, hz_out1, hz_out2, hz_out3, 7); - LD_SB4(src_y, src_stride, src_vt5, src_vt6, src_vt7, src_vt8); - src_y += (4 * src_stride); - - src_vt4 = (v16i8) __msa_insve_d((v2i64) src_vt4, 1, (v2i64) src_vt5); - src_vt5 = (v16i8) __msa_insve_d((v2i64) src_vt5, 1, (v2i64) src_vt6); - src_vt6 = (v16i8) __msa_insve_d((v2i64) src_vt6, 1, (v2i64) src_vt7); - src_vt7 = (v16i8) __msa_insve_d((v2i64) src_vt7, 1, (v2i64) src_vt8); - - XORI_B4_128_SB(src_vt4, src_vt5, src_vt6, src_vt7); - AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src_vt0, src_vt1, src_vt2, src_vt3, - src_vt4, src_vt5, vert_out0, vert_out1); - AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src_vt2, src_vt3, src_vt4, src_vt5, - src_vt6, src_vt7, vert_out2, vert_out3); - SRARI_H4_SH(vert_out0, vert_out1, vert_out2, vert_out3, 5); - SAT_SH4_SH(vert_out0, vert_out1, vert_out2, vert_out3, 7); - - out0 = __msa_srari_h((hz_out0 + vert_out0), 1); - out1 = __msa_srari_h((hz_out1 + vert_out1), 1); - out2 = __msa_srari_h((hz_out2 + vert_out2), 1); - out3 = __msa_srari_h((hz_out3 + vert_out3), 1); - - SAT_SH4_SH(out0, out1, out2, out3, 7); - ILVR_D2_UB(dst1, dst0, dst3, dst2, dst0, dst1); - CONVERT_UB_AVG_ST8x4_UB(out0, out1, out2, out3, dst0, dst1, - dst, dst_stride); - dst += (4 * dst_stride); - - src_vt0 = src_vt4; - src_vt1 = src_vt5; - src_vt2 = src_vt6; - src_vt3 = src_vt7; - src_vt4 = src_vt8; - } -} + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src, stride, src0, src1, src2, src3); + XORI_B4_128_SB(src0, src1, src2, src3); + src += (4 * stride); -static void avc_luma_hv_qrt_and_aver_dst_16x16_msa(const uint8_t *src_x, - const uint8_t *src_y, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride) -{ - uint32_t multiple8_cnt; + hz_out5 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out7 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); - for (multiple8_cnt = 2; multiple8_cnt--;) { - avc_luma_hv_qrt_and_aver_dst_8x8_msa(src_x, src_y, src_stride, - dst, dst_stride); + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, + hz_out4, hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, + hz_out43_r); + ILVL_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, + hz_out4, hz_out3, hz_out10_l, hz_out21_l, hz_out32_l, + hz_out43_l); + ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, + hz_out8, hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, + hz_out87_r); + ILVL_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, + hz_out8, hz_out7, hz_out54_l, hz_out65_l, hz_out76_l, + hz_out87_l); - src_x += 8; - src_y += 8; - dst += 8; - } + tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, + filt1, filt2); + dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, + filt1, filt2); + dst1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, + filt1, filt2); + dst2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, + filt1, filt2); + dst3 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); - src_x += (8 * src_stride) - 16; - src_y += (8 * src_stride) - 16; - dst += (8 * dst_stride) - 16; + out0 = PCKEV_XORI128_UB(dst0, dst1); + out1 = PCKEV_XORI128_UB(dst2, dst3); + ST8x4_UB(out0, out1, dst, stride); + dst += (4 * stride); - for (multiple8_cnt = 2; multiple8_cnt--;) { - avc_luma_hv_qrt_and_aver_dst_8x8_msa(src_x, src_y, src_stride, - dst, dst_stride); + hz_out0 = hz_out4; + hz_out1 = hz_out5; + hz_out2 = hz_out6; + hz_out3 = hz_out7; + hz_out4 = hz_out8; + } - src_x += 8; - src_y += 8; - dst += 8; + src_tmp += 8; + dst_tmp += 8; } } -void ff_put_h264_qpel16_mc00_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - v16u8 src0, src1, src2, src3, src4, src5, src6, src7; - v16u8 src8, src9, src10, src11, src12, src13, src14, src15; - - LD_UB8(src, stride, src0, src1, src2, src3, src4, src5, src6, src7); - src += (8 * stride); - LD_UB8(src, stride, src8, src9, src10, src11, src12, src13, src14, src15); - - ST_UB8(src0, src1, src2, src3, src4, src5, src6, src7, dst, stride); - dst += (8 * stride); - ST_UB8(src8, src9, src10, src11, src12, src13, src14, src15, dst, stride); -} - -void ff_put_h264_qpel8_mc00_msa(uint8_t *dst, const uint8_t *src, +void ff_put_h264_qpel8_mc22_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - uint64_t src0, src1, src2, src3, src4, src5, src6, src7; - - LD4(src, stride, src0, src1, src2, src3); - src += 4 * stride; - LD4(src, stride, src4, src5, src6, src7); - SD4(src0, src1, src2, src3, dst, stride); - dst += 4 * stride; - SD4(src4, src5, src6, src7, dst, stride); -} - -void ff_avg_h264_qpel16_mc00_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - v16u8 src0, src1, src2, src3, src4, src5, src6, src7; - v16u8 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; - - LD_UB8(src, stride, src0, src1, src2, src3, src4, src5, src6, src7); - src += (8 * stride); - LD_UB8(dst, stride, dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7); - - AVER_UB4_UB(src0, dst0, src1, dst1, src2, dst2, src3, dst3, dst0, dst1, - dst2, dst3); - AVER_UB4_UB(src4, dst4, src5, dst5, src6, dst6, src7, dst7, dst4, dst5, - dst6, dst7); - ST_UB8(dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst, stride); - dst += (8 * stride); + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, mask0, mask1, mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, hz_out9, hz_out10, hz_out11, hz_out12; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r, hz_out89_r, hz_out910_r; + v8i16 hz_out1110_r, hz_out1211_r, dst0, dst1, dst2, dst3; + v8i16 hz_out10_l, hz_out21_l, hz_out32_l, hz_out43_l, hz_out54_l; + v8i16 hz_out65_l, hz_out76_l, hz_out87_l, hz_out89_l, hz_out910_l; + v8i16 hz_out1110_l, hz_out1211_l, filt0, filt1, filt2; + v4i32 tmp0, tmp1; - LD_UB8(src, stride, src0, src1, src2, src3, src4, src5, src6, src7); - LD_UB8(dst, stride, dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7); + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); - AVER_UB4_UB(src0, dst0, src1, dst1, src2, dst2, src3, dst3, dst0, dst1, - dst2, dst3); - AVER_UB4_UB(src4, dst4, src5, dst5, src6, dst6, src7, dst7, dst4, dst5, - dst6, dst7); - ST_UB8(dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst, stride); -} + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); -void ff_avg_h264_qpel8_mc00_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - uint64_t tp0, tp1, tp2, tp3, tp4, tp5, tp6, tp7; - v16u8 src0 = { 0 }, src1 = { 0 }, src2 = { 0 }, src3 = { 0 }; - v16u8 dst0 = { 0 }, dst1 = { 0 }, dst2 = { 0 }, dst3 = { 0 }; + src -= ((2 * stride) + 2); + LD_SB5(src, stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + src += (5 * stride); - LD4(src, stride, tp0, tp1, tp2, tp3); - src += 4 * stride; - LD4(src, stride, tp4, tp5, tp6, tp7); - INSERT_D2_UB(tp0, tp1, src0); - INSERT_D2_UB(tp2, tp3, src1); - INSERT_D2_UB(tp4, tp5, src2); - INSERT_D2_UB(tp6, tp7, src3); + hz_out0 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); - LD4(dst, stride, tp0, tp1, tp2, tp3); - LD4(dst + 4 * stride, stride, tp4, tp5, tp6, tp7); - INSERT_D2_UB(tp0, tp1, dst0); - INSERT_D2_UB(tp2, tp3, dst1); - INSERT_D2_UB(tp4, tp5, dst2); - INSERT_D2_UB(tp6, tp7, dst3); + LD_SB4(src, stride, src0, src1, src2, src3); + XORI_B4_128_SB(src0, src1, src2, src3); + src += (4 * stride); + hz_out5 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out7 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r); + ILVL_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_l, hz_out21_l, hz_out32_l, hz_out43_l); + ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, hz_out87_r); + ILVL_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_l, hz_out65_l, hz_out76_l, hz_out87_l); - AVER_UB4_UB(src0, dst0, src1, dst1, src2, dst2, src3, dst3, dst0, dst1, - dst2, dst3); + tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, filt1, + filt2); + dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, filt1, + filt2); + dst1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, filt1, + filt2); + dst2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, filt1, + filt2); + dst3 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + out0 = PCKEV_XORI128_UB(dst0, dst1); + out1 = PCKEV_XORI128_UB(dst2, dst3); + ST8x4_UB(out0, out1, dst, stride); + dst += (4 * stride); - ST8x8_UB(dst0, dst1, dst2, dst3, dst, stride); + LD_SB4(src, stride, src0, src1, src2, src3); + XORI_B4_128_SB(src0, src1, src2, src3); + hz_out9 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out10 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out11 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out12 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + ILVR_H4_SH(hz_out9, hz_out8, hz_out10, hz_out9, hz_out11, hz_out10, + hz_out12, hz_out11, hz_out89_r, hz_out910_r, hz_out1110_r, + hz_out1211_r); + ILVL_H4_SH(hz_out9, hz_out8, hz_out10, hz_out9, hz_out11, hz_out10, + hz_out12, hz_out11, hz_out89_l, hz_out910_l, hz_out1110_l, + hz_out1211_l); + tmp0 = AVC_DOT_SW3_SW(hz_out54_r, hz_out76_r, hz_out89_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out54_l, hz_out76_l, hz_out89_l, filt0, filt1, + filt2); + dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out65_r, hz_out87_r, hz_out910_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out65_l, hz_out87_l, hz_out910_l, filt0, filt1, + filt2); + dst1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out76_r, hz_out89_r, hz_out1110_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out76_l, hz_out89_l, hz_out1110_l, filt0, filt1, + filt2); + dst2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out87_r, hz_out910_r, hz_out1211_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out87_l, hz_out910_l, hz_out1211_l, filt0, filt1, + filt2); + dst3 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + out0 = PCKEV_XORI128_UB(dst0, dst1); + out1 = PCKEV_XORI128_UB(dst2, dst3); + ST8x4_UB(out0, out1, dst, stride); } -void ff_avg_h264_qpel4_mc00_msa(uint8_t *dst, const uint8_t *src, +void ff_put_h264_qpel4_mc22_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - uint32_t tp0, tp1, tp2, tp3; - v16u8 src0 = { 0 }, dst0 = { 0 }; + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; + v16u8 res; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 mask0, mask1, mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, dst0, dst1, filt0, filt1, filt2; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r; + v4i32 tmp0, tmp1; - LW4(src, stride, tp0, tp1, tp2, tp3); - INSERT_W4_UB(tp0, tp1, tp2, tp3, src0); - LW4(dst, stride, tp0, tp1, tp2, tp3); - INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); - dst0 = __msa_aver_u_b(src0, dst0); + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); - ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); + src -= ((2 * stride) + 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + LD_SB4(src, stride, src5, src6, src7, src8); + + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B4_128_SB(src5, src6, src7, src8); + hz_out0 = AVC_HORZ_FILTER_SH(src0, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src5, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src6, src7, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src8, src8, mask0, mask1, mask2); + PCKOD_D2_SH(hz_out0, hz_out0, hz_out2, hz_out2, hz_out1, hz_out3); + PCKOD_D2_SH(hz_out4, hz_out4, hz_out6, hz_out6, hz_out5, hz_out7); + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r); + ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, hz_out87_r); + + tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, filt1, + filt2); + dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, filt1, + filt2); + dst1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + res = PCKEV_XORI128_UB(dst0, dst1); + ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); } -void ff_put_h264_qpel16_mc10_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel16_mc10_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { uint32_t loop_cnt; - v16i8 dst0, dst1, dst2, dst3, src0, src1, src2, src3, src4, src5, src6; + v16u8 dst0, dst1, dst2, dst3; + v16i8 out0, out1, out2, out3, src0, src1, src2, src3, src4, src5, src6; v16i8 mask0, mask1, mask2, mask3, mask4, mask5, src7, vec11; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; v8i16 res0, res1, res2, res3, res4, res5, res6, res7; @@ -2016,6 +3172,7 @@ void ff_put_h264_qpel16_mc10_msa(uint8_t *dst, const uint8_t *src, LD_SB2(src, 16, src6, src7); src += stride; + LD_UB4(dst, stride, dst0, dst1, dst2, dst3); XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); VSHF_B2_SB(src0, src0, src0, src1, mask0, mask3, vec0, vec3); VSHF_B2_SB(src2, src2, src2, src3, mask0, mask3, vec6, vec9); @@ -2045,23 +3202,26 @@ void ff_put_h264_qpel16_mc10_msa(uint8_t *dst, const uint8_t *src, SRARI_H4_SH(res4, res5, res6, res7, 5); SAT_SH4_SH(res0, res1, res2, res3, 7); SAT_SH4_SH(res4, res5, res6, res7, 7); - PCKEV_B2_SB(res1, res0, res3, res2, dst0, dst1); - PCKEV_B2_SB(res5, res4, res7, res6, dst2, dst3); - dst0 = __msa_aver_s_b(dst0, src0); - dst1 = __msa_aver_s_b(dst1, src2); - dst2 = __msa_aver_s_b(dst2, src4); - dst3 = __msa_aver_s_b(dst3, src6); - XORI_B4_128_SB(dst0, dst1, dst2, dst3); - ST_SB4(dst0, dst1, dst2, dst3, dst, stride); + PCKEV_B2_SB(res1, res0, res3, res2, out0, out1); + PCKEV_B2_SB(res5, res4, res7, res6, out2, out3); + out0 = __msa_aver_s_b(out0, src0); + out1 = __msa_aver_s_b(out1, src2); + out2 = __msa_aver_s_b(out2, src4); + out3 = __msa_aver_s_b(out3, src6); + XORI_B4_128_SB(out0, out1, out2, out3); + AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); + AVER_UB2_UB(out2, dst2, out3, dst3, dst2, dst3); + ST_UB4(dst0, dst1, dst2, dst3, dst, stride); dst += (4 * stride); } } -void ff_put_h264_qpel16_mc30_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel16_mc30_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { uint32_t loop_cnt; - v16i8 dst0, dst1, dst2, dst3, src0, src1, src2, src3, src4, src5, src6; + v16u8 dst0, dst1, dst2, dst3; + v16i8 out0, out1, out2, out3, src0, src1, src2, src3, src4, src5, src6; v16i8 mask0, mask1, mask2, mask3, mask4, mask5, src7, vec11; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; v8i16 res0, res1, res2, res3, res4, res5, res6, res7; @@ -2084,6 +3244,7 @@ void ff_put_h264_qpel16_mc30_msa(uint8_t *dst, const uint8_t *src, LD_SB2(src, 16, src6, src7); src += stride; + LD_UB4(dst, stride, dst0, dst1, dst2, dst3); XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); VSHF_B2_SB(src0, src0, src0, src1, mask0, mask3, vec0, vec3); VSHF_B2_SB(src2, src2, src2, src3, mask0, mask3, vec6, vec9); @@ -2113,21 +3274,25 @@ void ff_put_h264_qpel16_mc30_msa(uint8_t *dst, const uint8_t *src, SRARI_H4_SH(res4, res5, res6, res7, 5); SAT_SH4_SH(res0, res1, res2, res3, 7); SAT_SH4_SH(res4, res5, res6, res7, 7); - PCKEV_B2_SB(res1, res0, res3, res2, dst0, dst1); - PCKEV_B2_SB(res5, res4, res7, res6, dst2, dst3); - dst0 = __msa_aver_s_b(dst0, src0); - dst1 = __msa_aver_s_b(dst1, src2); - dst2 = __msa_aver_s_b(dst2, src4); - dst3 = __msa_aver_s_b(dst3, src6); - XORI_B4_128_SB(dst0, dst1, dst2, dst3); - ST_SB4(dst0, dst1, dst2, dst3, dst, stride); + PCKEV_B2_SB(res1, res0, res3, res2, out0, out1); + PCKEV_B2_SB(res5, res4, res7, res6, out2, out3); + out0 = __msa_aver_s_b(out0, src0); + out1 = __msa_aver_s_b(out1, src2); + out2 = __msa_aver_s_b(out2, src4); + out3 = __msa_aver_s_b(out3, src6); + XORI_B4_128_SB(out0, out1, out2, out3); + AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); + AVER_UB2_UB(out2, dst2, out3, dst3, dst2, dst3); + ST_UB4(dst0, dst1, dst2, dst3, dst, stride); dst += (4 * stride); } } -void ff_put_h264_qpel8_mc10_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel8_mc10_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { + uint64_t tp0, tp1, tp2, tp3; + v16u8 dst0 = { 0 }, dst1 = { 0 }, dst2 = { 0 }, dst3 = { 0 }; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, mask0, mask1, mask2; v16i8 tmp0, tmp1, tmp2, tmp3, vec11; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; @@ -2177,12 +3342,22 @@ void ff_put_h264_qpel8_mc10_msa(uint8_t *dst, const uint8_t *src, tmp2 = __msa_aver_s_b(tmp2, src4); tmp3 = __msa_aver_s_b(tmp3, src5); XORI_B4_128_SB(tmp0, tmp1, tmp2, tmp3); - ST8x8_UB(tmp0, tmp1, tmp2, tmp3, dst, stride); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + LD4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst2); + INSERT_D2_UB(tp2, tp3, dst3); + AVER_UB2_UB(tmp0, dst0, tmp1, dst1, dst0, dst1); + AVER_UB2_UB(tmp2, dst2, tmp3, dst3, dst2, dst3); + ST8x8_UB(dst0, dst1, dst2, dst3, dst, stride); } -void ff_put_h264_qpel8_mc30_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel8_mc30_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { + uint64_t tp0, tp1, tp2, tp3; + v16u8 dst0 = { 0 }, dst1 = { 0 }, dst2 = { 0 }, dst3 = { 0 }; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, mask0, mask1, mask2; v16i8 tmp0, tmp1, tmp2, tmp3, vec11; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; @@ -2232,15 +3407,25 @@ void ff_put_h264_qpel8_mc30_msa(uint8_t *dst, const uint8_t *src, tmp2 = __msa_aver_s_b(tmp2, src4); tmp3 = __msa_aver_s_b(tmp3, src5); XORI_B4_128_SB(tmp0, tmp1, tmp2, tmp3); - ST8x8_UB(tmp0, tmp1, tmp2, tmp3, dst, stride); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + LD4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst2); + INSERT_D2_UB(tp2, tp3, dst3); + AVER_UB2_UB(tmp0, dst0, tmp1, dst1, dst0, dst1); + AVER_UB2_UB(tmp2, dst2, tmp3, dst3, dst2, dst3); + ST8x8_UB(dst0, dst1, dst2, dst3, dst, stride); } -void ff_put_h264_qpel4_mc10_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel4_mc10_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - v16i8 src0, src1, src2, src3, res, mask0, mask1, mask2; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 res0, res1; + uint32_t tp0, tp1, tp2, tp3; + v16u8 dst0 = { 0 }; + v16i8 src0, src1, src2, src3, res, vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 mask0, mask1, mask2; + v8i16 out0, out1; v16i8 minus5b = __msa_ldi_b(-5); v16i8 plus20b = __msa_ldi_b(20); @@ -2248,14 +3433,14 @@ void ff_put_h264_qpel4_mc10_msa(uint8_t *dst, const uint8_t *src, LD_SB4(src - 2, stride, src0, src1, src2, src3); XORI_B4_128_SB(src0, src1, src2, src3); VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0, vec1); - HADD_SB2_SH(vec0, vec1, res0, res1); + HADD_SB2_SH(vec0, vec1, out0, out1); VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec2, vec3); - DPADD_SB2_SH(vec2, vec3, minus5b, minus5b, res0, res1); + DPADD_SB2_SH(vec2, vec3, minus5b, minus5b, out0, out1); VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec4, vec5); - DPADD_SB2_SH(vec4, vec5, plus20b, plus20b, res0, res1); - SRARI_H2_SH(res0, res1, 5); - SAT_SH2_SH(res0, res1, 7); - res = __msa_pckev_b((v16i8) res1, (v16i8) res0); + DPADD_SB2_SH(vec4, vec5, plus20b, plus20b, out0, out1); + SRARI_H2_SH(out0, out1, 5); + SAT_SH2_SH(out0, out1, 7); + res = __msa_pckev_b((v16i8) out1, (v16i8) out0); SLDI_B2_SB(src0, src1, src0, src1, src0, src1, 2); SLDI_B2_SB(src2, src3, src2, src3, src2, src3, 2); src0 = (v16i8) __msa_insve_w((v4i32) src0, 1, (v4i32) src1); @@ -2263,15 +3448,20 @@ void ff_put_h264_qpel4_mc10_msa(uint8_t *dst, const uint8_t *src, src0 = (v16i8) __msa_insve_d((v2i64) src0, 1, (v2i64) src1); res = __msa_aver_s_b(res, src0); res = (v16i8) __msa_xori_b((v16u8) res, 128); - ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + dst0 = __msa_aver_u_b((v16u8) res, dst0); + ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); } -void ff_put_h264_qpel4_mc30_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel4_mc30_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - v16i8 src0, src1, src2, src3, res, mask0, mask1, mask2; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 res0, res1; + uint32_t tp0, tp1, tp2, tp3; + v16u8 dst0 = { 0 }; + v16i8 src0, src1, src2, src3, res, vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 mask0, mask1, mask2; + v8i16 out0, out1; v16i8 minus5b = __msa_ldi_b(-5); v16i8 plus20b = __msa_ldi_b(20); @@ -2279,14 +3469,14 @@ void ff_put_h264_qpel4_mc30_msa(uint8_t *dst, const uint8_t *src, LD_SB4(src - 2, stride, src0, src1, src2, src3); XORI_B4_128_SB(src0, src1, src2, src3); VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0, vec1); - HADD_SB2_SH(vec0, vec1, res0, res1); + HADD_SB2_SH(vec0, vec1, out0, out1); VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec2, vec3); - DPADD_SB2_SH(vec2, vec3, minus5b, minus5b, res0, res1); + DPADD_SB2_SH(vec2, vec3, minus5b, minus5b, out0, out1); VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec4, vec5); - DPADD_SB2_SH(vec4, vec5, plus20b, plus20b, res0, res1); - SRARI_H2_SH(res0, res1, 5); - SAT_SH2_SH(res0, res1, 7); - res = __msa_pckev_b((v16i8) res1, (v16i8) res0); + DPADD_SB2_SH(vec4, vec5, plus20b, plus20b, out0, out1); + SRARI_H2_SH(out0, out1, 5); + SAT_SH2_SH(out0, out1, 7); + res = __msa_pckev_b((v16i8) out1, (v16i8) out0); SLDI_B2_SB(src0, src1, src0, src1, src0, src1, 3); SLDI_B2_SB(src2, src3, src2, src3, src2, src3, 3); src0 = (v16i8) __msa_insve_w((v4i32) src0, 1, (v4i32) src1); @@ -2294,13 +3484,17 @@ void ff_put_h264_qpel4_mc30_msa(uint8_t *dst, const uint8_t *src, src0 = (v16i8) __msa_insve_d((v2i64) src0, 1, (v2i64) src1); res = __msa_aver_s_b(res, src0); res = (v16i8) __msa_xori_b((v16u8) res, 128); - ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + dst0 = __msa_aver_u_b((v16u8) res, dst0); + ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); } -void ff_put_h264_qpel16_mc20_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel16_mc20_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { uint32_t loop_cnt; + v16u8 dst0, dst1, dst2, dst3; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, mask0, mask1, mask2; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; v16i8 vec11; @@ -2321,6 +3515,7 @@ void ff_put_h264_qpel16_mc20_msa(uint8_t *dst, const uint8_t *src, LD_SB2(src, 8, src6, src7); src += stride; + LD_UB4(dst, stride, dst0, dst1, dst2, dst3); XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec3); VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec6, vec9); @@ -2351,15 +3546,19 @@ void ff_put_h264_qpel16_mc20_msa(uint8_t *dst, const uint8_t *src, PCKEV_B4_SB(res1, res0, res3, res2, res5, res4, res7, res6, vec0, vec1, vec2, vec3); XORI_B4_128_SB(vec0, vec1, vec2, vec3); - ST_SB4(vec0, vec1, vec2, vec3, dst, stride); + AVER_UB2_UB(vec0, dst0, vec1, dst1, dst0, dst1); + AVER_UB2_UB(vec2, dst2, vec3, dst3, dst2, dst3); + ST_UB4(dst0, dst1, dst2, dst3, dst, stride); dst += (4 * stride); } } -void ff_put_h264_qpel8_mc20_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel8_mc20_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - v16u8 out0, out1, out2, out3; + uint64_t tp0, tp1, tp2, tp3; + v16u8 out0, out1, out2 = { 0 }, out3 = { 0 }; + v16u8 out4, out5, out6 = { 0 }, out7 = { 0 }; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, mask0, mask1, mask2; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; v16i8 vec11; @@ -2368,6 +3567,7 @@ void ff_put_h264_qpel8_mc20_msa(uint8_t *dst, const uint8_t *src, v16i8 plus20b = __msa_ldi_b(20); LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + LD_SB8(src - 2, stride, src0, src1, src2, src3, src4, src5, src6, src7); XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); @@ -2379,8 +3579,8 @@ void ff_put_h264_qpel8_mc20_msa(uint8_t *dst, const uint8_t *src, res0, res1, res2, res3); VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec8, vec9); VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec10, vec11); - DPADD_SB4_SH(vec8, vec9, vec10, vec11, plus20b, plus20b, plus20b, - plus20b, res0, res1, res2, res3); + DPADD_SB4_SH(vec8, vec9, vec10, vec11, plus20b, plus20b, plus20b, plus20b, + res0, res1, res2, res3); VSHF_B2_SB(src4, src4, src5, src5, mask0, mask0, vec0, vec1); VSHF_B2_SB(src6, src6, src7, src7, mask0, mask0, vec2, vec3); HADD_SB4_SH(vec0, vec1, vec2, vec3, res4, res5, res6, res7); @@ -2390,25 +3590,34 @@ void ff_put_h264_qpel8_mc20_msa(uint8_t *dst, const uint8_t *src, res4, res5, res6, res7); VSHF_B2_SB(src4, src4, src5, src5, mask2, mask2, vec8, vec9); VSHF_B2_SB(src6, src6, src7, src7, mask2, mask2, vec10, vec11); - DPADD_SB4_SH(vec8, vec9, vec10, vec11, plus20b, plus20b, plus20b, - plus20b, res4, res5, res6, res7); + DPADD_SB4_SH(vec8, vec9, vec10, vec11, plus20b, plus20b, plus20b, plus20b, + res4, res5, res6, res7); SRARI_H4_SH(res0, res1, res2, res3, 5); SRARI_H4_SH(res4, res5, res6, res7, 5); SAT_SH4_SH(res0, res1, res2, res3, 7); SAT_SH4_SH(res4, res5, res6, res7, 7); out0 = PCKEV_XORI128_UB(res0, res1); out1 = PCKEV_XORI128_UB(res2, res3); - out2 = PCKEV_XORI128_UB(res4, res5); - out3 = PCKEV_XORI128_UB(res6, res7); - ST8x8_UB(out0, out1, out2, out3, dst, stride); + out4 = PCKEV_XORI128_UB(res4, res5); + out5 = PCKEV_XORI128_UB(res6, res7); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, out2); + INSERT_D2_UB(tp2, tp3, out3); + LD4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, out6); + INSERT_D2_UB(tp2, tp3, out7); + AVER_UB2_UB(out0, out2, out1, out3, out0, out1); + AVER_UB2_UB(out4, out6, out5, out7, out4, out5); + ST8x8_UB(out0, out1, out4, out5, dst, stride); } -void ff_put_h264_qpel4_mc20_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel4_mc20_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - v16u8 out; - v16i8 src0, src1, src2, src3, mask0, mask1, mask2; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + uint32_t tp0, tp1, tp2, tp3; + v16u8 res, dst0 = { 0 }; + v16i8 src0, src1, src2, src3, vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 mask0, mask1, mask2; v8i16 res0, res1; v16i8 minus5b = __msa_ldi_b(-5); v16i8 plus20b = __msa_ldi_b(20); @@ -2424,18 +3633,21 @@ void ff_put_h264_qpel4_mc20_msa(uint8_t *dst, const uint8_t *src, DPADD_SB2_SH(vec4, vec5, plus20b, plus20b, res0, res1); SRARI_H2_SH(res0, res1, 5); SAT_SH2_SH(res0, res1, 7); - out = PCKEV_XORI128_UB(res0, res1); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); + res = PCKEV_XORI128_UB(res0, res1); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + res = __msa_aver_u_b(res, dst0); + ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); } -void ff_put_h264_qpel16_mc01_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel16_mc01_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { int32_t loop_cnt; int16_t filt_const0 = 0xfb01; int16_t filt_const1 = 0x1414; int16_t filt_const2 = 0x1fb; - v16u8 res0, res1, res2, res3; + v16u8 res0, res1, res2, res3, dst0, dst1, dst2, dst3; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; v16i8 src87_r, src10_l, src32_l, src54_l, src76_l, src21_l, src43_l; @@ -2484,8 +3696,11 @@ void ff_put_h264_qpel16_mc01_msa(uint8_t *dst, const uint8_t *src, res1 = (v16u8) __msa_aver_s_b((v16i8) res1, src3); res2 = (v16u8) __msa_aver_s_b((v16i8) res2, src4); res3 = (v16u8) __msa_aver_s_b((v16i8) res3, src5); + LD_UB4(dst, stride, dst0, dst1, dst2, dst3); XORI_B4_128_UB(res0, res1, res2, res3); - ST_UB4(res0, res1, res2, res3, dst, stride); + AVER_UB2_UB(res0, dst0, res1, dst1, dst0, dst1); + AVER_UB2_UB(res2, dst2, res3, dst3, dst2, dst3); + ST_UB4(dst0, dst1, dst2, dst3, dst, stride); dst += (4 * stride); src10_r = src54_r; @@ -2502,14 +3717,14 @@ void ff_put_h264_qpel16_mc01_msa(uint8_t *dst, const uint8_t *src, } } -void ff_put_h264_qpel16_mc03_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel16_mc03_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { int32_t loop_cnt; int16_t filt_const0 = 0xfb01; int16_t filt_const1 = 0x1414; int16_t filt_const2 = 0x1fb; - v16u8 res0, res1, res2, res3; + v16u8 res0, res1, res2, res3, dst0, dst1, dst2, dst3; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; v16i8 src87_r, src10_l, src32_l, src54_l, src76_l, src21_l, src43_l; @@ -2558,8 +3773,11 @@ void ff_put_h264_qpel16_mc03_msa(uint8_t *dst, const uint8_t *src, res1 = (v16u8) __msa_aver_s_b((v16i8) res1, src4); res2 = (v16u8) __msa_aver_s_b((v16i8) res2, src5); res3 = (v16u8) __msa_aver_s_b((v16i8) res3, src6); + LD_UB4(dst, stride, dst0, dst1, dst2, dst3); XORI_B4_128_UB(res0, res1, res2, res3); - ST_UB4(res0, res1, res2, res3, dst, stride); + AVER_UB2_UB(res0, dst0, res1, dst1, dst0, dst1); + AVER_UB2_UB(res2, dst2, res3, dst3, dst2, dst3); + ST_UB4(dst0, dst1, dst2, dst3, dst, stride); dst += (4 * stride); src10_r = src54_r; @@ -2575,16 +3793,18 @@ void ff_put_h264_qpel16_mc03_msa(uint8_t *dst, const uint8_t *src, } } -void ff_put_h264_qpel8_mc01_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel8_mc01_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { + uint64_t tp0, tp1, tp2, tp3; const int16_t filt_const0 = 0xfb01; const int16_t filt_const1 = 0x1414; const int16_t filt_const2 = 0x1fb; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; - v16i8 src11, src12, src10_r, src32_r, src54_r, src65_r, src76_r, src98_r; - v16i8 src21_r, src43_r, src87_r, src109_r, src1211_r, src1110_r; - v16i8 tmp0, tmp1, tmp2, tmp3, filt0, filt1, filt2, out0, out1, out2, out3; + v16u8 dst0 = { 0 }, dst1 = { 0 }, dst2 = { 0 }, dst3 = { 0 }; + v16i8 src0, src1, src2, src3, src4, src7, src8, src9, src10, src11, src12; + v16i8 src13, src14, tmp0, tmp1, tmp2, tmp3, src109_r; + v16i8 src10_r, src32_r, src76_r, src98_r, src21_r, src43_r, src87_r; + v16i8 filt0, filt1, filt2, out0, out1, out2, out3; v8i16 out0_r, out1_r, out2_r, out3_r, out4_r, out5_r, out6_r, out7_r; filt0 = (v16i8) __msa_fill_h(filt_const0); @@ -2595,29 +3815,38 @@ void ff_put_h264_qpel8_mc01_msa(uint8_t *dst, const uint8_t *src, LD_SB5(src, stride, src0, src1, src2, src3, src4); src += (5 * stride); - LD_SB8(src, stride, src5, src6, src7, src8, src9, src10, src11, src12); - XORI_B8_128_SB(src5, src6, src7, src8, src9, src10, src11, src12); + XORI_B5_128_SB(src0, src1, src2, src3, src4); ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, src32_r, src43_r); - ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, src65_r, - src76_r, src87_r); - ILVR_B4_SB(src9, src8, src10, src9, src11, src10, src12, src11, src98_r, - src109_r, src1110_r, src1211_r); - out0_r = AVC_DOT_SH3_SH(src10_r, src32_r, src54_r, filt0, filt1, filt2); - out1_r = AVC_DOT_SH3_SH(src21_r, src43_r, src65_r, filt0, filt1, filt2); - out2_r = AVC_DOT_SH3_SH(src32_r, src54_r, src76_r, filt0, filt1, filt2); - out3_r = AVC_DOT_SH3_SH(src43_r, src65_r, src87_r, filt0, filt1, filt2); - out4_r = AVC_DOT_SH3_SH(src54_r, src76_r, src98_r, filt0, filt1, filt2); - out5_r = AVC_DOT_SH3_SH(src65_r, src87_r, src109_r, filt0, filt1, filt2); - out6_r = AVC_DOT_SH3_SH(src76_r, src98_r, src1110_r, filt0, filt1, filt2); - out7_r = AVC_DOT_SH3_SH(src87_r, src109_r, src1211_r, filt0, filt1, filt2); - PCKEV_D2_SB(src3, src2, src5, src4, tmp0, tmp1); - PCKEV_D2_SB(src7, src6, src9, src8, tmp2, tmp3); + LD_SB8(src, stride, src7, src8, src9, src10, src11, src12, src13, src14); + XORI_B8_128_SB(src7, src8, src9, src10, src11, src12, src13, src14); + ILVR_B4_SB(src7, src4, src8, src7, src9, src8, src10, src9, src76_r, + src87_r, src98_r, src109_r); + out0_r = AVC_DOT_SH3_SH(src10_r, src32_r, src76_r, filt0, filt1, filt2); + out1_r = AVC_DOT_SH3_SH(src21_r, src43_r, src87_r, filt0, filt1, filt2); + out2_r = AVC_DOT_SH3_SH(src32_r, src76_r, src98_r, filt0, filt1, filt2); + out3_r = AVC_DOT_SH3_SH(src43_r, src87_r, src109_r, filt0, filt1, filt2); + PCKEV_D2_SB(src3, src2, src7, src4, tmp0, tmp1); + ILVR_B4_SB(src11, src10, src12, src11, src13, src12, src14, src13, src10_r, + src21_r, src32_r, src43_r); + out4_r = AVC_DOT_SH3_SH(src76_r, src98_r, src10_r, filt0, filt1, filt2); + out5_r = AVC_DOT_SH3_SH(src87_r, src109_r, src21_r, filt0, filt1, filt2); + out6_r = AVC_DOT_SH3_SH(src98_r, src10_r, src32_r, filt0, filt1, filt2); + out7_r = AVC_DOT_SH3_SH(src109_r, src21_r, src43_r, filt0, filt1, filt2); + PCKEV_D2_SB(src9, src8, src11, src10, tmp2, tmp3); SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 5); SRARI_H4_SH(out4_r, out5_r, out6_r, out7_r, 5); SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); SAT_SH4_SH(out4_r, out5_r, out6_r, out7_r, 7); + + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + LD4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst2); + INSERT_D2_UB(tp2, tp3, dst3); + PCKEV_B2_SB(out1_r, out0_r, out3_r, out2_r, out0, out1); PCKEV_B2_SB(out5_r, out4_r, out7_r, out6_r, out2, out3); out0 = __msa_aver_s_b(out0, tmp0); @@ -2625,19 +3854,23 @@ void ff_put_h264_qpel8_mc01_msa(uint8_t *dst, const uint8_t *src, out2 = __msa_aver_s_b(out2, tmp2); out3 = __msa_aver_s_b(out3, tmp3); XORI_B4_128_SB(out0, out1, out2, out3); - ST8x8_UB(out0, out1, out2, out3, dst, stride); + AVER_UB4_UB(out0, dst0, out1, dst1, out2, dst2, out3, dst3, dst0, dst1, + dst2, dst3); + ST8x8_UB(dst0, dst1, dst2, dst3, dst, stride); } -void ff_put_h264_qpel8_mc03_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel8_mc03_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { + uint64_t tp0, tp1, tp2, tp3; const int16_t filt_const0 = 0xfb01; - const int16_t filt_const1 = 0x1414; - const int16_t filt_const2 = 0x1fb; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; - v16i8 src11, src12, src10_r, src32_r, src54_r, src65_r, src76_r, src98_r; - v16i8 src21_r, src43_r, src87_r, src109_r, src1211_r, src1110_r; - v16i8 filt0, filt1, filt2, out0, out1, out2, out3, tmp0, tmp1, tmp2, tmp3; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + v16u8 dst0 = { 0 }, dst1 = { 0 }, dst2 = { 0 }, dst3 = { 0 }; + v16i8 src0, src1, src2, src3, src4, src7, src8, src9, src10, src11, src12; + v16i8 src13, src14, tmp0, tmp1, tmp2, tmp3, src109_r; + v16i8 src10_r, src32_r, src76_r, src98_r, src21_r, src43_r, src87_r; + v16i8 filt0, filt1, filt2, out0, out1, out2, out3; v8i16 out0_r, out1_r, out2_r, out3_r, out4_r, out5_r, out6_r, out7_r; filt0 = (v16i8) __msa_fill_h(filt_const0); @@ -2648,29 +3881,38 @@ void ff_put_h264_qpel8_mc03_msa(uint8_t *dst, const uint8_t *src, LD_SB5(src, stride, src0, src1, src2, src3, src4); src += (5 * stride); - LD_SB8(src, stride, src5, src6, src7, src8, src9, src10, src11, src12); + XORI_B5_128_SB(src0, src1, src2, src3, src4); - XORI_B8_128_SB(src5, src6, src7, src8, src9, src10, src11, src12); ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, src32_r, src43_r); - ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, src65_r, - src76_r, src87_r); - ILVR_B4_SB(src9, src8, src10, src9, src11, src10, src12, src11, src98_r, - src109_r, src1110_r, src1211_r); - out0_r = AVC_DOT_SH3_SH(src10_r, src32_r, src54_r, filt0, filt1, filt2); - out1_r = AVC_DOT_SH3_SH(src21_r, src43_r, src65_r, filt0, filt1, filt2); - out2_r = AVC_DOT_SH3_SH(src32_r, src54_r, src76_r, filt0, filt1, filt2); - out3_r = AVC_DOT_SH3_SH(src43_r, src65_r, src87_r, filt0, filt1, filt2); - out4_r = AVC_DOT_SH3_SH(src54_r, src76_r, src98_r, filt0, filt1, filt2); - out5_r = AVC_DOT_SH3_SH(src65_r, src87_r, src109_r, filt0, filt1, filt2); - out6_r = AVC_DOT_SH3_SH(src76_r, src98_r, src1110_r, filt0, filt1, filt2); - out7_r = AVC_DOT_SH3_SH(src87_r, src109_r, src1211_r, filt0, filt1, filt2); - PCKEV_D2_SB(src4, src3, src6, src5, tmp0, tmp1); - PCKEV_D2_SB(src8, src7, src10, src9, tmp2, tmp3); + LD_SB8(src, stride, src7, src8, src9, src10, src11, src12, src13, src14); + XORI_B8_128_SB(src7, src8, src9, src10, src11, src12, src13, src14); + ILVR_B4_SB(src7, src4, src8, src7, src9, src8, src10, src9, src76_r, + src87_r, src98_r, src109_r); + out0_r = AVC_DOT_SH3_SH(src10_r, src32_r, src76_r, filt0, filt1, filt2); + out1_r = AVC_DOT_SH3_SH(src21_r, src43_r, src87_r, filt0, filt1, filt2); + out2_r = AVC_DOT_SH3_SH(src32_r, src76_r, src98_r, filt0, filt1, filt2); + out3_r = AVC_DOT_SH3_SH(src43_r, src87_r, src109_r, filt0, filt1, filt2); + PCKEV_D2_SB(src4, src3, src8, src7, tmp0, tmp1); + ILVR_B4_SB(src11, src10, src12, src11, src13, src12, src14, src13, src10_r, + src21_r, src32_r, src43_r); + out4_r = AVC_DOT_SH3_SH(src76_r, src98_r, src10_r, filt0, filt1, filt2); + out5_r = AVC_DOT_SH3_SH(src87_r, src109_r, src21_r, filt0, filt1, filt2); + out6_r = AVC_DOT_SH3_SH(src98_r, src10_r, src32_r, filt0, filt1, filt2); + out7_r = AVC_DOT_SH3_SH(src109_r, src21_r, src43_r, filt0, filt1, filt2); + PCKEV_D2_SB(src10, src9, src12, src11, tmp2, tmp3); SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 5); SRARI_H4_SH(out4_r, out5_r, out6_r, out7_r, 5); SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); SAT_SH4_SH(out4_r, out5_r, out6_r, out7_r, 7); + + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + LD4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst2); + INSERT_D2_UB(tp2, tp3, dst3); + PCKEV_B2_SB(out1_r, out0_r, out3_r, out2_r, out0, out1); PCKEV_B2_SB(out5_r, out4_r, out7_r, out6_r, out2, out3); out0 = __msa_aver_s_b(out0, tmp0); @@ -2678,16 +3920,19 @@ void ff_put_h264_qpel8_mc03_msa(uint8_t *dst, const uint8_t *src, out2 = __msa_aver_s_b(out2, tmp2); out3 = __msa_aver_s_b(out3, tmp3); XORI_B4_128_SB(out0, out1, out2, out3); - ST8x8_UB(out0, out1, out2, out3, dst, stride); + AVER_UB4_UB(out0, dst0, out1, dst1, out2, dst2, out3, dst3, dst0, dst1, + dst2, dst3); + ST8x8_UB(dst0, dst1, dst2, dst3, dst, stride); } -void ff_put_h264_qpel4_mc01_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel4_mc01_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { + uint32_t tp0, tp1, tp2, tp3; int16_t filt_const0 = 0xfb01; int16_t filt_const1 = 0x1414; int16_t filt_const2 = 0x1fb; - v16u8 out; + v16u8 res, dst0 = { 0 }; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; v16i8 src87_r, src2110, src4332, src6554, src8776, filt0, filt1, filt2; @@ -2698,9 +3943,9 @@ void ff_put_h264_qpel4_mc01_msa(uint8_t *dst, const uint8_t *src, filt2 = (v16i8) __msa_fill_h(filt_const2); src -= (stride * 2); - LD_SB5(src, stride, src0, src1, src2, src3, src4); src += (5 * stride); + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, src32_r, src43_r); ILVR_D2_SB(src21_r, src10_r, src43_r, src32_r, src2110, src4332); @@ -2710,25 +3955,29 @@ void ff_put_h264_qpel4_mc01_msa(uint8_t *dst, const uint8_t *src, src76_r, src87_r); ILVR_D2_SB(src65_r, src54_r, src87_r, src76_r, src6554, src8776); XORI_B2_128_SB(src6554, src8776); + src32_r = (v16i8) __msa_insve_w((v4i32) src2, 1, (v4i32) src3); + src54_r = (v16i8) __msa_insve_w((v4i32) src4, 1, (v4i32) src5); + src32_r = (v16i8) __msa_insve_d((v2i64) src32_r, 1, (v2i64) src54_r); out10 = AVC_DOT_SH3_SH(src2110, src4332, src6554, filt0, filt1, filt2); out32 = AVC_DOT_SH3_SH(src4332, src6554, src8776, filt0, filt1, filt2); SRARI_H2_SH(out10, out32, 5); SAT_SH2_SH(out10, out32, 7); - out = PCKEV_XORI128_UB(out10, out32); - src32_r = (v16i8) __msa_insve_w((v4i32) src2, 1, (v4i32) src3); - src54_r = (v16i8) __msa_insve_w((v4i32) src4, 1, (v4i32) src5); - src32_r = (v16i8) __msa_insve_d((v2i64) src32_r, 1, (v2i64) src54_r); - out = __msa_aver_u_b(out, (v16u8) src32_r); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + res = PCKEV_XORI128_UB(out10, out32); + res = __msa_aver_u_b(res, (v16u8) src32_r); + dst0 = __msa_aver_u_b(res, dst0); + ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); } -void ff_put_h264_qpel4_mc03_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel4_mc03_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { + uint32_t tp0, tp1, tp2, tp3; int16_t filt_const0 = 0xfb01; int16_t filt_const1 = 0x1414; int16_t filt_const2 = 0x1fb; - v16u8 out; + v16u8 res, dst0 = { 0 }; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; v16i8 src87_r, src2110, src4332, src6554, src8776, filt0, filt1, filt2; @@ -2742,6 +3991,7 @@ void ff_put_h264_qpel4_mc03_msa(uint8_t *dst, const uint8_t *src, LD_SB5(src, stride, src0, src1, src2, src3, src4); src += (5 * stride); + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, src32_r, src43_r); ILVR_D2_SB(src21_r, src10_r, src43_r, src32_r, src2110, src4332); @@ -2755,122 +4005,136 @@ void ff_put_h264_qpel4_mc03_msa(uint8_t *dst, const uint8_t *src, out32 = AVC_DOT_SH3_SH(src4332, src6554, src8776, filt0, filt1, filt2); SRARI_H2_SH(out10, out32, 5); SAT_SH2_SH(out10, out32, 7); - out = PCKEV_XORI128_UB(out10, out32); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + res = PCKEV_XORI128_UB(out10, out32); src32_r = (v16i8) __msa_insve_w((v4i32) src3, 1, (v4i32) src4); src54_r = (v16i8) __msa_insve_w((v4i32) src5, 1, (v4i32) src6); src32_r = (v16i8) __msa_insve_d((v2i64) src32_r, 1, (v2i64) src54_r); - out = __msa_aver_u_b(out, (v16u8) src32_r); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); + res = __msa_aver_u_b(res, (v16u8) src32_r); + dst0 = __msa_aver_u_b(res, dst0); + ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); } -void ff_put_h264_qpel16_mc11_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel16_mc11_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_16w_msa(src - 2, - src - (stride * 2), stride, dst, stride, 16); + avc_luma_hv_qrt_and_aver_dst_16x16_msa(src - 2, + src - (stride * 2), + dst, stride); } -void ff_put_h264_qpel16_mc31_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel16_mc31_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_16w_msa(src - 2, - src - (stride * 2) + - sizeof(uint8_t), stride, dst, stride, 16); + avc_luma_hv_qrt_and_aver_dst_16x16_msa(src - 2, + src - (stride * 2) + + sizeof(uint8_t), + dst, stride); } -void ff_put_h264_qpel16_mc13_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel16_mc13_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_16w_msa(src + stride - 2, - src - (stride * 2), stride, dst, stride, 16); + avc_luma_hv_qrt_and_aver_dst_16x16_msa(src + stride - 2, + src - (stride * 2), + dst, stride); } -void ff_put_h264_qpel16_mc33_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel16_mc33_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_16w_msa(src + stride - 2, - src - (stride * 2) + - sizeof(uint8_t), stride, dst, stride, 16); + avc_luma_hv_qrt_and_aver_dst_16x16_msa(src + stride - 2, + src - (stride * 2) + + sizeof(uint8_t), + dst, stride); } -void ff_put_h264_qpel8_mc11_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel8_mc11_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_8w_msa(src - 2, src - (stride * 2), stride, dst, stride, 8); + avc_luma_hv_qrt_and_aver_dst_8x8_msa(src - 2, + src - (stride * 2), + dst, stride); } -void ff_put_h264_qpel8_mc31_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel8_mc31_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_8w_msa(src - 2, - src - (stride * 2) + - sizeof(uint8_t), stride, dst, stride, 8); + avc_luma_hv_qrt_and_aver_dst_8x8_msa(src - 2, + src - (stride * 2) + + sizeof(uint8_t), dst, stride); } -void ff_put_h264_qpel8_mc13_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel8_mc13_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_8w_msa(src + stride - 2, - src - (stride * 2), stride, dst, stride, 8); + avc_luma_hv_qrt_and_aver_dst_8x8_msa(src + stride - 2, + src - (stride * 2), + dst, stride); } -void ff_put_h264_qpel8_mc33_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel8_mc33_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_8w_msa(src + stride - 2, - src - (stride * 2) + - sizeof(uint8_t), stride, dst, stride, 8); + avc_luma_hv_qrt_and_aver_dst_8x8_msa(src + stride - 2, + src - (stride * 2) + + sizeof(uint8_t), dst, stride); } -void ff_put_h264_qpel4_mc11_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel4_mc11_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_4w_msa(src - 2, src - (stride * 2), stride, dst, stride, 4); + avc_luma_hv_qrt_and_aver_dst_4x4_msa(src - 2, + src - (stride * 2), + dst, stride); } -void ff_put_h264_qpel4_mc31_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel4_mc31_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_4w_msa(src - 2, - src - (stride * 2) + - sizeof(uint8_t), stride, dst, stride, 4); + avc_luma_hv_qrt_and_aver_dst_4x4_msa(src - 2, + src - (stride * 2) + + sizeof(uint8_t), dst, stride); } -void ff_put_h264_qpel4_mc13_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel4_mc13_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_4w_msa(src + stride - 2, - src - (stride * 2), stride, dst, stride, 4); + avc_luma_hv_qrt_and_aver_dst_4x4_msa(src + stride - 2, + src - (stride * 2), + dst, stride); } -void ff_put_h264_qpel4_mc33_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel4_mc33_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_4w_msa(src + stride - 2, - src - (stride * 2) + - sizeof(uint8_t), stride, dst, stride, 4); + avc_luma_hv_qrt_and_aver_dst_4x4_msa(src + stride - 2, + src - (stride * 2) + + sizeof(uint8_t), dst, stride); } -void ff_put_h264_qpel16_mc21_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel16_mc21_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { + uint64_t tp0, tp1, tp2, tp3; uint8_t *dst_tmp = dst; const uint8_t *src_tmp = src - (2 * stride) - 2; uint32_t multiple8_cnt, loop_cnt; const int32_t filt_const0 = 0xfffb0001; const int32_t filt_const1 = 0x140014; const int32_t filt_const2 = 0x1fffb; - v16u8 out0, out1; + v16u8 out0, out1, dst0 = { 0 }, dst1 = { 0 }; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, mask0, mask1; v16i8 mask2; v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; - v8i16 hz_out7, hz_out8, dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 hz_out7, hz_out8, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; v8i16 hz_out65_r, hz_out76_r, hz_out87_r, hz_out10_l, hz_out21_l; v8i16 hz_out32_l, hz_out43_l, hz_out54_l, hz_out65_l, hz_out76_l; v8i16 hz_out87_l, filt0, filt1, filt2; - v4i32 tmp0, tmp1; + v4i32 tmp0_w, tmp1_w; filt0 = (v8i16) __msa_fill_w(filt_const0); filt1 = (v8i16) __msa_fill_w(filt_const1); @@ -2893,65 +4157,83 @@ void ff_put_h264_qpel16_mc21_msa(uint8_t *dst, const uint8_t *src, hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); for (loop_cnt = 4; loop_cnt--;) { - LD_SB4(src, stride, src5, src6, src7, src8); - src += (4 * stride); - - XORI_B4_128_SB(src5, src6, src7, src8); + LD_SB2(src, stride, src5, src6); + src += (2 * stride); + XORI_B2_128_SB(src5, src6); hz_out5 = AVC_HORZ_FILTER_SH(src5, src5, mask0, mask1, mask2); hz_out6 = AVC_HORZ_FILTER_SH(src6, src6, mask0, mask1, mask2); - hz_out7 = AVC_HORZ_FILTER_SH(src7, src7, mask0, mask1, mask2); - hz_out8 = AVC_HORZ_FILTER_SH(src8, src8, mask0, mask1, mask2); - ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r); ILVL_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, hz_out3, hz_out10_l, hz_out21_l, hz_out32_l, hz_out43_l); - ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, - hz_out8, hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, + ILVR_H2_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out54_r, + hz_out65_r); + ILVL_H2_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out54_l, + hz_out65_l); + tmp0_w = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, + filt1, filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, + filt1, filt2); + tmp0 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, + filt1, filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, + filt1, filt2); + tmp2 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + + tmp1 = __msa_srari_h(hz_out2, 5); + tmp3 = __msa_srari_h(hz_out3, 5); + SAT_SH2_SH(tmp1, tmp3, 7); + + tmp0 = __msa_aver_s_h(tmp0, tmp1); + tmp1 = __msa_aver_s_h(tmp2, tmp3); + + LD2(dst, stride, tp0, tp1); + INSERT_D2_UB(tp0, tp1, dst0); + + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + dst0 = __msa_aver_u_b(out0, dst0); + ST8x2_UB(dst0, dst, stride); + dst += (2 * stride); + + LD_SB2(src, stride, src7, src8); + src += (2 * stride); + + XORI_B2_128_SB(src7, src8); + hz_out7 = AVC_HORZ_FILTER_SH(src7, src7, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src8, src8, mask0, mask1, mask2); + ILVR_H2_SH(hz_out7, hz_out6, hz_out8, hz_out7, hz_out76_r, hz_out87_r); - ILVL_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, - hz_out8, hz_out7, hz_out54_l, hz_out65_l, hz_out76_l, + ILVL_H2_SH(hz_out7, hz_out6, hz_out8, hz_out7, hz_out76_l, hz_out87_l); - - tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, - filt1, filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, - filt1, filt2); - dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); - tmp0 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, - filt1, filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, - filt1, filt2); - dst2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); - tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, - filt1, filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, - filt1, filt2); - dst4 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); - tmp0 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, - filt1, filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, - filt1, filt2); - dst6 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); - - dst1 = __msa_srari_h(hz_out2, 5); - dst3 = __msa_srari_h(hz_out3, 5); - dst5 = __msa_srari_h(hz_out4, 5); - dst7 = __msa_srari_h(hz_out5, 5); - SAT_SH4_SH(dst1, dst3, dst5, dst7, 7); - - dst0 = __msa_aver_s_h(dst0, dst1); - dst1 = __msa_aver_s_h(dst2, dst3); - dst2 = __msa_aver_s_h(dst4, dst5); - dst3 = __msa_aver_s_h(dst6, dst7); - - out0 = PCKEV_XORI128_UB(dst0, dst1); - out1 = PCKEV_XORI128_UB(dst2, dst3); - ST8x4_UB(out0, out1, dst, stride); - dst += (4 * stride); + tmp0_w = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, + filt1, filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, + filt1, filt2); + tmp4 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, + filt1, filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, + filt1, filt2); + tmp6 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + + tmp5 = __msa_srari_h(hz_out4, 5); + tmp7 = __msa_srari_h(hz_out5, 5); + SAT_SH2_SH(tmp5, tmp7, 7); + + tmp2 = __msa_aver_s_h(tmp4, tmp5); + tmp3 = __msa_aver_s_h(tmp6, tmp7); + + LD2(dst, stride, tp2, tp3); + INSERT_D2_UB(tp2, tp3, dst1); + + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + dst1 = __msa_aver_u_b(out1, dst1); + ST8x2_UB(dst1, dst, stride); + dst += (2 * stride); hz_out0 = hz_out4; hz_out1 = hz_out5; @@ -2965,25 +4247,26 @@ void ff_put_h264_qpel16_mc21_msa(uint8_t *dst, const uint8_t *src, } } -void ff_put_h264_qpel16_mc23_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel16_mc23_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { + uint64_t tp0, tp1, tp2, tp3; uint8_t *dst_tmp = dst; const uint8_t *src_tmp = src - (2 * stride) - 2; uint32_t multiple8_cnt, loop_cnt; const int32_t filt_const0 = 0xfffb0001; const int32_t filt_const1 = 0x140014; const int32_t filt_const2 = 0x1fffb; - v16u8 out0, out1; + v16u8 out0, out1, dst0 = { 0 }, dst1 = { 0 }; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, mask0, mask1; v16i8 mask2; v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; - v8i16 hz_out7, hz_out8, dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 hz_out7, hz_out8, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; v8i16 hz_out65_r, hz_out76_r, hz_out87_r, hz_out10_l, hz_out21_l; v8i16 hz_out32_l, hz_out43_l, hz_out54_l, hz_out65_l, hz_out76_l; v8i16 hz_out87_l, filt0, filt1, filt2; - v4i32 tmp0, tmp1; + v4i32 tmp0_w, tmp1_w; filt0 = (v8i16) __msa_fill_w(filt_const0); filt1 = (v8i16) __msa_fill_w(filt_const1); @@ -3006,65 +4289,80 @@ void ff_put_h264_qpel16_mc23_msa(uint8_t *dst, const uint8_t *src, hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); for (loop_cnt = 4; loop_cnt--;) { - LD_SB4(src, stride, src5, src6, src7, src8); - src += (4 * stride); - - XORI_B4_128_SB(src5, src6, src7, src8); + LD_SB2(src, stride, src5, src6); + src += (2 * stride); + XORI_B2_128_SB(src5, src6); hz_out5 = AVC_HORZ_FILTER_SH(src5, src5, mask0, mask1, mask2); hz_out6 = AVC_HORZ_FILTER_SH(src6, src6, mask0, mask1, mask2); - hz_out7 = AVC_HORZ_FILTER_SH(src7, src7, mask0, mask1, mask2); - hz_out8 = AVC_HORZ_FILTER_SH(src8, src8, mask0, mask1, mask2); - ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r); ILVL_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, hz_out3, hz_out10_l, hz_out21_l, hz_out32_l, hz_out43_l); - ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, - hz_out8, hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, + ILVR_H2_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out54_r, hz_out65_r); + ILVL_H2_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out54_l, hz_out65_l); + + tmp0_w = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, + filt1, filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, + filt1, filt2); + tmp0 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, + filt1, filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, + filt1, filt2); + tmp2 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + + tmp1 = __msa_srari_h(hz_out3, 5); + tmp3 = __msa_srari_h(hz_out4, 5); + SAT_SH2_SH(tmp1, tmp3, 7); + + tmp0 = __msa_aver_s_h(tmp0, tmp1); + tmp1 = __msa_aver_s_h(tmp2, tmp3); + + LD2(dst, stride, tp0, tp1); + INSERT_D2_UB(tp0, tp1, dst0); + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + dst0 = __msa_aver_u_b(out0, dst0); + ST8x2_UB(dst0, dst, stride); + dst += (2 * stride); + + LD_SB2(src, stride, src7, src8); + src += (2 * stride); + + XORI_B2_128_SB(src7, src8); + hz_out7 = AVC_HORZ_FILTER_SH(src7, src7, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src8, src8, mask0, mask1, mask2); + ILVR_H2_SH(hz_out7, hz_out6, hz_out8, hz_out7, hz_out76_r, hz_out87_r); - ILVL_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, - hz_out8, hz_out7, hz_out54_l, hz_out65_l, hz_out76_l, + ILVL_H2_SH(hz_out7, hz_out6, hz_out8, hz_out7, hz_out76_l, hz_out87_l); - - tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, - filt1, filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, - filt1, filt2); - dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); - tmp0 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, - filt1, filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, - filt1, filt2); - dst2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); - tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, - filt1, filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, - filt1, filt2); - dst4 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); - tmp0 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, - filt1, filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, - filt1, filt2); - dst6 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); - - dst1 = __msa_srari_h(hz_out3, 5); - dst3 = __msa_srari_h(hz_out4, 5); - dst5 = __msa_srari_h(hz_out5, 5); - dst7 = __msa_srari_h(hz_out6, 5); - SAT_SH4_SH(dst1, dst3, dst5, dst7, 7); - - dst0 = __msa_aver_s_h(dst0, dst1); - dst1 = __msa_aver_s_h(dst2, dst3); - dst2 = __msa_aver_s_h(dst4, dst5); - dst3 = __msa_aver_s_h(dst6, dst7); - - out0 = PCKEV_XORI128_UB(dst0, dst1); - out1 = PCKEV_XORI128_UB(dst2, dst3); - ST8x4_UB(out0, out1, dst, stride); - dst += (4 * stride); + tmp0_w = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, + filt1, filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, + filt1, filt2); + tmp4 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, + filt1, filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, + filt1, filt2); + tmp6 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + + tmp5 = __msa_srari_h(hz_out5, 5); + tmp7 = __msa_srari_h(hz_out6, 5); + SAT_SH2_SH(tmp5, tmp7, 7); + + tmp2 = __msa_aver_s_h(tmp4, tmp5); + tmp3 = __msa_aver_s_h(tmp6, tmp7); + + LD2(dst, stride, tp2, tp3); + INSERT_D2_UB(tp2, tp3, dst1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + dst1 = __msa_aver_u_b(out1, dst1); + ST8x2_UB(dst1, dst, stride); + dst += (2 * stride); hz_out0 = hz_out4; hz_out1 = hz_out5; @@ -3078,24 +4376,25 @@ void ff_put_h264_qpel16_mc23_msa(uint8_t *dst, const uint8_t *src, } } -void ff_put_h264_qpel8_mc21_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel8_mc21_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { const int32_t filt_const0 = 0xfffb0001; const int32_t filt_const1 = 0x140014; const int32_t filt_const2 = 0x1fffb; - v16u8 out0, out1; + uint64_t tp0, tp1, tp2, tp3; + v16u8 dst0 = { 0 }, dst1 = { 0 }, out0, out1; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v16i8 src11, src12, mask0, mask1, mask2; v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; v8i16 hz_out7, hz_out8, hz_out9, hz_out10, hz_out11, hz_out12; v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; v8i16 hz_out65_r, hz_out76_r, hz_out87_r, hz_out89_r, hz_out910_r; - v8i16 hz_out1110_r, hz_out1211_r, dst0, dst1, dst2, dst3; + v8i16 hz_out1110_r, hz_out1211_r, tmp0, tmp1, tmp2, tmp3; v8i16 hz_out10_l, hz_out21_l, hz_out32_l, hz_out43_l, hz_out54_l; v8i16 hz_out65_l, hz_out76_l, hz_out87_l, hz_out89_l, hz_out910_l; v8i16 hz_out1110_l, hz_out1211_l, filt0, filt1, filt2; - v4i32 tmp0, tmp1; + v4i32 tmp0_w, tmp1_w; LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); @@ -3133,38 +4432,43 @@ void ff_put_h264_qpel8_mc21_msa(uint8_t *dst, const uint8_t *src, ILVL_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, hz_out7, hz_out54_l, hz_out65_l, hz_out76_l, hz_out87_l); - tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, filt1, - filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, filt1, - filt2); - dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); - tmp0 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, filt1, - filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, filt1, - filt2); - dst1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); - tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, filt1, - filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, filt1, - filt2); - dst2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); - tmp0 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, filt1, - filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, filt1, - filt2); - dst3 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0_w = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, filt1, + filt2); + tmp0 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, filt1, + filt2); + tmp1 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, filt1, + filt2); + tmp2 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, filt1, + filt2); + tmp3 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); SRARI_H4_SH(hz_out2, hz_out3, hz_out4, hz_out5, 5); SAT_SH4_SH(hz_out2, hz_out3, hz_out4, hz_out5, 7); - dst0 = __msa_aver_s_h(dst0, hz_out2); - dst1 = __msa_aver_s_h(dst1, hz_out3); - dst2 = __msa_aver_s_h(dst2, hz_out4); - dst3 = __msa_aver_s_h(dst3, hz_out5); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + + tmp0 = __msa_aver_s_h(tmp0, hz_out2); + tmp1 = __msa_aver_s_h(tmp1, hz_out3); + tmp2 = __msa_aver_s_h(tmp2, hz_out4); + tmp3 = __msa_aver_s_h(tmp3, hz_out5); - out0 = PCKEV_XORI128_UB(dst0, dst1); - out1 = PCKEV_XORI128_UB(dst2, dst3); - ST8x4_UB(out0, out1, dst, stride); + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, stride); dst += (4 * stride); LD_SB4(src, stride, src9, src10, src11, src12); @@ -3179,58 +4483,64 @@ void ff_put_h264_qpel8_mc21_msa(uint8_t *dst, const uint8_t *src, ILVL_H4_SH(hz_out9, hz_out8, hz_out10, hz_out9, hz_out11, hz_out10, hz_out12, hz_out11, hz_out89_l, hz_out910_l, hz_out1110_l, hz_out1211_l); - tmp0 = AVC_DOT_SW3_SW(hz_out54_r, hz_out76_r, hz_out89_r, filt0, filt1, - filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out54_l, hz_out76_l, hz_out89_l, filt0, filt1, - filt2); - dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); - tmp0 = AVC_DOT_SW3_SW(hz_out65_r, hz_out87_r, hz_out910_r, filt0, filt1, - filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out65_l, hz_out87_l, hz_out910_l, filt0, filt1, - filt2); - dst1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); - tmp0 = AVC_DOT_SW3_SW(hz_out76_r, hz_out89_r, hz_out1110_r, filt0, filt1, - filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out76_l, hz_out89_l, hz_out1110_l, filt0, filt1, - filt2); - dst2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); - tmp0 = AVC_DOT_SW3_SW(hz_out87_r, hz_out910_r, hz_out1211_r, filt0, filt1, - filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out87_l, hz_out910_l, hz_out1211_l, filt0, filt1, - filt2); - dst3 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0_w = AVC_DOT_SW3_SW(hz_out54_r, hz_out76_r, hz_out89_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out54_l, hz_out76_l, hz_out89_l, filt0, filt1, + filt2); + tmp0 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out65_r, hz_out87_r, hz_out910_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out65_l, hz_out87_l, hz_out910_l, filt0, filt1, + filt2); + tmp1 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out76_r, hz_out89_r, hz_out1110_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out76_l, hz_out89_l, hz_out1110_l, filt0, filt1, + filt2); + tmp2 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out87_r, hz_out910_r, hz_out1211_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out87_l, hz_out910_l, hz_out1211_l, filt0, filt1, + filt2); + tmp3 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); SRARI_H4_SH(hz_out6, hz_out7, hz_out8, hz_out9, 5); SAT_SH4_SH(hz_out6, hz_out7, hz_out8, hz_out9, 7); - dst0 = __msa_aver_s_h(dst0, hz_out6); - dst1 = __msa_aver_s_h(dst1, hz_out7); - dst2 = __msa_aver_s_h(dst2, hz_out8); - dst3 = __msa_aver_s_h(dst3, hz_out9); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); - out0 = PCKEV_XORI128_UB(dst0, dst1); - out1 = PCKEV_XORI128_UB(dst2, dst3); - ST8x4_UB(out0, out1, dst, stride); + tmp0 = __msa_aver_s_h(tmp0, hz_out6); + tmp1 = __msa_aver_s_h(tmp1, hz_out7); + tmp2 = __msa_aver_s_h(tmp2, hz_out8); + tmp3 = __msa_aver_s_h(tmp3, hz_out9); + + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, stride); } -void ff_put_h264_qpel8_mc23_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel8_mc23_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { const int32_t filt_const0 = 0xfffb0001; const int32_t filt_const1 = 0x140014; const int32_t filt_const2 = 0x1fffb; - v16u8 out0, out1; + uint64_t tp0, tp1, tp2, tp3; + v16u8 dst0 = { 0 }, dst1 = { 0 }, out0, out1; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v16i8 src11, src12, mask0, mask1, mask2; v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; v8i16 hz_out7, hz_out8, hz_out9, hz_out10, hz_out11, hz_out12; v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; v8i16 hz_out65_r, hz_out76_r, hz_out87_r, hz_out89_r, hz_out910_r; - v8i16 hz_out1110_r, hz_out1211_r, dst0, dst1, dst2, dst3; + v8i16 hz_out1110_r, hz_out1211_r, tmp0, tmp1, tmp2, tmp3; v8i16 hz_out10_l, hz_out21_l, hz_out32_l, hz_out43_l, hz_out54_l; v8i16 hz_out65_l, hz_out76_l, hz_out87_l, hz_out89_l, hz_out910_l; v8i16 hz_out1110_l, hz_out1211_l, filt0, filt1, filt2; - v4i32 tmp0, tmp1; + v4i32 tmp0_w, tmp1_w; LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); @@ -3268,38 +4578,43 @@ void ff_put_h264_qpel8_mc23_msa(uint8_t *dst, const uint8_t *src, ILVL_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, hz_out7, hz_out54_l, hz_out65_l, hz_out76_l, hz_out87_l); - tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, filt1, - filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, filt1, - filt2); - dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); - tmp0 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, filt1, - filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, filt1, - filt2); - dst1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); - tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, filt1, - filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, filt1, - filt2); - dst2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); - tmp0 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, filt1, - filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, filt1, - filt2); - dst3 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0_w = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, filt1, + filt2); + tmp0 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, filt1, + filt2); + tmp1 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, filt1, + filt2); + tmp2 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, filt1, + filt2); + tmp3 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); SRARI_H4_SH(hz_out3, hz_out4, hz_out5, hz_out6, 5); SAT_SH4_SH(hz_out3, hz_out4, hz_out5, hz_out6, 7); - dst0 = __msa_aver_s_h(dst0, hz_out3); - dst1 = __msa_aver_s_h(dst1, hz_out4); - dst2 = __msa_aver_s_h(dst2, hz_out5); - dst3 = __msa_aver_s_h(dst3, hz_out6); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); - out0 = PCKEV_XORI128_UB(dst0, dst1); - out1 = PCKEV_XORI128_UB(dst2, dst3); - ST8x4_UB(out0, out1, dst, stride); + tmp0 = __msa_aver_s_h(tmp0, hz_out3); + tmp1 = __msa_aver_s_h(tmp1, hz_out4); + tmp2 = __msa_aver_s_h(tmp2, hz_out5); + tmp3 = __msa_aver_s_h(tmp3, hz_out6); + + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, stride); dst += (4 * stride); LD_SB4(src, stride, src9, src10, src11, src12); @@ -3314,47 +4629,53 @@ void ff_put_h264_qpel8_mc23_msa(uint8_t *dst, const uint8_t *src, ILVL_H4_SH(hz_out9, hz_out8, hz_out10, hz_out9, hz_out11, hz_out10, hz_out12, hz_out11, hz_out89_l, hz_out910_l, hz_out1110_l, hz_out1211_l); - tmp0 = AVC_DOT_SW3_SW(hz_out54_r, hz_out76_r, hz_out89_r, filt0, filt1, - filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out54_l, hz_out76_l, hz_out89_l, filt0, filt1, - filt2); - dst0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); - tmp0 = AVC_DOT_SW3_SW(hz_out65_r, hz_out87_r, hz_out910_r, filt0, filt1, - filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out65_l, hz_out87_l, hz_out910_l, filt0, filt1, - filt2); - dst1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); - tmp0 = AVC_DOT_SW3_SW(hz_out76_r, hz_out89_r, hz_out1110_r, filt0, filt1, - filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out76_l, hz_out89_l, hz_out1110_l, filt0, filt1, - filt2); - dst2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); - tmp0 = AVC_DOT_SW3_SW(hz_out87_r, hz_out910_r, hz_out1211_r, filt0, filt1, - filt2); - tmp1 = AVC_DOT_SW3_SW(hz_out87_l, hz_out910_l, hz_out1211_l, filt0, filt1, - filt2); - dst3 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0_w = AVC_DOT_SW3_SW(hz_out54_r, hz_out76_r, hz_out89_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out54_l, hz_out76_l, hz_out89_l, filt0, filt1, + filt2); + tmp0 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out65_r, hz_out87_r, hz_out910_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out65_l, hz_out87_l, hz_out910_l, filt0, filt1, + filt2); + tmp1 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out76_r, hz_out89_r, hz_out1110_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out76_l, hz_out89_l, hz_out1110_l, filt0, filt1, + filt2); + tmp2 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); + tmp0_w = AVC_DOT_SW3_SW(hz_out87_r, hz_out910_r, hz_out1211_r, filt0, filt1, + filt2); + tmp1_w = AVC_DOT_SW3_SW(hz_out87_l, hz_out910_l, hz_out1211_l, filt0, filt1, + filt2); + tmp3 = __msa_pckev_h((v8i16) tmp1_w, (v8i16) tmp0_w); SRARI_H4_SH(hz_out7, hz_out8, hz_out9, hz_out10, 5); SAT_SH4_SH(hz_out7, hz_out8, hz_out9, hz_out10, 7); - dst0 = __msa_aver_s_h(dst0, hz_out7); - dst1 = __msa_aver_s_h(dst1, hz_out8); - dst2 = __msa_aver_s_h(dst2, hz_out9); - dst3 = __msa_aver_s_h(dst3, hz_out10); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); - out0 = PCKEV_XORI128_UB(dst0, dst1); - out1 = PCKEV_XORI128_UB(dst2, dst3); - ST8x4_UB(out0, out1, dst, stride); + tmp0 = __msa_aver_s_h(tmp0, hz_out7); + tmp1 = __msa_aver_s_h(tmp1, hz_out8); + tmp2 = __msa_aver_s_h(tmp2, hz_out9); + tmp3 = __msa_aver_s_h(tmp3, hz_out10); + + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, stride); } -void ff_put_h264_qpel4_mc21_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel4_mc21_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { + uint32_t tp0, tp1, tp2, tp3; const int32_t filt_const0 = 0xfffb0001; const int32_t filt_const1 = 0x140014; const int32_t filt_const2 = 0x1fffb; - v16u8 res; + v16u8 res, out = { 0 }; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v16i8 mask0, mask1, mask2; v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; @@ -3407,18 +4728,21 @@ void ff_put_h264_qpel4_mc21_msa(uint8_t *dst, const uint8_t *src, dst0 = __msa_aver_s_h(dst0, hz_out2); dst1 = __msa_aver_s_h(dst1, hz_out4); - + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, out); res = PCKEV_XORI128_UB(dst0, dst1); + res = __msa_aver_u_b(res, out); ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); } -void ff_put_h264_qpel4_mc23_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel4_mc23_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { const int32_t filt_const0 = 0xfffb0001; const int32_t filt_const1 = 0x140014; const int32_t filt_const2 = 0x1fffb; - v16u8 res; + uint32_t tp0, tp1, tp2, tp3; + v16u8 res, out = { 0 }; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v16i8 mask0, mask1, mask2; v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; @@ -3472,19 +4796,21 @@ void ff_put_h264_qpel4_mc23_msa(uint8_t *dst, const uint8_t *src, dst0 = __msa_aver_s_h(dst0, hz_out0); dst1 = __msa_aver_s_h(dst1, hz_out1); - + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, out); res = PCKEV_XORI128_UB(dst0, dst1); + res = __msa_aver_u_b(res, out); ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); } -void ff_put_h264_qpel16_mc02_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel16_mc02_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { int32_t loop_cnt; int16_t filt_const0 = 0xfb01; int16_t filt_const1 = 0x1414; int16_t filt_const2 = 0x1fb; - v16u8 res0, res1, res2, res3; + v16u8 res0, res1, res2, res3, dst0, dst1, dst2, dst3; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; v16i8 src87_r, src10_l, src32_l, src54_l, src76_l, src21_l, src43_l; @@ -3526,9 +4852,12 @@ void ff_put_h264_qpel16_mc02_msa(uint8_t *dst, const uint8_t *src, SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); SRARI_H4_SH(out0_l, out1_l, out2_l, out3_l, 5); SAT_SH4_SH(out0_l, out1_l, out2_l, out3_l, 7); + LD_UB4(dst, stride, dst0, dst1, dst2, dst3); PCKEV_B4_UB(out0_l, out0_r, out1_l, out1_r, out2_l, out2_r, out3_l, out3_r, res0, res1, res2, res3); XORI_B4_128_UB(res0, res1, res2, res3); + AVER_UB2_UB(res0, dst0, res1, dst1, res0, res1); + AVER_UB2_UB(res2, dst2, res3, dst3, res2, res3); ST_UB4(res0, res1, res2, res3, dst, stride); dst += (4 * stride); @@ -3544,16 +4873,17 @@ void ff_put_h264_qpel16_mc02_msa(uint8_t *dst, const uint8_t *src, } } -void ff_put_h264_qpel8_mc02_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel8_mc02_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { + uint64_t tp0, tp1, tp2, tp3; const int16_t filt_const0 = 0xfb01; const int16_t filt_const1 = 0x1414; const int16_t filt_const2 = 0x1fb; + v16u8 dst0 = { 0 }, dst1 = { 0 }, dst2 = { 0 }, dst3 = { 0 }; v16u8 out0, out1, out2, out3; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; - v16i8 src11, src12, src10_r, src21_r, src32_r, src43_r, src76_r, src87_r; - v16i8 src98_r, src109_r, src89_r, src910_r, src1110_r, src1211_r; + v16i8 src0, src1, src2, src3, src4, src7, src8, src9, src10, src109_r; + v16i8 src10_r, src32_r, src76_r, src98_r, src21_r, src43_r, src87_r; v16i8 filt0, filt1, filt2; v8i16 out0_r, out1_r, out2_r, out3_r, out4_r, out5_r, out6_r, out7_r; @@ -3563,26 +4893,39 @@ void ff_put_h264_qpel8_mc02_msa(uint8_t *dst, const uint8_t *src, src -= (stride * 2); - LD_SB8(src, stride, src0, src1, src2, src3, src4, src5, src6, src7); - src += (8 * stride); - LD_SB5(src, stride, src8, src9, src10, src11, src12); + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + + XORI_B5_128_SB(src0, src1, src2, src3, src4); ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, src32_r, src43_r); - ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src76_r, src87_r, - src98_r, src109_r); - ILVR_B4_SB(src9, src8, src10, src9, src11, src10, src12, src11, src89_r, - src910_r, src1110_r, src1211_r); - XORI_B4_128_SB(src10_r, src21_r, src32_r, src43_r); - XORI_B4_128_SB(src76_r, src87_r, src98_r, src109_r); - XORI_B4_128_SB(src89_r, src910_r, src1110_r, src1211_r); + + LD_SB4(src, stride, src7, src8, src9, src10); + src += (4 * stride); + XORI_B4_128_SB(src7, src8, src9, src10); + ILVR_B4_SB(src7, src4, src8, src7, src9, src8, src10, src9, src76_r, + src87_r, src98_r, src109_r); out0_r = AVC_DOT_SH3_SH(src10_r, src32_r, src76_r, filt0, filt1, filt2); out1_r = AVC_DOT_SH3_SH(src21_r, src43_r, src87_r, filt0, filt1, filt2); out2_r = AVC_DOT_SH3_SH(src32_r, src76_r, src98_r, filt0, filt1, filt2); out3_r = AVC_DOT_SH3_SH(src43_r, src87_r, src109_r, filt0, filt1, filt2); - out4_r = AVC_DOT_SH3_SH(src76_r, src98_r, src89_r, filt0, filt1, filt2); - out5_r = AVC_DOT_SH3_SH(src87_r, src109_r, src910_r, filt0, filt1, filt2); - out6_r = AVC_DOT_SH3_SH(src98_r, src89_r, src1110_r, filt0, filt1, filt2); - out7_r = AVC_DOT_SH3_SH(src109_r, src910_r, src1211_r, filt0, filt1, filt2); + + LD_SB4(src, stride, src0, src1, src2, src3); + XORI_B4_128_SB(src0, src1, src2, src3); + ILVR_B4_SB(src0, src10, src1, src0, src2, src1, src3, src2, src10_r, + src21_r, src32_r, src43_r); + out4_r = AVC_DOT_SH3_SH(src76_r, src98_r, src10_r, filt0, filt1, filt2); + out5_r = AVC_DOT_SH3_SH(src87_r, src109_r, src21_r, filt0, filt1, filt2); + out6_r = AVC_DOT_SH3_SH(src98_r, src10_r, src32_r, filt0, filt1, filt2); + out7_r = AVC_DOT_SH3_SH(src109_r, src21_r, src43_r, filt0, filt1, filt2); + + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + LD4(dst + 4 * stride, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst2); + INSERT_D2_UB(tp2, tp3, dst3); + SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 5); SRARI_H4_SH(out4_r, out5_r, out6_r, out7_r, 5); SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); @@ -3591,16 +4934,19 @@ void ff_put_h264_qpel8_mc02_msa(uint8_t *dst, const uint8_t *src, out1 = PCKEV_XORI128_UB(out2_r, out3_r); out2 = PCKEV_XORI128_UB(out4_r, out5_r); out3 = PCKEV_XORI128_UB(out6_r, out7_r); - ST8x8_UB(out0, out1, out2, out3, dst, stride); + AVER_UB4_UB(out0, dst0, out1, dst1, out2, dst2, out3, dst3, dst0, dst1, + dst2, dst3); + ST8x8_UB(dst0, dst1, dst2, dst3, dst, stride); } -void ff_put_h264_qpel4_mc02_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel4_mc02_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - const int16_t filt_const0 = 0xfb01; - const int16_t filt_const1 = 0x1414; - const int16_t filt_const2 = 0x1fb; - v16u8 out; + uint32_t tp0, tp1, tp2, tp3; + int16_t filt_const0 = 0xfb01; + int16_t filt_const1 = 0x1414; + int16_t filt_const2 = 0x1fb; + v16u8 res, dst0 = { 0 }; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v16i8 src10_r, src32_r, src54_r, src76_r, src21_r, src43_r, src65_r; v16i8 src87_r, src2110, src4332, src6554, src8776, filt0, filt1, filt2; @@ -3611,396 +4957,833 @@ void ff_put_h264_qpel4_mc02_msa(uint8_t *dst, const uint8_t *src, filt2 = (v16i8) __msa_fill_h(filt_const2); src -= (stride * 2); - LD_SB5(src, stride, src0, src1, src2, src3, src4); src += (5 * stride); - LD_SB4(src, stride, src5, src6, src7, src8); ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, src32_r, src43_r); + ILVR_D2_SB(src21_r, src10_r, src43_r, src32_r, src2110, src4332); + XORI_B2_128_SB(src2110, src4332); + LD_SB4(src, stride, src5, src6, src7, src8); ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, src65_r, src76_r, src87_r); - ILVR_D4_SB(src21_r, src10_r, src43_r, src32_r, src65_r, src54_r, src87_r, - src76_r, src2110, src4332, src6554, src8776); - XORI_B4_128_SB(src2110, src4332, src6554, src8776); + ILVR_D2_SB(src65_r, src54_r, src87_r, src76_r, src6554, src8776); + XORI_B2_128_SB(src6554, src8776); out10 = AVC_DOT_SH3_SH(src2110, src4332, src6554, filt0, filt1, filt2); out32 = AVC_DOT_SH3_SH(src4332, src6554, src8776, filt0, filt1, filt2); SRARI_H2_SH(out10, out32, 5); SAT_SH2_SH(out10, out32, 7); - out = PCKEV_XORI128_UB(out10, out32); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + res = PCKEV_XORI128_UB(out10, out32); + dst0 = __msa_aver_u_b(res, dst0); + ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, stride); } -void ff_put_h264_qpel16_mc12_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel16_mc12_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_midh_qrt_16w_msa(src - (2 * stride) - 2, - stride, dst, stride, 16, 0); -} + uint32_t row; + v16u8 out, dst0; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 src11; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, tmp0, tmp1, tmp2, tmp3, mask3; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v8i16 shf_vec7, shf_vec8, shf_vec9, shf_vec10, shf_vec11, mask4, mask5; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; + v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; + v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; + v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; + v8i16 minus5h = __msa_ldi_h(-5); + v8i16 plus20h = __msa_ldi_h(20); -void ff_put_h264_qpel16_mc32_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_midh_qrt_16w_msa(src - (2 * stride) - 2, - stride, dst, stride, 16, 1); -} + mask3 = mask0 + 4; + mask4 = mask1 + 4; + mask5 = mask2 + 4; -void ff_put_h264_qpel8_mc12_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_midh_qrt_8w_msa(src - (2 * stride) - 2, stride, dst, stride, 8, 0); -} + src -= ((2 * stride) + 2); -void ff_put_h264_qpel8_mc32_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_midh_qrt_8w_msa(src - (2 * stride) - 2, stride, dst, stride, 8, 1); -} + LD_SB5(src, stride, src0, src1, src2, src3, src4); + LD_SB5(src + 8, stride, src7, src8, src9, src10, src11); + src += (5 * stride); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B5_128_SB(src7, src8, src9, src10, src11); -void ff_put_h264_qpel4_mc12_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_midh_qrt_4w_msa(src - (2 * stride) - 2, stride, dst, stride, 4, 0); -} + for (row = 16; row--;) { + LD_SB2(src, 8, src5, src6); + src += stride; + XORI_B2_128_SB(src5, src6); + dst0 = LD_UB(dst); -void ff_put_h264_qpel4_mc32_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_midh_qrt_4w_msa(src - (2 * stride) - 2, stride, dst, stride, 4, 1); + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src0, src1, src2, src3, src4, src5, + vt_res0, vt_res1); + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src7, src8, src9, src10, src11, src6, + vt_res2, vt_res3); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask3, + mask4, mask5, shf_vec6, shf_vec7, shf_vec8); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask3, + mask4, mask5, shf_vec9, shf_vec10, shf_vec11); + hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); + hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + hz_res2 = __msa_hadd_s_w(shf_vec6, shf_vec6); + hz_res3 = __msa_hadd_s_w(shf_vec9, shf_vec9); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); + DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + DPADD_SH2_SW(shf_vec7, shf_vec8, minus5h, plus20h, hz_res2, hz_res2); + DPADD_SH2_SW(shf_vec10, shf_vec11, minus5h, plus20h, hz_res3, hz_res3); + SRARI_W4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 10); + SAT_SW4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 7); + tmp0 = __msa_srari_h(shf_vec2, 5); + tmp1 = __msa_srari_h(shf_vec5, 5); + tmp2 = __msa_srari_h(shf_vec8, 5); + tmp3 = __msa_srari_h(shf_vec11, 5); + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + PCKEV_H2_SH(tmp2, tmp0, tmp3, tmp1, tmp0, tmp1); + PCKEV_H2_SH(hz_res2, hz_res0, hz_res3, hz_res1, tmp2, tmp3); + tmp0 = __msa_aver_s_h(tmp2, tmp0); + tmp1 = __msa_aver_s_h(tmp3, tmp1); + out = PCKEV_XORI128_UB(tmp0, tmp1); + out = __msa_aver_u_b(out, dst0); + ST_UB(out, dst); + dst += stride; + + src0 = src1; + src1 = src2; + src2 = src3; + src3 = src4; + src4 = src5; + src7 = src8; + src8 = src9; + src9 = src10; + src10 = src11; + src11 = src6; + } } -void ff_put_h264_qpel16_mc22_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel16_mc32_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_mid_16w_msa(src - (2 * stride) - 2, stride, dst, stride, 16); + uint32_t row; + v16u8 out, dst0; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 src11; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, tmp0, tmp1, tmp2, tmp3, mask3; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v8i16 shf_vec7, shf_vec8, shf_vec9, shf_vec10, shf_vec11, mask4, mask5; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; + v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; + v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; + v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; + v8i16 minus5h = __msa_ldi_h(-5); + v8i16 plus20h = __msa_ldi_h(20); + + mask3 = mask0 + 4; + mask4 = mask1 + 4; + mask5 = mask2 + 4; + + src -= ((2 * stride) + 2); + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + LD_SB5(src + 8, stride, src7, src8, src9, src10, src11); + src += (5 * stride); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B5_128_SB(src7, src8, src9, src10, src11); + + for (row = 16; row--;) { + LD_SB2(src, 8, src5, src6); + src += stride; + XORI_B2_128_SB(src5, src6); + dst0 = LD_UB(dst); + + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src0, src1, src2, src3, src4, src5, + vt_res0, vt_res1); + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src7, src8, src9, src10, src11, src6, + vt_res2, vt_res3); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask3, + mask4, mask5, shf_vec6, shf_vec7, shf_vec8); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask3, + mask4, mask5, shf_vec9, shf_vec10, shf_vec11); + hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); + hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + hz_res2 = __msa_hadd_s_w(shf_vec6, shf_vec6); + hz_res3 = __msa_hadd_s_w(shf_vec9, shf_vec9); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); + DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + DPADD_SH2_SW(shf_vec7, shf_vec8, minus5h, plus20h, hz_res2, hz_res2); + DPADD_SH2_SW(shf_vec10, shf_vec11, minus5h, plus20h, hz_res3, hz_res3); + SRARI_W4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 10); + SAT_SW4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 7); + tmp0 = __msa_srari_h(shf_vec2, 5); + tmp1 = __msa_srari_h(shf_vec5, 5); + tmp2 = __msa_srari_h(shf_vec8, 5); + tmp3 = __msa_srari_h(shf_vec11, 5); + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + tmp0 = __msa_pckod_h(tmp2, tmp0); + tmp1 = __msa_pckod_h(tmp3, tmp1); + PCKEV_H2_SH(hz_res2, hz_res0, hz_res3, hz_res1, tmp2, tmp3); + tmp0 = __msa_aver_s_h(tmp2, tmp0); + tmp1 = __msa_aver_s_h(tmp3, tmp1); + out = PCKEV_XORI128_UB(tmp0, tmp1); + out = __msa_aver_u_b(out, dst0); + ST_UB(out, dst); + dst += stride; + + src0 = src1; + src1 = src2; + src2 = src3; + src3 = src4; + src4 = src5; + src7 = src8; + src8 = src9; + src9 = src10; + src10 = src11; + src11 = src6; + } } -void ff_put_h264_qpel8_mc22_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel8_mc12_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_mid_8w_msa(src - (2 * stride) - 2, stride, dst, stride, 8); -} + uint32_t row; + uint64_t tp0, tp1; + v16u8 out, dst0 = { 0 }; + v16i8 src0, src1, src2, src3, src4, src5, src6; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, tmp0, tmp1, tmp2, tmp3; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v8i16 shf_vec7, shf_vec8, shf_vec9, shf_vec10, shf_vec11; + v8i16 mask3, mask4, mask5; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; + v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; + v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; + v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; + v8i16 minus5h = __msa_ldi_h(-5); + v8i16 plus20h = __msa_ldi_h(20); -void ff_put_h264_qpel4_mc22_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_mid_4w_msa(src - (2 * stride) - 2, stride, dst, stride, 4); -} + mask3 = mask0 + 4; + mask4 = mask1 + 4; + mask5 = mask2 + 4; -void ff_avg_h264_qpel16_mc10_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_hz_qrt_and_aver_dst_16x16_msa(src - 2, stride, dst, stride, 0); -} + src -= ((2 * stride) + 2); -void ff_avg_h264_qpel16_mc30_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_hz_qrt_and_aver_dst_16x16_msa(src - 2, stride, dst, stride, 1); -} + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + XORI_B5_128_SB(src0, src1, src2, src3, src4); -void ff_avg_h264_qpel8_mc10_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_hz_qrt_and_aver_dst_8x8_msa(src - 2, stride, dst, stride, 0); -} + for (row = 4; row--;) { + LD_SB2(src, stride, src5, src6); + src += (2 * stride); + XORI_B2_128_SB(src5, src6); -void ff_avg_h264_qpel8_mc30_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_hz_qrt_and_aver_dst_8x8_msa(src - 2, stride, dst, stride, 1); -} + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src0, src1, src2, src3, src4, src5, + vt_res0, vt_res1); + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src1, src2, src3, src4, src5, src6, + vt_res2, vt_res3); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask3, + mask4, mask5, shf_vec6, shf_vec7, shf_vec8); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask3, + mask4, mask5, shf_vec9, shf_vec10, shf_vec11); + hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); + hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + hz_res2 = __msa_hadd_s_w(shf_vec6, shf_vec6); + hz_res3 = __msa_hadd_s_w(shf_vec9, shf_vec9); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); + DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + DPADD_SH2_SW(shf_vec7, shf_vec8, minus5h, plus20h, hz_res2, hz_res2); + DPADD_SH2_SW(shf_vec10, shf_vec11, minus5h, plus20h, hz_res3, hz_res3); + SRARI_W4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 10); + SAT_SW4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 7); + tmp0 = __msa_srari_h(shf_vec2, 5); + tmp1 = __msa_srari_h(shf_vec5, 5); + tmp2 = __msa_srari_h(shf_vec8, 5); + tmp3 = __msa_srari_h(shf_vec11, 5); + LD2(dst, stride, tp0, tp1); + INSERT_D2_UB(tp0, tp1, dst0); + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + PCKEV_H2_SH(tmp2, tmp0, tmp3, tmp1, tmp0, tmp1); + PCKEV_H2_SH(hz_res2, hz_res0, hz_res3, hz_res1, tmp2, tmp3); + tmp0 = __msa_aver_s_h(tmp2, tmp0); + tmp1 = __msa_aver_s_h(tmp3, tmp1); + out = PCKEV_XORI128_UB(tmp0, tmp1); + out = __msa_aver_u_b(out, dst0); + ST8x2_UB(out, dst, stride); + dst += (2 * stride); -void ff_avg_h264_qpel4_mc10_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_hz_qrt_and_aver_dst_4x4_msa(src - 2, stride, dst, stride, 0); + src0 = src2; + src1 = src3; + src2 = src4; + src3 = src5; + src4 = src6; + } } -void ff_avg_h264_qpel4_mc30_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel8_mc32_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hz_qrt_and_aver_dst_4x4_msa(src - 2, stride, dst, stride, 1); -} - -void ff_avg_h264_qpel16_mc20_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_hz_and_aver_dst_16x16_msa(src - 2, stride, dst, stride); -} + uint32_t row; + uint64_t tp0, tp1; + v16u8 out, dst0 = { 0 }; + v16i8 src0, src1, src2, src3, src4, src5, src6; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, tmp0, tmp1, tmp2, tmp3; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v8i16 shf_vec7, shf_vec8, shf_vec9, shf_vec10, shf_vec11; + v8i16 mask3, mask4, mask5; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; + v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; + v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; + v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; + v8i16 minus5h = __msa_ldi_h(-5); + v8i16 plus20h = __msa_ldi_h(20); -void ff_avg_h264_qpel8_mc20_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_hz_and_aver_dst_8x8_msa(src - 2, stride, dst, stride); -} + mask3 = mask0 + 4; + mask4 = mask1 + 4; + mask5 = mask2 + 4; -void ff_avg_h264_qpel4_mc20_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_hz_and_aver_dst_4x4_msa(src - 2, stride, dst, stride); -} + src -= ((2 * stride) + 2); -void ff_avg_h264_qpel16_mc01_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_vt_qrt_and_aver_dst_16x16_msa(src - (stride * 2), - stride, dst, stride, 0); -} + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + XORI_B5_128_SB(src0, src1, src2, src3, src4); -void ff_avg_h264_qpel16_mc03_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_vt_qrt_and_aver_dst_16x16_msa(src - (stride * 2), - stride, dst, stride, 1); -} + for (row = 4; row--;) { + LD_SB2(src, stride, src5, src6); + src += (2 * stride); + XORI_B2_128_SB(src5, src6); -void ff_avg_h264_qpel8_mc01_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_vt_qrt_and_aver_dst_8x8_msa(src - (stride * 2), - stride, dst, stride, 0); -} + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src0, src1, src2, src3, src4, src5, + vt_res0, vt_res1); + AVC_CALC_DPADD_B_6PIX_2COEFF_SH(src1, src2, src3, src4, src5, src6, + vt_res2, vt_res3); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask3, + mask4, mask5, shf_vec6, shf_vec7, shf_vec8); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask3, + mask4, mask5, shf_vec9, shf_vec10, shf_vec11); + hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); + hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + hz_res2 = __msa_hadd_s_w(shf_vec6, shf_vec6); + hz_res3 = __msa_hadd_s_w(shf_vec9, shf_vec9); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); + DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + DPADD_SH2_SW(shf_vec7, shf_vec8, minus5h, plus20h, hz_res2, hz_res2); + DPADD_SH2_SW(shf_vec10, shf_vec11, minus5h, plus20h, hz_res3, hz_res3); + SRARI_W4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 10); + SAT_SW4_SW(hz_res0, hz_res1, hz_res2, hz_res3, 7); + tmp0 = __msa_srari_h(shf_vec2, 5); + tmp1 = __msa_srari_h(shf_vec5, 5); + tmp2 = __msa_srari_h(shf_vec8, 5); + tmp3 = __msa_srari_h(shf_vec11, 5); + LD2(dst, stride, tp0, tp1); + INSERT_D2_UB(tp0, tp1, dst0); + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + tmp0 = __msa_pckod_h(tmp2, tmp0); + tmp1 = __msa_pckod_h(tmp3, tmp1); + PCKEV_H2_SH(hz_res2, hz_res0, hz_res3, hz_res1, tmp2, tmp3); + tmp0 = __msa_aver_s_h(tmp2, tmp0); + tmp1 = __msa_aver_s_h(tmp3, tmp1); + out = PCKEV_XORI128_UB(tmp0, tmp1); + out = __msa_aver_u_b(out, dst0); + ST8x2_UB(out, dst, stride); + dst += (2 * stride); -void ff_avg_h264_qpel8_mc03_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_vt_qrt_and_aver_dst_8x8_msa(src - (stride * 2), - stride, dst, stride, 1); + src0 = src2; + src1 = src3; + src2 = src4; + src3 = src5; + src4 = src6; + } } -void ff_avg_h264_qpel4_mc01_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel4_mc12_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_vt_qrt_and_aver_dst_4x4_msa(src - (stride * 2), - stride, dst, stride, 0); -} + uint32_t tp0, tp1, tp2, tp3; + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + v16u8 out, dstv = { 0 }; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 src10_r, src21_r, src32_r, src43_r, src54_r, src65_r, src76_r; + v16i8 src87_r, src10_l, src21_l, src32_l, src43_l, src54_l, src65_l; + v16i8 src76_l, src87_l, filt0, filt1, filt2; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, dst0, dst1, dst2, dst3, shf_vec7; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; + v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; + v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; + v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; + v8i16 minus5h = __msa_ldi_h(-5); + v8i16 plus20h = __msa_ldi_h(20); + v8i16 zeros = { 0 }; -void ff_avg_h264_qpel4_mc03_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_vt_qrt_and_aver_dst_4x4_msa(src - (stride * 2), - stride, dst, stride, 1); -} + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); -void ff_avg_h264_qpel16_mc11_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_hv_qrt_and_aver_dst_16x16_msa(src - 2, - src - (stride * 2), - stride, dst, stride); -} + src -= ((2 * stride) + 2); -void ff_avg_h264_qpel16_mc31_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_hv_qrt_and_aver_dst_16x16_msa(src - 2, - src - (stride * 2) + - sizeof(uint8_t), stride, - dst, stride); -} + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + LD_SB4(src, stride, src5, src6, src7, src8); + XORI_B4_128_SB(src5, src6, src7, src8); -void ff_avg_h264_qpel16_mc13_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_hv_qrt_and_aver_dst_16x16_msa(src + stride - 2, - src - (stride * 2), - stride, dst, stride); -} + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, src65_r, + src76_r, src87_r); + ILVL_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_l, src21_l, + src32_l, src43_l); + ILVL_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_l, src65_l, + src76_l, src87_l); + vt_res0 = AVC_DOT_SH3_SH(src10_r, src32_r, src54_r, filt0, filt1, filt2); + vt_res1 = AVC_DOT_SH3_SH(src10_l, src32_l, src54_l, filt0, filt1, filt2); + vt_res2 = AVC_DOT_SH3_SH(src21_r, src43_r, src65_r, filt0, filt1, filt2); + vt_res3 = AVC_DOT_SH3_SH(src21_l, src43_l, src65_l, filt0, filt1, filt2); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); + hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + + vt_res0 = AVC_DOT_SH3_SH(src32_r, src54_r, src76_r, filt0, filt1, filt2); + vt_res1 = AVC_DOT_SH3_SH(src32_l, src54_l, src76_l, filt0, filt1, filt2); + vt_res2 = AVC_DOT_SH3_SH(src43_r, src65_r, src87_r, filt0, filt1, filt2); + vt_res3 = AVC_DOT_SH3_SH(src43_l, src65_l, src87_l, filt0, filt1, filt2); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec6); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec7); + hz_res2 = __msa_hadd_s_w(shf_vec0, shf_vec0); + DPADD_SH2_SW(shf_vec1, shf_vec6, minus5h, plus20h, hz_res2, hz_res2); + hz_res3 = __msa_hadd_s_w(shf_vec3, shf_vec3); + DPADD_SH2_SW(shf_vec4, shf_vec7, minus5h, plus20h, hz_res3, hz_res3); + + SRARI_W2_SW(hz_res0, hz_res1, 10); + SAT_SW2_SW(hz_res0, hz_res1, 7); + SRARI_W2_SW(hz_res2, hz_res3, 10); + SAT_SW2_SW(hz_res2, hz_res3, 7); + + dst0 = __msa_srari_h(shf_vec2, 5); + dst1 = __msa_srari_h(shf_vec5, 5); + dst2 = __msa_srari_h(shf_vec6, 5); + dst3 = __msa_srari_h(shf_vec7, 5); + + SAT_SH2_SH(dst0, dst1, 7); + SAT_SH2_SH(dst2, dst3, 7); + ILVEV_H2_SH(dst0, zeros, dst1, zeros, dst0, dst1); + ILVEV_H2_SH(dst2, zeros, dst3, zeros, dst2, dst3); + + hz_res0 = __msa_aver_s_w(hz_res0, (v4i32) dst0); + hz_res1 = __msa_aver_s_w(hz_res1, (v4i32) dst1); + hz_res2 = __msa_aver_s_w(hz_res2, (v4i32) dst2); + hz_res3 = __msa_aver_s_w(hz_res3, (v4i32) dst3); -void ff_avg_h264_qpel16_mc33_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_hv_qrt_and_aver_dst_16x16_msa(src + stride - 2, - src - (stride * 2) + - sizeof(uint8_t), stride, - dst, stride); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dstv); + PCKEV_H2_SH(hz_res1, hz_res0, hz_res3, hz_res2, dst0, dst2); + out = PCKEV_XORI128_UB(dst0, dst2); + out = __msa_aver_u_b(out, dstv); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); } -void ff_avg_h264_qpel8_mc11_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel4_mc32_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_hv_qrt_and_aver_dst_8x8_msa(src - 2, - src - (stride * 2), - stride, dst, stride); -} + uint32_t tp0, tp1, tp2, tp3; + const int16_t filt_const0 = 0xfb01; + const int16_t filt_const1 = 0x1414; + const int16_t filt_const2 = 0x1fb; + v16u8 out, dstv = { 0 }; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 src10_r, src21_r, src32_r, src43_r, src54_r, src65_r, src76_r; + v16i8 src87_r, src10_l, src21_l, src32_l, src43_l, src54_l, src65_l; + v16i8 src76_l, src87_l, filt0, filt1, filt2; + v8i16 vt_res0, vt_res1, vt_res2, vt_res3, dst0, dst1, dst2, dst3, shf_vec7; + v8i16 shf_vec0, shf_vec1, shf_vec2, shf_vec3, shf_vec4, shf_vec5, shf_vec6; + v4i32 hz_res0, hz_res1, hz_res2, hz_res3; + v8i16 mask0 = { 0, 5, 1, 6, 2, 7, 3, 8 }; + v8i16 mask1 = { 1, 4, 2, 5, 3, 6, 4, 7 }; + v8i16 mask2 = { 2, 3, 3, 4, 4, 5, 5, 6 }; + v8i16 minus5h = __msa_ldi_h(-5); + v8i16 plus20h = __msa_ldi_h(20); + v8i16 zeros = { 0 }; -void ff_avg_h264_qpel8_mc31_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_hv_qrt_and_aver_dst_8x8_msa(src - 2, - src - (stride * 2) + - sizeof(uint8_t), stride, dst, stride); -} + filt0 = (v16i8) __msa_fill_h(filt_const0); + filt1 = (v16i8) __msa_fill_h(filt_const1); + filt2 = (v16i8) __msa_fill_h(filt_const2); -void ff_avg_h264_qpel8_mc13_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_hv_qrt_and_aver_dst_8x8_msa(src + stride - 2, - src - (stride * 2), - stride, dst, stride); -} + src -= ((2 * stride) + 2); -void ff_avg_h264_qpel8_mc33_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_hv_qrt_and_aver_dst_8x8_msa(src + stride - 2, - src - (stride * 2) + - sizeof(uint8_t), stride, dst, stride); -} + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + LD_SB4(src, stride, src5, src6, src7, src8); + XORI_B4_128_SB(src5, src6, src7, src8); + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, src65_r, + src76_r, src87_r); + ILVL_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_l, src21_l, + src32_l, src43_l); + ILVL_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_l, src65_l, + src76_l, src87_l); + vt_res0 = AVC_DOT_SH3_SH(src10_r, src32_r, src54_r, filt0, filt1, filt2); + vt_res1 = AVC_DOT_SH3_SH(src10_l, src32_l, src54_l, filt0, filt1, filt2); + vt_res2 = AVC_DOT_SH3_SH(src21_r, src43_r, src65_r, filt0, filt1, filt2); + vt_res3 = AVC_DOT_SH3_SH(src21_l, src43_l, src65_l, filt0, filt1, filt2); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec2); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec5); + hz_res0 = __msa_hadd_s_w(shf_vec0, shf_vec0); + DPADD_SH2_SW(shf_vec1, shf_vec2, minus5h, plus20h, hz_res0, hz_res0); + hz_res1 = __msa_hadd_s_w(shf_vec3, shf_vec3); + DPADD_SH2_SW(shf_vec4, shf_vec5, minus5h, plus20h, hz_res1, hz_res1); + + vt_res0 = AVC_DOT_SH3_SH(src32_r, src54_r, src76_r, filt0, filt1, filt2); + vt_res1 = AVC_DOT_SH3_SH(src32_l, src54_l, src76_l, filt0, filt1, filt2); + vt_res2 = AVC_DOT_SH3_SH(src43_r, src65_r, src87_r, filt0, filt1, filt2); + vt_res3 = AVC_DOT_SH3_SH(src43_l, src65_l, src87_l, filt0, filt1, filt2); + VSHF_H3_SH(vt_res0, vt_res1, vt_res0, vt_res1, vt_res0, vt_res1, mask0, + mask1, mask2, shf_vec0, shf_vec1, shf_vec6); + VSHF_H3_SH(vt_res2, vt_res3, vt_res2, vt_res3, vt_res2, vt_res3, mask0, + mask1, mask2, shf_vec3, shf_vec4, shf_vec7); + hz_res2 = __msa_hadd_s_w(shf_vec0, shf_vec0); + DPADD_SH2_SW(shf_vec1, shf_vec6, minus5h, plus20h, hz_res2, hz_res2); + hz_res3 = __msa_hadd_s_w(shf_vec3, shf_vec3); + DPADD_SH2_SW(shf_vec4, shf_vec7, minus5h, plus20h, hz_res3, hz_res3); + + SRARI_W2_SW(hz_res0, hz_res1, 10); + SAT_SW2_SW(hz_res0, hz_res1, 7); + SRARI_W2_SW(hz_res2, hz_res3, 10); + SAT_SW2_SW(hz_res2, hz_res3, 7); + + dst0 = __msa_srari_h(shf_vec2, 5); + dst1 = __msa_srari_h(shf_vec5, 5); + dst2 = __msa_srari_h(shf_vec6, 5); + dst3 = __msa_srari_h(shf_vec7, 5); + + SAT_SH2_SH(dst0, dst1, 7); + SAT_SH2_SH(dst2, dst3, 7); + + dst0 = __msa_ilvod_h(zeros, dst0); + dst1 = __msa_ilvod_h(zeros, dst1); + dst2 = __msa_ilvod_h(zeros, dst2); + dst3 = __msa_ilvod_h(zeros, dst3); + + hz_res0 = __msa_aver_s_w(hz_res0, (v4i32) dst0); + hz_res1 = __msa_aver_s_w(hz_res1, (v4i32) dst1); + hz_res2 = __msa_aver_s_w(hz_res2, (v4i32) dst2); + hz_res3 = __msa_aver_s_w(hz_res3, (v4i32) dst3); -void ff_avg_h264_qpel4_mc11_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_hv_qrt_and_aver_dst_4x4_msa(src - 2, - src - (stride * 2), - stride, dst, stride); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dstv); + PCKEV_H2_SH(hz_res1, hz_res0, hz_res3, hz_res2, dst0, dst2); + out = PCKEV_XORI128_UB(dst0, dst2); + out = __msa_aver_u_b(out, dstv); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, stride); } -void ff_avg_h264_qpel4_mc31_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) +void ff_avg_h264_qpel16_mc22_msa(uint8_t *dst, const uint8_t *src, + ptrdiff_t stride) { - avc_luma_hv_qrt_and_aver_dst_4x4_msa(src - 2, - src - (stride * 2) + - sizeof(uint8_t), stride, dst, stride); -} + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; + const uint8_t *src_tmp = src - (2 * stride) - 2; + uint8_t *dst_tmp = dst; + uint64_t tp0, tp1, tp2, tp3; + uint32_t multiple8_cnt, loop_cnt; + v16u8 dst0, dst1, out0, out1; + v16i8 src0, src1, src2, src3, src4, mask0, mask1, mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, res0, res1, res2, res3; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r, hz_out10_l, hz_out21_l; + v8i16 hz_out32_l, hz_out43_l, hz_out54_l, hz_out65_l, hz_out76_l; + v8i16 hz_out87_l, filt0, filt1, filt2; + v4i32 tmp0, tmp1; + + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); + + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); + + for (multiple8_cnt = 2; multiple8_cnt--;) { + src = src_tmp; + dst = dst_tmp; + + LD_SB5(src, stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + src += (5 * stride); -void ff_avg_h264_qpel4_mc13_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_hv_qrt_and_aver_dst_4x4_msa(src + stride - 2, - src - (stride * 2), - stride, dst, stride); -} + hz_out0 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); -void ff_avg_h264_qpel4_mc33_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_hv_qrt_and_aver_dst_4x4_msa(src + stride - 2, - src - (stride * 2) + - sizeof(uint8_t), stride, dst, stride); -} + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src, stride, src0, src1, src2, src3); + XORI_B4_128_SB(src0, src1, src2, src3); + src += (4 * stride); -void ff_avg_h264_qpel16_mc21_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_midv_qrt_and_aver_dst_16w_msa(src - (2 * stride) - 2, - stride, dst, stride, 16, 0); -} + hz_out5 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out7 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, + hz_out4, hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, + hz_out43_r); + ILVL_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, + hz_out4, hz_out3, hz_out10_l, hz_out21_l, hz_out32_l, + hz_out43_l); + ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, + hz_out8, hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, + hz_out87_r); + ILVL_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, + hz_out8, hz_out7, hz_out54_l, hz_out65_l, hz_out76_l, + hz_out87_l); -void ff_avg_h264_qpel16_mc23_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_midv_qrt_and_aver_dst_16w_msa(src - (2 * stride) - 2, - stride, dst, stride, 16, 1); -} + tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, + filt1, filt2); + res0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, + filt1, filt2); + res1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, + filt1, filt2); + res2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, + filt1, filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, + filt1, filt2); + res3 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + out0 = PCKEV_XORI128_UB(res0, res1); + out1 = PCKEV_XORI128_UB(res2, res3); + AVER_UB2_UB(out0, dst0, out1, dst1, out0, out1); + ST8x4_UB(out0, out1, dst, stride); + dst += (4 * stride); -void ff_avg_h264_qpel8_mc21_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_midv_qrt_and_aver_dst_8w_msa(src - (2 * stride) - 2, - stride, dst, stride, 8, 0); -} + hz_out0 = hz_out4; + hz_out1 = hz_out5; + hz_out2 = hz_out6; + hz_out3 = hz_out7; + hz_out4 = hz_out8; + } -void ff_avg_h264_qpel8_mc23_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_midv_qrt_and_aver_dst_8w_msa(src - (2 * stride) - 2, - stride, dst, stride, 8, 1); + src_tmp += 8; + dst_tmp += 8; + } } -void ff_avg_h264_qpel4_mc21_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel8_mc22_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_midv_qrt_and_aver_dst_4w_msa(src - (2 * stride) - 2, - stride, dst, stride, 4, 0); -} + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; + uint64_t tp0, tp1, tp2, tp3; + v16u8 out0, out1, dst0 = { 0 }, dst1 = { 0 }; + v16i8 src0, src1, src2, src3, src4, mask0, mask1, mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, hz_out9, hz_out10, hz_out11, hz_out12; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r, hz_out89_r, hz_out910_r; + v8i16 hz_out1110_r, hz_out1211_r, res0, res1, res2, res3; + v8i16 hz_out10_l, hz_out21_l, hz_out32_l, hz_out43_l, hz_out54_l; + v8i16 hz_out65_l, hz_out76_l, hz_out87_l, hz_out89_l, hz_out910_l; + v8i16 hz_out1110_l, hz_out1211_l, filt0, filt1, filt2; + v4i32 tmp0, tmp1; -void ff_avg_h264_qpel4_mc23_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_midv_qrt_and_aver_dst_4w_msa(src - (2 * stride) - 2, - stride, dst, stride, 4, 1); -} + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); -void ff_avg_h264_qpel16_mc02_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_vt_and_aver_dst_16x16_msa(src - (stride * 2), stride, dst, stride); -} + LD_SB3(&luma_mask_arr[0], 16, mask0, mask1, mask2); -void ff_avg_h264_qpel8_mc02_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_vt_and_aver_dst_8x8_msa(src - (stride * 2), stride, dst, stride); -} + src -= ((2 * stride) + 2); + LD_SB5(src, stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + src += (5 * stride); -void ff_avg_h264_qpel4_mc02_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_vt_and_aver_dst_4x4_msa(src - (stride * 2), stride, dst, stride); -} + hz_out0 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out1 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out3 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src4, mask0, mask1, mask2); -void ff_avg_h264_qpel16_mc12_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_midh_qrt_and_aver_dst_16w_msa(src - (2 * stride) - 2, - stride, dst, stride, 16, 0); -} + LD_SB4(src, stride, src0, src1, src2, src3); + XORI_B4_128_SB(src0, src1, src2, src3); + src += (4 * stride); + hz_out5 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out7 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r); + ILVL_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_l, hz_out21_l, hz_out32_l, hz_out43_l); + ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, hz_out87_r); + ILVL_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_l, hz_out65_l, hz_out76_l, hz_out87_l); -void ff_avg_h264_qpel16_mc32_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_midh_qrt_and_aver_dst_16w_msa(src - (2 * stride) - 2, - stride, dst, stride, 16, 1); -} + tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out10_l, hz_out32_l, hz_out54_l, filt0, filt1, + filt2); + res0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out21_l, hz_out43_l, hz_out65_l, filt0, filt1, + filt2); + res1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out32_l, hz_out54_l, hz_out76_l, filt0, filt1, + filt2); + res2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out43_l, hz_out65_l, hz_out87_l, filt0, filt1, + filt2); + res3 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + out0 = PCKEV_XORI128_UB(res0, res1); + out1 = PCKEV_XORI128_UB(res2, res3); + AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, stride); + dst += (4 * stride); -void ff_avg_h264_qpel8_mc12_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_midh_qrt_and_aver_dst_8w_msa(src - (2 * stride) - 2, - stride, dst, stride, 8, 0); + LD_SB4(src, stride, src0, src1, src2, src3); + XORI_B4_128_SB(src0, src1, src2, src3); + hz_out9 = AVC_HORZ_FILTER_SH(src0, src0, mask0, mask1, mask2); + hz_out10 = AVC_HORZ_FILTER_SH(src1, src1, mask0, mask1, mask2); + hz_out11 = AVC_HORZ_FILTER_SH(src2, src2, mask0, mask1, mask2); + hz_out12 = AVC_HORZ_FILTER_SH(src3, src3, mask0, mask1, mask2); + ILVR_H4_SH(hz_out9, hz_out8, hz_out10, hz_out9, hz_out11, hz_out10, + hz_out12, hz_out11, hz_out89_r, hz_out910_r, hz_out1110_r, + hz_out1211_r); + ILVL_H4_SH(hz_out9, hz_out8, hz_out10, hz_out9, hz_out11, hz_out10, + hz_out12, hz_out11, hz_out89_l, hz_out910_l, hz_out1110_l, + hz_out1211_l); + tmp0 = AVC_DOT_SW3_SW(hz_out54_r, hz_out76_r, hz_out89_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out54_l, hz_out76_l, hz_out89_l, filt0, filt1, + filt2); + res0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out65_r, hz_out87_r, hz_out910_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out65_l, hz_out87_l, hz_out910_l, filt0, filt1, + filt2); + res1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out76_r, hz_out89_r, hz_out1110_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out76_l, hz_out89_l, hz_out1110_l, filt0, filt1, + filt2); + res2 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out87_r, hz_out910_r, hz_out1211_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out87_l, hz_out910_l, hz_out1211_l, filt0, filt1, + filt2); + res3 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + LD4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_D2_UB(tp0, tp1, dst0); + INSERT_D2_UB(tp2, tp3, dst1); + out0 = PCKEV_XORI128_UB(res0, res1); + out1 = PCKEV_XORI128_UB(res2, res3); + AVER_UB2_UB(out0, dst0, out1, dst1, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, stride); } -void ff_avg_h264_qpel8_mc32_msa(uint8_t *dst, const uint8_t *src, +void ff_avg_h264_qpel4_mc22_msa(uint8_t *dst, const uint8_t *src, ptrdiff_t stride) { - avc_luma_midh_qrt_and_aver_dst_8w_msa(src - (2 * stride) - 2, - stride, dst, stride, 8, 1); -} + const int32_t filt_const0 = 0xfffb0001; + const int32_t filt_const1 = 0x140014; + const int32_t filt_const2 = 0x1fffb; + uint32_t tp0, tp1, tp2, tp3; + v16u8 res, dst0 = { 0 }; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 mask0, mask1, mask2; + v8i16 hz_out0, hz_out1, hz_out2, hz_out3, hz_out4, hz_out5, hz_out6; + v8i16 hz_out7, hz_out8, res0, res1, filt0, filt1, filt2; + v8i16 hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r, hz_out54_r; + v8i16 hz_out65_r, hz_out76_r, hz_out87_r; + v4i32 tmp0, tmp1; -void ff_avg_h264_qpel4_mc12_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_midh_qrt_and_aver_dst_4w_msa(src - (2 * stride) - 2, - stride, dst, stride, 4, 0); -} + LD_SB3(&luma_mask_arr[48], 16, mask0, mask1, mask2); -void ff_avg_h264_qpel4_mc32_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_midh_qrt_and_aver_dst_4w_msa(src - (2 * stride) - 2, - stride, dst, stride, 4, 1); -} + filt0 = (v8i16) __msa_fill_w(filt_const0); + filt1 = (v8i16) __msa_fill_w(filt_const1); + filt2 = (v8i16) __msa_fill_w(filt_const2); -void ff_avg_h264_qpel16_mc22_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_mid_and_aver_dst_16x16_msa(src - (2 * stride) - 2, - stride, dst, stride); -} + src -= ((2 * stride) + 2); -void ff_avg_h264_qpel8_mc22_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_mid_and_aver_dst_8w_msa(src - (2 * stride) - 2, - stride, dst, stride, 8); -} + LD_SB5(src, stride, src0, src1, src2, src3, src4); + src += (5 * stride); + LD_SB4(src, stride, src5, src6, src7, src8); -void ff_avg_h264_qpel4_mc22_msa(uint8_t *dst, const uint8_t *src, - ptrdiff_t stride) -{ - avc_luma_mid_and_aver_dst_4x4_msa(src - (2 * stride) - 2, - stride, dst, stride); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B4_128_SB(src5, src6, src7, src8); + hz_out0 = AVC_HORZ_FILTER_SH(src0, src1, mask0, mask1, mask2); + hz_out2 = AVC_HORZ_FILTER_SH(src2, src3, mask0, mask1, mask2); + hz_out4 = AVC_HORZ_FILTER_SH(src4, src5, mask0, mask1, mask2); + hz_out6 = AVC_HORZ_FILTER_SH(src6, src7, mask0, mask1, mask2); + hz_out8 = AVC_HORZ_FILTER_SH(src8, src8, mask0, mask1, mask2); + PCKOD_D2_SH(hz_out0, hz_out0, hz_out2, hz_out2, hz_out1, hz_out3); + PCKOD_D2_SH(hz_out4, hz_out4, hz_out6, hz_out6, hz_out5, hz_out7); + ILVR_H4_SH(hz_out1, hz_out0, hz_out2, hz_out1, hz_out3, hz_out2, hz_out4, + hz_out3, hz_out10_r, hz_out21_r, hz_out32_r, hz_out43_r); + ILVR_H4_SH(hz_out5, hz_out4, hz_out6, hz_out5, hz_out7, hz_out6, hz_out8, + hz_out7, hz_out54_r, hz_out65_r, hz_out76_r, hz_out87_r); + + tmp0 = AVC_DOT_SW3_SW(hz_out10_r, hz_out32_r, hz_out54_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out21_r, hz_out43_r, hz_out65_r, filt0, filt1, + filt2); + res0 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + tmp0 = AVC_DOT_SW3_SW(hz_out32_r, hz_out54_r, hz_out76_r, filt0, filt1, + filt2); + tmp1 = AVC_DOT_SW3_SW(hz_out43_r, hz_out65_r, hz_out87_r, filt0, filt1, + filt2); + res1 = __msa_pckev_h((v8i16) tmp1, (v8i16) tmp0); + LW4(dst, stride, tp0, tp1, tp2, tp3); + INSERT_W4_UB(tp0, tp1, tp2, tp3, dst0); + res = PCKEV_XORI128_UB(res0, res1); + res = __msa_aver_u_b(res, dst0); + ST4x4_UB(res, res, 0, 1, 2, 3, dst, stride); } diff --git a/libavcodec/mips/hevc_macros_msa.h b/libavcodec/mips/hevc_macros_msa.h index 7dcfea03b41c9..ea53812b6490f 100644 --- a/libavcodec/mips/hevc_macros_msa.h +++ b/libavcodec/mips/hevc_macros_msa.h @@ -21,43 +21,6 @@ #ifndef AVCODEC_MIPS_HEVC_MACROS_MSA_H #define AVCODEC_MIPS_HEVC_MACROS_MSA_H -#define HEVC_PCK_SW_SB2(in0, in1, out) \ -{ \ - v8i16 tmp0_m; \ - \ - tmp0_m = __msa_pckev_h((v8i16) in0, (v8i16) in1); \ - out = (v4i32) __msa_pckev_b((v16i8) tmp0_m, (v16i8) tmp0_m); \ -} - -#define HEVC_PCK_SW_SB4(in0, in1, in2, in3, out) \ -{ \ - v8i16 tmp0_m, tmp1_m; \ - \ - PCKEV_H2_SH(in0, in1, in2, in3, tmp0_m, tmp1_m); \ - out = (v4i32) __msa_pckev_b((v16i8) tmp1_m, (v16i8) tmp0_m); \ -} - -#define HEVC_PCK_SW_SB8(in0, in1, in2, in3, in4, in5, in6, in7, out0, out1) \ -{ \ - v8i16 tmp0_m, tmp1_m, tmp2_m, tmp3_m; \ - \ - PCKEV_H4_SH(in0, in1, in2, in3, in4, in5, in6, in7, \ - tmp0_m, tmp1_m, tmp2_m, tmp3_m); \ - PCKEV_B2_SW(tmp1_m, tmp0_m, tmp3_m, tmp2_m, out0, out1); \ -} - -#define HEVC_PCK_SW_SB12(in0, in1, in2, in3, in4, in5, in6, in7, \ - in8, in9, in10, in11, out0, out1, out2) \ -{ \ - v8i16 tmp0_m, tmp1_m, tmp2_m, tmp3_m, tmp4_m, tmp5_m; \ - \ - PCKEV_H4_SH(in0, in1, in2, in3, in4, in5, in6, in7, \ - tmp0_m, tmp1_m, tmp2_m, tmp3_m); \ - PCKEV_H2_SH(in8, in9, in10, in11, tmp4_m, tmp5_m); \ - PCKEV_B2_SW(tmp1_m, tmp0_m, tmp3_m, tmp2_m, out0, out1); \ - out2 = (v4i32) __msa_pckev_b((v16i8) tmp5_m, (v16i8) tmp4_m); \ -} - #define HEVC_FILT_8TAP_SH(in0, in1, in2, in3, \ filt0, filt1, filt2, filt3) \ ( { \ @@ -80,6 +43,15 @@ out_m; \ } ) +#define HEVC_FILT_4TAP_SH(in0, in1, filt0, filt1) \ +( { \ + v8i16 out_m; \ + \ + out_m = __msa_dotp_s_h((v16i8) in0, (v16i8) filt0); \ + out_m = __msa_dpadd_s_h(out_m, (v16i8) in1, (v16i8) filt1); \ + out_m; \ +} ) + #define HEVC_FILT_4TAP(in0, in1, filt0, filt1) \ ( { \ v4i32 out_m; \ diff --git a/libavcodec/mips/hevc_mc_bi_msa.c b/libavcodec/mips/hevc_mc_bi_msa.c index 8208be327dabf..b555517b27d7e 100644 --- a/libavcodec/mips/hevc_mc_bi_msa.c +++ b/libavcodec/mips/hevc_mc_bi_msa.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Manojkumar Bhosale (Manojkumar.Bhosale@imgtec.com) + * Copyright (c) 2015 - 2017 Manojkumar Bhosale (Manojkumar.Bhosale@imgtec.com) * * This file is part of FFmpeg. * @@ -22,6 +22,12 @@ #include "libavcodec/mips/hevcdsp_mips.h" #include "libavcodec/mips/hevc_macros_msa.h" +static const uint8_t ff_hevc_mask_arr[16 * 2] __attribute__((aligned(0x40))) = { + /* 8 width cases */ + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, + 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 +}; + #define HEVC_BI_RND_CLIP2(in0, in1, vec0, vec1, rnd_val, out0, out1) \ { \ ADDS_SH2_SH(vec0, in0, vec1, in1, out0, out1); \ @@ -37,6 +43,21 @@ HEVC_BI_RND_CLIP2(in2, in3, vec2, vec3, rnd_val, out2, out3); \ } +#define HEVC_BI_RND_CLIP2_MAX_SATU(in0, in1, vec0, vec1, rnd_val, \ + out0, out1) \ +{ \ + ADDS_SH2_SH(vec0, in0, vec1, in1, out0, out1); \ + SRARI_H2_SH(out0, out1, rnd_val); \ + CLIP_SH2_0_255_MAX_SATU(out0, out1); \ +} + +#define HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, vec0, vec1, vec2, \ + vec3, rnd_val, out0, out1, out2, out3) \ +{ \ + HEVC_BI_RND_CLIP2_MAX_SATU(in0, in1, vec0, vec1, rnd_val, out0, out1); \ + HEVC_BI_RND_CLIP2_MAX_SATU(in2, in3, vec2, vec3, rnd_val, out2, out3); \ +} + static void hevc_bi_copy_4w_msa(uint8_t *src0_ptr, int32_t src_stride, int16_t *src1_ptr, @@ -45,71 +66,59 @@ static void hevc_bi_copy_4w_msa(uint8_t *src0_ptr, int32_t dst_stride, int32_t height) { + uint32_t loop_cnt, tp0, tp1, tp2, tp3; + uint64_t tpd0, tpd1, tpd2, tpd3; + v16i8 src0 = { 0 }, src1 = { 0 }; v16i8 zero = { 0 }; + v8i16 in0 = { 0 }, in1 = { 0 }, in2 = { 0 }, in3 = { 0 }; + v8i16 dst0, dst1, dst2, dst3; if (2 == height) { - v16i8 src0, src1; - v8i16 dst0, in0, in1; - - LD_SB2(src0_ptr, src_stride, src0, src1); - LD_SH2(src1_ptr, src2_stride, in0, in1); - - src0 = (v16i8) __msa_ilvr_w((v4i32) src1, (v4i32) src0); - in0 = (v8i16) __msa_ilvr_d((v2i64) in1, (v2i64) in0); + LW2(src0_ptr, src_stride, tp0, tp1); + INSERT_W2_SB(tp0, tp1, src0); + LD2(src1_ptr, src2_stride, tpd0, tpd1); + INSERT_D2_SH(tpd0, tpd1, in0); dst0 = (v8i16) __msa_ilvr_b(zero, src0); dst0 <<= 6; dst0 += in0; dst0 = __msa_srari_h(dst0, 7); - dst0 = CLIP_SH_0_255(dst0); + dst0 = CLIP_SH_0_255_MAX_SATU(dst0); dst0 = (v8i16) __msa_pckev_b((v16i8) dst0, (v16i8) dst0); ST4x2_UB(dst0, dst, dst_stride); } else if (4 == height) { - v16i8 src0, src1, src2, src3; - v8i16 dst0, dst1; - v8i16 in0, in1, in2, in3; - - LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); - LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); - ILVR_W2_SB(src1, src0, src3, src2, src0, src1); - ILVR_D2_SH(in1, in0, in3, in2, in0, in1); - ILVR_B2_SH(zero, src0, zero, src1, dst0, dst1); - - dst0 <<= 6; - dst1 <<= 6; - HEVC_BI_RND_CLIP2(in0, in1, dst0, dst1, 7, dst0, dst1); - + LW4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + INSERT_W4_SB(tp0, tp1, tp2, tp3, src0); + LD4(src1_ptr, src2_stride, tpd0, tpd1, tpd2, tpd3); + INSERT_D2_SH(tpd0, tpd1, in0); + INSERT_D2_SH(tpd2, tpd3, in1); + ILVRL_B2_SH(zero, src0, dst0, dst1); + SLLI_2V(dst0, dst1, 6); + HEVC_BI_RND_CLIP2_MAX_SATU(in0, in1, dst0, dst1, 7, dst0, dst1); dst0 = (v8i16) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, dst_stride); } else if (0 == height % 8) { - uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7; - v8i16 dst0, dst1, dst2, dst3; - v8i16 in0, in1, in2, in3, in4, in5, in6, in7; - for (loop_cnt = (height >> 3); loop_cnt--;) { - LD_SB8(src0_ptr, src_stride, - src0, src1, src2, src3, src4, src5, src6, src7); - src0_ptr += (8 * src_stride); - - LD_SH8(src1_ptr, src2_stride, - in0, in1, in2, in3, in4, in5, in6, in7); - src1_ptr += (8 * src2_stride); - - ILVR_D2_SH(in1, in0, in3, in2, in0, in1); - ILVR_D2_SH(in5, in4, in7, in6, in2, in3); - - ILVR_W4_SB(src1, src0, src3, src2, src5, src4, src7, src6, - src0, src1, src2, src3); - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0, dst1, dst2, dst3); - + LW4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + src0_ptr += 4 * src_stride; + INSERT_W4_SB(tp0, tp1, tp2, tp3, src0); + LW4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + src0_ptr += 4 * src_stride; + INSERT_W4_SB(tp0, tp1, tp2, tp3, src1); + LD4(src1_ptr, src2_stride, tpd0, tpd1, tpd2, tpd3); + src1_ptr += (4 * src2_stride); + INSERT_D2_SH(tpd0, tpd1, in0); + INSERT_D2_SH(tpd2, tpd3, in1); + LD4(src1_ptr, src2_stride, tpd0, tpd1, tpd2, tpd3); + src1_ptr += (4 * src2_stride); + INSERT_D2_SH(tpd0, tpd1, in2); + INSERT_D2_SH(tpd2, tpd3, in3); + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); SLLI_4V(dst0, dst1, dst2, dst3, 6); - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - dst0, dst1, dst2, dst3, 7, - dst0, dst1, dst2, dst3); - + HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, dst0, dst1, dst2, + dst3, 7, dst0, dst1, dst2, dst3); PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); ST4x8_UB(dst0, dst1, dst, dst_stride); dst += (8 * dst_stride); @@ -126,36 +135,39 @@ static void hevc_bi_copy_6w_msa(uint8_t *src0_ptr, int32_t height) { uint32_t loop_cnt; + uint64_t tp0, tp1, tp2, tp3; + v16u8 out0, out1, out2, out3; v16i8 zero = { 0 }; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7; + v16i8 src0 = { 0 }, src1 = { 0 }, src2 = { 0 }, src3 = { 0 }; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; for (loop_cnt = (height >> 3); loop_cnt--;) { - LD_SB8(src0_ptr, src_stride, - src0, src1, src2, src3, src4, src5, src6, src7); - src0_ptr += (8 * src_stride); + LD4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + src0_ptr += (4 * src_stride); + INSERT_D2_SB(tp0, tp1, src0); + INSERT_D2_SB(tp2, tp3, src1); + LD4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + src0_ptr += (4 * src_stride); + INSERT_D2_SB(tp0, tp1, src2); + INSERT_D2_SB(tp2, tp3, src3); LD_SH8(src1_ptr, src2_stride, in0, in1, in2, in3, in4, in5, in6, in7); src1_ptr += (8 * src2_stride); - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0, dst1, dst2, dst3); - ILVR_B4_SH(zero, src4, zero, src5, zero, src6, zero, src7, - dst4, dst5, dst6, dst7); - + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); + ILVRL_B2_SH(zero, src2, dst4, dst5); + ILVRL_B2_SH(zero, src3, dst6, dst7); SLLI_4V(dst0, dst1, dst2, dst3, 6); SLLI_4V(dst4, dst5, dst6, dst7, 6); - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); - - PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); - ST6x4_UB(dst0, dst1, dst, dst_stride); + HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, dst0, dst1, dst2, dst3, + 7, dst0, dst1, dst2, dst3); + HEVC_BI_RND_CLIP4_MAX_SATU(in4, in5, in6, in7, dst4, dst5, dst6, dst7, + 7, dst4, dst5, dst6, dst7); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); + ST6x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); - - HEVC_BI_RND_CLIP4(in4, in5, in6, in7, - dst4, dst5, dst6, dst7, 7, dst4, dst5, dst6, dst7); - - PCKEV_B2_SH(dst5, dst4, dst7, dst6, dst4, dst5); - ST6x4_UB(dst4, dst5, dst, dst_stride); + ST6x4_UB(out2, out3, dst, dst_stride); dst += (4 * dst_stride); } } @@ -168,100 +180,83 @@ static void hevc_bi_copy_8w_msa(uint8_t *src0_ptr, int32_t dst_stride, int32_t height) { + uint64_t tp0, tp1, tp2, tp3; + v16u8 out0, out1, out2, out3; + v16i8 src0 = { 0 }, src1 = { 0 }, src2 = { 0 }, src3 = { 0 }; v16i8 zero = { 0 }; + v8i16 in0, in1, in2, in3, in4, in5, in6, in7; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; if (2 == height) { - v16i8 src0, src1; - v8i16 in0, in1; - v8i16 dst0, dst1; - - LD_SB2(src0_ptr, src_stride, src0, src1); + LD2(src0_ptr, src_stride, tp0, tp1); + INSERT_D2_SB(tp0, tp1, src0); LD_SH2(src1_ptr, src2_stride, in0, in1); - ILVR_B2_SH(zero, src0, zero, src1, dst0, dst1); - - dst0 <<= 6; - dst1 <<= 6; - HEVC_BI_RND_CLIP2(in0, in1, dst0, dst1, 7, dst0, dst1); - - dst0 = (v8i16) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); - ST8x2_UB(dst0, dst, dst_stride); + ILVRL_B2_SH(zero, src0, dst0, dst1); + SLLI_2V(dst0, dst1, 6); + HEVC_BI_RND_CLIP2_MAX_SATU(in0, in1, dst0, dst1, 7, dst0, dst1); + out0 = (v16u8) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); + ST8x2_UB(out0, dst, dst_stride); } else if (4 == height) { - v16i8 src0, src1, src2, src3; - v8i16 in0, in1, in2, in3; - v8i16 dst0, dst1, dst2, dst3; - - LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); + LD4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + INSERT_D2_SB(tp0, tp1, src0); + INSERT_D2_SB(tp2, tp3, src1); + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0, dst1, dst2, dst3); - SLLI_4V(dst0, dst1, dst2, dst3, 6); - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); - - PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); - ST8x4_UB(dst0, dst1, dst, dst_stride); + HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, dst0, dst1, dst2, dst3, + 7, dst0, dst1, dst2, dst3); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + ST8x4_UB(out0, out1, dst, dst_stride); } else if (6 == height) { - v16i8 src0, src1, src2, src3, src4, src5; - v8i16 in0, in1, in2, in3, in4, in5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - - LD_SB6(src0_ptr, src_stride, src0, src1, src2, src3, src4, src5); + LD4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + src0_ptr += 4 * src_stride; + INSERT_D2_SB(tp0, tp1, src0); + INSERT_D2_SB(tp2, tp3, src1); + LD2(src0_ptr, src_stride, tp0, tp1); + INSERT_D2_SB(tp0, tp1, src2); + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); + ILVRL_B2_SH(zero, src2, dst4, dst5); LD_SH6(src1_ptr, src2_stride, in0, in1, in2, in3, in4, in5); - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0, dst1, dst2, dst3); - ILVR_B2_SH(zero, src4, zero, src5, dst4, dst5); - SLLI_4V(dst0, dst1, dst2, dst3, 6); - dst4 <<= 6; - dst5 <<= 6; - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); - HEVC_BI_RND_CLIP2(in4, in5, dst4, dst5, 7, dst4, dst5); - - PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); - dst2 = (v8i16) __msa_pckev_b((v16i8) dst5, (v16i8) dst4); - ST8x4_UB(dst0, dst1, dst, dst_stride); + SLLI_2V(dst4, dst5, 6); + HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, dst0, dst1, dst2, dst3, + 7, dst0, dst1, dst2, dst3); + HEVC_BI_RND_CLIP2_MAX_SATU(in4, in5, dst4, dst5, 7, dst4, dst5); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + ST8x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); - ST8x2_UB(dst2, dst, dst_stride); + ST8x2_UB(out2, dst, dst_stride); } else if (0 == height % 8) { - v16i8 src0, src1, src2, src3; - v8i16 in0, in1, in2, in3; - v8i16 dst0, dst1, dst2, dst3; uint32_t loop_cnt; for (loop_cnt = (height >> 3); loop_cnt--;) { - LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); - src0_ptr += (4 * src_stride); - LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); - src1_ptr += (4 * src2_stride); - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0, dst1, dst2, dst3); - - SLLI_4V(dst0, dst1, dst2, dst3, 6); - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - dst0, dst1, dst2, dst3, 7, - dst0, dst1, dst2, dst3); - - PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); - ST8x4_UB(dst0, dst1, dst, dst_stride); - dst += (4 * dst_stride); - - LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); - src0_ptr += (4 * src_stride); - LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); - src1_ptr += (4 * src2_stride); - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0, dst1, dst2, dst3); - + LD4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + src0_ptr += 4 * src_stride; + INSERT_D2_SB(tp0, tp1, src0); + INSERT_D2_SB(tp2, tp3, src1); + LD4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + src0_ptr += 4 * src_stride; + INSERT_D2_SB(tp0, tp1, src2); + INSERT_D2_SB(tp2, tp3, src3); + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); + ILVRL_B2_SH(zero, src2, dst4, dst5); + ILVRL_B2_SH(zero, src3, dst6, dst7); + LD_SH8(src1_ptr, src2_stride, in0, in1, in2, in3, in4, in5, in6, + in7); + src1_ptr += (8 * src2_stride); SLLI_4V(dst0, dst1, dst2, dst3, 6); - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - dst0, dst1, dst2, dst3, 7, - dst0, dst1, dst2, dst3); - - PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); - ST8x4_UB(dst0, dst1, dst, dst_stride); - dst += (4 * dst_stride); + SLLI_4V(dst4, dst5, dst6, dst7, 6); + HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, dst0, dst1, dst2, + dst3, 7, dst0, dst1, dst2, dst3); + HEVC_BI_RND_CLIP4_MAX_SATU(in4, in5, in6, in7, dst4, dst5, dst6, + dst7, 7, dst4, dst5, dst6, dst7); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); + ST8x8_UB(out0, out1, out2, out3, dst, dst_stride); + dst += (8 * dst_stride); } } } @@ -275,12 +270,13 @@ static void hevc_bi_copy_12w_msa(uint8_t *src0_ptr, int32_t height) { uint32_t loop_cnt; + v16i8 zero = { 0 }; + v16u8 out0, out1, out2; v16i8 src0, src1, src2, src3; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v16i8 zero = { 0 }; - for (loop_cnt = (16 >> 2); loop_cnt--;) { + for (loop_cnt = 4; loop_cnt--;) { LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); src0_ptr += (4 * src_stride); @@ -288,88 +284,21 @@ static void hevc_bi_copy_12w_msa(uint8_t *src0_ptr, LD_SH4(src1_ptr + 8, src2_stride, in4, in5, in6, in7); src1_ptr += (4 * src2_stride); ILVR_D2_SH(in5, in4, in7, in6, in4, in5); - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0, dst1, dst2, dst3); - + ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, dst0, dst1, + dst2, dst3); SLLI_4V(dst0, dst1, dst2, dst3, 6); ILVL_W2_SB(src1, src0, src3, src2, src0, src1); ILVR_B2_SH(zero, src0, zero, src1, dst4, dst5); - dst4 <<= 6; - dst5 <<= 6; - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); - HEVC_BI_RND_CLIP2(in4, in5, dst4, dst5, 7, dst4, dst5); - - PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); - dst2 = (v8i16) __msa_pckev_b((v16i8) dst5, (v16i8) dst4); - ST12x4_UB(dst0, dst1, dst2, dst, dst_stride); + SLLI_2V(dst4, dst5, 6); + HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, dst0, dst1, dst2, dst3, + 7, dst0, dst1, dst2, dst3); + HEVC_BI_RND_CLIP2_MAX_SATU(in4, in5, dst4, dst5, 7, dst4, dst5); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + ST12x4_UB(out0, out1, out2, dst, dst_stride); dst += (4 * dst_stride); } } -static void hevc_bi_copy_16multx4mult_msa(uint8_t *src0_ptr, - int32_t src_stride, - int16_t *src1_ptr, - int32_t src2_stride, - uint8_t *dst, - int32_t dst_stride, - int32_t height, - int32_t width) -{ - uint32_t loop_cnt; - uint32_t cnt; - uint8_t *src0_ptr_tmp; - int16_t *src1_ptr_tmp; - uint8_t *dst_tmp; - v16i8 zero = { 0 }; - - for (cnt = (width >> 4); cnt--;) { - src0_ptr_tmp = src0_ptr; - src1_ptr_tmp = src1_ptr; - dst_tmp = dst; - - for (loop_cnt = (height >> 2); loop_cnt--;) { - v16i8 src0, src1, src2, src3; - v8i16 in0, in1, in2, in3, in4, in5, in6, in7; - v8i16 dst0_r, dst1_r, dst2_r, dst3_r; - v8i16 dst0_l, dst1_l, dst2_l, dst3_l; - - LD_SB4(src0_ptr_tmp, src_stride, src0, src1, src2, src3); - src0_ptr_tmp += (4 * src_stride); - LD_SH4(src1_ptr_tmp, src2_stride, in0, in1, in2, in3); - LD_SH4(src1_ptr_tmp + 8, src2_stride, in4, in5, in6, in7); - src1_ptr_tmp += (4 * src2_stride); - - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0_r, dst1_r, dst2_r, dst3_r); - ILVL_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0_l, dst1_l, dst2_l, dst3_l); - - SLLI_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); - SLLI_4V(dst0_l, dst1_l, dst2_l, dst3_l, 6); - HEVC_BI_RND_CLIP4(in0, in1, in4, in5, - dst0_r, dst1_r, dst0_l, dst1_l, 7, - dst0_r, dst1_r, dst0_l, dst1_l); - - PCKEV_B2_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r, dst1_r); - ST_SH2(dst0_r, dst1_r, dst_tmp, dst_stride); - dst_tmp += (2 * dst_stride); - - HEVC_BI_RND_CLIP4(in2, in3, in6, in7, - dst2_r, dst3_r, dst2_l, dst3_l, 7, - dst2_r, dst3_r, dst2_l, dst3_l); - - PCKEV_B2_SH(dst2_l, dst2_r, dst3_l, dst3_r, dst2_r, dst3_r); - ST_SH2(dst2_r, dst3_r, dst_tmp, dst_stride); - dst_tmp += (2 * dst_stride); - } - - src0_ptr += 16; - src1_ptr += 16; - dst += 16; - } -} - static void hevc_bi_copy_16w_msa(uint8_t *src0_ptr, int32_t src_stride, int16_t *src1_ptr, @@ -378,8 +307,34 @@ static void hevc_bi_copy_16w_msa(uint8_t *src0_ptr, int32_t dst_stride, int32_t height) { - hevc_bi_copy_16multx4mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, height, 16); + uint32_t loop_cnt; + v16u8 out0, out1, out2, out3; + v16i8 src0, src1, src2, src3; + v8i16 in0, in1, in2, in3, in4, in5, in6, in7; + v8i16 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; + v16i8 zero = { 0 }; + + for (loop_cnt = (height >> 2); loop_cnt--;) { + LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); + src0_ptr += (4 * src_stride); + LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); + LD_SH4(src1_ptr + 8, src2_stride, in4, in5, in6, in7); + src1_ptr += (4 * src2_stride); + ILVRL_B2_SH(zero, src0, dst0_r, dst0_l); + ILVRL_B2_SH(zero, src1, dst1_r, dst1_l); + ILVRL_B2_SH(zero, src2, dst2_r, dst2_l); + ILVRL_B2_SH(zero, src3, dst3_r, dst3_l); + SLLI_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SLLI_4V(dst0_l, dst1_l, dst2_l, dst3_l, 6); + HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in4, in5, dst0_r, dst1_r, dst0_l, + dst1_l, 7, dst0_r, dst1_r, dst0_l, dst1_l); + HEVC_BI_RND_CLIP4_MAX_SATU(in2, in3, in6, in7, dst2_r, dst3_r, dst2_l, + dst3_l, 7, dst2_r, dst3_r, dst2_l, dst3_l); + PCKEV_B2_UB(dst0_l, dst0_r, dst1_l, dst1_r, out0, out1); + PCKEV_B2_UB(dst2_l, dst2_r, dst3_l, dst3_r, out2, out3); + ST_UB4(out0, out1, out2, out3, dst, dst_stride); + dst += (4 * dst_stride); + } } static void hevc_bi_copy_24w_msa(uint8_t *src0_ptr, @@ -390,11 +345,42 @@ static void hevc_bi_copy_24w_msa(uint8_t *src0_ptr, int32_t dst_stride, int32_t height) { - hevc_bi_copy_16multx4mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, height, 16); + uint32_t loop_cnt; + v16u8 out0, out1, out2, out3, out4, out5; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, zero = { 0 }; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8, dst9, dst10; + v8i16 in0, in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, dst11; + + for (loop_cnt = 8; loop_cnt--;) { + LD_SB4(src0_ptr, src_stride, src0, src1, src4, src5); + LD_SB4(src0_ptr + 16, src_stride, src2, src3, src6, src7); + src0_ptr += (4 * src_stride); + LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); + LD_SH4(src1_ptr + 8, src2_stride, in4, in5, in6, in7); + LD_SH4(src1_ptr + 16, src2_stride, in8, in9, in10, in11); + src1_ptr += (4 * src2_stride); - hevc_bi_copy_8w_msa(src0_ptr + 16, src_stride, src1_ptr + 16, src2_stride, - dst + 16, dst_stride, height); + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); + ILVR_B2_SH(zero, src2, zero, src3, dst4, dst5); + ILVRL_B2_SH(zero, src4, dst6, dst7); + ILVRL_B2_SH(zero, src5, dst8, dst9); + ILVR_B2_SH(zero, src6, zero, src7, dst10, dst11); + SLLI_4V(dst0, dst1, dst2, dst3, 6); + SLLI_4V(dst4, dst5, dst6, dst7, 6); + SLLI_4V(dst8, dst9, dst10, dst11, 6); + HEVC_BI_RND_CLIP4_MAX_SATU(in0, in4, in1, in5, dst0, dst1, dst2, dst3, + 7, dst0, dst1, dst2, dst3); + HEVC_BI_RND_CLIP4_MAX_SATU(in8, in9, in2, in6, dst4, dst5, dst6, dst7, + 7, dst4, dst5, dst6, dst7); + HEVC_BI_RND_CLIP4_MAX_SATU(in3, in7, in10, in11, dst8, dst9, dst10, + dst11, 7, dst8, dst9, dst10, dst11); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + PCKEV_B3_UB(dst7, dst6, dst9, dst8, dst11, dst10, out3, out4, out5); + ST_UB4(out0, out1, out3, out4, dst, dst_stride); + ST8x4_UB(out2, out5, dst + 16, dst_stride); + dst += (4 * dst_stride); + } } static void hevc_bi_copy_32w_msa(uint8_t *src0_ptr, @@ -405,8 +391,40 @@ static void hevc_bi_copy_32w_msa(uint8_t *src0_ptr, int32_t dst_stride, int32_t height) { - hevc_bi_copy_16multx4mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, height, 32); + uint32_t loop_cnt; + v16u8 out0, out1, out2, out3; + v16i8 src0, src1, src2, src3; + v16i8 zero = { 0 }; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 in0, in1, in2, in3, in4, in5, in6, in7; + + for (loop_cnt = (height >> 1); loop_cnt--;) { + LD_SB2(src0_ptr, 16, src0, src1); + src0_ptr += src_stride; + LD_SB2(src0_ptr, 16, src2, src3); + src0_ptr += src_stride; + LD_SH4(src1_ptr, 8, in0, in1, in2, in3); + src1_ptr += src2_stride; + LD_SH4(src1_ptr, 8, in4, in5, in6, in7); + src1_ptr += src2_stride; + + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); + ILVRL_B2_SH(zero, src2, dst4, dst5); + ILVRL_B2_SH(zero, src3, dst6, dst7); + SLLI_4V(dst0, dst1, dst2, dst3, 6); + SLLI_4V(dst4, dst5, dst6, dst7, 6); + HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, dst0, dst1, dst2, dst3, + 7, dst0, dst1, dst2, dst3); + HEVC_BI_RND_CLIP4_MAX_SATU(in4, in5, in6, in7, dst4, dst5, dst6, dst7, + 7, dst4, dst5, dst6, dst7); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); + ST_UB2(out0, out1, dst, 16); + dst += dst_stride; + ST_UB2(out2, out3, dst, 16); + dst += dst_stride; + } } static void hevc_bi_copy_48w_msa(uint8_t *src0_ptr, @@ -417,8 +435,50 @@ static void hevc_bi_copy_48w_msa(uint8_t *src0_ptr, int32_t dst_stride, int32_t height) { - hevc_bi_copy_16multx4mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, height, 48); + uint32_t loop_cnt; + v16u8 out0, out1, out2, out3, out4, out5; + v16i8 src0, src1, src2, src3, src4, src5; + v16i8 zero = { 0 }; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8, dst9, dst10; + v8i16 in0, in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, dst11; + + for (loop_cnt = (height >> 1); loop_cnt--;) { + LD_SB3(src0_ptr, 16, src0, src1, src2); + src0_ptr += src_stride; + LD_SB3(src0_ptr, 16, src3, src4, src5); + src0_ptr += src_stride; + + LD_SH6(src1_ptr, 8, in0, in1, in2, in3, in4, in5); + src1_ptr += src2_stride; + LD_SH6(src1_ptr, 8, in6, in7, in8, in9, in10, in11); + src1_ptr += src2_stride; + + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); + ILVRL_B2_SH(zero, src2, dst4, dst5); + ILVRL_B2_SH(zero, src3, dst6, dst7); + ILVRL_B2_SH(zero, src4, dst8, dst9); + ILVRL_B2_SH(zero, src5, dst10, dst11); + + SLLI_4V(dst0, dst1, dst2, dst3, 6); + SLLI_4V(dst4, dst5, dst6, dst7, 6); + SLLI_4V(dst8, dst9, dst10, dst11, 6); + + HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, dst0, dst1, dst2, dst3, + 7, dst0, dst1, dst2, dst3); + HEVC_BI_RND_CLIP4_MAX_SATU(in4, in5, in6, in7, dst4, dst5, dst6, dst7, + 7, dst4, dst5, dst6, dst7); + HEVC_BI_RND_CLIP4_MAX_SATU(in8, in9, in10, in11, dst8, dst9, dst10, + dst11, 7, dst8, dst9, dst10, dst11); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + PCKEV_B3_UB(dst7, dst6, dst9, dst8, dst11, dst10, out3, out4, out5); + ST_UB2(out0, out1, dst, 16); + ST_UB(out2, dst + 32); + dst += dst_stride; + ST_UB2(out3, out4, dst, 16); + ST_UB(out5, dst + 32); + dst += dst_stride; + } } static void hevc_bi_copy_64w_msa(uint8_t *src0_ptr, @@ -429,8 +489,35 @@ static void hevc_bi_copy_64w_msa(uint8_t *src0_ptr, int32_t dst_stride, int32_t height) { - hevc_bi_copy_16multx4mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, height, 64); + uint32_t loop_cnt; + v16u8 out0, out1, out2, out3; + v16i8 src0, src1, src2, src3; + v16i8 zero = { 0 }; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 in0, in1, in2, in3, in4, in5, in6, in7; + + for (loop_cnt = height; loop_cnt--;) { + LD_SB4(src0_ptr, 16, src0, src1, src2, src3); + src0_ptr += src_stride; + LD_SH8(src1_ptr, 8, in0, in1, in2, in3, in4, in5, in6, in7); + src1_ptr += src2_stride; + + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); + ILVRL_B2_SH(zero, src2, dst4, dst5); + ILVRL_B2_SH(zero, src3, dst6, dst7); + SLLI_4V(dst0, dst1, dst2, dst3, 6); + SLLI_4V(dst4, dst5, dst6, dst7, 6); + HEVC_BI_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, dst0, dst1, dst2, dst3, + 7, dst0, dst1, dst2, dst3); + HEVC_BI_RND_CLIP4_MAX_SATU(in4, in5, in6, in7, dst4, dst5, dst6, dst7, + 7, dst4, dst5, dst6, dst7); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); + + ST_UB4(out0, out1, out2, out3, dst, 16); + dst += dst_stride; + } } static void hevc_hz_bi_8t_4w_msa(uint8_t *src0_ptr, @@ -450,7 +537,7 @@ static void hevc_hz_bi_8t_4w_msa(uint8_t *src0_ptr, v8i16 dst0, dst1, dst2, dst3; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[16]); src0_ptr -= 3; @@ -476,26 +563,26 @@ static void hevc_hz_bi_8t_4w_msa(uint8_t *src0_ptr, ILVR_D2_SH(in5, in4, in7, in6, in2, in3); XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); - VSHF_B4_SB(src0, src1, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - VSHF_B4_SB(src2, src3, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - VSHF_B4_SB(src4, src5, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - VSHF_B4_SB(src6, src7, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src4, src5, src6, src7, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src4, src5, src6, src7, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec0, vec1); + VSHF_B2_SB(src4, src5, src6, src7, mask2, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src1, src2, src3, mask3, mask3, vec0, vec1); + VSHF_B2_SB(src4, src5, src6, src7, mask3, mask3, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt3, filt3, filt3, filt3, dst0, + dst1, dst2, dst3); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); @@ -523,7 +610,7 @@ static void hevc_hz_bi_8t_8w_msa(uint8_t *src0_ptr, v8i16 dst0, dst1, dst2, dst3; v8i16 in0, in1, in2, in3; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); src0_ptr -= 3; @@ -544,26 +631,26 @@ static void hevc_hz_bi_8t_8w_msa(uint8_t *src0_ptr, src1_ptr += (4 * src2_stride); XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask3, mask3, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt3, filt3, filt3, filt3, dst0, + dst1, dst2, dst3); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); @@ -583,10 +670,83 @@ static void hevc_hz_bi_8t_12w_msa(uint8_t *src0_ptr, const int8_t *filter, int32_t height) { - hevc_hz_bi_8t_8w_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter, height); - hevc_hz_bi_8t_4w_msa(src0_ptr + 8, src_stride, src1_ptr + 8, src2_stride, - dst + 8, dst_stride, filter, height); + uint32_t loop_cnt; + int32_t tmp0, tmp1; + int64_t tmp2, tmp3; + v16i8 src0, src1, src2, src3; + v16i8 vec0, vec1, vec2; + v8i16 filt0, filt1, filt2, filt3; + v16i8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask7; + v8i16 dst0, dst1, dst2; + v8i16 in0, in1, in2, in3; + v8i16 filter_vec, const_vec; + + src0_ptr -= 3; + const_vec = __msa_ldi_h(128); + const_vec <<= 6; + + filter_vec = LD_SH(filter); + SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + mask2 = mask0 + 4; + mask3 = mask0 + 6; + mask4 = LD_SB(&ff_hevc_mask_arr[16]); + mask5 = mask4 + 2; + mask6 = mask4 + 4; + mask7 = mask4 + 6; + + for (loop_cnt = 8; loop_cnt--;) { + LD_SB2(src0_ptr, 8, src0, src1); + src0_ptr += src_stride; + LD_SB2(src0_ptr, 8, src2, src3); + src0_ptr += src_stride; + LD_SH2(src1_ptr, 8, in0, in1); + src1_ptr += src2_stride; + LD_SH2(src1_ptr, 8, in2, in3); + src1_ptr += src2_stride; + XORI_B4_128_SB(src0, src1, src2, src3); + + dst0 = const_vec; + dst1 = const_vec; + dst2 = const_vec; + + VSHF_B3_SB(src0, src0, src1, src3, src2, src2, mask0, mask4, mask0, + vec0, vec1, vec2); + DPADD_SB2_SH(vec0, vec1, filt0, filt0, dst0, dst1); + dst2 = __msa_dpadd_s_h(dst2, vec2, (v16i8) filt0); + VSHF_B3_SB(src0, src0, src1, src3, src2, src2, mask1, mask5, mask1, + vec0, vec1, vec2); + DPADD_SB2_SH(vec0, vec1, filt1, filt1, dst0, dst1); + dst2 = __msa_dpadd_s_h(dst2, vec2, (v16i8) filt1); + VSHF_B3_SB(src0, src0, src1, src3, src2, src2, mask2, mask6, mask2, + vec0, vec1, vec2); + DPADD_SB2_SH(vec0, vec1, filt2, filt2, dst0, dst1); + dst2 = __msa_dpadd_s_h(dst2, vec2, (v16i8) filt2); + VSHF_B3_SB(src0, src0, src1, src3, src2, src2, mask3, mask7, mask3, + vec0, vec1, vec2); + DPADD_SB2_SH(vec0, vec1, filt3, filt3, dst0, dst1); + dst2 = __msa_dpadd_s_h(dst2, vec2, (v16i8) filt3); + + in1 = (v8i16) __msa_pckev_d((v2i64) in3, (v2i64) in1); + HEVC_BI_RND_CLIP2(in0, in1, dst0, dst1, 7, dst0, dst1); + dst2 = __msa_adds_s_h(in2, dst2); + dst2 = __msa_srari_h(dst2, 7); + dst2 = CLIP_SH_0_255(dst2); + PCKEV_B2_SH(dst1, dst0, dst2, dst2, dst0, dst1); + + tmp2 = __msa_copy_s_d((v2i64) dst0, 0); + tmp0 = __msa_copy_s_w((v4i32) dst0, 2); + tmp3 = __msa_copy_s_d((v2i64) dst1, 0); + tmp1 = __msa_copy_s_w((v4i32) dst0, 3); + SD(tmp2, dst); + SW(tmp0, dst + 8); + dst += dst_stride; + SD(tmp3, dst); + SW(tmp1, dst + 8); + dst += dst_stride; + } } static void hevc_hz_bi_8t_16w_msa(uint8_t *src0_ptr, @@ -606,7 +766,7 @@ static void hevc_hz_bi_8t_16w_msa(uint8_t *src0_ptr, v8i16 dst0, dst1, dst2, dst3; v8i16 in0, in1, in2, in3; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); src0_ptr -= 3; const_vec = __msa_ldi_h(128); @@ -630,26 +790,26 @@ static void hevc_hz_bi_8t_16w_msa(uint8_t *src0_ptr, src1_ptr += src2_stride; XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask3, mask3, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt3, filt3, filt3, filt3, dst0, + dst1, dst2, dst3); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); @@ -678,7 +838,7 @@ static void hevc_hz_bi_8t_24w_msa(uint8_t *src0_ptr, v8i16 dst0, dst1, dst2; v8i16 in0, in1, in2; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); src0_ptr = src0_ptr - 3; const_vec = __msa_ldi_h(128); @@ -703,21 +863,21 @@ static void hevc_hz_bi_8t_24w_msa(uint8_t *src0_ptr, src1_ptr += src2_stride; XORI_B2_128_SB(src0, src1); - VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, - vec0, vec1, vec2, vec3); dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask4, vec0, vec1); + VSHF_B2_SB(src1, src1, src0, src0, mask0, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt1, dst0, + dst1, dst2, dst0); + VSHF_B2_SB(src0, src1, src1, src1, mask5, mask1, vec0, vec1); + VSHF_B2_SB(src0, src0, src0, src1, mask2, mask6, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt2, filt2, dst1, + dst2, dst0, dst1); + VSHF_B2_SB(src1, src1, src0, src0, mask2, mask3, vec0, vec1); + VSHF_B2_SB(src0, src1, src1, src1, mask7, mask3, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt3, filt3, filt3, dst2, + dst0, dst1, dst2); HEVC_BI_RND_CLIP2(in0, in1, dst0, dst1, 7, dst0, dst1); dst2 = __msa_adds_s_h(dst2, in2); @@ -749,7 +909,7 @@ static void hevc_hz_bi_8t_32w_msa(uint8_t *src0_ptr, v8i16 dst0, dst1, dst2, dst3; v8i16 in0, in1, in2, in3; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); src0_ptr -= 3; const_vec = __msa_ldi_h(128); @@ -774,26 +934,26 @@ static void hevc_hz_bi_8t_32w_msa(uint8_t *src0_ptr, src1_ptr += src2_stride; XORI_B3_128_SB(src0, src1, src2); - VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, - vec0, vec1, vec2, vec3); dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask4, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask1, mask5, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask2, mask6, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask2, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask3, mask7, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask3, mask3, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt3, filt3, filt3, filt3, dst0, + dst1, dst2, dst3); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); @@ -822,7 +982,7 @@ static void hevc_hz_bi_8t_48w_msa(uint8_t *src0_ptr, v8i16 dst0, dst1, dst2, dst3, dst4, dst5; v8i16 in0, in1, in2, in3, in4, in5; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); src0_ptr -= 3; @@ -840,62 +1000,53 @@ static void hevc_hz_bi_8t_48w_msa(uint8_t *src0_ptr, mask6 = mask0 + 12; mask7 = mask0 + 14; - for (loop_cnt = height; loop_cnt--;) { - LD_SB2(src0_ptr, 16, src0, src1); - XORI_B2_128_SB(src0, src1); - LD_SH2(src1_ptr, 8, in0, in1); + for (loop_cnt = 64; loop_cnt--;) { + LD_SB3(src0_ptr, 16, src0, src1, src2); + src3 = LD_SB(src0_ptr + 40); + src0_ptr += src_stride; + LD_SH4(src1_ptr, 8, in0, in1, in2, in3); + XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, - vec0, vec1, vec2, vec3); dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - - HEVC_BI_RND_CLIP2(in0, in1, dst0, dst1, 7, dst0, dst1); - - tmp0 = __msa_pckev_b((v16i8) dst1, (v16i8) dst0); - ST_SB(tmp0, dst); - - LD_SB2(src0_ptr + 32, 8, src2, src3); - XORI_B2_128_SB(src2, src3); - src0_ptr += src_stride; - - LD_SH2(src1_ptr + 16, 8, in2, in3); - - VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - VSHF_B4_SB(src1, src2, mask4, mask5, mask6, mask7, - vec0, vec1, vec2, vec3); dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask4, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src2, mask0, mask4, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask1, mask5, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src2, mask1, mask5, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask2, mask6, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src2, mask2, mask6, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask3, mask7, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src2, mask3, mask7, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt3, filt3, filt3, filt3, dst0, + dst1, dst2, dst3); + HEVC_BI_RND_CLIP2(in0, in1, dst0, dst1, 7, dst0, dst1); HEVC_BI_RND_CLIP2(in2, in3, dst2, dst3, 7, dst2, dst3); - - tmp1 = __msa_pckev_b((v16i8) dst3, (v16i8) dst2); + PCKEV_B2_SB(dst1, dst0, dst3, dst2, tmp0, tmp1); + ST_SB(tmp0, dst); ST_SB(tmp1, dst + 16); LD_SH2(src1_ptr + 32, 8, in4, in5); src1_ptr += src2_stride; - VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst4 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst4, dst4, dst4, dst4); - VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst5 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst5, dst5, dst5, dst5); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt1, filt1, dst4, + dst5, dst4, dst5); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt3, filt3, dst4, + dst5, dst4, dst5); HEVC_BI_RND_CLIP2(in4, in5, dst4, dst5, 7, dst4, dst5); @@ -914,14 +1065,10 @@ static void hevc_hz_bi_8t_64w_msa(uint8_t *src0_ptr, const int8_t *filter, int32_t height) { - uint8_t *src0_ptr_tmp; - uint8_t *dst_tmp; - int16_t *src1_ptr_tmp; uint32_t loop_cnt; - uint32_t cnt; - v16i8 src0, src1, src2, tmp0, tmp1; + v16i8 src0, src1, src2, src3, src4, src5, tmp0, tmp1; v8i16 filt0, filt1, filt2, filt3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1, mask2, mask3, mask4, mask5, mask6, mask7; v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3; @@ -945,48 +1092,74 @@ static void hevc_hz_bi_8t_64w_msa(uint8_t *src0_ptr, mask7 = mask0 + 14; for (loop_cnt = height; loop_cnt--;) { - src0_ptr_tmp = src0_ptr; - dst_tmp = dst; - src1_ptr_tmp = src1_ptr; + LD_SB2(src0_ptr, 16, src0, src1); + src2 = LD_SB(src0_ptr + 24); + LD_SB2(src0_ptr + 32, 16, src3, src4); + src5 = LD_SB(src0_ptr + 56); + LD_SH4(src1_ptr, 8, in0, in1, in2, in3); + XORI_B3_128_SB(src0, src1, src2); - for (cnt = 2; cnt--;) { - LD_SB2(src0_ptr_tmp, 16, src0, src1); - src2 = LD_SB(src0_ptr_tmp + 24); - src0_ptr_tmp += 32; - LD_SH4(src1_ptr_tmp, 8, in0, in1, in2, in3); - src1_ptr_tmp += 32; - XORI_B3_128_SB(src0, src1, src2); + dst0 = const_vec; + dst1 = const_vec; + dst2 = const_vec; + dst3 = const_vec; - VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, - vec0, vec1, vec2, vec3); - dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); - dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); - dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask4, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask1, mask5, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask2, mask6, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask2, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask3, mask7, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask3, mask3, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt3, filt3, filt3, filt3, dst0, + dst1, dst2, dst3); - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - dst0, dst1, dst2, dst3, 7, - dst0, dst1, dst2, dst3); + HEVC_BI_RND_CLIP4(in0, in1, in2, in3, + dst0, dst1, dst2, dst3, 7, + dst0, dst1, dst2, dst3); - PCKEV_B2_SB(dst1, dst0, dst3, dst2, tmp0, tmp1); - ST_SB2(tmp0, tmp1, dst_tmp, 16); - dst_tmp += 32; - } + PCKEV_B2_SB(dst1, dst0, dst3, dst2, tmp0, tmp1); + ST_SB2(tmp0, tmp1, dst, 16); + src0 = src3; + src1 = src4; + src2 = src5; + + LD_SH4(src1_ptr + 32, 8, in0, in1, in2, in3); + XORI_B3_128_SB(src0, src1, src2); + + dst0 = const_vec; + dst1 = const_vec; + dst2 = const_vec; + dst3 = const_vec; + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask4, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask1, mask5, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask2, mask6, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask2, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask3, mask7, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask3, mask3, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt3, filt3, filt3, filt3, dst0, + dst1, dst2, dst3); + HEVC_BI_RND_CLIP4(in0, in1, in2, in3, + dst0, dst1, dst2, dst3, 7, + dst0, dst1, dst2, dst3); + PCKEV_B2_SB(dst1, dst0, dst3, dst2, tmp0, tmp1); + ST_SB2(tmp0, tmp1, dst + 32, 16); src1_ptr += src2_stride; src0_ptr += src_stride; dst += dst_stride; @@ -1447,30 +1620,30 @@ static void hevc_hv_bi_8t_4w_msa(uint8_t *src0_ptr, int32_t height) { uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; - v8i16 in0, in1; + uint64_t tp0, tp1; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v8i16 in0 = { 0 }, in1 = { 0 }; v8i16 filt0, filt1, filt2, filt3; - v4i32 filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 filt_h0, filt_h1, filt_h2, filt_h3; v16i8 mask1, mask2, mask3; v8i16 filter_vec, const_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; - v8i16 dst30, dst41, dst52, dst63, dst66, dst87; - v4i32 dst0_r, dst1_r, in0_r, in0_l; - v8i16 dst10_r, dst32_r, dst54_r, dst76_r; - v8i16 dst21_r, dst43_r, dst65_r, dst87_r; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; - v8u16 mask4 = { 0, 4, 1, 5, 2, 6, 3, 7 }; + v8i16 out0, out1; + v8i16 dst30, dst41, dst52, dst63, dst66, dst97, dst108; + v8i16 dst10, dst32, dst54, dst76, dst98, dst21, dst43, dst65, dst87, dst109; + v4i32 dst0, dst1, dst2, dst3; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); src0_ptr -= ((3 * src_stride) + 3); filter_vec = LD_SH(filter_x); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W4_SW(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); mask1 = mask0 + 2; mask2 = mask0 + 4; @@ -1491,71 +1664,77 @@ static void hevc_hv_bi_8t_4w_msa(uint8_t *src0_ptr, VSHF_B4_SB(src3, src6, mask0, mask1, mask2, mask3, vec12, vec13, vec14, vec15); - dst30 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst30, dst30, dst30, dst30); - dst41 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst41, dst41, dst41, dst41); - dst52 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst52, dst52, dst52, dst52); - dst63 = const_vec; - DPADD_SB4_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, filt3, - dst63, dst63, dst63, dst63); - - ILVR_H3_SH(dst41, dst30, dst52, dst41, dst63, dst52, - dst10_r, dst21_r, dst32_r); - dst43_r = __msa_ilvl_h(dst41, dst30); - dst54_r = __msa_ilvl_h(dst52, dst41); - dst65_r = __msa_ilvl_h(dst63, dst52); + dst30 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst41 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst52 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst63 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, + filt3); + + ILVRL_H2_SH(dst41, dst30, dst10, dst43); + ILVRL_H2_SH(dst52, dst41, dst21, dst54); + ILVRL_H2_SH(dst63, dst52, dst32, dst65); + dst66 = (v8i16) __msa_splati_d((v2i64) dst63, 1); - for (loop_cnt = height >> 1; loop_cnt--;) { - LD_SB2(src0_ptr, src_stride, src7, src8); - src0_ptr += (2 * src_stride); - LD_SH2(src1_ptr, src2_stride, in0, in1); - src1_ptr += (2 * src2_stride); + for (loop_cnt = height >> 2; loop_cnt--;) { + LD_SB4(src0_ptr, src_stride, src7, src8, src9, src10); + src0_ptr += (4 * src_stride); + XORI_B4_128_SB(src7, src8, src9, src10); - in0 = (v8i16) __msa_ilvr_d((v2i64) in1, (v2i64) in0); - XORI_B2_128_SB(src7, src8); + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in0); + src1_ptr += (2 * src2_stride); + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in1); + src1_ptr += (2 * src2_stride); - VSHF_B4_SB(src7, src8, mask0, mask1, mask2, mask3, + VSHF_B4_SB(src7, src9, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst87 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst87, dst87, dst87, dst87); - dst76_r = __msa_ilvr_h(dst87, dst66); - dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, - filt_h0, filt_h1, filt_h2, filt_h3); - dst87_r = __msa_vshf_h((v8i16) mask4, dst87, dst87); - dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, - filt_h0, filt_h1, filt_h2, filt_h3); - - dst0_r >>= 6; - dst1_r >>= 6; - UNPCK_SH_SW(in0, in0_r, in0_l); - dst0_r = __msa_adds_s_w(dst0_r, in0_r); - dst1_r = __msa_adds_s_w(dst1_r, in0_l); - SRARI_W2_SW(dst0_r, dst1_r, 7); - dst0_r = CLIP_SW_0_255(dst0_r); - dst1_r = CLIP_SW_0_255(dst1_r); - - HEVC_PCK_SW_SB2(dst1_r, dst0_r, dst0_r); - ST4x2_UB(dst0_r, dst, dst_stride); - dst += (2 * dst_stride); + VSHF_B4_SB(src8, src10, mask0, mask1, mask2, mask3, + vec4, vec5, vec6, vec7); + dst97 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst108 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + + dst76 = __msa_ilvr_h(dst97, dst66); + ILVRL_H2_SH(dst108, dst97, dst87, dst109); + dst66 = (v8i16) __msa_splati_d((v2i64) dst97, 1); + dst98 = __msa_ilvr_h(dst66, dst108); + + dst0 = HEVC_FILT_8TAP(dst10, dst32, dst54, dst76, filt_h0, filt_h1, + filt_h2, filt_h3); + dst1 = HEVC_FILT_8TAP(dst21, dst43, dst65, dst87, filt_h0, filt_h1, + filt_h2, filt_h3); + dst2 = HEVC_FILT_8TAP(dst32, dst54, dst76, dst98, filt_h0, filt_h1, + filt_h2, filt_h3); + dst3 = HEVC_FILT_8TAP(dst43, dst65, dst87, dst109, filt_h0, filt_h1, + filt_h2, filt_h3); + + SRA_4V(dst0, dst1, dst2, dst3, 6); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, out0, out1); + ADDS_SH2_SH(out0, in0, out1, in1, out0, out1); + ADDS_SH2_SH(out0, const_vec, out1, const_vec, out0, out1); + SRARI_H2_SH(out0, out1, 7); + CLIP_SH2_0_255_MAX_SATU(out0, out1); + out = (v16u8) __msa_pckev_b((v16i8) out1, (v16i8) out0); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + dst += (4 * dst_stride); - dst10_r = dst32_r; - dst32_r = dst54_r; - dst54_r = dst76_r; - dst21_r = dst43_r; - dst43_r = dst65_r; - dst65_r = dst87_r; - dst66 = (v8i16) __msa_splati_d((v2i64) dst87, 1); + dst10 = dst54; + dst32 = dst76; + dst54 = dst98; + dst21 = dst65; + dst43 = dst87; + dst65 = dst109; + dst66 = (v8i16) __msa_splati_d((v2i64) dst108, 1); } } -static void hevc_hv_bi_8t_8multx2mult_msa(uint8_t *src0_ptr, +static void hevc_hv_bi_8t_8multx1mult_msa(uint8_t *src0_ptr, int32_t src_stride, int16_t *src1_ptr, int32_t src2_stride, @@ -1570,22 +1749,20 @@ static void hevc_hv_bi_8t_8multx2mult_msa(uint8_t *src0_ptr, uint8_t *src0_ptr_tmp; int16_t *src1_ptr_tmp; uint8_t *dst_tmp; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; - v8i16 in0, in1; - v4i32 in0_r, in0_l, in1_r, in1_l; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7; + v8i16 in0, tmp; v8i16 filt0, filt1, filt2, filt3; - v4i32 filt_h0, filt_h1, filt_h2, filt_h3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1, filt_h2, filt_h3; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1, mask2, mask3; v8i16 filter_vec, const_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; - v4i32 dst0_r, dst0_l, dst1_r, dst1_l; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v4i32 dst0_r, dst0_l; v8i16 dst10_r, dst32_r, dst54_r, dst76_r; v8i16 dst10_l, dst32_l, dst54_l, dst76_l; - v8i16 dst21_r, dst43_r, dst65_r, dst87_r; - v8i16 dst21_l, dst43_l, dst65_l, dst87_l; src0_ptr -= ((3 * src_stride) + 3); const_vec = __msa_ldi_h(128); @@ -1595,9 +1772,9 @@ static void hevc_hv_bi_8t_8multx2mult_msa(uint8_t *src0_ptr, SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); - SPLATI_W4_SW(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); mask1 = mask0 + 2; mask2 = mask0 + 4; @@ -1622,18 +1799,14 @@ static void hevc_hv_bi_8t_8multx2mult_msa(uint8_t *src0_ptr, vec8, vec9, vec10, vec11); VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec12, vec13, vec14, vec15); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - dst1 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - dst2 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - dst3 = const_vec; - DPADD_SB4_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst1 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst2 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst3 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, + filt2, filt3); VSHF_B4_SB(src4, src4, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); @@ -1641,38 +1814,28 @@ static void hevc_hv_bi_8t_8multx2mult_msa(uint8_t *src0_ptr, vec4, vec5, vec6, vec7); VSHF_B4_SB(src6, src6, mask0, mask1, mask2, mask3, vec8, vec9, vec10, vec11); - dst4 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst4, dst4, dst4, dst4); - dst5 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst5, dst5, dst5, dst5); - dst6 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst6, dst6, dst6, dst6); - - ILVR_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, - dst10_r, dst32_r, dst54_r, dst21_r); - ILVR_H2_SH(dst4, dst3, dst6, dst5, dst43_r, dst65_r); - ILVL_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, - dst10_l, dst32_l, dst54_l, dst21_l); - ILVL_H2_SH(dst4, dst3, dst6, dst5, dst43_l, dst65_l); - - for (loop_cnt = height >> 1; loop_cnt--;) { - /* row 7 */ - LD_SB2(src0_ptr_tmp, src_stride, src7, src8); - XORI_B2_128_SB(src7, src8); - src0_ptr_tmp += 2 * src_stride; + dst4 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst5 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst6 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); - LD_SH2(src1_ptr_tmp, src2_stride, in0, in1); - src1_ptr_tmp += (2 * src2_stride); + for (loop_cnt = height; loop_cnt--;) { + src7 = LD_SB(src0_ptr_tmp); + src7 = (v16i8) __msa_xori_b((v16u8) src7, 128); + src0_ptr_tmp += src_stride; + + in0 = LD_SH(src1_ptr_tmp); + src1_ptr_tmp += src2_stride; VSHF_B4_SB(src7, src7, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst7 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst7, dst7, dst7, dst7); - + dst7 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); + ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); + ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, filt_h0, filt_h1, filt_h2, filt_h3); @@ -1681,49 +1844,21 @@ static void hevc_hv_bi_8t_8multx2mult_msa(uint8_t *src0_ptr, dst0_r >>= 6; dst0_l >>= 6; - VSHF_B4_SB(src8, src8, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); - dst8 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst8, dst8, dst8, dst8); - - ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); - dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, - filt_h0, filt_h1, filt_h2, filt_h3); - dst1_l = HEVC_FILT_8TAP(dst21_l, dst43_l, dst65_l, dst87_l, - filt_h0, filt_h1, filt_h2, filt_h3); - dst1_r >>= 6; - dst1_l >>= 6; - - UNPCK_SH_SW(in0, in0_r, in0_l); - UNPCK_SH_SW(in1, in1_r, in1_l); - in0_r = __msa_adds_s_w(in0_r, dst0_r); - in0_l = __msa_adds_s_w(in0_l, dst0_l); - in1_r = __msa_adds_s_w(in1_r, dst1_r); - in1_l = __msa_adds_s_w(in1_l, dst1_l); - SRARI_W4_SW(in0_r, in0_l, in1_r, in1_l, 7); - in0_r = CLIP_SW_0_255(in0_r); - in0_l = CLIP_SW_0_255(in0_l); - in1_r = CLIP_SW_0_255(in1_r); - in1_l = CLIP_SW_0_255(in1_l); - - HEVC_PCK_SW_SB4(in0_l, in0_r, in1_l, in1_r, dst0_r); - ST8x2_UB(dst0_r, dst_tmp, dst_stride); - dst_tmp += (2 * dst_stride); - - dst10_r = dst32_r; - dst32_r = dst54_r; - dst54_r = dst76_r; - dst10_l = dst32_l; - dst32_l = dst54_l; - dst54_l = dst76_l; - dst21_r = dst43_r; - dst43_r = dst65_r; - dst65_r = dst87_r; - dst21_l = dst43_l; - dst43_l = dst65_l; - dst65_l = dst87_l; - dst6 = dst8; + tmp = __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); + ADDS_SH2_SH(tmp, in0, tmp, const_vec, tmp, tmp); + tmp = __msa_srari_h(tmp, 7); + tmp = CLIP_SH_0_255_MAX_SATU(tmp); + out = (v16u8) __msa_pckev_b((v16i8) tmp, (v16i8) tmp); + ST8x1_UB(out, dst_tmp); + dst_tmp += dst_stride; + + dst0 = dst1; + dst1 = dst2; + dst2 = dst3; + dst3 = dst4; + dst4 = dst5; + dst5 = dst6; + dst6 = dst7; } src0_ptr += 8; @@ -1742,7 +1877,7 @@ static void hevc_hv_bi_8t_8w_msa(uint8_t *src0_ptr, const int8_t *filter_y, int32_t height) { - hevc_hv_bi_8t_8multx2mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, + hevc_hv_bi_8t_8multx1mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, 8); } @@ -1757,12 +1892,208 @@ static void hevc_hv_bi_8t_12w_msa(uint8_t *src0_ptr, const int8_t *filter_y, int32_t height) { - hevc_hv_bi_8t_8multx2mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter_x, filter_y, - height, 8); + uint32_t loop_cnt; + uint8_t *src0_ptr_tmp, *dst_tmp; + int16_t *src1_ptr_tmp; + uint64_t tp0, tp1; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask7; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; + v8i16 in0, in1 = { 0 }, out0, out1, tmp, filter_vec, const_vec; + v8i16 filt0, filt1, filt2, filt3, filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 dst30, dst41, dst52, dst63, dst66, dst97, dst108; + v8i16 dst10, dst32, dst54, dst76, dst98, dst21, dst43, dst65, dst87, dst109; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r; + v8i16 dst10_l, dst32_l, dst54_l, dst76_l; + v4i32 dst0_r, dst0_l, tmp0, tmp1, tmp2, tmp3; + + src0_ptr -= ((3 * src_stride) + 3); + + const_vec = __msa_ldi_h(128); + const_vec <<= 6; + + filter_vec = LD_SH(filter_x); + SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + mask2 = mask0 + 4; + mask3 = mask0 + 6; + + src0_ptr_tmp = src0_ptr; + dst_tmp = dst; + src1_ptr_tmp = src1_ptr; + + LD_SB7(src0_ptr_tmp, src_stride, src0, src1, src2, src3, src4, src5, + src6); + src0_ptr_tmp += (7 * src_stride); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + /* row 0 row 1 row 2 row 3 */ + VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec4, vec5, vec6, + vec7); + VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, vec8, vec9, vec10, + vec11); + VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec12, vec13, vec14, + vec15); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst1 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst2 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst3 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, + filt2, filt3); + VSHF_B4_SB(src4, src4, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + VSHF_B4_SB(src5, src5, mask0, mask1, mask2, mask3, vec4, vec5, vec6, + vec7); + VSHF_B4_SB(src6, src6, mask0, mask1, mask2, mask3, vec8, vec9, vec10, + vec11); + dst4 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst5 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst6 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + + for (loop_cnt = 16; loop_cnt--;) { + src7 = LD_SB(src0_ptr_tmp); + src7 = (v16i8) __msa_xori_b((v16u8) src7, 128); + src0_ptr_tmp += src_stride; + + in0 = LD_SH(src1_ptr_tmp); + src1_ptr_tmp += src2_stride; + + VSHF_B4_SB(src7, src7, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + dst7 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); + ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); + ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); + dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst0_l = HEVC_FILT_8TAP(dst10_l, dst32_l, dst54_l, dst76_l, filt_h0, + filt_h1, filt_h2, filt_h3); + dst0_r >>= 6; + dst0_l >>= 6; + + tmp = __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); + ADDS_SH2_SH(tmp, in0, tmp, const_vec, tmp, tmp); + tmp = __msa_srari_h(tmp, 7); + tmp = CLIP_SH_0_255_MAX_SATU(tmp); + out = (v16u8) __msa_pckev_b((v16i8) tmp, (v16i8) tmp); + ST8x1_UB(out, dst_tmp); + dst_tmp += dst_stride; + + dst0 = dst1; + dst1 = dst2; + dst2 = dst3; + dst3 = dst4; + dst4 = dst5; + dst5 = dst6; + dst6 = dst7; + } + + src0_ptr += 8; + dst += 8; + src1_ptr += 8; + + mask4 = LD_SB(ff_hevc_mask_arr + 16); + mask5 = mask4 + 2; + mask6 = mask4 + 4; + mask7 = mask4 + 6; + + LD_SB7(src0_ptr, src_stride, src0, src1, src2, src3, src4, src5, src6); + src0_ptr += (7 * src_stride); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + /* row 0 row 1 row 2 row 3 */ + VSHF_B4_SB(src0, src3, mask4, mask5, mask6, mask7, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src1, src4, mask4, mask5, mask6, mask7, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src2, src5, mask4, mask5, mask6, mask7, + vec8, vec9, vec10, vec11); + VSHF_B4_SB(src3, src6, mask4, mask5, mask6, mask7, + vec12, vec13, vec14, vec15); + dst30 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst41 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst52 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst63 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, + filt3); + + ILVRL_H2_SH(dst41, dst30, dst10, dst43); + ILVRL_H2_SH(dst52, dst41, dst21, dst54); + ILVRL_H2_SH(dst63, dst52, dst32, dst65); + + dst66 = (v8i16) __msa_splati_d((v2i64) dst63, 1); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src0_ptr, src_stride, src7, src8, src9, src10); + src0_ptr += (4 * src_stride); + XORI_B4_128_SB(src7, src8, src9, src10); - hevc_hv_bi_8t_4w_msa(src0_ptr + 8, src_stride, src1_ptr + 8, src2_stride, - dst + 8, dst_stride, filter_x, filter_y, height); + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in0); + src1_ptr += (2 * src2_stride); + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in1); + src1_ptr += (2 * src2_stride); + + VSHF_B4_SB(src7, src9, mask4, mask5, mask6, mask7, vec0, vec1, vec2, + vec3); + VSHF_B4_SB(src8, src10, mask4, mask5, mask6, mask7, vec4, vec5, vec6, + vec7); + dst97 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst108 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + + dst76 = __msa_ilvr_h(dst97, dst66); + ILVRL_H2_SH(dst108, dst97, dst87, dst109); + dst66 = (v8i16) __msa_splati_d((v2i64) dst97, 1); + dst98 = __msa_ilvr_h(dst66, dst108); + + tmp0 = HEVC_FILT_8TAP(dst10, dst32, dst54, dst76, filt_h0, filt_h1, + filt_h2, filt_h3); + tmp1 = HEVC_FILT_8TAP(dst21, dst43, dst65, dst87, filt_h0, filt_h1, + filt_h2, filt_h3); + tmp2 = HEVC_FILT_8TAP(dst32, dst54, dst76, dst98, filt_h0, filt_h1, + filt_h2, filt_h3); + tmp3 = HEVC_FILT_8TAP(dst43, dst65, dst87, dst109, filt_h0, filt_h1, + filt_h2, filt_h3); + SRA_4V(tmp0, tmp1, tmp2, tmp3, 6); + PCKEV_H2_SH(tmp1, tmp0, tmp3, tmp2, out0, out1); + ADDS_SH2_SH(out0, in0, out1, in1, out0, out1); + ADDS_SH2_SH(out0, const_vec, out1, const_vec, out0, out1); + SRARI_H2_SH(out0, out1, 7); + CLIP_SH2_0_255_MAX_SATU(out0, out1); + out = (v16u8) __msa_pckev_b((v16i8) out1, (v16i8) out0); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + dst += (4 * dst_stride); + + dst10 = dst54; + dst32 = dst76; + dst54 = dst98; + dst21 = dst65; + dst43 = dst87; + dst65 = dst109; + dst66 = (v8i16) __msa_splati_d((v2i64) dst108, 1); + } } static void hevc_hv_bi_8t_16w_msa(uint8_t *src0_ptr, @@ -1775,7 +2106,7 @@ static void hevc_hv_bi_8t_16w_msa(uint8_t *src0_ptr, const int8_t *filter_y, int32_t height) { - hevc_hv_bi_8t_8multx2mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, + hevc_hv_bi_8t_8multx1mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, 16); } @@ -1790,7 +2121,7 @@ static void hevc_hv_bi_8t_24w_msa(uint8_t *src0_ptr, const int8_t *filter_y, int32_t height) { - hevc_hv_bi_8t_8multx2mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, + hevc_hv_bi_8t_8multx1mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, 24); } @@ -1805,7 +2136,7 @@ static void hevc_hv_bi_8t_32w_msa(uint8_t *src0_ptr, const int8_t *filter_y, int32_t height) { - hevc_hv_bi_8t_8multx2mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, + hevc_hv_bi_8t_8multx1mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, 32); } @@ -1820,7 +2151,7 @@ static void hevc_hv_bi_8t_48w_msa(uint8_t *src0_ptr, const int8_t *filter_y, int32_t height) { - hevc_hv_bi_8t_8multx2mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, + hevc_hv_bi_8t_8multx1mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, 48); } @@ -1835,7 +2166,7 @@ static void hevc_hv_bi_8t_64w_msa(uint8_t *src0_ptr, const int8_t *filter_y, int32_t height) { - hevc_hv_bi_8t_8multx2mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, + hevc_hv_bi_8t_8multx1mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, 64); } @@ -1852,7 +2183,7 @@ static void hevc_hz_bi_4t_4x2_msa(uint8_t *src0_ptr, v8i16 filt0, filt1; v16i8 src0, src1, dst0, vec0, vec1; v8i16 in0, in1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[16]); v16i8 mask1; v8i16 tmp0; v8i16 filter_vec, const_vec; @@ -1895,7 +2226,8 @@ static void hevc_hz_bi_4t_4x4_msa(uint8_t *src0_ptr, v8i16 filt0, filt1; v16i8 src0, src1, src2, src3, dst0, vec0, vec1; v8i16 in0, in1, in2, in3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v16i8 vec2, vec3; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[16]); v16i8 mask1; v8i16 tmp0, tmp1; v8i16 filter_vec, const_vec; @@ -1916,12 +2248,12 @@ static void hevc_hz_bi_4t_4x4_msa(uint8_t *src0_ptr, ILVR_D2_SH(in1, in0, in3, in2, in0, in1); XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); tmp0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, tmp0, tmp0); - VSHF_B2_SB(src2, src3, src2, src3, mask0, mask1, vec0, vec1); tmp1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, tmp1, tmp1); + VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt1, filt1, tmp0, tmp1, + tmp0, tmp1); HEVC_BI_RND_CLIP2(in0, in1, tmp0, tmp1, 7, tmp0, tmp1); dst0 = __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); @@ -1942,8 +2274,8 @@ static void hevc_hz_bi_4t_4x8multiple_msa(uint8_t *src0_ptr, v16i8 src0, src1, src2, src3, src4, src5, src6, src7; v16i8 dst0, dst1; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; - v16i8 mask1, vec0, vec1; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[16]); + v16i8 mask1, vec0, vec1, vec2, vec3; v8i16 tmp0, tmp1, tmp2, tmp3; v8i16 filter_vec, const_vec; @@ -1969,18 +2301,18 @@ static void hevc_hz_bi_4t_4x8multiple_msa(uint8_t *src0_ptr, ILVR_D2_SH(in5, in4, in7, in6, in2, in3); XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); - VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); tmp0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, tmp0, tmp0); - VSHF_B2_SB(src2, src3, src2, src3, mask0, mask1, vec0, vec1); tmp1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, tmp1, tmp1); - VSHF_B2_SB(src4, src5, src4, src5, mask0, mask1, vec0, vec1); tmp2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, tmp2, tmp2); - VSHF_B2_SB(src6, src7, src6, src7, mask0, mask1, vec0, vec1); tmp3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, tmp3, tmp3); + VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src4, src5, src6, src7, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, tmp0, + tmp1, tmp2, tmp3); + VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src4, src5, src6, src7, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, tmp0, + tmp1, tmp2, tmp3); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, tmp0, tmp1, tmp2, tmp3, 7, tmp0, tmp1, tmp2, tmp3); @@ -2026,9 +2358,9 @@ static void hevc_hz_bi_4t_6w_msa(uint8_t *src0_ptr, v8i16 filt0, filt1; v16i8 src0, src1, src2, src3; v8i16 in0, in1, in2, in3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1; - v16i8 vec0, vec1; + v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3; v8i16 filter_vec, const_vec; @@ -2049,18 +2381,18 @@ static void hevc_hz_bi_4t_6w_msa(uint8_t *src0_ptr, src1_ptr += (4 * src2_stride); XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); @@ -2083,8 +2415,8 @@ static void hevc_hz_bi_4t_8x2_msa(uint8_t *src0_ptr, v8i16 filt0, filt1; v16i8 src0, src1; v8i16 in0, in1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; - v16i8 mask1, vec0, vec1; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); + v16i8 mask1, vec0, vec1, vec2, vec3; v8i16 dst0, dst1; v8i16 filter_vec, const_vec; @@ -2102,12 +2434,12 @@ static void hevc_hz_bi_4t_8x2_msa(uint8_t *src0_ptr, LD_SH2(src1_ptr, src2_stride, in0, in1); XORI_B2_128_SB(src0, src1); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt1, filt1, dst0, dst1, + dst0, dst1); HEVC_BI_RND_CLIP2(in0, in1, dst0, dst1, 7, dst0, dst1); dst0 = (v8i16) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); @@ -2126,9 +2458,9 @@ static void hevc_hz_bi_4t_8x6_msa(uint8_t *src0_ptr, v8i16 filt0, filt1; v16i8 src0, src1, src2, src3, src4, src5; v8i16 in0, in1, in2, in3, in4, in5; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1; - v16i8 vec0, vec1; + v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; v8i16 filter_vec, const_vec; @@ -2148,24 +2480,25 @@ static void hevc_hz_bi_4t_8x6_msa(uint8_t *src0_ptr, LD_SH2(src1_ptr, src2_stride, in4, in5); XORI_B6_128_SB(src0, src1, src2, src3, src4, src5); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, dst1, + dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, dst1, + dst2, dst3); dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); + + VSHF_B2_SB(src4, src4, src5, src5, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src4, src4, src5, src5, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt1, filt1, dst4, dst5, + dst4, dst5); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); @@ -2191,9 +2524,9 @@ static void hevc_hz_bi_4t_8x4multiple_msa(uint8_t *src0_ptr, v8i16 filt0, filt1; v16i8 src0, src1, src2, src3; v8i16 in0, in1, in2, in3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v16i8 vec0, vec1; + v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3; v8i16 filter_vec, const_vec; @@ -2214,18 +2547,18 @@ static void hevc_hz_bi_4t_8x4multiple_msa(uint8_t *src0_ptr, src1_ptr += (4 * src2_stride); XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); @@ -2271,12 +2604,12 @@ static void hevc_hz_bi_4t_12w_msa(uint8_t *src0_ptr, v8i16 filt0, filt1; v16i8 src0, src1, src2, src3; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask2 = { 8, 9, 9, 10, 10, 11, 11, 12, 24, 25, 25, 26, 26, 27, 27, 28 }; v16i8 mask1, mask3; - v16i8 vec0, vec1; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; v8i16 filter_vec, const_vec; @@ -2301,24 +2634,24 @@ static void hevc_hz_bi_4t_12w_msa(uint8_t *src0_ptr, ILVR_D2_SH(in5, in4, in7, in6, in4, in5); XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - VSHF_B2_SB(src2, src3, src2, src3, mask2, mask3, vec0, vec1); dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec4, vec5); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + DPADD_SB2_SH(vec4, vec5, filt0, filt0, dst4, dst5); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2, vec3); + VSHF_B2_SB(src0, src1, src2, src3, mask3, mask3, vec4, vec5); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + DPADD_SB2_SH(vec4, vec5, filt1, filt1, dst4, dst5); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); @@ -2341,13 +2674,11 @@ static void hevc_hz_bi_4t_16w_msa(uint8_t *src0_ptr, int32_t height) { uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7; - v8i16 in0, in1, in2, in3, in4, in5, in6, in7; + v16i8 src0, src1, src2, src3, vec0, vec1, vec2, vec3; + v8i16 in0, in1, in2, in3, dst0, dst1, dst2, dst3; v8i16 filt0, filt1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; - v16i8 vec0, vec1; v8i16 filter_vec, const_vec; src0_ptr -= 1; @@ -2360,49 +2691,36 @@ static void hevc_hz_bi_4t_16w_msa(uint8_t *src0_ptr, mask1 = mask0 + 2; - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src0_ptr, src_stride, src0, src2, src4, src6); - LD_SB4(src0_ptr + 8, src_stride, src1, src3, src5, src7); - src0_ptr += (4 * src_stride); - LD_SH4(src1_ptr, src2_stride, in0, in2, in4, in6); - LD_SH4(src1_ptr + 8, src2_stride, in1, in3, in5, in7); - src1_ptr += (4 * src2_stride); - XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); + for (loop_cnt = (height >> 1); loop_cnt--;) { + LD_SB2(src0_ptr, src_stride, src0, src2); + LD_SB2(src0_ptr + 8, src_stride, src1, src3); + src0_ptr += (2 * src_stride); + LD_SH2(src1_ptr, src2_stride, in0, in2); + LD_SH2(src1_ptr + 8, src2_stride, in1, in3); + src1_ptr += (2 * src2_stride); + + XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); + + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); - HEVC_BI_RND_CLIP4(in4, in5, in6, in7, - dst4, dst5, dst6, dst7, 7, dst4, dst5, dst6, dst7); - PCKEV_B4_SH(dst1, dst0, dst3, dst2, - dst5, dst4, dst7, dst6, dst0, dst1, dst2, dst3); - ST_SH4(dst0, dst1, dst2, dst3, dst, dst_stride); - dst += (4 * dst_stride); + PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); + ST_SH2(dst0, dst1, dst, dst_stride); + dst += (2 * dst_stride); } } @@ -2421,9 +2739,9 @@ static void hevc_hz_bi_4t_24w_msa(uint8_t *src0_ptr, v16i8 src0, src1, src2, src3, src4, src5, src6, src7; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; v8i16 filt0, filt1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1, mask2, mask3; - v16i8 vec0, vec1; + v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; v8i16 filter_vec, const_vec; @@ -2451,30 +2769,31 @@ static void hevc_hz_bi_4t_24w_msa(uint8_t *src0_ptr, src1_ptr += (4 * src2_stride); XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - VSHF_B2_SB(src2, src3, src2, src3, mask2, mask3, vec0, vec1); dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask2, vec0, vec1); + VSHF_B2_SB(src2, src2, src2, src3, mask0, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask1, mask3, vec0, vec1); + VSHF_B2_SB(src2, src2, src2, src3, mask1, mask3, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - VSHF_B2_SB(src4, src5, src4, src5, mask2, mask3, vec0, vec1); dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - VSHF_B2_SB(src6, src7, src6, src7, mask2, mask3, vec0, vec1); dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); + VSHF_B2_SB(src4, src4, src4, src5, mask0, mask2, vec0, vec1); + VSHF_B2_SB(src6, src6, src6, src7, mask0, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst4, + dst5, dst6, dst7); + VSHF_B2_SB(src4, src4, src4, src5, mask1, mask3, vec0, vec1); + VSHF_B2_SB(src6, src6, src6, src7, mask1, mask3, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst4, + dst5, dst6, dst7); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); @@ -2489,18 +2808,18 @@ static void hevc_hz_bi_4t_24w_msa(uint8_t *src0_ptr, LD_SH4(src1_ptr_tmp, src2_stride, in0, in1, in2, in3); src1_ptr_tmp += (4 * src2_stride); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src1, src1, src3, src3, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src5, src5, src7, src7, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src1, src1, src3, src3, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src5, src5, src7, src7, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); @@ -2524,10 +2843,10 @@ static void hevc_hz_bi_4t_32w_msa(uint8_t *src0_ptr, v16i8 src0, src1, src2; v8i16 in0, in1, in2, in3; v8i16 filt0, filt1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1, mask2, mask3; v8i16 dst0, dst1, dst2, dst3; - v16i8 vec0, vec1; + v16i8 vec0, vec1, vec2, vec3; v8i16 filter_vec, const_vec; src0_ptr -= 1; @@ -2542,34 +2861,7 @@ static void hevc_hz_bi_4t_32w_msa(uint8_t *src0_ptr, mask2 = mask0 + 8; mask3 = mask0 + 10; - for (loop_cnt = (height >> 1); loop_cnt--;) { - LD_SB2(src0_ptr, 16, src0, src1); - src2 = LD_SB(src0_ptr + 24); - src0_ptr += src_stride; - LD_SH4(src1_ptr, 8, in0, in1, in2, in3); - src1_ptr += src2_stride; - XORI_B3_128_SB(src0, src1, src2); - - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); - - PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); - ST_SH2(dst0, dst1, dst, 16); - dst += dst_stride; - + for (loop_cnt = height; loop_cnt--;) { LD_SB2(src0_ptr, 16, src0, src1); src2 = LD_SB(src0_ptr + 24); src0_ptr += src_stride; @@ -2577,18 +2869,18 @@ static void hevc_hz_bi_4t_32w_msa(uint8_t *src0_ptr, src1_ptr += src2_stride; XORI_B3_128_SB(src0, src1, src2); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask2, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask1, mask3, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0, dst1, dst2, dst3, 7, dst0, dst1, dst2, dst3); @@ -2800,10 +3092,9 @@ static void hevc_vt_bi_4t_6w_msa(uint8_t *src0_ptr, const int8_t *filter, int32_t height) { - int32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v8i16 in0, in1, in2, in3; - v16i8 src10_r, src32_r, src21_r, src43_r; + v16i8 src10_r, src32_r, src21_r, src43_r, src54_r, src65_r; v8i16 dst0_r, dst1_r, dst2_r, dst3_r; v8i16 filt0, filt1; v8i16 filter_vec, const_vec; @@ -2818,40 +3109,70 @@ static void hevc_vt_bi_4t_6w_msa(uint8_t *src0_ptr, LD_SB3(src0_ptr, src_stride, src0, src1, src2); src0_ptr += (3 * src_stride); + LD_SB2(src0_ptr, src_stride, src3, src4); + src0_ptr += (2 * src_stride); + LD_SB2(src0_ptr, src_stride, src5, src6); + src0_ptr += (2 * src_stride); + LD_SB2(src0_ptr, src_stride, src7, src8); + src0_ptr += (2 * src_stride); + LD_SB2(src0_ptr, src_stride, src9, src10); + src0_ptr += (2 * src_stride); + + LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); + src1_ptr += (4 * src2_stride); + XORI_B3_128_SB(src0, src1, src2); + XORI_B2_128_SB(src3, src4); + XORI_B2_128_SB(src5, src6); + XORI_B2_128_SB(src7, src8); + XORI_B2_128_SB(src9, src10); + ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); + ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB2(src0_ptr, src_stride, src3, src4); - src0_ptr += (2 * src_stride); - LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); - src1_ptr += (4 * src2_stride); - XORI_B2_128_SB(src3, src4); - ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); + dst0_r = const_vec; + DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, dst0_r, dst0_r); + dst1_r = const_vec; + DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, dst1_r, dst1_r); - dst0_r = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, dst0_r, dst0_r); - dst1_r = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, dst1_r, dst1_r); + ILVR_B2_SB(src5, src4, src6, src5, src54_r, src65_r); - LD_SB2(src0_ptr, src_stride, src5, src2); - src0_ptr += (2 * src_stride); - XORI_B2_128_SB(src5, src2); - ILVR_B2_SB(src5, src4, src2, src5, src10_r, src21_r); + dst2_r = const_vec; + DPADD_SB2_SH(src32_r, src54_r, filt0, filt1, dst2_r, dst2_r); + dst3_r = const_vec; + DPADD_SB2_SH(src43_r, src65_r, filt0, filt1, dst3_r, dst3_r); - dst2_r = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, dst2_r, dst2_r); - dst3_r = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, dst3_r, dst3_r); + HEVC_BI_RND_CLIP4(in0, in1, in2, in3, + dst0_r, dst1_r, dst2_r, dst3_r, 7, + dst0_r, dst1_r, dst2_r, dst3_r); - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - dst0_r, dst1_r, dst2_r, dst3_r, 7, - dst0_r, dst1_r, dst2_r, dst3_r); + PCKEV_B2_SH(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); + ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); + dst += (4 * dst_stride); - PCKEV_B2_SH(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); - ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); - dst += (4 * dst_stride); - } + LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); + src1_ptr += (4 * src2_stride); + ILVR_B2_SB(src7, src6, src8, src7, src32_r, src43_r); + + dst0_r = const_vec; + DPADD_SB2_SH(src54_r, src32_r, filt0, filt1, dst0_r, dst0_r); + dst1_r = const_vec; + DPADD_SB2_SH(src65_r, src43_r, filt0, filt1, dst1_r, dst1_r); + + ILVR_B2_SB(src9, src8, src10, src9, src54_r, src65_r); + + dst2_r = const_vec; + DPADD_SB2_SH(src32_r, src54_r, filt0, filt1, dst2_r, dst2_r); + dst3_r = const_vec; + DPADD_SB2_SH(src43_r, src65_r, filt0, filt1, dst3_r, dst3_r); + + HEVC_BI_RND_CLIP4(in0, in1, in2, in3, + dst0_r, dst1_r, dst2_r, dst3_r, 7, + dst0_r, dst1_r, dst2_r, dst3_r); + + PCKEV_B2_SH(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); + ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); + dst += (4 * dst_stride); } static void hevc_vt_bi_4t_8x2_msa(uint8_t *src0_ptr, @@ -3053,12 +3374,12 @@ static void hevc_vt_bi_4t_12w_msa(uint8_t *src0_ptr, int32_t height) { int32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5; + v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; - v16i8 src10_r, src32_r, src21_r, src43_r; + v16i8 src10_r, src32_r, src21_r, src43_r, src54_r, src65_r; v8i16 dst0_r, dst1_r, dst2_r, dst3_r; v16i8 src10_l, src32_l, src54_l, src21_l, src43_l, src65_l; - v16i8 src2110, src4332; + v16i8 src2110, src4332, src6554; v8i16 dst0_l, dst1_l, filt0, filt1; v8i16 filter_vec, const_vec; @@ -3080,15 +3401,21 @@ static void hevc_vt_bi_4t_12w_msa(uint8_t *src0_ptr, for (loop_cnt = (height >> 2); loop_cnt--;) { LD_SB2(src0_ptr, src_stride, src3, src4); src0_ptr += (2 * src_stride); + LD_SB2(src0_ptr, src_stride, src5, src6); + src0_ptr += (2 * src_stride); LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); LD_SH4((src1_ptr + 8), src2_stride, in4, in5, in6, in7); src1_ptr += (4 * src2_stride); ILVR_D2_SH(in5, in4, in7, in6, in4, in5); XORI_B2_128_SB(src3, src4); + XORI_B2_128_SB(src5, src6); ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); src4332 = (v16i8) __msa_ilvr_d((v2i64) src43_l, (v2i64) src32_l); + ILVR_B2_SB(src5, src4, src6, src5, src54_r, src65_r); + ILVL_B2_SB(src5, src4, src6, src5, src54_l, src65_l); + src6554 = (v16i8) __msa_ilvr_d((v2i64) src65_l, (v2i64) src54_l); dst0_r = const_vec; DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, dst0_r, dst0_r); @@ -3096,21 +3423,12 @@ static void hevc_vt_bi_4t_12w_msa(uint8_t *src0_ptr, DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, dst1_r, dst1_r); dst0_l = const_vec; DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst0_l, dst0_l); - - LD_SB2(src0_ptr, src_stride, src5, src2); - src0_ptr += (2 * src_stride); - XORI_B2_128_SB(src5, src2); - - ILVR_B2_SB(src5, src4, src2, src5, src10_r, src21_r); - ILVL_B2_SB(src5, src4, src2, src5, src54_l, src65_l); - src2110 = (v16i8) __msa_ilvr_d((v2i64) src65_l, (v2i64) src54_l); - dst2_r = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, dst2_r, dst2_r); + DPADD_SB2_SH(src32_r, src54_r, filt0, filt1, dst2_r, dst2_r); dst3_r = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, dst3_r, dst3_r); + DPADD_SB2_SH(src43_r, src65_r, filt0, filt1, dst3_r, dst3_r); dst1_l = const_vec; - DPADD_SB2_SH(src4332, src2110, filt0, filt1, dst1_l, dst1_l); + DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst1_l, dst1_l); HEVC_BI_RND_CLIP4(in0, in1, in2, in3, dst0_r, dst1_r, dst2_r, dst3_r, 7, dst0_r, dst1_r, dst2_r, dst3_r); @@ -3120,6 +3438,11 @@ static void hevc_vt_bi_4t_12w_msa(uint8_t *src0_ptr, dst0_l = (v8i16) __msa_pckev_b((v16i8) dst1_l, (v16i8) dst0_l); ST12x4_UB(dst0_r, dst1_r, dst0_l, dst, dst_stride); dst += (4 * dst_stride); + + src2 = src6; + src10_r = src54_r; + src21_r = src65_r; + src2110 = src6554; } } @@ -3449,20 +3772,20 @@ static void hevc_hv_bi_4t_4x2_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter_x, - const int8_t *filter_y, - int32_t height) + const int8_t *filter_y) { - v8i16 in0, in1; + uint64_t tp0, tp1; + v16u8 out; + v8i16 in0 = { 0 }; v16i8 src0, src1, src2, src3, src4; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; v8i16 filter_vec, const_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4; - v4i32 dst0_r, dst1_r; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; + v8i16 dst20, dst31, dst42, dst10, dst32, dst21, dst43, tmp; + v4i32 dst0, dst1; src0_ptr -= (src_stride + 1); @@ -3470,56 +3793,43 @@ static void hevc_hv_bi_4t_4x2_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; const_vec = __msa_ldi_h(128); const_vec <<= 6; - LD_SB3(src0_ptr, src_stride, src0, src1, src2); - src0_ptr += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); - - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); - - LD_SB2(src0_ptr, src_stride, src3, src4); - LD_SH2(src1_ptr, src2_stride, in0, in1); - in0 = (v8i16) __msa_ilvr_d((v2i64) in1, (v2i64) in0); - XORI_B2_128_SB(src3, src4); - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - dst0_r = (v4i32) __msa_pckev_h((v8i16) dst1_r, (v8i16) dst0_r); - dst0_r = (v4i32) __msa_adds_s_h((v8i16) dst0_r, in0); - dst0_r = (v4i32) __msa_srari_h((v8i16) dst0_r, 7); - dst0_r = (v4i32) CLIP_SH_0_255(dst0_r); - - dst0_r = (v4i32) __msa_pckev_b((v16i8) dst0_r, (v16i8) dst0_r); - ST4x2_UB(dst0_r, dst, dst_stride); + LD_SB5(src0_ptr, src_stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in0); + in0 = __msa_adds_s_h(in0, const_vec); + + VSHF_B2_SB(src0, src2, src0, src2, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src3, src1, src3, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src4, src2, src4, mask0, mask1, vec4, vec5); + + dst20 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst31 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst42 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + + ILVRL_H2_SH(dst31, dst20, dst10, dst32); + ILVRL_H2_SH(dst42, dst31, dst21, dst43); + + dst0 = HEVC_FILT_4TAP(dst10, dst32, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21, dst43, filt_h0, filt_h1); + dst0 >>= 6; + dst1 >>= 6; + tmp = __msa_pckev_h((v8i16) dst1, (v8i16) dst0); + tmp = __msa_adds_s_h(tmp, in0); + tmp = __msa_srari_h(tmp, 7); + tmp = CLIP_SH_0_255_MAX_SATU(tmp); + out = (v16u8) __msa_pckev_b((v16i8) tmp, (v16i8) tmp); + ST4x2_UB(out, dst, dst_stride); } static void hevc_hv_bi_4t_4x4_msa(uint8_t *src0_ptr, @@ -3529,21 +3839,22 @@ static void hevc_hv_bi_4t_4x4_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter_x, - const int8_t *filter_y, - int32_t height) + const int8_t *filter_y) { - v8i16 in0, in1, in2, in3; + uint64_t tp0, tp1; + v16u8 out; v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v8i16 dst0_r, dst1_r; - v4i32 tmp0, tmp1, tmp2, tmp3; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 tmp0, tmp1; + v8i16 in0 = { 0 }, in1 = { 0 }; + v8i16 dst30, dst41, dst52, dst63; + v8i16 dst10, dst32, dst54, dst21, dst43, dst65; + v4i32 dst0, dst1, dst2, dst3; src0_ptr -= (src_stride + 1); @@ -3551,69 +3862,50 @@ static void hevc_hv_bi_4t_4x4_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; + LD_SB7(src0_ptr, src_stride, src0, src1, src2, src3, src4, src5, src6); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + const_vec = __msa_ldi_h(128); const_vec <<= 6; - LD_SB3(src0_ptr, src_stride, src0, src1, src2); - src0_ptr += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); - - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); - - LD_SB4(src0_ptr, src_stride, src3, src4, src5, src6); - LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); - ILVR_D2_SH(in1, in0, in3, in2, in0, in1); - XORI_B4_128_SB(src3, src4, src5, src6); - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - dst32_r = __msa_ilvr_h(dst3, dst2); - tmp0 = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - tmp0 >>= 6; - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - dst43_r = __msa_ilvr_h(dst4, dst3); - tmp1 = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - tmp1 >>= 6; - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - dst10_r = __msa_ilvr_h(dst5, dst4); - tmp2 = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - tmp2 >>= 6; - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - dst21_r = __msa_ilvr_h(dst2, dst5); - tmp3 = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - tmp3 >>= 6; - PCKEV_H2_SH(tmp1, tmp0, tmp3, tmp2, dst0_r, dst1_r); - HEVC_BI_RND_CLIP2(in0, in1, dst0_r, dst1_r, 7, dst0_r, dst1_r); - - dst0_r = (v8i16) __msa_pckev_b((v16i8) dst1_r, (v16i8) dst0_r); - ST4x4_UB(dst0_r, dst0_r, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in0); + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in1); + + ADDS_SH2_SH(in0, const_vec, in1, const_vec, in0, in1); + + VSHF_B2_SB(src0, src3, src0, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src4, src1, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src5, src2, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src6, src3, src6, mask0, mask1, vec6, vec7); + + dst30 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst41 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst52 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst63 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + ILVRL_H2_SH(dst41, dst30, dst10, dst43); + ILVRL_H2_SH(dst52, dst41, dst21, dst54); + ILVRL_H2_SH(dst63, dst52, dst32, dst65); + dst0 = HEVC_FILT_4TAP(dst10, dst32, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21, dst43, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32, dst54, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43, dst65, filt_h0, filt_h1); + SRA_4V(dst0, dst1, dst2, dst3, 6); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp0, tmp1); + ADDS_SH2_SH(tmp0, in0, tmp1, in1, tmp0, tmp1); + SRARI_H2_SH(tmp0, tmp1, 7); + CLIP_SH2_0_255_MAX_SATU(tmp0, tmp1); + out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); } static void hevc_hv_bi_4t_4multx8mult_msa(uint8_t *src0_ptr, @@ -3627,18 +3919,21 @@ static void hevc_hv_bi_4t_4multx8mult_msa(uint8_t *src0_ptr, int32_t height) { uint32_t loop_cnt; - v8i16 in0, in1, in2, in3, in4, in5, in6, in7; + uint64_t tp0, tp1; + v16u8 out0, out1; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8, dst9; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v8i16 tmp0, tmp1, tmp2, tmp3; + v8i16 dst10, dst21, dst22, dst73, dst84, dst95, dst106; v8i16 dst10_r, dst32_r, dst54_r, dst76_r; v8i16 dst21_r, dst43_r, dst65_r, dst87_r; + v8i16 dst98_r, dst109_r; + v8i16 in0 = { 0 }, in1 = { 0 }, in2 = { 0 }, in3 = { 0 }; v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r, dst6_r, dst7_r; src0_ptr -= (src_stride + 1); @@ -3647,10 +3942,9 @@ static void hevc_hv_bi_4t_4multx8mult_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -3661,90 +3955,75 @@ static void hevc_hv_bi_4t_4multx8mult_msa(uint8_t *src0_ptr, src0_ptr += (3 * src_stride); XORI_B3_128_SB(src0, src1, src2); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); + VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src2, src1, src2, mask0, mask1, vec2, vec3); + dst10 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst21 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + ILVRL_H2_SH(dst21, dst10, dst10_r, dst21_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst21, 1); + for (loop_cnt = height >> 3; loop_cnt--;) { LD_SB8(src0_ptr, src_stride, src3, src4, src5, src6, src7, src8, src9, src10); src0_ptr += (8 * src_stride); - LD_SH8(src1_ptr, src2_stride, in0, in1, in2, in3, in4, in5, in6, in7); - src1_ptr += (8 * src2_stride); - ILVR_D2_SH(in1, in0, in3, in2, in0, in1); - ILVR_D2_SH(in5, in4, in7, in6, in2, in3); XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - dst32_r = __msa_ilvr_h(dst3, dst2); + VSHF_B2_SB(src3, src7, src3, src7, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src8, src4, src8, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src9, src5, src9, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src10, src6, src10, mask0, mask1, vec6, vec7); + + dst73 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst84 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst95 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst106 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + dst32_r = __msa_ilvr_h(dst73, dst22); + ILVRL_H2_SH(dst84, dst73, dst43_r, dst87_r); + ILVRL_H2_SH(dst95, dst84, dst54_r, dst98_r); + ILVRL_H2_SH(dst106, dst95, dst65_r, dst109_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst73, 1); + dst76_r = __msa_ilvr_h(dst22, dst106); + + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in0); + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in1); + + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in2); + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in3); + + ADDS_SH4_SH(in0, const_vec, in1, const_vec, in2, const_vec, in3, + const_vec, in0, in1, in2, in3); dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - dst43_r = __msa_ilvr_h(dst4, dst3); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - dst54_r = __msa_ilvr_h(dst5, dst4); dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); - dst2_r >>= 6; - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - dst65_r = __msa_ilvr_h(dst6, dst5); dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); - dst3_r >>= 6; - /* row 7 */ - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); - dst76_r = __msa_ilvr_h(dst7, dst6); dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); - dst4_r >>= 6; - /* row 8 */ - VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec0, vec1); - dst8 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst8, dst8); - dst87_r = __msa_ilvr_h(dst8, dst7); dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); - dst5_r >>= 6; - /* row 9 */ - VSHF_B2_SB(src9, src9, src9, src9, mask0, mask1, vec0, vec1); - dst9 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst9, dst9); - dst10_r = __msa_ilvr_h(dst9, dst8); - dst6_r = HEVC_FILT_4TAP(dst76_r, dst10_r, filt_h0, filt_h1); - dst6_r >>= 6; - /* row 10 */ - VSHF_B2_SB(src10, src10, src10, src10, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - dst21_r = __msa_ilvr_h(dst2, dst9); - dst7_r = HEVC_FILT_4TAP(dst87_r, dst21_r, filt_h0, filt_h1); - dst7_r >>= 6; + dst6_r = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7_r = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRA_4V(dst4_r, dst5_r, dst6_r, dst7_r, 6); PCKEV_H4_SH(dst1_r, dst0_r, dst3_r, dst2_r, dst5_r, dst4_r, dst7_r, dst6_r, tmp0, tmp1, tmp2, tmp3); - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - tmp0, tmp1, tmp2, tmp3, 7, tmp0, tmp1, tmp2, tmp3); - - PCKEV_B2_SH(tmp1, tmp0, tmp3, tmp2, tmp0, tmp1); - ST4x8_UB(tmp0, tmp1, dst, dst_stride); + ADDS_SH4_SH(in0, tmp0, in1, tmp1, in2, tmp2, in3, tmp3, tmp0, tmp1, + tmp2, tmp3); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 7); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); dst += (8 * dst_stride); + + dst10_r = dst98_r; + dst21_r = dst109_r; + dst22 = (v8i16) __msa_splati_d((v2i64) dst106, 1); } } @@ -3760,10 +4039,10 @@ static void hevc_hv_bi_4t_4w_msa(uint8_t *src0_ptr, { if (2 == height) { hevc_hv_bi_4t_4x2_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter_x, filter_y, height); + dst, dst_stride, filter_x, filter_y); } else if (4 == height) { hevc_hv_bi_4t_4x4_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter_x, filter_y, height); + dst, dst_stride, filter_x, filter_y); } else if (0 == (height % 8)) { hevc_hv_bi_4t_4multx8mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, @@ -3782,20 +4061,28 @@ static void hevc_hv_bi_4t_6w_msa(uint8_t *src0_ptr, const int8_t *filter_y, int32_t height) { - uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6; - v8i16 in0, in1, in2, in3; + uint32_t tpw0, tpw1, tpw2, tpw3; + uint64_t tp0, tp1; + v16u8 out0, out1, out2; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6, dsth7, dsth8, dsth9; + v8i16 dsth10, tmp4, tmp5; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + v4i32 dst4_r, dst5_r, dst6_r, dst7_r; v8i16 tmp0, tmp1, tmp2, tmp3; v8i16 dst10_r, dst32_r, dst21_r, dst43_r; v8i16 dst10_l, dst32_l, dst21_l, dst43_l; + v8i16 dst54_r, dst76_r, dst98_r, dst65_r, dst87_r, dst109_r; + v8i16 dst54_l, dst76_l, dst98_l, dst65_l, dst87_l, dst109_l; + v8i16 dst1021_l, dst3243_l, dst5465_l, dst7687_l, dst98109_l; + v8i16 in0 = { 0 }, in1 = { 0 }, in2 = { 0 }, in3 = { 0 }; + v8i16 in4 = { 0 }, in5 = { 0 }; src0_ptr -= (src_stride + 1); @@ -3803,10 +4090,9 @@ static void hevc_hv_bi_4t_6w_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -3819,72 +4105,102 @@ static void hevc_hv_bi_4t_6w_msa(uint8_t *src0_ptr, VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - - ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); - ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - - for (loop_cnt = height >> 2; loop_cnt--;) { - LD_SB4(src0_ptr, src_stride, src3, src4, src5, src6); - src0_ptr += (4 * src_stride); - LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); - src1_ptr += (4 * src2_stride); - XORI_B4_128_SB(src3, src4, src5, src6); - - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; + dsth0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; + LD_SB8(src0_ptr, src_stride, + src3, src4, src5, src6, src7, src8, src9, src10); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); - ILVRL_H2_SH(dst5, dst4, dst10_r, dst10_l); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_l = HEVC_FILT_4TAP(dst32_l, dst10_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; + dsth3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - ILVRL_H2_SH(dst2, dst5, dst21_r, dst21_l); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_l = HEVC_FILT_4TAP(dst43_l, dst21_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; - PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, tmp0, tmp1, tmp2, tmp3); - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - tmp0, tmp1, tmp2, tmp3, 7, tmp0, tmp1, tmp2, tmp3); + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src9, src9, src9, src9, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src10, src10, src10, src10, mask0, mask1, vec6, vec7); + + dsth7 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth8 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth9 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth10 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); + ILVRL_H2_SH(dsth7, dsth6, dst76_r, dst76_l); + ILVRL_H2_SH(dsth8, dsth7, dst87_r, dst87_l); + ILVRL_H2_SH(dsth9, dsth8, dst98_r, dst98_l); + ILVRL_H2_SH(dsth10, dsth9, dst109_r, dst109_l); + PCKEV_D2_SH(dst21_l, dst10_l, dst43_l, dst32_l, dst1021_l, dst3243_l); + PCKEV_D2_SH(dst65_l, dst54_l, dst87_l, dst76_l, dst5465_l, dst7687_l); + dst98109_l = (v8i16) __msa_pckev_d((v2i64) dst109_l, (v2i64) dst98_l); - PCKEV_B2_SW(tmp1, tmp0, tmp3, tmp2, dst0_r, dst1_r); - ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); - dst += (4 * dst_stride); - } + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6_r = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7_r = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst1021_l, dst3243_l, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst3243_l, dst5465_l, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst5465_l, dst7687_l, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst7687_l, dst98109_l, filt_h0, filt_h1); + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRA_4V(dst4_r, dst5_r, dst6_r, dst7_r, 6); + SRA_4V(dst0_l, dst1_l, dst2_l, dst3_l, 6); + PCKEV_H2_SH(dst1_r, dst0_r, dst3_r, dst2_r, tmp0, tmp1); + PCKEV_H2_SH(dst5_r, dst4_r, dst7_r, dst6_r, tmp2, tmp3); + PCKEV_H2_SH(dst1_l, dst0_l, dst3_l, dst2_l, tmp4, tmp5); + + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in0); + LD2(src1_ptr + 2 * src2_stride, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in1); + + LD2(src1_ptr + 4 * src2_stride, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in2); + LD2(src1_ptr + 6 * src2_stride, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in3); + + ADDS_SH4_SH(in0, const_vec, in1, const_vec, in2, const_vec, in3, const_vec, + in0, in1, in2, in3); + ADDS_SH4_SH(in0, tmp0, in1, tmp1, in2, tmp2, in3, tmp3, tmp0, tmp1, tmp2, + tmp3); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 7); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); + + LW4(src1_ptr + 4, src2_stride, tpw0, tpw1, tpw2, tpw3); + src1_ptr += (4 * src2_stride); + INSERT_W4_SH(tpw0, tpw1, tpw2, tpw3, in4); + LW4(src1_ptr + 4, src2_stride, tpw0, tpw1, tpw2, tpw3); + INSERT_W4_SH(tpw0, tpw1, tpw2, tpw3, in5); + ADDS_SH2_SH(in4, const_vec, in5, const_vec, in4, in5); + ADDS_SH2_SH(in4, tmp4, in5, tmp5, tmp4, tmp5); + SRARI_H2_SH(tmp4, tmp5, 7); + CLIP_SH2_0_255_MAX_SATU(tmp4, tmp5); + out2 = (v16u8) __msa_pckev_b((v16i8) tmp5, (v16i8) tmp4); + ST2x4_UB(out2, 0, dst + 4, dst_stride); + dst += 4 * dst_stride; + ST2x4_UB(out2, 4, dst + 4, dst_stride); } static void hevc_hv_bi_4t_8x2_msa(uint8_t *src0_ptr, @@ -3894,16 +4210,16 @@ static void hevc_hv_bi_4t_8x2_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter_x, - const int8_t *filter_y, - int32_t height) + const int8_t *filter_y) { + v16u8 out; v16i8 src0, src1, src2, src3, src4; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; v8i16 dst0, dst1, dst2, dst3, dst4; v4i32 dst0_r, dst0_l, dst1_r, dst1_l; v8i16 dst10_r, dst32_r, dst21_r, dst43_r; @@ -3917,62 +4233,144 @@ static void hevc_hv_bi_4t_8x2_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; const_vec = __msa_ldi_h(128); const_vec <<= 6; - LD_SB3(src0_ptr, src_stride, src0, src1, src2); - src0_ptr += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); + LD_SB5(src0_ptr, src_stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + + LD_SH2(src1_ptr, src2_stride, in0, in1); + ADDS_SH2_SH(in0, const_vec, in1, const_vec, in0, in1); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec8, vec9); + + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec8, vec9, filt0, filt1); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - - LD_SB2(src0_ptr, src_stride, src3, src4); - LD_SH2(src1_ptr, src2_stride, in0, in1); - XORI_B2_128_SB(src3, src4); - - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); PCKEV_H2_SH(dst0_l, dst0_r, dst1_l, dst1_r, tmp0, tmp1); - HEVC_BI_RND_CLIP2(in0, in1, tmp0, tmp1, 7, tmp0, tmp1); + ADDS_SH2_SH(in0, tmp0, in1, tmp1, tmp0, tmp1); + SRARI_H2_SH(tmp0, tmp1, 7); + CLIP_SH2_0_255_MAX_SATU(tmp0, tmp1); + out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); + ST8x2_UB(out, dst, dst_stride); +} - dst0_r = (v4i32) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); - ST8x2_UB(dst0_r, dst, dst_stride); +static void hevc_hv_bi_4t_8multx4_msa(uint8_t *src0_ptr, + int32_t src_stride, + int16_t *src1_ptr, + int32_t src2_stride, + uint8_t *dst, + int32_t dst_stride, + const int8_t *filter_x, + const int8_t *filter_y, + int32_t width8mult) +{ + uint32_t cnt; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, mask0, mask1; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 filt0, filt1, filt_h0, filt_h1, filter_vec, const_vec; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, tmp0, tmp1, tmp2, tmp3; + v8i16 in0, in1, in2, in3; + v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; + + src0_ptr -= (src_stride + 1); + + filter_vec = LD_SH(filter_x); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + + const_vec = __msa_ldi_h(128); + const_vec <<= 6; + + for (cnt = width8mult; cnt--;) { + LD_SB7(src0_ptr, src_stride, src0, src1, src2, src3, src4, src5, src6); + src0_ptr += 8; + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); + src1_ptr += 8; + ADDS_SH4_SH(in0, const_vec, in1, const_vec, in2, const_vec, in3, + const_vec, in0, in1, in2, in3); + + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + + ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); + ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); + + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, tmp0, tmp1, tmp2, tmp3); + ADDS_SH4_SH(in0, tmp0, in1, tmp1, in2, tmp2, in3, tmp3, + tmp0, tmp1, tmp2, tmp3); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 7); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST8x4_UB(out0, out1, dst, dst_stride); + dst += 8; + } } static void hevc_hv_bi_4t_8x6_msa(uint8_t *src0_ptr, @@ -3982,17 +4380,18 @@ static void hevc_hv_bi_4t_8x6_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter_x, - const int8_t *filter_y, - int32_t height) + const int8_t *filter_y) { + v16u8 out0, out1, out2; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v8i16 in0, in1, in2, in3, in4, in5; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; + v16i8 vec10, vec11, vec12, vec13, vec14, vec15, vec16, vec17; v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; @@ -4008,120 +4407,87 @@ static void hevc_hv_bi_4t_8x6_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; const_vec = __msa_ldi_h(128); const_vec <<= 6; - LD_SB3(src0_ptr, src_stride, src0, src1, src2); - src0_ptr += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); + LD_SB5(src0_ptr, src_stride, src0, src1, src2, src3, src4); + src0_ptr += (5 * src_stride); + LD_SB4(src0_ptr, src_stride, src5, src6, src7, src8); + + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B4_128_SB(src5, src6, src7, src8); + + LD_SH6(src1_ptr, src2_stride, in0, in1, in2, in3, in4, in5); + ADDS_SH4_SH(in0, const_vec, in1, const_vec, in2, const_vec, in3, const_vec, + in0, in1, in2, in3); + ADDS_SH2_SH(in4, const_vec, in5, const_vec, in4, in5); + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec8, vec9); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec10, vec11); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec12, vec13); + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec14, vec15); + VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec16, vec17); + + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec8, vec9, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec10, vec11, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec12, vec13, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(vec14, vec15, filt0, filt1); + dst8 = HEVC_FILT_4TAP_SH(vec16, vec17, filt0, filt1); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - - LD_SB2(src0_ptr, src_stride, src3, src4); - src0_ptr += (2 * src_stride); - XORI_B2_128_SB(src3, src4); - LD_SH6(src1_ptr, src2_stride, in0, in1, in2, in3, in4, in5); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); + ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - tmp0 = __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - tmp1 = __msa_pckev_h((v8i16) dst1_l, (v8i16) dst1_r); - - LD_SB2(src0_ptr, src_stride, src5, src6); - src0_ptr += (2 * src_stride); - XORI_B2_128_SB(src5, src6); - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; - tmp2 = __msa_pckev_h((v8i16) dst2_l, (v8i16) dst2_r); - - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - - ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; - tmp3 = __msa_pckev_h((v8i16) dst3_l, (v8i16) dst3_r); - - LD_SB2(src0_ptr, src_stride, src7, src8); - XORI_B2_128_SB(src7, src8); - /* row 7 */ - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); - - ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); dst4_l = HEVC_FILT_4TAP(dst54_l, dst76_l, filt_h0, filt_h1); - - dst4_r >>= 6; - dst4_l >>= 6; - tmp4 = __msa_pckev_h((v8i16) dst4_l, (v8i16) dst4_r); - /* row 8 */ - VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec0, vec1); - dst8 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst8, dst8); - - ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); dst5_l = HEVC_FILT_4TAP(dst65_l, dst87_l, filt_h0, filt_h1); - dst5_r >>= 6; - dst5_l >>= 6; - tmp5 = __msa_pckev_h((v8i16) dst5_l, (v8i16) dst5_r); - - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - tmp0, tmp1, tmp2, tmp3, 7, tmp0, tmp1, tmp2, tmp3); - HEVC_BI_RND_CLIP2(in4, in5, tmp4, tmp5, 7, tmp4, tmp5); - PCKEV_B2_SW(tmp1, tmp0, tmp3, tmp2, dst0_r, dst1_r); - dst2_r = (v4i32) __msa_pckev_b((v16i8) tmp5, (v16i8) tmp4); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + SRA_4V(dst4_r, dst4_l, dst5_r, dst5_l, 6); + PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, dst3_r, + tmp0, tmp1, tmp2, tmp3); + PCKEV_H2_SH(dst4_l, dst4_r, dst5_l, dst5_r, tmp4, tmp5); + ADDS_SH4_SH(in0, tmp0, in1, tmp1, in2, tmp2, in3, tmp3, + tmp0, tmp1, tmp2, tmp3); + ADDS_SH2_SH(in4, tmp4, in5, tmp5, tmp4, tmp5); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 7); + SRARI_H2_SH(tmp4, tmp5, 7); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + CLIP_SH2_0_255_MAX_SATU(tmp4, tmp5); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + out2 = (v16u8) __msa_pckev_b((v16i8) tmp5, (v16i8) tmp4); + ST8x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); - ST8x2_UB(dst2_r, dst, dst_stride); + ST8x2_UB(out2, dst, dst_stride); } static void hevc_hv_bi_4t_8multx4mult_msa(uint8_t *src0_ptr, @@ -4139,19 +4505,21 @@ static void hevc_hv_bi_4t_8multx4mult_msa(uint8_t *src0_ptr, uint8_t *src0_ptr_tmp; int16_t *src1_ptr_tmp; uint8_t *dst_tmp; + v16u8 out0, out1; v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 in0, in1, in2, in3; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; v8i16 tmp0, tmp1, tmp2, tmp3; v8i16 dst10_r, dst32_r, dst21_r, dst43_r; v8i16 dst10_l, dst32_l, dst21_l, dst43_l; + v8i16 dst54_r, dst54_l, dst65_r, dst65_l, dst6; src0_ptr -= (src_stride + 1); @@ -4159,10 +4527,9 @@ static void hevc_hv_bi_4t_8multx4mult_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -4181,12 +4548,10 @@ static void hevc_hv_bi_4t_8multx4mult_msa(uint8_t *src0_ptr, VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); @@ -4198,55 +4563,50 @@ static void hevc_hv_bi_4t_8multx4mult_msa(uint8_t *src0_ptr, src1_ptr_tmp += (4 * src2_stride); XORI_B4_128_SB(src3, src4, src5, src6); + ADDS_SH4_SH(in0, const_vec, in1, const_vec, in2, const_vec, in3, + const_vec, in0, in1, in2, in3); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - ILVRL_H2_SH(dst5, dst4, dst10_r, dst10_l); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_l = HEVC_FILT_4TAP(dst32_l, dst10_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; - - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - ILVRL_H2_SH(dst2, dst5, dst21_r, dst21_l); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_l = HEVC_FILT_4TAP(dst43_l, dst21_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; - - PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, tmp0, tmp1, tmp2, tmp3); - HEVC_BI_RND_CLIP4(in0, in1, in2, in3, - tmp0, tmp1, tmp2, tmp3, 7, - tmp0, tmp1, tmp2, tmp3); - - PCKEV_B2_SW(tmp1, tmp0, tmp3, tmp2, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst_tmp, dst_stride); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, tmp0, tmp1, tmp2, tmp3); + ADDS_SH4_SH(in0, tmp0, in1, tmp1, in2, tmp2, in3, tmp3, + tmp0, tmp1, tmp2, tmp3); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 7); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST8x4_UB(out0, out1, dst_tmp, dst_stride); dst_tmp += (4 * dst_stride); + + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dst2 = dst6; } src0_ptr += 8; @@ -4267,10 +4627,13 @@ static void hevc_hv_bi_4t_8w_msa(uint8_t *src0_ptr, { if (2 == height) { hevc_hv_bi_4t_8x2_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter_x, filter_y, height); + dst, dst_stride, filter_x, filter_y); + } else if (4 == height) { + hevc_hv_bi_4t_8multx4_msa(src0_ptr, src_stride, src1_ptr, src2_stride, + dst, dst_stride, filter_x, filter_y, 1); } else if (6 == height) { hevc_hv_bi_4t_8x6_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter_x, filter_y, height); + dst, dst_stride, filter_x, filter_y); } else { hevc_hv_bi_4t_8multx4mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, @@ -4289,11 +4652,196 @@ static void hevc_hv_bi_4t_12w_msa(uint8_t *src0_ptr, const int8_t *filter_y, int32_t height) { - hevc_hv_bi_4t_8multx4mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter_x, filter_y, - height, 8); - hevc_hv_bi_4t_4w_msa(src0_ptr + 8, src_stride, src1_ptr + 8, src2_stride, - dst + 8, dst_stride, filter_x, filter_y, height); + uint32_t loop_cnt; + uint64_t tp0, tp1; + uint8_t *src0_ptr_tmp, *dst_tmp; + int16_t *src1_ptr_tmp; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 mask0, mask1, mask2, mask3; + v8i16 filt0, filt1, filt_h0, filt_h1, filter_vec, tmp0, tmp1, tmp2, tmp3; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6, const_vec; + v8i16 dst10, dst21, dst22, dst73, dst84, dst95, dst106; + v8i16 dst76_r, dst98_r, dst87_r, dst109_r; + v8i16 in0 = { 0 }, in1 = { 0 }, in2 = { 0 }, in3 = { 0 }; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; + v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + v4i32 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + + src0_ptr -= (src_stride + 1); + + filter_vec = LD_SH(filter_x); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + + const_vec = __msa_ldi_h(128); + const_vec <<= 6; + + src0_ptr_tmp = src0_ptr; + dst_tmp = dst; + src1_ptr_tmp = src1_ptr; + + LD_SB3(src0_ptr_tmp, src_stride, src0, src1, src2); + src0_ptr_tmp += (3 * src_stride); + + XORI_B3_128_SB(src0, src1, src2); + + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + + dsth0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src0_ptr_tmp, src_stride, src3, src4, src5, src6); + src0_ptr_tmp += (4 * src_stride); + XORI_B4_128_SB(src3, src4, src5, src6); + + LD_SH4(src1_ptr_tmp, src2_stride, in0, in1, in2, in3); + src1_ptr_tmp += (4 * src2_stride); + ADDS_SH4_SH(in0, const_vec, in1, const_vec, in2, const_vec, in3, + const_vec, in0, in1, in2, in3); + + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + + dsth3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); + + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, tmp0, tmp1, tmp2, tmp3); + ADDS_SH4_SH(in0, tmp0, in1, tmp1, in2, tmp2, in3, tmp3, + tmp0, tmp1, tmp2, tmp3); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 7); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST8x4_UB(out0, out1, dst_tmp, dst_stride); + dst_tmp += (4 * dst_stride); + + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dsth2 = dsth6; + } + + src0_ptr += 8; + dst += 8; + src1_ptr += 8; + + mask2 = LD_SB(ff_hevc_mask_arr + 16); + mask3 = mask2 + 2; + + LD_SB3(src0_ptr, src_stride, src0, src1, src2); + src0_ptr += (3 * src_stride); + XORI_B3_128_SB(src0, src1, src2); + VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); + VSHF_B2_SB(src1, src2, src1, src2, mask2, mask3, vec2, vec3); + + dst10 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst21 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + + ILVRL_H2_SH(dst21, dst10, dst10_r, dst21_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst21, 1); + + for (loop_cnt = 2; loop_cnt--;) { + LD_SB8(src0_ptr, src_stride, + src3, src4, src5, src6, src7, src8, src9, src10); + src0_ptr += (8 * src_stride); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); + VSHF_B2_SB(src3, src7, src3, src7, mask2, mask3, vec0, vec1); + VSHF_B2_SB(src4, src8, src4, src8, mask2, mask3, vec2, vec3); + VSHF_B2_SB(src5, src9, src5, src9, mask2, mask3, vec4, vec5); + VSHF_B2_SB(src6, src10, src6, src10, mask2, mask3, vec6, vec7); + + dst73 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst84 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst95 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst106 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + dst32_r = __msa_ilvr_h(dst73, dst22); + ILVRL_H2_SH(dst84, dst73, dst43_r, dst87_r); + ILVRL_H2_SH(dst95, dst84, dst54_r, dst98_r); + ILVRL_H2_SH(dst106, dst95, dst65_r, dst109_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst73, 1); + dst76_r = __msa_ilvr_h(dst22, dst106); + + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in0); + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in1); + + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in2); + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in3); + + ADDS_SH4_SH(in0, const_vec, in1, const_vec, in2, const_vec, in3, + const_vec, in0, in1, in2, in3); + + dst0 = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4 = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5 = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6 = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7 = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + + SRA_4V(dst0, dst1, dst2, dst3, 6); + SRA_4V(dst4, dst5, dst6, dst7, 6); + PCKEV_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, + tmp0, tmp1, tmp2, tmp3); + ADDS_SH4_SH(in0, tmp0, in1, tmp1, in2, tmp2, in3, tmp3, + tmp0, tmp1, tmp2, tmp3); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 7); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); + dst += (8 * dst_stride); + + dst10_r = dst98_r; + dst21_r = dst109_r; + dst22 = (v8i16) __msa_splati_d((v2i64) dst106, 1); + } } static void hevc_hv_bi_4t_16w_msa(uint8_t *src0_ptr, @@ -4306,9 +4854,14 @@ static void hevc_hv_bi_4t_16w_msa(uint8_t *src0_ptr, const int8_t *filter_y, int32_t height) { - hevc_hv_bi_4t_8multx4mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter_x, filter_y, - height, 16); + if (4 == height) { + hevc_hv_bi_4t_8multx4_msa(src0_ptr, src_stride, src1_ptr, src2_stride, + dst, dst_stride, filter_x, filter_y, 2); + } else { + hevc_hv_bi_4t_8multx4mult_msa(src0_ptr, src_stride, src1_ptr, + src2_stride, dst, dst_stride, filter_x, + filter_y, height, 16); + } } static void hevc_hv_bi_4t_24w_msa(uint8_t *src0_ptr, @@ -4333,7 +4886,7 @@ static void hevc_hv_bi_4t_32w_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter_x, - const const int8_t *filter_y, + const int8_t *filter_y, int32_t height) { hevc_hv_bi_4t_8multx4mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, @@ -4368,22 +4921,22 @@ BI_MC_COPY(64); #undef BI_MC_COPY -#define BI_MC(PEL, DIR, WIDTH, TAP, DIR1, FILT_DIR) \ -void ff_hevc_put_hevc_bi_##PEL##_##DIR##WIDTH##_8_msa(uint8_t *dst, \ - ptrdiff_t dst_stride, \ - uint8_t *src, \ - ptrdiff_t src_stride, \ - int16_t *src_16bit, \ - int height, \ - intptr_t mx, \ - intptr_t my, \ - int width) \ -{ \ - const int8_t *filter = ff_hevc_##PEL##_filters[FILT_DIR - 1]; \ - \ - hevc_##DIR1##_bi_##TAP##t_##WIDTH##w_msa(src, src_stride, src_16bit, \ - MAX_PB_SIZE, dst, dst_stride, \ - filter, height); \ +#define BI_MC(PEL, DIR, WIDTH, TAP, DIR1, FILT_DIR) \ +void ff_hevc_put_hevc_bi_##PEL##_##DIR##WIDTH##_8_msa(uint8_t *dst, \ + ptrdiff_t dst_stride, \ + uint8_t *src, \ + ptrdiff_t src_stride, \ + int16_t *src_16bit, \ + int height, \ + intptr_t mx, \ + intptr_t my, \ + int width) \ +{ \ + const int8_t *filter = ff_hevc_##PEL##_filters[FILT_DIR - 1]; \ + \ + hevc_##DIR1##_bi_##TAP##t_##WIDTH##w_msa(src, src_stride, src_16bit, \ + MAX_PB_SIZE, dst, dst_stride, \ + filter, height); \ } BI_MC(qpel, h, 4, 8, hz, mx); @@ -4422,41 +4975,40 @@ BI_MC(epel, v, 32, 4, vt, my); #undef BI_MC -#define BI_MC_HV(PEL, DIR, WIDTH, TAP, DIR1) \ -void ff_hevc_put_hevc_bi_##PEL##_##DIR##WIDTH##_8_msa(uint8_t *dst, \ - ptrdiff_t dst_stride, \ - uint8_t *src, \ - ptrdiff_t src_stride, \ - int16_t *src_16bit, \ - int height, \ - intptr_t mx, \ - intptr_t my, \ - int width) \ -{ \ - const int8_t *filter_x = ff_hevc_##PEL##_filters[mx - 1]; \ - const int8_t *filter_y = ff_hevc_##PEL##_filters[my - 1]; \ - \ - hevc_##DIR1##_bi_##TAP##t_##WIDTH##w_msa(src, src_stride, src_16bit, \ - MAX_PB_SIZE, dst, dst_stride, \ - filter_x, filter_y, \ - height); \ +#define BI_MC_HV(PEL, WIDTH, TAP) \ +void ff_hevc_put_hevc_bi_##PEL##_hv##WIDTH##_8_msa(uint8_t *dst, \ + ptrdiff_t dst_stride, \ + uint8_t *src, \ + ptrdiff_t src_stride, \ + int16_t *src_16bit, \ + int height, \ + intptr_t mx, \ + intptr_t my, \ + int width) \ +{ \ + const int8_t *filter_x = ff_hevc_##PEL##_filters[mx - 1]; \ + const int8_t *filter_y = ff_hevc_##PEL##_filters[my - 1]; \ + \ + hevc_hv_bi_##TAP##t_##WIDTH##w_msa(src, src_stride, src_16bit, \ + MAX_PB_SIZE, dst, dst_stride, \ + filter_x, filter_y, height); \ } -BI_MC_HV(qpel, hv, 4, 8, hv); -BI_MC_HV(qpel, hv, 8, 8, hv); -BI_MC_HV(qpel, hv, 12, 8, hv); -BI_MC_HV(qpel, hv, 16, 8, hv); -BI_MC_HV(qpel, hv, 24, 8, hv); -BI_MC_HV(qpel, hv, 32, 8, hv); -BI_MC_HV(qpel, hv, 48, 8, hv); -BI_MC_HV(qpel, hv, 64, 8, hv); - -BI_MC_HV(epel, hv, 4, 4, hv); -BI_MC_HV(epel, hv, 8, 4, hv); -BI_MC_HV(epel, hv, 6, 4, hv); -BI_MC_HV(epel, hv, 12, 4, hv); -BI_MC_HV(epel, hv, 16, 4, hv); -BI_MC_HV(epel, hv, 24, 4, hv); -BI_MC_HV(epel, hv, 32, 4, hv); +BI_MC_HV(qpel, 4, 8); +BI_MC_HV(qpel, 8, 8); +BI_MC_HV(qpel, 12, 8); +BI_MC_HV(qpel, 16, 8); +BI_MC_HV(qpel, 24, 8); +BI_MC_HV(qpel, 32, 8); +BI_MC_HV(qpel, 48, 8); +BI_MC_HV(qpel, 64, 8); + +BI_MC_HV(epel, 4, 4); +BI_MC_HV(epel, 8, 4); +BI_MC_HV(epel, 6, 4); +BI_MC_HV(epel, 12, 4); +BI_MC_HV(epel, 16, 4); +BI_MC_HV(epel, 24, 4); +BI_MC_HV(epel, 32, 4); #undef BI_MC_HV diff --git a/libavcodec/mips/hevc_mc_biw_msa.c b/libavcodec/mips/hevc_mc_biw_msa.c index 05a28ece44f33..ea65f00497dd0 100644 --- a/libavcodec/mips/hevc_mc_biw_msa.c +++ b/libavcodec/mips/hevc_mc_biw_msa.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Manojkumar Bhosale (Manojkumar.Bhosale@imgtec.com) + * Copyright (c) 2015 - 2017 Manojkumar Bhosale (Manojkumar.Bhosale@imgtec.com) * * This file is part of FFmpeg. * @@ -22,9 +22,17 @@ #include "libavcodec/mips/hevcdsp_mips.h" #include "libavcodec/mips/hevc_macros_msa.h" +static const uint8_t ff_hevc_mask_arr[16 * 2] __attribute__((aligned(0x40))) = { + /* 8 width cases */ + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, + 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 +}; + #define HEVC_BIW_RND_CLIP2(in0, in1, vec0, vec1, wgt, rnd, offset, \ - out0_r, out1_r, out0_l, out1_l) \ + out0, out1) \ { \ + v4i32 out0_r, out1_r, out0_l, out1_l; \ + \ ILVR_H2_SW(in0, vec0, in1, vec1, out0_r, out1_r); \ ILVL_H2_SW(in0, vec0, in1, vec1, out0_l, out1_l); \ \ @@ -34,37 +42,41 @@ out1_l = __msa_dpadd_s_w(offset, (v8i16) out1_l, (v8i16) wgt); \ \ SRAR_W4_SW(out0_r, out1_r, out0_l, out1_l, rnd); \ - \ - out0_r = CLIP_SW_0_255(out0_r); \ - out1_r = CLIP_SW_0_255(out1_r); \ - out0_l = CLIP_SW_0_255(out0_l); \ - out1_l = CLIP_SW_0_255(out1_l); \ + PCKEV_H2_SH(out0_l, out0_r, out1_l, out1_r, out0, out1); \ + CLIP_SH2_0_255(out0, out1); \ } -#define HEVC_BIW_RND_CLIP4(in0, in1, in2, in3, vec0, vec1, vec2, vec3, \ - wgt, rnd, offset, \ - out0_r, out1_r, out2_r, out3_r, \ - out0_l, out1_l, out2_l, out3_l) \ -{ \ - HEVC_BIW_RND_CLIP2(in0, in1, vec0, vec1, wgt, rnd, offset, \ - out0_r, out1_r, out0_l, out1_l) \ - HEVC_BIW_RND_CLIP2(in2, in3, vec2, vec3, wgt, rnd, offset, \ - out2_r, out3_r, out2_l, out3_l) \ +#define HEVC_BIW_RND_CLIP4(in0, in1, in2, in3, vec0, vec1, vec2, vec3, \ + wgt, rnd, offset, out0, out1, out2, out3) \ +{ \ + HEVC_BIW_RND_CLIP2(in0, in1, vec0, vec1, wgt, rnd, offset, out0, out1); \ + HEVC_BIW_RND_CLIP2(in2, in3, vec2, vec3, wgt, rnd, offset, out2, out3); \ } -#define HEVC_BI_RND_CLIP2(in0, in1, vec0, vec1, rnd_val, out0, out1) \ -{ \ - ADDS_SH2_SH(vec0, in0, vec1, in1, out0, out1); \ - SRARI_H2_SH(out0, out1, rnd_val); \ - CLIP_SH2_0_255(out0, out1); \ +#define HEVC_BIW_RND_CLIP2_MAX_SATU(in0, in1, vec0, vec1, wgt, rnd, \ + offset, out0, out1) \ +{ \ + v4i32 out0_r, out1_r, out0_l, out1_l; \ + \ + ILVR_H2_SW(in0, vec0, in1, vec1, out0_r, out1_r); \ + ILVL_H2_SW(in0, vec0, in1, vec1, out0_l, out1_l); \ + out0_r = __msa_dpadd_s_w(offset, (v8i16) out0_r, (v8i16) wgt); \ + out1_r = __msa_dpadd_s_w(offset, (v8i16) out1_r, (v8i16) wgt); \ + out0_l = __msa_dpadd_s_w(offset, (v8i16) out0_l, (v8i16) wgt); \ + out1_l = __msa_dpadd_s_w(offset, (v8i16) out1_l, (v8i16) wgt); \ + SRAR_W4_SW(out0_r, out1_r, out0_l, out1_l, rnd); \ + PCKEV_H2_SH(out0_l, out0_r, out1_l, out1_r, out0, out1); \ + CLIP_SH2_0_255_MAX_SATU(out0, out1); \ } -#define HEVC_BI_RND_CLIP4(in0, in1, in2, in3, \ - vec0, vec1, vec2, vec3, rnd_val, \ - out0, out1, out2, out3) \ -{ \ - HEVC_BI_RND_CLIP2(in0, in1, vec0, vec1, rnd_val, out0, out1); \ - HEVC_BI_RND_CLIP2(in2, in3, vec2, vec3, rnd_val, out2, out3); \ +#define HEVC_BIW_RND_CLIP4_MAX_SATU(in0, in1, in2, in3, vec0, vec1, vec2, \ + vec3, wgt, rnd, offset, out0, out1, \ + out2, out3) \ +{ \ + HEVC_BIW_RND_CLIP2_MAX_SATU(in0, in1, vec0, vec1, wgt, rnd, offset, \ + out0, out1); \ + HEVC_BIW_RND_CLIP2_MAX_SATU(in2, in3, vec2, vec3, wgt, rnd, offset, \ + out2, out3); \ } static void hevc_biwgt_copy_4w_msa(uint8_t *src0_ptr, @@ -80,93 +92,77 @@ static void hevc_biwgt_copy_4w_msa(uint8_t *src0_ptr, int32_t offset1, int32_t rnd_val) { + uint32_t loop_cnt, tp0, tp1, tp2, tp3; + uint64_t tpd0, tpd1, tpd2, tpd3; int32_t offset, weight; + v16u8 out0, out1; v16i8 zero = { 0 }; - v4i32 weight_vec, offset_vec, rnd_vec; + v16i8 src0 = { 0 }, src1 = { 0 }; + v8i16 in0 = { 0 }, in1 = { 0 }, in2 = { 0 }, in3 = { 0 }; + v8i16 dst0, dst1, dst2, dst3, weight_vec; + v4i32 dst0_r, dst0_l, offset_vec, rnd_vec; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); offset_vec = __msa_fill_w(offset); - weight_vec = __msa_fill_w(weight); + weight_vec = (v8i16) __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); if (2 == height) { - v16i8 src0, src1; - v8i16 in0, in1, dst0; - v4i32 dst0_r, dst0_l; - - LD_SB2(src0_ptr, src_stride, src0, src1); - LD_SH2(src1_ptr, src2_stride, in0, in1); - in0 = (v8i16) __msa_ilvr_d((v2i64) in1, (v2i64) in0); - src0 = (v16i8) __msa_ilvr_w((v4i32) src1, (v4i32) src0); + LW2(src0_ptr, src_stride, tp0, tp1); + INSERT_W2_SB(tp0, tp1, src0); + LD2(src1_ptr, src2_stride, tpd0, tpd1); + INSERT_D2_SH(tpd0, tpd1, in0); dst0 = (v8i16) __msa_ilvr_b(zero, src0); dst0 <<= 6; ILVRL_H2_SW(dst0, in0, dst0_r, dst0_l); - dst0_r = __msa_dpadd_s_w(offset_vec, (v8i16) dst0_r, - (v8i16) weight_vec); - dst0_l = __msa_dpadd_s_w(offset_vec, (v8i16) dst0_l, - (v8i16) weight_vec); + dst0_r = __msa_dpadd_s_w(offset_vec, (v8i16) dst0_r, weight_vec); + dst0_l = __msa_dpadd_s_w(offset_vec, (v8i16) dst0_l, weight_vec); SRAR_W2_SW(dst0_r, dst0_l, rnd_vec); - dst0_r = CLIP_SW_0_255(dst0_r); - dst0_l = CLIP_SW_0_255(dst0_l); - - HEVC_PCK_SW_SB2(dst0_l, dst0_r, dst0_r); - ST4x2_UB(dst0_r, dst, dst_stride); + dst0 = (v8i16) __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); + dst0 = CLIP_SH_0_255_MAX_SATU(dst0); + out0 = (v16u8) __msa_pckev_b((v16i8) dst0, (v16i8) dst0); + ST4x2_UB(out0, dst, dst_stride); } else if (4 == height) { - v16i8 src0, src1, src2, src3; - v8i16 in0, in1, in2, in3; - v8i16 dst0, dst1; - v4i32 dst0_r, dst1_r, dst0_l, dst1_l; - - LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); - LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); - ILVR_D2_SH(in1, in0, in3, in2, in0, in1); - ILVR_W2_SB(src1, src0, src3, src2, src0, src1); - ILVR_B2_SH(zero, src0, zero, src1, dst0, dst1); - dst0 <<= 6; - dst1 <<= 6; - HEVC_BIW_RND_CLIP2(dst0, dst1, in0, in1, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); - - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST4x4_UB(dst0_r, dst0_r, 0, 1, 2, 3, dst, dst_stride); + LW4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + INSERT_W4_SB(tp0, tp1, tp2, tp3, src0); + LD4(src1_ptr, src2_stride, tpd0, tpd1, tpd2, tpd3); + INSERT_D2_SH(tpd0, tpd1, in0); + INSERT_D2_SH(tpd2, tpd3, in1); + ILVRL_B2_SH(zero, src0, dst0, dst1); + SLLI_2V(dst0, dst1, 6); + HEVC_BIW_RND_CLIP2_MAX_SATU(dst0, dst1, in0, in1, weight_vec, rnd_vec, + offset_vec, dst0, dst1); + out0 = (v16u8) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); + ST4x4_UB(out0, out0, 0, 1, 2, 3, dst, dst_stride); } else if (0 == height % 8) { - uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7; - v8i16 in0, in1, in2, in3, in4, in5, in6, in7; - v8i16 dst0, dst1, dst2, dst3; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - for (loop_cnt = (height >> 3); loop_cnt--;) { - LD_SB8(src0_ptr, src_stride, - src0, src1, src2, src3, src4, src5, src6, src7); - src0_ptr += (8 * src_stride); - LD_SH8(src1_ptr, src2_stride, - in0, in1, in2, in3, in4, in5, in6, in7); - src1_ptr += (8 * src2_stride); - - ILVR_D2_SH(in1, in0, in3, in2, in0, in1); - ILVR_D2_SH(in5, in4, in7, in6, in2, in3); - ILVR_W4_SB(src1, src0, src3, src2, src5, src4, src7, src6, - src0, src1, src2, src3); - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0, dst1, dst2, dst3); - + LW4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + src0_ptr += 4 * src_stride; + INSERT_W4_SB(tp0, tp1, tp2, tp3, src0); + LW4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + src0_ptr += 4 * src_stride; + INSERT_W4_SB(tp0, tp1, tp2, tp3, src1); + LD4(src1_ptr, src2_stride, tpd0, tpd1, tpd2, tpd3); + src1_ptr += (4 * src2_stride); + INSERT_D2_SH(tpd0, tpd1, in0); + INSERT_D2_SH(tpd2, tpd3, in1); + LD4(src1_ptr, src2_stride, tpd0, tpd1, tpd2, tpd3); + src1_ptr += (4 * src2_stride); + INSERT_D2_SH(tpd0, tpd1, in2); + INSERT_D2_SH(tpd2, tpd3, in3); + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); SLLI_4V(dst0, dst1, dst2, dst3, 6); - HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, - in0, in1, in2, in3, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST4x8_UB(dst0_r, dst1_r, dst, dst_stride); + HEVC_BIW_RND_CLIP4_MAX_SATU(dst0, dst1, dst2, dst3, in0, in1, in2, + in3, weight_vec, rnd_vec, offset_vec, + dst0, dst1, dst2, dst3); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); dst += (8 * dst_stride); } } @@ -187,11 +183,12 @@ static void hevc_biwgt_copy_6w_msa(uint8_t *src0_ptr, { uint32_t loop_cnt; int32_t offset, weight; + uint64_t tp0, tp1, tp2, tp3; + v16u8 out0, out1; v16i8 zero = { 0 }; - v16i8 src0, src1, src2, src3; + v16i8 src0 = { 0 }, src1 = { 0 }; v8i16 in0, in1, in2, in3; v8i16 dst0, dst1, dst2, dst3; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; v4i32 offset_vec, weight_vec, rnd_vec; offset = (offset0 + offset1) << rnd_val; @@ -203,23 +200,21 @@ static void hevc_biwgt_copy_6w_msa(uint8_t *src0_ptr, rnd_vec = __msa_fill_w(rnd_val + 1); for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); + LD4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); src0_ptr += (4 * src_stride); + INSERT_D2_SB(tp0, tp1, src0); + INSERT_D2_SB(tp2, tp3, src1); LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); src1_ptr += (4 * src2_stride); - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0, dst1, dst2, dst3); - + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); SLLI_4V(dst0, dst1, dst2, dst3, 6); - HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, - in0, in1, in2, in3, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); + HEVC_BIW_RND_CLIP4_MAX_SATU(dst0, dst1, dst2, dst3, + in0, in1, in2, in3, + weight_vec, rnd_vec, offset_vec, + dst0, dst1, dst2, dst3); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + ST6x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -237,8 +232,13 @@ static void hevc_biwgt_copy_8w_msa(uint8_t *src0_ptr, int32_t offset1, int32_t rnd_val) { + uint64_t tp0, tp1, tp2, tp3; int32_t offset, weight; + v16u8 out0, out1, out2; v16i8 zero = { 0 }; + v16i8 src0 = { 0 }, src1 = { 0 }, src2 = { 0 }; + v8i16 in0, in1, in2, in3, in4, in5; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5; v4i32 offset_vec, weight_vec, rnd_vec; offset = (offset0 + offset1) << rnd_val; @@ -250,80 +250,59 @@ static void hevc_biwgt_copy_8w_msa(uint8_t *src0_ptr, rnd_vec = __msa_fill_w(rnd_val + 1); if (2 == height) { - v16i8 src0, src1; - v8i16 in0, in1, dst0, dst1; - v4i32 dst0_r, dst1_r, dst0_l, dst1_l; - - LD_SB2(src0_ptr, src_stride, src0, src1); + LD2(src0_ptr, src_stride, tp0, tp1); + INSERT_D2_SB(tp0, tp1, src0); LD_SH2(src1_ptr, src2_stride, in0, in1); + ILVRL_B2_SH(zero, src0, dst0, dst1); + SLLI_2V(dst0, dst1, 6); - ILVR_B2_SH(zero, src0, zero, src1, dst0, dst1); - - dst0 <<= 6; - dst1 <<= 6; HEVC_BIW_RND_CLIP2(dst0, dst1, in0, in1, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + dst0, dst1); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST8x2_UB(dst0_r, dst, dst_stride); + out0 = (v16u8) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); + ST8x2_UB(out0, dst, dst_stride); } else if (6 == height) { - v16i8 src0, src1, src2, src3, src4, src5; - v8i16 in0, in1, in2, in3, in4, in5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; - - LD_SB6(src0_ptr, src_stride, src0, src1, src2, src3, src4, src5); + LD4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); + src0_ptr += 4 * src_stride; + INSERT_D2_SB(tp0, tp1, src0); + INSERT_D2_SB(tp2, tp3, src1); + LD2(src0_ptr, src_stride, tp0, tp1); + INSERT_D2_SB(tp0, tp1, src2); + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); + ILVRL_B2_SH(zero, src2, dst4, dst5); LD_SH6(src1_ptr, src2_stride, in0, in1, in2, in3, in4, in5); - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0, dst1, dst2, dst3); - ILVR_B2_SH(zero, src4, zero, src5, dst4, dst5); - SLLI_4V(dst0, dst1, dst2, dst3, 6); - dst4 <<= 6; - dst5 <<= 6; - HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, - in0, in1, in2, in3, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - HEVC_BIW_RND_CLIP2(dst4, dst5, in4, in5, - weight_vec, rnd_vec, offset_vec, - dst4_r, dst5_r, dst4_l, dst5_l); - - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, - dst0_r, dst1_r, dst2_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + SLLI_2V(dst4, dst5, 6); + HEVC_BIW_RND_CLIP4_MAX_SATU(dst0, dst1, dst2, dst3, in0, in1, in2, in3, + weight_vec, rnd_vec, offset_vec, dst0, dst1, + dst2, dst3); + HEVC_BIW_RND_CLIP2_MAX_SATU(dst4, dst5, in4, in5, weight_vec, rnd_vec, + offset_vec, dst4, dst5); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + ST8x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); - ST8x2_UB(dst2_r, dst, dst_stride); + ST8x2_UB(out2, dst, dst_stride); } else if (0 == height % 4) { uint32_t loop_cnt; - v16i8 src0, src1, src2, src3; - v8i16 in0, in1, in2, in3; - v8i16 dst0, dst1, dst2, dst3; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); + LD4(src0_ptr, src_stride, tp0, tp1, tp2, tp3); src0_ptr += (4 * src_stride); + INSERT_D2_SB(tp0, tp1, src0); + INSERT_D2_SB(tp2, tp3, src1); + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); src1_ptr += (4 * src2_stride); - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - dst0, dst1, dst2, dst3); SLLI_4V(dst0, dst1, dst2, dst3, 6); - HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, - in0, in1, in2, in3, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + HEVC_BIW_RND_CLIP4_MAX_SATU(dst0, dst1, dst2, dst3, in0, in1, in2, + in3, weight_vec, rnd_vec, offset_vec, + dst0, dst1, dst2, dst3); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + ST8x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -345,11 +324,10 @@ static void hevc_biwgt_copy_12w_msa(uint8_t *src0_ptr, uint32_t loop_cnt; int32_t offset, weight; v16i8 zero = { 0 }; + v16u8 out0, out1, out2; v16i8 src0, src1, src2, src3; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; v4i32 offset_vec, weight_vec, rnd_vec; offset = (offset0 + offset1) << rnd_val; @@ -377,44 +355,37 @@ static void hevc_biwgt_copy_12w_msa(uint8_t *src0_ptr, dst4 <<= 6; dst5 <<= 6; - HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, - in0, in1, in2, in3, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - HEVC_BIW_RND_CLIP2(dst4, dst5, in4, in5, - weight_vec, rnd_vec, offset_vec, - dst4_r, dst5_r, dst4_l, dst5_l); - - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, - dst0_r, dst1_r, dst2_r); - ST12x4_UB(dst0_r, dst1_r, dst2_r, dst, dst_stride); + HEVC_BIW_RND_CLIP4_MAX_SATU(dst0, dst1, dst2, dst3, in0, in1, in2, in3, + weight_vec, rnd_vec, offset_vec, dst0, dst1, + dst2, dst3); + HEVC_BIW_RND_CLIP2_MAX_SATU(dst4, dst5, in4, in5, weight_vec, rnd_vec, + offset_vec, dst4, dst5); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + ST12x4_UB(out0, out1, out2, dst, dst_stride); dst += (4 * dst_stride); } } -static void hevc_biwgt_copy_16multx4mult_msa(uint8_t *src0_ptr, - int32_t src_stride, - int16_t *src1_ptr, - int32_t src2_stride, - uint8_t *dst, - int32_t dst_stride, - int32_t height, - int32_t weight0, - int32_t weight1, - int32_t offset0, - int32_t offset1, - int32_t rnd_val, - int32_t width) +static void hevc_biwgt_copy_16w_msa(uint8_t *src0_ptr, + int32_t src_stride, + int16_t *src1_ptr, + int32_t src2_stride, + uint8_t *dst, + int32_t dst_stride, + int32_t height, + int32_t weight0, + int32_t weight1, + int32_t offset0, + int32_t offset1, + int32_t rnd_val) { - uint32_t loop_cnt, cnt; - uint8_t *src0_ptr_tmp; - int16_t *src1_ptr_tmp; - uint8_t *dst_tmp; + uint32_t loop_cnt; int32_t offset, weight; + v16u8 out0, out1, out2, out3; v16i8 zero = { 0 }; + v16i8 src0, src1, src2, src3; + v8i16 in0, in1, in2, in3, in4, in5, in6, in7; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; v4i32 offset_vec, weight_vec, rnd_vec; offset = (offset0 + offset1) << rnd_val; @@ -425,79 +396,31 @@ static void hevc_biwgt_copy_16multx4mult_msa(uint8_t *src0_ptr, weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); - for (cnt = (width >> 4); cnt--;) { - src0_ptr_tmp = src0_ptr; - src1_ptr_tmp = src1_ptr; - dst_tmp = dst; - - for (loop_cnt = (height >> 2); loop_cnt--;) { - v16i8 src0, src1, src2, src3; - v8i16 in0, in1, in2, in3, in4, in5, in6, in7; - v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l; - - LD_SB4(src0_ptr_tmp, src_stride, src0, src1, src2, src3); - src0_ptr_tmp += (4 * src_stride); - LD_SH4(src1_ptr_tmp, src2_stride, in0, in1, in2, in3); - LD_SH4(src1_ptr_tmp + 8, src2_stride, in4, in5, in6, in7); - src1_ptr_tmp += (4 * src2_stride); - - ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - tmp0, tmp1, tmp2, tmp3); - ILVL_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, - tmp4, tmp5, tmp6, tmp7); - - SLLI_4V(tmp0, tmp1, tmp2, tmp3, 6); - SLLI_4V(tmp4, tmp5, tmp6, tmp7, 6); - HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp4, tmp5, - in0, in1, in4, in5, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst_tmp, dst_stride); - dst_tmp += (2 * dst_stride); - - HEVC_BIW_RND_CLIP4(tmp2, tmp3, tmp6, tmp7, - in2, in3, in6, in7, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst_tmp, dst_stride); - dst_tmp += (2 * dst_stride); - } - - src0_ptr += 16; - src1_ptr += 16; - dst += 16; + for (loop_cnt = (height >> 2); loop_cnt--;) { + LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); + src0_ptr += (4 * src_stride); + LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); + LD_SH4(src1_ptr + 8, src2_stride, in4, in5, in6, in7); + src1_ptr += (4 * src2_stride); + ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, tmp0, tmp1, + tmp2, tmp3); + ILVL_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, tmp4, tmp5, + tmp6, tmp7); + SLLI_4V(tmp0, tmp1, tmp2, tmp3, 6); + SLLI_4V(tmp4, tmp5, tmp6, tmp7, 6); + HEVC_BIW_RND_CLIP4_MAX_SATU(tmp0, tmp1, tmp4, tmp5, in0, in1, in4, in5, + weight_vec, rnd_vec, offset_vec, tmp0, tmp1, + tmp4, tmp5); + HEVC_BIW_RND_CLIP4_MAX_SATU(tmp2, tmp3, tmp6, tmp7, in2, in3, in6, in7, + weight_vec, rnd_vec, offset_vec, tmp2, tmp3, + tmp6, tmp7); + PCKEV_B2_UB(tmp4, tmp0, tmp5, tmp1, out0, out1); + PCKEV_B2_UB(tmp6, tmp2, tmp7, tmp3, out2, out3); + ST_UB4(out0, out1, out2, out3, dst, dst_stride); + dst += (4 * dst_stride); } } -static void hevc_biwgt_copy_16w_msa(uint8_t *src0_ptr, - int32_t src_stride, - int16_t *src1_ptr, - int32_t src2_stride, - uint8_t *dst, - int32_t dst_stride, - int32_t height, - int32_t weight0, - int32_t weight1, - int32_t offset0, - int32_t offset1, - int32_t rnd_val) -{ - hevc_biwgt_copy_16multx4mult_msa(src0_ptr, src_stride, - src1_ptr, src2_stride, - dst, dst_stride, height, weight0, - weight1, offset0, offset1, rnd_val, 16); -} - static void hevc_biwgt_copy_24w_msa(uint8_t *src0_ptr, int32_t src_stride, int16_t *src1_ptr, @@ -511,14 +434,55 @@ static void hevc_biwgt_copy_24w_msa(uint8_t *src0_ptr, int32_t offset1, int32_t rnd_val) { - hevc_biwgt_copy_16multx4mult_msa(src0_ptr, src_stride, - src1_ptr, src2_stride, - dst, dst_stride, height, weight0, - weight1, offset0, offset1, rnd_val, 16); - hevc_biwgt_copy_8w_msa(src0_ptr + 16, src_stride, - src1_ptr + 16, src2_stride, - dst + 16, dst_stride, height, weight0, - weight1, offset0, offset1, rnd_val); + uint32_t loop_cnt; + int32_t offset, weight; + v16u8 out0, out1, out2, out3, out4, out5; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, zero = { 0 }; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8, dst9, dst10; + v8i16 in0, in1, in2, in3, in4, in5, in6, in7, in8, in9, in10, in11, dst11; + v4i32 offset_vec, weight_vec, rnd_vec; + + offset = (offset0 + offset1) << rnd_val; + weight0 = weight0 & 0x0000FFFF; + weight = weight0 | (weight1 << 16); + + offset_vec = __msa_fill_w(offset); + weight_vec = __msa_fill_w(weight); + rnd_vec = __msa_fill_w(rnd_val + 1); + + for (loop_cnt = 8; loop_cnt--;) { + LD_SB4(src0_ptr, src_stride, src0, src1, src4, src5); + LD_SB4(src0_ptr + 16, src_stride, src2, src3, src6, src7); + src0_ptr += (4 * src_stride); + LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); + LD_SH4(src1_ptr + 8, src2_stride, in4, in5, in6, in7); + LD_SH4(src1_ptr + 16, src2_stride, in8, in9, in10, in11); + src1_ptr += (4 * src2_stride); + + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); + ILVR_B2_SH(zero, src2, zero, src3, dst4, dst5); + ILVRL_B2_SH(zero, src4, dst6, dst7); + ILVRL_B2_SH(zero, src5, dst8, dst9); + ILVR_B2_SH(zero, src6, zero, src7, dst10, dst11); + SLLI_4V(dst0, dst1, dst2, dst3, 6); + SLLI_4V(dst4, dst5, dst6, dst7, 6); + SLLI_4V(dst8, dst9, dst10, dst11, 6); + HEVC_BIW_RND_CLIP4_MAX_SATU(dst0, dst1, dst2, dst3, in0, in4, in1, in5, + weight_vec, rnd_vec, offset_vec, dst0, dst1, + dst2, dst3); + HEVC_BIW_RND_CLIP4_MAX_SATU(dst4, dst5, dst6, dst7, in8, in9, in2, in6, + weight_vec, rnd_vec, offset_vec, dst4, dst5, + dst6, dst7); + HEVC_BIW_RND_CLIP4_MAX_SATU(dst8, dst9, dst10, dst11, in3, in7, in10, + in11, weight_vec, rnd_vec, offset_vec, + dst8, dst9, dst10, dst11); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + PCKEV_B3_UB(dst7, dst6, dst9, dst8, dst11, dst10, out3, out4, out5); + ST_UB4(out0, out1, out3, out4, dst, dst_stride); + ST8x4_UB(out2, out5, dst + 16, dst_stride); + dst += (4 * dst_stride); + } } static void hevc_biwgt_copy_32w_msa(uint8_t *src0_ptr, @@ -534,10 +498,52 @@ static void hevc_biwgt_copy_32w_msa(uint8_t *src0_ptr, int32_t offset1, int32_t rnd_val) { - hevc_biwgt_copy_16multx4mult_msa(src0_ptr, src_stride, - src1_ptr, src2_stride, - dst, dst_stride, height, weight0, - weight1, offset0, offset1, rnd_val, 32); + uint32_t loop_cnt; + int32_t offset, weight; + v16u8 out0, out1, out2, out3; + v16i8 zero = { 0 }; + v16i8 src0, src1, src2, src3; + v8i16 in0, in1, in2, in3, in4, in5, in6, in7; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + v4i32 offset_vec, weight_vec, rnd_vec; + + offset = (offset0 + offset1) << rnd_val; + weight0 = weight0 & 0x0000FFFF; + weight = weight0 | (weight1 << 16); + + offset_vec = __msa_fill_w(offset); + weight_vec = __msa_fill_w(weight); + rnd_vec = __msa_fill_w(rnd_val + 1); + + for (loop_cnt = (height >> 1); loop_cnt--;) { + LD_SB2(src0_ptr, 16, src0, src1); + src0_ptr += src_stride; + LD_SB2(src0_ptr, 16, src2, src3); + src0_ptr += src_stride; + LD_SH4(src1_ptr, 8, in0, in1, in2, in3); + src1_ptr += src2_stride; + LD_SH4(src1_ptr, 8, in4, in5, in6, in7); + src1_ptr += src2_stride; + + ILVRL_B2_SH(zero, src0, tmp0, tmp4); + ILVRL_B2_SH(zero, src1, tmp1, tmp5); + ILVRL_B2_SH(zero, src2, tmp2, tmp6); + ILVRL_B2_SH(zero, src3, tmp3, tmp7); + SLLI_4V(tmp0, tmp1, tmp2, tmp3, 6); + SLLI_4V(tmp4, tmp5, tmp6, tmp7, 6); + HEVC_BIW_RND_CLIP4_MAX_SATU(tmp0, tmp4, tmp1, tmp5, in0, in1, in2, in3, + weight_vec, rnd_vec, offset_vec, tmp0, tmp4, + tmp1, tmp5); + HEVC_BIW_RND_CLIP4_MAX_SATU(tmp2, tmp6, tmp3, tmp7, in4, in5, in6, in7, + weight_vec, rnd_vec, offset_vec, tmp2, tmp6, + tmp3, tmp7); + PCKEV_B2_UB(tmp4, tmp0, tmp5, tmp1, out0, out1); + PCKEV_B2_UB(tmp6, tmp2, tmp7, tmp3, out2, out3); + ST_UB2(out0, out1, dst, 16); + dst += dst_stride; + ST_UB2(out2, out3, dst, 16); + dst += dst_stride; + } } static void hevc_biwgt_copy_48w_msa(uint8_t *src0_ptr, @@ -553,10 +559,43 @@ static void hevc_biwgt_copy_48w_msa(uint8_t *src0_ptr, int32_t offset1, int32_t rnd_val) { - hevc_biwgt_copy_16multx4mult_msa(src0_ptr, src_stride, - src1_ptr, src2_stride, - dst, dst_stride, height, weight0, - weight1, offset0, offset1, rnd_val, 48); + uint32_t loop_cnt; + int32_t offset, weight; + v16u8 out0, out1, out2; + v16i8 src0, src1, src2; + v16i8 zero = { 0 }; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, in0, in1, in2, in3, in4, in5; + v4i32 offset_vec, weight_vec, rnd_vec; + + offset = (offset0 + offset1) << rnd_val; + weight0 = weight0 & 0x0000FFFF; + weight = weight0 | (weight1 << 16); + + offset_vec = __msa_fill_w(offset); + weight_vec = __msa_fill_w(weight); + rnd_vec = __msa_fill_w(rnd_val + 1); + + for (loop_cnt = 64; loop_cnt--;) { + LD_SB3(src0_ptr, 16, src0, src1, src2); + src0_ptr += src_stride; + LD_SH6(src1_ptr, 8, in0, in1, in2, in3, in4, in5); + src1_ptr += src2_stride; + + ILVRL_B2_SH(zero, src0, dst0, dst1); + ILVRL_B2_SH(zero, src1, dst2, dst3); + ILVRL_B2_SH(zero, src2, dst4, dst5); + SLLI_4V(dst0, dst1, dst2, dst3, 6); + SLLI_2V(dst4, dst5, 6); + HEVC_BIW_RND_CLIP4_MAX_SATU(dst0, dst1, dst2, dst3, in0, in1, in2, in3, + weight_vec, rnd_vec, offset_vec, dst0, dst1, + dst2, dst3); + HEVC_BIW_RND_CLIP2_MAX_SATU(dst4, dst5, in4, in5, weight_vec, rnd_vec, + offset_vec, dst4, dst5); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + ST_UB2(out0, out1, dst, 16); + ST_UB(out2, dst + 32); + dst += dst_stride; + } } static void hevc_biwgt_copy_64w_msa(uint8_t *src0_ptr, @@ -572,10 +611,46 @@ static void hevc_biwgt_copy_64w_msa(uint8_t *src0_ptr, int32_t offset1, int32_t rnd_val) { - hevc_biwgt_copy_16multx4mult_msa(src0_ptr, src_stride, - src1_ptr, src2_stride, - dst, dst_stride, height, weight0, - weight1, offset0, offset1, rnd_val, 64); + uint32_t loop_cnt; + int32_t offset, weight; + v16u8 out0, out1, out2, out3; + v16i8 zero = { 0 }; + v16i8 src0, src1, src2, src3; + v8i16 in0, in1, in2, in3, in4, in5, in6, in7; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + v4i32 offset_vec, weight_vec, rnd_vec; + + offset = (offset0 + offset1) << rnd_val; + weight0 = weight0 & 0x0000FFFF; + weight = weight0 | (weight1 << 16); + + offset_vec = __msa_fill_w(offset); + weight_vec = __msa_fill_w(weight); + rnd_vec = __msa_fill_w(rnd_val + 1); + + for (loop_cnt = height; loop_cnt--;) { + LD_SB4(src0_ptr, 16, src0, src1, src2, src3); + src0_ptr += src_stride; + LD_SH8(src1_ptr, 8, in0, in1, in2, in3, in4, in5, in6, in7); + src1_ptr += src2_stride; + + ILVR_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, tmp0, tmp1, + tmp2, tmp3); + ILVL_B4_SH(zero, src0, zero, src1, zero, src2, zero, src3, tmp4, tmp5, + tmp6, tmp7); + SLLI_4V(tmp0, tmp1, tmp2, tmp3, 6); + SLLI_4V(tmp4, tmp5, tmp6, tmp7, 6); + HEVC_BIW_RND_CLIP4_MAX_SATU(tmp0, tmp4, tmp1, tmp5, in0, in1, in2, in3, + weight_vec, rnd_vec, offset_vec, tmp0, tmp4, + tmp1, tmp5); + HEVC_BIW_RND_CLIP4_MAX_SATU(tmp2, tmp6, tmp3, tmp7, in4, in5, in6, in7, + weight_vec, rnd_vec, offset_vec, tmp2, tmp6, + tmp3, tmp7); + PCKEV_B2_UB(tmp4, tmp0, tmp5, tmp1, out0, out1); + PCKEV_B2_UB(tmp6, tmp2, tmp7, tmp3, out2, out3); + ST_UB4(out0, out1, out2, out3, dst, 16); + dst += dst_stride; + } } static void hevc_hz_biwgt_8t_4w_msa(uint8_t *src0_ptr, @@ -593,17 +668,16 @@ static void hevc_hz_biwgt_8t_4w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v8i16 filt0, filt1, filt2, filt3; v16i8 src0, src1, src2, src3; v16i8 mask1, mask2, mask3; v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1; v8i16 in0, in1, in2, in3; - v4i32 dst0_r, dst1_r, dst0_l, dst1_l; - v8i16 filter_vec, const_vec; + v8i16 filter_vec, out0, out1; v4i32 weight_vec, offset_vec, rnd_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[16]); src0_ptr -= 3; filter_vec = LD_SH(filter); @@ -616,9 +690,10 @@ static void hevc_hz_biwgt_8t_4w_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -633,21 +708,19 @@ static void hevc_hz_biwgt_8t_4w_msa(uint8_t *src0_ptr, VSHF_B4_SB(src0, src1, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src2, src3, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); + dst1 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); HEVC_BIW_RND_CLIP2(dst0, dst1, in0, in1, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + out0, out1); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST4x4_UB(dst0_r, dst0_r, 0, 1, 2, 3, dst, dst_stride); + out0 = (v8i16) __msa_pckev_b((v16i8) out1, (v16i8) out0); + ST4x4_UB(out0, out0, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); } } @@ -667,25 +740,25 @@ static void hevc_hz_biwgt_8t_8w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v8i16 filt0, filt1, filt2, filt3; v16i8 src0, src1, src2, src3; v16i8 mask1, mask2, mask3; v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3; v8i16 in0, in1, in2, in3; - v4i32 dst0_r, dst1_r, dst0_l, dst1_l, dst2_r, dst3_r, dst2_l, dst3_l; - v8i16 filter_vec, const_vec; + v8i16 filter_vec, out0, out1, out2, out3; v4i32 weight_vec, offset_vec, rnd_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); src0_ptr -= 3; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -706,34 +779,28 @@ static void hevc_hz_biwgt_8t_8w_msa(uint8_t *src0_ptr, VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); + dst1 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); + dst2 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + dst3 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + out0, out1, out2, out3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(out1, out0, out3, out2, out0, out1); + ST8x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -752,19 +819,92 @@ static void hevc_hz_biwgt_8t_12w_msa(uint8_t *src0_ptr, int32_t offset1, int32_t rnd_val) { - hevc_hz_biwgt_8t_8w_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter, height, - weight0, weight1, offset0, offset1, rnd_val); - hevc_hz_biwgt_8t_4w_msa(src0_ptr + 8, src_stride, src1_ptr + 8, src2_stride, - dst + 8, dst_stride, filter, height, - weight0, weight1, offset0, offset1, rnd_val); -} + uint32_t loop_cnt; + int32_t offset, weight, constant; + v16i8 src0, src1, src2, src3, vec0, vec1, vec2, vec3; + v16i8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask7; + v8i16 filt0, filt1, filt2, filt3, out0, out1, out2, out3; + v8i16 dst0, dst1, dst2, dst3, in0, in1, in2, in3, filter_vec; + v4i32 weight_vec, offset_vec, rnd_vec; -static void hevc_hz_biwgt_8t_16w_msa(uint8_t *src0_ptr, - int32_t src_stride, - int16_t *src1_ptr, - int32_t src2_stride, - uint8_t *dst, + src0_ptr -= 3; + + weight0 = weight0 & 0x0000FFFF; + weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset = (offset0 + offset1) << rnd_val; + offset += constant; + + offset_vec = __msa_fill_w(offset); + weight_vec = __msa_fill_w(weight); + rnd_vec = __msa_fill_w(rnd_val + 1); + + filter_vec = LD_SH(filter); + SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); + + mask0 = LD_SB(&ff_hevc_mask_arr[0]); + mask1 = mask0 + 2; + mask2 = mask0 + 4; + mask3 = mask0 + 6; + mask4 = LD_SB(&ff_hevc_mask_arr[16]); + mask5 = mask4 + 2; + mask6 = mask4 + 4; + mask7 = mask4 + 6; + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); + LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); + XORI_B4_128_SB(src0, src1, src2, src3); + VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + dst1 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + dst2 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + dst3 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, + weight_vec, rnd_vec, offset_vec, out0, out1, out2, + out3); + PCKEV_B2_SH(out1, out0, out3, out2, out0, out1); + ST8x4_UB(out0, out1, dst, dst_stride); + + LD_SB4(src0_ptr + 8, src_stride, src0, src1, src2, src3); + src0_ptr += (4 * src_stride); + LD_SH4(src1_ptr + 8, src2_stride, in0, in1, in2, in3); + src1_ptr += (4 * src2_stride); + ILVR_D2_SH(in1, in0, in3, in2, in0, in1); + XORI_B4_128_SB(src0, src1, src2, src3); + VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, vec0, vec1, vec2, + vec3); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + VSHF_B4_SB(src2, src3, mask4, mask5, mask6, mask7, vec0, vec1, vec2, + vec3); + dst1 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + HEVC_BIW_RND_CLIP2(dst0, dst1, in0, in1, weight_vec, rnd_vec, + offset_vec, out0, out1); + out0 = (v8i16) __msa_pckev_b((v16i8) out1, (v16i8) out0); + ST4x4_UB(out0, out0, 0, 1, 2, 3, dst + 8, dst_stride); + dst += (4 * dst_stride); + } +} + +static void hevc_hz_biwgt_8t_16w_msa(uint8_t *src0_ptr, + int32_t src_stride, + int16_t *src1_ptr, + int32_t src2_stride, + uint8_t *dst, int32_t dst_stride, const int8_t *filter, int32_t height, @@ -775,15 +915,14 @@ static void hevc_hz_biwgt_8t_16w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2, src3; v8i16 in0, in1, in2, in3; v8i16 filt0, filt1, filt2, filt3; v16i8 mask1, mask2, mask3; - v8i16 filter_vec, const_vec; + v8i16 filter_vec, out0, out1, out2, out3; v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; v4i32 weight_vec, offset_vec, rnd_vec; v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; @@ -791,9 +930,10 @@ static void hevc_hz_biwgt_8t_16w_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -818,34 +958,28 @@ static void hevc_hz_biwgt_8t_16w_msa(uint8_t *src0_ptr, VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); + dst1 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); + dst2 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + dst3 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + out0, out1, out2, out3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(out1, out0, out3, out2, out0, out1); + ST_SH2(out0, out1, dst, dst_stride); dst += (2 * dst_stride); } } @@ -866,25 +1000,26 @@ static void hevc_hz_biwgt_8t_24w_msa(uint8_t *src0_ptr, { uint32_t loop_cnt; uint64_t dst_val0; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1; v8i16 in0, in1, in2; v8i16 filt0, filt1, filt2, filt3; v16i8 mask1, mask2, mask3, mask4, mask5, mask6, mask7; v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2; - v4i32 dst0_r, dst1_r, dst2_r, dst0_l, dst1_l, dst2_l; - v8i16 filter_vec, const_vec; + v4i32 dst2_r, dst2_l; + v8i16 filter_vec, out0, out1, out2; v4i32 weight_vec, offset_vec, rnd_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); src0_ptr = src0_ptr - 3; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -900,33 +1035,30 @@ static void hevc_hz_biwgt_8t_24w_msa(uint8_t *src0_ptr, mask6 = mask0 + 12; mask7 = mask0 + 14; - for (loop_cnt = height; loop_cnt--;) { - LD_SB2(src0_ptr, 16, src0, src1); - src0_ptr += src_stride; - LD_SH2(src1_ptr, 8, in0, in1); - in2 = LD_SH(src1_ptr + 16); - src1_ptr += src2_stride; - XORI_B2_128_SB(src0, src1); + LD_SB2(src0_ptr, 16, src0, src1); + src0_ptr += src_stride; + LD_SH2(src1_ptr, 8, in0, in1); + in2 = LD_SH(src1_ptr + 16); + src1_ptr += src2_stride; + XORI_B2_128_SB(src0, src1); + for (loop_cnt = 31; loop_cnt--;) { VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, vec0, vec1, vec2, vec3); - dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); + dst1 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); + dst2 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); HEVC_BIW_RND_CLIP2(dst0, dst1, in0, in1, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + out0, out1); ILVRL_H2_SW(dst2, in2, dst2_r, dst2_l); dst2_r = __msa_dpadd_s_w(offset_vec, (v8i16) dst2_r, @@ -934,16 +1066,44 @@ static void hevc_hz_biwgt_8t_24w_msa(uint8_t *src0_ptr, dst2_l = __msa_dpadd_s_w(offset_vec, (v8i16) dst2_l, (v8i16) weight_vec); SRAR_W2_SW(dst2_r, dst2_l, rnd_vec); - dst2_r = CLIP_SW_0_255(dst2_r); - dst2_l = CLIP_SW_0_255(dst2_l); + dst2_r = (v4i32) __msa_pckev_h((v8i16) dst2_l, (v8i16) dst2_r); + out2 = CLIP_SH_0_255(dst2_r); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - HEVC_PCK_SW_SB2(dst2_l, dst2_r, dst2_r); - dst_val0 = __msa_copy_u_d((v2i64) dst2_r, 0); - ST_SW(dst0_r, dst); + LD_SB2(src0_ptr, 16, src0, src1); + src0_ptr += src_stride; + LD_SH2(src1_ptr, 8, in0, in1); + in2 = LD_SH(src1_ptr + 16); + src1_ptr += src2_stride; + XORI_B2_128_SB(src0, src1); + PCKEV_B2_SH(out1, out0, out2, out2, out0, out2); + dst_val0 = __msa_copy_u_d((v2i64) out2, 0); + ST_SH(out0, dst); SD(dst_val0, dst + 16); dst += dst_stride; } + + VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, vec0, vec1, vec2, vec3); + dst1 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); + dst2 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + HEVC_BIW_RND_CLIP2(dst0, dst1, in0, in1, weight_vec, rnd_vec, offset_vec, + out0, out1); + ILVRL_H2_SW(dst2, in2, dst2_r, dst2_l); + dst2_r = __msa_dpadd_s_w(offset_vec, (v8i16) dst2_r, (v8i16) weight_vec); + dst2_l = __msa_dpadd_s_w(offset_vec, (v8i16) dst2_l, (v8i16) weight_vec); + SRAR_W2_SW(dst2_r, dst2_l, rnd_vec); + dst2_r = (v4i32) __msa_pckev_h((v8i16) dst2_l, (v8i16) dst2_r); + out2 = CLIP_SH_0_255(dst2_r); + PCKEV_B2_SH(out1, out0, out2, out2, out0, out2); + dst_val0 = __msa_copy_u_d((v2i64) out2, 0); + ST_SH(out0, dst); + SD(dst_val0, dst + 16); + dst += dst_stride; } static void hevc_hz_biwgt_8t_32w_msa(uint8_t *src0_ptr, @@ -961,25 +1121,25 @@ static void hevc_hz_biwgt_8t_32w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2; v8i16 in0, in1, in2, in3; v8i16 filt0, filt1, filt2, filt3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1, mask2, mask3, mask4, mask5, mask6, mask7; v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; + v8i16 filter_vec, out0, out1, out2, out3; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 3; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -1006,34 +1166,28 @@ static void hevc_hz_biwgt_8t_32w_msa(uint8_t *src0_ptr, VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, vec0, vec1, vec2, vec3); - dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); + dst1 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); + dst2 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + dst3 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + out0, out1, out2, out3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, 16); + PCKEV_B2_SH(out1, out0, out3, out2, out0, out1); + ST_SH2(out0, out1, dst, 16); dst += dst_stride; } } @@ -1053,27 +1207,25 @@ static void hevc_hz_biwgt_8t_48w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; - uint64_t dst_val0; - v16i8 src0, src1, src2, src3; - v8i16 in0, in1, in2, in3, in4, in5; + int32_t offset, weight, constant; + v16i8 src0, src1, src2, src3, src4; + v8i16 in0, in1, in2, in3; v8i16 filt0, filt1, filt2, filt3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1, mask2, mask3, mask4, mask5, mask6, mask7; v16i8 vec0, vec1, vec2, vec3; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; + v8i16 dst0, dst1, dst2, dst3; + v8i16 filter_vec, out0, out1, out2, out3; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 3; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -1089,86 +1241,57 @@ static void hevc_hz_biwgt_8t_48w_msa(uint8_t *src0_ptr, mask6 = mask0 + 12; mask7 = mask0 + 14; - for (loop_cnt = height; loop_cnt--;) { - LD_SB3(src0_ptr, 16, src0, src1, src2); - src3 = LD_SB(src0_ptr + 40); + for (loop_cnt = 64; loop_cnt--;) { + LD_SB2(src0_ptr, 16, src0, src1); + src2 = LD_SB(src0_ptr + 24); + LD_SH4(src1_ptr, 8, in0, in1, in2, in3); + XORI_B3_128_SB(src0, src1, src2); + LD_SB2(src0_ptr + 32, 8, src3, src4); src0_ptr += src_stride; - LD_SH2(src1_ptr, 8, in0, in1); - in2 = LD_SH(src1_ptr + 16); - XORI_B4_128_SB(src0, src1, src2, src3); + XORI_B2_128_SB(src3, src4); VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, vec0, vec1, vec2, vec3); - dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); + dst1 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - VSHF_B4_SB(src1, src2, mask4, mask5, mask6, mask7, - vec0, vec1, vec2, vec3); - dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + dst2 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst4 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst4, dst4, dst4, dst4); - VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); - dst5 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst5, dst5, dst5, dst5); + dst3 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); - HEVC_BIW_RND_CLIP2(dst0, dst1, in0, in1, + HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + out0, out1, out2, out3); - ILVRL_H2_SW(dst2, in2, dst2_r, dst2_l); - dst2_r = __msa_dpadd_s_w(offset_vec, (v8i16) dst2_r, - (v8i16) weight_vec); - dst2_l = __msa_dpadd_s_w(offset_vec, (v8i16) dst2_l, - (v8i16) weight_vec); - SRAR_W2_SW(dst2_r, dst2_l, rnd_vec); - dst2_r = CLIP_SW_0_255(dst2_r); - dst2_l = CLIP_SW_0_255(dst2_l); - - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - HEVC_PCK_SW_SB2(dst2_l, dst2_r, dst2_r); - dst_val0 = __msa_copy_u_d((v2i64) dst2_r, 0); - ST_SW(dst0_r, dst); - SD(dst_val0, dst + 16); + PCKEV_B2_SH(out1, out0, out3, out2, out0, out1); + ST_SH2(out0, out1, dst, 16); - LD_SH2(src1_ptr + 24, 8, in3, in4); - in5 = LD_SH(src1_ptr + 40); + LD_SH2(src1_ptr + 32, 8, in2, in3); src1_ptr += src2_stride; - HEVC_BIW_RND_CLIP2(dst3, dst4, in3, in4, + VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, + vec0, vec1, vec2, vec3); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + VSHF_B4_SB(src4, src4, mask0, mask1, mask2, mask3, + vec0, vec1, vec2, vec3); + dst1 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + + HEVC_BIW_RND_CLIP2(dst0, dst1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst3_r, dst4_r, dst3_l, dst4_l); + out0, out1); - ILVRL_H2_SW(dst5, in5, dst5_r, dst5_l); - dst5_r = __msa_dpadd_s_w(offset_vec, (v8i16) dst5_r, - (v8i16) weight_vec); - dst5_l = __msa_dpadd_s_w(offset_vec, (v8i16) dst5_l, - (v8i16) weight_vec); - SRAR_W2_SW(dst5_r, dst5_l, rnd_vec); - dst5_r = CLIP_SW_0_255(dst5_r); - dst5_l = CLIP_SW_0_255(dst5_l); - - HEVC_PCK_SW_SB4(dst4_l, dst4_r, dst5_l, dst5_r, dst4_r); - HEVC_PCK_SW_SB2(dst3_l, dst3_r, dst3_r); - dst_val0 = __msa_copy_u_d((v2i64) dst3_r, 0); - SD(dst_val0, dst + 24); - ST_SW(dst4_r, dst + 32); + out0 = (v8i16) __msa_pckev_b((v16i8) out1, (v16i8) out0); + ST_SH(out0, dst + 32); dst += dst_stride; } } @@ -1191,25 +1314,25 @@ static void hevc_hz_biwgt_8t_64w_msa(uint8_t *src0_ptr, uint8_t *dst_tmp; int16_t *src1_ptr_tmp; uint32_t loop_cnt, cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2; v8i16 in0, in1, in2, in3; v8i16 filt0, filt1, filt2, filt3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1, mask2, mask3, mask4, mask5, mask6, mask7; v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; + v8i16 filter_vec, out0, out1, out2, out3; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 3; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -1240,34 +1363,28 @@ static void hevc_hz_biwgt_8t_64w_msa(uint8_t *src0_ptr, VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, vec0, vec1, vec2, vec3); - dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); + dst1 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); + dst2 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + dst3 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + out0, out1, out2, out3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst_tmp, 16); + PCKEV_B2_SH(out1, out0, out3, out2, out0, out1); + ST_SH2(out0, out1, dst_tmp, 16); dst_tmp += 32; } @@ -1303,22 +1420,22 @@ static void hevc_vt_biwgt_8t_4w_msa(uint8_t *src0_ptr, v16i8 src2110, src4332, src6554, src8776, src10998; v16i8 src12111110, src14131312; v8i16 dst10, dst32, dst54, dst76; - v4i32 dst10_r, dst32_r, dst54_r, dst76_r; - v4i32 dst10_l, dst32_l, dst54_l, dst76_l; v8i16 filt0, filt1, filt2, filt3; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 filter_vec, out0, out1, out2, out3; + v4i32 weight_vec, weight1_vec, offset_vec, rnd_vec, const_vec; src0_ptr -= (3 * src_stride); offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_ldi_w(128); const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); + weight1_vec = __msa_fill_w(weight1); + offset_vec += const_vec * weight1_vec; filter_vec = LD_SH(filter); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); @@ -1351,28 +1468,22 @@ static void hevc_vt_biwgt_8t_4w_msa(uint8_t *src0_ptr, src8776, src10998, src12111110, src14131312); XORI_B4_128_SB(src8776, src10998, src12111110, src14131312); - dst10 = const_vec; - DPADD_SB4_SH(src2110, src4332, src6554, src8776, filt0, filt1, - filt2, filt3, dst10, dst10, dst10, dst10); - dst32 = const_vec; - DPADD_SB4_SH(src4332, src6554, src8776, src10998, - filt0, filt1, filt2, filt3, dst32, dst32, dst32, dst32); - dst54 = const_vec; - DPADD_SB4_SH(src6554, src8776, src10998, src12111110, - filt0, filt1, filt2, filt3, dst54, dst54, dst54, dst54); - dst76 = const_vec; - DPADD_SB4_SH(src8776, src10998, src12111110, src14131312, - filt0, filt1, filt2, filt3, dst76, dst76, dst76, dst76); + DOTP_SB4_SH(src2110, src4332, src6554, src8776, filt0, filt0, filt0, + filt0, dst10, dst32, dst54, dst76); + DPADD_SB4_SH(src4332, src6554, src8776, src10998, filt1, filt1, filt1, + filt1, dst10, dst32, dst54, dst76); + DPADD_SB4_SH(src6554, src8776, src10998, src12111110, filt2, filt2, + filt2, filt2, dst10, dst32, dst54, dst76); + DPADD_SB4_SH(src8776, src10998, src12111110, src14131312, filt3, filt3, + filt3, filt3, dst10, dst32, dst54, dst76); HEVC_BIW_RND_CLIP4(dst10, dst32, dst54, dst76, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst10_r, dst32_r, dst54_r, dst76_r, - dst10_l, dst32_l, dst54_l, dst76_l); + out0, out1, out2, out3); - HEVC_PCK_SW_SB8(dst10_l, dst10_r, dst32_l, dst32_r, - dst54_l, dst54_r, dst76_l, dst76_r, dst10_r, dst54_r); - ST4x8_UB(dst10_r, dst54_r, dst, dst_stride); + PCKEV_B2_SH(out1, out0, out3, out2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); dst += (8 * dst_stride); src2110 = src10998; @@ -1405,20 +1516,21 @@ static void hevc_vt_biwgt_8t_8w_msa(uint8_t *src0_ptr, v16i8 src21_r, src43_r, src65_r, src87_r, src109_r; v8i16 tmp0, tmp1, tmp2, tmp3; v8i16 filt0, filt1, filt2, filt3; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 filter_vec, out0, out1, out2, out3; + v4i32 weight_vec, weight1_vec, offset_vec, rnd_vec, const_vec; src0_ptr -= (3 * src_stride); offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_ldi_w(128); const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); + weight1_vec = __msa_fill_w(weight1); + offset_vec += const_vec * weight1_vec; filter_vec = LD_SH(filter); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); @@ -1441,28 +1553,22 @@ static void hevc_vt_biwgt_8t_8w_msa(uint8_t *src0_ptr, ILVR_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, src76_r, src87_r, src98_r, src109_r); - tmp0 = const_vec; - DPADD_SB4_SH(src10_r, src32_r, src54_r, src76_r, - filt0, filt1, filt2, filt3, tmp0, tmp0, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB4_SH(src21_r, src43_r, src65_r, src87_r, - filt0, filt1, filt2, filt3, tmp1, tmp1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB4_SH(src32_r, src54_r, src76_r, src98_r, - filt0, filt1, filt2, filt3, tmp2, tmp2, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB4_SH(src43_r, src65_r, src87_r, src109_r, - filt0, filt1, filt2, filt3, tmp3, tmp3, tmp3, tmp3); + DOTP_SB4_SH(src10_r, src21_r, src32_r, src43_r, filt0, filt0, filt0, + filt0, tmp0, tmp1, tmp2, tmp3); + DPADD_SB4_SH(src32_r, src43_r, src54_r, src65_r, filt1, filt1, filt1, + filt1, tmp0, tmp1, tmp2, tmp3); + DPADD_SB4_SH(src54_r, src65_r, src76_r, src87_r, filt2, filt2, filt2, + filt2, tmp0, tmp1, tmp2, tmp3); + DPADD_SB4_SH(src76_r, src87_r, src98_r, src109_r, filt3, filt3, filt3, + filt3, tmp0, tmp1, tmp2, tmp3); HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + out0, out1, out2, out3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(out1, out0, out3, out2, out0, out1); + ST8x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); src10_r = src54_r; @@ -1500,20 +1606,22 @@ static void hevc_vt_biwgt_8t_12w_msa(uint8_t *src0_ptr, v16i8 src21_l, src43_l, src65_l, src87_l; v16i8 src2110, src4332, src6554, src8776; v8i16 filt0, filt1, filt2, filt3; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst0_l, dst1_l, dst2_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 out0, out1, out2, filter_vec; + v4i32 dst2_r, dst2_l; + v4i32 weight_vec, weight1_vec, offset_vec, rnd_vec, const_vec; src0_ptr -= (3 * src_stride); offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_ldi_w(128); const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); + weight1_vec = __msa_fill_w(weight1); + offset_vec += const_vec * weight1_vec; filter_vec = LD_SH(filter); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); @@ -1531,7 +1639,7 @@ static void hevc_vt_biwgt_8t_12w_msa(uint8_t *src0_ptr, ILVR_D3_SB(src21_l, src10_l, src43_l, src32_l, src65_l, src54_l, src2110, src4332, src6554); - for (loop_cnt = (height >> 1); loop_cnt--;) { + for (loop_cnt = 8; loop_cnt--;) { LD_SB2(src0_ptr, src_stride, src7, src8); src0_ptr += (2 * src_stride); LD_SH2(src1_ptr, src2_stride, in0, in1); @@ -1544,19 +1652,18 @@ static void hevc_vt_biwgt_8t_12w_msa(uint8_t *src0_ptr, ILVL_B2_SB(src7, src6, src8, src7, src76_l, src87_l); src8776 = (v16i8) __msa_ilvr_d((v2i64) src87_l, (v2i64) src76_l); - tmp0 = const_vec; - DPADD_SB4_SH(src10_r, src32_r, src54_r, src76_r, - filt0, filt1, filt2, filt3, tmp0, tmp0, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB4_SH(src21_r, src43_r, src65_r, src87_r, - filt0, filt1, filt2, filt3, tmp1, tmp1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB4_SH(src2110, src4332, src6554, src8776, - filt0, filt1, filt2, filt3, tmp2, tmp2, tmp2, tmp2); + DOTP_SB3_SH(src10_r, src21_r, src2110, filt0, filt0, filt0, + tmp0, tmp1, tmp2); + DPADD_SB2_SH(src32_r, src43_r, filt1, filt1, tmp0, tmp1); + tmp2 = __msa_dpadd_s_h(tmp2, src4332, (v16i8) filt1); + DPADD_SB2_SH(src54_r, src65_r, filt2, filt2, tmp0, tmp1); + tmp2 = __msa_dpadd_s_h(tmp2, src6554, (v16i8) filt2); + DPADD_SB2_SH(src76_r, src87_r, filt3, filt3, tmp0, tmp1); + tmp2 = __msa_dpadd_s_h(tmp2, src8776, (v16i8) filt3); HEVC_BIW_RND_CLIP2(tmp0, tmp1, in0, in1, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + out0, out1); ILVRL_H2_SW(tmp2, in2, dst2_r, dst2_l); dst2_r = __msa_dpadd_s_w(offset_vec, (v8i16) dst2_r, @@ -1564,13 +1671,11 @@ static void hevc_vt_biwgt_8t_12w_msa(uint8_t *src0_ptr, dst2_l = __msa_dpadd_s_w(offset_vec, (v8i16) dst2_l, (v8i16) weight_vec); SRAR_W2_SW(dst2_r, dst2_l, rnd_vec); - dst2_r = CLIP_SW_0_255(dst2_r); - dst2_l = CLIP_SW_0_255(dst2_l); - - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - HEVC_PCK_SW_SB2(dst2_l, dst2_r, dst2_r); - ST8x2_UB(dst0_r, dst, dst_stride); - ST4x2_UB(dst2_r, dst + 8, dst_stride); + dst2_r = (v4i32) __msa_pckev_h((v8i16) dst2_l, (v8i16) dst2_r); + out2 = CLIP_SH_0_255(dst2_r); + PCKEV_B2_SH(out1, out0, out2, out2, out0, out2); + ST8x2_UB(out0, dst, dst_stride); + ST4x2_UB(out2, dst + 8, dst_stride); dst += (2 * dst_stride); src10_r = src32_r; @@ -1614,9 +1719,9 @@ static void hevc_vt_biwgt_8t_16multx2mult_msa(uint8_t *src0_ptr, v16i8 src21_l, src43_l, src65_l, src87_l; v8i16 tmp0, tmp1, tmp2, tmp3; v8i16 filt0, filt1, filt2, filt3; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 filter_vec; + v8i16 out0, out1, out2, out3; + v4i32 weight_vec, weight1_vec, offset_vec, rnd_vec, const_vec; src0_ptr -= (3 * src_stride); @@ -1624,11 +1729,13 @@ static void hevc_vt_biwgt_8t_16multx2mult_msa(uint8_t *src0_ptr, weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_ldi_w(128); const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); + weight1_vec = __msa_fill_w(weight1); + offset_vec += const_vec * weight1_vec; filter_vec = LD_SH(filter); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); @@ -1661,28 +1768,22 @@ static void hevc_vt_biwgt_8t_16multx2mult_msa(uint8_t *src0_ptr, ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); ILVL_B2_SB(src7, src6, src8, src7, src76_l, src87_l); - tmp0 = const_vec; - DPADD_SB4_SH(src10_r, src32_r, src54_r, src76_r, - filt0, filt1, filt2, filt3, tmp0, tmp0, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB4_SH(src21_r, src43_r, src65_r, src87_r, - filt0, filt1, filt2, filt3, tmp1, tmp1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB4_SH(src10_l, src32_l, src54_l, src76_l, - filt0, filt1, filt2, filt3, tmp2, tmp2, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB4_SH(src21_l, src43_l, src65_l, src87_l, - filt0, filt1, filt2, filt3, tmp3, tmp3, tmp3, tmp3); + DOTP_SB4_SH(src10_r, src21_r, src10_l, src21_l, filt0, filt0, + filt0, filt0, tmp0, tmp1, tmp2, tmp3); + DPADD_SB4_SH(src32_r, src43_r, src32_l, src43_l, filt1, filt1, + filt1, filt1, tmp0, tmp1, tmp2, tmp3); + DPADD_SB4_SH(src54_r, src65_r, src54_l, src65_l, filt2, filt2, + filt2, filt2, tmp0, tmp1, tmp2, tmp3); + DPADD_SB4_SH(src76_r, src87_r, src76_l, src87_l, filt3, filt3, + filt3, filt3, tmp0, tmp1, tmp2, tmp3); HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + out0, out1, out2, out3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst_tmp, dst_stride); + PCKEV_B2_SH(out2, out0, out3, out1, out0, out1); + ST_SH2(out0, out1, dst_tmp, dst_stride); dst_tmp += (2 * dst_stride); src10_r = src32_r; @@ -1831,23 +1932,23 @@ static void hevc_hv_biwgt_8t_4w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; - v8i16 in0, in1; + uint64_t tp0, tp1; + int32_t offset, weight; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v8i16 in0 = { 0 }, in1 = { 0 }; v8i16 filt0, filt1, filt2, filt3; - v4i32 filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 filt_h0, filt_h1, filt_h2, filt_h3; v16i8 mask1, mask2, mask3; - v8i16 filter_vec, const_vec; + v8i16 filter_vec, weight_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; v8i16 dst30, dst41, dst52, dst63, dst66, dst87; - v4i32 dst0_r, dst1_r; - v4i32 tmp1, tmp2; - v4i32 weight_vec0, weight_vec1, offset_vec, rnd_vec; - v8i16 dst10_r, dst32_r, dst54_r, dst76_r; - v8i16 dst21_r, dst43_r, dst65_r, dst87_r; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; - v8u16 mask4 = { 0, 4, 1, 5, 2, 6, 3, 7 }; + v8i16 tmp0, tmp1, tmp2, tmp3; + v8i16 dst10, dst32, dst54, dst76; + v8i16 dst21, dst43, dst65, dst97, dst108, dst109, dst98; + v4i32 offset_vec, rnd_vec, const_vec, dst0, dst1, dst2, dst3; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); src0_ptr -= ((3 * src_stride) + 3); @@ -1855,10 +1956,9 @@ static void hevc_hv_biwgt_8t_4w_msa(uint8_t *src0_ptr, SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W4_SW(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); mask1 = mask0 + 2; mask2 = mask0 + 4; @@ -1866,13 +1966,14 @@ static void hevc_hv_biwgt_8t_4w_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; + weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_fill_w((128 * weight1)); const_vec <<= 6; offset_vec = __msa_fill_w(offset); - weight_vec0 = __msa_fill_w(weight0); - weight_vec1 = __msa_fill_w(weight1); rnd_vec = __msa_fill_w(rnd_val + 1); + offset_vec += const_vec; + weight_vec = (v8i16) __msa_fill_w(weight); LD_SB7(src0_ptr, src_stride, src0, src1, src2, src3, src4, src5, src6); src0_ptr += (7 * src_stride); @@ -1886,70 +1987,77 @@ static void hevc_hv_biwgt_8t_4w_msa(uint8_t *src0_ptr, VSHF_B4_SB(src3, src6, mask0, mask1, mask2, mask3, vec12, vec13, vec14, vec15); - dst30 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst30, dst30, dst30, dst30); - dst41 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst41, dst41, dst41, dst41); - dst52 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst52, dst52, dst52, dst52); - dst63 = const_vec; - DPADD_SB4_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, filt3, - dst63, dst63, dst63, dst63); - - ILVR_H3_SH(dst41, dst30, dst52, dst41, dst63, dst52, - dst10_r, dst21_r, dst32_r); - dst43_r = __msa_ilvl_h(dst41, dst30); - dst54_r = __msa_ilvl_h(dst52, dst41); - dst65_r = __msa_ilvl_h(dst63, dst52); + dst30 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst41 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst52 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst63 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, + filt3); + + ILVRL_H2_SH(dst41, dst30, dst10, dst43); + ILVRL_H2_SH(dst52, dst41, dst21, dst54); + ILVRL_H2_SH(dst63, dst52, dst32, dst65); + dst66 = (v8i16) __msa_splati_d((v2i64) dst63, 1); - for (loop_cnt = height >> 1; loop_cnt--;) { - LD_SB2(src0_ptr, src_stride, src7, src8); - src0_ptr += (2 * src_stride); - LD_SH2(src1_ptr, src2_stride, in0, in1); - src1_ptr += (2 * src2_stride); + for (loop_cnt = height >> 2; loop_cnt--;) { + LD_SB4(src0_ptr, src_stride, src7, src8, src9, src10); + src0_ptr += (4 * src_stride); + XORI_B4_128_SB(src7, src8, src9, src10); - in0 = (v8i16) __msa_ilvr_d((v2i64) in1, (v2i64) in0); - XORI_B2_128_SB(src7, src8); + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in0); + src1_ptr += (2 * src2_stride); + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in1); + src1_ptr += (2 * src2_stride); - VSHF_B4_SB(src7, src8, mask0, mask1, mask2, mask3, + VSHF_B4_SB(src7, src9, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst87 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst87, dst87, dst87, dst87); - dst76_r = __msa_ilvr_h(dst87, dst66); - dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, - filt_h0, filt_h1, filt_h2, filt_h3); - dst87_r = __msa_vshf_h((v8i16) mask4, dst87, dst87); - dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, - filt_h0, filt_h1, filt_h2, filt_h3); - - dst0_r >>= 6; - dst1_r >>= 6; - - ILVRL_H2_SW(in0, in0, tmp1, tmp2); - tmp1 = __msa_dpadd_s_w(offset_vec, (v8i16) tmp1, (v8i16) weight_vec0); - tmp2 = __msa_dpadd_s_w(offset_vec, (v8i16) tmp2, (v8i16) weight_vec0); - tmp1 += dst0_r * weight_vec1; - tmp2 += dst1_r * weight_vec1; - SRAR_W2_SW(tmp1, tmp2, rnd_vec); - tmp1 = CLIP_SW_0_255(tmp1); - tmp2 = CLIP_SW_0_255(tmp2); - - HEVC_PCK_SW_SB2(tmp2, tmp1, tmp1); - ST4x2_UB(tmp1, dst, dst_stride); - dst += (2 * dst_stride); + VSHF_B4_SB(src8, src10, mask0, mask1, mask2, mask3, + vec4, vec5, vec6, vec7); + dst97 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst108 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + + dst76 = __msa_ilvr_h(dst97, dst66); + ILVRL_H2_SH(dst108, dst97, dst87, dst109); + dst66 = (v8i16) __msa_splati_d((v2i64) dst97, 1); + dst98 = __msa_ilvr_h(dst66, dst108); + + dst0 = HEVC_FILT_8TAP(dst10, dst32, dst54, dst76, filt_h0, filt_h1, + filt_h2, filt_h3); + dst1 = HEVC_FILT_8TAP(dst21, dst43, dst65, dst87, filt_h0, filt_h1, + filt_h2, filt_h3); + dst2 = HEVC_FILT_8TAP(dst32, dst54, dst76, dst98, filt_h0, filt_h1, + filt_h2, filt_h3); + dst3 = HEVC_FILT_8TAP(dst43, dst65, dst87, dst109, filt_h0, filt_h1, + filt_h2, filt_h3); + SRA_4V(dst0, dst1, dst2, dst3, 6); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp1, tmp3); + ILVRL_H2_SH(tmp1, in0, tmp0, tmp1); + ILVRL_H2_SH(tmp3, in1, tmp2, tmp3); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + CLIP_SW4_0_255_MAX_SATU(dst0, dst1, dst2, dst3); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp0, tmp1); + out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + dst += (4 * dst_stride); - dst10_r = dst32_r; - dst32_r = dst54_r; - dst54_r = dst76_r; - dst21_r = dst43_r; - dst43_r = dst65_r; - dst65_r = dst87_r; - dst66 = (v8i16) __msa_splati_d((v2i64) dst87, 1); + dst10 = dst54; + dst32 = dst76; + dst54 = dst98; + dst21 = dst65; + dst43 = dst87; + dst65 = dst109; + dst66 = (v8i16) __msa_splati_d((v2i64) dst108, 1); } } @@ -1967,57 +2075,58 @@ static void hevc_hv_biwgt_8t_8multx2mult_msa(uint8_t *src0_ptr, int32_t offset0, int32_t offset1, int32_t rnd_val, - int32_t width) + int32_t width8mult) { uint32_t loop_cnt, cnt; - int32_t offset; + int32_t offset, weight; uint8_t *src0_ptr_tmp; int16_t *src1_ptr_tmp; uint8_t *dst_tmp; + v16u8 out; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v8i16 in0, in1; v8i16 filt0, filt1, filt2, filt3; - v4i32 filt_h0, filt_h1, filt_h2, filt_h3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1, filt_h2, filt_h3; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1, mask2, mask3; - v8i16 filter_vec, const_vec; + v8i16 filter_vec, weight_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; v4i32 dst0_r, dst0_l, dst1_r, dst1_l; - v4i32 tmp0, tmp1, tmp2, tmp3; + v8i16 tmp0, tmp1, tmp2, tmp3; v8i16 dst10_r, dst32_r, dst54_r, dst76_r; v8i16 dst10_l, dst32_l, dst54_l, dst76_l; v8i16 dst21_r, dst43_r, dst65_r, dst87_r; v8i16 dst21_l, dst43_l, dst65_l, dst87_l; - v4i32 weight_vec0, weight_vec1, offset_vec, rnd_vec; + v4i32 offset_vec, rnd_vec, const_vec; src0_ptr -= ((3 * src_stride) + 3); offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; + weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_fill_w((128 * weight1)); const_vec <<= 6; offset_vec = __msa_fill_w(offset); - weight_vec0 = __msa_fill_w(weight0); - weight_vec1 = __msa_fill_w(weight1); rnd_vec = __msa_fill_w(rnd_val + 1); + offset_vec += const_vec; + weight_vec = (v8i16) __msa_fill_w(weight); filter_vec = LD_SH(filter_x); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W4_SW(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); mask1 = mask0 + 2; mask2 = mask0 + 4; mask3 = mask0 + 6; - for (cnt = width >> 3; cnt--;) { + for (cnt = width8mult; cnt--;) { src0_ptr_tmp = src0_ptr; src1_ptr_tmp = src1_ptr; dst_tmp = dst; @@ -2038,18 +2147,14 @@ static void hevc_hv_biwgt_8t_8multx2mult_msa(uint8_t *src0_ptr, VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec12, vec13, vec14, vec15); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - dst1 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - dst2 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - dst3 = const_vec; - DPADD_SB4_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst1 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst2 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst3 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, + filt2, filt3); /* row 4 row 5 row 6 */ VSHF_B4_SB(src4, src4, mask0, mask1, mask2, mask3, @@ -2059,22 +2164,12 @@ static void hevc_hv_biwgt_8t_8multx2mult_msa(uint8_t *src0_ptr, VSHF_B4_SB(src6, src6, mask0, mask1, mask2, mask3, vec8, vec9, vec10, vec11); - dst4 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst4, dst4, dst4, dst4); - dst5 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst5, dst5, dst5, dst5); - dst6 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst6, dst6, dst6, dst6); - - ILVR_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, - dst10_r, dst32_r, dst54_r, dst21_r); - ILVR_H2_SH(dst4, dst3, dst6, dst5, dst43_r, dst65_r); - ILVL_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, - dst10_l, dst32_l, dst54_l, dst21_l); - ILVL_H2_SH(dst4, dst3, dst6, dst5, dst43_l, dst65_l); + dst4 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst5 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst6 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); for (loop_cnt = height >> 1; loop_cnt--;) { LD_SB2(src0_ptr_tmp, src_stride, src7, src8); @@ -2084,11 +2179,17 @@ static void hevc_hv_biwgt_8t_8multx2mult_msa(uint8_t *src0_ptr, LD_SH2(src1_ptr_tmp, src2_stride, in0, in1); src1_ptr_tmp += (2 * src2_stride); + ILVR_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, dst10_r, + dst32_r, dst54_r, dst21_r); + ILVL_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, dst10_l, + dst32_l, dst54_l, dst21_l); + ILVR_H2_SH(dst4, dst3, dst6, dst5, dst43_r, dst65_r); + ILVL_H2_SH(dst4, dst3, dst6, dst5, dst43_l, dst65_l); + VSHF_B4_SB(src7, src7, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst7 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst7, dst7, dst7, dst7); + dst7 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, @@ -2102,10 +2203,8 @@ static void hevc_hv_biwgt_8t_8multx2mult_msa(uint8_t *src0_ptr, /* row 8 */ VSHF_B4_SB(src8, src8, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - - dst8 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst8, dst8, dst8, dst8); + dst8 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, @@ -2116,43 +2215,26 @@ static void hevc_hv_biwgt_8t_8multx2mult_msa(uint8_t *src0_ptr, dst1_r >>= 6; dst1_l >>= 6; - ILVRL_H2_SW(in0, in0, tmp0, tmp1); - ILVRL_H2_SW(in1, in1, tmp2, tmp3); - tmp0 = __msa_dpadd_s_w(offset_vec, (v8i16) tmp0, - (v8i16) weight_vec0); - tmp1 = __msa_dpadd_s_w(offset_vec, (v8i16) tmp1, - (v8i16) weight_vec0); - tmp2 = __msa_dpadd_s_w(offset_vec, (v8i16) tmp2, - (v8i16) weight_vec0); - tmp3 = __msa_dpadd_s_w(offset_vec, (v8i16) tmp3, - (v8i16) weight_vec0); - - tmp0 += (dst0_r * weight_vec1); - tmp1 += (dst0_l * weight_vec1); - tmp2 += (dst1_r * weight_vec1); - tmp3 += (dst1_l * weight_vec1); - - SRAR_W4_SW(tmp0, tmp1, tmp2, tmp3, rnd_vec); - tmp0 = CLIP_SW_0_255(tmp0); - tmp1 = CLIP_SW_0_255(tmp1); - tmp2 = CLIP_SW_0_255(tmp2); - tmp3 = CLIP_SW_0_255(tmp3); - HEVC_PCK_SW_SB4(tmp1, tmp0, tmp3, tmp2, dst0_r); - ST8x2_UB(dst0_r, dst_tmp, dst_stride); + PCKEV_H2_SH(dst0_l, dst0_r, dst1_l, dst1_r, tmp1, tmp3); + ILVRL_H2_SH(tmp1, in0, tmp0, tmp1); + ILVRL_H2_SH(tmp3, in1, tmp2, tmp3); + dst0_r = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst0_l = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst1_r = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst1_l = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + SRAR_W4_SW(dst0_l, dst0_r, dst1_l, dst1_r, rnd_vec); + CLIP_SW4_0_255_MAX_SATU(dst0_l, dst0_r, dst1_l, dst1_r); + PCKEV_H2_SH(dst0_l, dst0_r, dst1_l, dst1_r, tmp0, tmp1); + out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); + ST8x2_UB(out, dst_tmp, dst_stride); dst_tmp += (2 * dst_stride); - dst10_r = dst32_r; - dst32_r = dst54_r; - dst54_r = dst76_r; - dst10_l = dst32_l; - dst32_l = dst54_l; - dst54_l = dst76_l; - dst21_r = dst43_r; - dst43_r = dst65_r; - dst65_r = dst87_r; - dst21_l = dst43_l; - dst43_l = dst65_l; - dst65_l = dst87_l; + dst0 = dst2; + dst1 = dst3; + dst2 = dst4; + dst3 = dst5; + dst4 = dst6; + dst5 = dst7; dst6 = dst8; } @@ -2181,7 +2263,7 @@ static void hevc_hv_biwgt_8t_8w_msa(uint8_t *src0_ptr, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, weight0, weight1, offset0, - offset1, rnd_val, 8); + offset1, rnd_val, 1); } static void hevc_hv_biwgt_8t_12w_msa(uint8_t *src0_ptr, @@ -2199,16 +2281,239 @@ static void hevc_hv_biwgt_8t_12w_msa(uint8_t *src0_ptr, int32_t offset1, int32_t rnd_val) { - hevc_hv_biwgt_8t_8multx2mult_msa(src0_ptr, src_stride, - src1_ptr, src2_stride, - dst, dst_stride, filter_x, filter_y, - height, weight0, weight1, offset0, - offset1, rnd_val, 8); - hevc_hv_biwgt_8t_4w_msa(src0_ptr + 8, src_stride, - src1_ptr + 8, src2_stride, - dst + 8, dst_stride, filter_x, filter_y, - height, weight0, weight1, offset0, offset1, - rnd_val); + uint32_t loop_cnt; + uint8_t *src0_ptr_tmp, *dst_tmp; + int16_t *src1_ptr_tmp; + int32_t offset, weight; + uint64_t tp0, tp1; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; + v16i8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask7; + v8i16 in0 = { 0 }, in1 = { 0 }; + v8i16 filter_vec, weight_vec, tmp0, tmp1, tmp2, tmp3; + v8i16 filt0, filt1, filt2, filt3, filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6, dsth7, dsth8; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst76_l, dst21_l, dst43_l, dst65_l; + v8i16 dst30, dst41, dst52, dst63, dst66, dst87, dst10, dst32, dst54, dst76; + v8i16 dst21, dst43, dst65, dst97, dst108, dst109, dst98, dst87_r, dst87_l; + v4i32 offset_vec, rnd_vec, const_vec, dst0, dst1, dst2, dst3; + + src0_ptr -= ((3 * src_stride) + 3); + + offset = (offset0 + offset1) << rnd_val; + weight0 = weight0 & 0x0000FFFF; + weight = weight0 | (weight1 << 16); + + const_vec = __msa_fill_w((128 * weight1)); + const_vec <<= 6; + offset_vec = __msa_fill_w(offset); + rnd_vec = __msa_fill_w(rnd_val + 1); + offset_vec += const_vec; + weight_vec = (v8i16) __msa_fill_w(weight); + + filter_vec = LD_SH(filter_x); + SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + mask2 = mask0 + 4; + mask3 = mask0 + 6; + + src0_ptr_tmp = src0_ptr; + src1_ptr_tmp = src1_ptr; + dst_tmp = dst; + + LD_SB7(src0_ptr_tmp, src_stride, src0, src1, src2, src3, src4, src5, src6); + src0_ptr_tmp += (7 * src_stride); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, vec8, vec9, vec10, + vec11); + VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec12, vec13, vec14, + vec15); + dsth0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dsth1 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dsth2 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dsth3 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, + filt2, filt3); + VSHF_B4_SB(src4, src4, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src5, src5, mask0, mask1, mask2, mask3, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src6, src6, mask0, mask1, mask2, mask3, vec8, vec9, vec10, + vec11); + dsth4 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dsth5 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dsth6 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + + for (loop_cnt = 8; loop_cnt--;) { + LD_SB2(src0_ptr_tmp, src_stride, src7, src8); + src0_ptr_tmp += (2 * src_stride); + XORI_B2_128_SB(src7, src8); + + LD_SH2(src1_ptr_tmp, src2_stride, in0, in1); + src1_ptr_tmp += (2 * src2_stride); + + ILVR_H4_SH(dsth1, dsth0, dsth3, dsth2, dsth5, dsth4, dsth2, dsth1, + dst10_r, dst32_r, dst54_r, dst21_r); + ILVL_H4_SH(dsth1, dsth0, dsth3, dsth2, dsth5, dsth4, dsth2, dsth1, + dst10_l, dst32_l, dst54_l, dst21_l); + ILVR_H2_SH(dsth4, dsth3, dsth6, dsth5, dst43_r, dst65_r); + ILVL_H2_SH(dsth4, dsth3, dsth6, dsth5, dst43_l, dst65_l); + + VSHF_B4_SB(src7, src7, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + dsth7 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + + ILVRL_H2_SH(dsth7, dsth6, dst76_r, dst76_l); + dst0 = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst1 = HEVC_FILT_8TAP(dst10_l, dst32_l, dst54_l, dst76_l, filt_h0, + filt_h1, filt_h2, filt_h3); + dst0 >>= 6; + dst1 >>= 6; + + VSHF_B4_SB(src8, src8, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + dsth8 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + + ILVRL_H2_SH(dsth8, dsth7, dst87_r, dst87_l); + dst2 = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst3 = HEVC_FILT_8TAP(dst21_l, dst43_l, dst65_l, dst87_l, filt_h0, + filt_h1, filt_h2, filt_h3); + dst2 >>= 6; + dst3 >>= 6; + + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp1, tmp3); + ILVRL_H2_SH(tmp1, in0, tmp0, tmp1); + ILVRL_H2_SH(tmp3, in1, tmp2, tmp3); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + SRAR_W4_SW(dst1, dst0, dst3, dst2, rnd_vec); + CLIP_SW4_0_255_MAX_SATU(dst1, dst0, dst3, dst2); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp0, tmp1); + out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); + ST8x2_UB(out, dst_tmp, dst_stride); + dst_tmp += (2 * dst_stride); + + dsth0 = dsth2; + dsth1 = dsth3; + dsth2 = dsth4; + dsth3 = dsth5; + dsth4 = dsth6; + dsth5 = dsth7; + dsth6 = dsth8; + } + + src0_ptr += 8; + src1_ptr += 8; + dst += 8; + + mask4 = LD_SB(ff_hevc_mask_arr + 16); + mask5 = mask4 + 2; + mask6 = mask4 + 4; + mask7 = mask4 + 6; + + LD_SB7(src0_ptr, src_stride, src0, src1, src2, src3, src4, src5, src6); + src0_ptr += (7 * src_stride); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + VSHF_B4_SB(src0, src3, mask4, mask5, mask6, mask7, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src1, src4, mask4, mask5, mask6, mask7, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src2, src5, mask4, mask5, mask6, mask7, vec8, vec9, vec10, + vec11); + VSHF_B4_SB(src3, src6, mask4, mask5, mask6, mask7, vec12, vec13, vec14, + vec15); + dst30 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst41 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst52 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst63 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, + filt3); + ILVRL_H2_SH(dst41, dst30, dst10, dst43); + ILVRL_H2_SH(dst52, dst41, dst21, dst54); + ILVRL_H2_SH(dst63, dst52, dst32, dst65); + + dst66 = (v8i16) __msa_splati_d((v2i64) dst63, 1); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src0_ptr, src_stride, src7, src8, src9, src10); + src0_ptr += (4 * src_stride); + XORI_B4_128_SB(src7, src8, src9, src10); + + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in0); + src1_ptr += (2 * src2_stride); + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in1); + src1_ptr += (2 * src2_stride); + + VSHF_B4_SB(src7, src9, mask4, mask5, mask6, mask7, vec0, vec1, vec2, + vec3); + VSHF_B4_SB(src8, src10, mask4, mask5, mask6, mask7, vec4, vec5, vec6, + vec7); + dst97 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst108 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + + dst76 = __msa_ilvr_h(dst97, dst66); + ILVRL_H2_SH(dst108, dst97, dst87, dst109); + dst66 = (v8i16) __msa_splati_d((v2i64) dst97, 1); + dst98 = __msa_ilvr_h(dst66, dst108); + + dst0 = HEVC_FILT_8TAP(dst10, dst32, dst54, dst76, filt_h0, filt_h1, + filt_h2, filt_h3); + dst1 = HEVC_FILT_8TAP(dst21, dst43, dst65, dst87, filt_h0, filt_h1, + filt_h2, filt_h3); + dst2 = HEVC_FILT_8TAP(dst32, dst54, dst76, dst98, filt_h0, filt_h1, + filt_h2, filt_h3); + dst3 = HEVC_FILT_8TAP(dst43, dst65, dst87, dst109, filt_h0, filt_h1, + filt_h2, filt_h3); + SRA_4V(dst0, dst1, dst2, dst3, 6); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp1, tmp3); + ILVRL_H2_SH(tmp1, in0, tmp0, tmp1); + ILVRL_H2_SH(tmp3, in1, tmp2, tmp3); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + CLIP_SW4_0_255_MAX_SATU(dst0, dst1, dst2, dst3); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp0, tmp1); + out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + dst += (4 * dst_stride); + + dst10 = dst54; + dst32 = dst76; + dst54 = dst98; + dst21 = dst65; + dst43 = dst87; + dst65 = dst109; + dst66 = (v8i16) __msa_splati_d((v2i64) dst108, 1); + } } static void hevc_hv_biwgt_8t_16w_msa(uint8_t *src0_ptr, @@ -2230,7 +2535,7 @@ static void hevc_hv_biwgt_8t_16w_msa(uint8_t *src0_ptr, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, weight0, weight1, offset0, - offset1, rnd_val, 16); + offset1, rnd_val, 2); } static void hevc_hv_biwgt_8t_24w_msa(uint8_t *src0_ptr, @@ -2252,7 +2557,7 @@ static void hevc_hv_biwgt_8t_24w_msa(uint8_t *src0_ptr, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, weight0, weight1, offset0, - offset1, rnd_val, 24); + offset1, rnd_val, 3); } static void hevc_hv_biwgt_8t_32w_msa(uint8_t *src0_ptr, @@ -2274,7 +2579,7 @@ static void hevc_hv_biwgt_8t_32w_msa(uint8_t *src0_ptr, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, weight0, weight1, offset0, - offset1, rnd_val, 32); + offset1, rnd_val, 4); } static void hevc_hv_biwgt_8t_48w_msa(uint8_t *src0_ptr, @@ -2296,7 +2601,7 @@ static void hevc_hv_biwgt_8t_48w_msa(uint8_t *src0_ptr, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, weight0, weight1, offset0, - offset1, rnd_val, 48); + offset1, rnd_val, 6); } static void hevc_hv_biwgt_8t_64w_msa(uint8_t *src0_ptr, @@ -2318,7 +2623,7 @@ static void hevc_hv_biwgt_8t_64w_msa(uint8_t *src0_ptr, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, height, weight0, weight1, offset0, - offset1, rnd_val, 64); + offset1, rnd_val, 8); } static void hevc_hz_biwgt_4t_4x2_msa(uint8_t *src0_ptr, @@ -2328,22 +2633,21 @@ static void hevc_hz_biwgt_4t_4x2_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, int32_t offset1, int32_t rnd_val) { - int32_t offset, weight; + int32_t offset, weight, constant; v8i16 filt0, filt1; v16i8 src0, src1; v8i16 in0, in1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[16]); v16i8 mask1, vec0, vec1; v8i16 dst0; v4i32 dst0_r, dst0_l; - v8i16 filter_vec, const_vec; + v8i16 out0, filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 1; @@ -2356,9 +2660,10 @@ static void hevc_hz_biwgt_4t_4x2_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -2369,18 +2674,16 @@ static void hevc_hz_biwgt_4t_4x2_msa(uint8_t *src0_ptr, XORI_B2_128_SB(src0, src1); VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); ILVRL_H2_SW(dst0, in0, dst0_r, dst0_l); dst0_r = __msa_dpadd_s_w(offset_vec, (v8i16) dst0_r, (v8i16) weight_vec); dst0_l = __msa_dpadd_s_w(offset_vec, (v8i16) dst0_l, (v8i16) weight_vec); SRAR_W2_SW(dst0_r, dst0_l, rnd_vec); - dst0_r = CLIP_SW_0_255(dst0_r); - dst0_l = CLIP_SW_0_255(dst0_l); - - HEVC_PCK_SW_SB2(dst0_l, dst0_r, dst0_r); - ST4x2_UB(dst0_r, dst, dst_stride); + dst0_r = (v4i32) __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); + out0 = CLIP_SH_0_255(dst0_r); + out0 = (v8i16) __msa_pckev_b((v16i8) out0, (v16i8) out0); + ST4x2_UB(out0, dst, dst_stride); } static void hevc_hz_biwgt_4t_4x4_msa(uint8_t *src0_ptr, @@ -2390,23 +2693,21 @@ static void hevc_hz_biwgt_4t_4x4_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, int32_t offset1, int32_t rnd_val) { - int32_t offset, weight; + int32_t offset, weight, constant; v8i16 filt0, filt1; v16i8 src0, src1, src2, src3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[16]); v16i8 mask1; v8i16 dst0, dst1; v16i8 vec0, vec1; v8i16 in0, in1, in2, in3; - v4i32 dst0_r, dst1_r, dst0_l, dst1_l; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 1; @@ -2420,9 +2721,10 @@ static void hevc_hz_biwgt_4t_4x4_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -2433,17 +2735,15 @@ static void hevc_hz_biwgt_4t_4x4_msa(uint8_t *src0_ptr, ILVR_D2_SH(in1, in0, in3, in2, in0, in1); VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src2, src3, src2, src3, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + dst1 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); HEVC_BIW_RND_CLIP2(dst0, dst1, in0, in1, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + dst0, dst1); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST4x4_UB(dst0_r, dst0_r, 0, 1, 2, 3, dst, dst_stride); + dst0 = (v8i16) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); + ST4x4_UB(dst0, dst0, 0, 1, 2, 3, dst, dst_stride); } static void hevc_hz_biwgt_4t_4x8multiple_msa(uint8_t *src0_ptr, @@ -2461,16 +2761,15 @@ static void hevc_hz_biwgt_4t_4x8multiple_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t weight, offset; + int32_t weight, offset, constant; v8i16 filt0, filt1; v16i8 src0, src1, src2, src3, src4, src5, src6, src7; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[16]); v16i8 mask1; v16i8 vec0, vec1; v8i16 dst0, dst1, dst2, dst3; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 1; @@ -2481,9 +2780,10 @@ static void hevc_hz_biwgt_4t_4x8multiple_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -2503,26 +2803,20 @@ static void hevc_hz_biwgt_4t_4x8multiple_msa(uint8_t *src0_ptr, XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src2, src3, src2, src3, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + dst1 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src4, src5, src4, src5, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + dst2 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src6, src7, src6, src7, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + dst0, dst1, dst2, dst3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST4x8_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); + ST4x8_UB(dst0, dst1, dst, dst_stride); dst += (8 * dst_stride); } } @@ -2543,11 +2837,11 @@ static void hevc_hz_biwgt_4t_4w_msa(uint8_t *src0_ptr, { if (2 == height) { hevc_hz_biwgt_4t_4x2_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter, height, + dst, dst_stride, filter, weight0, weight1, offset0, offset1, rnd_val); } else if (4 == height) { hevc_hz_biwgt_4t_4x4_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter, height, + dst, dst_stride, filter, weight0, weight1, offset0, offset1, rnd_val); } else if (0 == (height % 8)) { hevc_hz_biwgt_4t_4x8multiple_msa(src0_ptr, src_stride, @@ -2573,16 +2867,15 @@ static void hevc_hz_biwgt_4t_6w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v8i16 filt0, filt1; v16i8 src0, src1, src2, src3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1; v16i8 vec0, vec1; v8i16 in0, in1, in2, in3; v8i16 dst0, dst1, dst2, dst3; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 1; @@ -2593,16 +2886,17 @@ static void hevc_hz_biwgt_4t_6w_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); mask1 = mask0 + 2; - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = 2; loop_cnt--;) { LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); src0_ptr += (4 * src_stride); LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); @@ -2610,27 +2904,21 @@ static void hevc_hz_biwgt_4t_6w_msa(uint8_t *src0_ptr, XORI_B4_128_SB(src0, src1, src2, src3); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + dst1 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + dst2 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + dst0, dst1, dst2, dst3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); + ST6x4_UB(dst0, dst1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -2642,22 +2930,20 @@ static void hevc_hz_biwgt_4t_8x2_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, int32_t offset1, int32_t rnd_val) { - int32_t offset, weight; + int32_t offset, weight, constant; v8i16 filt0, filt1; v16i8 src0, src1; v8i16 in0, in1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1, vec0, vec1; v8i16 dst0, dst1; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst0_l, dst1_l; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 1; @@ -2668,9 +2954,10 @@ static void hevc_hz_biwgt_4t_8x2_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -2681,17 +2968,15 @@ static void hevc_hz_biwgt_4t_8x2_msa(uint8_t *src0_ptr, LD_SH2(src1_ptr, src2_stride, in0, in1); XORI_B2_128_SB(src0, src1); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + dst1 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); HEVC_BIW_RND_CLIP2(dst0, dst1, in0, in1, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + dst0, dst1); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST8x2_UB(dst0_r, dst, dst_stride); + dst0 = (v8i16) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); + ST8x2_UB(dst0, dst, dst_stride); } static void hevc_hz_biwgt_4t_8x6_msa(uint8_t *src0_ptr, @@ -2701,24 +2986,21 @@ static void hevc_hz_biwgt_4t_8x6_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, int32_t offset1, int32_t rnd_val) { - int32_t weight, offset; + int32_t weight, offset, constant; v8i16 filt0, filt1; v16i8 src0, src1, src2, src3, src4, src5; v8i16 in0, in1, in2, in3, in4, in5; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1; v16i8 vec0, vec1; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 1; @@ -2729,9 +3011,10 @@ static void hevc_hz_biwgt_4t_8x6_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -2745,38 +3028,30 @@ static void hevc_hz_biwgt_4t_8x6_msa(uint8_t *src0_ptr, LD_SH2(src1_ptr, src2_stride, in4, in5); XORI_B6_128_SB(src0, src1, src2, src3, src4, src5); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + dst1 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + dst2 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); + dst4 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); + dst5 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + dst0, dst1, dst2, dst3); HEVC_BIW_RND_CLIP2(dst4, dst5, in4, in5, weight_vec, rnd_vec, offset_vec, - dst4_r, dst5_r, dst4_l, dst5_l); + dst4, dst5); - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, dst0_r, dst1_r, dst2_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); + dst3 = (v8i16) __msa_pckev_b((v16i8) dst5, (v16i8) dst4); + ST8x4_UB(dst0, dst1, dst, dst_stride); dst += (4 * dst_stride); - ST8x2_UB(dst2_r, dst, dst_stride); + ST8x2_UB(dst3, dst, dst_stride); } static void hevc_hz_biwgt_4t_8x4multiple_msa(uint8_t *src0_ptr, @@ -2794,16 +3069,15 @@ static void hevc_hz_biwgt_4t_8x4multiple_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v8i16 filt0, filt1; v16i8 src0, src1, src2, src3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v16i8 vec0, vec1; v8i16 in0, in1, in2, in3; v8i16 dst0, dst1, dst2, dst3; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 1; @@ -2814,9 +3088,10 @@ static void hevc_hz_biwgt_4t_8x4multiple_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -2831,26 +3106,20 @@ static void hevc_hz_biwgt_4t_8x4multiple_msa(uint8_t *src0_ptr, XORI_B4_128_SB(src0, src1, src2, src3); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + dst1 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + dst2 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + dst0, dst1, dst2, dst3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); + ST8x4_UB(dst0, dst1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -2871,11 +3140,11 @@ static void hevc_hz_biwgt_4t_8w_msa(uint8_t *src0_ptr, { if (2 == height) { hevc_hz_biwgt_4t_8x2_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter, height, + dst, dst_stride, filter, weight0, weight1, offset0, offset1, rnd_val); } else if (6 == height) { hevc_hz_biwgt_4t_8x6_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter, height, + dst, dst_stride, filter, weight0, weight1, offset0, offset1, rnd_val); } else if (0 == (height % 4)) { hevc_hz_biwgt_4t_8x4multiple_msa(src0_ptr, src_stride, @@ -2901,20 +3170,18 @@ static void hevc_hz_biwgt_4t_12w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v8i16 filt0, filt1; v16i8 src0, src1, src2, src3; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask2 = { 8, 9, 9, 10, 10, 11, 11, 12, 24, 25, 25, 26, 26, 27, 27, 28 }; v16i8 mask1, mask3; v16i8 vec0, vec1; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 1; @@ -2925,9 +3192,10 @@ static void hevc_hz_biwgt_4t_12w_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -2935,7 +3203,7 @@ static void hevc_hz_biwgt_4t_12w_msa(uint8_t *src0_ptr, mask1 = mask0 + 2; mask3 = mask2 + 2; - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = 4; loop_cnt--;) { LD_SB4(src0_ptr, src_stride, src0, src1, src2, src3); src0_ptr += (4 * src_stride); LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); @@ -2945,38 +3213,29 @@ static void hevc_hz_biwgt_4t_12w_msa(uint8_t *src0_ptr, XORI_B4_128_SB(src0, src1, src2, src3); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + dst1 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + dst2 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); + dst4 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src2, src3, src2, src3, mask2, mask3, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); + dst5 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + dst0, dst1, dst2, dst3); HEVC_BIW_RND_CLIP2(dst4, dst5, in4, in5, weight_vec, rnd_vec, offset_vec, - dst4_r, dst5_r, dst4_l, dst5_l); + dst4, dst5); - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, - dst0_r, dst1_r, dst2_r); - ST12x4_UB(dst0_r, dst1_r, dst2_r, dst, dst_stride); + PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); + dst3 = (v8i16) __msa_pckev_b((v16i8) dst5, (v16i8) dst4); + ST12x4_UB(dst0, dst1, dst3, dst, dst_stride); dst += (4 * dst_stride); } } @@ -2996,16 +3255,15 @@ static void hevc_hz_biwgt_4t_16w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2, src3, src4, src5, src6, src7; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; v8i16 filt0, filt1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; v16i8 vec0, vec1; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 1; @@ -3016,9 +3274,10 @@ static void hevc_hz_biwgt_4t_16w_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -3035,49 +3294,37 @@ static void hevc_hz_biwgt_4t_16w_msa(uint8_t *src0_ptr, XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + dst1 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + dst2 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); + dst4 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); + dst5 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); + dst6 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); + dst7 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + dst0, dst1, dst2, dst3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); + ST_SH2(dst0, dst1, dst, dst_stride); dst += (2 * dst_stride); HEVC_BIW_RND_CLIP4(dst4, dst5, dst6, dst7, in4, in5, in6, in7, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + dst0, dst1, dst2, dst3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); + ST_SH2(dst0, dst1, dst, dst_stride); dst += (2 * dst_stride); } } @@ -3097,17 +3344,15 @@ static void hevc_hz_biwgt_4t_24w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; - uint8_t *dst_tmp = dst + 16; + int32_t offset, weight, constant; v16i8 src0, src1, src2, src3; v8i16 filt0, filt1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1, mask2, mask3; v16i8 vec0, vec1; v8i16 dst0, dst1, dst2, dst3; v8i16 in0, in1, in2, in3, in4, in5; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 1; @@ -3118,9 +3363,10 @@ static void hevc_hz_biwgt_4t_24w_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -3129,7 +3375,7 @@ static void hevc_hz_biwgt_4t_24w_msa(uint8_t *src0_ptr, mask2 = mask0 + 8; mask3 = mask0 + 10; - for (loop_cnt = (height >> 1); loop_cnt--;) { + for (loop_cnt = 16; loop_cnt--;) { LD_SB2(src0_ptr, src_stride, src0, src2); LD_SB2(src0_ptr + 16, src_stride, src1, src3); src0_ptr += (2 * src_stride); @@ -3140,41 +3386,33 @@ static void hevc_hz_biwgt_4t_24w_msa(uint8_t *src0_ptr, XORI_B4_128_SB(src0, src1, src2, src3); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + dst1 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + dst2 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src2, src3, src2, src3, mask2, mask3, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + dst0, dst1, dst2, dst3); + + PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); + ST_SH2(dst0, dst1, dst, dst_stride); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); - dst += (2 * dst_stride); /* 8 width */ VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + dst1 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); HEVC_BIW_RND_CLIP2(dst0, dst1, in4, in5, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + dst0, dst1); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST8x2_UB(dst0_r, dst_tmp, dst_stride); - dst_tmp += (2 * dst_stride); + dst0 = (v8i16) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); + ST8x2_UB(dst0, (dst + 16), dst_stride); + dst += (2 * dst_stride); } } @@ -3193,16 +3431,15 @@ static void hevc_hz_biwgt_4t_32w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2; v8i16 filt0, filt1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1, mask2, mask3; v8i16 dst0, dst1, dst2, dst3; v16i8 vec0, vec1; v8i16 in0, in1, in2, in3; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= 1; @@ -3213,9 +3450,10 @@ static void hevc_hz_biwgt_4t_32w_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -3233,26 +3471,20 @@ static void hevc_hz_biwgt_4t_32w_msa(uint8_t *src0_ptr, XORI_B3_128_SB(src0, src1, src2); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + dst1 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + dst2 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); HEVC_BIW_RND_CLIP4(dst0, dst1, dst2, dst3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + dst0, dst1, dst2, dst3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, 16); + PCKEV_B2_SH(dst1, dst0, dst3, dst2, dst0, dst1); + ST_SH2(dst0, dst1, dst, 16); dst += dst_stride; } } @@ -3264,20 +3496,19 @@ static void hevc_vt_biwgt_4t_4x2_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, int32_t offset1, int32_t rnd_val) { - int32_t weight, offset; + int32_t weight, offset, constant; v16i8 src0, src1, src2, src3, src4; v8i16 in0, in1, dst10; v16i8 src10_r, src32_r, src21_r, src43_r, src2110, src4332; v4i32 dst10_r, dst10_l; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec, out; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= src_stride; @@ -3285,9 +3516,10 @@ static void hevc_vt_biwgt_4t_4x2_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -3310,18 +3542,16 @@ static void hevc_vt_biwgt_4t_4x2_msa(uint8_t *src0_ptr, src4332 = (v16i8) __msa_ilvr_d((v2i64) src43_r, (v2i64) src32_r); src4332 = (v16i8) __msa_xori_b((v16u8) src4332, 128); - dst10 = const_vec; - DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst10, dst10); + dst10 = HEVC_FILT_4TAP_SH(src2110, src4332, filt0, filt1); ILVRL_H2_SW(dst10, in0, dst10_r, dst10_l); dst10_r = __msa_dpadd_s_w(offset_vec, (v8i16) dst10_r, (v8i16) weight_vec); dst10_l = __msa_dpadd_s_w(offset_vec, (v8i16) dst10_l, (v8i16) weight_vec); SRAR_W2_SW(dst10_r, dst10_l, rnd_vec); - dst10_r = CLIP_SW_0_255(dst10_r); - dst10_l = CLIP_SW_0_255(dst10_l); - - HEVC_PCK_SW_SB2(dst10_l, dst10_r, dst10_r); - ST4x2_UB(dst10_r, dst, dst_stride); + dst10_r = (v4i32) __msa_pckev_h((v8i16) dst10_l, (v8i16) dst10_r); + out = CLIP_SH_0_255(dst10_r); + out = (v8i16) __msa_pckev_b((v16i8) out, (v16i8) out); + ST4x2_UB(out, dst, dst_stride); } static void hevc_vt_biwgt_4t_4x4_msa(uint8_t *src0_ptr, @@ -3331,22 +3561,20 @@ static void hevc_vt_biwgt_4t_4x4_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, int32_t offset1, int32_t rnd_val) { - int32_t weight, offset; + int32_t weight, offset, constant; v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 in0, in1, in2, in3; v16i8 src10_r, src32_r, src54_r, src21_r, src43_r, src65_r; v16i8 src2110, src4332, src6554; v8i16 dst10, dst32; - v4i32 dst10_r, dst32_r, dst10_l, dst32_l; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= src_stride; @@ -3354,9 +3582,10 @@ static void hevc_vt_biwgt_4t_4x4_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -3380,17 +3609,15 @@ static void hevc_vt_biwgt_4t_4x4_msa(uint8_t *src0_ptr, ILVR_D2_SB(src43_r, src32_r, src65_r, src54_r, src4332, src6554); XORI_B2_128_SB(src4332, src6554); - dst10 = const_vec; - DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst10, dst10); - dst32 = const_vec; - DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst32, dst32); + dst10 = HEVC_FILT_4TAP_SH(src2110, src4332, filt0, filt1); + dst32 = HEVC_FILT_4TAP_SH(src4332, src6554, filt0, filt1); HEVC_BIW_RND_CLIP2(dst10, dst32, in0, in1, weight_vec, rnd_vec, offset_vec, - dst10_r, dst32_r, dst10_l, dst32_l); + dst10, dst32); - HEVC_PCK_SW_SB4(dst10_l, dst10_r, dst32_l, dst32_r, dst10_r); - ST4x4_UB(dst10_r, dst10_r, 0, 1, 2, 3, dst, dst_stride); + dst10 = (v8i16) __msa_pckev_b((v16i8) dst32, (v16i8) dst10); + ST4x4_UB(dst10, dst10, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); } @@ -3409,17 +3636,15 @@ static void hevc_vt_biwgt_4t_4x8multiple_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t weight, offset; + int32_t weight, offset, constant; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; v16i8 src10_r, src32_r, src54_r, src76_r, src98_r; v16i8 src21_r, src43_r, src65_r, src87_r, src109_r; v16i8 src2110, src4332, src6554, src8776; v8i16 dst10, dst32, dst54, dst76; - v4i32 dst10_r, dst32_r, dst54_r, dst76_r; - v4i32 dst10_l, dst32_l, dst54_l, dst76_l; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; src0_ptr -= src_stride; @@ -3427,9 +3652,10 @@ static void hevc_vt_biwgt_4t_4x8multiple_msa(uint8_t *src0_ptr, offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -3459,12 +3685,9 @@ static void hevc_vt_biwgt_4t_4x8multiple_msa(uint8_t *src0_ptr, src4332, src6554, src8776); XORI_B3_128_SB(src4332, src6554, src8776); - dst10 = const_vec; - DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst10, dst10); - dst32 = const_vec; - DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst32, dst32); - dst54 = const_vec; - DPADD_SB2_SH(src6554, src8776, filt0, filt1, dst54, dst54); + dst10 = HEVC_FILT_4TAP_SH(src2110, src4332, filt0, filt1); + dst32 = HEVC_FILT_4TAP_SH(src4332, src6554, filt0, filt1); + dst54 = HEVC_FILT_4TAP_SH(src6554, src8776, filt0, filt1); LD_SB2(src0_ptr, src_stride, src9, src2); src0_ptr += (2 * src_stride); @@ -3472,17 +3695,14 @@ static void hevc_vt_biwgt_4t_4x8multiple_msa(uint8_t *src0_ptr, src2110 = (v16i8) __msa_ilvr_d((v2i64) src109_r, (v2i64) src98_r); src2110 = (v16i8) __msa_xori_b((v16u8) src2110, 128); - dst76 = const_vec; - DPADD_SB2_SH(src8776, src2110, filt0, filt1, dst76, dst76); + dst76 = HEVC_FILT_4TAP_SH(src8776, src2110, filt0, filt1); HEVC_BIW_RND_CLIP4(dst10, dst32, dst54, dst76, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst10_r, dst32_r, dst54_r, dst76_r, - dst10_l, dst32_l, dst54_l, dst76_l); + dst10, dst32, dst54, dst76); - HEVC_PCK_SW_SB8(dst10_l, dst10_r, dst32_l, dst32_r, - dst54_l, dst54_r, dst76_l, dst76_r, dst10_r, dst54_r); - ST4x8_UB(dst10_r, dst54_r, dst, dst_stride); + PCKEV_B2_SH(dst32, dst10, dst76, dst54, dst10, dst32); + ST4x8_UB(dst10, dst32, dst, dst_stride); dst += (8 * dst_stride); } } @@ -3503,11 +3723,11 @@ static void hevc_vt_biwgt_4t_4w_msa(uint8_t *src0_ptr, { if (2 == height) { hevc_vt_biwgt_4t_4x2_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter, height, + dst, dst_stride, filter, weight0, weight1, offset0, offset1, rnd_val); } else if (4 == height) { hevc_vt_biwgt_4t_4x4_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter, height, + dst, dst_stride, filter, weight0, weight1, offset0, offset1, rnd_val); } else if (0 == (height % 8)) { hevc_vt_biwgt_4t_4x8multiple_msa(src0_ptr, src_stride, @@ -3533,24 +3753,24 @@ static void hevc_vt_biwgt_4t_6w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2, src3, src4; v8i16 in0, in1, in2, in3; v16i8 src10_r, src32_r, src21_r, src43_r; v8i16 tmp0, tmp1, tmp2, tmp3; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; src0_ptr -= src_stride; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -3571,29 +3791,23 @@ static void hevc_vt_biwgt_4t_6w_msa(uint8_t *src0_ptr, XORI_B2_128_SB(src3, src4); ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); + tmp0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); LD_SB2(src0_ptr, src_stride, src1, src2); src0_ptr += (2 * src_stride); XORI_B2_128_SB(src1, src2); ILVR_B2_SB(src1, src4, src2, src1, src10_r, src21_r); - tmp2 = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, tmp3, tmp3); + tmp2 = HEVC_FILT_4TAP_SH(src32_r, src10_r, filt0, filt1); + tmp3 = HEVC_FILT_4TAP_SH(src43_r, src21_r, filt0, filt1); HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + tmp0, tmp1, tmp2, tmp3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(tmp1, tmp0, tmp3, tmp2, tmp0, tmp1); + ST6x4_UB(tmp0, tmp1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -3605,30 +3819,29 @@ static void hevc_vt_biwgt_4t_8x2_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, int32_t offset1, int32_t rnd_val) { - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2, src3, src4; v8i16 in0, in1, tmp0, tmp1; v16i8 src10_r, src32_r, src21_r, src43_r; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst0_l, dst1_l; src0_ptr -= src_stride; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -3646,16 +3859,14 @@ static void hevc_vt_biwgt_4t_8x2_msa(uint8_t *src0_ptr, XORI_B2_128_SB(src3, src4); ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); + tmp0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); HEVC_BIW_RND_CLIP2(tmp0, tmp1, in0, in1, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + tmp0, tmp1); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST8x2_UB(dst0_r, dst, dst_stride); + tmp0 = (v8i16) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); + ST8x2_UB(tmp0, dst, dst_stride); } static void hevc_vt_biwgt_4t_8x6_msa(uint8_t *src0_ptr, @@ -3665,33 +3876,31 @@ static void hevc_vt_biwgt_4t_8x6_msa(uint8_t *src0_ptr, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, int32_t offset1, int32_t rnd_val) { - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v8i16 in0, in1, in2, in3, in4, in5; v16i8 src10_r, src32_r, src54_r, src76_r; v16i8 src21_r, src43_r, src65_r, src87_r; v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; src0_ptr -= src_stride; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -3711,33 +3920,25 @@ static void hevc_vt_biwgt_4t_8x6_msa(uint8_t *src0_ptr, src32_r, src43_r, src54_r, src65_r); ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB2_SH(src32_r, src54_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src43_r, src65_r, filt0, filt1, tmp3, tmp3); - tmp4 = const_vec; - DPADD_SB2_SH(src54_r, src76_r, filt0, filt1, tmp4, tmp4); - tmp5 = const_vec; - DPADD_SB2_SH(src65_r, src87_r, filt0, filt1, tmp5, tmp5); + tmp0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + tmp2 = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + tmp3 = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); + tmp4 = HEVC_FILT_4TAP_SH(src54_r, src76_r, filt0, filt1); + tmp5 = HEVC_FILT_4TAP_SH(src65_r, src87_r, filt0, filt1); HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + tmp0, tmp1, tmp2, tmp3); HEVC_BIW_RND_CLIP2(tmp4, tmp5, in4, in5, weight_vec, rnd_vec, offset_vec, - dst4_r, dst5_r, dst4_l, dst5_l); + tmp4, tmp5); - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, dst0_r, dst1_r, dst2_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(tmp1, tmp0, tmp3, tmp2, tmp0, tmp1); + tmp3 = (v8i16) __msa_pckev_b((v16i8) tmp5, (v16i8) tmp4); + ST8x4_UB(tmp0, tmp1, dst, dst_stride); dst += (4 * dst_stride); - ST8x2_UB(dst2_r, dst, dst_stride); + ST8x2_UB(tmp3, dst, dst_stride); } static void hevc_vt_biwgt_4t_8x4multiple_msa(uint8_t *src0_ptr, @@ -3755,24 +3956,24 @@ static void hevc_vt_biwgt_4t_8x4multiple_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2, src3, src4; v8i16 in0, in1, in2, in3; v16i8 src10_r, src32_r, src21_r, src43_r; v8i16 tmp0, tmp1, tmp2, tmp3; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; src0_ptr -= src_stride; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -3793,29 +3994,23 @@ static void hevc_vt_biwgt_4t_8x4multiple_msa(uint8_t *src0_ptr, XORI_B2_128_SB(src3, src4); ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); + tmp0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); LD_SB2(src0_ptr, src_stride, src1, src2); src0_ptr += (2 * src_stride); XORI_B2_128_SB(src1, src2); ILVR_B2_SB(src1, src4, src2, src1, src10_r, src21_r); - tmp2 = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, tmp3, tmp3); + tmp2 = HEVC_FILT_4TAP_SH(src32_r, src10_r, filt0, filt1); + tmp3 = HEVC_FILT_4TAP_SH(src43_r, src21_r, filt0, filt1); HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + tmp0, tmp1, tmp2, tmp3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(tmp1, tmp0, tmp3, tmp2, tmp0, tmp1); + ST8x4_UB(tmp0, tmp1, dst, dst_stride); dst += (4 * dst_stride); } } @@ -3836,11 +4031,11 @@ static void hevc_vt_biwgt_4t_8w_msa(uint8_t *src0_ptr, { if (2 == height) { hevc_vt_biwgt_4t_8x2_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter, height, + dst, dst_stride, filter, weight0, weight1, offset0, offset1, rnd_val); } else if (6 == height) { hevc_vt_biwgt_4t_8x6_msa(src0_ptr, src_stride, src1_ptr, src2_stride, - dst, dst_stride, filter, height, + dst, dst_stride, filter, weight0, weight1, offset0, offset1, rnd_val); } else { hevc_vt_biwgt_4t_8x4multiple_msa(src0_ptr, src_stride, @@ -3866,7 +4061,7 @@ static void hevc_vt_biwgt_4t_12w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2, src3, src4, src5; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; v16i8 src10_r, src32_r, src21_r, src43_r; @@ -3874,19 +4069,18 @@ static void hevc_vt_biwgt_4t_12w_msa(uint8_t *src0_ptr, v16i8 src10_l, src32_l, src54_l, src21_l, src43_l, src65_l; v16i8 src2110, src4332; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; src0_ptr -= (1 * src_stride); offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -3914,12 +4108,9 @@ static void hevc_vt_biwgt_4t_12w_msa(uint8_t *src0_ptr, ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); src4332 = (v16i8) __msa_ilvr_d((v2i64) src43_l, (v2i64) src32_l); - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - tmp4 = const_vec; - DPADD_SB2_SH(src2110, src4332, filt0, filt1, tmp4, tmp4); + tmp0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + tmp4 = HEVC_FILT_4TAP_SH(src2110, src4332, filt0, filt1); LD_SB2(src0_ptr, src_stride, src5, src2); src0_ptr += (2 * src_stride); @@ -3928,26 +4119,20 @@ static void hevc_vt_biwgt_4t_12w_msa(uint8_t *src0_ptr, ILVL_B2_SB(src5, src4, src2, src5, src54_l, src65_l); src2110 = (v16i8) __msa_ilvr_d((v2i64) src65_l, (v2i64) src54_l); - tmp2 = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, tmp3, tmp3); - tmp5 = const_vec; - DPADD_SB2_SH(src4332, src2110, filt0, filt1, tmp5, tmp5); + tmp2 = HEVC_FILT_4TAP_SH(src32_r, src10_r, filt0, filt1); + tmp3 = HEVC_FILT_4TAP_SH(src43_r, src21_r, filt0, filt1); + tmp5 = HEVC_FILT_4TAP_SH(src4332, src2110, filt0, filt1); HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + tmp0, tmp1, tmp2, tmp3); HEVC_BIW_RND_CLIP2(tmp4, tmp5, in4, in5, weight_vec, rnd_vec, offset_vec, - dst4_r, dst5_r, dst4_l, dst5_l); + tmp4, tmp5); - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, - dst0_r, dst1_r, dst2_r); - ST12x4_UB(dst0_r, dst1_r, dst2_r, dst, dst_stride); + PCKEV_B2_SH(tmp1, tmp0, tmp3, tmp2, tmp0, tmp1); + tmp2 = (v8i16) __msa_pckev_b((v16i8) tmp5, (v16i8) tmp4); + ST12x4_UB(tmp0, tmp1, tmp2, dst, dst_stride); dst += (4 * dst_stride); } } @@ -3967,25 +4152,25 @@ static void hevc_vt_biwgt_4t_16w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2, src3, src4, src5; v8i16 in0, in1, in2, in3; v16i8 src10_r, src32_r, src21_r, src43_r; v16i8 src10_l, src32_l, src21_l, src43_l; v8i16 tmp0, tmp1, tmp2, tmp3; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; src0_ptr -= src_stride; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -4009,23 +4194,17 @@ static void hevc_vt_biwgt_4t_16w_msa(uint8_t *src0_ptr, ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB2_SH(src10_l, src32_l, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src21_l, src43_l, filt0, filt1, tmp3, tmp3); + tmp0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + tmp2 = HEVC_FILT_4TAP_SH(src10_l, src32_l, filt0, filt1); + tmp3 = HEVC_FILT_4TAP_SH(src21_l, src43_l, filt0, filt1); HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); + tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_SH(tmp2, tmp0, tmp3, tmp1, tmp0, tmp1); + ST_SH2(tmp0, tmp1, dst, dst_stride); dst += (2 * dst_stride); LD_SB2(src0_ptr, src_stride, src5, src2); src0_ptr += (2 * src_stride); @@ -4037,23 +4216,17 @@ static void hevc_vt_biwgt_4t_16w_msa(uint8_t *src0_ptr, ILVR_B2_SB(src5, src4, src2, src5, src10_r, src21_r); ILVL_B2_SB(src5, src4, src2, src5, src10_l, src21_l); - tmp0 = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB2_SH(src32_l, src10_l, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src43_l, src21_l, filt0, filt1, tmp3, tmp3); + tmp0 = HEVC_FILT_4TAP_SH(src32_r, src10_r, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(src43_r, src21_r, filt0, filt1); + tmp2 = HEVC_FILT_4TAP_SH(src32_l, src10_l, filt0, filt1); + tmp3 = HEVC_FILT_4TAP_SH(src43_l, src21_l, filt0, filt1); HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + tmp0, tmp1, tmp2, tmp3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(tmp2, tmp0, tmp3, tmp1, tmp0, tmp1); + ST_SH2(tmp0, tmp1, dst, dst_stride); dst += (2 * dst_stride); } } @@ -4073,7 +4246,7 @@ static void hevc_vt_biwgt_4t_24w_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2, src3, src4, src5; v16i8 src6, src7, src8, src9, src10, src11; v8i16 in0, in1, in2, in3, in4, in5; @@ -4082,19 +4255,18 @@ static void hevc_vt_biwgt_4t_24w_msa(uint8_t *src0_ptr, v16i8 src21_r, src43_r, src87_r, src109_r; v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; src0_ptr -= src_stride; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -4130,36 +4302,28 @@ static void hevc_vt_biwgt_4t_24w_msa(uint8_t *src0_ptr, XORI_B2_128_SB(src9, src10); ILVR_B2_SB(src9, src8, src10, src9, src98_r, src109_r); /* 16width */ - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp4 = const_vec; - DPADD_SB2_SH(src10_l, src32_l, filt0, filt1, tmp4, tmp4); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - tmp5 = const_vec; - DPADD_SB2_SH(src21_l, src43_l, filt0, filt1, tmp5, tmp5); + tmp0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + tmp4 = HEVC_FILT_4TAP_SH(src10_l, src32_l, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + tmp5 = HEVC_FILT_4TAP_SH(src21_l, src43_l, filt0, filt1); /* 8width */ - tmp2 = const_vec; - DPADD_SB2_SH(src76_r, src98_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src87_r, src109_r, filt0, filt1, tmp3, tmp3); + tmp2 = HEVC_FILT_4TAP_SH(src76_r, src98_r, filt0, filt1); + tmp3 = HEVC_FILT_4TAP_SH(src87_r, src109_r, filt0, filt1); /* 16width */ HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp4, tmp5, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + tmp0, tmp1, tmp4, tmp5); /* 8width */ HEVC_BIW_RND_CLIP2(tmp2, tmp3, in4, in5, weight_vec, rnd_vec, offset_vec, - dst4_r, dst5_r, dst4_l, dst5_l); + tmp2, tmp3); /* 16width */ - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); + PCKEV_B2_SH(tmp4, tmp0, tmp5, tmp1, tmp0, tmp1); /* 8width */ - HEVC_PCK_SW_SB4(dst4_l, dst4_r, dst5_l, dst5_r, dst4_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); - ST8x2_UB(dst4_r, dst + 16, dst_stride); + tmp2 = (v8i16) __msa_pckev_b((v16i8) tmp3, (v16i8) tmp2); + ST_SH2(tmp0, tmp1, dst, dst_stride); + ST8x2_UB(tmp2, dst + 16, dst_stride); dst += (2 * dst_stride); /* 16width */ @@ -4177,37 +4341,29 @@ static void hevc_vt_biwgt_4t_24w_msa(uint8_t *src0_ptr, XORI_B2_128_SB(src11, src8); ILVR_B2_SB(src11, src10, src8, src11, src76_r, src87_r); /* 16width */ - tmp0 = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, tmp0, tmp0); - tmp4 = const_vec; - DPADD_SB2_SH(src32_l, src10_l, filt0, filt1, tmp4, tmp4); - tmp1 = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, tmp1, tmp1); - tmp5 = const_vec; - DPADD_SB2_SH(src43_l, src21_l, filt0, filt1, tmp5, tmp5); + tmp0 = HEVC_FILT_4TAP_SH(src32_r, src10_r, filt0, filt1); + tmp4 = HEVC_FILT_4TAP_SH(src32_l, src10_l, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(src43_r, src21_r, filt0, filt1); + tmp5 = HEVC_FILT_4TAP_SH(src43_l, src21_l, filt0, filt1); /* 8width */ - tmp2 = const_vec; - DPADD_SB2_SH(src98_r, src76_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src109_r, src87_r, filt0, filt1, tmp3, tmp3); + tmp2 = HEVC_FILT_4TAP_SH(src98_r, src76_r, filt0, filt1); + tmp3 = HEVC_FILT_4TAP_SH(src109_r, src87_r, filt0, filt1); /* 16width */ HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp4, tmp5, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + tmp0, tmp1, tmp4, tmp5); /* 8width */ HEVC_BIW_RND_CLIP2(tmp2, tmp3, in4, in5, weight_vec, rnd_vec, offset_vec, - dst4_r, dst5_r, dst4_l, dst5_l); + tmp2, tmp3); /* 16width */ - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); + PCKEV_B2_SH(tmp4, tmp0, tmp5, tmp1, tmp0, tmp1); /* 8width */ - HEVC_PCK_SW_SB4(dst4_l, dst4_r, dst5_l, dst5_r, dst4_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); - ST8x2_UB(dst4_r, dst + 16, dst_stride); + tmp2 = (v8i16) __msa_pckev_b((v16i8) tmp3, (v16i8) tmp2); + ST_SH2(tmp0, tmp1, dst, dst_stride); + ST8x2_UB(tmp2, dst + 16, dst_stride); dst += (2 * dst_stride); } } @@ -4228,7 +4384,7 @@ static void hevc_vt_biwgt_4t_32w_msa(uint8_t *src0_ptr, { uint32_t loop_cnt; uint8_t *dst_tmp = dst + 16; - int32_t offset, weight; + int32_t offset, weight, constant; v16i8 src0, src1, src2, src3, src4, src6, src7, src8, src9, src10; v8i16 in0, in1, in2, in3, in4, in5, in6, in7; v16i8 src10_r, src32_r, src76_r, src98_r; @@ -4237,19 +4393,18 @@ static void hevc_vt_biwgt_4t_32w_msa(uint8_t *src0_ptr, v16i8 src10_l, src32_l, src76_l, src98_l; v16i8 src21_l, src43_l, src87_l, src109_l; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r, dst6_r, dst7_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l, dst6_l, dst7_l; src0_ptr -= src_stride; offset = (offset0 + offset1) << rnd_val; weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); + constant = 128 * weight1; + constant <<= 6; + offset += constant; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; offset_vec = __msa_fill_w(offset); weight_vec = __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); @@ -4279,24 +4434,18 @@ static void hevc_vt_biwgt_4t_32w_msa(uint8_t *src0_ptr, ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); /* 16width */ - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp4 = const_vec; - DPADD_SB2_SH(src10_l, src32_l, filt0, filt1, tmp4, tmp4); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - tmp5 = const_vec; - DPADD_SB2_SH(src21_l, src43_l, filt0, filt1, tmp5, tmp5); + tmp0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + tmp4 = HEVC_FILT_4TAP_SH(src10_l, src32_l, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + tmp5 = HEVC_FILT_4TAP_SH(src21_l, src43_l, filt0, filt1); /* 16width */ HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp4, tmp5, in0, in1, in2, in3, weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + tmp0, tmp1, tmp4, tmp5); /* 16width */ - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_SH(tmp4, tmp0, tmp5, tmp1, tmp0, tmp1); + ST_SH2(tmp0, tmp1, dst, dst_stride); dst += (2 * dst_stride); src10_r = src32_r; @@ -4315,25 +4464,19 @@ static void hevc_vt_biwgt_4t_32w_msa(uint8_t *src0_ptr, ILVR_B2_SB(src9, src8, src10, src9, src98_r, src109_r); ILVL_B2_SB(src9, src8, src10, src9, src98_l, src109_l); /* next 16width */ - tmp2 = const_vec; - DPADD_SB2_SH(src76_r, src98_r, filt0, filt1, tmp2, tmp2); - tmp6 = const_vec; - DPADD_SB2_SH(src76_l, src98_l, filt0, filt1, tmp6, tmp6); - tmp3 = const_vec; - DPADD_SB2_SH(src87_r, src109_r, filt0, filt1, tmp3, tmp3); - tmp7 = const_vec; - DPADD_SB2_SH(src87_l, src109_l, filt0, filt1, tmp7, tmp7); + tmp2 = HEVC_FILT_4TAP_SH(src76_r, src98_r, filt0, filt1); + tmp6 = HEVC_FILT_4TAP_SH(src76_l, src98_l, filt0, filt1); + tmp3 = HEVC_FILT_4TAP_SH(src87_r, src109_r, filt0, filt1); + tmp7 = HEVC_FILT_4TAP_SH(src87_l, src109_l, filt0, filt1); /* next 16width */ HEVC_BIW_RND_CLIP4(tmp2, tmp3, tmp6, tmp7, in4, in5, in6, in7, weight_vec, rnd_vec, offset_vec, - dst4_r, dst5_r, dst6_r, dst7_r, - dst4_l, dst5_l, dst6_l, dst7_l); + tmp2, tmp3, tmp6, tmp7); /* next 16width */ - HEVC_PCK_SW_SB8(dst4_l, dst4_r, dst6_l, dst6_r, - dst5_l, dst5_r, dst7_l, dst7_r, dst4_r, dst5_r); - ST_SW2(dst4_r, dst5_r, dst_tmp, dst_stride); + PCKEV_B2_SH(tmp6, tmp2, tmp7, tmp3, tmp2, tmp3); + ST_SH2(tmp2, tmp3, dst_tmp, dst_stride); dst_tmp += (2 * dst_stride); src76_r = src98_r; @@ -4352,26 +4495,25 @@ static void hevc_hv_biwgt_4t_4x2_msa(uint8_t *src0_ptr, int32_t dst_stride, const int8_t *filter_x, const int8_t *filter_y, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, int32_t offset1, int32_t rnd_val) { + uint64_t tp0, tp1; int32_t offset, weight; - v8i16 in0, in1; + v8i16 in0 = { 0 }; + v16u8 out; v16i8 src0, src1, src2, src3, src4; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec, tmp, weight_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4; - v4i32 dst0_r, dst1_r, dst0_l; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 dst20, dst31, dst42, dst10, dst32, dst21, dst43, tmp0, tmp1; + v4i32 dst0, dst1, offset_vec, rnd_vec, const_vec; src0_ptr -= (src_stride + 1); @@ -4379,10 +4521,9 @@ static void hevc_hv_biwgt_4t_4x2_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -4390,56 +4531,44 @@ static void hevc_hv_biwgt_4t_4x2_msa(uint8_t *src0_ptr, weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_fill_w((128 * weight1)); const_vec <<= 6; offset_vec = __msa_fill_w(offset); - weight_vec = __msa_fill_w(weight); + weight_vec = (v8i16) __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); - - LD_SB3(src0_ptr, src_stride, src0, src1, src2); - src0_ptr += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); - - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); - - LD_SB2(src0_ptr, src_stride, src3, src4); - LD_SH2(src1_ptr, src2_stride, in0, in1); - in0 = (v8i16) __msa_ilvr_d((v2i64) in1, (v2i64) in0); - XORI_B2_128_SB(src3, src4); - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_r = (v4i32) __msa_pckev_h((v8i16) dst1_r, (v8i16) dst0_r); - - ILVRL_H2_SW(dst1_r, in0, dst0_r, dst0_l); - dst0_r = __msa_dpadd_s_w(offset_vec, (v8i16) dst0_r, (v8i16) weight_vec); - dst0_l = __msa_dpadd_s_w(offset_vec, (v8i16) dst0_l, (v8i16) weight_vec); - SRAR_W2_SW(dst0_r, dst0_l, rnd_vec); - dst0_r = CLIP_SW_0_255(dst0_r); - dst0_l = CLIP_SW_0_255(dst0_l); - - HEVC_PCK_SW_SB2(dst0_l, dst0_r, dst0_r); - ST4x2_UB(dst0_r, dst, dst_stride); + offset_vec += const_vec; + + LD_SB5(src0_ptr, src_stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + + VSHF_B2_SB(src0, src2, src0, src2, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src3, src1, src3, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src4, src2, src4, mask0, mask1, vec4, vec5); + + dst20 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst31 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst42 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + + ILVRL_H2_SH(dst31, dst20, dst10, dst32); + ILVRL_H2_SH(dst42, dst31, dst21, dst43); + + dst0 = HEVC_FILT_4TAP(dst10, dst32, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21, dst43, filt_h0, filt_h1); + dst0 >>= 6; + dst1 >>= 6; + dst0 = (v4i32) __msa_pckev_h((v8i16) dst1, (v8i16) dst0); + + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in0); + + ILVRL_H2_SH(dst0, in0, tmp0, tmp1); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + SRAR_W2_SW(dst0, dst1, rnd_vec); + tmp = __msa_pckev_h((v8i16) dst1, (v8i16) dst0); + tmp = CLIP_SH_0_255_MAX_SATU(tmp); + out = (v16u8) __msa_pckev_b((v16i8) tmp, (v16i8) tmp); + ST4x2_UB(out, dst, dst_stride); } static void hevc_hv_biwgt_4t_4x4_msa(uint8_t *src0_ptr, @@ -4450,28 +4579,28 @@ static void hevc_hv_biwgt_4t_4x4_msa(uint8_t *src0_ptr, int32_t dst_stride, const int8_t *filter_x, const int8_t *filter_y, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, int32_t offset1, int32_t rnd_val) { + uint64_t tp0, tp1; int32_t offset, weight; - v8i16 in0, in1, in2, in3; + v16u8 out; + v8i16 in0 = { 0 }, in1 = { 0 }; v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v8i16 tmp0, tmp1; - v4i32 dst0_l, dst1_l; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 filter_vec, weight_vec; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 tmp0, tmp1, tmp2, tmp3; + v8i16 dst30, dst41, dst52, dst63; + v8i16 dst10, dst32, dst54, dst21, dst43, dst65; + v4i32 offset_vec, rnd_vec, const_vec; + v4i32 dst0, dst1, dst2, dst3; src0_ptr -= (src_stride + 1); @@ -4479,10 +4608,9 @@ static void hevc_hv_biwgt_4t_4x4_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -4490,66 +4618,54 @@ static void hevc_hv_biwgt_4t_4x4_msa(uint8_t *src0_ptr, weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_fill_w((128 * weight1)); const_vec <<= 6; offset_vec = __msa_fill_w(offset); - weight_vec = __msa_fill_w(weight); + weight_vec = (v8i16) __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); + offset_vec += const_vec; - LD_SB3(src0_ptr, src_stride, src0, src1, src2); - src0_ptr += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); - - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); - - LD_SB4(src0_ptr, src_stride, src3, src4, src5, src6); - LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); - ILVR_D2_SH(in1, in0, in3, in2, in0, in1); - XORI_B4_128_SB(src3, src4, src5, src6); - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - dst10_r = __msa_ilvr_h(dst5, dst4); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_r >>= 6; - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - dst21_r = __msa_ilvr_h(dst2, dst5); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_r >>= 6; - PCKEV_H2_SH(dst1_r, dst0_r, dst3_r, dst2_r, tmp0, tmp1); - HEVC_BIW_RND_CLIP2(tmp0, tmp1, in0, in1, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + LD_SB7(src0_ptr, src_stride, src0, src1, src2, src3, src4, src5, src6); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST4x4_UB(dst0_r, dst0_r, 0, 1, 2, 3, dst, dst_stride); + VSHF_B2_SB(src0, src3, src0, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src4, src1, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src5, src2, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src6, src3, src6, mask0, mask1, vec6, vec7); + + dst30 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst41 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst52 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst63 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + ILVRL_H2_SH(dst41, dst30, dst10, dst43); + ILVRL_H2_SH(dst52, dst41, dst21, dst54); + ILVRL_H2_SH(dst63, dst52, dst32, dst65); + dst0 = HEVC_FILT_4TAP(dst10, dst32, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21, dst43, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32, dst54, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43, dst65, filt_h0, filt_h1); + SRA_4V(dst0, dst1, dst2, dst3, 6); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp1, tmp3); + + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in0); + src1_ptr += (2 * src2_stride); + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in1); + + ILVRL_H2_SH(tmp1, in0, tmp0, tmp1); + ILVRL_H2_SH(tmp3, in1, tmp2, tmp3); + + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp0, tmp1); + CLIP_SH2_0_255_MAX_SATU(tmp0, tmp1); + out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); } static void hevc_hv_biwgt_4t_4multx8mult_msa(uint8_t *src0_ptr, @@ -4568,22 +4684,24 @@ static void hevc_hv_biwgt_4t_4multx8mult_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t loop_cnt; + uint64_t tp0, tp1; int32_t offset, weight; - v8i16 in0, in1, in2, in3, in4, in5, in6, in7; + v16u8 out0, out1; + v8i16 in0 = { 0 }, in1 = { 0 }, in2 = { 0 }, in3 = { 0 }; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8, dst9; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r, dst6_r, dst7_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l; - v8i16 tmp0, tmp1, tmp2, tmp3; + v8i16 filter_vec, weight_vec; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + v8i16 dst10, dst21, dst22, dst73, dst84, dst95, dst106; v8i16 dst10_r, dst32_r, dst54_r, dst76_r; v8i16 dst21_r, dst43_r, dst65_r, dst87_r; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 dst98_r, dst109_r; + v4i32 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v4i32 offset_vec, rnd_vec, const_vec; src0_ptr -= (src_stride + 1); @@ -4591,10 +4709,9 @@ static void hevc_hv_biwgt_4t_4multx8mult_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -4602,100 +4719,96 @@ static void hevc_hv_biwgt_4t_4multx8mult_msa(uint8_t *src0_ptr, weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_fill_w((128 * weight1)); const_vec <<= 6; offset_vec = __msa_fill_w(offset); - weight_vec = __msa_fill_w(weight); + weight_vec = (v8i16) __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); + offset_vec += const_vec; LD_SB3(src0_ptr, src_stride, src0, src1, src2); src0_ptr += (3 * src_stride); XORI_B3_128_SB(src0, src1, src2); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); + VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src2, src1, src2, mask0, mask1, vec2, vec3); + dst10 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst21 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + ILVRL_H2_SH(dst21, dst10, dst10_r, dst21_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst21, 1); for (loop_cnt = height >> 3; loop_cnt--;) { LD_SB8(src0_ptr, src_stride, src3, src4, src5, src6, src7, src8, src9, src10); src0_ptr += (8 * src_stride); - LD_SH8(src1_ptr, src2_stride, in0, in1, in2, in3, in4, in5, in6, in7); - src1_ptr += (8 * src2_stride); - ILVR_D2_SH(in1, in0, in3, in2, in0, in1); - ILVR_D2_SH(in5, in4, in7, in6, in2, in3); XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - dst54_r = __msa_ilvr_h(dst5, dst4); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); - dst2_r >>= 6; - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - dst65_r = __msa_ilvr_h(dst6, dst5); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); - dst3_r >>= 6; - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); - dst76_r = __msa_ilvr_h(dst7, dst6); - dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); - dst4_r >>= 6; - VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec0, vec1); - dst8 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst8, dst8); - dst87_r = __msa_ilvr_h(dst8, dst7); - dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); - dst5_r >>= 6; - VSHF_B2_SB(src9, src9, src9, src9, mask0, mask1, vec0, vec1); - dst9 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst9, dst9); - dst10_r = __msa_ilvr_h(dst9, dst8); - dst6_r = HEVC_FILT_4TAP(dst76_r, dst10_r, filt_h0, filt_h1); - dst6_r >>= 6; - VSHF_B2_SB(src10, src10, src10, src10, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - dst21_r = __msa_ilvr_h(dst2, dst9); - dst7_r = HEVC_FILT_4TAP(dst87_r, dst21_r, filt_h0, filt_h1); - dst7_r >>= 6; - PCKEV_H4_SH(dst1_r, dst0_r, dst3_r, dst2_r, - dst5_r, dst4_r, dst7_r, dst6_r, tmp0, tmp1, tmp2, tmp3); - HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - in0, in1, in2, in3, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST4x8_UB(dst0_r, dst1_r, dst, dst_stride); + VSHF_B2_SB(src3, src7, src3, src7, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src8, src4, src8, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src9, src5, src9, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src10, src6, src10, mask0, mask1, vec6, vec7); + + dst73 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst84 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst95 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst106 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + dst32_r = __msa_ilvr_h(dst73, dst22); + ILVRL_H2_SH(dst84, dst73, dst43_r, dst87_r); + ILVRL_H2_SH(dst95, dst84, dst54_r, dst98_r); + ILVRL_H2_SH(dst106, dst95, dst65_r, dst109_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst73, 1); + dst76_r = __msa_ilvr_h(dst22, dst106); + + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in0); + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in1); + + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in2); + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in3); + + dst0 = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4 = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5 = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6 = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7 = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + SRA_4V(dst0, dst1, dst2, dst3, 6); + SRA_4V(dst4, dst5, dst6, dst7, 6); + PCKEV_H4_SW(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, dst0, dst1, + dst2, dst3); + ILVRL_H2_SH(dst0, in0, tmp0, tmp1); + ILVRL_H2_SH(dst1, in1, tmp2, tmp3); + ILVRL_H2_SH(dst2, in2, tmp4, tmp5); + ILVRL_H2_SH(dst3, in3, tmp6, tmp7); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + dst4 = __msa_dpadd_s_w(offset_vec, tmp4, weight_vec); + dst5 = __msa_dpadd_s_w(offset_vec, tmp5, weight_vec); + dst6 = __msa_dpadd_s_w(offset_vec, tmp6, weight_vec); + dst7 = __msa_dpadd_s_w(offset_vec, tmp7, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + SRAR_W4_SW(dst4, dst5, dst6, dst7, rnd_vec); + PCKEV_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, tmp0, tmp1, + tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); dst += (8 * dst_stride); + + dst10_r = dst98_r; + dst21_r = dst109_r; + dst22 = (v8i16) __msa_splati_d((v2i64) dst106, 1); } } @@ -4717,13 +4830,11 @@ static void hevc_hv_biwgt_4t_4w_msa(uint8_t *src0_ptr, if (2 == height) { hevc_hv_biwgt_4t_4x2_msa(src0_ptr, src_stride, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, - height, weight0, weight1, offset0, offset1, - rnd_val); + weight0, weight1, offset0, offset1, rnd_val); } else if (4 == height) { hevc_hv_biwgt_4t_4x4_msa(src0_ptr, src_stride, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, - height, weight0, weight1, offset0, offset1, - rnd_val); + weight0, weight1, offset0, offset1, rnd_val); } else if (0 == (height % 8)) { hevc_hv_biwgt_4t_4multx8mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, @@ -4748,22 +4859,28 @@ static void hevc_hv_biwgt_4t_6w_msa(uint8_t *src0_ptr, int32_t offset1, int32_t rnd_val) { - uint32_t loop_cnt; + uint32_t tpw0, tpw1, tpw2, tpw3; + uint64_t tp0, tp1; int32_t offset, weight; - v16i8 src0, src1, src2, src3, src4, src5, src6; - v8i16 in0, in1, in2, in3; + v16u8 out0, out1, out2; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v8i16 in0 = { 0 }, in1 = { 0 }, in2 = { 0 }, in3 = { 0 }; + v8i16 in4 = { 0 }, in5 = { 0 }; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1, filter_vec; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6, dsth7, dsth8, dsth9; + v8i16 dsth10, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, weight_vec; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r, dst98_r, dst21_r, dst43_r; + v8i16 dst65_r, dst87_r, dst109_r, dst10_l, dst32_l, dst54_l, dst76_l; + v8i16 dst98_l, dst21_l, dst43_l, dst65_l, dst87_l, dst109_l; + v8i16 dst1021_l, dst3243_l, dst5465_l, dst7687_l, dst98109_l; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; - v8i16 tmp0, tmp1, tmp2, tmp3; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; - v8i16 dst10_l, dst32_l, dst21_l, dst43_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v4i32 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v4i32 dst4_r, dst5_r, dst6_r, dst7_r; + v4i32 offset_vec, rnd_vec, const_vec; src0_ptr -= (src_stride + 1); @@ -4771,10 +4888,9 @@ static void hevc_hv_biwgt_4t_6w_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -4782,11 +4898,12 @@ static void hevc_hv_biwgt_4t_6w_msa(uint8_t *src0_ptr, weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_fill_w((128 * weight1)); const_vec <<= 6; offset_vec = __msa_fill_w(offset); - weight_vec = __msa_fill_w(weight); + weight_vec = (v8i16) __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); + offset_vec += const_vec; LD_SB3(src0_ptr, src_stride, src0, src1, src2); src0_ptr += (3 * src_stride); @@ -4795,74 +4912,120 @@ static void hevc_hv_biwgt_4t_6w_msa(uint8_t *src0_ptr, VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - - ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); - ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - - for (loop_cnt = height >> 2; loop_cnt--;) { - LD_SB4(src0_ptr, src_stride, src3, src4, src5, src6); - src0_ptr += (4 * src_stride); - LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); - src1_ptr += (4 * src2_stride); - XORI_B4_128_SB(src3, src4, src5, src6); + dsth0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; + LD_SB8(src0_ptr, src_stride, src3, src4, src5, src6, src7, src8, src9, + src10); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; + dsth3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - ILVRL_H2_SH(dst5, dst4, dst10_r, dst10_l); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_l = HEVC_FILT_4TAP(dst32_l, dst10_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - ILVRL_H2_SH(dst2, dst5, dst21_r, dst21_l); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_l = HEVC_FILT_4TAP(dst43_l, dst21_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; - PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, tmp0, tmp1, tmp2, tmp3); - HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - in0, in1, in2, in3, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src9, src9, src9, src9, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src10, src10, src10, src10, mask0, mask1, vec6, vec7); + + dsth7 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth8 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth9 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth10 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); + ILVRL_H2_SH(dsth7, dsth6, dst76_r, dst76_l); + ILVRL_H2_SH(dsth8, dsth7, dst87_r, dst87_l); + ILVRL_H2_SH(dsth9, dsth8, dst98_r, dst98_l); + ILVRL_H2_SH(dsth10, dsth9, dst109_r, dst109_l); + PCKEV_D2_SH(dst21_l, dst10_l, dst43_l, dst32_l, dst1021_l, dst3243_l); + PCKEV_D2_SH(dst65_l, dst54_l, dst87_l, dst76_l, dst5465_l, dst7687_l); + dst98109_l = (v8i16) __msa_pckev_d((v2i64) dst109_l, (v2i64) dst98_l); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); - dst += (4 * dst_stride); - } + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6_r = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7_r = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst1021_l, dst3243_l, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst3243_l, dst5465_l, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst5465_l, dst7687_l, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst7687_l, dst98109_l, filt_h0, filt_h1); + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRA_4V(dst4_r, dst5_r, dst6_r, dst7_r, 6); + SRA_4V(dst0_l, dst1_l, dst2_l, dst3_l, 6); + PCKEV_H2_SW(dst1_r, dst0_r, dst3_r, dst2_r, dst0, dst1); + PCKEV_H2_SW(dst5_r, dst4_r, dst7_r, dst6_r, dst2, dst3); + + LD2(src1_ptr, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in0); + LD2(src1_ptr + 2 * src2_stride, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in1); + + LD2(src1_ptr + 4 * src2_stride, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in2); + LD2(src1_ptr + 6 * src2_stride, src2_stride, tp0, tp1); + INSERT_D2_SH(tp0, tp1, in3); + + ILVRL_H2_SH(dst0, in0, tmp0, tmp1); + ILVRL_H2_SH(dst1, in1, tmp2, tmp3); + ILVRL_H2_SH(dst2, in2, tmp4, tmp5); + ILVRL_H2_SH(dst3, in3, tmp6, tmp7); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + dst4 = __msa_dpadd_s_w(offset_vec, tmp4, weight_vec); + dst5 = __msa_dpadd_s_w(offset_vec, tmp5, weight_vec); + dst6 = __msa_dpadd_s_w(offset_vec, tmp6, weight_vec); + dst7 = __msa_dpadd_s_w(offset_vec, tmp7, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + SRAR_W4_SW(dst4, dst5, dst6, dst7, rnd_vec); + PCKEV_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, tmp0, tmp1, + tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); + + PCKEV_H2_SW(dst1_l, dst0_l, dst3_l, dst2_l, dst4, dst5); + + LW4(src1_ptr + 4, src2_stride, tpw0, tpw1, tpw2, tpw3); + src1_ptr += (4 * src2_stride); + INSERT_W4_SH(tpw0, tpw1, tpw2, tpw3, in4); + LW4(src1_ptr + 4, src2_stride, tpw0, tpw1, tpw2, tpw3); + INSERT_W4_SH(tpw0, tpw1, tpw2, tpw3, in5); + + ILVRL_H2_SH(dst4, in4, tmp0, tmp1); + ILVRL_H2_SH(dst5, in5, tmp2, tmp3); + + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp4, tmp5); + + CLIP_SH2_0_255_MAX_SATU(tmp4, tmp5); + out2 = (v16u8) __msa_pckev_b((v16i8) tmp5, (v16i8) tmp4); + ST2x4_UB(out2, 0, dst + 4, dst_stride); + dst += 4 * dst_stride; + ST2x4_UB(out2, 4, dst + 4, dst_stride); } static void hevc_hv_biwgt_4t_8x2_msa(uint8_t *src0_ptr, @@ -4873,7 +5036,6 @@ static void hevc_hv_biwgt_4t_8x2_msa(uint8_t *src0_ptr, int32_t dst_stride, const int8_t *filter_x, const int8_t *filter_y, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, @@ -4881,20 +5043,21 @@ static void hevc_hv_biwgt_4t_8x2_msa(uint8_t *src0_ptr, int32_t rnd_val) { int32_t weight, offset; + v16u8 out; v16i8 src0, src1, src2, src3, src4; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v8i16 filter_vec, weight_vec; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; v8i16 dst0, dst1, dst2, dst3, dst4; v8i16 in0, in1; v4i32 dst0_r, dst0_l, dst1_r, dst1_l; v8i16 dst10_r, dst32_r, dst21_r, dst43_r; v8i16 dst10_l, dst32_l, dst21_l, dst43_l; - v8i16 tmp0, tmp1; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 tmp0, tmp1, tmp2, tmp3; + v4i32 offset_vec, rnd_vec, const_vec; src0_ptr -= (src_stride + 1); @@ -4902,10 +5065,9 @@ static void hevc_hv_biwgt_4t_8x2_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -4913,61 +5075,177 @@ static void hevc_hv_biwgt_4t_8x2_msa(uint8_t *src0_ptr, weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_fill_w((128 * weight1)); const_vec <<= 6; offset_vec = __msa_fill_w(offset); - weight_vec = __msa_fill_w(weight); + weight_vec = (v8i16) __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); + offset_vec += const_vec; - LD_SB3(src0_ptr, src_stride, src0, src1, src2); - src0_ptr += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); + LD_SB5(src0_ptr, src_stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + + LD_SH2(src1_ptr, src2_stride, in0, in1); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec8, vec9); + + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec8, vec9, filt0, filt1); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); + ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + PCKEV_H2_SH(dst0_l, dst0_r, dst1_l, dst1_r, tmp1, tmp3); + + ILVRL_H2_SH(tmp1, in0, tmp0, tmp1); + ILVRL_H2_SH(tmp3, in1, tmp2, tmp3); + + dst0_r = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst0_l = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst1_r = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst1_l = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + SRAR_W4_SW(dst0_r, dst0_l, dst1_r, dst1_l, rnd_vec); + PCKEV_H2_SH(dst0_l, dst0_r, dst1_l, dst1_r, tmp0, tmp1); + CLIP_SH2_0_255_MAX_SATU(tmp0, tmp1); + out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); + ST8x2_UB(out, dst, dst_stride); +} - LD_SB2(src0_ptr, src_stride, src3, src4); +static void hevc_hv_biwgt_4t_8multx4_msa(uint8_t *src0_ptr, + int32_t src_stride, + int16_t *src1_ptr, + int32_t src2_stride, + uint8_t *dst, + int32_t dst_stride, + const int8_t *filter_x, + const int8_t *filter_y, + int32_t weight0, + int32_t weight1, + int32_t offset0, + int32_t offset1, + int32_t rnd_val, + int32_t width8mult) +{ + int32_t weight, offset; + uint32_t cnt; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, mask0, mask1; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 filt0, filt1, filt_h0, filt_h1, filter_vec, weight_vec; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, in0, in1, in2, in3; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; + v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + v4i32 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v4i32 offset_vec, rnd_vec, const_vec; - LD_SH2(src1_ptr, src2_stride, in0, in1); - XORI_B2_128_SB(src3, src4); + src0_ptr -= (src_stride + 1); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + filter_vec = LD_SH(filter_x); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - tmp0 = __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - tmp1 = __msa_pckev_h((v8i16) dst1_l, (v8i16) dst1_r); + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; - HEVC_BIW_RND_CLIP2(tmp0, tmp1, in0, in1, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst0_l, dst1_l); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST8x2_UB(dst0_r, dst, dst_stride); + offset = (offset0 + offset1) << rnd_val; + weight0 = weight0 & 0x0000FFFF; + weight = weight0 | (weight1 << 16); + + const_vec = __msa_fill_w((128 * weight1)); + const_vec <<= 6; + offset_vec = __msa_fill_w(offset); + rnd_vec = __msa_fill_w(rnd_val + 1); + offset_vec += const_vec; + weight_vec = (v8i16) __msa_fill_w(weight); + + for (cnt = width8mult; cnt--;) { + LD_SB7(src0_ptr, src_stride, src0, src1, src2, src3, src4, src5, src6); + src0_ptr += 8; + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + LD_SH4(src1_ptr, src2_stride, in0, in1, in2, in3); + src1_ptr += 8; + + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + + dsth0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); + + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + + dsth3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); + + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + PCKEV_H4_SW(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, dst0, dst1, dst2, dst3); + + ILVRL_H2_SH(dst0, in0, tmp0, tmp1); + ILVRL_H2_SH(dst1, in1, tmp2, tmp3); + ILVRL_H2_SH(dst2, in2, tmp4, tmp5); + ILVRL_H2_SH(dst3, in3, tmp6, tmp7); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + dst4 = __msa_dpadd_s_w(offset_vec, tmp4, weight_vec); + dst5 = __msa_dpadd_s_w(offset_vec, tmp5, weight_vec); + dst6 = __msa_dpadd_s_w(offset_vec, tmp6, weight_vec); + dst7 = __msa_dpadd_s_w(offset_vec, tmp7, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + SRAR_W4_SW(dst4, dst5, dst6, dst7, rnd_vec); + PCKEV_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, + tmp0, tmp1, tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST8x4_UB(out0, out1, dst, dst_stride); + dst += 8; + } } static void hevc_hv_biwgt_4t_8x6_msa(uint8_t *src0_ptr, @@ -4978,7 +5256,6 @@ static void hevc_hv_biwgt_4t_8x6_msa(uint8_t *src0_ptr, int32_t dst_stride, const int8_t *filter_x, const int8_t *filter_y, - int32_t height, int32_t weight0, int32_t weight1, int32_t offset0, @@ -4986,14 +5263,16 @@ static void hevc_hv_biwgt_4t_8x6_msa(uint8_t *src0_ptr, int32_t rnd_val) { uint32_t offset, weight; + v16u8 out0, out1, out2; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; + v8i16 filter_vec, weight_vec; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; + v16i8 vec10, vec11, vec12, vec13, vec14, vec15, vec16, vec17; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6, dsth7, dsth8; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; v4i32 dst4_r, dst4_l, dst5_r, dst5_l; v8i16 dst10_r, dst32_r, dst10_l, dst32_l; @@ -5001,8 +5280,9 @@ static void hevc_hv_biwgt_4t_8x6_msa(uint8_t *src0_ptr, v8i16 dst54_r, dst54_l, dst65_r, dst65_l; v8i16 dst76_r, dst76_l, dst87_r, dst87_l; v8i16 in0, in1, in2, in3, in4, in5; - v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + v4i32 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v4i32 offset_vec, rnd_vec, const_vec; src0_ptr -= (src_stride + 1); @@ -5010,10 +5290,9 @@ static void hevc_hv_biwgt_4t_8x6_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -5021,123 +5300,103 @@ static void hevc_hv_biwgt_4t_8x6_msa(uint8_t *src0_ptr, weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_fill_w((128 * weight1)); const_vec <<= 6; offset_vec = __msa_fill_w(offset); - weight_vec = __msa_fill_w(weight); + weight_vec = (v8i16) __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); + offset_vec += const_vec; - LD_SB3(src0_ptr, src_stride, src0, src1, src2); - src0_ptr += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); + LD_SB5(src0_ptr, src_stride, src0, src1, src2, src3, src4); + src0_ptr += (5 * src_stride); + LD_SB4(src0_ptr, src_stride, src5, src6, src7, src8); + + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B4_128_SB(src5, src6, src7, src8); + + LD_SH6(src1_ptr, src2_stride, in0, in1, in2, in3, in4, in5); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - - ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); - ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - - LD_SB2(src0_ptr, src_stride, src3, src4); - src0_ptr += (2 * src_stride); - XORI_B2_128_SB(src3, src4); - LD_SH6(src1_ptr, src2_stride, in0, in1, in2, in3, in4, in5); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec8, vec9); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec10, vec11); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec12, vec13); + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec14, vec15); + VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec16, vec17); + + dsth0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dsth4 = HEVC_FILT_4TAP_SH(vec8, vec9, filt0, filt1); + dsth5 = HEVC_FILT_4TAP_SH(vec10, vec11, filt0, filt1); + dsth6 = HEVC_FILT_4TAP_SH(vec12, vec13, filt0, filt1); + dsth7 = HEVC_FILT_4TAP_SH(vec14, vec15, filt0, filt1); + dsth8 = HEVC_FILT_4TAP_SH(vec16, vec17, filt0, filt1); + + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); + ILVRL_H2_SH(dsth7, dsth6, dst76_r, dst76_l); + ILVRL_H2_SH(dsth8, dsth7, dst87_r, dst87_l); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - tmp0 = __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - tmp1 = __msa_pckev_h((v8i16) dst1_l, (v8i16) dst1_r); - - LD_SB2(src0_ptr, src_stride, src5, src6); - src0_ptr += (2 * src_stride); - XORI_B2_128_SB(src5, src6); - - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; - tmp2 = __msa_pckev_h((v8i16) dst2_l, (v8i16) dst2_r); - - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - - ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; - tmp3 = __msa_pckev_h((v8i16) dst3_l, (v8i16) dst3_r); - - HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - in0, in1, in2, in3, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); - dst += (4 * dst_stride); - - LD_SB2(src0_ptr, src_stride, src7, src8); - XORI_B2_128_SB(src7, src8); - - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); - - ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); dst4_l = HEVC_FILT_4TAP(dst54_l, dst76_l, filt_h0, filt_h1); - dst4_r >>= 6; - dst4_l >>= 6; - tmp4 = __msa_pckev_h((v8i16) dst4_l, (v8i16) dst4_r); - - VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec0, vec1); - dst8 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst8, dst8); - - ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); dst5_l = HEVC_FILT_4TAP(dst65_l, dst87_l, filt_h0, filt_h1); - dst5_r >>= 6; - dst5_l >>= 6; - tmp5 = __msa_pckev_h((v8i16) dst5_l, (v8i16) dst5_r); - - HEVC_BIW_RND_CLIP2(tmp4, tmp5, in4, in5, - weight_vec, rnd_vec, offset_vec, - dst4_r, dst5_r, dst4_l, dst5_l); - HEVC_PCK_SW_SB4(dst4_l, dst4_r, dst5_l, dst5_r, dst2_r); - ST8x2_UB(dst2_r, dst, dst_stride); + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + SRA_4V(dst4_r, dst4_l, dst5_r, dst5_l, 6); + PCKEV_H4_SW(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, dst3_r, + dst0, dst1, dst2, dst3); + + ILVRL_H2_SH(dst0, in0, tmp0, tmp1); + ILVRL_H2_SH(dst1, in1, tmp2, tmp3); + ILVRL_H2_SH(dst2, in2, tmp4, tmp5); + ILVRL_H2_SH(dst3, in3, tmp6, tmp7); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + dst4 = __msa_dpadd_s_w(offset_vec, tmp4, weight_vec); + dst5 = __msa_dpadd_s_w(offset_vec, tmp5, weight_vec); + dst6 = __msa_dpadd_s_w(offset_vec, tmp6, weight_vec); + dst7 = __msa_dpadd_s_w(offset_vec, tmp7, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + SRAR_W4_SW(dst4, dst5, dst6, dst7, rnd_vec); + PCKEV_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, + tmp0, tmp1, tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + + PCKEV_H2_SW(dst4_l, dst4_r, dst5_l, dst5_r, dst0, dst1); + ILVRL_H2_SH(dst0, in4, tmp0, tmp1); + ILVRL_H2_SH(dst1, in5, tmp2, tmp3); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp4, tmp5); + CLIP_SH2_0_255_MAX_SATU(tmp4, tmp5); + out2 = (v16u8) __msa_pckev_b((v16i8) tmp5, (v16i8) tmp4); + ST8x4_UB(out0, out1, dst, dst_stride); + dst += (4 * dst_stride); + ST8x2_UB(out2, dst, dst_stride); } static void hevc_hv_biwgt_4t_8multx4mult_msa(uint8_t *src0_ptr, @@ -5162,20 +5421,22 @@ static void hevc_hv_biwgt_4t_8multx4mult_msa(uint8_t *src0_ptr, uint8_t *src0_ptr_tmp; int16_t *src1_ptr_tmp; uint8_t *dst_tmp; + v16u8 out0, out1; v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 in0, in1, in2, in3; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; + v8i16 filter_vec; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; - v8i16 tmp0, tmp1, tmp2, tmp3; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; - v8i16 dst10_l, dst32_l, dst21_l, dst43_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + v4i32 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l, weight_vec; + v4i32 offset_vec, rnd_vec, const_vec; src0_ptr -= (src_stride + 1); @@ -5183,10 +5444,9 @@ static void hevc_hv_biwgt_4t_8multx4mult_msa(uint8_t *src0_ptr, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -5194,11 +5454,12 @@ static void hevc_hv_biwgt_4t_8multx4mult_msa(uint8_t *src0_ptr, weight0 = weight0 & 0x0000FFFF; weight = weight0 | (weight1 << 16); - const_vec = __msa_ldi_h(128); + const_vec = __msa_fill_w((128 * weight1)); const_vec <<= 6; offset_vec = __msa_fill_w(offset); - weight_vec = __msa_fill_w(weight); + weight_vec = (v8i16) __msa_fill_w(weight); rnd_vec = __msa_fill_w(rnd_val + 1); + offset_vec += const_vec; for (cnt = width >> 3; cnt--;) { src0_ptr_tmp = src0_ptr; @@ -5212,15 +5473,12 @@ static void hevc_hv_biwgt_4t_8multx4mult_msa(uint8_t *src0_ptr, VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + dsth0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); - ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); - ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); for (loop_cnt = height >> 2; loop_cnt--;) { LD_SB4(src0_ptr_tmp, src_stride, src3, src4, src5, src6); @@ -5230,57 +5488,59 @@ static void hevc_hv_biwgt_4t_8multx4mult_msa(uint8_t *src0_ptr, XORI_B4_128_SB(src3, src4, src5, src6); VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; + dsth3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - ILVRL_H2_SH(dst5, dst4, dst10_r, dst10_l); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_l = HEVC_FILT_4TAP(dst32_l, dst10_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; - - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - ILVRL_H2_SH(dst2, dst5, dst21_r, dst21_l); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_l = HEVC_FILT_4TAP(dst43_l, dst21_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; - - PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, tmp0, tmp1, tmp2, tmp3); - HEVC_BIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - in0, in1, in2, in3, - weight_vec, rnd_vec, offset_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst_tmp, dst_stride); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + PCKEV_H4_SW(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, dst0, dst1, dst2, dst3); + ILVRL_H2_SH(dst0, in0, tmp0, tmp1); + ILVRL_H2_SH(dst1, in1, tmp2, tmp3); + ILVRL_H2_SH(dst2, in2, tmp4, tmp5); + ILVRL_H2_SH(dst3, in3, tmp6, tmp7); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + dst4 = __msa_dpadd_s_w(offset_vec, tmp4, weight_vec); + dst5 = __msa_dpadd_s_w(offset_vec, tmp5, weight_vec); + dst6 = __msa_dpadd_s_w(offset_vec, tmp6, weight_vec); + dst7 = __msa_dpadd_s_w(offset_vec, tmp7, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + SRAR_W4_SW(dst4, dst5, dst6, dst7, rnd_vec); + PCKEV_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, + tmp0, tmp1, tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST8x4_UB(out0, out1, dst_tmp, dst_stride); dst_tmp += (4 * dst_stride); + + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dsth2 = dsth6; } src0_ptr += 8; @@ -5307,13 +5567,16 @@ static void hevc_hv_biwgt_4t_8w_msa(uint8_t *src0_ptr, if (2 == height) { hevc_hv_biwgt_4t_8x2_msa(src0_ptr, src_stride, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, - height, weight0, weight1, offset0, offset1, - rnd_val); + weight0, weight1, offset0, offset1, rnd_val); + } else if (4 == height) { + hevc_hv_biwgt_4t_8multx4_msa(src0_ptr, src_stride, src1_ptr, + src2_stride, dst, dst_stride, filter_x, + filter_y, weight0, weight1, offset0, + offset1, rnd_val, 1); } else if (6 == height) { hevc_hv_biwgt_4t_8x6_msa(src0_ptr, src_stride, src1_ptr, src2_stride, dst, dst_stride, filter_x, filter_y, - height, weight0, weight1, offset0, offset1, - rnd_val); + weight0, weight1, offset0, offset1, rnd_val); } else if (0 == (height % 4)) { hevc_hv_biwgt_4t_8multx4mult_msa(src0_ptr, src_stride, src1_ptr, src2_stride, @@ -5338,16 +5601,228 @@ static void hevc_hv_biwgt_4t_12w_msa(uint8_t *src0_ptr, int32_t offset1, int32_t rnd_val) { - hevc_hv_biwgt_4t_8multx4mult_msa(src0_ptr, src_stride, - src1_ptr, src2_stride, - dst, dst_stride, - filter_x, filter_y, height, weight0, - weight1, offset0, offset1, rnd_val, 8); + uint32_t loop_cnt; + uint64_t tp0, tp1; + int32_t offset, weight; + uint8_t *src0_ptr_tmp, *dst_tmp; + int16_t *src1_ptr_tmp; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 mask0, mask1, mask2, mask3; + v8i16 filt0, filt1, filt_h0, filt_h1, filter_vec; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6, weight_vec; + v8i16 dst10, dst21, dst22, dst73, dst84, dst95, dst106; + v8i16 dst76_r, dst98_r, dst87_r, dst109_r; + v8i16 in0 = { 0 }, in1 = { 0 }, in2 = { 0 }, in3 = { 0 }; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; + v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + v4i32 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v4i32 offset_vec, rnd_vec, const_vec; + + src0_ptr -= (src_stride + 1); + + filter_vec = LD_SH(filter_x); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + + offset = (offset0 + offset1) << rnd_val; + weight0 = weight0 & 0x0000FFFF; + weight = weight0 | (weight1 << 16); + + const_vec = __msa_fill_w((128 * weight1)); + const_vec <<= 6; + offset_vec = __msa_fill_w(offset); + rnd_vec = __msa_fill_w(rnd_val + 1); + offset_vec += const_vec; + weight_vec = (v8i16) __msa_fill_w(weight); + + src0_ptr_tmp = src0_ptr; + dst_tmp = dst; + src1_ptr_tmp = src1_ptr; + + LD_SB3(src0_ptr_tmp, src_stride, src0, src1, src2); + src0_ptr_tmp += (3 * src_stride); + + XORI_B3_128_SB(src0, src1, src2); + + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + + dsth0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src0_ptr_tmp, src_stride, src3, src4, src5, src6); + src0_ptr_tmp += (4 * src_stride); + XORI_B4_128_SB(src3, src4, src5, src6); + + LD_SH4(src1_ptr_tmp, src2_stride, in0, in1, in2, in3); + src1_ptr_tmp += (4 * src2_stride); + + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + + dsth3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); + + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + PCKEV_H4_SW(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, dst0, dst1, dst2, dst3); + ILVRL_H2_SH(dst0, in0, tmp0, tmp1); + ILVRL_H2_SH(dst1, in1, tmp2, tmp3); + ILVRL_H2_SH(dst2, in2, tmp4, tmp5); + ILVRL_H2_SH(dst3, in3, tmp6, tmp7); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + dst4 = __msa_dpadd_s_w(offset_vec, tmp4, weight_vec); + dst5 = __msa_dpadd_s_w(offset_vec, tmp5, weight_vec); + dst6 = __msa_dpadd_s_w(offset_vec, tmp6, weight_vec); + dst7 = __msa_dpadd_s_w(offset_vec, tmp7, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + SRAR_W4_SW(dst4, dst5, dst6, dst7, rnd_vec); + PCKEV_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, + tmp0, tmp1, tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST8x4_UB(out0, out1, dst_tmp, dst_stride); + dst_tmp += (4 * dst_stride); + + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dsth2 = dsth6; + } + + src0_ptr += 8; + dst += 8; + src1_ptr += 8; + + mask2 = LD_SB(ff_hevc_mask_arr + 16); + mask3 = mask2 + 2; + + LD_SB3(src0_ptr, src_stride, src0, src1, src2); + src0_ptr += (3 * src_stride); + XORI_B3_128_SB(src0, src1, src2); + VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); + VSHF_B2_SB(src1, src2, src1, src2, mask2, mask3, vec2, vec3); + + dst10 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst21 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); - hevc_hv_biwgt_4t_4w_msa(src0_ptr + 8, src_stride, src1_ptr + 8, src2_stride, - dst + 8, dst_stride, filter_x, filter_y, - height, weight0, weight1, offset0, - offset1, rnd_val); + ILVRL_H2_SH(dst21, dst10, dst10_r, dst21_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst21, 1); + + for (loop_cnt = 2; loop_cnt--;) { + LD_SB8(src0_ptr, src_stride, src3, src4, src5, src6, src7, src8, src9, + src10); + src0_ptr += (8 * src_stride); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); + VSHF_B2_SB(src3, src7, src3, src7, mask2, mask3, vec0, vec1); + VSHF_B2_SB(src4, src8, src4, src8, mask2, mask3, vec2, vec3); + VSHF_B2_SB(src5, src9, src5, src9, mask2, mask3, vec4, vec5); + VSHF_B2_SB(src6, src10, src6, src10, mask2, mask3, vec6, vec7); + + dst73 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst84 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst95 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst106 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + dst32_r = __msa_ilvr_h(dst73, dst22); + ILVRL_H2_SH(dst84, dst73, dst43_r, dst87_r); + ILVRL_H2_SH(dst95, dst84, dst54_r, dst98_r); + ILVRL_H2_SH(dst106, dst95, dst65_r, dst109_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst73, 1); + dst76_r = __msa_ilvr_h(dst22, dst106); + + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in0); + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in1); + + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in2); + LD2(src1_ptr, src2_stride, tp0, tp1); + src1_ptr += 2 * src2_stride; + INSERT_D2_SH(tp0, tp1, in3); + + dst0 = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4 = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5 = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6 = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7 = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + + SRA_4V(dst0, dst1, dst2, dst3, 6); + SRA_4V(dst4, dst5, dst6, dst7, 6); + PCKEV_H4_SW(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, + dst0, dst1, dst2, dst3); + ILVRL_H2_SH(dst0, in0, tmp0, tmp1); + ILVRL_H2_SH(dst1, in1, tmp2, tmp3); + ILVRL_H2_SH(dst2, in2, tmp4, tmp5); + ILVRL_H2_SH(dst3, in3, tmp6, tmp7); + dst0 = __msa_dpadd_s_w(offset_vec, tmp0, weight_vec); + dst1 = __msa_dpadd_s_w(offset_vec, tmp1, weight_vec); + dst2 = __msa_dpadd_s_w(offset_vec, tmp2, weight_vec); + dst3 = __msa_dpadd_s_w(offset_vec, tmp3, weight_vec); + dst4 = __msa_dpadd_s_w(offset_vec, tmp4, weight_vec); + dst5 = __msa_dpadd_s_w(offset_vec, tmp5, weight_vec); + dst6 = __msa_dpadd_s_w(offset_vec, tmp6, weight_vec); + dst7 = __msa_dpadd_s_w(offset_vec, tmp7, weight_vec); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + SRAR_W4_SW(dst4, dst5, dst6, dst7, rnd_vec); + PCKEV_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, + tmp0, tmp1, tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); + dst += (8 * dst_stride); + + dst10_r = dst98_r; + dst21_r = dst109_r; + dst22 = (v8i16) __msa_splati_d((v2i64) dst106, 1); + } } static void hevc_hv_biwgt_4t_16w_msa(uint8_t *src0_ptr, @@ -5365,11 +5840,17 @@ static void hevc_hv_biwgt_4t_16w_msa(uint8_t *src0_ptr, int32_t offset1, int32_t rnd_val) { - hevc_hv_biwgt_4t_8multx4mult_msa(src0_ptr, src_stride, - src1_ptr, src2_stride, - dst, dst_stride, - filter_x, filter_y, height, weight0, - weight1, offset0, offset1, rnd_val, 16); + if (4 == height) { + hevc_hv_biwgt_4t_8multx4_msa(src0_ptr, src_stride, src1_ptr, + src2_stride, dst, dst_stride, filter_x, + filter_y, weight0, weight1, offset0, + offset1, rnd_val, 2); + } else { + hevc_hv_biwgt_4t_8multx4mult_msa(src0_ptr, src_stride, src1_ptr, + src2_stride, dst, dst_stride, + filter_x, filter_y, height, weight0, + weight1, offset0, offset1, rnd_val, 16); + } } static void hevc_hv_biwgt_4t_24w_msa(uint8_t *src0_ptr, @@ -5453,35 +5934,32 @@ BI_W_MC_COPY(64); #undef BI_W_MC_COPY -#define BI_W_MC(PEL, DIR, WIDTH, TAP, DIR1, FILT_DIR) \ -void ff_hevc_put_hevc_bi_w_##PEL##_##DIR##WIDTH##_8_msa(uint8_t *dst, \ - ptrdiff_t \ - dst_stride, \ - uint8_t *src, \ - ptrdiff_t \ - src_stride, \ - int16_t *src_16bit, \ - int height, \ - int denom, \ - int weight0, \ - int weight1, \ - int offset0, \ - int offset1, \ - intptr_t mx, \ - intptr_t my, \ - int width) \ -{ \ - const int8_t *filter = ff_hevc_##PEL##_filters[FILT_DIR - 1]; \ - \ - int shift = 14 + 1 - 8; \ - int log2Wd = denom + shift - 1; \ - \ - hevc_##DIR1##_biwgt_##TAP##t_##WIDTH##w_msa(src, src_stride, \ - src_16bit, MAX_PB_SIZE, \ - dst, dst_stride, \ - filter, height, \ - weight0, weight1, offset0, \ - offset1, log2Wd); \ +#define BI_W_MC(PEL, DIR, WIDTH, TAP, DIR1, FILT_DIR) \ +void ff_hevc_put_hevc_bi_w_##PEL##_##DIR##WIDTH##_8_msa(uint8_t *dst, \ + ptrdiff_t \ + dst_stride, \ + uint8_t *src, \ + ptrdiff_t \ + src_stride, \ + int16_t *src_16bit, \ + int height, \ + int denom, \ + int weight0, \ + int weight1, \ + int offset0, \ + int offset1, \ + intptr_t mx, \ + intptr_t my, \ + int width) \ +{ \ + const int8_t *filter = ff_hevc_##PEL##_filters[FILT_DIR - 1]; \ + int log2Wd = denom + 14 - 8; \ + \ + hevc_##DIR1##_biwgt_##TAP##t_##WIDTH##w_msa(src, src_stride, src_16bit, \ + MAX_PB_SIZE, dst, dst_stride, \ + filter, height, weight0, \ + weight1, offset0, offset1, \ + log2Wd); \ } BI_W_MC(qpel, h, 4, 8, hz, mx); @@ -5520,53 +5998,48 @@ BI_W_MC(epel, v, 32, 4, vt, my); #undef BI_W_MC -#define BI_W_MC_HV(PEL, DIR, WIDTH, TAP, DIR1) \ -void ff_hevc_put_hevc_bi_w_##PEL##_##DIR##WIDTH##_8_msa(uint8_t *dst, \ - ptrdiff_t \ - dst_stride, \ - uint8_t *src, \ - ptrdiff_t \ - src_stride, \ - int16_t *src_16bit, \ - int height, \ - int denom, \ - int weight0, \ - int weight1, \ - int offset0, \ - int offset1, \ - intptr_t mx, \ - intptr_t my, \ - int width) \ -{ \ - const int8_t *filter_x = ff_hevc_##PEL##_filters[mx - 1]; \ - const int8_t *filter_y = ff_hevc_##PEL##_filters[my - 1]; \ - \ - int shift = 14 + 1 - 8; \ - int log2Wd = denom + shift - 1; \ - \ - hevc_##DIR1##_biwgt_##TAP##t_##WIDTH##w_msa(src, src_stride, \ - src_16bit, MAX_PB_SIZE, \ - dst, dst_stride, \ - filter_x, filter_y, \ - height, weight0, weight1, \ - offset0, offset1, log2Wd); \ +#define BI_W_MC_HV(PEL, WIDTH, TAP) \ +void ff_hevc_put_hevc_bi_w_##PEL##_hv##WIDTH##_8_msa(uint8_t *dst, \ + ptrdiff_t dst_stride, \ + uint8_t *src, \ + ptrdiff_t src_stride, \ + int16_t *src_16bit, \ + int height, \ + int denom, \ + int weight0, \ + int weight1, \ + int offset0, \ + int offset1, \ + intptr_t mx, \ + intptr_t my, \ + int width) \ +{ \ + const int8_t *filter_x = ff_hevc_##PEL##_filters[mx - 1]; \ + const int8_t *filter_y = ff_hevc_##PEL##_filters[my - 1]; \ + int log2Wd = denom + 14 - 8; \ + \ + hevc_hv_biwgt_##TAP##t_##WIDTH##w_msa(src, src_stride, src_16bit, \ + MAX_PB_SIZE, dst, dst_stride, \ + filter_x, filter_y, height, \ + weight0, weight1, offset0, \ + offset1, log2Wd); \ } -BI_W_MC_HV(qpel, hv, 4, 8, hv); -BI_W_MC_HV(qpel, hv, 8, 8, hv); -BI_W_MC_HV(qpel, hv, 12, 8, hv); -BI_W_MC_HV(qpel, hv, 16, 8, hv); -BI_W_MC_HV(qpel, hv, 24, 8, hv); -BI_W_MC_HV(qpel, hv, 32, 8, hv); -BI_W_MC_HV(qpel, hv, 48, 8, hv); -BI_W_MC_HV(qpel, hv, 64, 8, hv); - -BI_W_MC_HV(epel, hv, 4, 4, hv); -BI_W_MC_HV(epel, hv, 8, 4, hv); -BI_W_MC_HV(epel, hv, 6, 4, hv); -BI_W_MC_HV(epel, hv, 12, 4, hv); -BI_W_MC_HV(epel, hv, 16, 4, hv); -BI_W_MC_HV(epel, hv, 24, 4, hv); -BI_W_MC_HV(epel, hv, 32, 4, hv); +BI_W_MC_HV(qpel, 4, 8); +BI_W_MC_HV(qpel, 8, 8); +BI_W_MC_HV(qpel, 12, 8); +BI_W_MC_HV(qpel, 16, 8); +BI_W_MC_HV(qpel, 24, 8); +BI_W_MC_HV(qpel, 32, 8); +BI_W_MC_HV(qpel, 48, 8); +BI_W_MC_HV(qpel, 64, 8); + +BI_W_MC_HV(epel, 4, 4); +BI_W_MC_HV(epel, 8, 4); +BI_W_MC_HV(epel, 6, 4); +BI_W_MC_HV(epel, 12, 4); +BI_W_MC_HV(epel, 16, 4); +BI_W_MC_HV(epel, 24, 4); +BI_W_MC_HV(epel, 32, 4); #undef BI_W_MC_HV diff --git a/libavcodec/mips/hevc_mc_uni_msa.c b/libavcodec/mips/hevc_mc_uni_msa.c index eead591ff492e..740c970ca12ad 100644 --- a/libavcodec/mips/hevc_mc_uni_msa.c +++ b/libavcodec/mips/hevc_mc_uni_msa.c @@ -22,6 +22,85 @@ #include "libavcodec/mips/hevcdsp_mips.h" #include "libavcodec/mips/hevc_macros_msa.h" +static const uint8_t ff_hevc_mask_arr[16 * 3] __attribute__((aligned(0x40))) = { + /* 8 width cases */ + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, + /* 4 width cases */ + 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20, + /* 4 width cases */ + 8, 9, 9, 10, 10, 11, 11, 12, 24, 25, 25, 26, 26, 27, 27, 28 +}; + +#define HORIZ_8TAP_4WID_4VECS_FILT(src0, src1, src2, src3, \ + mask0, mask1, mask2, mask3, \ + filt0, filt1, filt2, filt3, \ + out0, out1) \ +{ \ + v16i8 vec0_m, vec1_m, vec2_m, vec3_m, vec4_m, vec5_m, vec6_m, vec7_m; \ + \ + VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0_m, vec1_m); \ + DOTP_SB2_SH(vec0_m, vec1_m, filt0, filt0, out0, out1); \ + VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec2_m, vec3_m); \ + DPADD_SB2_SH(vec2_m, vec3_m, filt1, filt1, out0, out1); \ + VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec4_m, vec5_m); \ + DPADD_SB2_SH(vec4_m, vec5_m, filt2, filt2, out0, out1); \ + VSHF_B2_SB(src0, src1, src2, src3, mask3, mask3, vec6_m, vec7_m); \ + DPADD_SB2_SH(vec6_m, vec7_m, filt3, filt3, out0, out1); \ +} + +#define HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, \ + mask0, mask1, mask2, mask3, \ + filt0, filt1, filt2, filt3, \ + out0, out1, out2, out3) \ +{ \ + v16i8 vec0_m, vec1_m, vec2_m, vec3_m, vec4_m, vec5_m, vec6_m, vec7_m; \ + \ + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0_m, vec1_m); \ + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2_m, vec3_m); \ + DOTP_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt0, filt0, filt0, filt0, \ + out0, out1, out2, out3); \ + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec0_m, vec1_m); \ + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec2_m, vec3_m); \ + DPADD_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt2, filt2, filt2, filt2, \ + out0, out1, out2, out3); \ + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec4_m, vec5_m); \ + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec6_m, vec7_m); \ + DPADD_SB4_SH(vec4_m, vec5_m, vec6_m, vec7_m, filt1, filt1, filt1, filt1, \ + out0, out1, out2, out3); \ + VSHF_B2_SB(src0, src0, src1, src1, mask3, mask3, vec4_m, vec5_m); \ + VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec6_m, vec7_m); \ + DPADD_SB4_SH(vec4_m, vec5_m, vec6_m, vec7_m, filt3, filt3, filt3, filt3, \ + out0, out1, out2, out3); \ +} + +#define HORIZ_4TAP_4WID_4VECS_FILT(src0, src1, src2, src3, \ + mask0, mask1, filt0, filt1, \ + out0, out1) \ +{ \ + v16i8 vec0_m, vec1_m, vec2_m, vec3_m; \ + \ + VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0_m, vec1_m); \ + DOTP_SB2_SH(vec0_m, vec1_m, filt0, filt0, out0, out1); \ + VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec2_m, vec3_m); \ + DPADD_SB2_SH(vec2_m, vec3_m, filt1, filt1, out0, out1); \ +} + +#define HORIZ_4TAP_8WID_4VECS_FILT(src0, src1, src2, src3, \ + mask0, mask1, filt0, filt1, \ + out0, out1, out2, out3) \ +{ \ + v16i8 vec0_m, vec1_m, vec2_m, vec3_m; \ + \ + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0_m, vec1_m); \ + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2_m, vec3_m); \ + DOTP_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt0, filt0, filt0, filt0, \ + out0, out1, out2, out3); \ + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0_m, vec1_m); \ + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2_m, vec3_m); \ + DPADD_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt1, filt1, filt1, filt1, \ + out0, out1, out2, out3); \ +} + static void copy_width8_msa(uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, int32_t height) @@ -204,114 +283,6 @@ static void copy_width64_msa(uint8_t *src, int32_t src_stride, } } -static const uint8_t mc_filt_mask_arr[16 * 3] = { - /* 8 width cases */ - 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, - /* 4 width cases */ - 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20, - /* 4 width cases */ - 8, 9, 9, 10, 10, 11, 11, 12, 24, 25, 25, 26, 26, 27, 27, 28 -}; - -#define FILT_8TAP_DPADD_S_H(vec0, vec1, vec2, vec3, \ - filt0, filt1, filt2, filt3) \ -( { \ - v8i16 tmp0, tmp1; \ - \ - tmp0 = __msa_dotp_s_h((v16i8) vec0, (v16i8) filt0); \ - tmp0 = __msa_dpadd_s_h(tmp0, (v16i8) vec1, (v16i8) filt1); \ - tmp1 = __msa_dotp_s_h((v16i8) vec2, (v16i8) filt2); \ - tmp1 = __msa_dpadd_s_h(tmp1, (v16i8) vec3, (v16i8) filt3); \ - tmp0 = __msa_adds_s_h(tmp0, tmp1); \ - \ - tmp0; \ -} ) - -#define HORIZ_8TAP_4WID_4VECS_FILT(src0, src1, src2, src3, \ - mask0, mask1, mask2, mask3, \ - filt0, filt1, filt2, filt3, \ - out0, out1) \ -{ \ - v16i8 vec0_m, vec1_m, vec2_m, vec3_m, vec4_m, vec5_m, vec6_m, vec7_m; \ - v8i16 res0_m, res1_m, res2_m, res3_m; \ - \ - VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0_m, vec1_m); \ - DOTP_SB2_SH(vec0_m, vec1_m, filt0, filt0, res0_m, res1_m); \ - VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec2_m, vec3_m); \ - DPADD_SB2_SH(vec2_m, vec3_m, filt1, filt1, res0_m, res1_m); \ - VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec4_m, vec5_m); \ - DOTP_SB2_SH(vec4_m, vec5_m, filt2, filt2, res2_m, res3_m); \ - VSHF_B2_SB(src0, src1, src2, src3, mask3, mask3, vec6_m, vec7_m); \ - DPADD_SB2_SH(vec6_m, vec7_m, filt3, filt3, res2_m, res3_m); \ - ADDS_SH2_SH(res0_m, res2_m, res1_m, res3_m, out0, out1); \ -} - -#define HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, \ - mask0, mask1, mask2, mask3, \ - filt0, filt1, filt2, filt3, \ - out0, out1, out2, out3) \ -{ \ - v16i8 vec0_m, vec1_m, vec2_m, vec3_m, vec4_m, vec5_m, vec6_m, vec7_m; \ - v8i16 res0_m, res1_m, res2_m, res3_m, res4_m, res5_m, res6_m, res7_m; \ - \ - VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0_m, vec1_m); \ - VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2_m, vec3_m); \ - DOTP_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt0, filt0, filt0, filt0, \ - res0_m, res1_m, res2_m, res3_m); \ - VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec0_m, vec1_m); \ - VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec2_m, vec3_m); \ - DOTP_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt2, filt2, filt2, filt2, \ - res4_m, res5_m, res6_m, res7_m); \ - VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec4_m, vec5_m); \ - VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec6_m, vec7_m); \ - DPADD_SB4_SH(vec4_m, vec5_m, vec6_m, vec7_m, filt1, filt1, filt1, filt1, \ - res0_m, res1_m, res2_m, res3_m); \ - VSHF_B2_SB(src0, src0, src1, src1, mask3, mask3, vec4_m, vec5_m); \ - VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec6_m, vec7_m); \ - DPADD_SB4_SH(vec4_m, vec5_m, vec6_m, vec7_m, filt3, filt3, filt3, filt3, \ - res4_m, res5_m, res6_m, res7_m); \ - ADDS_SH4_SH(res0_m, res4_m, res1_m, res5_m, res2_m, res6_m, res3_m, \ - res7_m, out0, out1, out2, out3); \ -} - -#define FILT_4TAP_DPADD_S_H(vec0, vec1, filt0, filt1) \ -( { \ - v8i16 tmp0; \ - \ - tmp0 = __msa_dotp_s_h((v16i8) vec0, (v16i8) filt0); \ - tmp0 = __msa_dpadd_s_h(tmp0, (v16i8) vec1, (v16i8) filt1); \ - \ - tmp0; \ -} ) - -#define HORIZ_4TAP_4WID_4VECS_FILT(src0, src1, src2, src3, \ - mask0, mask1, filt0, filt1, \ - out0, out1) \ -{ \ - v16i8 vec0_m, vec1_m, vec2_m, vec3_m; \ - \ - VSHF_B2_SB(src0, src1, src2, src3, mask0, mask0, vec0_m, vec1_m); \ - DOTP_SB2_SH(vec0_m, vec1_m, filt0, filt0, out0, out1); \ - VSHF_B2_SB(src0, src1, src2, src3, mask1, mask1, vec2_m, vec3_m); \ - DPADD_SB2_SH(vec2_m, vec3_m, filt1, filt1, out0, out1); \ -} - -#define HORIZ_4TAP_8WID_4VECS_FILT(src0, src1, src2, src3, \ - mask0, mask1, filt0, filt1, \ - out0, out1, out2, out3) \ -{ \ - v16i8 vec0_m, vec1_m, vec2_m, vec3_m; \ - \ - VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0_m, vec1_m); \ - VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2_m, vec3_m); \ - DOTP_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt0, filt0, filt0, filt0, \ - out0, out1, out2, out3); \ - VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0_m, vec1_m); \ - VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2_m, vec3_m); \ - DPADD_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt1, filt1, filt1, filt1, \ - out0, out1, out2, out3); \ -} - static void common_hz_8t_4x4_msa(uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter) @@ -320,7 +291,7 @@ static void common_hz_8t_4x4_msa(uint8_t *src, int32_t src_stride, v16i8 src0, src1, src2, src3, filt0, filt1, filt2, filt3; v8i16 filt, out0, out1; - mask0 = LD_UB(&mc_filt_mask_arr[16]); + mask0 = LD_UB(&ff_hevc_mask_arr[16]); src -= 3; /* rearranging filter */ @@ -350,7 +321,7 @@ static void common_hz_8t_4x8_msa(uint8_t *src, int32_t src_stride, v16u8 mask0, mask1, mask2, mask3, out; v8i16 filt, out0, out1, out2, out3; - mask0 = LD_UB(&mc_filt_mask_arr[16]); + mask0 = LD_UB(&ff_hevc_mask_arr[16]); src -= 3; /* rearranging filter */ @@ -387,7 +358,7 @@ static void common_hz_8t_4x16_msa(uint8_t *src, int32_t src_stride, v16i8 src0, src1, src2, src3, filt0, filt1, filt2, filt3; v8i16 filt, out0, out1, out2, out3; - mask0 = LD_UB(&mc_filt_mask_arr[16]); + mask0 = LD_UB(&ff_hevc_mask_arr[16]); src -= 3; /* rearranging filter */ @@ -450,47 +421,17 @@ static void common_hz_8t_4w_msa(uint8_t *src, int32_t src_stride, } } -static void common_hz_8t_8x4_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - const int8_t *filter) -{ - v16i8 src0, src1, src2, src3, filt0, filt1, filt2, filt3; - v16u8 mask0, mask1, mask2, mask3, tmp0, tmp1; - v8i16 filt, out0, out1, out2, out3; - - mask0 = LD_UB(&mc_filt_mask_arr[0]); - src -= 3; - - /* rearranging filter */ - filt = LD_SH(filter); - SPLATI_H4_SB(filt, 0, 1, 2, 3, filt0, filt1, filt2, filt3); - - mask1 = mask0 + 2; - mask2 = mask0 + 4; - mask3 = mask0 + 6; - - LD_SB4(src, src_stride, src0, src1, src2, src3); - XORI_B4_128_SB(src0, src1, src2, src3); - HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, mask2, - mask3, filt0, filt1, filt2, filt3, out0, out1, - out2, out3); - SRARI_H4_SH(out0, out1, out2, out3, 6); - SAT_SH4_SH(out0, out1, out2, out3, 7); - tmp0 = PCKEV_XORI128_UB(out0, out1); - tmp1 = PCKEV_XORI128_UB(out2, out3); - ST8x4_UB(tmp0, tmp1, dst, dst_stride); -} - -static void common_hz_8t_8x8mult_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - const int8_t *filter, int32_t height) +static void common_hz_8t_8w_msa(uint8_t *src, int32_t src_stride, + uint8_t *dst, int32_t dst_stride, + const int8_t *filter, int32_t height) { uint32_t loop_cnt; v16i8 src0, src1, src2, src3, filt0, filt1, filt2, filt3; v16u8 mask0, mask1, mask2, mask3, tmp0, tmp1; + v16i8 vec0_m, vec1_m, vec2_m, vec3_m, vec4_m, vec5_m, vec6_m, vec7_m; v8i16 filt, out0, out1, out2, out3; - mask0 = LD_UB(&mc_filt_mask_arr[0]); + mask0 = LD_UB(&ff_hevc_mask_arr[0]); src -= 3; /* rearranging filter */ @@ -505,9 +446,24 @@ static void common_hz_8t_8x8mult_msa(uint8_t *src, int32_t src_stride, LD_SB4(src, src_stride, src0, src1, src2, src3); XORI_B4_128_SB(src0, src1, src2, src3); src += (4 * src_stride); - HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, mask2, - mask3, filt0, filt1, filt2, filt3, out0, - out1, out2, out3); + + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0_m, vec1_m); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2_m, vec3_m); + DOTP_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt0, filt0, filt0, filt0, + out0, out1, out2, out3); + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec0_m, vec1_m); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec2_m, vec3_m); + DPADD_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt2, filt2, filt2, filt2, + out0, out1, out2, out3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec4_m, vec5_m); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec6_m, vec7_m); + DPADD_SB4_SH(vec4_m, vec5_m, vec6_m, vec7_m, filt1, filt1, filt1, filt1, + out0, out1, out2, out3); + VSHF_B2_SB(src0, src0, src1, src1, mask3, mask3, vec4_m, vec5_m); + VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec6_m, vec7_m); + DPADD_SB4_SH(vec4_m, vec5_m, vec6_m, vec7_m, filt3, filt3, filt3, filt3, + out0, out1, out2, out3); + SRARI_H4_SH(out0, out1, out2, out3, 6); SAT_SH4_SH(out0, out1, out2, out3, 7); tmp0 = PCKEV_XORI128_UB(out0, out1); @@ -517,36 +473,22 @@ static void common_hz_8t_8x8mult_msa(uint8_t *src, int32_t src_stride, } } -static void common_hz_8t_8w_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - const int8_t *filter, int32_t height) -{ - if (4 == height) { - common_hz_8t_8x4_msa(src, src_stride, dst, dst_stride, filter); - } else { - common_hz_8t_8x8mult_msa(src, src_stride, dst, dst_stride, filter, - height); - } -} - static void common_hz_8t_12w_msa(uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter, int32_t height) { - uint8_t *src1_ptr, *dst1; uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, filt0, filt1, filt2, filt3; - v8i16 filt, out0, out1, out2, out3; - v16u8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask00, tmp0, tmp1; - - mask00 = LD_UB(&mc_filt_mask_arr[0]); - mask0 = LD_UB(&mc_filt_mask_arr[16]); + v16u8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask00; + v16u8 tmp0, tmp1, tmp2; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 filt0, filt1, filt2, filt3; + v8i16 filt, out0, out1, out2, out3, out4, out5; - src1_ptr = src - 3; - dst1 = dst; + mask00 = LD_UB(&ff_hevc_mask_arr[0]); + mask0 = LD_UB(&ff_hevc_mask_arr[16]); - dst = dst1 + 8; - src = src1_ptr + 8; + src = src - 3; /* rearranging filter */ filt = LD_SH(filter); @@ -559,32 +501,53 @@ static void common_hz_8t_12w_msa(uint8_t *src, int32_t src_stride, mask5 = mask0 + 4; mask6 = mask0 + 6; - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = 4; loop_cnt--;) { /* 8 width */ - LD_SB4(src1_ptr, src_stride, src0, src1, src2, src3); + LD_SB4(src, src_stride, src0, src1, src2, src3); + /* 4 width */ + LD_SB4(src + 8, src_stride, src4, src5, src6, src7); + XORI_B4_128_SB(src0, src1, src2, src3); - src1_ptr += (4 * src_stride); - HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask00, mask1, mask2, - mask3, filt0, filt1, filt2, filt3, out0, - out1, out2, out3); + XORI_B4_128_SB(src4, src5, src6, src7); + src += (4 * src_stride); + + VSHF_B2_SB(src0, src0, src1, src1, mask00, mask00, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask00, mask00, vec2, vec3); + DOTP_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, out0, + out1, out2, out3); + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, out0, + out1, out2, out3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec4, vec5); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt1, filt1, filt1, filt1, out0, + out1, out2, out3); + VSHF_B2_SB(src0, src0, src1, src1, mask3, mask3, vec4, vec5); + VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt3, filt3, filt3, filt3, out0, + out1, out2, out3); + + /* 4 width */ + VSHF_B2_SB(src4, src5, src6, src7, mask0, mask0, vec0, vec1); + DOTP_SB2_SH(vec0, vec1, filt0, filt0, out4, out5); + VSHF_B2_SB(src4, src5, src6, src7, mask4, mask4, vec2, vec3); + DPADD_SB2_SH(vec2, vec3, filt1, filt1, out4, out5); + VSHF_B2_SB(src4, src5, src6, src7, mask5, mask5, vec4, vec5); + DPADD_SB2_SH(vec4, vec5, filt2, filt2, out4, out5); + VSHF_B2_SB(src4, src5, src6, src7, mask6, mask6, vec6, vec7); + DPADD_SB2_SH(vec6, vec7, filt3, filt3, out4, out5); + SRARI_H4_SH(out0, out1, out2, out3, 6); + SRARI_H2_SH(out4, out5, 6); SAT_SH4_SH(out0, out1, out2, out3, 7); + SAT_SH2_SH(out4, out5, 7); tmp0 = PCKEV_XORI128_UB(out0, out1); tmp1 = PCKEV_XORI128_UB(out2, out3); - ST8x4_UB(tmp0, tmp1, dst1, dst_stride); - dst1 += (4 * dst_stride); + tmp2 = PCKEV_XORI128_UB(out4, out5); - /* 4 width */ - LD_SB4(src, src_stride, src0, src1, src2, src3); - XORI_B4_128_SB(src0, src1, src2, src3); - src += (4 * src_stride); - HORIZ_8TAP_4WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask4, mask5, - mask6, filt0, filt1, filt2, filt3, out0, - out1); - SRARI_H2_SH(out0, out1, 6); - SAT_SH2_SH(out0, out1, 7); - tmp0 = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(tmp0, tmp0, 0, 1, 2, 3, dst, dst_stride); + ST8x4_UB(tmp0, tmp1, dst, dst_stride); + ST4x4_UB(tmp2, tmp2, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); } } @@ -594,11 +557,12 @@ static void common_hz_8t_16w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter, int32_t height) { uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, filt0, filt1, filt2, filt3; v16u8 mask0, mask1, mask2, mask3, out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7; + v16i8 filt0, filt1, filt2, filt3; v8i16 filt, out0, out1, out2, out3; - mask0 = LD_UB(&mc_filt_mask_arr[0]); + mask0 = LD_UB(&ff_hevc_mask_arr[0]); src -= 3; /* rearranging filter */ @@ -609,11 +573,17 @@ static void common_hz_8t_16w_msa(uint8_t *src, int32_t src_stride, mask2 = mask0 + 4; mask3 = mask0 + 6; - for (loop_cnt = (height >> 1); loop_cnt--;) { + for (loop_cnt = (height >> 2); loop_cnt--;) { LD_SB2(src, src_stride, src0, src2); LD_SB2(src + 8, src_stride, src1, src3); - XORI_B4_128_SB(src0, src1, src2, src3); src += (2 * src_stride); + + LD_SB2(src, src_stride, src4, src6); + LD_SB2(src + 8, src_stride, src5, src7); + src += (2 * src_stride); + + XORI_B4_128_SB(src0, src1, src2, src3); + XORI_B4_128_SB(src4, src5, src6, src7); HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, mask2, mask3, filt0, filt1, filt2, filt3, out0, out1, out2, out3); @@ -625,6 +595,18 @@ static void common_hz_8t_16w_msa(uint8_t *src, int32_t src_stride, out = PCKEV_XORI128_UB(out2, out3); ST_UB(out, dst); dst += dst_stride; + + HORIZ_8TAP_8WID_4VECS_FILT(src4, src5, src6, src7, mask0, mask1, mask2, + mask3, filt0, filt1, filt2, filt3, out0, + out1, out2, out3); + SRARI_H4_SH(out0, out1, out2, out3, 6); + SAT_SH4_SH(out0, out1, out2, out3, 7); + out = PCKEV_XORI128_UB(out0, out1); + ST_UB(out, dst); + dst += dst_stride; + out = PCKEV_XORI128_UB(out2, out3); + ST_UB(out, dst); + dst += dst_stride; } } @@ -637,10 +619,9 @@ static void common_hz_8t_24w_msa(uint8_t *src, int32_t src_stride, v16u8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask7, out; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; v16i8 vec11; - v8i16 out0, out1, out2, out3, out4, out5, out6, out7, out8, out9, out10; - v8i16 out11, filt; + v8i16 out0, out1, out2, out3, out8, out9, filt; - mask0 = LD_UB(&mc_filt_mask_arr[0]); + mask0 = LD_UB(&ff_hevc_mask_arr[0]); src -= 3; /* rearranging filter */ @@ -655,7 +636,7 @@ static void common_hz_8t_24w_msa(uint8_t *src, int32_t src_stride, mask6 = mask0 + 12; mask7 = mask0 + 14; - for (loop_cnt = (height >> 1); loop_cnt--;) { + for (loop_cnt = 16; loop_cnt--;) { LD_SB2(src, src_stride, src0, src2); LD_SB2(src + 16, src_stride, src1, src3); XORI_B4_128_SB(src0, src1, src2, src3); @@ -669,9 +650,9 @@ static void common_hz_8t_24w_msa(uint8_t *src, int32_t src_stride, VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec0, vec8); VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec2, vec9); VSHF_B2_SB(src0, src1, src2, src3, mask6, mask6, vec1, vec3); - DOTP_SB4_SH(vec0, vec8, vec2, vec9, filt2, filt2, filt2, filt2, out4, - out10, out6, out11); - DOTP_SB2_SH(vec1, vec3, filt2, filt2, out5, out7); + DPADD_SB4_SH(vec0, vec8, vec2, vec9, filt2, filt2, filt2, filt2, + out0, out8, out2, out9); + DPADD_SB2_SH(vec1, vec3, filt2, filt2, out1, out3); VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec4, vec10); VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec6, vec11); VSHF_B2_SB(src0, src1, src2, src3, mask5, mask5, vec5, vec7); @@ -682,11 +663,8 @@ static void common_hz_8t_24w_msa(uint8_t *src, int32_t src_stride, VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec6, vec11); VSHF_B2_SB(src0, src1, src2, src3, mask7, mask7, vec5, vec7); DPADD_SB4_SH(vec4, vec10, vec6, vec11, filt3, filt3, filt3, filt3, - out4, out10, out6, out11); - DPADD_SB2_SH(vec5, vec7, filt3, filt3, out5, out7); - ADDS_SH4_SH(out0, out4, out8, out10, out2, out6, out9, out11, out0, - out8, out2, out9); - ADDS_SH2_SH(out1, out5, out3, out7, out1, out3); + out0, out8, out2, out9); + DPADD_SB2_SH(vec5, vec7, filt3, filt3, out1, out3); SRARI_H4_SH(out0, out8, out2, out9, 6); SRARI_H2_SH(out1, out3, 6); SAT_SH4_SH(out0, out8, out2, out9, 7); @@ -707,11 +685,12 @@ static void common_hz_8t_32w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter, int32_t height) { uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, filt0, filt1, filt2, filt3; v16u8 mask0, mask1, mask2, mask3, out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7; + v16i8 filt0, filt1, filt2, filt3; v8i16 filt, out0, out1, out2, out3; - mask0 = LD_UB(&mc_filt_mask_arr[0]); + mask0 = LD_UB(&ff_hevc_mask_arr[0]); src -= 3; /* rearranging filter */ @@ -724,31 +703,32 @@ static void common_hz_8t_32w_msa(uint8_t *src, int32_t src_stride, for (loop_cnt = (height >> 1); loop_cnt--;) { src0 = LD_SB(src); + src1 = LD_SB(src + 8); src2 = LD_SB(src + 16); src3 = LD_SB(src + 24); - src1 = __msa_sldi_b(src2, src0, 8); src += src_stride; XORI_B4_128_SB(src0, src1, src2, src3); + + src4 = LD_SB(src); + src5 = LD_SB(src + 8); + src6 = LD_SB(src + 16); + src7 = LD_SB(src + 24); + src += src_stride; + XORI_B4_128_SB(src4, src5, src6, src7); + HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, mask2, mask3, filt0, filt1, filt2, filt3, out0, out1, out2, out3); SRARI_H4_SH(out0, out1, out2, out3, 6); SAT_SH4_SH(out0, out1, out2, out3, 7); - src0 = LD_SB(src); - src2 = LD_SB(src + 16); - src3 = LD_SB(src + 24); - src1 = __msa_sldi_b(src2, src0, 8); - src += src_stride; - out = PCKEV_XORI128_UB(out0, out1); ST_UB(out, dst); out = PCKEV_XORI128_UB(out2, out3); ST_UB(out, dst + 16); dst += dst_stride; - XORI_B4_128_SB(src0, src1, src2, src3); - HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, mask2, + HORIZ_8TAP_8WID_4VECS_FILT(src4, src5, src6, src7, mask0, mask1, mask2, mask3, filt0, filt1, filt2, filt3, out0, out1, out2, out3); SRARI_H4_SH(out0, out1, out2, out3, 6); @@ -767,10 +747,11 @@ static void common_hz_8t_48w_msa(uint8_t *src, int32_t src_stride, { uint32_t loop_cnt; v16i8 src0, src1, src2, src3, filt0, filt1, filt2, filt3, vec0, vec1, vec2; + v16i8 src4; v16u8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask7, out; - v8i16 filt, out0, out1, out2, out3, out4, out5, out6; + v8i16 filt, out0, out1, out2, out3; - mask0 = LD_UB(&mc_filt_mask_arr[0]); + mask0 = LD_UB(&ff_hevc_mask_arr[0]); src -= 3; /* rearranging filter */ @@ -785,11 +766,17 @@ static void common_hz_8t_48w_msa(uint8_t *src, int32_t src_stride, mask6 = mask0 + 12; mask7 = mask0 + 14; - for (loop_cnt = height; loop_cnt--;) { - LD_SB3(src, 16, src0, src2, src3); - src1 = __msa_sldi_b(src2, src0, 8); + for (loop_cnt = 64; loop_cnt--;) { + src0 = LD_SB(src); + src1 = LD_SB(src + 8); + src2 = LD_SB(src + 16); + src3 = LD_SB(src + 32); + src4 = LD_SB(src + 40); + src += src_stride; XORI_B4_128_SB(src0, src1, src2, src3); + src4 = (v16i8) __msa_xori_b((v16u8) src4, 128); + VSHF_B3_SB(src0, src0, src1, src1, src2, src2, mask0, mask0, mask0, vec0, vec1, vec2); DOTP_SB3_SH(vec0, vec1, vec2, filt0, filt0, filt0, out0, out1, out2); @@ -799,45 +786,42 @@ static void common_hz_8t_48w_msa(uint8_t *src, int32_t src_stride, out2 = __msa_dpadd_s_h(out2, vec2, filt1); VSHF_B3_SB(src0, src0, src1, src1, src2, src2, mask2, mask2, mask2, vec0, vec1, vec2); - DOTP_SB3_SH(vec0, vec1, vec2, filt2, filt2, filt2, out3, out4, out5); + DPADD_SB2_SH(vec0, vec1, filt2, filt2, out0, out1); + out2 = __msa_dpadd_s_h(out2, vec2, filt2); + VSHF_B3_SB(src0, src0, src1, src1, src2, src2, mask3, mask3, mask3, vec0, vec1, vec2); - DPADD_SB2_SH(vec0, vec1, filt3, filt3, out3, out4); - out5 = __msa_dpadd_s_h(out5, vec2, filt3); - ADDS_SH2_SH(out0, out3, out1, out4, out0, out1); - out2 = __msa_adds_s_h(out2, out5); + DPADD_SB2_SH(vec0, vec1, filt3, filt3, out0, out1); + out2 = __msa_dpadd_s_h(out2, vec2, filt3); + SRARI_H2_SH(out0, out1, 6); - out6 = __msa_srari_h(out2, 6); - SAT_SH3_SH(out0, out1, out6, 7); + out3 = __msa_srari_h(out2, 6); + SAT_SH3_SH(out0, out1, out3, 7); out = PCKEV_XORI128_UB(out0, out1); ST_UB(out, dst); - src1 = LD_SB(src + 40); - src += src_stride; - src1 = (v16i8) __msa_xori_b((v16u8) src1, 128); - - VSHF_B3_SB(src2, src3, src3, src3, src1, src1, mask4, mask0, mask0, + VSHF_B3_SB(src2, src3, src3, src3, src4, src4, mask4, mask0, mask0, vec0, vec1, vec2); DOTP_SB3_SH(vec0, vec1, vec2, filt0, filt0, filt0, out0, out1, out2); - VSHF_B3_SB(src2, src3, src3, src3, src1, src1, mask5, mask1, mask1, + VSHF_B3_SB(src2, src3, src3, src3, src4, src4, mask5, mask1, mask1, vec0, vec1, vec2); DPADD_SB2_SH(vec0, vec1, filt1, filt1, out0, out1); out2 = __msa_dpadd_s_h(out2, vec2, filt1); - VSHF_B3_SB(src2, src3, src3, src3, src1, src1, mask6, mask2, mask2, + VSHF_B3_SB(src2, src3, src3, src3, src4, src4, mask6, mask2, mask2, vec0, vec1, vec2); - DOTP_SB3_SH(vec0, vec1, vec2, filt2, filt2, filt2, out3, out4, out5); - VSHF_B3_SB(src2, src3, src3, src3, src1, src1, mask7, mask3, mask3, + DPADD_SB2_SH(vec0, vec1, filt2, filt2, out0, out1); + out2 = __msa_dpadd_s_h(out2, vec2, filt2); + VSHF_B3_SB(src2, src3, src3, src3, src4, src4, mask7, mask3, mask3, vec0, vec1, vec2); - DPADD_SB2_SH(vec0, vec1, filt3, filt3, out3, out4); - out5 = __msa_dpadd_s_h(out5, vec2, filt3); - ADDS_SH2_SH(out0, out3, out1, out4, out3, out4); - out5 = __msa_adds_s_h(out2, out5); - SRARI_H2_SH(out3, out4, 6); - out5 = __msa_srari_h(out5, 6); - SAT_SH3_SH(out3, out4, out5, 7); - out = PCKEV_XORI128_UB(out6, out3); + DPADD_SB2_SH(vec0, vec1, filt3, filt3, out0, out1); + out2 = __msa_dpadd_s_h(out2, vec2, filt3); + + SRARI_H2_SH(out0, out1, 6); + out2 = __msa_srari_h(out2, 6); + SAT_SH3_SH(out0, out1, out2, 7); + out = PCKEV_XORI128_UB(out3, out0); ST_UB(out, dst + 16); - out = PCKEV_XORI128_UB(out4, out5); + out = PCKEV_XORI128_UB(out1, out2); ST_UB(out, dst + 32); dst += dst_stride; } @@ -848,11 +832,13 @@ static void common_hz_8t_64w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter, int32_t height) { int32_t loop_cnt; - v16i8 src0, src1, src2, src3, filt0, filt1, filt2, filt3; v16u8 mask0, mask1, mask2, mask3, out; - v8i16 filt, out0, out1, out2, out3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 filt0, filt1, filt2, filt3; + v8i16 res0, res1, res2, res3, filt; - mask0 = LD_UB(&mc_filt_mask_arr[0]); + mask0 = LD_UB(&ff_hevc_mask_arr[0]); src -= 3; /* rearranging filter */ @@ -864,37 +850,57 @@ static void common_hz_8t_64w_msa(uint8_t *src, int32_t src_stride, mask3 = mask0 + 6; for (loop_cnt = height; loop_cnt--;) { - src0 = LD_SB(src); - src2 = LD_SB(src + 16); - src3 = LD_SB(src + 24); - src1 = __msa_sldi_b(src2, src0, 8); + LD_SB8(src, 8, src0, src1, src2, src3, src4, src5, src6, src7); + src += src_stride; - XORI_B4_128_SB(src0, src1, src2, src3); - HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, - mask2, mask3, filt0, filt1, filt2, filt3, - out0, out1, out2, out3); - SRARI_H4_SH(out0, out1, out2, out3, 6); - SAT_SH4_SH(out0, out1, out2, out3, 7); - out = PCKEV_XORI128_UB(out0, out1); + XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); + + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + DOTP_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, res0, + res1, res2, res3); + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, res0, + res1, res2, res3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec4, vec5); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt1, filt1, filt1, filt1, res0, + res1, res2, res3); + VSHF_B2_SB(src0, src0, src1, src1, mask3, mask3, vec4, vec5); + VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt3, filt3, filt3, filt3, res0, + res1, res2, res3); + + SRARI_H4_SH(res0, res1, res2, res3, 6); + SAT_SH4_SH(res0, res1, res2, res3, 7); + out = PCKEV_XORI128_UB(res0, res1); ST_UB(out, dst); - out = PCKEV_XORI128_UB(out2, out3); + out = PCKEV_XORI128_UB(res2, res3); ST_UB(out, dst + 16); - src0 = LD_SB(src + 32); - src2 = LD_SB(src + 48); - src3 = LD_SB(src + 56); - src1 = __msa_sldi_b(src2, src0, 8); - src += src_stride; - - XORI_B4_128_SB(src0, src1, src2, src3); - HORIZ_8TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, - mask2, mask3, filt0, filt1, filt2, filt3, - out0, out1, out2, out3); - SRARI_H4_SH(out0, out1, out2, out3, 6); - SAT_SH4_SH(out0, out1, out2, out3, 7); - out = PCKEV_XORI128_UB(out0, out1); + VSHF_B2_SB(src4, src4, src5, src5, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src6, src6, src7, src7, mask0, mask0, vec2, vec3); + DOTP_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, res0, + res1, res2, res3); + VSHF_B2_SB(src4, src4, src5, src5, mask2, mask2, vec0, vec1); + VSHF_B2_SB(src6, src6, src7, src7, mask2, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, res0, + res1, res2, res3); + VSHF_B2_SB(src4, src4, src5, src5, mask1, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src7, src7, mask1, mask1, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt1, filt1, filt1, filt1, res0, + res1, res2, res3); + VSHF_B2_SB(src4, src4, src5, src5, mask3, mask3, vec4, vec5); + VSHF_B2_SB(src6, src6, src7, src7, mask3, mask3, vec6, vec7); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt3, filt3, filt3, filt3, res0, + res1, res2, res3); + + SRARI_H4_SH(res0, res1, res2, res3, 6); + SAT_SH4_SH(res0, res1, res2, res3, 7); + out = PCKEV_XORI128_UB(res0, res1); ST_UB(out, dst + 32); - out = PCKEV_XORI128_UB(out2, out3); + out = PCKEV_XORI128_UB(res2, res3); ST_UB(out, dst + 48); dst += dst_stride; } @@ -905,12 +911,14 @@ static void common_vt_8t_4w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter, int32_t height) { uint32_t loop_cnt; + v16u8 out0, out1; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 src11, src12, src13, src14; v16i8 src10_r, src32_r, src54_r, src76_r, src98_r, src21_r, src43_r; v16i8 src65_r, src87_r, src109_r, src2110, src4332, src6554, src8776; + v16i8 src1110_r, src1211_r, src1312_r, src1413_r, src12111110, src14131312; v16i8 src10998, filt0, filt1, filt2, filt3; - v16u8 out; - v8i16 filt, out10, out32; + v8i16 filt, out10, out32, out54, out76; src -= (3 * src_stride); @@ -927,28 +935,45 @@ static void common_vt_8t_4w_msa(uint8_t *src, int32_t src_stride, src4332, src6554); XORI_B3_128_SB(src2110, src4332, src6554); - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = (height >> 3); loop_cnt--;) { LD_SB4(src, src_stride, src7, src8, src9, src10); src += (4 * src_stride); + LD_SB4(src, src_stride, src11, src12, src13, src14); + src += (4 * src_stride); ILVR_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, src76_r, src87_r, src98_r, src109_r); + ILVR_B4_SB(src11, src10, src12, src11, src13, src12, src14, src13, + src1110_r, src1211_r, src1312_r, src1413_r); ILVR_D2_SB(src87_r, src76_r, src109_r, src98_r, src8776, src10998); + ILVR_D2_SB(src1211_r, src1110_r, src1413_r, src1312_r, + src12111110, src14131312); XORI_B2_128_SB(src8776, src10998); - out10 = FILT_8TAP_DPADD_S_H(src2110, src4332, src6554, src8776, filt0, - filt1, filt2, filt3); - out32 = FILT_8TAP_DPADD_S_H(src4332, src6554, src8776, src10998, filt0, - filt1, filt2, filt3); + XORI_B2_128_SB(src12111110, src14131312); + + DOTP_SB2_SH(src2110, src4332, filt0, filt0, out10, out32); + DOTP_SB2_SH(src6554, src8776, filt0, filt0, out54, out76); + DPADD_SB2_SH(src4332, src6554, filt1, filt1, out10, out32); + DPADD_SB2_SH(src8776, src10998, filt1, filt1, out54, out76); + DPADD_SB2_SH(src6554, src8776, filt2, filt2, out10, out32); + DPADD_SB2_SH(src10998, src12111110, filt2, filt2, out54, out76); + DPADD_SB2_SH(src8776, src10998, filt3, filt3, out10, out32); + DPADD_SB2_SH(src12111110, src14131312, filt3, filt3, out54, out76); SRARI_H2_SH(out10, out32, 6); + SRARI_H2_SH(out54, out76, 6); SAT_SH2_SH(out10, out32, 7); - out = PCKEV_XORI128_UB(out10, out32); - ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + SAT_SH2_SH(out54, out76, 7); + out0 = PCKEV_XORI128_UB(out10, out32); + out1 = PCKEV_XORI128_UB(out54, out76); + ST4x4_UB(out0, out0, 0, 1, 2, 3, dst, dst_stride); + dst += (4 * dst_stride); + ST4x4_UB(out1, out1, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); - src2110 = src6554; - src4332 = src8776; - src6554 = src10998; - src6 = src10; + src2110 = src10998; + src4332 = src12111110; + src6554 = src14131312; + src6 = src14; } } @@ -982,14 +1007,14 @@ static void common_vt_8t_8w_msa(uint8_t *src, int32_t src_stride, ILVR_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, src76_r, src87_r, src98_r, src109_r); - out0_r = FILT_8TAP_DPADD_S_H(src10_r, src32_r, src54_r, src76_r, filt0, - filt1, filt2, filt3); - out1_r = FILT_8TAP_DPADD_S_H(src21_r, src43_r, src65_r, src87_r, filt0, - filt1, filt2, filt3); - out2_r = FILT_8TAP_DPADD_S_H(src32_r, src54_r, src76_r, src98_r, filt0, - filt1, filt2, filt3); - out3_r = FILT_8TAP_DPADD_S_H(src43_r, src65_r, src87_r, src109_r, filt0, - filt1, filt2, filt3); + DOTP_SB4_SH(src10_r, src21_r, src32_r, src43_r, filt0, filt0, filt0, + filt0, out0_r, out1_r, out2_r, out3_r); + DPADD_SB4_SH(src32_r, src43_r, src54_r, src65_r, filt1, filt1, filt1, + filt1, out0_r, out1_r, out2_r, out3_r); + DPADD_SB4_SH(src54_r, src65_r, src76_r, src87_r, filt2, filt2, filt2, + filt2, out0_r, out1_r, out2_r, out3_r); + DPADD_SB4_SH(src76_r, src87_r, src98_r, src109_r, filt3, filt3, filt3, + filt3, out0_r, out1_r, out2_r, out3_r); SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); tmp0 = PCKEV_XORI128_UB(out0_r, out1_r); @@ -1011,61 +1036,81 @@ static void common_vt_8t_12w_msa(uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter, int32_t height) { - int32_t loop_cnt; + uint32_t loop_cnt; uint32_t out2, out3; uint64_t out0, out1; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, res0, res1; - v16i8 res2, vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; - v8i16 vec01, vec23, vec45, vec67, tmp0, tmp1, tmp2; - v8i16 filt, filt0, filt1, filt2, filt3; - v4i32 mask = { 2, 6, 2, 6 }; + v16u8 tmp0, tmp1, tmp2, tmp3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 filt0, filt1, filt2, filt3; + v16i8 src10_r, src32_r, src54_r, src76_r, src98_r, src21_r, src43_r; + v16i8 src65_r, src87_r, src109_r, src10_l, src32_l, src54_l, src76_l; + v16i8 src98_l, src21_l, src43_l, src65_l, src87_l, src109_l; + v8i16 filt, out0_r, out1_r, out2_r, out3_r, out0_l, out1_l, out2_l, out3_l; src -= (3 * src_stride); - /* rearranging filter_y */ filt = LD_SH(filter); - SPLATI_H4_SH(filt, 0, 1, 2, 3, filt0, filt1, filt2, filt3); + SPLATI_H4_SB(filt, 0, 1, 2, 3, filt0, filt1, filt2, filt3); LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); src += (7 * src_stride); XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); - /* 4 width */ - VSHF_W2_SB(src0, src1, src1, src2, mask, mask, vec0, vec1); - VSHF_W2_SB(src2, src3, src3, src4, mask, mask, vec2, vec3); - VSHF_W2_SB(src4, src5, src5, src6, mask, mask, vec4, vec5); - - for (loop_cnt = (height >> 1); loop_cnt--;) { - LD_SB2(src, src_stride, src7, src8); - XORI_B2_128_SB(src7, src8); - src += (2 * src_stride); + ILVR_B4_SB(src1, src0, src3, src2, src5, src4, src2, src1, src10_r, src32_r, + src54_r, src21_r); + ILVR_B2_SB(src4, src3, src6, src5, src43_r, src65_r); + ILVL_B4_SB(src1, src0, src3, src2, src5, src4, src2, src1, src10_l, src32_l, + src54_l, src21_l); + ILVL_B2_SB(src4, src3, src6, src5, src43_l, src65_l); - ILVR_B4_SH(src1, src0, src3, src2, src5, src4, src7, src6, - vec01, vec23, vec45, vec67); - tmp0 = FILT_8TAP_DPADD_S_H(vec01, vec23, vec45, vec67, filt0, filt1, - filt2, filt3); - ILVR_B4_SH(src2, src1, src4, src3, src6, src5, src8, src7, vec01, vec23, - vec45, vec67); - tmp1 = FILT_8TAP_DPADD_S_H(vec01, vec23, vec45, vec67, filt0, filt1, - filt2, filt3); + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src, src_stride, src7, src8, src9, src10); + XORI_B4_128_SB(src7, src8, src9, src10); + src += (4 * src_stride); - /* 4 width */ - VSHF_W2_SB(src6, src7, src7, src8, mask, mask, vec6, vec7); - ILVR_B4_SH(vec1, vec0, vec3, vec2, vec5, vec4, vec7, vec6, vec01, vec23, - vec45, vec67); - tmp2 = FILT_8TAP_DPADD_S_H(vec01, vec23, vec45, vec67, filt0, filt1, - filt2, filt3); - SRARI_H2_SH(tmp0, tmp1, 6); - tmp2 = __msa_srari_h(tmp2, 6); - SAT_SH3_SH(tmp0, tmp1, tmp2, 7); - PCKEV_B3_SB(tmp0, tmp0, tmp1, tmp1, tmp2, tmp2, res0, res1, res2); - XORI_B3_128_SB(res0, res1, res2); + ILVR_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, src76_r, + src87_r, src98_r, src109_r); + ILVL_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, src76_l, + src87_l, src98_l, src109_l); + out0_r = HEVC_FILT_8TAP_SH(src10_r, src32_r, src54_r, src76_r, filt0, + filt1, filt2, filt3); + out1_r = HEVC_FILT_8TAP_SH(src21_r, src43_r, src65_r, src87_r, filt0, + filt1, filt2, filt3); + out2_r = HEVC_FILT_8TAP_SH(src32_r, src54_r, src76_r, src98_r, filt0, + filt1, filt2, filt3); + out3_r = HEVC_FILT_8TAP_SH(src43_r, src65_r, src87_r, src109_r, filt0, + filt1, filt2, filt3); + out0_l = HEVC_FILT_8TAP_SH(src10_l, src32_l, src54_l, src76_l, filt0, + filt1, filt2, filt3); + out1_l = HEVC_FILT_8TAP_SH(src21_l, src43_l, src65_l, src87_l, filt0, + filt1, filt2, filt3); + out2_l = HEVC_FILT_8TAP_SH(src32_l, src54_l, src76_l, src98_l, filt0, + filt1, filt2, filt3); + out3_l = HEVC_FILT_8TAP_SH(src43_l, src65_l, src87_l, src109_l, filt0, + filt1, filt2, filt3); + SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); + SRARI_H4_SH(out0_l, out1_l, out2_l, out3_l, 6); + SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); + SAT_SH4_SH(out0_l, out1_l, out2_l, out3_l, 7); + PCKEV_B4_UB(out0_l, out0_r, out1_l, out1_r, out2_l, out2_r, out3_l, + out3_r, tmp0, tmp1, tmp2, tmp3); + XORI_B4_128_UB(tmp0, tmp1, tmp2, tmp3); - out0 = __msa_copy_u_d((v2i64) res0, 0); - out1 = __msa_copy_u_d((v2i64) res1, 0); - out2 = __msa_copy_u_w((v4i32) res2, 0); - out3 = __msa_copy_u_w((v4i32) res2, 1); + out0 = __msa_copy_u_d((v2i64) tmp0, 0); + out1 = __msa_copy_u_d((v2i64) tmp1, 0); + out2 = __msa_copy_u_w((v4i32) tmp0, 2); + out3 = __msa_copy_u_w((v4i32) tmp1, 2); + SD(out0, dst); + SW(out2, (dst + 8)); + dst += dst_stride; + SD(out1, dst); + SW(out3, (dst + 8)); + dst += dst_stride; + out0 = __msa_copy_u_d((v2i64) tmp2, 0); + out1 = __msa_copy_u_d((v2i64) tmp3, 0); + out2 = __msa_copy_u_w((v4i32) tmp2, 2); + out3 = __msa_copy_u_w((v4i32) tmp3, 2); SD(out0, dst); SW(out2, (dst + 8)); dst += dst_stride; @@ -1073,19 +1118,19 @@ static void common_vt_8t_12w_msa(uint8_t *src, int32_t src_stride, SW(out3, (dst + 8)); dst += dst_stride; - src0 = src2; - src1 = src3; - src2 = src4; - src3 = src5; - src4 = src6; - src5 = src7; - src6 = src8; - vec0 = vec2; - vec1 = vec3; - vec2 = vec4; - vec3 = vec5; - vec4 = vec6; - vec5 = vec7; + src10_r = src54_r; + src32_r = src76_r; + src54_r = src98_r; + src21_r = src65_r; + src43_r = src87_r; + src65_r = src109_r; + src10_l = src54_l; + src32_l = src76_l; + src54_l = src98_l; + src21_l = src65_l; + src43_l = src87_l; + src65_l = src109_l; + src6 = src10; } } @@ -1126,22 +1171,22 @@ static void common_vt_8t_16w_msa(uint8_t *src, int32_t src_stride, src87_r, src98_r, src109_r); ILVL_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, src76_l, src87_l, src98_l, src109_l); - out0_r = FILT_8TAP_DPADD_S_H(src10_r, src32_r, src54_r, src76_r, filt0, - filt1, filt2, filt3); - out1_r = FILT_8TAP_DPADD_S_H(src21_r, src43_r, src65_r, src87_r, filt0, - filt1, filt2, filt3); - out2_r = FILT_8TAP_DPADD_S_H(src32_r, src54_r, src76_r, src98_r, filt0, - filt1, filt2, filt3); - out3_r = FILT_8TAP_DPADD_S_H(src43_r, src65_r, src87_r, src109_r, filt0, - filt1, filt2, filt3); - out0_l = FILT_8TAP_DPADD_S_H(src10_l, src32_l, src54_l, src76_l, filt0, - filt1, filt2, filt3); - out1_l = FILT_8TAP_DPADD_S_H(src21_l, src43_l, src65_l, src87_l, filt0, - filt1, filt2, filt3); - out2_l = FILT_8TAP_DPADD_S_H(src32_l, src54_l, src76_l, src98_l, filt0, - filt1, filt2, filt3); - out3_l = FILT_8TAP_DPADD_S_H(src43_l, src65_l, src87_l, src109_l, filt0, - filt1, filt2, filt3); + out0_r = HEVC_FILT_8TAP_SH(src10_r, src32_r, src54_r, src76_r, filt0, + filt1, filt2, filt3); + out1_r = HEVC_FILT_8TAP_SH(src21_r, src43_r, src65_r, src87_r, filt0, + filt1, filt2, filt3); + out2_r = HEVC_FILT_8TAP_SH(src32_r, src54_r, src76_r, src98_r, filt0, + filt1, filt2, filt3); + out3_r = HEVC_FILT_8TAP_SH(src43_r, src65_r, src87_r, src109_r, filt0, + filt1, filt2, filt3); + out0_l = HEVC_FILT_8TAP_SH(src10_l, src32_l, src54_l, src76_l, filt0, + filt1, filt2, filt3); + out1_l = HEVC_FILT_8TAP_SH(src21_l, src43_l, src65_l, src87_l, filt0, + filt1, filt2, filt3); + out2_l = HEVC_FILT_8TAP_SH(src32_l, src54_l, src76_l, src98_l, filt0, + filt1, filt2, filt3); + out3_l = HEVC_FILT_8TAP_SH(src43_l, src65_l, src87_l, src109_l, filt0, + filt1, filt2, filt3); SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); SRARI_H4_SH(out0_l, out1_l, out2_l, out3_l, 6); SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); @@ -1211,22 +1256,22 @@ static void common_vt_8t_16w_mult_msa(uint8_t *src, int32_t src_stride, src87_r, src98_r, src109_r); ILVL_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, src76_l, src87_l, src98_l, src109_l); - out0_r = FILT_8TAP_DPADD_S_H(src10_r, src32_r, src54_r, src76_r, - filt0, filt1, filt2, filt3); - out1_r = FILT_8TAP_DPADD_S_H(src21_r, src43_r, src65_r, src87_r, - filt0, filt1, filt2, filt3); - out2_r = FILT_8TAP_DPADD_S_H(src32_r, src54_r, src76_r, src98_r, - filt0, filt1, filt2, filt3); - out3_r = FILT_8TAP_DPADD_S_H(src43_r, src65_r, src87_r, src109_r, - filt0, filt1, filt2, filt3); - out0_l = FILT_8TAP_DPADD_S_H(src10_l, src32_l, src54_l, src76_l, - filt0, filt1, filt2, filt3); - out1_l = FILT_8TAP_DPADD_S_H(src21_l, src43_l, src65_l, src87_l, - filt0, filt1, filt2, filt3); - out2_l = FILT_8TAP_DPADD_S_H(src32_l, src54_l, src76_l, src98_l, - filt0, filt1, filt2, filt3); - out3_l = FILT_8TAP_DPADD_S_H(src43_l, src65_l, src87_l, src109_l, - filt0, filt1, filt2, filt3); + out0_r = HEVC_FILT_8TAP_SH(src10_r, src32_r, src54_r, src76_r, + filt0, filt1, filt2, filt3); + out1_r = HEVC_FILT_8TAP_SH(src21_r, src43_r, src65_r, src87_r, + filt0, filt1, filt2, filt3); + out2_r = HEVC_FILT_8TAP_SH(src32_r, src54_r, src76_r, src98_r, + filt0, filt1, filt2, filt3); + out3_r = HEVC_FILT_8TAP_SH(src43_r, src65_r, src87_r, src109_r, + filt0, filt1, filt2, filt3); + out0_l = HEVC_FILT_8TAP_SH(src10_l, src32_l, src54_l, src76_l, + filt0, filt1, filt2, filt3); + out1_l = HEVC_FILT_8TAP_SH(src21_l, src43_l, src65_l, src87_l, + filt0, filt1, filt2, filt3); + out2_l = HEVC_FILT_8TAP_SH(src32_l, src54_l, src76_l, src98_l, + filt0, filt1, filt2, filt3); + out3_l = HEVC_FILT_8TAP_SH(src43_l, src65_l, src87_l, src109_l, + filt0, filt1, filt2, filt3); SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); SRARI_H4_SH(out0_l, out1_l, out2_l, out3_l, 6); SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); @@ -1301,37 +1346,34 @@ static void hevc_hv_uni_8t_4w_msa(uint8_t *src, int32_t height) { uint32_t loop_cnt; + v16u8 out0, out1; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 src9, src10, src11, src12, src13, src14; v8i16 filt0, filt1, filt2, filt3; - v4i32 filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 filt_h0, filt_h1, filt_h2, filt_h3; v16i8 mask1, mask2, mask3; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; - v8i16 dst30, dst41, dst52, dst63, dst66, dst87; - v4i32 dst0_r, dst1_r; - v8i16 dst10_r, dst32_r, dst54_r, dst76_r; - v8i16 dst21_r, dst43_r, dst65_r, dst87_r; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; - v8i16 mask4 = { 0, 4, 1, 5, 2, 6, 3, 7 }; + v8i16 dst30, dst41, dst52, dst63, dst66, dst117, dst128, dst139, dst1410; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r, dst98_r, dst1110_r, dst1312_r; + v8i16 dst21_r, dst43_r, dst65_r, dst87_r, dst109_r, dst1211_r, dst1413_r; + v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r, dst6_r, dst7_r; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); src -= ((3 * src_stride) + 3); filter_vec = LD_SH(filter_x); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W4_SW(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); mask1 = mask0 + 2; mask2 = mask0 + 4; mask3 = mask0 + 6; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); src += (7 * src_stride); XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); @@ -1343,61 +1385,91 @@ static void hevc_hv_uni_8t_4w_msa(uint8_t *src, VSHF_B4_SB(src3, src6, mask0, mask1, mask2, mask3, vec12, vec13, vec14, vec15); - dst30 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst30, dst30, dst30, dst30); - dst41 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst41, dst41, dst41, dst41); - dst52 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst52, dst52, dst52, dst52); - dst63 = const_vec; - DPADD_SB4_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, filt3, - dst63, dst63, dst63, dst63); - - ILVR_H3_SH(dst41, dst30, dst52, dst41, dst63, dst52, - dst10_r, dst21_r, dst32_r); - dst43_r = __msa_ilvl_h(dst41, dst30); - dst54_r = __msa_ilvl_h(dst52, dst41); - dst65_r = __msa_ilvl_h(dst63, dst52); + dst30 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst41 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst52 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst63 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, + filt3); + + ILVRL_H2_SH(dst41, dst30, dst10_r, dst43_r); + ILVRL_H2_SH(dst52, dst41, dst21_r, dst54_r); + ILVRL_H2_SH(dst63, dst52, dst32_r, dst65_r); + dst66 = (v8i16) __msa_splati_d((v2i64) dst63, 1); - for (loop_cnt = height >> 1; loop_cnt--;) { - LD_SB2(src, src_stride, src7, src8); - src += 2 * src_stride; - XORI_B2_128_SB(src7, src8); + for (loop_cnt = height >> 3; loop_cnt--;) { + LD_SB8(src, src_stride, src7, src8, src9, src10, src11, src12, src13, + src14); + src += (8 * src_stride); + XORI_B8_128_SB(src7, src8, src9, src10, src11, src12, src13, src14); - VSHF_B4_SB(src7, src8, mask0, mask1, mask2, mask3, + VSHF_B4_SB(src7, src11, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst87 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst87, dst87, dst87, dst87); + VSHF_B4_SB(src8, src12, mask0, mask1, mask2, mask3, + vec4, vec5, vec6, vec7); + VSHF_B4_SB(src9, src13, mask0, mask1, mask2, mask3, + vec8, vec9, vec10, vec11); + VSHF_B4_SB(src10, src14, mask0, mask1, mask2, mask3, + vec12, vec13, vec14, vec15); - dst76_r = __msa_ilvr_h(dst87, dst66); - dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, - filt_h0, filt_h1, filt_h2, filt_h3); - dst87_r = __msa_vshf_h(mask4, dst87, dst87); - dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, - filt_h0, filt_h1, filt_h2, filt_h3); + dst117 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst128 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst139 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, + filt2, filt3); + dst1410 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, + filt2, filt3); - dst0_r >>= 6; - dst1_r >>= 6; - SRARI_W2_SW(dst0_r, dst1_r, 6); - dst0_r = CLIP_SW_0_255(dst0_r); - dst1_r = CLIP_SW_0_255(dst1_r); + dst76_r = __msa_ilvr_h(dst117, dst66); + ILVRL_H2_SH(dst128, dst117, dst87_r, dst1211_r); + ILVRL_H2_SH(dst139, dst128, dst98_r, dst1312_r); + ILVRL_H2_SH(dst1410, dst139, dst109_r, dst1413_r); + dst117 = (v8i16) __msa_splati_d((v2i64) dst117, 1); + dst1110_r = __msa_ilvr_h(dst117, dst1410); + + dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst2_r = HEVC_FILT_8TAP(dst32_r, dst54_r, dst76_r, dst98_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst3_r = HEVC_FILT_8TAP(dst43_r, dst65_r, dst87_r, dst109_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst4_r = HEVC_FILT_8TAP(dst54_r, dst76_r, dst98_r, dst1110_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst5_r = HEVC_FILT_8TAP(dst65_r, dst87_r, dst109_r, dst1211_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst6_r = HEVC_FILT_8TAP(dst76_r, dst98_r, dst1110_r, dst1312_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst7_r = HEVC_FILT_8TAP(dst87_r, dst109_r, dst1211_r, dst1413_r, + filt_h0, filt_h1, filt_h2, filt_h3); - HEVC_PCK_SW_SB2(dst1_r, dst0_r, dst0_r); - ST4x2_UB(dst0_r, dst, dst_stride); - dst += (2 * dst_stride); + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRA_4V(dst4_r, dst5_r, dst6_r, dst7_r, 6); + SRARI_W4_SW(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRARI_W4_SW(dst4_r, dst5_r, dst6_r, dst7_r, 6); + SAT_SW4_SW(dst0_r, dst1_r, dst2_r, dst3_r, 7); + SAT_SW4_SW(dst4_r, dst5_r, dst6_r, dst7_r, 7); + PCKEV_H2_SW(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); + PCKEV_H2_SW(dst5_r, dst4_r, dst7_r, dst6_r, dst4_r, dst5_r); + out0 = PCKEV_XORI128_UB(dst0_r, dst1_r); + out1 = PCKEV_XORI128_UB(dst4_r, dst5_r); + ST4x4_UB(out0, out0, 0, 1, 2, 3, dst, dst_stride); + dst += (4 * dst_stride); + ST4x4_UB(out1, out1, 0, 1, 2, 3, dst, dst_stride); + dst += (4 * dst_stride); - dst10_r = dst32_r; - dst32_r = dst54_r; - dst54_r = dst76_r; - dst21_r = dst43_r; - dst43_r = dst65_r; - dst65_r = dst87_r; - dst66 = (v8i16) __msa_splati_d((v2i64) dst87, 1); + dst10_r = dst98_r; + dst32_r = dst1110_r; + dst54_r = dst1312_r; + dst21_r = dst109_r; + dst43_r = dst1211_r; + dst65_r = dst1413_r; + dst66 = (v8i16) __msa_splati_d((v2i64) dst1410, 1); } } @@ -1412,11 +1484,12 @@ static void hevc_hv_uni_8t_8multx2mult_msa(uint8_t *src, uint32_t loop_cnt, cnt; uint8_t *src_tmp; uint8_t *dst_tmp; + v16u8 out; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v8i16 filt0, filt1, filt2, filt3; - v4i32 filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 filt_h0, filt_h1, filt_h2, filt_h3; v16i8 mask1, mask2, mask3; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; @@ -1425,20 +1498,17 @@ static void hevc_hv_uni_8t_8multx2mult_msa(uint8_t *src, v8i16 dst10_l, dst32_l, dst54_l, dst76_l; v8i16 dst21_r, dst43_r, dst65_r, dst87_r; v8i16 dst21_l, dst43_l, dst65_l, dst87_l; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); src -= ((3 * src_stride) + 3); - const_vec = __msa_ldi_h(128); - const_vec <<= 6; filter_vec = LD_SH(filter_x); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W4_SW(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); mask1 = mask0 + 2; mask2 = mask0 + 4; @@ -1461,18 +1531,14 @@ static void hevc_hv_uni_8t_8multx2mult_msa(uint8_t *src, vec8, vec9, vec10, vec11); VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec12, vec13, vec14, vec15); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - dst1 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - dst2 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - dst3 = const_vec; - DPADD_SB4_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst1 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst2 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst3 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, + filt2, filt3); VSHF_B4_SB(src4, src4, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); @@ -1480,33 +1546,29 @@ static void hevc_hv_uni_8t_8multx2mult_msa(uint8_t *src, vec4, vec5, vec6, vec7); VSHF_B4_SB(src6, src6, mask0, mask1, mask2, mask3, vec8, vec9, vec10, vec11); - dst4 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst4, dst4, dst4, dst4); - dst5 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst5, dst5, dst5, dst5); - dst6 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst6, dst6, dst6, dst6); - - ILVR_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, - dst10_r, dst32_r, dst54_r, dst21_r); - ILVR_H2_SH(dst4, dst3, dst6, dst5, dst43_r, dst65_r); - ILVL_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, - dst10_l, dst32_l, dst54_l, dst21_l); - ILVL_H2_SH(dst4, dst3, dst6, dst5, dst43_l, dst65_l); + dst4 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst5 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst6 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); for (loop_cnt = height >> 1; loop_cnt--;) { LD_SB2(src_tmp, src_stride, src7, src8); XORI_B2_128_SB(src7, src8); src_tmp += 2 * src_stride; + ILVR_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, + dst10_r, dst32_r, dst54_r, dst21_r); + ILVL_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, + dst10_l, dst32_l, dst54_l, dst21_l); + ILVR_H2_SH(dst4, dst3, dst6, dst5, dst43_r, dst65_r); + ILVL_H2_SH(dst4, dst3, dst6, dst5, dst43_l, dst65_l); + VSHF_B4_SB(src7, src7, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst7 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst7, dst7, dst7, dst7); + dst7 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, @@ -1518,9 +1580,8 @@ static void hevc_hv_uni_8t_8multx2mult_msa(uint8_t *src, VSHF_B4_SB(src8, src8, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst8 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst8, dst8, dst8, dst8); + dst8 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, @@ -1530,27 +1591,19 @@ static void hevc_hv_uni_8t_8multx2mult_msa(uint8_t *src, dst1_r >>= 6; dst1_l >>= 6; SRARI_W4_SW(dst0_r, dst0_l, dst1_r, dst1_l, 6); - dst0_r = CLIP_SW_0_255(dst0_r); - dst0_l = CLIP_SW_0_255(dst0_l); - dst1_r = CLIP_SW_0_255(dst1_r); - dst1_l = CLIP_SW_0_255(dst1_l); + SAT_SW4_SW(dst0_r, dst0_l, dst1_r, dst1_l, 7); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST8x2_UB(dst0_r, dst_tmp, dst_stride); + PCKEV_H2_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst0, dst1); + out = PCKEV_XORI128_UB(dst0, dst1); + ST8x2_UB(out, dst_tmp, dst_stride); dst_tmp += (2 * dst_stride); - dst10_r = dst32_r; - dst32_r = dst54_r; - dst54_r = dst76_r; - dst10_l = dst32_l; - dst32_l = dst54_l; - dst54_l = dst76_l; - dst21_r = dst43_r; - dst43_r = dst65_r; - dst65_r = dst87_r; - dst21_l = dst43_l; - dst43_l = dst65_l; - dst65_l = dst87_l; + dst0 = dst2; + dst1 = dst3; + dst2 = dst4; + dst3 = dst5; + dst4 = dst6; + dst5 = dst7; dst6 = dst8; } @@ -1579,11 +1632,232 @@ static void hevc_hv_uni_8t_12w_msa(uint8_t *src, const int8_t *filter_y, int32_t height) { - hevc_hv_uni_8t_8multx2mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 8); + uint32_t loop_cnt; + uint8_t *src_tmp, *dst_tmp; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 src11, src12, src13, src14; + v16i8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask7; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; + v8i16 dst30, dst41, dst52, dst63, dst66, dst117, dst128, dst139, dst1410; + v8i16 filt0, filt1, filt2, filt3, filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst76_l, dst21_l, dst43_l, dst65_l; + v8i16 dst87_r, dst98_r, dst1110_r, dst1312_r, dst109_r, dst1211_r; + v8i16 dst1413_r, dst87_l, filter_vec; + v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r, dst6_r, dst7_r; + v4i32 dst0_l, dst1_l; + + src -= ((3 * src_stride) + 3); + + filter_vec = LD_SH(filter_x); + SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + mask2 = mask0 + 4; + mask3 = mask0 + 6; + + src_tmp = src; + dst_tmp = dst; + + LD_SB7(src_tmp, src_stride, src0, src1, src2, src3, src4, src5, src6); + src_tmp += (7 * src_stride); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + /* row 0 row 1 row 2 row 3 */ + VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, vec8, vec9, vec10, + vec11); + VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec12, vec13, vec14, + vec15); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst1 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst2 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst3 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, + filt2, filt3); + + VSHF_B4_SB(src4, src4, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src5, src5, mask0, mask1, mask2, mask3, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src6, src6, mask0, mask1, mask2, mask3, vec8, vec9, vec10, + vec11); + dst4 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst5 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst6 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + + for (loop_cnt = 8; loop_cnt--;) { + LD_SB2(src_tmp, src_stride, src7, src8); + XORI_B2_128_SB(src7, src8); + src_tmp += 2 * src_stride; + + ILVR_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, dst10_r, + dst32_r, dst54_r, dst21_r); + ILVL_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, dst10_l, + dst32_l, dst54_l, dst21_l); + ILVR_H2_SH(dst4, dst3, dst6, dst5, dst43_r, dst65_r); + ILVL_H2_SH(dst4, dst3, dst6, dst5, dst43_l, dst65_l); + + VSHF_B4_SB(src7, src7, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + dst7 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + + ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); + dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, + filt_h0, filt_h1, filt_h2, filt_h3); + dst0_l = HEVC_FILT_8TAP(dst10_l, dst32_l, dst54_l, dst76_l, + filt_h0, filt_h1, filt_h2, filt_h3); + dst0_r >>= 6; + dst0_l >>= 6; + + VSHF_B4_SB(src8, src8, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + dst8 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + + ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); + dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, + filt_h0, filt_h1, filt_h2, filt_h3); + dst1_l = HEVC_FILT_8TAP(dst21_l, dst43_l, dst65_l, dst87_l, + filt_h0, filt_h1, filt_h2, filt_h3); + dst1_r >>= 6; + dst1_l >>= 6; + SRARI_W4_SW(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SAT_SW4_SW(dst0_r, dst0_l, dst1_r, dst1_l, 7); + + PCKEV_H2_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst0, dst1); + out0 = PCKEV_XORI128_UB(dst0, dst1); + ST8x2_UB(out0, dst_tmp, dst_stride); + dst_tmp += (2 * dst_stride); + + dst0 = dst2; + dst1 = dst3; + dst2 = dst4; + dst3 = dst5; + dst4 = dst6; + dst5 = dst7; + dst6 = dst8; + } + + src += 8; + dst += 8; + + mask4 = LD_SB(ff_hevc_mask_arr + 16); + mask5 = mask4 + 2; + mask6 = mask4 + 4; + mask7 = mask4 + 6; + + LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); + src += (7 * src_stride); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + VSHF_B4_SB(src0, src3, mask4, mask5, mask6, mask7, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src1, src4, mask4, mask5, mask6, mask7, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src2, src5, mask4, mask5, mask6, mask7, vec8, vec9, vec10, + vec11); + VSHF_B4_SB(src3, src6, mask4, mask5, mask6, mask7, vec12, vec13, vec14, + vec15); + + dst30 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst41 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst52 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst63 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, + filt3); + + ILVRL_H2_SH(dst41, dst30, dst10_r, dst43_r); + ILVRL_H2_SH(dst52, dst41, dst21_r, dst54_r); + ILVRL_H2_SH(dst63, dst52, dst32_r, dst65_r); + + dst66 = (v8i16) __msa_splati_d((v2i64) dst63, 1); + + for (loop_cnt = 2; loop_cnt--;) { + LD_SB8(src, src_stride, src7, src8, src9, src10, src11, src12, src13, + src14); + src += (8 * src_stride); + XORI_B8_128_SB(src7, src8, src9, src10, src11, src12, src13, src14); + + VSHF_B4_SB(src7, src11, mask4, mask5, mask6, mask7, vec0, vec1, vec2, + vec3); + VSHF_B4_SB(src8, src12, mask4, mask5, mask6, mask7, vec4, vec5, vec6, + vec7); + VSHF_B4_SB(src9, src13, mask4, mask5, mask6, mask7, vec8, vec9, vec10, + vec11); + VSHF_B4_SB(src10, src14, mask4, mask5, mask6, mask7, vec12, vec13, + vec14, vec15); + + dst117 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst128 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst139 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, + filt2, filt3); + dst1410 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, + filt2, filt3); + + dst76_r = __msa_ilvr_h(dst117, dst66); + ILVRL_H2_SH(dst128, dst117, dst87_r, dst1211_r); + ILVRL_H2_SH(dst139, dst128, dst98_r, dst1312_r); + ILVRL_H2_SH(dst1410, dst139, dst109_r, dst1413_r); + dst117 = (v8i16) __msa_splati_d((v2i64) dst117, 1); + dst1110_r = __msa_ilvr_h(dst117, dst1410); + + dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst2_r = HEVC_FILT_8TAP(dst32_r, dst54_r, dst76_r, dst98_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst3_r = HEVC_FILT_8TAP(dst43_r, dst65_r, dst87_r, dst109_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst4_r = HEVC_FILT_8TAP(dst54_r, dst76_r, dst98_r, dst1110_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst5_r = HEVC_FILT_8TAP(dst65_r, dst87_r, dst109_r, dst1211_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst6_r = HEVC_FILT_8TAP(dst76_r, dst98_r, dst1110_r, dst1312_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst7_r = HEVC_FILT_8TAP(dst87_r, dst109_r, dst1211_r, dst1413_r, + filt_h0, filt_h1, filt_h2, filt_h3); + + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRA_4V(dst4_r, dst5_r, dst6_r, dst7_r, 6); + SRARI_W4_SW(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRARI_W4_SW(dst4_r, dst5_r, dst6_r, dst7_r, 6); + SAT_SW4_SW(dst0_r, dst1_r, dst2_r, dst3_r, 7); + SAT_SW4_SW(dst4_r, dst5_r, dst6_r, dst7_r, 7); + PCKEV_H2_SW(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); + PCKEV_H2_SW(dst5_r, dst4_r, dst7_r, dst6_r, dst4_r, dst5_r); + out0 = PCKEV_XORI128_UB(dst0_r, dst1_r); + out1 = PCKEV_XORI128_UB(dst4_r, dst5_r); + ST4x4_UB(out0, out0, 0, 1, 2, 3, dst, dst_stride); + dst += (4 * dst_stride); + ST4x4_UB(out1, out1, 0, 1, 2, 3, dst, dst_stride); + dst += (4 * dst_stride); - hevc_hv_uni_8t_4w_msa(src + 8, src_stride, dst + 8, dst_stride, - filter_x, filter_y, height); + dst10_r = dst98_r; + dst32_r = dst1110_r; + dst54_r = dst1312_r; + dst21_r = dst109_r; + dst43_r = dst1211_r; + dst65_r = dst1413_r; + dst66 = (v8i16) __msa_splati_d((v2i64) dst1410, 1); + } } static void hevc_hv_uni_8t_16w_msa(uint8_t *src, @@ -1654,7 +1928,7 @@ static void common_hz_4t_4x2_msa(uint8_t *src, int32_t src_stride, v16u8 out; v8i16 filt, res0; - mask0 = LD_SB(&mc_filt_mask_arr[16]); + mask0 = LD_SB(&ff_hevc_mask_arr[16]); src -= 1; /* rearranging filter */ @@ -1666,7 +1940,7 @@ static void common_hz_4t_4x2_msa(uint8_t *src, int32_t src_stride, LD_SB2(src, src_stride, src0, src1); XORI_B2_128_SB(src0, src1); VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); - res0 = FILT_4TAP_DPADD_S_H(vec0, vec1, filt0, filt1); + res0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); res0 = __msa_srari_h(res0, 6); res0 = __msa_sat_s_h(res0, 7); out = PCKEV_XORI128_UB(res0, res0); @@ -1681,7 +1955,7 @@ static void common_hz_4t_4x4_msa(uint8_t *src, int32_t src_stride, v8i16 filt, out0, out1; v16u8 out; - mask0 = LD_SB(&mc_filt_mask_arr[16]); + mask0 = LD_SB(&ff_hevc_mask_arr[16]); src -= 1; /* rearranging filter */ @@ -1708,7 +1982,7 @@ static void common_hz_4t_4x8_msa(uint8_t *src, int32_t src_stride, v16u8 out; v8i16 filt, out0, out1, out2, out3; - mask0 = LD_SB(&mc_filt_mask_arr[16]); + mask0 = LD_SB(&ff_hevc_mask_arr[16]); src -= 1; /* rearranging filter */ @@ -1745,7 +2019,7 @@ static void common_hz_4t_4x16_msa(uint8_t *src, int32_t src_stride, v16u8 out; v8i16 filt, out0, out1, out2, out3; - mask0 = LD_SB(&mc_filt_mask_arr[16]); + mask0 = LD_SB(&ff_hevc_mask_arr[16]); src -= 1; /* rearranging filter */ @@ -1805,12 +2079,11 @@ static void common_hz_4t_6w_msa(uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter, int32_t height) { - uint32_t loop_cnt; v16i8 src0, src1, src2, src3, filt0, filt1, mask0, mask1; v16u8 out4, out5; v8i16 filt, out0, out1, out2, out3; - mask0 = LD_SB(&mc_filt_mask_arr[0]); + mask0 = LD_SB(&ff_hevc_mask_arr[0]); src -= 1; /* rearranging filter */ @@ -1819,21 +2092,31 @@ static void common_hz_4t_6w_msa(uint8_t *src, int32_t src_stride, mask1 = mask0 + 2; - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); + LD_SB4(src, src_stride, src0, src1, src2, src3); + src += (4 * src_stride); - XORI_B4_128_SB(src0, src1, src2, src3); - HORIZ_4TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, filt0, - filt1, out0, out1, out2, out3); - SRARI_H4_SH(out0, out1, out2, out3, 6); - SAT_SH4_SH(out0, out1, out2, out3, 7); + XORI_B4_128_SB(src0, src1, src2, src3); + HORIZ_4TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, filt0, + filt1, out0, out1, out2, out3); + SRARI_H4_SH(out0, out1, out2, out3, 6); + SAT_SH4_SH(out0, out1, out2, out3, 7); + out4 = PCKEV_XORI128_UB(out0, out1); + out5 = PCKEV_XORI128_UB(out2, out3); + ST6x4_UB(out4, out5, dst, dst_stride); + dst += (4 * dst_stride); - out4 = PCKEV_XORI128_UB(out0, out1); - out5 = PCKEV_XORI128_UB(out2, out3); - ST6x4_UB(out4, out5, dst, dst_stride); - dst += (4 * dst_stride); - } + LD_SB4(src, src_stride, src0, src1, src2, src3); + src += (4 * src_stride); + + XORI_B4_128_SB(src0, src1, src2, src3); + HORIZ_4TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, filt0, + filt1, out0, out1, out2, out3); + SRARI_H4_SH(out0, out1, out2, out3, 6); + SAT_SH4_SH(out0, out1, out2, out3, 7); + out4 = PCKEV_XORI128_UB(out0, out1); + out5 = PCKEV_XORI128_UB(out2, out3); + ST6x4_UB(out4, out5, dst, dst_stride); + dst += (4 * dst_stride); } static void common_hz_4t_8x2mult_msa(uint8_t *src, int32_t src_stride, @@ -1845,7 +2128,7 @@ static void common_hz_4t_8x2mult_msa(uint8_t *src, int32_t src_stride, v16u8 out; v8i16 filt, vec0, vec1, vec2, vec3; - mask0 = LD_SB(&mc_filt_mask_arr[0]); + mask0 = LD_SB(&ff_hevc_mask_arr[0]); src -= 1; filt = LD_SH(filter); @@ -1879,7 +2162,7 @@ static void common_hz_4t_8x4mult_msa(uint8_t *src, int32_t src_stride, v16u8 tmp0, tmp1; v8i16 filt, out0, out1, out2, out3; - mask0 = LD_SB(&mc_filt_mask_arr[0]); + mask0 = LD_SB(&ff_hevc_mask_arr[0]); src -= 1; /* rearranging filter */ @@ -1928,8 +2211,8 @@ static void common_hz_4t_12w_msa(uint8_t *src, int32_t src_stride, v16u8 tmp0, tmp1; v8i16 filt, out0, out1, out2, out3, out4, out5; - mask0 = LD_SB(&mc_filt_mask_arr[0]); - mask2 = LD_SB(&mc_filt_mask_arr[32]); + mask0 = LD_SB(&ff_hevc_mask_arr[0]); + mask2 = LD_SB(&ff_hevc_mask_arr[32]); src -= 1; @@ -1940,32 +2223,33 @@ static void common_hz_4t_12w_msa(uint8_t *src, int32_t src_stride, mask1 = mask0 + 2; mask3 = mask2 + 2; - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = 4; loop_cnt--;) { LD_SB4(src, src_stride, src0, src1, src2, src3); src += (4 * src_stride); XORI_B4_128_SB(src0, src1, src2, src3); + VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec0, vec1); + DOTP_SB2_SH(vec0, vec1, filt0, filt0, out0, out1); + VSHF_B2_SB(src0, src1, src2, src3, mask3, mask3, vec2, vec3); + DPADD_SB2_SH(vec2, vec3, filt1, filt1, out0, out1); + SRARI_H2_SH(out0, out1, 6); + SAT_SH2_SH(out0, out1, 7); + tmp0 = PCKEV_XORI128_UB(out0, out1); + ST4x4_UB(tmp0, tmp0, 0, 1, 2, 3, dst + 8, dst_stride); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec4, vec5); VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec6, vec7); - VSHF_B2_SB(src0, src1, src2, src3, mask2, mask2, vec0, vec1); DOTP_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt0, filt0, filt0, out2, out3, out4, out5); - DOTP_SB2_SH(vec0, vec1, filt0, filt0, out0, out1); VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec8, vec9); VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec10, vec11); - VSHF_B2_SB(src0, src1, src2, src3, mask3, mask3, vec2, vec3); DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt1, filt1, filt1, filt1, out2, out3, out4, out5); - DPADD_SB2_SH(vec2, vec3, filt1, filt1, out0, out1); - SRARI_H4_SH(out0, out1, out2, out3, 6); - SRARI_H2_SH(out4, out5, 6); - SAT_SH4_SH(out0, out1, out2, out3, 7); - SAT_SH2_SH(out4, out5, 7); + SRARI_H4_SH(out2, out3, out4, out5, 6); + SAT_SH4_SH(out2, out3, out4, out5, 7); tmp0 = PCKEV_XORI128_UB(out2, out3); tmp1 = PCKEV_XORI128_UB(out4, out5); ST8x4_UB(tmp0, tmp1, dst, dst_stride); - tmp0 = PCKEV_XORI128_UB(out0, out1); - ST4x4_UB(tmp0, tmp0, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); } } @@ -1977,10 +2261,11 @@ static void common_hz_4t_16w_msa(uint8_t *src, int32_t src_stride, uint32_t loop_cnt; v16i8 src0, src1, src2, src3, src4, src5, src6, src7; v16i8 filt0, filt1, mask0, mask1; + v16i8 vec0_m, vec1_m, vec2_m, vec3_m; v8i16 filt, out0, out1, out2, out3, out4, out5, out6, out7; v16u8 out; - mask0 = LD_SB(&mc_filt_mask_arr[0]); + mask0 = LD_SB(&ff_hevc_mask_arr[0]); src -= 1; /* rearranging filter */ @@ -1995,20 +2280,34 @@ static void common_hz_4t_16w_msa(uint8_t *src, int32_t src_stride, src += (4 * src_stride); XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); - HORIZ_4TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, filt0, - filt1, out0, out1, out2, out3); - HORIZ_4TAP_8WID_4VECS_FILT(src4, src5, src6, src7, mask0, mask1, filt0, - filt1, out4, out5, out6, out7); - SRARI_H4_SH(out0, out1, out2, out3, 6); - SRARI_H4_SH(out4, out5, out6, out7, 6); + + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0_m, vec1_m); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2_m, vec3_m); + DOTP_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt0, filt0, filt0, filt0, + out0, out1, out2, out3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0_m, vec1_m); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2_m, vec3_m); + DPADD_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt1, filt1, filt1, filt1, + out0, out1, out2, out3); + SRARI_H4_SH(out0, out1, out2, out3, 6); SAT_SH4_SH(out0, out1, out2, out3, 7); - SAT_SH4_SH(out4, out5, out6, out7, 7); out = PCKEV_XORI128_UB(out0, out1); ST_UB(out, dst); dst += dst_stride; out = PCKEV_XORI128_UB(out2, out3); ST_UB(out, dst); dst += dst_stride; + + VSHF_B2_SB(src4, src4, src5, src5, mask0, mask0, vec0_m, vec1_m); + VSHF_B2_SB(src6, src6, src7, src7, mask0, mask0, vec2_m, vec3_m); + DOTP_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt0, filt0, filt0, filt0, + out4, out5, out6, out7); + VSHF_B2_SB(src4, src4, src5, src5, mask1, mask1, vec0_m, vec1_m); + VSHF_B2_SB(src6, src6, src7, src7, mask1, mask1, vec2_m, vec3_m); + DPADD_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt1, filt1, filt1, filt1, + out4, out5, out6, out7); + SRARI_H4_SH(out4, out5, out6, out7, 6); + SAT_SH4_SH(out4, out5, out6, out7, 7); out = PCKEV_XORI128_UB(out4, out5); ST_UB(out, dst); dst += dst_stride; @@ -2030,7 +2329,7 @@ static void common_hz_4t_24w_msa(uint8_t *src, int32_t src_stride, v8i16 filt, out0, out1, out2, out3; v16u8 tmp0, tmp1; - mask0 = LD_SB(&mc_filt_mask_arr[0]); + mask0 = LD_SB(&ff_hevc_mask_arr[0]); src -= 1; /* rearranging filter */ @@ -2041,7 +2340,7 @@ static void common_hz_4t_24w_msa(uint8_t *src, int32_t src_stride, mask00 = mask0 + 8; mask11 = mask0 + 10; - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = 8; loop_cnt--;) { LD_SB4(src, src_stride, src0, src2, src4, src6); LD_SB4(src + 16, src_stride, src1, src3, src5, src7); src += (4 * src_stride); @@ -2109,9 +2408,10 @@ static void common_hz_4t_32w_msa(uint8_t *src, int32_t src_stride, v16i8 src0, src1, src2, src3, src4, src5, src6, src7; v16i8 filt0, filt1, mask0, mask1; v16u8 out; + v16i8 vec0_m, vec1_m, vec2_m, vec3_m; v8i16 filt, out0, out1, out2, out3, out4, out5, out6, out7; - mask0 = LD_SB(&mc_filt_mask_arr[0]); + mask0 = LD_SB(&ff_hevc_mask_arr[0]); src -= 1; /* rearranging filter */ @@ -2122,20 +2422,35 @@ static void common_hz_4t_32w_msa(uint8_t *src, int32_t src_stride, for (loop_cnt = (height >> 1); loop_cnt--;) { src0 = LD_SB(src); + src1 = LD_SB(src + 8); src2 = LD_SB(src + 16); src3 = LD_SB(src + 24); src += src_stride; src4 = LD_SB(src); + src5 = LD_SB(src + 8); src6 = LD_SB(src + 16); src7 = LD_SB(src + 24); - SLDI_B2_SB(src2, src6, src0, src4, src1, src5, 8); src += src_stride; XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); - HORIZ_4TAP_8WID_4VECS_FILT(src0, src1, src2, src3, mask0, mask1, - filt0, filt1, out0, out1, out2, out3); - HORIZ_4TAP_8WID_4VECS_FILT(src4, src5, src6, src7, mask0, mask1, - filt0, filt1, out4, out5, out6, out7); + + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0_m, vec1_m); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2_m, vec3_m); + DOTP_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt0, filt0, filt0, filt0, + out0, out1, out2, out3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0_m, vec1_m); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2_m, vec3_m); + DPADD_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt1, filt1, filt1, filt1, + out0, out1, out2, out3); + + VSHF_B2_SB(src4, src4, src5, src5, mask0, mask0, vec0_m, vec1_m); + VSHF_B2_SB(src6, src6, src7, src7, mask0, mask0, vec2_m, vec3_m); + DOTP_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt0, filt0, filt0, filt0, + out4, out5, out6, out7); + VSHF_B2_SB(src4, src4, src5, src5, mask1, mask1, vec0_m, vec1_m); + VSHF_B2_SB(src6, src6, src7, src7, mask1, mask1, vec2_m, vec3_m); + DPADD_SB4_SH(vec0_m, vec1_m, vec2_m, vec3_m, filt1, filt1, filt1, filt1, + out4, out5, out6, out7); SRARI_H4_SH(out0, out1, out2, out3, 6); SRARI_H4_SH(out4, out5, out6, out7, 6); SAT_SH4_SH(out0, out1, out2, out3, 7); @@ -2177,7 +2492,7 @@ static void common_vt_4t_4x2_msa(uint8_t *src, int32_t src_stride, ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); src4332 = (v16i8) __msa_ilvr_d((v2i64) src43_r, (v2i64) src32_r); src4332 = (v16i8) __msa_xori_b((v16u8) src4332, 128); - out10 = FILT_4TAP_DPADD_S_H(src2110, src4332, filt0, filt1); + out10 = HEVC_FILT_4TAP_SH(src2110, src4332, filt0, filt1); out10 = __msa_srari_h(out10, 6); out10 = __msa_sat_s_h(out10, 7); out = PCKEV_XORI128_UB(out10, out10); @@ -2214,14 +2529,14 @@ static void common_vt_4t_4x4multiple_msa(uint8_t *src, int32_t src_stride, ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); src4332 = (v16i8) __msa_ilvr_d((v2i64) src43_r, (v2i64) src32_r); src4332 = (v16i8) __msa_xori_b((v16u8) src4332, 128); - out10 = FILT_4TAP_DPADD_S_H(src2110, src4332, filt0, filt1); + out10 = HEVC_FILT_4TAP_SH(src2110, src4332, filt0, filt1); src2 = LD_SB(src); src += (src_stride); ILVR_B2_SB(src5, src4, src2, src5, src54_r, src65_r); src2110 = (v16i8) __msa_ilvr_d((v2i64) src65_r, (v2i64) src54_r); src2110 = (v16i8) __msa_xori_b((v16u8) src2110, 128); - out32 = FILT_4TAP_DPADD_S_H(src4332, src2110, filt0, filt1); + out32 = HEVC_FILT_4TAP_SH(src4332, src2110, filt0, filt1); SRARI_H2_SH(out10, out32, 6); SAT_SH2_SH(out10, out32, 7); out = PCKEV_XORI128_UB(out10, out32); @@ -2246,51 +2561,65 @@ static void common_vt_4t_6w_msa(uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter, int32_t height) { - uint32_t loop_cnt; - v16u8 src0, src1, src2, src3, vec0, vec1, vec2, vec3, out0, out1; - v8i16 vec01, vec12, vec23, vec30, tmp0, tmp1, tmp2, tmp3; - v8i16 filt, filt0, filt1; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6; + v16i8 src10_r, src32_r, src21_r, src43_r, src54_r, src65_r; + v8i16 dst0_r, dst1_r, dst2_r, dst3_r, filt0, filt1, filter_vec; src -= src_stride; - /* rearranging filter_y */ - filt = LD_SH(filter); - SPLATI_H2_SH(filt, 0, 1, filt0, filt1); + filter_vec = LD_SH(filter); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); - LD_UB3(src, src_stride, src0, src1, src2); + LD_SB3(src, src_stride, src0, src1, src2); src += (3 * src_stride); + XORI_B3_128_SB(src0, src1, src2); + ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); + + LD_SB2(src, src_stride, src3, src4); + src += (2 * src_stride); + XORI_B2_128_SB(src3, src4); + ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); - vec0 = (v16u8) __msa_xori_b((v16u8) src0, 128); - vec1 = (v16u8) __msa_xori_b((v16u8) src1, 128); - vec2 = (v16u8) __msa_xori_b((v16u8) src2, 128); + dst0_r = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + dst1_r = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_UB4(src, src_stride, src3, src0, src1, src2); - src += (4 * src_stride); + LD_SB2(src, src_stride, src5, src6); + src += (2 * src_stride); + XORI_B2_128_SB(src5, src6); + ILVR_B2_SB(src5, src4, src6, src5, src54_r, src65_r); - vec3 = (v16u8) __msa_xori_b((v16u8) src3, 128); - ILVR_B2_SH(vec1, vec0, vec3, vec2, vec01, vec23); - tmp0 = FILT_4TAP_DPADD_S_H(vec01, vec23, filt0, filt1); + dst2_r = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + dst3_r = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); - vec0 = __msa_xori_b((v16u8) src0, 128); - ILVR_B2_SH(vec2, vec1, vec0, vec3, vec12, vec30); - tmp1 = FILT_4TAP_DPADD_S_H(vec12, vec30, filt0, filt1); + SRARI_H4_SH(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SAT_SH4_SH(dst0_r, dst1_r, dst2_r, dst3_r, 7); + out0 = PCKEV_XORI128_UB(dst0_r, dst1_r); + out1 = PCKEV_XORI128_UB(dst2_r, dst3_r); + ST6x4_UB(out0, out1, dst, dst_stride); + dst += (4 * dst_stride); - vec1 = __msa_xori_b((v16u8) src1, 128); - vec01 = (v8i16) __msa_ilvr_b((v16i8) vec1, (v16i8) vec0); - tmp2 = FILT_4TAP_DPADD_S_H(vec23, vec01, filt0, filt1); + LD_SB2(src, src_stride, src3, src4); + src += (2 * src_stride); + XORI_B2_128_SB(src3, src4); + ILVR_B2_SB(src3, src6, src4, src3, src32_r, src43_r); - vec2 = __msa_xori_b((v16u8) src2, 128); - vec12 = (v8i16) __msa_ilvr_b((v16i8) vec2, (v16i8) vec1); - tmp3 = FILT_4TAP_DPADD_S_H(vec30, vec12, filt0, filt1); + dst0_r = HEVC_FILT_4TAP_SH(src54_r, src32_r, filt0, filt1); + dst1_r = HEVC_FILT_4TAP_SH(src65_r, src43_r, filt0, filt1); - SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 6); - SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); - out0 = PCKEV_XORI128_UB(tmp0, tmp1); - out1 = PCKEV_XORI128_UB(tmp2, tmp3); - ST6x4_UB(out0, out1, dst, dst_stride); - dst += (4 * dst_stride); - } + LD_SB2(src, src_stride, src5, src6); + src += (2 * src_stride); + XORI_B2_128_SB(src5, src6); + ILVR_B2_SB(src5, src4, src6, src5, src54_r, src65_r); + + dst2_r = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + dst3_r = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); + + SRARI_H4_SH(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SAT_SH4_SH(dst0_r, dst1_r, dst2_r, dst3_r, 7); + out0 = PCKEV_XORI128_UB(dst0_r, dst1_r); + out1 = PCKEV_XORI128_UB(dst2_r, dst3_r); + ST6x4_UB(out0, out1, dst, dst_stride); } static void common_vt_4t_8x2_msa(uint8_t *src, int32_t src_stride, @@ -2310,9 +2639,9 @@ static void common_vt_4t_8x2_msa(uint8_t *src, int32_t src_stride, LD_SB5(src, src_stride, src0, src1, src2, src3, src4); XORI_B5_128_SB(src0, src1, src2, src3, src4); ILVR_B2_SH(src1, src0, src3, src2, src01, src23); - tmp0 = FILT_4TAP_DPADD_S_H(src01, src23, filt0, filt1); + tmp0 = HEVC_FILT_4TAP_SH(src01, src23, filt0, filt1); ILVR_B2_SH(src2, src1, src4, src3, src12, src34); - tmp1 = FILT_4TAP_DPADD_S_H(src12, src34, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(src12, src34, filt0, filt1); SRARI_H2_SH(tmp0, tmp1, 6); SAT_SH2_SH(tmp0, tmp1, 7); out = PCKEV_XORI128_UB(tmp0, tmp1); @@ -2347,9 +2676,9 @@ static void common_vt_4t_8x6_msa(uint8_t *src, int32_t src_stride, XORI_B3_128_SB(src3, src4, src5); ILVR_B3_SH(src3, src2, src4, src3, src5, src4, vec1, vec3, vec4); - tmp0 = FILT_4TAP_DPADD_S_H(vec0, vec1, filt0, filt1); - tmp1 = FILT_4TAP_DPADD_S_H(vec2, vec3, filt0, filt1); - tmp2 = FILT_4TAP_DPADD_S_H(vec1, vec4, filt0, filt1); + tmp0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + tmp1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + tmp2 = HEVC_FILT_4TAP_SH(vec1, vec4, filt0, filt1); SRARI_H2_SH(tmp0, tmp1, 6); tmp2 = __msa_srari_h(tmp2, 6); SAT_SH3_SH(tmp0, tmp1, tmp2, 7); @@ -2400,10 +2729,10 @@ static void common_vt_4t_8x4mult_msa(uint8_t *src, int32_t src_stride, XORI_B4_128_SB(src7, src8, src9, src10); ILVR_B4_SB(src7, src2, src8, src7, src9, src8, src10, src9, src72_r, src87_r, src98_r, src109_r); - out0_r = FILT_4TAP_DPADD_S_H(src10_r, src72_r, filt0, filt1); - out1_r = FILT_4TAP_DPADD_S_H(src21_r, src87_r, filt0, filt1); - out2_r = FILT_4TAP_DPADD_S_H(src72_r, src98_r, filt0, filt1); - out3_r = FILT_4TAP_DPADD_S_H(src87_r, src109_r, filt0, filt1); + out0_r = HEVC_FILT_4TAP_SH(src10_r, src72_r, filt0, filt1); + out1_r = HEVC_FILT_4TAP_SH(src21_r, src87_r, filt0, filt1); + out2_r = HEVC_FILT_4TAP_SH(src72_r, src98_r, filt0, filt1); + out3_r = HEVC_FILT_4TAP_SH(src87_r, src109_r, filt0, filt1); SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); tmp0 = PCKEV_XORI128_UB(out0_r, out1_r); @@ -2437,58 +2766,60 @@ static void common_vt_4t_12w_msa(uint8_t *src, int32_t src_stride, { uint32_t loop_cnt; v16i8 src0, src1, src2, src3, src4, src5, src6; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; v16u8 out0, out1; - v8i16 src10, src21, src32, src43, src54, src65, src87, src109, src1211; - v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, filt, filt0, filt1; - v4u32 mask = { 2, 6, 2, 6 }; + v16i8 src10_r, src32_r, src21_r, src43_r, src54_r, src65_r; + v16i8 src10_l, src32_l, src54_l, src21_l, src43_l, src65_l; + v16i8 src2110, src4332, src6554; + v8i16 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, filt0, filt1; + v8i16 filter_vec; - /* rearranging filter_y */ - filt = LD_SH(filter); - SPLATI_H2_SH(filt, 0, 1, filt0, filt1); + src -= (1 * src_stride); - src -= src_stride; + filter_vec = LD_SH(filter); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); LD_SB3(src, src_stride, src0, src1, src2); src += (3 * src_stride); XORI_B3_128_SB(src0, src1, src2); - VSHF_W2_SB(src0, src1, src1, src2, mask, mask, vec0, vec1); + ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); + ILVL_B2_SB(src1, src0, src2, src1, src10_l, src21_l); + src2110 = (v16i8) __msa_ilvr_d((v2i64) src21_l, (v2i64) src10_l); - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = 4; loop_cnt--;) { LD_SB4(src, src_stride, src3, src4, src5, src6); src += (4 * src_stride); XORI_B4_128_SB(src3, src4, src5, src6); - ILVR_B2_SH(src1, src0, src3, src2, src10, src32); - VSHF_W2_SB(src2, src3, src3, src4, mask, mask, vec2, vec3); - VSHF_W2_SB(src4, src5, src5, src6, mask, mask, vec4, vec5); - tmp0 = FILT_4TAP_DPADD_S_H(src10, src32, filt0, filt1); - ILVR_B4_SH(src2, src1, src4, src3, src5, src4, src6, src5, - src21, src43, src54, src65); - tmp1 = FILT_4TAP_DPADD_S_H(src21, src43, filt0, filt1); - tmp2 = FILT_4TAP_DPADD_S_H(src32, src54, filt0, filt1); - tmp3 = FILT_4TAP_DPADD_S_H(src43, src65, filt0, filt1); - ILVR_B3_SH(vec1, vec0, vec3, vec2, vec5, vec4, src87, src109, src1211); - tmp4 = FILT_4TAP_DPADD_S_H(src87, src109, filt0, filt1); - tmp5 = FILT_4TAP_DPADD_S_H(src109, src1211, filt0, filt1); - SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 6); - SRARI_H2_SH(tmp4, tmp5, 6); - SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); - SAT_SH2_SH(tmp4, tmp5, 7); - out0 = PCKEV_XORI128_UB(tmp0, tmp1); - out1 = PCKEV_XORI128_UB(tmp2, tmp3); + ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); + ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); + src4332 = (v16i8) __msa_ilvr_d((v2i64) src43_l, (v2i64) src32_l); + ILVR_B2_SB(src5, src4, src6, src5, src54_r, src65_r); + ILVL_B2_SB(src5, src4, src6, src5, src54_l, src65_l); + src6554 = (v16i8) __msa_ilvr_d((v2i64) src65_l, (v2i64) src54_l); + + dst0_r = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + dst1_r = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + dst0_l = HEVC_FILT_4TAP_SH(src2110, src4332, filt0, filt1); + dst2_r = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + dst3_r = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); + dst1_l = HEVC_FILT_4TAP_SH(src4332, src6554, filt0, filt1); + + SRARI_H4_SH(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRARI_H2_SH(dst0_l, dst1_l, 6); + SAT_SH4_SH(dst0_r, dst1_r, dst2_r, dst3_r, 7); + SAT_SH2_SH(dst0_l, dst1_l, 7); + out0 = PCKEV_XORI128_UB(dst0_r, dst1_r); + out1 = PCKEV_XORI128_UB(dst2_r, dst3_r); ST8x4_UB(out0, out1, dst, dst_stride); - out0 = PCKEV_XORI128_UB(tmp4, tmp5); + out0 = PCKEV_XORI128_UB(dst0_l, dst1_l); ST4x4_UB(out0, out0, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); - src0 = src4; - src1 = src5; - src2 = src6; - vec0 = vec4; - vec1 = vec5; src2 = src6; + src10_r = src54_r; + src21_r = src65_r; + src2110 = src6554; } } @@ -2524,14 +2855,14 @@ static void common_vt_4t_16w_msa(uint8_t *src, int32_t src_stride, src32_r, src43_r, src54_r, src65_r); ILVL_B4_SB(src3, src2, src4, src3, src5, src4, src6, src5, src32_l, src43_l, src54_l, src65_l); - out0_r = FILT_4TAP_DPADD_S_H(src10_r, src32_r, filt0, filt1); - out1_r = FILT_4TAP_DPADD_S_H(src21_r, src43_r, filt0, filt1); - out2_r = FILT_4TAP_DPADD_S_H(src32_r, src54_r, filt0, filt1); - out3_r = FILT_4TAP_DPADD_S_H(src43_r, src65_r, filt0, filt1); - out0_l = FILT_4TAP_DPADD_S_H(src10_l, src32_l, filt0, filt1); - out1_l = FILT_4TAP_DPADD_S_H(src21_l, src43_l, filt0, filt1); - out2_l = FILT_4TAP_DPADD_S_H(src32_l, src54_l, filt0, filt1); - out3_l = FILT_4TAP_DPADD_S_H(src43_l, src65_l, filt0, filt1); + out0_r = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + out1_r = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + out2_r = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + out3_r = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); + out0_l = HEVC_FILT_4TAP_SH(src10_l, src32_l, filt0, filt1); + out1_l = HEVC_FILT_4TAP_SH(src21_l, src43_l, filt0, filt1); + out2_l = HEVC_FILT_4TAP_SH(src32_l, src54_l, filt0, filt1); + out3_l = HEVC_FILT_4TAP_SH(src43_l, src65_l, filt0, filt1); SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); SRARI_H4_SH(out0_l, out1_l, out2_l, out3_l, 6); SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); @@ -2580,7 +2911,7 @@ static void common_vt_4t_24w_msa(uint8_t *src, int32_t src_stride, XORI_B3_128_SB(src6, src7, src8); ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = 8; loop_cnt--;) { /* 16 width */ LD_SB2(src, src_stride, src3, src4); XORI_B2_128_SB(src3, src4); @@ -2594,14 +2925,14 @@ static void common_vt_4t_24w_msa(uint8_t *src, int32_t src_stride, ILVR_B2_SB(src9, src8, src10, src9, src98_r, src109_r); /* 16 width */ - out0_r = FILT_4TAP_DPADD_S_H(src10_r, src32_r, filt0, filt1); - out0_l = FILT_4TAP_DPADD_S_H(src10_l, src32_l, filt0, filt1); - out1_r = FILT_4TAP_DPADD_S_H(src21_r, src43_r, filt0, filt1); - out1_l = FILT_4TAP_DPADD_S_H(src21_l, src43_l, filt0, filt1); + out0_r = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + out0_l = HEVC_FILT_4TAP_SH(src10_l, src32_l, filt0, filt1); + out1_r = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + out1_l = HEVC_FILT_4TAP_SH(src21_l, src43_l, filt0, filt1); /* 8 width */ - out2_r = FILT_4TAP_DPADD_S_H(src76_r, src98_r, filt0, filt1); - out3_r = FILT_4TAP_DPADD_S_H(src87_r, src109_r, filt0, filt1); + out2_r = HEVC_FILT_4TAP_SH(src76_r, src98_r, filt0, filt1); + out3_r = HEVC_FILT_4TAP_SH(src87_r, src109_r, filt0, filt1); /* 16 + 8 width */ SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); @@ -2634,14 +2965,14 @@ static void common_vt_4t_24w_msa(uint8_t *src, int32_t src_stride, ILVR_B2_SB(src11, src10, src8, src11, src76_r, src87_r); /* 16 width */ - out0_r = FILT_4TAP_DPADD_S_H(src32_r, src10_r, filt0, filt1); - out0_l = FILT_4TAP_DPADD_S_H(src32_l, src10_l, filt0, filt1); - out1_r = FILT_4TAP_DPADD_S_H(src43_r, src21_r, filt0, filt1); - out1_l = FILT_4TAP_DPADD_S_H(src43_l, src21_l, filt0, filt1); + out0_r = HEVC_FILT_4TAP_SH(src32_r, src10_r, filt0, filt1); + out0_l = HEVC_FILT_4TAP_SH(src32_l, src10_l, filt0, filt1); + out1_r = HEVC_FILT_4TAP_SH(src43_r, src21_r, filt0, filt1); + out1_l = HEVC_FILT_4TAP_SH(src43_l, src21_l, filt0, filt1); /* 8 width */ - out2_r = FILT_4TAP_DPADD_S_H(src98_r, src76_r, filt0, filt1); - out3_r = FILT_4TAP_DPADD_S_H(src109_r, src87_r, filt0, filt1); + out2_r = HEVC_FILT_4TAP_SH(src98_r, src76_r, filt0, filt1); + out3_r = HEVC_FILT_4TAP_SH(src109_r, src87_r, filt0, filt1); /* 16 + 8 width */ SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); @@ -2661,13 +2992,11 @@ static void common_vt_4t_24w_msa(uint8_t *src, int32_t src_stride, } } -static void common_vt_4t_32w_mult_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - const int8_t *filter, int32_t height, - int32_t width) +static void common_vt_4t_32w_msa(uint8_t *src, int32_t src_stride, + uint8_t *dst, int32_t dst_stride, + const int8_t *filter, int32_t height) { - uint32_t loop_cnt, cnt; - uint8_t *dst_tmp, *src_tmp; + uint32_t loop_cnt; v16i8 src0, src1, src2, src3, src4, src6, src7, src8, src9, src10; v16i8 src10_r, src32_r, src76_r, src98_r; v16i8 src21_r, src43_r, src87_r, src109_r; @@ -2683,93 +3012,77 @@ static void common_vt_4t_32w_mult_msa(uint8_t *src, int32_t src_stride, filt = LD_SH(filter); SPLATI_H2_SB(filt, 0, 1, filt0, filt1); - for (cnt = (width >> 5); cnt--;) { - dst_tmp = dst; - src_tmp = src; + /* 16 width */ + LD_SB3(src, src_stride, src0, src1, src2); + XORI_B3_128_SB(src0, src1, src2); + + ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); + ILVL_B2_SB(src1, src0, src2, src1, src10_l, src21_l); + + /* next 16 width */ + LD_SB3(src + 16, src_stride, src6, src7, src8); + src += (3 * src_stride); + + XORI_B3_128_SB(src6, src7, src8); + ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); + ILVL_B2_SB(src7, src6, src8, src7, src76_l, src87_l); + for (loop_cnt = (height >> 1); loop_cnt--;) { /* 16 width */ - LD_SB3(src_tmp, src_stride, src0, src1, src2); - XORI_B3_128_SB(src0, src1, src2); + LD_SB2(src, src_stride, src3, src4); + XORI_B2_128_SB(src3, src4); + ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); + ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); + + /* 16 width */ + out0_r = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + out0_l = HEVC_FILT_4TAP_SH(src10_l, src32_l, filt0, filt1); + out1_r = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + out1_l = HEVC_FILT_4TAP_SH(src21_l, src43_l, filt0, filt1); + + /* 16 width */ + SRARI_H4_SH(out0_r, out1_r, out0_l, out1_l, 6); + SAT_SH4_SH(out0_r, out1_r, out0_l, out1_l, 7); + out = PCKEV_XORI128_UB(out0_r, out0_l); + ST_UB(out, dst); + out = PCKEV_XORI128_UB(out1_r, out1_l); + ST_UB(out, dst + dst_stride); - ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); - ILVL_B2_SB(src1, src0, src2, src1, src10_l, src21_l); + src10_r = src32_r; + src21_r = src43_r; + src10_l = src32_l; + src21_l = src43_l; + src2 = src4; /* next 16 width */ - LD_SB3(src_tmp + 16, src_stride, src6, src7, src8); - src_tmp += (3 * src_stride); + LD_SB2(src + 16, src_stride, src9, src10); + src += (2 * src_stride); + XORI_B2_128_SB(src9, src10); + ILVR_B2_SB(src9, src8, src10, src9, src98_r, src109_r); + ILVL_B2_SB(src9, src8, src10, src9, src98_l, src109_l); - XORI_B3_128_SB(src6, src7, src8); - ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); - ILVL_B2_SB(src7, src6, src8, src7, src76_l, src87_l); - - for (loop_cnt = (height >> 1); loop_cnt--;) { - /* 16 width */ - LD_SB2(src_tmp, src_stride, src3, src4); - XORI_B2_128_SB(src3, src4); - ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); - ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); - - /* 16 width */ - out0_r = FILT_4TAP_DPADD_S_H(src10_r, src32_r, filt0, filt1); - out0_l = FILT_4TAP_DPADD_S_H(src10_l, src32_l, filt0, filt1); - out1_r = FILT_4TAP_DPADD_S_H(src21_r, src43_r, filt0, filt1); - out1_l = FILT_4TAP_DPADD_S_H(src21_l, src43_l, filt0, filt1); - - /* 16 width */ - SRARI_H4_SH(out0_r, out1_r, out0_l, out1_l, 6); - SAT_SH4_SH(out0_r, out1_r, out0_l, out1_l, 7); - out = PCKEV_XORI128_UB(out0_r, out0_l); - ST_UB(out, dst_tmp); - out = PCKEV_XORI128_UB(out1_r, out1_l); - ST_UB(out, dst_tmp + dst_stride); - - src10_r = src32_r; - src21_r = src43_r; - src10_l = src32_l; - src21_l = src43_l; - src2 = src4; - - /* next 16 width */ - LD_SB2(src_tmp + 16, src_stride, src9, src10); - src_tmp += (2 * src_stride); - XORI_B2_128_SB(src9, src10); - ILVR_B2_SB(src9, src8, src10, src9, src98_r, src109_r); - ILVL_B2_SB(src9, src8, src10, src9, src98_l, src109_l); - - /* next 16 width */ - out2_r = FILT_4TAP_DPADD_S_H(src76_r, src98_r, filt0, filt1); - out2_l = FILT_4TAP_DPADD_S_H(src76_l, src98_l, filt0, filt1); - out3_r = FILT_4TAP_DPADD_S_H(src87_r, src109_r, filt0, filt1); - out3_l = FILT_4TAP_DPADD_S_H(src87_l, src109_l, filt0, filt1); - - /* next 16 width */ - SRARI_H4_SH(out2_r, out3_r, out2_l, out3_l, 6); - SAT_SH4_SH(out2_r, out3_r, out2_l, out3_l, 7); - out = PCKEV_XORI128_UB(out2_r, out2_l); - ST_UB(out, dst_tmp + 16); - out = PCKEV_XORI128_UB(out3_r, out3_l); - ST_UB(out, dst_tmp + 16 + dst_stride); - - dst_tmp += 2 * dst_stride; - - src76_r = src98_r; - src87_r = src109_r; - src76_l = src98_l; - src87_l = src109_l; - src8 = src10; - } + /* next 16 width */ + out2_r = HEVC_FILT_4TAP_SH(src76_r, src98_r, filt0, filt1); + out2_l = HEVC_FILT_4TAP_SH(src76_l, src98_l, filt0, filt1); + out3_r = HEVC_FILT_4TAP_SH(src87_r, src109_r, filt0, filt1); + out3_l = HEVC_FILT_4TAP_SH(src87_l, src109_l, filt0, filt1); - src += 32; - dst += 32; - } -} + /* next 16 width */ + SRARI_H4_SH(out2_r, out3_r, out2_l, out3_l, 6); + SAT_SH4_SH(out2_r, out3_r, out2_l, out3_l, 7); + out = PCKEV_XORI128_UB(out2_r, out2_l); + ST_UB(out, dst + 16); + out = PCKEV_XORI128_UB(out3_r, out3_l); + ST_UB(out, dst + 16 + dst_stride); -static void common_vt_4t_32w_msa(uint8_t *src, int32_t src_stride, - uint8_t *dst, int32_t dst_stride, - const int8_t *filter, int32_t height) -{ - common_vt_4t_32w_mult_msa(src, src_stride, dst, dst_stride, - filter, height, 32); + dst += 2 * dst_stride; + + src76_r = src98_r; + src87_r = src109_r; + src76_l = src98_l; + src87_l = src109_l; + src8 = src10; + } } static void hevc_hv_uni_4t_4x2_msa(uint8_t *src, @@ -2777,19 +3090,18 @@ static void hevc_hv_uni_4t_4x2_msa(uint8_t *src, uint8_t *dst, int32_t dst_stride, const int8_t *filter_x, - const int8_t *filter_y, - int32_t height) + const int8_t *filter_y) { + v16u8 out; v16i8 src0, src1, src2, src3, src4; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; - v8i16 filter_vec, const_vec; + v8i16 filter_vec, tmp; v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4; - v4i32 dst0_r, dst1_r; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; + v8i16 dst20, dst31, dst42, dst10, dst32, dst21, dst43; + v4i32 dst0, dst1; src -= (src_stride + 1); @@ -2797,60 +3109,35 @@ static void hevc_hv_uni_4t_4x2_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); - - XORI_B3_128_SB(src0, src1, src2); - - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); - LD_SB2(src, src_stride, src3, src4); - XORI_B2_128_SB(src3, src4); - - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - - dst0_r = (v4i32) __msa_pckev_h((v8i16) dst1_r, (v8i16) dst0_r); - dst0_r = (v4i32) __msa_srari_h((v8i16) dst0_r, 6); - dst0_r = (v4i32) CLIP_SH_0_255(dst0_r); - dst0_r = (v4i32) __msa_pckev_b((v16i8) dst0_r, (v16i8) dst0_r); + LD_SB5(src, src_stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); - ST4x2_UB(dst0_r, dst, dst_stride); + VSHF_B2_SB(src0, src2, src0, src2, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src3, src1, src3, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src4, src2, src4, mask0, mask1, vec4, vec5); + + dst20 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst31 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst42 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + + ILVRL_H2_SH(dst31, dst20, dst10, dst32); + ILVRL_H2_SH(dst42, dst31, dst21, dst43); + + dst0 = HEVC_FILT_4TAP(dst10, dst32, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21, dst43, filt_h0, filt_h1); + dst0 >>= 6; + dst1 >>= 6; + tmp = __msa_pckev_h((v8i16) dst1, (v8i16) dst0); + tmp = __msa_srari_h(tmp, 6); + tmp = __msa_sat_s_h(tmp, 7); + out = PCKEV_XORI128_UB(tmp, tmp); + ST4x2_UB(out, dst, dst_stride); } static void hevc_hv_uni_4t_4x4_msa(uint8_t *src, @@ -2858,20 +3145,19 @@ static void hevc_hv_uni_4t_4x4_msa(uint8_t *src, uint8_t *dst, int32_t dst_stride, const int8_t *filter_x, - const int8_t *filter_y, - int32_t height) + const int8_t *filter_y) { + v16u8 out; v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r; - v8i16 out0_r, out1_r; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 filter_vec, tmp0, tmp1; + v8i16 dst30, dst41, dst52, dst63; + v8i16 dst10, dst32, dst54, dst21, dst43, dst65; + v4i32 dst0, dst1, dst2, dst3; src -= (src_stride + 1); @@ -2879,78 +3165,38 @@ static void hevc_hv_uni_4t_4x4_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); - - XORI_B3_128_SB(src0, src1, src2); - - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); - LD_SB4(src, src_stride, src3, src4, src5, src6); - XORI_B4_128_SB(src3, src4, src5, src6); - - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - dst10_r = __msa_ilvr_h(dst5, dst4); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_r >>= 6; - - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - dst21_r = __msa_ilvr_h(dst2, dst5); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_r >>= 6; - - PCKEV_H2_SH(dst1_r, dst0_r, dst3_r, dst2_r, out0_r, out1_r); - SRARI_H2_SH(out0_r, out1_r, 6); - CLIP_SH2_0_255(out0_r, out1_r); - out0_r = (v8i16) __msa_pckev_b((v16i8) out1_r, (v16i8) out0_r); + LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); - ST4x4_UB(out0_r, out0_r, 0, 1, 2, 3, dst, dst_stride); + VSHF_B2_SB(src0, src3, src0, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src4, src1, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src5, src2, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src6, src3, src6, mask0, mask1, vec6, vec7); + + dst30 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst41 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst52 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst63 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + ILVRL_H2_SH(dst41, dst30, dst10, dst43); + ILVRL_H2_SH(dst52, dst41, dst21, dst54); + ILVRL_H2_SH(dst63, dst52, dst32, dst65); + dst0 = HEVC_FILT_4TAP(dst10, dst32, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21, dst43, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32, dst54, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43, dst65, filt_h0, filt_h1); + SRA_4V(dst0, dst1, dst2, dst3, 6); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp0, tmp1); + SRARI_H2_SH(tmp0, tmp1, 6); + SAT_SH2_SH(tmp0, tmp1, 7); + out = PCKEV_XORI128_UB(tmp0, tmp1); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); } static void hevc_hv_uni_4t_4multx8mult_msa(uint8_t *src, @@ -2962,19 +3208,20 @@ static void hevc_hv_uni_4t_4multx8mult_msa(uint8_t *src, int32_t height) { uint32_t loop_cnt; + v16u8 out0, out1; v16i8 src0, src1, src2, src3, src4, src5; v16i8 src6, src7, src8, src9, src10; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8, dst9; + v8i16 filter_vec, tmp0, tmp1, tmp2, tmp3; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dst10, dst21, dst22, dst73, dst84, dst95, dst106; v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r, dst6_r, dst7_r; v8i16 dst10_r, dst32_r, dst54_r, dst76_r; v8i16 dst21_r, dst43_r, dst65_r, dst87_r; - v8i16 out0_r, out1_r, out2_r, out3_r; + v8i16 dst98_r, dst109_r; src -= (src_stride + 1); @@ -2982,33 +3229,23 @@ static void hevc_hv_uni_4t_4multx8mult_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - LD_SB3(src, src_stride, src0, src1, src2); src += (3 * src_stride); XORI_B3_128_SB(src0, src1, src2); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); + VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src2, src1, src2, mask0, mask1, vec2, vec3); + dst10 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst21 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + ILVRL_H2_SH(dst21, dst10, dst10_r, dst21_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst21, 1); for (loop_cnt = height >> 3; loop_cnt--;) { LD_SB8(src, src_stride, @@ -3017,88 +3254,46 @@ static void hevc_hv_uni_4t_4multx8mult_msa(uint8_t *src, XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src3, src7, src3, src7, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src8, src4, src8, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src9, src5, src9, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src10, src6, src10, mask0, mask1, vec6, vec7); - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; + dst73 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst84 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst95 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst106 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); + dst32_r = __msa_ilvr_h(dst73, dst22); + ILVRL_H2_SH(dst84, dst73, dst43_r, dst87_r); + ILVRL_H2_SH(dst95, dst84, dst54_r, dst98_r); + ILVRL_H2_SH(dst106, dst95, dst65_r, dst109_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst73, 1); + dst76_r = __msa_ilvr_h(dst22, dst106); - dst43_r = __msa_ilvr_h(dst4, dst3); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - dst54_r = __msa_ilvr_h(dst5, dst4); dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); - dst2_r >>= 6; - - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - - dst65_r = __msa_ilvr_h(dst6, dst5); dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); - dst3_r >>= 6; - - /* row 7 */ - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); - - dst76_r = __msa_ilvr_h(dst7, dst6); dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); - dst4_r >>= 6; - - /* row 8 */ - VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec0, vec1); - dst8 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst8, dst8); - - dst87_r = __msa_ilvr_h(dst8, dst7); dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); - dst5_r >>= 6; - - /* row 9 */ - VSHF_B2_SB(src9, src9, src9, src9, mask0, mask1, vec0, vec1); - dst9 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst9, dst9); - - dst10_r = __msa_ilvr_h(dst9, dst8); - dst6_r = HEVC_FILT_4TAP(dst76_r, dst10_r, filt_h0, filt_h1); - dst6_r >>= 6; - - /* row 10 */ - VSHF_B2_SB(src10, src10, src10, src10, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - dst21_r = __msa_ilvr_h(dst2, dst9); - dst7_r = HEVC_FILT_4TAP(dst87_r, dst21_r, filt_h0, filt_h1); - dst7_r >>= 6; - + dst6_r = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7_r = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRA_4V(dst4_r, dst5_r, dst6_r, dst7_r, 6); PCKEV_H4_SH(dst1_r, dst0_r, dst3_r, dst2_r, dst5_r, dst4_r, dst7_r, dst6_r, - out0_r, out1_r, out2_r, out3_r); - - SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); - CLIP_SH4_0_255(out0_r, out1_r, out2_r, out3_r); - - PCKEV_B2_SH(out1_r, out0_r, out3_r, out2_r, out0_r, out1_r); - ST4x8_UB(out0_r, out1_r, dst, dst_stride); + tmp0, tmp1, tmp2, tmp3); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 6); + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + ST4x8_UB(out0, out1, dst, dst_stride); dst += (8 * dst_stride); + + dst10_r = dst98_r; + dst21_r = dst109_r; + dst22 = (v8i16) __msa_splati_d((v2i64) dst106, 1); } } @@ -3112,10 +3307,10 @@ static void hevc_hv_uni_4t_4w_msa(uint8_t *src, { if (2 == height) { hevc_hv_uni_4t_4x2_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height); + filter_x, filter_y); } else if (4 == height) { hevc_hv_uni_4t_4x4_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height); + filter_x, filter_y); } else if (0 == (height % 8)) { hevc_hv_uni_4t_4multx8mult_msa(src, src_stride, dst, dst_stride, filter_x, filter_y, height); @@ -3130,19 +3325,23 @@ static void hevc_hv_uni_4t_6w_msa(uint8_t *src, const int8_t *filter_y, int32_t height) { - uint32_t loop_cnt; + v16u8 out0, out1, out2; v16i8 src0, src1, src2, src3, src4, src5, src6; + v16i8 src7, src8, src9, src10; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; + v8i16 filt_h0, filt_h1, filter_vec; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6, dsth7, dsth8, dsth9; + v8i16 dsth10, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + v4i32 dst4_r, dst5_r, dst6_r, dst7_r; v8i16 dst10_r, dst32_r, dst21_r, dst43_r; v8i16 dst10_l, dst32_l, dst21_l, dst43_l; - v8i16 out0_r, out1_r, out2_r, out3_r; + v8i16 dst54_r, dst76_r, dst98_r, dst65_r, dst87_r, dst109_r; + v8i16 dst98_l, dst65_l, dst54_l, dst76_l, dst87_l, dst109_l; + v8i16 dst1021_l, dst3243_l, dst5465_l, dst7687_l, dst98109_l; src -= (src_stride + 1); @@ -3150,16 +3349,12 @@ static void hevc_hv_uni_4t_6w_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - LD_SB3(src, src_stride, src0, src1, src2); src += (3 * src_stride); @@ -3169,96 +3364,94 @@ static void hevc_hv_uni_4t_6w_msa(uint8_t *src, VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + dsth0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); - ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); - ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); - for (loop_cnt = height >> 2; loop_cnt--;) { - LD_SB4(src, src_stride, src3, src4, src5, src6); - src += (4 * src_stride); + LD_SB8(src, src_stride, src3, src4, src5, src6, src7, src8, src9, src10); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); - XORI_B4_128_SB(src3, src4, src5, src6); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + dsth3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src9, src9, src9, src9, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src10, src10, src10, src10, mask0, mask1, vec6, vec7); + + dsth7 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth8 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth9 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth10 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); + ILVRL_H2_SH(dsth7, dsth6, dst76_r, dst76_l); + ILVRL_H2_SH(dsth8, dsth7, dst87_r, dst87_l); + ILVRL_H2_SH(dsth9, dsth8, dst98_r, dst98_l); + ILVRL_H2_SH(dsth10, dsth9, dst109_r, dst109_l); + + PCKEV_D2_SH(dst21_l, dst10_l, dst43_l, dst32_l, dst1021_l, dst3243_l); + PCKEV_D2_SH(dst65_l, dst54_l, dst87_l, dst76_l, dst5465_l, dst7687_l); + dst98109_l = (v8i16) __msa_pckev_d((v2i64) dst109_l, (v2i64) dst98_l); - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - ILVRL_H2_SH(dst5, dst4, dst10_r, dst10_l); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_l = HEVC_FILT_4TAP(dst32_l, dst10_l, filt_h0, filt_h1); - - dst2_r >>= 6; - dst2_l >>= 6; - - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - ILVRL_H2_SH(dst2, dst5, dst21_r, dst21_l); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_l = HEVC_FILT_4TAP(dst43_l, dst21_l, filt_h0, filt_h1); - - dst3_r >>= 6; - dst3_l >>= 6; - - PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - out0_r, out1_r, out2_r, out3_r); - - SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); - CLIP_SH4_0_255(out0_r, out1_r, out2_r, out3_r); - - PCKEV_B2_SH(out1_r, out0_r, out3_r, out2_r, out0_r, out1_r); - ST6x4_UB(out0_r, out1_r, dst, dst_stride); - dst += (4 * dst_stride); - } -} + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6_r = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7_r = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst1021_l, dst3243_l, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst3243_l, dst5465_l, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst5465_l, dst7687_l, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst7687_l, dst98109_l, filt_h0, filt_h1); + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRA_4V(dst4_r, dst5_r, dst6_r, dst7_r, 6); + SRA_4V(dst0_l, dst1_l, dst2_l, dst3_l, 6); + PCKEV_H2_SH(dst1_r, dst0_r, dst3_r, dst2_r, tmp0, tmp1); + PCKEV_H2_SH(dst5_r, dst4_r, dst7_r, dst6_r, tmp2, tmp3); + PCKEV_H2_SH(dst1_l, dst0_l, dst3_l, dst2_l, tmp4, tmp5); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 6); + SRARI_H2_SH(tmp4, tmp5, 6); + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3,7); + SAT_SH2_SH(tmp4, tmp5,7); + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + out2 = PCKEV_XORI128_UB(tmp4, tmp5); + ST4x8_UB(out0, out1, dst, dst_stride); + ST2x4_UB(out2, 0, dst + 4, dst_stride); + dst += 4 * dst_stride; + ST2x4_UB(out2, 4, dst + 4, dst_stride); +} static void hevc_hv_uni_4t_8x2_msa(uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter_x, - const int8_t *filter_y, - int32_t height) + const int8_t *filter_y) { + v16u8 out; v16i8 src0, src1, src2, src3, src4; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1, filter_vec; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; v8i16 dst0, dst1, dst2, dst3, dst4; v4i32 dst0_r, dst0_l, dst1_r, dst1_l; v8i16 dst10_r, dst32_r, dst21_r, dst43_r; @@ -3271,66 +3464,125 @@ static void hevc_hv_uni_4t_8x2_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); - - XORI_B3_128_SB(src0, src1, src2); + LD_SB5(src, src_stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec8, vec9); + + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec8, vec9, filt0, filt1); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - - LD_SB2(src, src_stride, src3, src4); - XORI_B2_128_SB(src3, src4); - - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); PCKEV_H2_SH(dst0_l, dst0_r, dst1_l, dst1_r, out0_r, out1_r); SRARI_H2_SH(out0_r, out1_r, 6); - CLIP_SH2_0_255(out0_r, out1_r); - out0_r = (v8i16) __msa_pckev_b((v16i8) out1_r, (v16i8) out0_r); + SAT_SH2_SH(out0_r, out1_r, 7); + out = PCKEV_XORI128_UB(out0_r, out1_r); + ST8x2_UB(out, dst, dst_stride); +} + +static void hevc_hv_uni_4t_8multx4_msa(uint8_t *src, + int32_t src_stride, + uint8_t *dst, + int32_t dst_stride, + const int8_t *filter_x, + const int8_t *filter_y, + int32_t width8mult) +{ + uint32_t cnt; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, mask0, mask1; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 filt0, filt1, filt_h0, filt_h1, filter_vec; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, tmp0, tmp1, tmp2, tmp3; + v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; + + src -= (src_stride + 1); + + filter_vec = LD_SH(filter_x); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + + for (cnt = width8mult; cnt--;) { + LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); + src += 8; + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + + ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); + ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - ST8x2_UB(out0_r, dst, dst_stride); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + + PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, tmp0, tmp1, tmp2, tmp3); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 6); + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + ST8x4_UB(out0, out1, dst, dst_stride); + dst += 8; + } } static void hevc_hv_uni_4t_8x6_msa(uint8_t *src, @@ -3338,16 +3590,16 @@ static void hevc_hv_uni_4t_8x6_msa(uint8_t *src, uint8_t *dst, int32_t dst_stride, const int8_t *filter_x, - const int8_t *filter_y, - int32_t height) + const int8_t *filter_y) { + v16u8 out0, out1, out2; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1, filter_vec; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; + v16i8 vec10, vec11, vec12, vec13, vec14, vec15, vec16, vec17; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; v4i32 dst4_r, dst4_l, dst5_r, dst5_l; @@ -3363,157 +3615,104 @@ static void hevc_hv_uni_4t_8x6_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); + LD_SB5(src, src_stride, src0, src1, src2, src3, src4); + src += (5 * src_stride); + LD_SB4(src, src_stride, src5, src6, src7, src8); - XORI_B3_128_SB(src0, src1, src2); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B4_128_SB(src5, src6, src7, src8); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec8, vec9); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec10, vec11); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec12, vec13); + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec14, vec15); + VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec16, vec17); + + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec8, vec9, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec10, vec11, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec12, vec13, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(vec14, vec15, filt0, filt1); + dst8 = HEVC_FILT_4TAP_SH(vec16, vec17, filt0, filt1); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - - LD_SB2(src, src_stride, src3, src4); - src += (2 * src_stride); - - XORI_B2_128_SB(src3, src4); - - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); + ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - - dst0_r >>= 6; - dst0_l >>= 6; - - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - - LD_SB2(src, src_stride, src5, src6); - src += (2 * src_stride); - - XORI_B2_128_SB(src5, src6); - - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; - - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - - ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; - - LD_SB2(src, src_stride, src7, src8); - src += (2 * src_stride); - - XORI_B2_128_SB(src7, src8); - - /* row 7 */ - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); - - ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); dst4_l = HEVC_FILT_4TAP(dst54_l, dst76_l, filt_h0, filt_h1); - - dst4_r >>= 6; - dst4_l >>= 6; - - /* row 8 */ - VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec0, vec1); - dst8 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst8, dst8); - - ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); dst5_l = HEVC_FILT_4TAP(dst65_l, dst87_l, filt_h0, filt_h1); - dst5_r >>= 6; - dst5_l >>= 6; + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + SRA_4V(dst4_r, dst4_l, dst5_r, dst5_l, 6); PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, dst3_r, out0_r, out1_r, out2_r, out3_r); PCKEV_H2_SH(dst4_l, dst4_r, dst5_l, dst5_r, out4_r, out5_r); SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); SRARI_H2_SH(out4_r, out5_r, 6); - CLIP_SH4_0_255(out0_r, out1_r, out2_r, out3_r); - CLIP_SH2_0_255(out4_r, out5_r); + SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); + SAT_SH2_SH(out4_r, out5_r, 7); + out0 = PCKEV_XORI128_UB(out0_r, out1_r); + out1 = PCKEV_XORI128_UB(out2_r, out3_r); + out2 = PCKEV_XORI128_UB(out4_r, out5_r); - PCKEV_B2_SH(out1_r, out0_r, out3_r, out2_r, out0_r, out1_r); - out2_r = (v8i16) __msa_pckev_b((v16i8) out5_r, (v16i8) out4_r); - - ST8x4_UB(out0_r, out1_r, dst, dst_stride); + ST8x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); - ST8x2_UB(out2_r, dst, dst_stride); + ST8x2_UB(out2, dst, dst_stride); } -static void hevc_hv_uni_4t_8w_mult_msa(uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - const int8_t *filter_x, - const int8_t *filter_y, - int32_t height, - int32_t width) +static void hevc_hv_uni_4t_8multx4mult_msa(uint8_t *src, + int32_t src_stride, + uint8_t *dst, + int32_t dst_stride, + const int8_t *filter_x, + const int8_t *filter_y, + int32_t height, + int32_t width8mult) { uint32_t loop_cnt, cnt; uint8_t *src_tmp; uint8_t *dst_tmp; + v16u8 out0, out1; v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1, filter_vec; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; v8i16 dst10_r, dst32_r, dst21_r, dst43_r; v8i16 dst10_l, dst32_l, dst21_l, dst43_l; + v8i16 dst54_r, dst54_l, dst65_r, dst65_l, dst6; v8i16 out0_r, out1_r, out2_r, out3_r; src -= (src_stride + 1); @@ -3522,17 +3721,13 @@ static void hevc_hv_uni_4t_8w_mult_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - - for (cnt = width >> 3; cnt--;) { + for (cnt = width8mult; cnt--;) { src_tmp = src; dst_tmp = dst; @@ -3545,79 +3740,62 @@ static void hevc_hv_uni_4t_8w_mult_msa(uint8_t *src, VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - for (loop_cnt = height >> 2; loop_cnt--;) { + for (loop_cnt = (height >> 2); loop_cnt--;) { LD_SB4(src_tmp, src_stride, src3, src4, src5, src6); src_tmp += (4 * src_stride); XORI_B4_128_SB(src3, src4, src5, src6); - /* row 3 */ VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - - dst0_r >>= 6; - dst0_l >>= 6; - - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - ILVRL_H2_SH(dst5, dst4, dst10_r, dst10_l); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_l = HEVC_FILT_4TAP(dst32_l, dst10_l, filt_h0, filt_h1); - - dst2_r >>= 6; - dst2_l >>= 6; + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - ILVRL_H2_SH(dst2, dst5, dst21_r, dst21_l); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_l = HEVC_FILT_4TAP(dst43_l, dst21_l, filt_h0, filt_h1); - - dst3_r >>= 6; - dst3_l >>= 6; + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, dst3_r, out0_r, out1_r, out2_r, out3_r); SRARI_H4_SH(out0_r, out1_r, out2_r, out3_r, 6); - CLIP_SH4_0_255(out0_r, out1_r, out2_r, out3_r); - - PCKEV_B2_SH(out1_r, out0_r, out3_r, out2_r, out0_r, out1_r); - ST8x4_UB(out0_r, out1_r, dst_tmp, dst_stride); + SAT_SH4_SH(out0_r, out1_r, out2_r, out3_r, 7); + out0 = PCKEV_XORI128_UB(out0_r, out1_r); + out1 = PCKEV_XORI128_UB(out2_r, out3_r); + ST8x4_UB(out0, out1, dst_tmp, dst_stride); dst_tmp += (4 * dst_stride); + + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dst2 = dst6; } src += 8; @@ -3635,13 +3813,16 @@ static void hevc_hv_uni_4t_8w_msa(uint8_t *src, { if (2 == height) { hevc_hv_uni_4t_8x2_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height); + filter_x, filter_y); + } else if (4 == height) { + hevc_hv_uni_4t_8multx4_msa(src, src_stride, dst, dst_stride, + filter_x, filter_y, 1); } else if (6 == height) { hevc_hv_uni_4t_8x6_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height); + filter_x, filter_y); } else if (0 == (height % 4)) { - hevc_hv_uni_4t_8w_mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 8); + hevc_hv_uni_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, + filter_x, filter_y, height, 1); } } @@ -3653,11 +3834,164 @@ static void hevc_hv_uni_4t_12w_msa(uint8_t *src, const int8_t *filter_y, int32_t height) { - hevc_hv_uni_4t_8w_mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 8); + uint32_t loop_cnt; + uint8_t *src_tmp, *dst_tmp; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 mask0, mask1, mask2, mask3; + v8i16 filt0, filt1, filt_h0, filt_h1, filter_vec, tmp0, tmp1, tmp2, tmp3; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6; + v8i16 dst10, dst21, dst22, dst73, dst84, dst95, dst106; + v8i16 dst76_r, dst98_r, dst87_r, dst109_r; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; + v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + v4i32 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + + src -= (src_stride + 1); + + filter_vec = LD_SH(filter_x); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); - hevc_hv_uni_4t_4w_msa(src + 8, src_stride, dst + 8, dst_stride, - filter_x, filter_y, height); + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + + src_tmp = src; + dst_tmp = dst; + + LD_SB3(src_tmp, src_stride, src0, src1, src2); + src_tmp += (3 * src_stride); + + XORI_B3_128_SB(src0, src1, src2); + + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + + dsth0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src_tmp, src_stride, src3, src4, src5, src6); + src_tmp += (4 * src_stride); + XORI_B4_128_SB(src3, src4, src5, src6); + + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + + dsth3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); + + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + + PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, tmp0, tmp1, tmp2, tmp3); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 6); + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + ST8x4_UB(out0, out1, dst_tmp, dst_stride); + dst_tmp += (4 * dst_stride); + + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dsth2 = dsth6; + } + + src += 8; + dst += 8; + + mask2 = LD_SB(ff_hevc_mask_arr + 16); + mask3 = mask2 + 2; + + LD_SB3(src, src_stride, src0, src1, src2); + src += (3 * src_stride); + XORI_B3_128_SB(src0, src1, src2); + VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); + VSHF_B2_SB(src1, src2, src1, src2, mask2, mask3, vec2, vec3); + + dst10 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst21 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + + ILVRL_H2_SH(dst21, dst10, dst10_r, dst21_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst21, 1); + + for (loop_cnt = 2; loop_cnt--;) { + LD_SB8(src, src_stride, + src3, src4, src5, src6, src7, src8, src9, src10); + src += (8 * src_stride); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); + VSHF_B2_SB(src3, src7, src3, src7, mask2, mask3, vec0, vec1); + VSHF_B2_SB(src4, src8, src4, src8, mask2, mask3, vec2, vec3); + VSHF_B2_SB(src5, src9, src5, src9, mask2, mask3, vec4, vec5); + VSHF_B2_SB(src6, src10, src6, src10, mask2, mask3, vec6, vec7); + + dst73 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst84 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst95 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst106 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + dst32_r = __msa_ilvr_h(dst73, dst22); + ILVRL_H2_SH(dst84, dst73, dst43_r, dst87_r); + ILVRL_H2_SH(dst95, dst84, dst54_r, dst98_r); + ILVRL_H2_SH(dst106, dst95, dst65_r, dst109_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst73, 1); + dst76_r = __msa_ilvr_h(dst22, dst106); + + dst0 = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4 = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5 = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6 = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7 = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + SRA_4V(dst0, dst1, dst2, dst3, 6); + SRA_4V(dst4, dst5, dst6, dst7, 6); + PCKEV_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, + tmp0, tmp1, tmp2, tmp3); + SRARI_H4_SH(tmp0, tmp1, tmp2, tmp3, 6); + SAT_SH4_SH(tmp0, tmp1, tmp2, tmp3, 7); + out0 = PCKEV_XORI128_UB(tmp0, tmp1); + out1 = PCKEV_XORI128_UB(tmp2, tmp3); + ST4x8_UB(out0, out1, dst, dst_stride); + dst += (8 * dst_stride); + + dst10_r = dst98_r; + dst21_r = dst109_r; + dst22 = (v8i16) __msa_splati_d((v2i64) dst106, 1); + } } static void hevc_hv_uni_4t_16w_msa(uint8_t *src, @@ -3668,8 +4002,13 @@ static void hevc_hv_uni_4t_16w_msa(uint8_t *src, const int8_t *filter_y, int32_t height) { - hevc_hv_uni_4t_8w_mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 16); + if (4 == height) { + hevc_hv_uni_4t_8multx4_msa(src, src_stride, dst, dst_stride, filter_x, + filter_y, 2); + } else { + hevc_hv_uni_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, + filter_x, filter_y, height, 2); + } } static void hevc_hv_uni_4t_24w_msa(uint8_t *src, @@ -3680,8 +4019,8 @@ static void hevc_hv_uni_4t_24w_msa(uint8_t *src, const int8_t *filter_y, int32_t height) { - hevc_hv_uni_4t_8w_mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 24); + hevc_hv_uni_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, + filter_x, filter_y, height, 3); } static void hevc_hv_uni_4t_32w_msa(uint8_t *src, @@ -3692,8 +4031,8 @@ static void hevc_hv_uni_4t_32w_msa(uint8_t *src, const int8_t *filter_y, int32_t height) { - hevc_hv_uni_4t_8w_mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 32); + hevc_hv_uni_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, + filter_x, filter_y, height, 4); } #define UNI_MC_COPY(WIDTH) \ @@ -3721,15 +4060,13 @@ UNI_MC_COPY(64); #define UNI_MC(PEL, DIR, WIDTH, TAP, DIR1, FILT_DIR) \ void ff_hevc_put_hevc_uni_##PEL##_##DIR##WIDTH##_8_msa(uint8_t *dst, \ - ptrdiff_t \ - dst_stride, \ - uint8_t *src, \ - ptrdiff_t \ - src_stride, \ - int height, \ - intptr_t mx, \ - intptr_t my, \ - int width) \ + ptrdiff_t dst_stride, \ + uint8_t *src, \ + ptrdiff_t src_stride, \ + int height, \ + intptr_t mx, \ + intptr_t my, \ + int width) \ { \ const int8_t *filter = ff_hevc_##PEL##_filters[FILT_DIR - 1]; \ \ @@ -3773,41 +4110,38 @@ UNI_MC(epel, v, 32, 4, vt, my); #undef UNI_MC -#define UNI_MC_HV(PEL, DIR, WIDTH, TAP, DIR1) \ -void ff_hevc_put_hevc_uni_##PEL##_##DIR##WIDTH##_8_msa(uint8_t *dst, \ - ptrdiff_t \ - dst_stride, \ - uint8_t *src, \ - ptrdiff_t \ - src_stride, \ - int height, \ - intptr_t mx, \ - intptr_t my, \ - int width) \ -{ \ - const int8_t *filter_x = ff_hevc_##PEL##_filters[mx - 1]; \ - const int8_t *filter_y = ff_hevc_##PEL##_filters[my - 1]; \ - \ - hevc_##DIR1##_uni_##TAP##t_##WIDTH##w_msa(src, src_stride, dst, \ - dst_stride, filter_x, \ - filter_y, height); \ -} - -UNI_MC_HV(qpel, hv, 4, 8, hv); -UNI_MC_HV(qpel, hv, 8, 8, hv); -UNI_MC_HV(qpel, hv, 12, 8, hv); -UNI_MC_HV(qpel, hv, 16, 8, hv); -UNI_MC_HV(qpel, hv, 24, 8, hv); -UNI_MC_HV(qpel, hv, 32, 8, hv); -UNI_MC_HV(qpel, hv, 48, 8, hv); -UNI_MC_HV(qpel, hv, 64, 8, hv); - -UNI_MC_HV(epel, hv, 4, 4, hv); -UNI_MC_HV(epel, hv, 6, 4, hv); -UNI_MC_HV(epel, hv, 8, 4, hv); -UNI_MC_HV(epel, hv, 12, 4, hv); -UNI_MC_HV(epel, hv, 16, 4, hv); -UNI_MC_HV(epel, hv, 24, 4, hv); -UNI_MC_HV(epel, hv, 32, 4, hv); +#define UNI_MC_HV(PEL, WIDTH, TAP) \ +void ff_hevc_put_hevc_uni_##PEL##_hv##WIDTH##_8_msa(uint8_t *dst, \ + ptrdiff_t dst_stride, \ + uint8_t *src, \ + ptrdiff_t src_stride, \ + int height, \ + intptr_t mx, \ + intptr_t my, \ + int width) \ +{ \ + const int8_t *filter_x = ff_hevc_##PEL##_filters[mx - 1]; \ + const int8_t *filter_y = ff_hevc_##PEL##_filters[my - 1]; \ + \ + hevc_hv_uni_##TAP##t_##WIDTH##w_msa(src, src_stride, dst, dst_stride, \ + filter_x, filter_y, height); \ +} + +UNI_MC_HV(qpel, 4, 8); +UNI_MC_HV(qpel, 8, 8); +UNI_MC_HV(qpel, 12, 8); +UNI_MC_HV(qpel, 16, 8); +UNI_MC_HV(qpel, 24, 8); +UNI_MC_HV(qpel, 32, 8); +UNI_MC_HV(qpel, 48, 8); +UNI_MC_HV(qpel, 64, 8); + +UNI_MC_HV(epel, 4, 4); +UNI_MC_HV(epel, 6, 4); +UNI_MC_HV(epel, 8, 4); +UNI_MC_HV(epel, 12, 4); +UNI_MC_HV(epel, 16, 4); +UNI_MC_HV(epel, 24, 4); +UNI_MC_HV(epel, 32, 4); #undef UNI_MC_HV diff --git a/libavcodec/mips/hevc_mc_uniw_msa.c b/libavcodec/mips/hevc_mc_uniw_msa.c index 7c01c32d5749a..f9ecb414ba95a 100644 --- a/libavcodec/mips/hevc_mc_uniw_msa.c +++ b/libavcodec/mips/hevc_mc_uniw_msa.c @@ -29,46 +29,6 @@ static const uint8_t ff_hevc_mask_arr[16 * 2] __attribute__((aligned(0x40))) = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; -#define HEVC_HV_UNIW_RND_CLIP4(in0, in1, in2, in3, wgt, offset, rnd, \ - out0, out1, out2, out3) \ -{ \ - MUL4(in0, wgt, in1, wgt, in2, wgt, in3, wgt, out0, out1, out2, out3); \ - SRAR_W4_SW(out0, out1, out2, out3, rnd); \ - ADD4(out0, offset, out1, offset, out2, offset, out3, offset, \ - out0, out1, out2, out3); \ - out0 = CLIP_SW_0_255(out0); \ - out1 = CLIP_SW_0_255(out1); \ - out2 = CLIP_SW_0_255(out2); \ - out3 = CLIP_SW_0_255(out3); \ -} - -#define HEVC_UNIW_RND_CLIP2(in0, in1, wgt, offset, rnd, \ - out0_r, out1_r, out0_l, out1_l) \ -{ \ - ILVR_H2_SW(in0, in0, in1, in1, out0_r, out1_r); \ - ILVL_H2_SW(in0, in0, in1, in1, out0_l, out1_l); \ - DOTP_SH4_SW(out0_r, out1_r, out0_l, out1_l, wgt, wgt, wgt, wgt, \ - out0_r, out1_r, out0_l, out1_l); \ - SRAR_W4_SW(out0_r, out1_r, out0_l, out1_l, rnd); \ - ADD4(out0_r, offset, out1_r, offset, \ - out0_l, offset, out1_l, offset, \ - out0_r, out1_r, out0_l, out1_l); \ - out0_r = CLIP_SW_0_255(out0_r); \ - out1_r = CLIP_SW_0_255(out1_r); \ - out0_l = CLIP_SW_0_255(out0_l); \ - out1_l = CLIP_SW_0_255(out1_l); \ -} - -#define HEVC_UNIW_RND_CLIP4(in0, in1, in2, in3, wgt, offset, rnd, \ - out0_r, out1_r, out2_r, out3_r, \ - out0_l, out1_l, out2_l, out3_l) \ -{ \ - HEVC_UNIW_RND_CLIP2(in0, in1, wgt, offset, rnd, \ - out0_r, out1_r, out0_l, out1_l); \ - HEVC_UNIW_RND_CLIP2(in2, in3, wgt, offset, rnd, \ - out2_r, out3_r, out2_l, out3_l); \ -} - #define HEVC_UNIW_RND_CLIP2_MAX_SATU_H(in0_h, in1_h, wgt_w, offset_h, rnd_w, \ out0_h, out1_h) \ { \ @@ -1337,6 +1297,7 @@ static void hevc_vt_uniwgt_8t_4w_msa(uint8_t *src, int32_t rnd_val) { int32_t loop_cnt; + v16u8 out0, out1; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v16i8 src9, src10, src11, src12, src13, src14; v16i8 src10_r, src32_r, src54_r, src76_r, src98_r; @@ -1344,21 +1305,27 @@ static void hevc_vt_uniwgt_8t_4w_msa(uint8_t *src, v16i8 src1110_r, src1211_r, src1312_r, src1413_r; v16i8 src2110, src4332, src6554, src8776, src10998; v16i8 src12111110, src14131312; - v8i16 dst10, dst32, dst54, dst76; + v8i16 filter_vec, dst01, dst23, dst45, dst67; v8i16 filt0, filt1, filt2, filt3; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 dst0, dst1, dst2, dst3, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= (3 * src_stride); - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight = weight & 0x0000FFFF; + weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); @@ -1387,28 +1354,21 @@ static void hevc_vt_uniwgt_8t_4w_msa(uint8_t *src, src1413_r, src1312_r, src8776, src10998, src12111110, src14131312); XORI_B4_128_SB(src8776, src10998, src12111110, src14131312); + dst01 = HEVC_FILT_8TAP_SH(src2110, src4332, src6554, src8776, filt0, + filt1, filt2, filt3); + dst23 = HEVC_FILT_8TAP_SH(src4332, src6554, src8776, src10998, filt0, + filt1, filt2, filt3); + dst45 = HEVC_FILT_8TAP_SH(src6554, src8776, src10998, src12111110, + filt0, filt1, filt2, filt3); + dst67 = HEVC_FILT_8TAP_SH(src8776, src10998, src12111110, src14131312, + filt0, filt1, filt2, filt3); - dst10 = const_vec; - DPADD_SB4_SH(src2110, src4332, src6554, src8776, filt0, filt1, - filt2, filt3, dst10, dst10, dst10, dst10); - dst32 = const_vec; - DPADD_SB4_SH(src4332, src6554, src8776, src10998, - filt0, filt1, filt2, filt3, dst32, dst32, dst32, dst32); - dst54 = const_vec; - DPADD_SB4_SH(src6554, src8776, src10998, src12111110, - filt0, filt1, filt2, filt3, dst54, dst54, dst54, dst54); - dst76 = const_vec; - DPADD_SB4_SH(src8776, src10998, src12111110, src14131312, - filt0, filt1, filt2, filt3, dst76, dst76, dst76, dst76); - - HEVC_UNIW_RND_CLIP4(dst10, dst32, dst54, dst76, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST4x8_UB(dst0_r, dst1_r, dst, dst_stride); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst01, dst23, dst45, dst67, weight_vec, + offset_vec, rnd_vec, dst0, dst1, dst2, + dst3); + + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); dst += (8 * dst_stride); src2110 = src10998; @@ -1429,24 +1389,30 @@ static void hevc_vt_uniwgt_8t_8w_msa(uint8_t *src, int32_t rnd_val) { int32_t loop_cnt; + v16u8 out0, out1; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v16i8 src10_r, src32_r, src54_r, src76_r, src98_r; v16i8 src21_r, src43_r, src65_r, src87_r, src109_r; - v8i16 tmp0, tmp1, tmp2, tmp3; v8i16 filt0, filt1, filt2, filt3; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 filter_vec; + v8i16 dst0, dst1, dst2, dst3, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= (3 * src_stride); - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); @@ -1464,28 +1430,21 @@ static void hevc_vt_uniwgt_8t_8w_msa(uint8_t *src, XORI_B4_128_SB(src7, src8, src9, src10); ILVR_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, src76_r, src87_r, src98_r, src109_r); + dst0 = HEVC_FILT_8TAP_SH(src10_r, src32_r, src54_r, src76_r, filt0, + filt1, filt2, filt3); + dst1 = HEVC_FILT_8TAP_SH(src21_r, src43_r, src65_r, src87_r, filt0, + filt1, filt2, filt3); + dst2 = HEVC_FILT_8TAP_SH(src32_r, src54_r, src76_r, src98_r, filt0, + filt1, filt2, filt3); + dst3 = HEVC_FILT_8TAP_SH(src43_r, src65_r, src87_r, src109_r, filt0, + filt1, filt2, filt3); + + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, weight_vec, + offset_vec, rnd_vec, dst0, dst1, dst2, + dst3); - tmp0 = const_vec; - DPADD_SB4_SH(src10_r, src32_r, src54_r, src76_r, - filt0, filt1, filt2, filt3, tmp0, tmp0, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB4_SH(src21_r, src43_r, src65_r, src87_r, - filt0, filt1, filt2, filt3, tmp1, tmp1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB4_SH(src32_r, src54_r, src76_r, src98_r, - filt0, filt1, filt2, filt3, tmp2, tmp2, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB4_SH(src43_r, src65_r, src87_r, src109_r, - filt0, filt1, filt2, filt3, tmp3, tmp3, tmp3, tmp3); - - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + ST8x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); src10_r = src54_r; @@ -1509,28 +1468,34 @@ static void hevc_vt_uniwgt_8t_12w_msa(uint8_t *src, int32_t rnd_val) { int32_t loop_cnt; + v16u8 out0, out1, out2; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v16i8 src10_r, src32_r, src54_r, src76_r, src98_r; v16i8 src21_r, src43_r, src65_r, src87_r, src109_r; - v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; v16i8 src10_l, src32_l, src54_l, src76_l, src98_l; v16i8 src21_l, src43_l, src65_l, src87_l, src109_l; v16i8 src2110, src4332, src6554, src8776, src10998; v8i16 filt0, filt1, filt2, filt3; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5; + v8i16 weight_vec_h, offset_vec, denom_vec, filter_vec; + v4i32 weight_vec, rnd_vec; src -= (3 * src_stride); - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); @@ -1547,7 +1512,7 @@ static void hevc_vt_uniwgt_8t_12w_msa(uint8_t *src, ILVR_D3_SB(src21_l, src10_l, src43_l, src32_l, src65_l, src54_l, src2110, src4332, src6554); - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = 4; loop_cnt--;) { LD_SB4(src, src_stride, src7, src8, src9, src10); src += (4 * src_stride); XORI_B4_128_SB(src7, src8, src9, src10); @@ -1558,37 +1523,28 @@ static void hevc_vt_uniwgt_8t_12w_msa(uint8_t *src, src76_l, src87_l, src98_l, src109_l); ILVR_D2_SB(src87_l, src76_l, src109_l, src98_l, src8776, src10998); - tmp0 = const_vec; - DPADD_SB4_SH(src10_r, src32_r, src54_r, src76_r, - filt0, filt1, filt2, filt3, tmp0, tmp0, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB4_SH(src21_r, src43_r, src65_r, src87_r, - filt0, filt1, filt2, filt3, tmp1, tmp1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB4_SH(src32_r, src54_r, src76_r, src98_r, - filt0, filt1, filt2, filt3, tmp2, tmp2, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB4_SH(src43_r, src65_r, src87_r, src109_r, - filt0, filt1, filt2, filt3, tmp3, tmp3, tmp3, tmp3); - tmp4 = const_vec; - DPADD_SB4_SH(src2110, src4332, src6554, src8776, - filt0, filt1, filt2, filt3, tmp4, tmp4, tmp4, tmp4); - tmp5 = const_vec; - DPADD_SB4_SH(src4332, src6554, src8776, src10998, - filt0, filt1, filt2, filt3, tmp5, tmp5, tmp5, tmp5); - - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - HEVC_UNIW_RND_CLIP2(tmp4, tmp5, weight_vec, offset_vec, rnd_vec, - dst4_r, dst5_r, dst4_l, dst5_l); - - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, - dst0_r, dst1_r, dst2_r); - ST12x4_UB(dst0_r, dst1_r, dst2_r, dst, dst_stride); + dst0 = HEVC_FILT_8TAP_SH(src10_r, src32_r, src54_r, src76_r, filt0, + filt1, filt2, filt3); + dst1 = HEVC_FILT_8TAP_SH(src21_r, src43_r, src65_r, src87_r, filt0, + filt1, filt2, filt3); + dst2 = HEVC_FILT_8TAP_SH(src32_r, src54_r, src76_r, src98_r, filt0, + filt1, filt2, filt3); + dst3 = HEVC_FILT_8TAP_SH(src43_r, src65_r, src87_r, src109_r, filt0, + filt1, filt2, filt3); + dst4 = HEVC_FILT_8TAP_SH(src2110, src4332, src6554, src8776, filt0, + filt1, filt2, filt3); + dst5 = HEVC_FILT_8TAP_SH(src4332, src6554, src8776, src10998, filt0, + filt1, filt2, filt3); + + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, weight_vec, + offset_vec, rnd_vec, dst0, dst1, dst2, + dst3); + HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst4, dst5, weight_vec, offset_vec, + rnd_vec, dst4, dst5); + + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + ST8x4_UB(out0, out1, dst, dst_stride); + ST4x4_UB(out2, out2, 0, 1, 2, 3, dst + 8, dst_stride); dst += (4 * dst_stride); src10_r = src54_r; @@ -1604,7 +1560,7 @@ static void hevc_vt_uniwgt_8t_12w_msa(uint8_t *src, } } -static void hevc_vt_uniwgt_8t_16multx2mult_msa(uint8_t *src, +static void hevc_vt_uniwgt_8t_16multx4mult_msa(uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, @@ -1613,91 +1569,101 @@ static void hevc_vt_uniwgt_8t_16multx2mult_msa(uint8_t *src, int32_t weight, int32_t offset, int32_t rnd_val, - int32_t width) + int32_t weightmul16) { uint8_t *src_tmp; uint8_t *dst_tmp; int32_t loop_cnt, cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16u8 out0, out1, out2, out3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v16i8 src10_r, src32_r, src54_r, src76_r; v16i8 src21_r, src43_r, src65_r, src87_r; - v8i16 tmp0, tmp1, tmp2, tmp3; v16i8 src10_l, src32_l, src54_l, src76_l; v16i8 src21_l, src43_l, src65_l, src87_l; + v16i8 src98_r, src109_r, src98_l, src109_l; v8i16 filt0, filt1, filt2, filt3; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 filter_vec; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= (3 * src_stride); - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); - for (cnt = (width >> 4); cnt--;) { + for (cnt = weightmul16; cnt--;) { src_tmp = src; dst_tmp = dst; LD_SB7(src_tmp, src_stride, src0, src1, src2, src3, src4, src5, src6); src_tmp += (7 * src_stride); XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); - ILVR_B4_SB(src1, src0, src3, src2, src5, src4, src2, src1, - src10_r, src32_r, src54_r, src21_r); - ILVR_B2_SB(src4, src3, src6, src5, src43_r, src65_r); - ILVL_B4_SB(src1, src0, src3, src2, src5, src4, src2, src1, - src10_l, src32_l, src54_l, src21_l); - ILVL_B2_SB(src4, src3, src6, src5, src43_l, src65_l); - - for (loop_cnt = (height >> 1); loop_cnt--;) { - LD_SB2(src_tmp, src_stride, src7, src8); - src_tmp += (2 * src_stride); - XORI_B2_128_SB(src7, src8); - ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); - ILVL_B2_SB(src7, src6, src8, src7, src76_l, src87_l); - - tmp0 = const_vec; - DPADD_SB4_SH(src10_r, src32_r, src54_r, src76_r, - filt0, filt1, filt2, filt3, tmp0, tmp0, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB4_SH(src21_r, src43_r, src65_r, src87_r, - filt0, filt1, filt2, filt3, tmp1, tmp1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB4_SH(src10_l, src32_l, src54_l, src76_l, - filt0, filt1, filt2, filt3, tmp2, tmp2, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB4_SH(src21_l, src43_l, src65_l, src87_l, - filt0, filt1, filt2, filt3, tmp3, tmp3, tmp3, tmp3); - - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst_tmp, dst_stride); - dst_tmp += (2 * dst_stride); - src10_r = src32_r; - src32_r = src54_r; - src54_r = src76_r; - src21_r = src43_r; - src43_r = src65_r; - src65_r = src87_r; - src10_l = src32_l; - src32_l = src54_l; - src54_l = src76_l; - src21_l = src43_l; - src43_l = src65_l; - src65_l = src87_l; - src6 = src8; + for (loop_cnt = (height >> 2); loop_cnt--;) { + LD_SB4(src_tmp, src_stride, src7, src8, src9, src10); + src_tmp += (4 * src_stride); + XORI_B4_128_SB(src7, src8, src9, src10); + + ILVR_B4_SB(src1, src0, src3, src2, src5, src4, src2, src1, + src10_r, src32_r, src54_r, src21_r); + ILVR_B2_SB(src4, src3, src6, src5, src43_r, src65_r); + ILVL_B4_SB(src1, src0, src3, src2, src5, src4, src2, src1, + src10_l, src32_l, src54_l, src21_l); + ILVL_B2_SB(src4, src3, src6, src5, src43_l, src65_l); + ILVR_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, + src76_r, src87_r, src98_r, src109_r); + ILVL_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, + src76_l, src87_l, src98_l, src109_l); + + dst0 = HEVC_FILT_8TAP_SH(src10_r, src32_r, src54_r, src76_r, filt0, + filt1, filt2, filt3); + dst1 = HEVC_FILT_8TAP_SH(src10_l, src32_l, src54_l, src76_l, filt0, + filt1, filt2, filt3); + dst2 = HEVC_FILT_8TAP_SH(src21_r, src43_r, src65_r, src87_r, filt0, + filt1, filt2, filt3); + dst3 = HEVC_FILT_8TAP_SH(src21_l, src43_l, src65_l, src87_l, filt0, + filt1, filt2, filt3); + dst4 = HEVC_FILT_8TAP_SH(src32_r, src54_r, src76_r, src98_r, filt0, + filt1, filt2, filt3); + dst5 = HEVC_FILT_8TAP_SH(src32_l, src54_l, src76_l, src98_l, filt0, + filt1, filt2, filt3); + dst6 = HEVC_FILT_8TAP_SH(src43_r, src65_r, src87_r, src109_r, filt0, + filt1, filt2, filt3); + dst7 = HEVC_FILT_8TAP_SH(src43_l, src65_l, src87_l, src109_l, filt0, + filt1, filt2, filt3); + + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, weight_vec, + offset_vec, rnd_vec, dst0, dst1, + dst2, dst3); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst4, dst5, dst6, dst7, weight_vec, + offset_vec, rnd_vec, dst4, dst5, + dst6, dst7); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); + ST_UB4(out0, out1, out2, out3, dst_tmp, dst_stride); + dst_tmp += (4 * dst_stride); + + src0 = src4; + src1 = src5; + src2 = src6; + src3 = src7; + src4 = src8; + src5 = src9; + src6 = src10; } src += 16; @@ -1715,9 +1681,9 @@ static void hevc_vt_uniwgt_8t_16w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - hevc_vt_uniwgt_8t_16multx2mult_msa(src, src_stride, dst, dst_stride, + hevc_vt_uniwgt_8t_16multx4mult_msa(src, src_stride, dst, dst_stride, filter, height, weight, - offset, rnd_val, 16); + offset, rnd_val, 1); } static void hevc_vt_uniwgt_8t_24w_msa(uint8_t *src, @@ -1730,12 +1696,12 @@ static void hevc_vt_uniwgt_8t_24w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - hevc_vt_uniwgt_8t_16multx2mult_msa(src, src_stride, dst, dst_stride, - filter, height, weight, - offset, rnd_val, 16); + hevc_vt_uniwgt_8t_16multx4mult_msa(src, src_stride, dst, dst_stride, + filter, 32, weight, + offset, rnd_val, 1); hevc_vt_uniwgt_8t_8w_msa(src + 16, src_stride, dst + 16, dst_stride, - filter, height, weight, offset, rnd_val); + filter, 32, weight, offset, rnd_val); } static void hevc_vt_uniwgt_8t_32w_msa(uint8_t *src, @@ -1748,9 +1714,9 @@ static void hevc_vt_uniwgt_8t_32w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - hevc_vt_uniwgt_8t_16multx2mult_msa(src, src_stride, dst, dst_stride, + hevc_vt_uniwgt_8t_16multx4mult_msa(src, src_stride, dst, dst_stride, filter, height, weight, - offset, rnd_val, 32); + offset, rnd_val, 2); } static void hevc_vt_uniwgt_8t_48w_msa(uint8_t *src, @@ -1763,9 +1729,9 @@ static void hevc_vt_uniwgt_8t_48w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - hevc_vt_uniwgt_8t_16multx2mult_msa(src, src_stride, dst, dst_stride, - filter, height, weight, - offset, rnd_val, 48); + hevc_vt_uniwgt_8t_16multx4mult_msa(src, src_stride, dst, dst_stride, + filter, 64, weight, + offset, rnd_val, 3); } static void hevc_vt_uniwgt_8t_64w_msa(uint8_t *src, @@ -1778,9 +1744,9 @@ static void hevc_vt_uniwgt_8t_64w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - hevc_vt_uniwgt_8t_16multx2mult_msa(src, src_stride, dst, dst_stride, + hevc_vt_uniwgt_8t_16multx4mult_msa(src, src_stride, dst, dst_stride, filter, height, weight, - offset, rnd_val, 64); + offset, rnd_val, 4); } static void hevc_hv_uniwgt_8t_4w_msa(uint8_t *src, @@ -1795,40 +1761,42 @@ static void hevc_hv_uniwgt_8t_4w_msa(uint8_t *src, int32_t rnd_val) { uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v8i16 filt0, filt1, filt2, filt3; - v4i32 filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 filt_h0, filt_h1, filt_h2, filt_h3; v16i8 mask1, mask2, mask3; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; - v8i16 dst30, dst41, dst52, dst63, dst66, dst87; - v4i32 dst0_r, dst1_r, weight_vec, offset_vec, rnd_vec; - v8i16 dst10_r, dst32_r, dst54_r, dst76_r; - v8i16 dst21_r, dst43_r, dst65_r, dst87_r; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; - v8u16 mask4 = { 0, 4, 1, 5, 2, 6, 3, 7 }; + v8i16 dst30, dst41, dst52, dst63, dst66, dst97, dst108; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r, dst98_r; + v8i16 dst21_r, dst43_r, dst65_r, dst87_r, dst109_r; + v4i32 dst0_r, dst1_r, dst2_r, dst3_r; + v4i32 weight_vec, offset_vec, rnd_vec, const_128, denom_vec; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); src -= ((3 * src_stride) + 3); filter_vec = LD_SH(filter_x); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W4_SW(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); mask1 = mask0 + 2; mask2 = mask0 + 4; mask3 = mask0 + 6; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight_vec = __msa_fill_w(weight); offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + denom_vec = rnd_vec - 6; + + const_128 = __msa_ldi_w(128); + const_128 *= weight_vec; + offset_vec += __msa_srar_w(const_128, denom_vec); LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); src += (7 * src_stride); @@ -1841,64 +1809,68 @@ static void hevc_hv_uniwgt_8t_4w_msa(uint8_t *src, vec8, vec9, vec10, vec11); VSHF_B4_SB(src3, src6, mask0, mask1, mask2, mask3, vec12, vec13, vec14, vec15); - dst30 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst30, dst30, dst30, dst30); - dst41 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst41, dst41, dst41, dst41); - dst52 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst52, dst52, dst52, dst52); - dst63 = const_vec; - DPADD_SB4_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, filt3, - dst63, dst63, dst63, dst63); - - ILVR_H3_SH(dst41, dst30, dst52, dst41, dst63, dst52, - dst10_r, dst21_r, dst32_r); - - dst43_r = __msa_ilvl_h(dst41, dst30); - dst54_r = __msa_ilvl_h(dst52, dst41); - dst65_r = __msa_ilvl_h(dst63, dst52); + dst30 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst41 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst52 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst63 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, + filt3); + + ILVRL_H2_SH(dst41, dst30, dst10_r, dst43_r); + ILVRL_H2_SH(dst52, dst41, dst21_r, dst54_r); + ILVRL_H2_SH(dst63, dst52, dst32_r, dst65_r); dst66 = (v8i16) __msa_splati_d((v2i64) dst63, 1); - for (loop_cnt = height >> 1; loop_cnt--;) { - LD_SB2(src, src_stride, src7, src8); - src += (2 * src_stride); - XORI_B2_128_SB(src7, src8); + for (loop_cnt = height >> 2; loop_cnt--;) { + LD_SB4(src, src_stride, src7, src8, src9, src10); + src += (4 * src_stride); + XORI_B4_128_SB(src7, src8, src9, src10); - VSHF_B4_SB(src7, src8, mask0, mask1, mask2, mask3, + VSHF_B4_SB(src7, src9, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst87 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst87, dst87, dst87, dst87); - dst76_r = __msa_ilvr_h(dst87, dst66); - dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, - filt_h0, filt_h1, filt_h2, filt_h3); - dst87_r = __msa_vshf_h((v8i16) mask4, dst87, dst87); - dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, - filt_h0, filt_h1, filt_h2, filt_h3); - - dst0_r >>= 6; - dst1_r >>= 6; + VSHF_B4_SB(src8, src10, mask0, mask1, mask2, mask3, + vec4, vec5, vec6, vec7); + dst97 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst108 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + + dst76_r = __msa_ilvr_h(dst97, dst66); + ILVRL_H2_SH(dst108, dst97, dst87_r, dst109_r); + dst66 = (v8i16) __msa_splati_d((v2i64) dst97, 1); + dst98_r = __msa_ilvr_h(dst66, dst108); + + dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst2_r = HEVC_FILT_8TAP(dst32_r, dst54_r, dst76_r, dst98_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst3_r = HEVC_FILT_8TAP(dst43_r, dst65_r, dst87_r, dst109_r, filt_h0, + filt_h1, filt_h2, filt_h3); + + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); MUL2(dst0_r, weight_vec, dst1_r, weight_vec, dst0_r, dst1_r); - SRAR_W2_SW(dst0_r, dst1_r, rnd_vec); + MUL2(dst2_r, weight_vec, dst3_r, weight_vec, dst2_r, dst3_r); + SRAR_W4_SW(dst0_r, dst1_r, dst2_r, dst3_r, rnd_vec); ADD2(dst0_r, offset_vec, dst1_r, offset_vec, dst0_r, dst1_r); - dst0_r = CLIP_SW_0_255(dst0_r); - dst1_r = CLIP_SW_0_255(dst1_r); - - HEVC_PCK_SW_SB2(dst1_r, dst0_r, dst0_r); - ST4x2_UB(dst0_r, dst, dst_stride); - dst += (2 * dst_stride); + ADD2(dst2_r, offset_vec, dst3_r, offset_vec, dst2_r, dst3_r); + CLIP_SW4_0_255_MAX_SATU(dst0_r, dst1_r, dst2_r, dst3_r); + PCKEV_H2_SW(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); + out = (v16u8) __msa_pckev_b((v16i8) dst1_r, (v16i8) dst0_r); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + dst += (4 * dst_stride); - dst10_r = dst32_r; - dst32_r = dst54_r; - dst54_r = dst76_r; - dst21_r = dst43_r; - dst43_r = dst65_r; - dst65_r = dst87_r; - dst66 = (v8i16) __msa_splati_d((v2i64) dst87, 1); + dst10_r = dst54_r; + dst32_r = dst76_r; + dst54_r = dst98_r; + dst21_r = dst65_r; + dst43_r = dst87_r; + dst65_r = dst109_r; + dst66 = (v8i16) __msa_splati_d((v2i64) dst108, 1); } } @@ -1921,7 +1893,7 @@ static void hevc_hv_uniwgt_8t_8multx2mult_msa(uint8_t *src, v8i16 filt0, filt1, filt2, filt3; v4i32 filt_h0, filt_h1, filt_h2, filt_h3; v16i8 mask1, mask2, mask3; - v8i16 filter_vec, const_vec; + v8i16 filter_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; @@ -1930,23 +1902,25 @@ static void hevc_hv_uniwgt_8t_8multx2mult_msa(uint8_t *src, v8i16 dst10_l, dst32_l, dst54_l, dst76_l; v8i16 dst21_r, dst43_r, dst65_r, dst87_r; v8i16 dst21_l, dst43_l, dst65_l, dst87_l; - v4i32 weight_vec, offset_vec, rnd_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v4i32 weight_vec, offset_vec, rnd_vec, const_128, denom_vec; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); src -= ((3 * src_stride) + 3); - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight_vec = __msa_fill_w(weight); offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + denom_vec = rnd_vec - 6; + + const_128 = __msa_ldi_w(128); + const_128 *= weight_vec; + offset_vec += __msa_srar_w(const_128, denom_vec); filter_vec = LD_SH(filter_x); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); SPLATI_W4_SW(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); mask1 = mask0 + 2; @@ -1969,18 +1943,14 @@ static void hevc_hv_uniwgt_8t_8multx2mult_msa(uint8_t *src, vec8, vec9, vec10, vec11); VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec12, vec13, vec14, vec15); - dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - dst1 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - dst2 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - dst3 = const_vec; - DPADD_SB4_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst1 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst2 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst3 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, + filt2, filt3); VSHF_B4_SB(src4, src4, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); @@ -1988,15 +1958,12 @@ static void hevc_hv_uniwgt_8t_8multx2mult_msa(uint8_t *src, vec4, vec5, vec6, vec7); VSHF_B4_SB(src6, src6, mask0, mask1, mask2, mask3, vec8, vec9, vec10, vec11); - dst4 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst4, dst4, dst4, dst4); - dst5 = const_vec; - DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, - dst5, dst5, dst5, dst5); - dst6 = const_vec; - DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, - dst6, dst6, dst6, dst6); + dst4 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst5 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst6 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); ILVR_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, dst10_r, dst32_r, dst54_r, dst21_r); @@ -2012,9 +1979,8 @@ static void hevc_hv_uniwgt_8t_8multx2mult_msa(uint8_t *src, VSHF_B4_SB(src7, src7, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst7 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst7, dst7, dst7, dst7); + dst7 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, @@ -2027,9 +1993,8 @@ static void hevc_hv_uniwgt_8t_8multx2mult_msa(uint8_t *src, /* row 8 */ VSHF_B4_SB(src8, src8, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst8 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst8, dst8, dst8, dst8); + dst8 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, + filt2, filt3); ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, @@ -2039,11 +2004,15 @@ static void hevc_hv_uniwgt_8t_8multx2mult_msa(uint8_t *src, dst1_r >>= 6; dst1_l >>= 6; - HEVC_HV_UNIW_RND_CLIP4(dst0_r, dst1_r, dst0_l, dst1_l, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + MUL2(dst0_r, weight_vec, dst0_l, weight_vec, dst0_r, dst0_l); + MUL2(dst1_r, weight_vec, dst1_l, weight_vec, dst1_r, dst1_l); + SRAR_W4_SW(dst0_r, dst1_r, dst0_l, dst1_l, rnd_vec); + ADD2(dst0_r, offset_vec, dst0_l, offset_vec, dst0_r, dst0_l); + ADD2(dst1_r, offset_vec, dst1_l, offset_vec, dst1_r, dst1_l); + CLIP_SW4_0_255_MAX_SATU(dst0_r, dst1_r, dst0_l, dst1_l); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); + PCKEV_H2_SW(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r, dst1_r); + dst0_r = (v4i32) __msa_pckev_b((v16i8) dst1_r, (v16i8) dst0_r); ST8x2_UB(dst0_r, dst_tmp, dst_stride); dst_tmp += (2 * dst_stride); @@ -2094,12 +2063,198 @@ static void hevc_hv_uniwgt_8t_12w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - hevc_hv_uniwgt_8t_8multx2mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, weight, - offset, rnd_val, 8); - hevc_hv_uniwgt_8t_4w_msa(src + 8, src_stride, dst + 8, dst_stride, - filter_x, filter_y, height, weight, offset, - rnd_val); + uint32_t loop_cnt; + uint8_t *src_tmp, *dst_tmp; + v16u8 out; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask7; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 dst30, dst41, dst52, dst63, dst66, dst97, dst108; + v8i16 filt0, filt1, filt2, filt3, filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r, dst10_l, dst32_l, dst54_l; + v8i16 dst98_r, dst21_r, dst43_r, dst65_r, dst87_r, dst109_r; + v8i16 dst76_l, filter_vec; + v4i32 dst0_r, dst0_l, dst1_r, dst2_r, dst3_r; + v4i32 weight_vec, offset_vec, rnd_vec, const_128, denom_vec; + + src -= ((3 * src_stride) + 3); + + filter_vec = LD_SH(filter_x); + SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + + weight_vec = __msa_fill_w(weight); + offset_vec = __msa_fill_w(offset); + rnd_vec = __msa_fill_w(rnd_val); + denom_vec = rnd_vec - 6; + + const_128 = __msa_ldi_w(128); + const_128 *= weight_vec; + offset_vec += __msa_srar_w(const_128, denom_vec); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + mask2 = mask0 + 4; + mask3 = mask0 + 6; + + src_tmp = src; + dst_tmp = dst; + + LD_SB7(src_tmp, src_stride, src0, src1, src2, src3, src4, src5, src6); + src_tmp += (7 * src_stride); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + /* row 0 row 1 row 2 row 3 */ + VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, vec8, vec9, vec10, + vec11); + VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec12, vec13, vec14, + vec15); + dst0 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst1 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst2 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst3 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, + filt2, filt3); + VSHF_B4_SB(src4, src4, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src5, src5, mask0, mask1, mask2, mask3, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src6, src6, mask0, mask1, mask2, mask3, vec8, vec9, vec10, + vec11); + dst4 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst5 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst6 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + + for (loop_cnt = 16; loop_cnt--;) { + src7 = LD_SB(src_tmp); + src7 = (v16i8) __msa_xori_b((v16u8) src7, 128); + src_tmp += src_stride; + + VSHF_B4_SB(src7, src7, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + dst7 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); + ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); + + dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, + filt_h0, filt_h1, filt_h2, filt_h3); + dst0_l = HEVC_FILT_8TAP(dst10_l, dst32_l, dst54_l, dst76_l, + filt_h0, filt_h1, filt_h2, filt_h3); + dst0_r >>= 6; + dst0_l >>= 6; + + MUL2(dst0_r, weight_vec, dst0_l, weight_vec, dst0_r, dst0_l); + SRAR_W2_SW(dst0_r, dst0_l, rnd_vec); + ADD2(dst0_r, offset_vec, dst0_l, offset_vec, dst0_r, dst0_l); + CLIP_SW2_0_255_MAX_SATU(dst0_r, dst0_l); + dst0_r = (v4i32) __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); + out = (v16u8) __msa_pckev_b((v16i8) dst0_r, (v16i8) dst0_r); + ST8x1_UB(out, dst_tmp); + dst_tmp += dst_stride; + + dst0 = dst1; + dst1 = dst2; + dst2 = dst3; + dst3 = dst4; + dst4 = dst5; + dst5 = dst6; + dst6 = dst7; + } + + src += 8; + dst += 8; + + mask4 = LD_SB(ff_hevc_mask_arr + 16); + mask5 = mask4 + 2; + mask6 = mask4 + 4; + mask7 = mask4 + 6; + + LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); + src += (7 * src_stride); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + VSHF_B4_SB(src0, src3, mask4, mask5, mask6, mask7, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src1, src4, mask4, mask5, mask6, mask7, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src2, src5, mask4, mask5, mask6, mask7, vec8, vec9, vec10, + vec11); + VSHF_B4_SB(src3, src6, mask4, mask5, mask6, mask7, vec12, vec13, vec14, + vec15); + dst30 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst41 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + dst52 = HEVC_FILT_8TAP_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, + filt3); + dst63 = HEVC_FILT_8TAP_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, + filt3); + ILVRL_H2_SH(dst41, dst30, dst10_r, dst43_r); + ILVRL_H2_SH(dst52, dst41, dst21_r, dst54_r); + ILVRL_H2_SH(dst63, dst52, dst32_r, dst65_r); + + dst66 = (v8i16) __msa_splati_d((v2i64) dst63, 1); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src, src_stride, src7, src8, src9, src10); + src += (4 * src_stride); + XORI_B4_128_SB(src7, src8, src9, src10); + + VSHF_B4_SB(src7, src9, mask4, mask5, mask6, mask7, vec0, vec1, vec2, + vec3); + VSHF_B4_SB(src8, src10, mask4, mask5, mask6, mask7, vec4, vec5, vec6, + vec7); + dst97 = HEVC_FILT_8TAP_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, + filt3); + dst108 = HEVC_FILT_8TAP_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, + filt3); + + dst76_r = __msa_ilvr_h(dst97, dst66); + ILVRL_H2_SH(dst108, dst97, dst87_r, dst109_r); + dst66 = (v8i16) __msa_splati_d((v2i64) dst97, 1); + dst98_r = __msa_ilvr_h(dst66, dst108); + + dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst2_r = HEVC_FILT_8TAP(dst32_r, dst54_r, dst76_r, dst98_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst3_r = HEVC_FILT_8TAP(dst43_r, dst65_r, dst87_r, dst109_r, filt_h0, + filt_h1, filt_h2, filt_h3); + + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + MUL2(dst0_r, weight_vec, dst1_r, weight_vec, dst0_r, dst1_r); + MUL2(dst2_r, weight_vec, dst3_r, weight_vec, dst2_r, dst3_r); + SRAR_W4_SW(dst0_r, dst1_r, dst2_r, dst3_r, rnd_vec); + ADD2(dst0_r, offset_vec, dst1_r, offset_vec, dst0_r, dst1_r); + ADD2(dst2_r, offset_vec, dst3_r, offset_vec, dst2_r, dst3_r); + CLIP_SW4_0_255_MAX_SATU(dst0_r, dst1_r, dst2_r, dst3_r); + PCKEV_H2_SW(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); + out = (v16u8) __msa_pckev_b((v16i8) dst1_r, (v16i8) dst0_r); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); + dst += (4 * dst_stride); + + dst10_r = dst54_r; + dst32_r = dst76_r; + dst54_r = dst98_r; + dst21_r = dst65_r; + dst43_r = dst87_r; + dst65_r = dst109_r; + dst66 = (v8i16) __msa_splati_d((v2i64) dst108, 1); + } } static void hevc_hv_uniwgt_8t_16w_msa(uint8_t *src, @@ -2187,19 +2342,19 @@ static void hevc_hz_uniwgt_4t_4x2_msa(uint8_t *src, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { + v16u8 out; v8i16 filt0, filt1; v16i8 src0, src1, vec0, vec1; v16i8 mask1; v8i16 dst0; v4i32 dst0_r, dst0_l; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[16]); src -= 1; @@ -2210,29 +2365,33 @@ static void hevc_hz_uniwgt_4t_4x2_msa(uint8_t *src, weight = weight & 0x0000FFFF; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + LD_SB2(src, src_stride, src0, src1); XORI_B2_128_SB(src0, src1); VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); ILVRL_H2_SW(dst0, dst0, dst0_r, dst0_l); DOTP_SH2_SW(dst0_r, dst0_l, weight_vec, weight_vec, dst0_r, dst0_l); SRAR_W2_SW(dst0_r, dst0_l, rnd_vec); - ADD2(dst0_r, offset_vec, dst0_l, offset_vec, dst0_r, dst0_l); - dst0_r = CLIP_SW_0_255(dst0_r); - dst0_l = CLIP_SW_0_255(dst0_l); - - HEVC_PCK_SW_SB2(dst0_l, dst0_r, dst0_r); - ST4x2_UB(dst0_r, dst, dst_stride); + dst0 = __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); + dst0 = __msa_adds_s_h(dst0, offset_vec); + dst0 = CLIP_SH_0_255_MAX_SATU(dst0); + out = (v16u8) __msa_pckev_b((v16i8) dst0, (v16i8) dst0); + ST4x2_UB(out, dst, dst_stride); dst += (4 * dst_stride); } @@ -2241,19 +2400,18 @@ static void hevc_hz_uniwgt_4t_4x4_msa(uint8_t *src, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { + v16u8 out; v8i16 filt0, filt1; v16i8 src0, src1, src2, src3; - v16i8 mask1, vec0, vec1; + v16i8 mask1, vec0, vec1, vec2, vec3; v8i16 dst0, dst1; - v4i32 dst0_r, dst1_r, dst0_l, dst1_l; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[16]); src -= 1; @@ -2265,29 +2423,32 @@ static void hevc_hz_uniwgt_4t_4x4_msa(uint8_t *src, weight = weight & 0x0000FFFF; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); - LD_SB4(src, src_stride, src0, src1, src2, src3); - XORI_B4_128_SB(src0, src1, src2, src3); + weight *= 128; + rnd_val -= 6; - VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + + LD_SB4(src, src_stride, src0, src1, src2, src3); + XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B2_SB(src2, src3, src2, src3, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src2, src3, src2, src3, mask0, mask1, vec2, vec3); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); - HEVC_UNIW_RND_CLIP2(dst0, dst1, weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst0, dst1, weight_vec, offset_vec, rnd_vec, + dst0, dst1); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST4x4_UB(dst0_r, dst0_r, 0, 1, 2, 3, dst, dst_stride); + out = (v16u8) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); dst += (4 * dst_stride); } @@ -2302,14 +2463,15 @@ static void hevc_hz_uniwgt_4t_4x8multiple_msa(uint8_t *src, int32_t rnd_val) { uint32_t loop_cnt; + v16u8 out0, out1; v8i16 filt0, filt1; v16i8 src0, src1, src2, src3, src4, src5, src6, src7; - v16i8 mask1, vec0, vec1; + v16i8 mask1, vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v8i16 dst0, dst1, dst2, dst3; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v8i16 filter_vec; + v8i16 weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[16]); src -= 1; @@ -2317,13 +2479,20 @@ static void hevc_hz_uniwgt_4t_4x8multiple_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); weight = weight & 0x0000FFFF; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + mask1 = mask0 + 2; for (loop_cnt = (height >> 3); loop_cnt--;) { @@ -2333,29 +2502,20 @@ static void hevc_hz_uniwgt_4t_4x8multiple_msa(uint8_t *src, XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - - VSHF_B2_SB(src2, src3, src2, src3, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - - VSHF_B2_SB(src4, src5, src4, src5, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - VSHF_B2_SB(src6, src7, src6, src7, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src2, src3, src2, src3, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src4, src5, src4, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src7, src6, src7, mask0, mask1, vec6, vec7); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, + weight_vec, offset_vec, rnd_vec, + dst0, dst1, dst2, dst3); - HEVC_UNIW_RND_CLIP4(dst0, dst1, dst2, dst3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST4x8_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); dst += (8 * dst_stride); } } @@ -2372,10 +2532,10 @@ static void hevc_hz_uniwgt_4t_4w_msa(uint8_t *src, { if (2 == height) { hevc_hz_uniwgt_4t_4x2_msa(src, src_stride, dst, dst_stride, - filter, height, weight, offset, rnd_val); + filter, weight, offset, rnd_val); } else if (4 == height) { hevc_hz_uniwgt_4t_4x4_msa(src, src_stride, dst, dst_stride, - filter, height, weight, offset, rnd_val); + filter, weight, offset, rnd_val); } else if (8 == height || 16 == height) { hevc_hz_uniwgt_4t_4x8multiple_msa(src, src_stride, dst, dst_stride, filter, height, weight, @@ -2393,16 +2553,15 @@ static void hevc_hz_uniwgt_4t_6w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - uint32_t loop_cnt; + v16u8 out0, out1, out2, out3; v8i16 filt0, filt1; - v16i8 src0, src1, src2, src3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v16i8 vec0, vec1; - v8i16 dst0, dst1, dst2, dst3; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= 1; @@ -2410,48 +2569,53 @@ static void hevc_hz_uniwgt_4t_6w_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); weight = weight & 0x0000FFFF; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); - mask1 = mask0 + 2; - - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); - - XORI_B4_128_SB(src0, src1, src2, src3); - - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + weight *= 128; + rnd_val -= 6; - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); - HEVC_UNIW_RND_CLIP4(dst0, dst1, dst2, dst3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + mask1 = mask0 + 2; - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); + LD_SB8(src, src_stride, src0, src1, src2, src3, src4, src5, src6, src7); + XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec6, vec7); + dst4 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, + weight_vec, offset_vec, rnd_vec, + dst0, dst1, dst2, dst3); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst4, dst5, dst6, dst7, + weight_vec, offset_vec, rnd_vec, + dst4, dst5, dst6, dst7); - ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); - dst += (4 * dst_stride); - } + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); + ST6x4_UB(out0, out1, dst, dst_stride); + dst += (4 * dst_stride); + ST6x4_UB(out2, out3, dst, dst_stride); } static void hevc_hz_uniwgt_4t_8x2_msa(uint8_t *src, @@ -2459,19 +2623,18 @@ static void hevc_hz_uniwgt_4t_8x2_msa(uint8_t *src, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { + v16u8 out; v8i16 filt0, filt1, dst0, dst1; v16i8 src0, src1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v16i8 vec0, vec1; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst0_l, dst1_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v16i8 vec0, vec1, vec2, vec3; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= 1; @@ -2479,30 +2642,92 @@ static void hevc_hz_uniwgt_4t_8x2_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); weight = weight & 0x0000FFFF; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + mask1 = mask0 + 2; LD_SB2(src, src_stride, src0, src1); XORI_B2_128_SB(src0, src1); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + + HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst0, dst1, weight_vec, offset_vec, rnd_vec, + dst0, dst1); + + out = (v16u8) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); + ST8x2_UB(out, dst, dst_stride); +} + +static void hevc_hz_uniwgt_4t_8x4_msa(uint8_t *src, + int32_t src_stride, + uint8_t *dst, + int32_t dst_stride, + const int8_t *filter, + int32_t weight, + int32_t offset, + int32_t rnd_val) +{ + v16u8 out0, out1; + v16i8 src0, src1, src2, src3; + v16i8 mask0, mask1, vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 filt0, filt1, dst0, dst1, dst2, dst3; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; + + src -= 1; + + filter_vec = LD_SH(filter); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); + + weight = weight & 0x0000FFFF; + weight_vec = __msa_fill_w(weight); + rnd_vec = __msa_fill_w(rnd_val); + + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + + mask0 = LD_SB(&ff_hevc_mask_arr[0]); + mask1 = mask0 + 2; + + LD_SB4(src, src_stride, src0, src1, src2, src3); + XORI_B4_128_SB(src0, src1, src2, src3); + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); - HEVC_UNIW_RND_CLIP2(dst0, dst1, weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, + weight_vec, offset_vec, rnd_vec, + dst0, dst1, dst2, dst3); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST8x2_UB(dst0_r, dst, dst_stride); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + ST8x4_UB(out0, out1, dst, dst_stride); } static void hevc_hz_uniwgt_4t_8x6_msa(uint8_t *src, @@ -2510,21 +2735,20 @@ static void hevc_hz_uniwgt_4t_8x6_msa(uint8_t *src, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { + v16u8 out0, out1, out2; v8i16 filt0, filt1; v16i8 src0, src1, src2, src3, src4, src5; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1; - v16i8 vec0, vec1; + v16i8 vec11; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= 1; @@ -2532,61 +2756,52 @@ static void hevc_hz_uniwgt_4t_8x6_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); weight = weight & 0x0000FFFF; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + mask1 = mask0 + 2; - LD_SB6(src, src_stride, src0, src1, src2, src3, src4, src5); LD_SB6(src, src_stride, src0, src1, src2, src3, src4, src5); XORI_B6_128_SB(src0, src1, src2, src3, src4, src5); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - HEVC_UNIW_RND_CLIP4(dst0, dst1, dst2, dst3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_UNIW_RND_CLIP2(dst4, dst5, weight_vec, offset_vec, rnd_vec, - dst4_r, dst5_r, dst4_l, dst5_l); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec8, vec9); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec10, vec11); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec8, vec9, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec10, vec11, filt0, filt1); + + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, + weight_vec, offset_vec, rnd_vec, + dst0, dst1, dst2, dst3); - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, dst0_r, dst1_r, dst2_r); + HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst4, dst5, weight_vec, offset_vec, rnd_vec, + dst4, dst5); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + ST8x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); - ST8x2_UB(dst2_r, dst, dst_stride); + ST8x2_UB(out2, dst, dst_stride); } -static void hevc_hz_uniwgt_4t_8x4multiple_msa(uint8_t *src, +static void hevc_hz_uniwgt_4t_8x8multiple_msa(uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, @@ -2598,14 +2813,14 @@ static void hevc_hz_uniwgt_4t_8x4multiple_msa(uint8_t *src, { uint32_t loop_cnt; v8i16 filt0, filt1; - v16i8 src0, src1, src2, src3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16u8 out0, out1, out2, out3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1; - v16i8 vec0, vec1; - v8i16 dst0, dst1, dst2, dst3; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= 1; @@ -2613,47 +2828,56 @@ static void hevc_hz_uniwgt_4t_8x4multiple_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); weight = weight & 0x0000FFFF; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); - mask1 = mask0 + 2; - - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src, src_stride, src0, src1, src2, src3); - src += (4 * src_stride); - - XORI_B4_128_SB(src0, src1, src2, src3); - - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + weight *= 128; + rnd_val -= 6; - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + mask1 = mask0 + 2; - HEVC_UNIW_RND_CLIP4(dst0, dst1, dst2, dst3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + for (loop_cnt = (height >> 3); loop_cnt--;) { + LD_SB8(src, src_stride, src0, src1, src2, src3, src4, src5, src6, src7); + src += (8 * src_stride); + XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec6, vec7); + dst4 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, + weight_vec, offset_vec, rnd_vec, + dst0, dst1, dst2, dst3); + + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst4, dst5, dst6, dst7, + weight_vec, offset_vec, rnd_vec, + dst4, dst5, dst6, dst7); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); - dst += (4 * dst_stride); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); + ST8x8_UB(out0, out1, out2, out3, dst, dst_stride); + dst += (8 * dst_stride); } } @@ -2669,12 +2893,15 @@ static void hevc_hz_uniwgt_4t_8w_msa(uint8_t *src, { if (2 == height) { hevc_hz_uniwgt_4t_8x2_msa(src, src_stride, dst, dst_stride, - filter, height, weight, offset, rnd_val); + filter, weight, offset, rnd_val); + } else if (4 == height) { + hevc_hz_uniwgt_4t_8x4_msa(src, src_stride, dst, dst_stride, + filter, weight, offset, rnd_val); } else if (6 == height) { hevc_hz_uniwgt_4t_8x6_msa(src, src_stride, dst, dst_stride, - filter, height, weight, offset, rnd_val); + filter, weight, offset, rnd_val); } else { - hevc_hz_uniwgt_4t_8x4multiple_msa(src, src_stride, dst, dst_stride, + hevc_hz_uniwgt_4t_8x8multiple_msa(src, src_stride, dst, dst_stride, filter, height, weight, offset, rnd_val); } @@ -2691,19 +2918,18 @@ static void hevc_hz_uniwgt_4t_12w_msa(uint8_t *src, int32_t rnd_val) { uint32_t loop_cnt; + v16u8 out0, out1, out2; v8i16 filt0, filt1; v16i8 src0, src1, src2, src3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask2 = { 8, 9, 9, 10, 10, 11, 11, 12, 24, 25, 25, 26, 26, 27, 27, 28 }; v16i8 mask1; - v16i8 vec0, vec1; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9, vec10; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v8i16 filter_vec, const_vec; - v16i8 mask3; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v16i8 mask3, vec11; + v4i32 weight_vec, rnd_vec; src -= 1; @@ -2711,60 +2937,51 @@ static void hevc_hz_uniwgt_4t_12w_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); weight = weight & 0x0000FFFF; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + mask1 = mask0 + 2; mask3 = mask2 + 2; - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = 4; loop_cnt--;) { LD_SB4(src, src_stride, src0, src1, src2, src3); src += (4 * src_stride); XORI_B4_128_SB(src0, src1, src2, src3); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - VSHF_B2_SB(src2, src3, src2, src3, mask2, mask3, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - HEVC_UNIW_RND_CLIP4(dst0, dst1, dst2, dst3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_UNIW_RND_CLIP2(dst4, dst5, weight_vec, offset_vec, rnd_vec, - dst4_r, dst5_r, dst4_l, dst5_l); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec8, vec9); + VSHF_B2_SB(src2, src3, src2, src3, mask2, mask3, vec10, vec11); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec8, vec9, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec10, vec11, filt0, filt1); + + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, + weight_vec, offset_vec, rnd_vec, + dst0, dst1, dst2, dst3); - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, - dst0_r, dst1_r, dst2_r); + HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst4, dst5, weight_vec, offset_vec, + rnd_vec, dst4, dst5); - ST12x4_UB(dst0_r, dst1_r, dst2_r, dst, dst_stride); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + ST12x4_UB(out0, out1, out2, dst, dst_stride); dst += (4 * dst_stride); } } @@ -2780,15 +2997,15 @@ static void hevc_hz_uniwgt_4t_16w_msa(uint8_t *src, int32_t rnd_val) { uint32_t loop_cnt; + v16u8 out0, out1, out2, out3; v16i8 src0, src1, src2, src3, src4, src5, src6, src7; v8i16 filt0, filt1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; - v16i8 vec0, vec1; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= 1; @@ -2796,13 +3013,20 @@ static void hevc_hz_uniwgt_4t_16w_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); weight = weight & 0x0000FFFF; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + mask1 = mask0 + 2; for (loop_cnt = (height >> 2); loop_cnt--;) { @@ -2813,56 +3037,35 @@ static void hevc_hz_uniwgt_4t_16w_msa(uint8_t *src, XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec6, vec7); + dst4 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, + weight_vec, offset_vec, rnd_vec, + dst0, dst1, dst2, dst3); - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst4, dst5, dst6, dst7, + weight_vec, offset_vec, rnd_vec, + dst4, dst5, dst6, dst7); - HEVC_UNIW_RND_CLIP4(dst0, dst1, dst2, dst3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + PCKEV_B4_UB(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, + out0, out1, out2, out3); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); - dst += (2 * dst_stride); - - HEVC_UNIW_RND_CLIP4(dst4, dst5, dst6, dst7, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); - dst += (2 * dst_stride); + ST_UB4(out0, out1, out2, out3, dst, dst_stride); + dst += (4 * dst_stride); } } @@ -2877,16 +3080,14 @@ static void hevc_hz_uniwgt_4t_24w_msa(uint8_t *src, int32_t rnd_val) { uint32_t loop_cnt; - uint8_t *dst_tmp = dst + 16; + v16u8 out0, out1, out2; v16i8 src0, src1, src2, src3; v8i16 filt0, filt1; - v8i16 dst0, dst1, dst2, dst3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; - v16i8 mask1, mask2, mask3; - v16i8 vec0, vec1; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v16i8 mask0, mask1, mask2, mask3; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= 1; @@ -2894,19 +3095,25 @@ static void hevc_hz_uniwgt_4t_24w_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); weight = weight & 0x0000FFFF; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + + mask0 = LD_SB(&ff_hevc_mask_arr[0]); mask1 = mask0 + 2; mask2 = mask0 + 8; mask3 = mask0 + 10; - for (loop_cnt = (height >> 1); loop_cnt--;) { - /* 16 width */ + for (loop_cnt = 16; loop_cnt--;) { LD_SB2(src, src_stride, src0, src2); LD_SB2(src + 16, src_stride, src1, src3); src += (2 * src_stride); @@ -2914,46 +3121,29 @@ static void hevc_hz_uniwgt_4t_24w_msa(uint8_t *src, XORI_B4_128_SB(src0, src1, src2, src3); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - - VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - VSHF_B2_SB(src2, src3, src2, src3, mask2, mask3, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - HEVC_UNIW_RND_CLIP4(dst0, dst1, dst2, dst3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); - dst += (2 * dst_stride); - - /* 8 width */ + VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src2, src3, src2, src3, mask2, mask3, vec6, vec7); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec2, vec3); + dst4 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, + weight_vec, offset_vec, rnd_vec, + dst0, dst1, dst2, dst3); - HEVC_UNIW_RND_CLIP2(dst0, dst1, weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst4, dst5, weight_vec, offset_vec, + rnd_vec, dst4, dst5); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST8x2_UB(dst0_r, dst_tmp, dst_stride); - dst_tmp += (2 * dst_stride); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + ST_UB2(out0, out1, dst, dst_stride); + ST8x2_UB(out2, dst + 16, dst_stride); + dst += (2 * dst_stride); } } @@ -2968,15 +3158,15 @@ static void hevc_hz_uniwgt_4t_32w_msa(uint8_t *src, int32_t rnd_val) { uint32_t loop_cnt; - v16i8 src0, src1, src2; + v16u8 out0, out1, out2, out3; + v16i8 src0, src1, src2, src3, src4, src5; v8i16 filt0, filt1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(&ff_hevc_mask_arr[0]); v16i8 mask1, mask2, mask3; - v8i16 dst0, dst1, dst2, dst3; - v16i8 vec0, vec1; - v8i16 filter_vec, const_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= 1; @@ -2984,13 +3174,20 @@ static void hevc_hz_uniwgt_4t_32w_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); weight = weight & 0x0000FFFF; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + mask1 = mask0 + 2; mask2 = mask0 + 8; mask3 = mask0 + 10; @@ -2999,65 +3196,40 @@ static void hevc_hz_uniwgt_4t_32w_msa(uint8_t *src, LD_SB2(src, 16, src0, src1); src2 = LD_SB(src + 24); src += src_stride; - - XORI_B3_128_SB(src0, src1, src2); - - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - - VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - HEVC_UNIW_RND_CLIP4(dst0, dst1, dst2, dst3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, 16); - dst += dst_stride; - - LD_SB2(src, 16, src0, src1); - src2 = LD_SB(src + 24); + LD_SB2(src, 16, src3, src4); + src5 = LD_SB(src + 24); src += src_stride; - - XORI_B3_128_SB(src0, src1, src2); - + XORI_B6_128_SB(src0, src1, src2, src3, src4, src5); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - - VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - HEVC_UNIW_RND_CLIP4(dst0, dst1, dst2, dst3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); + VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec2, vec3); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec6, vec7); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src3, src4, src3, src4, mask2, mask3, vec2, vec3); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec6, vec7); + dst4 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, + weight_vec, offset_vec, rnd_vec, + dst0, dst1, dst2, dst3); + + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst4, dst5, dst6, dst7, + weight_vec, offset_vec, rnd_vec, + dst4, dst5, dst6, dst7); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, 16); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); + ST_UB2(out0, out1, dst, 16); + dst += dst_stride; + ST_UB2(out2, out3, dst, 16); dst += dst_stride; } } @@ -3067,55 +3239,54 @@ static void hevc_vt_uniwgt_4t_4x2_msa(uint8_t *src, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { + v16u8 out; v16i8 src0, src1, src2, src3, src4; v16i8 src10_r, src32_r, src21_r, src43_r; v16i8 src2110, src4332; - v8i16 dst10; + v8i16 dst0; v4i32 dst0_r, dst0_l; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= src_stride; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); + LD_SB5(src, src_stride, src0, src1, src2, src3, src4); ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); - src2110 = (v16i8) __msa_ilvr_d((v2i64) src21_r, (v2i64) src10_r); - src2110 = (v16i8) __msa_xori_b((v16u8) src2110, 128); - LD_SB2(src, src_stride, src3, src4); ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); - src4332 = (v16i8) __msa_ilvr_d((v2i64) src43_r, (v2i64) src32_r); - src4332 = (v16i8) __msa_xori_b((v16u8) src4332, 128); - - dst10 = const_vec; - DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst10, dst10); - - ILVRL_H2_SW(dst10, dst10, dst0_r, dst0_l); + ILVR_D2_SB(src21_r, src10_r, src43_r, src32_r, src2110, src4332); + XORI_B2_128_SB(src2110, src4332); + dst0 = HEVC_FILT_4TAP_SH(src2110, src4332, filt0, filt1); + ILVRL_H2_SW(dst0, dst0, dst0_r, dst0_l); DOTP_SH2_SW(dst0_r, dst0_l, weight_vec, weight_vec, dst0_r, dst0_l); SRAR_W2_SW(dst0_r, dst0_l, rnd_vec); - ADD2(dst0_r, offset_vec, dst0_l, offset_vec, dst0_r, dst0_l); - dst0_r = CLIP_SW_0_255(dst0_r); - dst0_l = CLIP_SW_0_255(dst0_l); - - HEVC_PCK_SW_SB2(dst0_l, dst0_r, dst0_r); - ST4x2_UB(dst0_r, dst, dst_stride); + dst0 = __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); + dst0 = __msa_adds_s_h(dst0, offset_vec); + dst0 = CLIP_SH_0_255_MAX_SATU(dst0); + out = (v16u8) __msa_pckev_b((v16i8) dst0, (v16i8) dst0); + ST4x2_UB(out, dst, dst_stride); } static void hevc_vt_uniwgt_4t_4x4_msa(uint8_t *src, @@ -3123,55 +3294,53 @@ static void hevc_vt_uniwgt_4t_4x4_msa(uint8_t *src, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { + v16u8 out; v16i8 src0, src1, src2, src3, src4, src5, src6; v16i8 src10_r, src32_r, src54_r, src21_r, src43_r, src65_r; v16i8 src2110, src4332, src6554; - v8i16 dst10, dst32; - v4i32 dst0_r, dst1_r, dst0_l, dst1_l; + v8i16 dst0, dst1; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= src_stride; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); + LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); - src2110 = (v16i8) __msa_ilvr_d((v2i64) src21_r, (v2i64) src10_r); - src2110 = (v16i8) __msa_xori_b((v16u8) src2110, 128); - - LD_SB4(src, src_stride, src3, src4, src5, src6); ILVR_B4_SB(src3, src2, src4, src3, src5, src4, src6, src5, src32_r, src43_r, src54_r, src65_r); - ILVR_D2_SB(src43_r, src32_r, src65_r, src54_r, src4332, src6554); - XORI_B2_128_SB(src4332, src6554); - - dst10 = const_vec; - DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst10, dst10); - dst32 = const_vec; - DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst32, dst32); - HEVC_UNIW_RND_CLIP2(dst10, dst32, weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst0_l, dst1_l); - - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST4x4_UB(dst0_r, dst0_r, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); + ILVR_D3_SB(src21_r, src10_r, src43_r, src32_r, src65_r, src54_r, + src2110, src4332, src6554); + XORI_B3_128_SB(src2110, src4332, src6554); + dst0 = HEVC_FILT_4TAP_SH(src2110, src4332, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(src4332, src6554, filt0, filt1); + HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst0, dst1, weight_vec, offset_vec, rnd_vec, + dst0, dst1); + + out = (v16u8) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); } static void hevc_vt_uniwgt_4t_4x8multiple_msa(uint8_t *src, @@ -3185,26 +3354,33 @@ static void hevc_vt_uniwgt_4t_4x8multiple_msa(uint8_t *src, int32_t rnd_val) { int32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v16i8 src10_r, src32_r, src54_r, src76_r, src98_r; v16i8 src21_r, src43_r, src65_r, src87_r, src109_r; v16i8 src2110, src4332, src6554, src8776; - v8i16 dst10, dst32, dst54, dst76; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; - v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; + v16i8 src10998; + v8i16 dst0, dst1, dst2, dst3, filt0, filt1; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= src_stride; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); @@ -3215,39 +3391,31 @@ static void hevc_vt_uniwgt_4t_4x8multiple_msa(uint8_t *src, src2110 = (v16i8) __msa_xori_b((v16u8) src2110, 128); for (loop_cnt = (height >> 3); loop_cnt--;) { - LD_SB6(src, src_stride, src3, src4, src5, src6, src7, src8); - src += (6 * src_stride); + LD_SB8(src, src_stride, + src3, src4, src5, src6, src7, src8, src9, src10); + src += (8 * src_stride); ILVR_B4_SB(src3, src2, src4, src3, src5, src4, src6, src5, src32_r, src43_r, src54_r, src65_r); ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); - ILVR_D3_SB(src43_r, src32_r, src65_r, src54_r, src87_r, src76_r, - src4332, src6554, src8776); - XORI_B3_128_SB(src4332, src6554, src8776); - - dst10 = const_vec; - DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst10, dst10); - dst32 = const_vec; - DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst32, dst32); - dst54 = const_vec; - DPADD_SB2_SH(src6554, src8776, filt0, filt1, dst54, dst54); - - LD_SB2(src, src_stride, src9, src2); - src += (2 * src_stride); - ILVR_B2_SB(src9, src8, src2, src9, src98_r, src109_r); - src2110 = (v16i8) __msa_ilvr_d((v2i64) src109_r, (v2i64) src98_r); - src2110 = (v16i8) __msa_xori_b((v16u8) src2110, 128); - - dst76 = const_vec; - DPADD_SB2_SH(src8776, src2110, filt0, filt1, dst76, dst76); - HEVC_UNIW_RND_CLIP4(dst10, dst32, dst54, dst76, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST4x8_UB(dst0_r, dst1_r, dst, dst_stride); + ILVR_B2_SB(src9, src8, src10, src9, src98_r, src109_r); + ILVR_D4_SB(src43_r, src32_r, src65_r, src54_r, src87_r, src76_r, + src109_r, src98_r, src4332, src6554, src8776, src10998); + XORI_B4_128_SB(src4332, src6554, src8776, src10998); + dst0 = HEVC_FILT_4TAP_SH(src2110, src4332, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(src4332, src6554, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(src6554, src8776, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(src8776, src10998, filt0, filt1); + + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, + weight_vec, offset_vec, rnd_vec, + dst0, dst1, dst2, dst3); + + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); dst += (8 * dst_stride); + + src2 = src10; + src2110 = src10998; } } @@ -3263,10 +3431,10 @@ static void hevc_vt_uniwgt_4t_4w_msa(uint8_t *src, { if (2 == height) { hevc_vt_uniwgt_4t_4x2_msa(src, src_stride, dst, dst_stride, - filter, height, weight, offset, rnd_val); + filter, weight, offset, rnd_val); } else if (4 == height) { hevc_vt_uniwgt_4t_4x4_msa(src, src_stride, dst, dst_stride, - filter, height, weight, offset, rnd_val); + filter, weight, offset, rnd_val); } else if (0 == (height % 8)) { hevc_vt_uniwgt_4t_4x8multiple_msa(src, src_stride, dst, dst_stride, filter, height, weight, offset, @@ -3284,64 +3452,66 @@ static void hevc_vt_uniwgt_4t_6w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - int32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4; + v16u8 out0, out1, out2, out3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v16i8 src10_r, src32_r, src21_r, src43_r; - v8i16 tmp0, tmp1, tmp2, tmp3; + v16i8 src54_r, src65_r, src76_r, src87_r, src98_r, src109_r; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= src_stride; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); LD_SB3(src, src_stride, src0, src1, src2); src += (3 * src_stride); + LD_SB8(src, src_stride, src3, src4, src5, src6, src7, src8, src9, src10); XORI_B3_128_SB(src0, src1, src2); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); + ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); + ILVR_B2_SB(src5, src4, src6, src5, src54_r, src65_r); + ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); + ILVR_B2_SB(src9, src8, src10, src9, src98_r, src109_r); + dst0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(src54_r, src76_r, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(src65_r, src87_r, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(src76_r, src98_r, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(src87_r, src109_r, filt0, filt1); + + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, + weight_vec, offset_vec, rnd_vec, + dst0, dst1, dst2, dst3); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst4, dst5, dst6, dst7, + weight_vec, offset_vec, rnd_vec, + dst4, dst5, dst6, dst7); - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB2(src, src_stride, src3, src4); - src += (2 * src_stride); - XORI_B2_128_SB(src3, src4); - ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); - - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - - LD_SB2(src, src_stride, src1, src2); - src += (2 * src_stride); - XORI_B2_128_SB(src1, src2); - ILVR_B2_SB(src1, src4, src2, src1, src10_r, src21_r); - - tmp2 = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, tmp3, tmp3); - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - - ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); - dst += (4 * dst_stride); - } + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); + ST6x4_UB(out0, out1, dst, dst_stride); + dst += (4 * dst_stride); + ST6x4_UB(out2, out3, dst, dst_stride); } static void hevc_vt_uniwgt_4t_8x2_msa(uint8_t *src, @@ -3349,151 +3519,208 @@ static void hevc_vt_uniwgt_4t_8x2_msa(uint8_t *src, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { + v16u8 out; v16i8 src0, src1, src2, src3, src4; v16i8 src10_r, src32_r, src21_r, src43_r; - v8i16 tmp0, tmp1; + v8i16 dst0, dst1; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst0_l, dst1_l; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= src_stride; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); + LD_SB5(src, src_stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); - LD_SB2(src, src_stride, src3, src4); - XORI_B2_128_SB(src3, src4); ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); + dst0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - HEVC_UNIW_RND_CLIP2(tmp0, tmp1, weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst0_l, dst1_l); + HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst0, dst1, weight_vec, offset_vec, rnd_vec, + dst0, dst1); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST8x2_UB(dst0_r, dst, dst_stride); + out = (v16u8) __msa_pckev_b((v16i8) dst1, (v16i8) dst0); + ST8x2_UB(out, dst, dst_stride); } -static void hevc_vt_uniwgt_4t_8x6_msa(uint8_t *src, +static void hevc_vt_uniwgt_4t_8x4_msa(uint8_t *src, int32_t src_stride, uint8_t *dst, int32_t dst_stride, const int8_t *filter, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; - v16i8 src10_r, src32_r, src54_r, src76_r; - v16i8 src21_r, src43_r, src65_r, src87_r; - v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4; + v16i8 src10_r, src32_r, src21_r, src43_r; + v16i8 src5, src6, src54_r, src65_r; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; + v8i16 dst0, dst1, dst2, dst3; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= src_stride; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); - LD_SB3(src, src_stride, src0, src1, src2); + LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); src += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); - - LD_SB6(src, src_stride, src3, src4, src5, src6, src7, src8); - XORI_B6_128_SB(src3, src4, src5, src6, src7, src8); - ILVR_B4_SB(src3, src2, src4, src3, src5, src4, src6, src5, - src32_r, src43_r, src54_r, src65_r); - ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); - - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB2_SH(src32_r, src54_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src43_r, src65_r, filt0, filt1, tmp3, tmp3); - tmp4 = const_vec; - DPADD_SB2_SH(src54_r, src76_r, filt0, filt1, tmp4, tmp4); - tmp5 = const_vec; - DPADD_SB2_SH(src65_r, src87_r, filt0, filt1, tmp5, tmp5); - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - HEVC_UNIW_RND_CLIP2(tmp4, tmp5, weight_vec, offset_vec, rnd_vec, - dst4_r, dst5_r, dst4_l, dst5_l); - - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, dst0_r, dst1_r, dst2_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); - dst += (4 * dst_stride); - ST8x2_UB(dst2_r, dst, dst_stride); + ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); + ILVR_B2_SB(src5, src4, src6, src5, src54_r, src65_r); + dst0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, weight_vec, + offset_vec, rnd_vec, dst0, dst1, dst2, + dst3); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + ST8x4_UB(out0, out1, dst, dst_stride); } -static void hevc_vt_uniwgt_4t_8x4multiple_msa(uint8_t *src, - int32_t src_stride, - uint8_t *dst, - int32_t dst_stride, - const int8_t *filter, - int32_t height, - int32_t weight, - int32_t offset, - int32_t rnd_val) +static void hevc_vt_uniwgt_4t_8x6_msa(uint8_t *src, + int32_t src_stride, + uint8_t *dst, + int32_t dst_stride, + const int8_t *filter, + int32_t weight, + int32_t offset, + int32_t rnd_val) +{ + v16u8 out0, out1, out2; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 src10_r, src32_r, src54_r, src76_r; + v16i8 src21_r, src43_r, src65_r, src87_r; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5; + v8i16 filt0, filt1; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; + + src -= src_stride; + + weight = weight & 0x0000FFFF; + + weight_vec = __msa_fill_w(weight); + rnd_vec = __msa_fill_w(rnd_val); + + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + + filter_vec = LD_SH(filter); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); + + LD_SB3(src, src_stride, src0, src1, src2); + src += (3 * src_stride); + LD_SB6(src, src_stride, src3, src4, src5, src6, src7, src8); + + XORI_B3_128_SB(src0, src1, src2); + XORI_B6_128_SB(src3, src4, src5, src6, src7, src8); + ILVR_B4_SB(src1, src0, src2, src1, src3, src2, src4, src3, src10_r, src21_r, + src32_r, src43_r); + ILVR_B4_SB(src5, src4, src6, src5, src7, src6, src8, src7, src54_r, src65_r, + src76_r, src87_r); + dst0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(src54_r, src76_r, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(src65_r, src87_r, filt0, filt1); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, weight_vec, + offset_vec, rnd_vec, dst0, dst1, dst2, dst3); + HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst4, dst5, weight_vec, offset_vec, rnd_vec, + dst4, dst5); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + ST8x4_UB(out0, out1, dst, dst_stride); + dst += (4 * dst_stride); + ST8x2_UB(out2, dst, dst_stride); +} + +static void hevc_vt_uniwgt_4t_8x8mult_msa(uint8_t *src, + int32_t src_stride, + uint8_t *dst, + int32_t dst_stride, + const int8_t *filter, + int32_t height, + int32_t weight, + int32_t offset, + int32_t rnd_val) { int32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4; + v16u8 out0, out1, out2, out3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v16i8 src10_r, src32_r, src21_r, src43_r; - v8i16 tmp0, tmp1, tmp2, tmp3; + v16i8 src54_r, src65_r, src76_r, src87_r, src98_r, src109_r; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= src_stride; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); @@ -3502,35 +3729,37 @@ static void hevc_vt_uniwgt_4t_8x4multiple_msa(uint8_t *src, XORI_B3_128_SB(src0, src1, src2); ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB2(src, src_stride, src3, src4); - src += (2 * src_stride); - XORI_B2_128_SB(src3, src4); + for (loop_cnt = (height >> 3); loop_cnt--;) { + LD_SB8(src, src_stride, + src3, src4, src5, src6, src7, src8, src9, src10); + src += (8 * src_stride); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); + ILVR_B2_SB(src5, src4, src6, src5, src54_r, src65_r); + ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); + ILVR_B2_SB(src9, src8, src10, src9, src98_r, src109_r); + dst0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(src54_r, src76_r, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(src65_r, src87_r, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(src76_r, src98_r, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(src87_r, src109_r, filt0, filt1); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, weight_vec, + offset_vec, rnd_vec, dst0, dst1, dst2, + dst3); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst4, dst5, dst6, dst7, weight_vec, + offset_vec, rnd_vec, dst4, dst5, dst6, + dst7); + PCKEV_B2_UB(dst1, dst0, dst3, dst2, out0, out1); + PCKEV_B2_UB(dst5, dst4, dst7, dst6, out2, out3); + ST8x8_UB(out0, out1, out2, out3, dst, dst_stride); + dst += (8 * dst_stride); - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - - LD_SB2(src, src_stride, src1, src2); - src += (2 * src_stride); - XORI_B2_128_SB(src1, src2); - ILVR_B2_SB(src1, src4, src2, src1, src10_r, src21_r); - - tmp2 = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, tmp3, tmp3); - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); - dst += (4 * dst_stride); + src2 = src10; + src10_r = src98_r; + src21_r = src109_r; } } @@ -3546,14 +3775,17 @@ static void hevc_vt_uniwgt_4t_8w_msa(uint8_t *src, { if (2 == height) { hevc_vt_uniwgt_4t_8x2_msa(src, src_stride, dst, dst_stride, - filter, height, weight, offset, rnd_val); + filter, weight, offset, rnd_val); + } else if (4 == height) { + hevc_vt_uniwgt_4t_8x4_msa(src, src_stride, dst, dst_stride, + filter, weight, offset, rnd_val); } else if (6 == height) { hevc_vt_uniwgt_4t_8x6_msa(src, src_stride, dst, dst_stride, - filter, height, weight, offset, rnd_val); + filter, weight, offset, rnd_val); } else { - hevc_vt_uniwgt_4t_8x4multiple_msa(src, src_stride, dst, dst_stride, - filter, height, weight, offset, - rnd_val); + hevc_vt_uniwgt_4t_8x8mult_msa(src, src_stride, dst, dst_stride, + filter, height, weight, offset, + rnd_val); } } @@ -3568,27 +3800,35 @@ static void hevc_vt_uniwgt_4t_12w_msa(uint8_t *src, int32_t rnd_val) { int32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5; + v16u8 out0, out1, out2, out3, out4, out5; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v16i8 src10_r, src32_r, src21_r, src43_r; - v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; v16i8 src10_l, src32_l, src54_l, src21_l, src43_l, src65_l; v16i8 src2110, src4332; + v16i8 src54_r, src76_r, src98_r, src65_r, src87_r, src109_r; + v16i8 src76_l, src98_l, src87_l, src109_l, src6554, src8776, src10998; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; + v8i16 dst9, dst10, dst11, filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= (1 * src_stride); - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); @@ -3599,47 +3839,56 @@ static void hevc_vt_uniwgt_4t_12w_msa(uint8_t *src, ILVL_B2_SB(src1, src0, src2, src1, src10_l, src21_l); src2110 = (v16i8) __msa_ilvr_d((v2i64) src21_l, (v2i64) src10_l); - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB2(src, src_stride, src3, src4); - src += (2 * src_stride); - XORI_B2_128_SB(src3, src4); - ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); - ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); + for (loop_cnt = 2; loop_cnt--;) { + LD_SB8(src, src_stride, src3, src4, src5, src6, src7, src8, src9, src10); + src += (8 * src_stride); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); + ILVRL_B2_SB(src3, src2, src32_r, src32_l); + ILVRL_B2_SB(src4, src3, src43_r, src43_l); + ILVRL_B2_SB(src5, src4, src54_r, src54_l); + ILVRL_B2_SB(src6, src5, src65_r, src65_l); src4332 = (v16i8) __msa_ilvr_d((v2i64) src43_l, (v2i64) src32_l); + src6554 = (v16i8) __msa_ilvr_d((v2i64) src65_l, (v2i64) src54_l); + dst0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(src2110, src4332, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(src4332, src6554, filt0, filt1); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, weight_vec, + offset_vec, rnd_vec, dst0, dst1, dst2, + dst3); + HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst4, dst5, weight_vec, offset_vec, + rnd_vec, dst4, dst5); + PCKEV_B3_UB(dst1, dst0, dst3, dst2, dst5, dst4, out0, out1, out2); + ST12x4_UB(out0, out1, out2, dst, dst_stride); + dst += (4 * dst_stride); - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - tmp4 = const_vec; - DPADD_SB2_SH(src2110, src4332, filt0, filt1, tmp4, tmp4); - - LD_SB2(src, src_stride, src5, src2); - src += (2 * src_stride); - XORI_B2_128_SB(src5, src2); - ILVR_B2_SB(src5, src4, src2, src5, src10_r, src21_r); - ILVL_B2_SB(src5, src4, src2, src5, src54_l, src65_l); - src2110 = (v16i8) __msa_ilvr_d((v2i64) src65_l, (v2i64) src54_l); - - tmp2 = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, tmp3, tmp3); - tmp5 = const_vec; - DPADD_SB2_SH(src4332, src2110, filt0, filt1, tmp5, tmp5); - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - HEVC_UNIW_RND_CLIP2(tmp4, tmp5, weight_vec, offset_vec, rnd_vec, - dst4_r, dst5_r, dst4_l, dst5_l); - - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, - dst0_r, dst1_r, dst2_r); - ST12x4_UB(dst0_r, dst1_r, dst2_r, dst, dst_stride); + ILVRL_B2_SB(src7, src6, src76_r, src76_l); + ILVRL_B2_SB(src8, src7, src87_r, src87_l); + ILVRL_B2_SB(src9, src8, src98_r, src98_l); + ILVRL_B2_SB(src10, src9, src109_r, src109_l); + src8776 = (v16i8) __msa_ilvr_d((v2i64) src87_l, (v2i64) src76_l); + src10998 = (v16i8) __msa_ilvr_d((v2i64) src109_l, (v2i64) src98_l); + dst6 = HEVC_FILT_4TAP_SH(src54_r, src76_r, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(src65_r, src87_r, filt0, filt1); + dst8 = HEVC_FILT_4TAP_SH(src76_r, src98_r, filt0, filt1); + dst9 = HEVC_FILT_4TAP_SH(src87_r, src109_r, filt0, filt1); + dst10 = HEVC_FILT_4TAP_SH(src6554, src8776, filt0, filt1); + dst11 = HEVC_FILT_4TAP_SH(src8776, src10998, filt0, filt1); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst6, dst7, dst8, dst9, weight_vec, + offset_vec, rnd_vec, dst6, dst7, dst8, + dst9); + HEVC_UNIW_RND_CLIP2_MAX_SATU_H(dst10, dst11, weight_vec, offset_vec, + rnd_vec, dst10, dst11); + PCKEV_B3_UB(dst7, dst6, dst9, dst8, dst11, dst10, out3, out4, out5); + ST12x4_UB(out3, out4, out5, dst, dst_stride); dst += (4 * dst_stride); + + src2 = src10; + src10_r = src98_r; + src21_r = src109_r; + src2110 = src10998; } } @@ -3654,25 +3903,33 @@ static void hevc_vt_uniwgt_4t_16w_msa(uint8_t *src, int32_t rnd_val) { int32_t loop_cnt; + v16u8 out0, out1, out2, out3; v16i8 src0, src1, src2, src3, src4, src5; v16i8 src10_r, src32_r, src21_r, src43_r; v16i8 src10_l, src32_l, src21_l, src43_l; - v8i16 tmp0, tmp1, tmp2, tmp3; + v16i8 src54_r, src54_l, src65_r, src65_l, src6; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst0_l, dst1_l, dst2_l, dst3_l; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= src_stride; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); @@ -3683,53 +3940,37 @@ static void hevc_vt_uniwgt_4t_16w_msa(uint8_t *src, ILVL_B2_SB(src1, src0, src2, src1, src10_l, src21_l); for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB2(src, src_stride, src3, src4); - src += (2 * src_stride); - XORI_B2_128_SB(src3, src4); - ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); - ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); - - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB2_SH(src10_l, src32_l, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src21_l, src43_l, filt0, filt1, tmp3, tmp3); - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); - dst += (2 * dst_stride); + LD_SB4(src, src_stride, src3, src4, src5, src6); + src += (4 * src_stride); + XORI_B4_128_SB(src3, src4, src5, src6); + ILVRL_B2_SB(src3, src2, src32_r, src32_l); + ILVRL_B2_SB(src4, src3, src43_r, src43_l); + ILVRL_B2_SB(src5, src4, src54_r, src54_l); + ILVRL_B2_SB(src6, src5, src65_r, src65_l); + dst0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(src10_l, src32_l, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(src21_l, src43_l, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(src32_l, src54_l, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(src43_l, src65_l, filt0, filt1); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, weight_vec, + offset_vec, rnd_vec, dst0, dst1, dst2, + dst3); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst4, dst5, dst6, dst7, weight_vec, + offset_vec, rnd_vec, dst4, dst5, dst6, + dst7); + PCKEV_B4_UB(dst4, dst0, dst5, dst1, dst6, dst2, dst7, dst3, out0, out1, + out2, out3); + ST_UB4(out0, out1, out2, out3, dst, dst_stride); + dst += (4 * dst_stride); - LD_SB2(src, src_stride, src5, src2); - src += (2 * src_stride); - XORI_B2_128_SB(src5, src2); - ILVR_B2_SB(src5, src4, src2, src5, src10_r, src21_r); - ILVL_B2_SB(src5, src4, src2, src5, src10_l, src21_l); - - tmp0 = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, tmp0, tmp0); - tmp1 = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, tmp1, tmp1); - tmp2 = const_vec; - DPADD_SB2_SH(src32_l, src10_l, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src43_l, src21_l, filt0, filt1, tmp3, tmp3); - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp2, tmp3, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); - dst += (2 * dst_stride); + src2 = src6; + src10_r = src54_r; + src21_r = src65_r; + src10_l = src54_l; + src21_l = src65_l; } } @@ -3744,113 +3985,94 @@ static void hevc_vt_uniwgt_4t_24w_msa(uint8_t *src, int32_t rnd_val) { uint32_t loop_cnt; + v16u8 out0, out1, out2, out3, out4, out5; v16i8 src0, src1, src2, src3, src4, src5; - v16i8 src6, src7, src8, src9, src10, src11; - v16i8 src10_r, src32_r, src76_r, src98_r; - v16i8 src21_r, src43_r, src87_r, src109_r; - v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; - v16i8 src10_l, src32_l, src21_l, src43_l; + v16i8 src6, src7, src8, src9, src10, src11, src12, src13; + v16i8 src10_r, src32_r, src54_r, src21_r, src43_r, src65_r; + v16i8 src10_l, src32_l, src54_l, src21_l, src43_l, src65_l; + v16i8 src87_r, src98_r, src109_r, src1110_r, src1211_r, src1312_r; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8, dst9, dst10; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec, dst11; + v4i32 weight_vec, rnd_vec; src -= src_stride; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); LD_SB3(src, src_stride, src0, src1, src2); + LD_SB3(src + 16, src_stride, src7, src8, src9); + src += (3 * src_stride); XORI_B3_128_SB(src0, src1, src2); + XORI_B3_128_SB(src7, src8, src9); ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); ILVL_B2_SB(src1, src0, src2, src1, src10_l, src21_l); + ILVR_B2_SB(src8, src7, src9, src8, src87_r, src98_r); - LD_SB3(src + 16, src_stride, src6, src7, src8); - src += (3 * src_stride); - XORI_B3_128_SB(src6, src7, src8); - ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); - - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB2(src, src_stride, src3, src4); - XORI_B2_128_SB(src3, src4); + for (loop_cnt = 8; loop_cnt--;) { + LD_SB4(src, src_stride, src3, src4, src5, src6); + LD_SB4(src + 16, src_stride, src10, src11, src12, src13); + src += (4 * src_stride); + XORI_B4_128_SB(src3, src4, src5, src6); + XORI_B4_128_SB(src10, src11, src12, src13); ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); - LD_SB2(src + 16, src_stride, src9, src10); - src += (2 * src_stride); - XORI_B2_128_SB(src9, src10); - ILVR_B2_SB(src9, src8, src10, src9, src98_r, src109_r); - - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp4 = const_vec; - DPADD_SB2_SH(src10_l, src32_l, filt0, filt1, tmp4, tmp4); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - tmp5 = const_vec; - DPADD_SB2_SH(src21_l, src43_l, filt0, filt1, tmp5, tmp5); - tmp2 = const_vec; - DPADD_SB2_SH(src76_r, src98_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src87_r, src109_r, filt0, filt1, tmp3, tmp3); - - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp4, tmp5, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - HEVC_UNIW_RND_CLIP2(tmp2, tmp3, weight_vec, offset_vec, rnd_vec, - dst4_r, dst5_r, dst4_l, dst5_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - HEVC_PCK_SW_SB4(dst4_l, dst4_r, dst5_l, dst5_r, dst4_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); - ST8x2_UB(dst4_r, dst + 16, dst_stride); - dst += (2 * dst_stride); + ILVRL_B2_SB(src5, src4, src54_r, src54_l); + ILVRL_B2_SB(src6, src5, src65_r, src65_l); + ILVR_B2_SB(src10, src9, src11, src10, src109_r, src1110_r); + ILVR_B2_SB(src12, src11, src13, src12, src1211_r, src1312_r); + dst0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(src32_r, src54_r, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(src43_r, src65_r, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(src10_l, src32_l, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(src21_l, src43_l, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(src32_l, src54_l, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(src43_l, src65_l, filt0, filt1); + dst8 = HEVC_FILT_4TAP_SH(src87_r, src109_r, filt0, filt1); + dst9 = HEVC_FILT_4TAP_SH(src98_r, src1110_r, filt0, filt1); + dst10 = HEVC_FILT_4TAP_SH(src109_r, src1211_r, filt0, filt1); + dst11 = HEVC_FILT_4TAP_SH(src1110_r, src1312_r, filt0, filt1); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, weight_vec, + offset_vec, rnd_vec, dst0, dst1, dst2, + dst3); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst4, dst5, dst6, dst7, weight_vec, + offset_vec, rnd_vec, dst4, dst5, dst6, + dst7); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst8, dst9, dst10, dst11, weight_vec, + offset_vec, rnd_vec, dst8, dst9, dst10, + dst11); + PCKEV_B4_UB(dst4, dst0, dst5, dst1, dst6, dst2, dst7, dst3, out0, out1, + out2, out3); + PCKEV_B2_UB(dst9, dst8, dst11, dst10, out4, out5); + ST_UB4(out0, out1, out2, out3, dst, dst_stride); + ST8x4_UB(out4, out5, dst + 16, dst_stride); + dst += (4 * dst_stride); - LD_SB2(src, src_stride, src5, src2); - XORI_B2_128_SB(src5, src2); - ILVR_B2_SB(src5, src4, src2, src5, src10_r, src21_r); - ILVL_B2_SB(src5, src4, src2, src5, src10_l, src21_l); - LD_SB2(src + 16, src_stride, src11, src8); - src += (2 * src_stride); - XORI_B2_128_SB(src11, src8); - ILVR_B2_SB(src11, src10, src8, src11, src76_r, src87_r); - - tmp0 = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, tmp0, tmp0); - tmp4 = const_vec; - DPADD_SB2_SH(src32_l, src10_l, filt0, filt1, tmp4, tmp4); - tmp1 = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, tmp1, tmp1); - tmp5 = const_vec; - DPADD_SB2_SH(src43_l, src21_l, filt0, filt1, tmp5, tmp5); - tmp2 = const_vec; - DPADD_SB2_SH(src98_r, src76_r, filt0, filt1, tmp2, tmp2); - tmp3 = const_vec; - DPADD_SB2_SH(src109_r, src87_r, filt0, filt1, tmp3, tmp3); - - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp4, tmp5, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - HEVC_UNIW_RND_CLIP2(tmp2, tmp3, weight_vec, offset_vec, rnd_vec, - dst4_r, dst5_r, dst4_l, dst5_l); - - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - HEVC_PCK_SW_SB4(dst4_l, dst4_r, dst5_l, dst5_r, dst4_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); - ST8x2_UB(dst4_r, dst + 16, dst_stride); - dst += (2 * dst_stride); + src2 = src6; + src9 = src13; + src10_r = src54_r; + src21_r = src65_r; + src10_l = src54_l; + src21_l = src65_l; + src87_r = src1211_r; + src98_r = src1312_r; } } @@ -3864,104 +4086,87 @@ static void hevc_vt_uniwgt_4t_32w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - int32_t loop_cnt; - uint8_t *dst_tmp = dst + 16; - v16i8 src0, src1, src2, src3, src4, src6, src7, src8, src9, src10; + uint32_t loop_cnt; + v16u8 out0, out1, out2, out3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9; v16i8 src10_r, src32_r, src76_r, src98_r; - v16i8 src21_r, src43_r, src87_r, src109_r; - v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + v16i8 src21_r, src43_r, src65_r, src87_r; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; v16i8 src10_l, src32_l, src76_l, src98_l; - v16i8 src21_l, src43_l, src87_l, src109_l; + v16i8 src21_l, src43_l, src65_l, src87_l; v8i16 filt0, filt1; - v8i16 filter_vec, const_vec; - v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r, dst6_r, dst7_r; - v4i32 dst0_l, dst1_l, dst2_l, dst3_l, dst4_l, dst5_l, dst6_l, dst7_l; + v8i16 filter_vec, weight_vec_h, offset_vec, denom_vec; + v4i32 weight_vec, rnd_vec; src -= src_stride; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; weight = weight & 0x0000FFFF; weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + weight *= 128; + rnd_val -= 6; + + weight_vec_h = __msa_fill_h(weight); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val); + + weight_vec_h = __msa_srar_h(weight_vec_h, denom_vec); + offset_vec = __msa_adds_s_h(offset_vec, weight_vec_h); + filter_vec = LD_SH(filter); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); LD_SB3(src, src_stride, src0, src1, src2); - XORI_B3_128_SB(src0, src1, src2); + LD_SB3(src + 16, src_stride, src5, src6, src7); + src += (3 * src_stride); + XORI_B6_128_SB(src0, src1, src2, src5, src6, src7); ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); ILVL_B2_SB(src1, src0, src2, src1, src10_l, src21_l); - - LD_SB3(src + 16, src_stride, src6, src7, src8); - src += (3 * src_stride); - XORI_B3_128_SB(src6, src7, src8); - ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); - ILVL_B2_SB(src7, src6, src8, src7, src76_l, src87_l); + ILVR_B2_SB(src6, src5, src7, src6, src65_r, src76_r); + ILVL_B2_SB(src6, src5, src7, src6, src65_l, src76_l); for (loop_cnt = (height >> 1); loop_cnt--;) { LD_SB2(src, src_stride, src3, src4); - XORI_B2_128_SB(src3, src4); + LD_SB2(src + 16, src_stride, src8, src9); + src += (2 * src_stride); + XORI_B4_128_SB(src3, src4, src8, src9); ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); + ILVRL_B2_SB(src8, src7, src87_r, src87_l); + ILVRL_B2_SB(src9, src8, src98_r, src98_l); + dst0 = HEVC_FILT_4TAP_SH(src10_r, src32_r, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(src21_r, src43_r, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(src10_l, src32_l, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(src21_l, src43_l, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(src65_r, src87_r, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(src76_r, src98_r, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(src65_l, src87_l, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(src76_l, src98_l, filt0, filt1); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst0, dst1, dst2, dst3, weight_vec, + offset_vec, rnd_vec, dst0, dst1, dst2, + dst3); + HEVC_UNIW_RND_CLIP4_MAX_SATU_H(dst4, dst5, dst6, dst7, weight_vec, + offset_vec, rnd_vec, dst4, dst5, dst6, + dst7); + PCKEV_B4_UB(dst2, dst0, dst3, dst1, dst6, dst4, dst7, dst5, out0, out1, + out2, out3); + ST_UB2(out0, out2, dst, 16); + dst += dst_stride; + ST_UB2(out1, out3, dst, 16); + dst += dst_stride; - tmp0 = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, tmp0, tmp0); - tmp4 = const_vec; - DPADD_SB2_SH(src10_l, src32_l, filt0, filt1, tmp4, tmp4); - tmp1 = const_vec; - DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, tmp1, tmp1); - tmp5 = const_vec; - DPADD_SB2_SH(src21_l, src43_l, filt0, filt1, tmp5, tmp5); - - HEVC_UNIW_RND_CLIP4(tmp0, tmp1, tmp4, tmp5, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r, - dst0_l, dst1_l, dst2_l, dst3_l); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst2_l, dst2_r, - dst1_l, dst1_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST_SW2(dst0_r, dst1_r, dst, dst_stride); - dst += (2 * dst_stride); - + src2 = src4; + src7 = src9; src10_r = src32_r; src21_r = src43_r; src10_l = src32_l; src21_l = src43_l; - src2 = src4; - - LD_SB2(src + 16, src_stride, src9, src10); - src += (2 * src_stride); - XORI_B2_128_SB(src9, src10); - ILVR_B2_SB(src9, src8, src10, src9, src98_r, src109_r); - ILVL_B2_SB(src9, src8, src10, src9, src98_l, src109_l); - - tmp2 = const_vec; - DPADD_SB2_SH(src76_r, src98_r, filt0, filt1, tmp2, tmp2); - tmp6 = const_vec; - DPADD_SB2_SH(src76_l, src98_l, filt0, filt1, tmp6, tmp6); - tmp3 = const_vec; - DPADD_SB2_SH(src87_r, src109_r, filt0, filt1, tmp3, tmp3); - tmp7 = const_vec; - DPADD_SB2_SH(src87_l, src109_l, filt0, filt1, tmp7, tmp7); - - HEVC_UNIW_RND_CLIP4(tmp2, tmp3, tmp6, tmp7, - weight_vec, offset_vec, rnd_vec, - dst4_r, dst5_r, dst6_r, dst7_r, - dst4_l, dst5_l, dst6_l, dst7_l); - - HEVC_PCK_SW_SB8(dst4_l, dst4_r, dst6_l, dst6_r, - dst5_l, dst5_r, dst7_l, dst7_r, dst4_r, dst5_r); - ST_SW2(dst4_r, dst5_r, dst_tmp, dst_stride); - dst_tmp += (2 * dst_stride); - + src65_r = src87_r; src76_r = src98_r; - src87_r = src109_r; + src65_l = src87_l; src76_l = src98_l; - src87_l = src109_l; - src8 = src10; } } @@ -3971,22 +4176,20 @@ static void hevc_hv_uniwgt_4t_4x2_msa(uint8_t *src, int32_t dst_stride, const int8_t *filter_x, const int8_t *filter_y, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { + v16u8 out; v16i8 src0, src1, src2, src3, src4; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; - v8i16 filter_vec, const_vec; + v8i16 filt_h0, filt_h1, filter_vec, tmp; v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; - v4i32 dst0_r, dst1_r; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 dst20, dst31, dst42, dst10, dst32, dst21, dst43; + v8i16 offset_vec, const_128, denom_vec; + v4i32 dst0, dst1, weight_vec, rnd_vec; src -= (src_stride + 1); @@ -3994,63 +4197,41 @@ static void hevc_hv_uniwgt_4t_4x2_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); - - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); - LD_SB2(src, src_stride, src3, src4); - XORI_B2_128_SB(src3, src4); - - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - - MUL2(dst0_r, weight_vec, dst1_r, weight_vec, dst0_r, dst1_r); - SRAR_W2_SW(dst0_r, dst1_r, rnd_vec); - ADD2(dst0_r, offset_vec, dst1_r, offset_vec, dst0_r, dst1_r); - dst0_r = CLIP_SW_0_255(dst0_r); - dst1_r = CLIP_SW_0_255(dst1_r); - - HEVC_PCK_SW_SB2(dst1_r, dst0_r, dst0_r); - ST4x2_UB(dst0_r, dst, dst_stride); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val - 6); + const_128 = __msa_fill_h((128 * weight)); + offset_vec += __msa_srar_h(const_128, denom_vec); + + LD_SB5(src, src_stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + VSHF_B2_SB(src0, src2, src0, src2, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src3, src1, src3, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src4, src2, src4, mask0, mask1, vec4, vec5); + dst20 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst31 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst42 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + ILVRL_H2_SH(dst31, dst20, dst10, dst32); + ILVRL_H2_SH(dst42, dst31, dst21, dst43); + dst0 = HEVC_FILT_4TAP(dst10, dst32, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21, dst43, filt_h0, filt_h1); + dst0 >>= 6; + dst1 >>= 6; + MUL2(dst0, weight_vec, dst1, weight_vec, dst0, dst1); + SRAR_W2_SW(dst0, dst1, rnd_vec); + tmp = __msa_pckev_h((v8i16) dst1, (v8i16) dst0); + tmp += offset_vec; + tmp = CLIP_SH_0_255_MAX_SATU(tmp); + out = (v16u8) __msa_pckev_b((v16i8) tmp, (v16i8) tmp); + ST4x2_UB(out, dst, dst_stride); } static void hevc_hv_uniwgt_4t_4x4_msa(uint8_t *src, @@ -4059,22 +4240,20 @@ static void hevc_hv_uniwgt_4t_4x4_msa(uint8_t *src, int32_t dst_stride, const int8_t *filter_x, const int8_t *filter_y, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { + v16u8 out; v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1, filter_vec, tmp0, tmp1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; - v4i32 weight_vec, offset_vec, rnd_vec; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dst30, dst41, dst52, dst63, dst10, dst32, dst54, dst21, dst43, dst65; + v8i16 offset_vec, const_128, denom_vec; + v4i32 dst0, dst1, dst2, dst3, weight_vec, rnd_vec; src -= (src_stride + 1); @@ -4082,76 +4261,46 @@ static void hevc_hv_uniwgt_4t_4x4_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); - - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); - - LD_SB4(src, src_stride, src3, src4, src5, src6); - XORI_B4_128_SB(src3, src4, src5, src6); - - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val - 6); + const_128 = __msa_fill_h((128 * weight)); + offset_vec += __msa_srar_h(const_128, denom_vec); - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - dst10_r = __msa_ilvr_h(dst5, dst4); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_r >>= 6; - - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - dst21_r = __msa_ilvr_h(dst2, dst5); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_r >>= 6; - - HEVC_HV_UNIW_RND_CLIP4(dst0_r, dst1_r, dst2_r, dst3_r, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r); - HEVC_PCK_SW_SB4(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r); - ST4x4_UB(dst0_r, dst0_r, 0, 1, 2, 3, dst, dst_stride); + LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + VSHF_B2_SB(src0, src3, src0, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src4, src1, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src5, src2, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src6, src3, src6, mask0, mask1, vec6, vec7); + dst30 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst41 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst52 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst63 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + ILVRL_H2_SH(dst41, dst30, dst10, dst43); + ILVRL_H2_SH(dst52, dst41, dst21, dst54); + ILVRL_H2_SH(dst63, dst52, dst32, dst65); + dst0 = HEVC_FILT_4TAP(dst10, dst32, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21, dst43, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32, dst54, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43, dst65, filt_h0, filt_h1); + SRA_4V(dst0, dst1, dst2, dst3, 6); + MUL2(dst0, weight_vec, dst1, weight_vec, dst0, dst1); + MUL2(dst2, weight_vec, dst3, weight_vec, dst2, dst3); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + PCKEV_H2_SH(dst1, dst0, dst3, dst2, tmp0, tmp1); + ADD2(tmp0, offset_vec, tmp1, offset_vec, tmp0, tmp1); + CLIP_SH2_0_255_MAX_SATU(tmp0, tmp1); + out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); + ST4x4_UB(out, out, 0, 1, 2, 3, dst, dst_stride); } static void hevc_hv_uniwgt_4t_4multx8mult_msa(uint8_t *src, @@ -4166,18 +4315,18 @@ static void hevc_hv_uniwgt_4t_4multx8mult_msa(uint8_t *src, int32_t rnd_val) { uint32_t loop_cnt; + v16u8 out0, out1; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8, dst9; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r, dst6_r, dst7_r; + v8i16 filt_h0, filt_h1, filter_vec, tmp0, tmp1, tmp2, tmp3; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dst10, dst21, dst22, dst73, dst84, dst95, dst106; v8i16 dst10_r, dst32_r, dst54_r, dst76_r; v8i16 dst21_r, dst43_r, dst65_r, dst87_r; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 dst98_r, dst109_r, offset_vec, const_128, denom_vec; + v4i32 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, weight_vec, rnd_vec; src -= (src_stride + 1); @@ -4185,110 +4334,79 @@ static void hevc_hv_uniwgt_4t_4multx8mult_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val - 6); + const_128 = __msa_fill_h((128 * weight)); + offset_vec += __msa_srar_h(const_128, denom_vec); + LD_SB3(src, src_stride, src0, src1, src2); src += (3 * src_stride); XORI_B3_128_SB(src0, src1, src2); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); - + VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src2, src1, src2, mask0, mask1, vec2, vec3); + dst10 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst21 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + ILVRL_H2_SH(dst21, dst10, dst10_r, dst21_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst21, 1); + for (loop_cnt = height >> 3; loop_cnt--;) { LD_SB8(src, src_stride, src3, src4, src5, src6, src7, src8, src9, src10); src += (8 * src_stride); XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - dst54_r = __msa_ilvr_h(dst5, dst4); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); - dst2_r >>= 6; - - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - dst65_r = __msa_ilvr_h(dst6, dst5); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); - dst3_r >>= 6; - - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); - dst76_r = __msa_ilvr_h(dst7, dst6); - dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); - dst4_r >>= 6; - - VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec0, vec1); - dst8 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst8, dst8); - dst87_r = __msa_ilvr_h(dst8, dst7); - dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); - dst5_r >>= 6; - - VSHF_B2_SB(src9, src9, src9, src9, mask0, mask1, vec0, vec1); - dst9 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst9, dst9); - dst10_r = __msa_ilvr_h(dst9, dst8); - dst6_r = HEVC_FILT_4TAP(dst76_r, dst10_r, filt_h0, filt_h1); - dst6_r >>= 6; - - VSHF_B2_SB(src10, src10, src10, src10, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - dst21_r = __msa_ilvr_h(dst2, dst9); - dst7_r = HEVC_FILT_4TAP(dst87_r, dst21_r, filt_h0, filt_h1); - dst7_r >>= 6; - - HEVC_HV_UNIW_RND_CLIP4(dst0_r, dst1_r, dst2_r, dst3_r, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst2_r, dst3_r); - HEVC_PCK_SW_SB4(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r); - ST4x4_UB(dst0_r, dst0_r, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); + VSHF_B2_SB(src3, src7, src3, src7, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src8, src4, src8, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src9, src5, src9, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src10, src6, src10, mask0, mask1, vec6, vec7); + dst73 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst84 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst95 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst106 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dst32_r = __msa_ilvr_h(dst73, dst22); + ILVRL_H2_SH(dst84, dst73, dst43_r, dst87_r); + ILVRL_H2_SH(dst95, dst84, dst54_r, dst98_r); + ILVRL_H2_SH(dst106, dst95, dst65_r, dst109_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst73, 1); + dst76_r = __msa_ilvr_h(dst22, dst106); + dst0 = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4 = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5 = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6 = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7 = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + SRA_4V(dst0, dst1, dst2, dst3, 6); + SRA_4V(dst4, dst5, dst6, dst7, 6); + MUL2(dst0, weight_vec, dst1, weight_vec, dst0, dst1); + MUL2(dst2, weight_vec, dst3, weight_vec, dst2, dst3); + MUL2(dst4, weight_vec, dst5, weight_vec, dst4, dst5); + MUL2(dst6, weight_vec, dst7, weight_vec, dst6, dst7); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + SRAR_W4_SW(dst4, dst5, dst6, dst7, rnd_vec); + PCKEV_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, tmp0, tmp1, + tmp2, tmp3); + ADD2(tmp0, offset_vec, tmp1, offset_vec, tmp0, tmp1); + ADD2(tmp2, offset_vec, tmp3, offset_vec, tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); + dst += (8 * dst_stride); - HEVC_HV_UNIW_RND_CLIP4(dst4_r, dst5_r, dst6_r, dst7_r, - weight_vec, offset_vec, rnd_vec, - dst4_r, dst5_r, dst6_r, dst7_r); - HEVC_PCK_SW_SB4(dst5_r, dst4_r, dst7_r, dst6_r, dst0_r); - ST4x4_UB(dst0_r, dst0_r, 0, 1, 2, 3, dst, dst_stride); - dst += (4 * dst_stride); + dst10_r = dst98_r; + dst21_r = dst109_r; + dst22 = (v8i16) __msa_splati_d((v2i64) dst106, 1); } } @@ -4305,11 +4423,11 @@ static void hevc_hv_uniwgt_4t_4w_msa(uint8_t *src, { if (2 == height) { hevc_hv_uniwgt_4t_4x2_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, weight, + filter_x, filter_y, weight, offset, rnd_val); } else if (4 == height) { hevc_hv_uniwgt_4t_4x4_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, weight, + filter_x,filter_y, weight, offset, rnd_val); } else if (0 == (height % 8)) { hevc_hv_uniwgt_4t_4multx8mult_msa(src, src_stride, dst, dst_stride, @@ -4329,20 +4447,22 @@ static void hevc_hv_uniwgt_4t_6w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6; + v16u8 out0, out1, out2; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v4i32 dst0_r, dst0_l, dst1_r, dst1_l; - v4i32 weight_vec, offset_vec, rnd_vec; - v4i32 dst2_r, dst2_l, dst3_r, dst3_l; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; - v8i16 dst10_l, dst32_l, dst21_l, dst43_l; + v8i16 filt_h0, filt_h1, filter_vec; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6, dsth7, dsth8, dsth9; + v8i16 dsth10, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r, dst98_r, dst21_r, dst43_r; + v8i16 dst65_r, dst87_r, dst109_r, dst10_l, dst32_l, dst54_l, dst76_l; + v8i16 dst98_l, dst21_l, dst43_l, dst65_l, dst87_l, dst109_l; + v8i16 dst1021_l, dst3243_l, dst5465_l, dst7687_l, dst98109_l; + v8i16 offset_vec, const_128, denom_vec; + v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r, dst6_r, dst7_r; + v4i32 dst0_l, dst1_l, dst2_l, dst3_l, weight_vec, rnd_vec; src -= (src_stride + 1); @@ -4350,20 +4470,20 @@ static void hevc_hv_uniwgt_4t_6w_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val - 6); + const_128 = __msa_fill_h((128 * weight)); + offset_vec += __msa_srar_h(const_128, denom_vec); + LD_SB3(src, src_stride, src0, src1, src2); src += (3 * src_stride); XORI_B3_128_SB(src0, src1, src2); @@ -4371,72 +4491,78 @@ static void hevc_hv_uniwgt_4t_6w_msa(uint8_t *src, VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - - ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); - ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - - for (loop_cnt = height >> 2; loop_cnt--;) { - LD_SB4(src, src_stride, src3, src4, src5, src6); - src += (4 * src_stride); - XORI_B4_128_SB(src3, src4, src5, src6); - - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - ILVRL_H2_SH(dst5, dst4, dst10_r, dst10_l); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_l = HEVC_FILT_4TAP(dst32_l, dst10_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; - - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - ILVRL_H2_SH(dst2, dst5, dst21_r, dst21_l); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_l = HEVC_FILT_4TAP(dst43_l, dst21_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; - - HEVC_HV_UNIW_RND_CLIP4(dst0_r, dst1_r, dst0_l, dst1_l, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst0_l, dst1_l); - HEVC_HV_UNIW_RND_CLIP4(dst2_r, dst3_r, dst2_l, dst3_l, - weight_vec, offset_vec, rnd_vec, - dst2_r, dst3_r, dst2_l, dst3_l); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST6x4_UB(dst0_r, dst1_r, dst, dst_stride); - dst += (4 * dst_stride); - } + dsth0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); + + LD_SB8(src, src_stride, src3, src4, src5, src6, src7, src8, src9, src10); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + dsth3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src9, src9, src9, src9, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src10, src10, src10, src10, mask0, mask1, vec6, vec7); + dsth7 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth8 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth9 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth10 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); + ILVRL_H2_SH(dsth7, dsth6, dst76_r, dst76_l); + ILVRL_H2_SH(dsth8, dsth7, dst87_r, dst87_l); + ILVRL_H2_SH(dsth9, dsth8, dst98_r, dst98_l); + ILVRL_H2_SH(dsth10, dsth9, dst109_r, dst109_l); + PCKEV_D2_SH(dst21_l, dst10_l, dst43_l, dst32_l, dst1021_l, dst3243_l); + PCKEV_D2_SH(dst65_l, dst54_l, dst87_l, dst76_l, dst5465_l, dst7687_l); + dst98109_l = (v8i16) __msa_pckev_d((v2i64) dst109_l, (v2i64) dst98_l); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6_r = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7_r = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst1021_l, dst3243_l, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst3243_l, dst5465_l, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst5465_l, dst7687_l, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst7687_l, dst98109_l, filt_h0, filt_h1); + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRA_4V(dst4_r, dst5_r, dst6_r, dst7_r, 6); + SRA_4V(dst0_l, dst1_l, dst2_l, dst3_l, 6); + MUL2(dst0_r, weight_vec, dst1_r, weight_vec, dst0_r, dst1_r); + MUL2(dst2_r, weight_vec, dst3_r, weight_vec, dst2_r, dst3_r); + MUL2(dst4_r, weight_vec, dst5_r, weight_vec, dst4_r, dst5_r); + MUL2(dst6_r, weight_vec, dst7_r, weight_vec, dst6_r, dst7_r); + MUL2(dst0_l, weight_vec, dst1_l, weight_vec, dst0_l, dst1_l); + MUL2(dst2_l, weight_vec, dst3_l, weight_vec, dst2_l, dst3_l); + SRAR_W4_SW(dst0_r, dst1_r, dst2_r, dst3_r, rnd_vec); + SRAR_W4_SW(dst4_r, dst5_r, dst6_r, dst7_r, rnd_vec); + SRAR_W4_SW(dst0_l, dst1_l, dst2_l, dst3_l, rnd_vec); + PCKEV_H2_SH(dst1_r, dst0_r, dst3_r, dst2_r, tmp0, tmp1); + PCKEV_H2_SH(dst5_r, dst4_r, dst7_r, dst6_r, tmp2, tmp3); + PCKEV_H2_SH(dst1_l, dst0_l, dst3_l, dst2_l, tmp4, tmp5); + ADD2(tmp0, offset_vec, tmp1, offset_vec, tmp0, tmp1); + ADD2(tmp2, offset_vec, tmp3, offset_vec, tmp2, tmp3); + ADD2(tmp4, offset_vec, tmp5, offset_vec, tmp4, tmp5); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + CLIP_SH2_0_255_MAX_SATU(tmp4, tmp5); + PCKEV_B3_UB(tmp1, tmp0, tmp3, tmp2, tmp5, tmp4, out0, out1, out2); + ST4x8_UB(out0, out1, dst, dst_stride); + ST2x4_UB(out2, 0, dst + 4, dst_stride); + dst += 4 * dst_stride; + ST2x4_UB(out2, 4, dst + 4, dst_stride); } static void hevc_hv_uniwgt_4t_8x2_msa(uint8_t *src, @@ -4445,23 +4571,24 @@ static void hevc_hv_uniwgt_4t_8x2_msa(uint8_t *src, int32_t dst_stride, const int8_t *filter_x, const int8_t *filter_y, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { + v16u8 out; v16i8 src0, src1, src2, src3, src4; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1, filter_vec; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; v8i16 dst0, dst1, dst2, dst3, dst4; v4i32 dst0_r, dst0_l, dst1_r, dst1_l; v8i16 dst10_r, dst32_r, dst21_r, dst43_r; v8i16 dst10_l, dst32_l, dst21_l, dst43_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 tmp0, tmp1; + v8i16 offset_vec, const_128, denom_vec; + v4i32 weight_vec, rnd_vec; src -= (src_stride + 1); @@ -4469,65 +4596,144 @@ static void hevc_hv_uniwgt_4t_8x2_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val - 6); + const_128 = __msa_fill_h((128 * weight)); + offset_vec += __msa_srar_h(const_128, denom_vec); + LD_SB5(src, src_stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec8, vec9); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec8, vec9, filt0, filt1); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - - LD_SB2(src, src_stride, src3, src4); - src += (2 * src_stride); - XORI_B2_128_SB(src3, src4); - - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - - HEVC_HV_UNIW_RND_CLIP4(dst0_r, dst1_r, dst0_l, dst1_l, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst0_l, dst1_l); - HEVC_PCK_SW_SB4(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r); - ST8x2_UB(dst0_r, dst, dst_stride); - dst += (2 * dst_stride); + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + MUL2(dst0_r, weight_vec, dst1_r, weight_vec, dst0_r, dst1_r); + MUL2(dst0_l, weight_vec, dst1_l, weight_vec, dst0_l, dst1_l); + SRAR_W4_SW(dst0_r, dst0_l, dst1_r, dst1_l, rnd_vec); + PCKEV_H2_SH(dst0_l, dst0_r, dst1_l, dst1_r, tmp0, tmp1); + ADD2(tmp0, offset_vec, tmp1, offset_vec, tmp0, tmp1); + CLIP_SH2_0_255_MAX_SATU(tmp0, tmp1); + out = (v16u8) __msa_pckev_b((v16i8) tmp1, (v16i8) tmp0); + ST8x2_UB(out, dst, dst_stride); +} + +static void hevc_hv_uniwgt_4t_8multx4_msa(uint8_t *src, + int32_t src_stride, + uint8_t *dst, + int32_t dst_stride, + const int8_t *filter_x, + const int8_t *filter_y, + int32_t width8mult, + int32_t weight, + int32_t offset, + int32_t rnd_val) +{ + uint32_t cnt; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, mask0, mask1; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 filt0, filt1, filt_h0, filt_h1, filter_vec; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, tmp0, tmp1, tmp2, tmp3; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; + v8i16 offset_vec, const_128, denom_vec; + v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + v4i32 weight_vec, rnd_vec; + + src -= (src_stride + 1); + + filter_vec = LD_SH(filter_x); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + + weight_vec = __msa_fill_w(weight); + rnd_vec = __msa_fill_w(rnd_val); + + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val - 6); + const_128 = __msa_fill_h((128 * weight)); + offset_vec += __msa_srar_h(const_128, denom_vec); + + for (cnt = width8mult; cnt--;) { + LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); + src += 8; + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); + ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + MUL2(dst0_r, weight_vec, dst1_r, weight_vec, dst0_r, dst1_r); + MUL2(dst2_r, weight_vec, dst3_r, weight_vec, dst2_r, dst3_r); + MUL2(dst0_l, weight_vec, dst1_l, weight_vec, dst0_l, dst1_l); + MUL2(dst2_l, weight_vec, dst3_l, weight_vec, dst2_l, dst3_l); + SRAR_W4_SW(dst0_r, dst0_l, dst1_r, dst1_l, rnd_vec); + SRAR_W4_SW(dst2_r, dst2_l, dst3_r, dst3_l, rnd_vec); + PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, tmp0, tmp1, tmp2, tmp3); + ADD2(tmp0, offset_vec, tmp1, offset_vec, tmp0, tmp1); + ADD2(tmp2, offset_vec, tmp3, offset_vec, tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST8x4_UB(out0, out1, dst, dst_stride); + dst += 8; + } } static void hevc_hv_uniwgt_4t_8x6_msa(uint8_t *src, @@ -4536,26 +4742,27 @@ static void hevc_hv_uniwgt_4t_8x6_msa(uint8_t *src, int32_t dst_stride, const int8_t *filter_x, const int8_t *filter_y, - int32_t height, int32_t weight, int32_t offset, int32_t rnd_val) { + v16u8 out0, out1, out2; v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1, filter_vec; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; + v16i8 vec10, vec11, vec12, vec13, vec14, vec15, vec16, vec17; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; - v4i32 dst4_r, dst4_l, dst5_r, dst5_l; + v4i32 dst4_r, dst4_l, dst5_r, dst5_l, weight_vec, rnd_vec; v8i16 dst10_r, dst32_r, dst10_l, dst32_l; v8i16 dst21_r, dst43_r, dst21_l, dst43_l; v8i16 dst54_r, dst54_l, dst65_r, dst65_l; v8i16 dst76_r, dst76_l, dst87_r, dst87_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + v8i16 offset_vec, const_128, denom_vec; src -= (src_stride + 1); @@ -4563,126 +4770,87 @@ static void hevc_hv_uniwgt_4t_8x6_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); - - XORI_B3_128_SB(src0, src1, src2); - + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val - 6); + const_128 = __msa_fill_h((128 * weight)); + offset_vec += __msa_srar_h(const_128, denom_vec); + + LD_SB5(src, src_stride, src0, src1, src2, src3, src4); + src += (5 * src_stride); + LD_SB4(src, src_stride, src5, src6, src7, src8); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B4_128_SB(src5, src6, src7, src8); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec8, vec9); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec10, vec11); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec12, vec13); + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec14, vec15); + VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec16, vec17); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst3 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec8, vec9, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec10, vec11, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec12, vec13, filt0, filt1); + dst7 = HEVC_FILT_4TAP_SH(vec14, vec15, filt0, filt1); + dst8 = HEVC_FILT_4TAP_SH(vec16, vec17, filt0, filt1); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - - LD_SB2(src, src_stride, src3, src4); - src += (2 * src_stride); - XORI_B2_128_SB(src3, src4); - - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); + ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - - LD_SB2(src, src_stride, src5, src6); - src += (2 * src_stride); - XORI_B2_128_SB(src5, src6); - - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; - - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; - - LD_SB2(src, src_stride, src7, src8); - src += (2 * src_stride); - XORI_B2_128_SB(src7, src8); - - /* row 7 */ - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); - ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); dst4_l = HEVC_FILT_4TAP(dst54_l, dst76_l, filt_h0, filt_h1); - - dst4_r >>= 6; - dst4_l >>= 6; - - /* row 8 */ - VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec0, vec1); - dst8 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst8, dst8); - ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); dst5_l = HEVC_FILT_4TAP(dst65_l, dst87_l, filt_h0, filt_h1); - dst5_r >>= 6; - dst5_l >>= 6; - - HEVC_HV_UNIW_RND_CLIP4(dst0_r, dst1_r, dst0_l, dst1_l, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst0_l, dst1_l); - HEVC_HV_UNIW_RND_CLIP4(dst2_r, dst3_r, dst2_l, dst3_l, - weight_vec, offset_vec, rnd_vec, - dst2_r, dst3_r, dst2_l, dst3_l); - HEVC_HV_UNIW_RND_CLIP4(dst4_r, dst5_r, dst4_l, dst5_l, - weight_vec, offset_vec, rnd_vec, - dst4_r, dst5_r, dst4_l, dst5_l); - HEVC_PCK_SW_SB12(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst4_l, dst4_r, dst5_l, dst5_r, dst0_r, dst1_r, dst2_r); - ST8x4_UB(dst0_r, dst1_r, dst, dst_stride); + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + SRA_4V(dst4_r, dst4_l, dst5_r, dst5_l, 6); + MUL2(dst0_r, weight_vec, dst1_r, weight_vec, dst0_r, dst1_r); + MUL2(dst2_r, weight_vec, dst3_r, weight_vec, dst2_r, dst3_r); + MUL2(dst4_r, weight_vec, dst5_r, weight_vec, dst4_r, dst5_r); + MUL2(dst0_l, weight_vec, dst1_l, weight_vec, dst0_l, dst1_l); + MUL2(dst2_l, weight_vec, dst3_l, weight_vec, dst2_l, dst3_l); + MUL2(dst4_l, weight_vec, dst5_l, weight_vec, dst4_l, dst5_l); + SRAR_W4_SW(dst0_r, dst0_l, dst1_r, dst1_l, rnd_vec); + SRAR_W4_SW(dst2_r, dst2_l, dst3_r, dst3_l, rnd_vec); + SRAR_W4_SW(dst4_r, dst4_l, dst5_r, dst5_l, rnd_vec); + PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, dst3_r, + tmp0, tmp1, tmp2, tmp3); + PCKEV_H2_SH(dst4_l, dst4_r, dst5_l, dst5_r, tmp4, tmp5); + ADD2(tmp0, offset_vec, tmp1, offset_vec, tmp0, tmp1); + ADD2(tmp2, offset_vec, tmp3, offset_vec, tmp2, tmp3); + ADD2(tmp4, offset_vec, tmp5, offset_vec, tmp4, tmp5); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + CLIP_SH2_0_255_MAX_SATU(tmp4, tmp5); + PCKEV_B3_UB(tmp1, tmp0, tmp3, tmp2, tmp5, tmp4, out0, out1, out2); + ST8x4_UB(out0, out1, dst, dst_stride); dst += (4 * dst_stride); - ST8x2_UB(dst2_r, dst, dst_stride); + ST8x2_UB(out2, dst, dst_stride); } static void hevc_hv_uniwgt_4t_8multx4mult_msa(uint8_t *src, @@ -4695,24 +4863,25 @@ static void hevc_hv_uniwgt_4t_8multx4mult_msa(uint8_t *src, int32_t weight, int32_t offset, int32_t rnd_val, - int32_t width) + int32_t width8mult) { uint32_t loop_cnt, cnt; uint8_t *src_tmp; uint8_t *dst_tmp; + v16u8 out0, out1; v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1, filter_vec; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; - v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, tmp0, tmp1, tmp2, tmp3; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; v4i32 dst0_r, dst0_l, dst1_r, dst1_l; - v4i32 weight_vec, offset_vec, rnd_vec; + v8i16 offset_vec, const_128, denom_vec; v4i32 dst2_r, dst2_l, dst3_r, dst3_l; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; - v8i16 dst10_l, dst32_l, dst21_l, dst43_l; + v4i32 weight_vec, rnd_vec; src -= (src_stride + 1); @@ -4720,21 +4889,21 @@ static void hevc_hv_uniwgt_4t_8multx4mult_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; - const_vec = __msa_ldi_h(128); - const_vec <<= 6; - weight_vec = __msa_fill_w(weight); - offset_vec = __msa_fill_w(offset); rnd_vec = __msa_fill_w(rnd_val); - for (cnt = width >> 3; cnt--;) { + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val - 6); + const_128 = __msa_fill_h((128 * weight)); + offset_vec += __msa_srar_h(const_128, denom_vec); + + for (cnt = width8mult; cnt--;) { src_tmp = src; dst_tmp = dst; @@ -4745,12 +4914,9 @@ static void hevc_hv_uniwgt_4t_8multx4mult_msa(uint8_t *src, VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + dst0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); @@ -4761,51 +4927,47 @@ static void hevc_hv_uniwgt_4t_8multx4mult_msa(uint8_t *src, XORI_B4_128_SB(src3, src4, src5, src6); VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + dst3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - ILVRL_H2_SH(dst5, dst4, dst10_r, dst10_l); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_l = HEVC_FILT_4TAP(dst32_l, dst10_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; - - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - ILVRL_H2_SH(dst2, dst5, dst21_r, dst21_l); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_l = HEVC_FILT_4TAP(dst43_l, dst21_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; - - HEVC_HV_UNIW_RND_CLIP4(dst0_r, dst1_r, dst0_l, dst1_l, - weight_vec, offset_vec, rnd_vec, - dst0_r, dst1_r, dst0_l, dst1_l); - HEVC_HV_UNIW_RND_CLIP4(dst2_r, dst3_r, dst2_l, dst3_l, - weight_vec, offset_vec, rnd_vec, - dst2_r, dst3_r, dst2_l, dst3_l); - HEVC_PCK_SW_SB8(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst_tmp, dst_stride); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + MUL2(dst0_r, weight_vec, dst1_r, weight_vec, dst0_r, dst1_r); + MUL2(dst2_r, weight_vec, dst3_r, weight_vec, dst2_r, dst3_r); + MUL2(dst0_l, weight_vec, dst1_l, weight_vec, dst0_l, dst1_l); + MUL2(dst2_l, weight_vec, dst3_l, weight_vec, dst2_l, dst3_l); + SRAR_W4_SW(dst0_r, dst0_l, dst1_r, dst1_l, rnd_vec); + SRAR_W4_SW(dst2_r, dst2_l, dst3_r, dst3_l, rnd_vec); + PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, tmp0, tmp1, tmp2, tmp3); + ADD2(tmp0, offset_vec, tmp1, offset_vec, tmp0, tmp1); + ADD2(tmp2, offset_vec, tmp3, offset_vec, tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST8x4_UB(out0, out1, dst_tmp, dst_stride); dst_tmp += (4 * dst_stride); + + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dst2 = dst6; } src += 8; @@ -4827,16 +4989,20 @@ static void hevc_hv_uniwgt_4t_8w_msa(uint8_t *src, if (2 == height) { hevc_hv_uniwgt_4t_8x2_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, weight, + filter_x, filter_y, weight, offset, rnd_val); + } else if (4 == height) { + hevc_hv_uniwgt_4t_8multx4_msa(src, src_stride, dst, dst_stride, + filter_x, filter_y, 1, weight, + offset, rnd_val); } else if (6 == height) { hevc_hv_uniwgt_4t_8x6_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, weight, + filter_x, filter_y, weight, offset, rnd_val); } else if (0 == (height % 4)) { hevc_hv_uniwgt_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, filter_x, filter_y, height, weight, - offset, rnd_val, 8); + offset, rnd_val, 1); } } @@ -4851,12 +5017,170 @@ static void hevc_hv_uniwgt_4t_12w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - hevc_hv_uniwgt_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, weight, - offset, rnd_val, 8); - hevc_hv_uniwgt_4t_4w_msa(src + 8, src_stride, dst + 8, dst_stride, - filter_x, filter_y, height, weight, - offset, rnd_val); + uint32_t loop_cnt; + uint8_t *src_tmp, *dst_tmp; + v16u8 out0, out1; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 mask0, mask1, mask2, mask3; + v8i16 filt0, filt1, filt_h0, filt_h1, filter_vec, tmp0, tmp1, tmp2, tmp3; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6; + v8i16 dst10, dst21, dst22, dst73, dst84, dst95, dst106; + v8i16 dst76_r, dst98_r, dst87_r, dst109_r; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; + v8i16 offset_vec, const_128, denom_vec; + v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + v4i32 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, weight_vec, rnd_vec; + + src -= (src_stride + 1); + + filter_vec = LD_SH(filter_x); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + + weight_vec = __msa_fill_w(weight); + rnd_vec = __msa_fill_w(rnd_val); + + offset_vec = __msa_fill_h(offset); + denom_vec = __msa_fill_h(rnd_val - 6); + const_128 = __msa_fill_h((128 * weight)); + offset_vec += __msa_srar_h(const_128, denom_vec); + + src_tmp = src; + dst_tmp = dst; + + LD_SB3(src_tmp, src_stride, src0, src1, src2); + src_tmp += (3 * src_stride); + XORI_B3_128_SB(src0, src1, src2); + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + dsth0 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth1 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth2 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src_tmp, src_stride, src3, src4, src5, src6); + src_tmp += (4 * src_stride); + XORI_B4_128_SB(src3, src4, src5, src6); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + dsth3 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dsth4 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dsth5 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dsth6 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + MUL2(dst0_r, weight_vec, dst1_r, weight_vec, dst0_r, dst1_r); + MUL2(dst2_r, weight_vec, dst3_r, weight_vec, dst2_r, dst3_r); + MUL2(dst0_l, weight_vec, dst1_l, weight_vec, dst0_l, dst1_l); + MUL2(dst2_l, weight_vec, dst3_l, weight_vec, dst2_l, dst3_l); + SRAR_W4_SW(dst0_r, dst0_l, dst1_r, dst1_l, rnd_vec); + SRAR_W4_SW(dst2_r, dst2_l, dst3_r, dst3_l, rnd_vec); + PCKEV_H4_SH(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, tmp0, tmp1, tmp2, tmp3); + ADD2(tmp0, offset_vec, tmp1, offset_vec, tmp0, tmp1); + ADD2(tmp2, offset_vec, tmp3, offset_vec, tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST8x4_UB(out0, out1, dst_tmp, dst_stride); + dst_tmp += (4 * dst_stride); + + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dsth2 = dsth6; + } + + src += 8; + dst += 8; + + mask2 = LD_SB(ff_hevc_mask_arr + 16); + mask3 = mask2 + 2; + + LD_SB3(src, src_stride, src0, src1, src2); + src += (3 * src_stride); + XORI_B3_128_SB(src0, src1, src2); + VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); + VSHF_B2_SB(src1, src2, src1, src2, mask2, mask3, vec2, vec3); + dst10 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst21 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + ILVRL_H2_SH(dst21, dst10, dst10_r, dst21_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst21, 1); + + for (loop_cnt = 2; loop_cnt--;) { + LD_SB8(src, src_stride, src3, src4, src5, src6, src7, src8, src9, + src10); + src += (8 * src_stride); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); + VSHF_B2_SB(src3, src7, src3, src7, mask2, mask3, vec0, vec1); + VSHF_B2_SB(src4, src8, src4, src8, mask2, mask3, vec2, vec3); + VSHF_B2_SB(src5, src9, src5, src9, mask2, mask3, vec4, vec5); + VSHF_B2_SB(src6, src10, src6, src10, mask2, mask3, vec6, vec7); + dst73 = HEVC_FILT_4TAP_SH(vec0, vec1, filt0, filt1); + dst84 = HEVC_FILT_4TAP_SH(vec2, vec3, filt0, filt1); + dst95 = HEVC_FILT_4TAP_SH(vec4, vec5, filt0, filt1); + dst106 = HEVC_FILT_4TAP_SH(vec6, vec7, filt0, filt1); + dst32_r = __msa_ilvr_h(dst73, dst22); + ILVRL_H2_SH(dst84, dst73, dst43_r, dst87_r); + ILVRL_H2_SH(dst95, dst84, dst54_r, dst98_r); + ILVRL_H2_SH(dst106, dst95, dst65_r, dst109_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst73, 1); + dst76_r = __msa_ilvr_h(dst22, dst106); + dst0 = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4 = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5 = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6 = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7 = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + SRA_4V(dst0, dst1, dst2, dst3, 6); + SRA_4V(dst4, dst5, dst6, dst7, 6); + MUL2(dst0, weight_vec, dst1, weight_vec, dst0, dst1); + MUL2(dst2, weight_vec, dst3, weight_vec, dst2, dst3); + MUL2(dst4, weight_vec, dst5, weight_vec, dst4, dst5); + MUL2(dst6, weight_vec, dst7, weight_vec, dst6, dst7); + SRAR_W4_SW(dst0, dst1, dst2, dst3, rnd_vec); + SRAR_W4_SW(dst4, dst5, dst6, dst7, rnd_vec); + PCKEV_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, tmp0, tmp1, + tmp2, tmp3); + ADD2(tmp0, offset_vec, tmp1, offset_vec, tmp0, tmp1); + ADD2(tmp2, offset_vec, tmp3, offset_vec, tmp2, tmp3); + CLIP_SH4_0_255_MAX_SATU(tmp0, tmp1, tmp2, tmp3); + PCKEV_B2_UB(tmp1, tmp0, tmp3, tmp2, out0, out1); + ST4x8_UB(out0, out1, dst, dst_stride); + dst += (8 * dst_stride); + + dst10_r = dst98_r; + dst21_r = dst109_r; + dst22 = (v8i16) __msa_splati_d((v2i64) dst106, 1); + } } static void hevc_hv_uniwgt_4t_16w_msa(uint8_t *src, @@ -4870,9 +5194,15 @@ static void hevc_hv_uniwgt_4t_16w_msa(uint8_t *src, int32_t offset, int32_t rnd_val) { - hevc_hv_uniwgt_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, weight, - offset, rnd_val, 16); + if (4 == height) { + hevc_hv_uniwgt_4t_8multx4_msa(src, src_stride, dst, dst_stride, + filter_x, filter_y, 2, weight, offset, + rnd_val); + } else { + hevc_hv_uniwgt_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, + filter_x, filter_y, height, weight, + offset, rnd_val, 2); + } } static void hevc_hv_uniwgt_4t_24w_msa(uint8_t *src, @@ -4888,7 +5218,7 @@ static void hevc_hv_uniwgt_4t_24w_msa(uint8_t *src, { hevc_hv_uniwgt_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, filter_x, filter_y, height, weight, - offset, rnd_val, 24); + offset, rnd_val, 3); } static void hevc_hv_uniwgt_4t_32w_msa(uint8_t *src, @@ -4904,7 +5234,7 @@ static void hevc_hv_uniwgt_4t_32w_msa(uint8_t *src, { hevc_hv_uniwgt_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, filter_x, filter_y, height, weight, - offset, rnd_val, 32); + offset, rnd_val, 4); } #define UNIWGT_MC_COPY(WIDTH) \ @@ -4939,18 +5269,18 @@ UNIWGT_MC_COPY(64); #define UNI_W_MC(PEL, DIR, WIDTH, TAP, DIR1, FILT_DIR) \ void ff_hevc_put_hevc_uni_w_##PEL##_##DIR##WIDTH##_8_msa(uint8_t *dst, \ - ptrdiff_t \ - dst_stride, \ - uint8_t *src, \ - ptrdiff_t \ - src_stride, \ - int height, \ - int denom, \ - int weight, \ - int offset, \ - intptr_t mx, \ - intptr_t my, \ - int width) \ + ptrdiff_t \ + dst_stride, \ + uint8_t *src, \ + ptrdiff_t \ + src_stride, \ + int height, \ + int denom, \ + int weight, \ + int offset, \ + intptr_t mx, \ + intptr_t my, \ + int width) \ { \ const int8_t *filter = ff_hevc_##PEL##_filters[FILT_DIR - 1]; \ int shift = denom + 14 - 8; \ @@ -4996,46 +5326,43 @@ UNI_W_MC(epel, v, 32, 4, vt, my); #undef UNI_W_MC -#define UNI_W_MC_HV(PEL, DIR, WIDTH, TAP, DIR1) \ -void ff_hevc_put_hevc_uni_w_##PEL##_##DIR##WIDTH##_8_msa(uint8_t *dst, \ - ptrdiff_t \ - dst_stride, \ - uint8_t *src, \ - ptrdiff_t \ - src_stride, \ - int height, \ - int denom, \ - int weight, \ - int offset, \ - intptr_t mx, \ - intptr_t my, \ - int width) \ -{ \ - const int8_t *filter_x = ff_hevc_##PEL##_filters[mx - 1]; \ - const int8_t *filter_y = ff_hevc_##PEL##_filters[my - 1]; \ - int shift = denom + 14 - 8; \ - \ - hevc_##DIR1##_uniwgt_##TAP##t_##WIDTH##w_msa(src, src_stride, dst, \ - dst_stride, filter_x, \ - filter_y, height, weight, \ - offset, shift); \ +#define UNI_W_MC_HV(PEL, WIDTH, TAP) \ +void ff_hevc_put_hevc_uni_w_##PEL##_hv##WIDTH##_8_msa(uint8_t *dst, \ + ptrdiff_t dst_stride, \ + uint8_t *src, \ + ptrdiff_t src_stride, \ + int height, \ + int denom, \ + int weight, \ + int offset, \ + intptr_t mx, \ + intptr_t my, \ + int width) \ +{ \ + const int8_t *filter_x = ff_hevc_##PEL##_filters[mx - 1]; \ + const int8_t *filter_y = ff_hevc_##PEL##_filters[my - 1]; \ + int shift = denom + 14 - 8; \ + \ + hevc_hv_uniwgt_##TAP##t_##WIDTH##w_msa(src, src_stride, dst, dst_stride, \ + filter_x, filter_y, height, \ + weight, offset, shift); \ } -UNI_W_MC_HV(qpel, hv, 4, 8, hv); -UNI_W_MC_HV(qpel, hv, 8, 8, hv); -UNI_W_MC_HV(qpel, hv, 12, 8, hv); -UNI_W_MC_HV(qpel, hv, 16, 8, hv); -UNI_W_MC_HV(qpel, hv, 24, 8, hv); -UNI_W_MC_HV(qpel, hv, 32, 8, hv); -UNI_W_MC_HV(qpel, hv, 48, 8, hv); -UNI_W_MC_HV(qpel, hv, 64, 8, hv); - -UNI_W_MC_HV(epel, hv, 4, 4, hv); -UNI_W_MC_HV(epel, hv, 6, 4, hv); -UNI_W_MC_HV(epel, hv, 8, 4, hv); -UNI_W_MC_HV(epel, hv, 12, 4, hv); -UNI_W_MC_HV(epel, hv, 16, 4, hv); -UNI_W_MC_HV(epel, hv, 24, 4, hv); -UNI_W_MC_HV(epel, hv, 32, 4, hv); +UNI_W_MC_HV(qpel, 4, 8); +UNI_W_MC_HV(qpel, 8, 8); +UNI_W_MC_HV(qpel, 12, 8); +UNI_W_MC_HV(qpel, 16, 8); +UNI_W_MC_HV(qpel, 24, 8); +UNI_W_MC_HV(qpel, 32, 8); +UNI_W_MC_HV(qpel, 48, 8); +UNI_W_MC_HV(qpel, 64, 8); + +UNI_W_MC_HV(epel, 4, 4); +UNI_W_MC_HV(epel, 6, 4); +UNI_W_MC_HV(epel, 8, 4); +UNI_W_MC_HV(epel, 12, 4); +UNI_W_MC_HV(epel, 16, 4); +UNI_W_MC_HV(epel, 24, 4); +UNI_W_MC_HV(epel, 32, 4); #undef UNI_W_MC_HV diff --git a/libavcodec/mips/hevcdsp_msa.c b/libavcodec/mips/hevcdsp_msa.c index 73cc3ea21307c..81db62b876d9b 100644 --- a/libavcodec/mips/hevcdsp_msa.c +++ b/libavcodec/mips/hevcdsp_msa.c @@ -22,6 +22,13 @@ #include "libavcodec/mips/hevcdsp_mips.h" #include "libavcodec/mips/hevc_macros_msa.h" +static const uint8_t ff_hevc_mask_arr[16 * 2] __attribute__((aligned(0x40))) = { + /* 8 width cases */ + 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, + /* 4 width cases */ + 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 +}; + static void hevc_copy_4w_msa(uint8_t *src, int32_t src_stride, int16_t *dst, int32_t dst_stride, int32_t height) @@ -449,7 +456,7 @@ static void hevc_hz_8t_4w_msa(uint8_t *src, int32_t src_stride, v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); src -= 3; const_vec = __msa_ldi_h(128); @@ -504,7 +511,7 @@ static void hevc_hz_8t_8w_msa(uint8_t *src, int32_t src_stride, v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); src -= 3; const_vec = __msa_ldi_h(128); @@ -552,8 +559,75 @@ static void hevc_hz_8t_12w_msa(uint8_t *src, int32_t src_stride, int16_t *dst, int32_t dst_stride, const int8_t *filter, int32_t height) { - hevc_hz_8t_8w_msa(src, src_stride, dst, dst_stride, filter, height); - hevc_hz_8t_4w_msa(src + 8, src_stride, dst + 8, dst_stride, filter, height); + uint32_t loop_cnt; + int64_t res0, res1, res2, res3; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7; + v16i8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask7; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v8i16 filt0, filt1, filt2, filt3, dst0, dst1, dst2, dst3, dst4, dst5; + v8i16 filter_vec, const_vec; + + src -= 3; + const_vec = __msa_ldi_h(128); + const_vec <<= 6; + + filter_vec = LD_SH(filter); + SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + mask2 = mask0 + 4; + mask3 = mask0 + 6; + mask4 = LD_SB(ff_hevc_mask_arr + 16); + mask5 = mask4 + 2; + mask6 = mask4 + 4; + mask7 = mask4 + 6; + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src, src_stride, src0, src1, src2, src3); + LD_SB4(src + 8, src_stride, src4, src5, src6, src7); + src += (4 * src_stride); + XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); + + dst0 = const_vec; + dst1 = const_vec; + dst2 = const_vec; + dst3 = const_vec; + dst4 = const_vec; + dst5 = const_vec; + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + VSHF_B2_SB(src4, src5, src6, src7, mask4, mask4, vec4, vec5); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + DPADD_SB2_SH(vec4, vec5, filt0, filt0, dst4, dst5); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2, vec3); + VSHF_B2_SB(src4, src5, src6, src7, mask5, mask5, vec4, vec5); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + DPADD_SB2_SH(vec4, vec5, filt1, filt1, dst4, dst5); + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec2, vec3); + VSHF_B2_SB(src4, src5, src6, src7, mask6, mask6, vec4, vec5); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, dst0, + dst1, dst2, dst3); + DPADD_SB2_SH(vec4, vec5, filt2, filt2, dst4, dst5); + VSHF_B2_SB(src0, src0, src1, src1, mask3, mask3, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec2, vec3); + VSHF_B2_SB(src4, src5, src6, src7, mask7, mask7, vec4, vec5); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt3, filt3, filt3, filt3, dst0, + dst1, dst2, dst3); + DPADD_SB2_SH(vec4, vec5, filt3, filt3, dst4, dst5); + + res0 = __msa_copy_s_d((v2i64) dst4, 0); + res1 = __msa_copy_s_d((v2i64) dst4, 1); + res2 = __msa_copy_s_d((v2i64) dst5, 0); + res3 = __msa_copy_s_d((v2i64) dst5, 1); + ST_SH4(dst0, dst1, dst2, dst3, dst, dst_stride); + SD4(res0, res1, res2, res3, (dst + 8), dst_stride); + dst += (4 * dst_stride); + } } static void hevc_hz_8t_16w_msa(uint8_t *src, int32_t src_stride, @@ -561,13 +635,13 @@ static void hevc_hz_8t_16w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter, int32_t height) { uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7; + v16i8 src0, src1, src2, src3; v8i16 filt0, filt1, filt2, filt3; v16i8 mask1, mask2, mask3; v16i8 vec0, vec1, vec2, vec3; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 dst0, dst1, dst2, dst3; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); src -= 3; const_vec = __msa_ldi_h(128); @@ -580,56 +654,36 @@ static void hevc_hz_8t_16w_msa(uint8_t *src, int32_t src_stride, mask2 = mask0 + 4; mask3 = mask0 + 6; - for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB4(src, src_stride, src0, src2, src4, src6); - LD_SB4(src + 8, src_stride, src1, src3, src5, src7); - src += (4 * src_stride); - XORI_B8_128_SB(src0, src1, src2, src3, src4, src5, src6, src7); + for (loop_cnt = (height >> 1); loop_cnt--;) { + LD_SB2(src, src_stride, src0, src2); + LD_SB2(src + 8, src_stride, src1, src3); + src += (2 * src_stride); + XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); - VSHF_B4_SB(src4, src4, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); - dst4 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst4, dst4, dst4, dst4); - VSHF_B4_SB(src5, src5, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); - dst5 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst5, dst5, dst5, dst5); - VSHF_B4_SB(src6, src6, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); - dst6 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst6, dst6, dst6, dst6); - VSHF_B4_SB(src7, src7, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); - dst7 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst7, dst7, dst7, dst7); - - ST_SH4(dst0, dst2, dst4, dst6, dst, dst_stride); - ST_SH4(dst1, dst3, dst5, dst7, dst + 8, dst_stride); - dst += (4 * dst_stride); + VSHF_B2_SB(src0, src0, src1, src1, mask0, mask0, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask1, mask1, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask2, mask2, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src1, src1, mask3, mask3, vec0, vec1); + VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt3, filt3, filt3, filt3, dst0, + dst1, dst2, dst3); + + ST_SH2(dst0, dst2, dst, dst_stride); + ST_SH2(dst1, dst3, dst + 8, dst_stride); + dst += (2 * dst_stride); } } @@ -641,10 +695,10 @@ static void hevc_hz_8t_24w_msa(uint8_t *src, int32_t src_stride, v16i8 src0, src1, src2, src3; v8i16 filt0, filt1, filt2, filt3; v16i8 mask1, mask2, mask3, mask4, mask5, mask6, mask7; - v16i8 vec0, vec1, vec2, vec3; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); src -= 3; filter_vec = LD_SH(filter); @@ -668,36 +722,36 @@ static void hevc_hz_8t_24w_msa(uint8_t *src, int32_t src_stride, src += src_stride; XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, - vec0, vec1, vec2, vec3); dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); - VSHF_B4_SB(src2, src3, mask4, mask5, mask6, mask7, - vec0, vec1, vec2, vec3); dst4 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst4, dst4, dst4, dst4); - VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst5 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst5, dst5, dst5, dst5); + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask4, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask0, mask0, vec2, vec3); + VSHF_B2_SB(src2, src3, src3, src3, mask4, mask0, vec4, vec5); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + DPADD_SB2_SH(vec4, vec5, filt0, filt0, dst4, dst5); + VSHF_B2_SB(src0, src0, src0, src1, mask1, mask5, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask1, mask1, vec2, vec3); + VSHF_B2_SB(src2, src3, src3, src3, mask5, mask1, vec4, vec5); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + DPADD_SB2_SH(vec4, vec5, filt1, filt1, dst4, dst5); + VSHF_B2_SB(src0, src0, src0, src1, mask2, mask6, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask2, mask2, vec2, vec3); + VSHF_B2_SB(src2, src3, src3, src3, mask6, mask2, vec4, vec5); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, dst0, + dst1, dst2, dst3); + DPADD_SB2_SH(vec4, vec5, filt2, filt2, dst4, dst5); + VSHF_B2_SB(src0, src0, src0, src1, mask3, mask7, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask3, mask3, vec2, vec3); + VSHF_B2_SB(src2, src3, src3, src3, mask7, mask3, vec4, vec5); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt3, filt3, filt3, filt3, dst0, + dst1, dst2, dst3); + DPADD_SB2_SH(vec4, vec5, filt3, filt3, dst4, dst5); ST_SH2(dst0, dst1, dst, 8); ST_SH(dst2, dst + 16); @@ -719,7 +773,7 @@ static void hevc_hz_8t_32w_msa(uint8_t *src, int32_t src_stride, v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); src -= 3; filter_vec = LD_SH(filter); @@ -776,10 +830,10 @@ static void hevc_hz_8t_48w_msa(uint8_t *src, int32_t src_stride, v16i8 src0, src1, src2, src3; v8i16 filt0, filt1, filt2, filt3; v16i8 mask1, mask2, mask3, mask4, mask5, mask6, mask7; - v16i8 vec0, vec1, vec2, vec3; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5; v8i16 dst0, dst1, dst2, dst3, dst4, dst5; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); src -= 3; filter_vec = LD_SH(filter); @@ -802,38 +856,39 @@ static void hevc_hz_8t_48w_msa(uint8_t *src, int32_t src_stride, src += src_stride; XORI_B4_128_SB(src0, src1, src2, src3); - VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst0 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst0, dst0, dst0, dst0); - VSHF_B4_SB(src0, src1, mask4, mask5, mask6, mask7, - vec0, vec1, vec2, vec3); dst1 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst1, dst1, dst1, dst1); - VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst2 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst2, dst2, dst2, dst2); - VSHF_B4_SB(src1, src2, mask4, mask5, mask6, mask7, - vec0, vec1, vec2, vec3); dst3 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst3, dst3, dst3, dst3); - VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst4 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst4, dst4, dst4, dst4); - VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); dst5 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst5, dst5, dst5, dst5); + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask4, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src2, mask0, mask4, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask1, mask5, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src2, mask1, mask5, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask2, mask6, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src2, mask2, mask6, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt2, filt2, filt2, filt2, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask3, mask7, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src2, mask3, mask7, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt3, filt3, filt3, filt3, dst0, + dst1, dst2, dst3); + ST_SH4(dst0, dst1, dst2, dst3, dst, 8); - ST_SH6(dst0, dst1, dst2, dst3, dst4, dst5, dst, 8); + VSHF_B2_SB(src2, src2, src3, src3, mask0, mask0, vec4, vec5); + DPADD_SB2_SH(vec4, vec5, filt0, filt0, dst4, dst5); + VSHF_B2_SB(src2, src2, src3, src3, mask1, mask1, vec4, vec5); + DPADD_SB2_SH(vec4, vec5, filt1, filt1, dst4, dst5); + VSHF_B2_SB(src2, src2, src3, src3, mask2, mask2, vec4, vec5); + DPADD_SB2_SH(vec4, vec5, filt2, filt2, dst4, dst5); + VSHF_B2_SB(src2, src2, src3, src3, mask3, mask3, vec4, vec5); + DPADD_SB2_SH(vec4, vec5, filt3, filt3, dst4, dst5); + ST_SH2(dst4, dst5, (dst + 32), 8); dst += dst_stride; } } @@ -849,7 +904,7 @@ static void hevc_hz_8t_64w_msa(uint8_t *src, int32_t src_stride, v16i8 vec0, vec1, vec2, vec3; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); src -= 3; @@ -1308,31 +1363,28 @@ static void hevc_hv_8t_4w_msa(uint8_t *src, int32_t src_stride, int32_t height) { uint32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + int32_t dst_stride_in_bytes = 2 * dst_stride; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v8i16 filt0, filt1, filt2, filt3; - v4i32 filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 filt_h0, filt_h1, filt_h2, filt_h3; v16i8 mask1, mask2, mask3; v8i16 filter_vec, const_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; - v8i16 dst30, dst41, dst52, dst63, dst66, dst87; - v4i32 dst0_r, dst1_r; - v8i16 dst10_r, dst32_r, dst54_r, dst76_r; - v8i16 dst21_r, dst43_r, dst65_r, dst87_r; - v16i8 mask0 = { - 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 - }; - v8u16 mask4 = { 0, 4, 1, 5, 2, 6, 3, 7 }; + v8i16 dst30, dst41, dst52, dst63, dst66, dst97, dst108; + v4i32 dst0_r, dst1_r, dst2_r, dst3_r; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r, dst98_r; + v8i16 dst21_r, dst43_r, dst65_r, dst87_r, dst109_r; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); src -= ((3 * src_stride) + 3); filter_vec = LD_SH(filter_x); SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W4_SW(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); mask1 = mask0 + 2; mask2 = mask0 + 4; @@ -1364,47 +1416,56 @@ static void hevc_hv_8t_4w_msa(uint8_t *src, int32_t src_stride, DPADD_SB4_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, filt3, dst63, dst63, dst63, dst63); - ILVR_H3_SH(dst41, dst30, dst52, dst41, dst63, dst52, - dst10_r, dst21_r, dst32_r); - dst43_r = __msa_ilvl_h(dst41, dst30); - dst54_r = __msa_ilvl_h(dst52, dst41); - dst65_r = __msa_ilvl_h(dst63, dst52); + ILVRL_H2_SH(dst41, dst30, dst10_r, dst43_r); + ILVRL_H2_SH(dst52, dst41, dst21_r, dst54_r); + ILVRL_H2_SH(dst63, dst52, dst32_r, dst65_r); dst66 = (v8i16) __msa_splati_d((v2i64) dst63, 1); - for (loop_cnt = height >> 1; loop_cnt--;) { - LD_SB2(src, src_stride, src7, src8); - src += (2 * src_stride); - XORI_B2_128_SB(src7, src8); + for (loop_cnt = height >> 2; loop_cnt--;) { + LD_SB4(src, src_stride, src7, src8, src9, src10); + src += (4 * src_stride); + XORI_B4_128_SB(src7, src8, src9, src10); - VSHF_B4_SB(src7, src8, mask0, mask1, mask2, mask3, + VSHF_B4_SB(src7, src9, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); - dst87 = const_vec; + VSHF_B4_SB(src8, src10, mask0, mask1, mask2, mask3, + vec4, vec5, vec6, vec7); + dst97 = const_vec; + dst108 = const_vec; DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst87, dst87, dst87, dst87); - dst76_r = __msa_ilvr_h(dst87, dst66); + dst97, dst97, dst97, dst97); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, + dst108, dst108, dst108, dst108); + + dst76_r = __msa_ilvr_h(dst97, dst66); + ILVRL_H2_SH(dst108, dst97, dst87_r, dst109_r); + dst66 = (v8i16) __msa_splati_d((v2i64) dst97, 1); + dst98_r = __msa_ilvr_h(dst66, dst108); + dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, filt_h0, filt_h1, filt_h2, filt_h3); - dst87_r = __msa_vshf_h((v8i16) mask4, dst87, dst87); dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, filt_h0, filt_h1, filt_h2, filt_h3); - dst0_r >>= 6; - dst1_r >>= 6; - - dst0_r = (v4i32) __msa_pckev_h((v8i16) dst1_r, (v8i16) dst0_r); - ST8x2_UB(dst0_r, dst, (2 * dst_stride)); - dst += (2 * dst_stride); + dst2_r = HEVC_FILT_8TAP(dst32_r, dst54_r, dst76_r, dst98_r, + filt_h0, filt_h1, filt_h2, filt_h3); + dst3_r = HEVC_FILT_8TAP(dst43_r, dst65_r, dst87_r, dst109_r, + filt_h0, filt_h1, filt_h2, filt_h3); + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + PCKEV_H2_SW(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst2_r); + ST8x4_UB(dst0_r, dst2_r, dst, dst_stride_in_bytes); + dst += (4 * dst_stride); - dst10_r = dst32_r; - dst32_r = dst54_r; - dst54_r = dst76_r; - dst21_r = dst43_r; - dst43_r = dst65_r; - dst65_r = dst87_r; - dst66 = (v8i16) __msa_splati_d((v2i64) dst87, 1); + dst10_r = dst54_r; + dst32_r = dst76_r; + dst54_r = dst98_r; + dst21_r = dst65_r; + dst43_r = dst87_r; + dst65_r = dst109_r; + dst66 = (v8i16) __msa_splati_d((v2i64) dst108, 1); } } -static void hevc_hv_8t_8multx2mult_msa(uint8_t *src, +static void hevc_hv_8t_8multx1mult_msa(uint8_t *src, int32_t src_stride, int16_t *dst, int32_t dst_stride, @@ -1415,19 +1476,17 @@ static void hevc_hv_8t_8multx2mult_msa(uint8_t *src, uint32_t loop_cnt, cnt; uint8_t *src_tmp; int16_t *dst_tmp; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7; v8i16 filt0, filt1, filt2, filt3; - v4i32 filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 filt_h0, filt_h1, filt_h2, filt_h3; v16i8 mask1, mask2, mask3; v8i16 filter_vec, const_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; v4i32 dst0_r, dst0_l; v8i16 dst10_r, dst32_r, dst54_r, dst76_r; v8i16 dst10_l, dst32_l, dst54_l, dst76_l; - v8i16 dst21_r, dst43_r, dst65_r, dst87_r; - v8i16 dst21_l, dst43_l, dst65_l, dst87_l; v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; src -= ((3 * src_stride) + 3); @@ -1435,10 +1494,9 @@ static void hevc_hv_8t_8multx2mult_msa(uint8_t *src, SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W4_SW(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); mask1 = mask0 + 2; mask2 = mask0 + 4; @@ -1494,17 +1552,10 @@ static void hevc_hv_8t_8multx2mult_msa(uint8_t *src, DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, dst6, dst6, dst6, dst6); - ILVR_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, - dst10_r, dst32_r, dst54_r, dst21_r); - ILVR_H2_SH(dst4, dst3, dst6, dst5, dst43_r, dst65_r); - ILVL_H4_SH(dst1, dst0, dst3, dst2, dst5, dst4, dst2, dst1, - dst10_l, dst32_l, dst54_l, dst21_l); - ILVL_H2_SH(dst4, dst3, dst6, dst5, dst43_l, dst65_l); - - for (loop_cnt = height >> 1; loop_cnt--;) { - LD_SB2(src_tmp, src_stride, src7, src8); - XORI_B2_128_SB(src7, src8); - src_tmp += 2 * src_stride; + for (loop_cnt = height; loop_cnt--;) { + src7 = LD_SB(src_tmp); + src7 = (v16i8) __msa_xori_b((v16u8) src7, 128); + src_tmp += src_stride; VSHF_B4_SB(src7, src7, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); @@ -1512,6 +1563,9 @@ static void hevc_hv_8t_8multx2mult_msa(uint8_t *src, DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, dst7, dst7, dst7, dst7); + ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); + ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, filt_h0, filt_h1, filt_h2, filt_h3); @@ -1524,37 +1578,13 @@ static void hevc_hv_8t_8multx2mult_msa(uint8_t *src, ST_SW(dst0_r, dst_tmp); dst_tmp += dst_stride; - VSHF_B4_SB(src8, src8, mask0, mask1, mask2, mask3, - vec0, vec1, vec2, vec3); - dst8 = const_vec; - DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, - dst8, dst8, dst8, dst8); - - ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); - dst6 = dst8; - dst0_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, - filt_h0, filt_h1, filt_h2, filt_h3); - dst0_l = HEVC_FILT_8TAP(dst21_l, dst43_l, dst65_l, dst87_l, - filt_h0, filt_h1, filt_h2, filt_h3); - dst0_r >>= 6; - dst0_l >>= 6; - - dst0_r = (v4i32) __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); - ST_SW(dst0_r, dst_tmp); - dst_tmp += dst_stride; - - dst10_r = dst32_r; - dst32_r = dst54_r; - dst54_r = dst76_r; - dst10_l = dst32_l; - dst32_l = dst54_l; - dst54_l = dst76_l; - dst21_r = dst43_r; - dst43_r = dst65_r; - dst65_r = dst87_r; - dst21_l = dst43_l; - dst43_l = dst65_l; - dst65_l = dst87_l; + dst0 = dst1; + dst1 = dst2; + dst2 = dst3; + dst3 = dst4; + dst4 = dst5; + dst5 = dst6; + dst6 = dst7; } src += 8; @@ -1567,7 +1597,7 @@ static void hevc_hv_8t_8w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter_x, const int8_t *filter_y, int32_t height) { - hevc_hv_8t_8multx2mult_msa(src, src_stride, dst, dst_stride, + hevc_hv_8t_8multx1mult_msa(src, src_stride, dst, dst_stride, filter_x, filter_y, height, 8); } @@ -1576,11 +1606,195 @@ static void hevc_hv_8t_12w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter_x, const int8_t *filter_y, int32_t height) { - hevc_hv_8t_8multx2mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 8); + uint32_t loop_cnt; + int32_t dst_stride_in_bytes = 2 * dst_stride; + uint8_t *src_tmp; + int16_t *dst_tmp; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 mask0, mask1, mask2, mask3, mask4, mask5, mask6, mask7; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 vec8, vec9, vec10, vec11, vec12, vec13, vec14, vec15; + v8i16 filt0, filt1, filt2, filt3, filt_h0, filt_h1, filt_h2, filt_h3; + v8i16 filter_vec, const_vec; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; + v8i16 dst30, dst41, dst52, dst63, dst66, dst97, dst108; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r, dst98_r, dst21_r, dst43_r; + v8i16 dst65_r, dst87_r, dst109_r, dst10_l, dst32_l, dst54_l, dst76_l; + v4i32 dst0_r, dst0_l, dst1_r, dst2_r, dst3_r; + + src -= ((3 * src_stride) + 3); + filter_vec = LD_SH(filter_x); + SPLATI_H4_SH(filter_vec, 0, 1, 2, 3, filt0, filt1, filt2, filt3); - hevc_hv_8t_4w_msa(src + 8, src_stride, dst + 8, dst_stride, - filter_x, filter_y, height); + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W4_SH(filter_vec, filt_h0, filt_h1, filt_h2, filt_h3); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + mask2 = mask0 + 4; + mask3 = mask0 + 6; + + const_vec = __msa_ldi_h(128); + const_vec <<= 6; + + src_tmp = src; + dst_tmp = dst; + + LD_SB7(src_tmp, src_stride, src0, src1, src2, src3, src4, src5, src6); + src_tmp += (7 * src_stride); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + /* row 0 row 1 row 2 row 3 */ + VSHF_B4_SB(src0, src0, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src1, src1, mask0, mask1, mask2, mask3, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src2, src2, mask0, mask1, mask2, mask3, vec8, vec9, vec10, + vec11); + VSHF_B4_SB(src3, src3, mask0, mask1, mask2, mask3, vec12, vec13, vec14, + vec15); + dst0 = const_vec; + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, dst0, dst0, + dst0, dst0); + dst1 = const_vec; + DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, dst1, dst1, + dst1, dst1); + dst2 = const_vec; + DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, dst2, + dst2, dst2, dst2); + dst3 = const_vec; + DPADD_SB4_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, filt3, dst3, + dst3, dst3, dst3); + + /* row 4 row 5 row 6 */ + VSHF_B4_SB(src4, src4, mask0, mask1, mask2, mask3, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src5, src5, mask0, mask1, mask2, mask3, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src6, src6, mask0, mask1, mask2, mask3, vec8, vec9, vec10, + vec11); + dst4 = const_vec; + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, dst4, dst4, + dst4, dst4); + dst5 = const_vec; + DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, dst5, dst5, + dst5, dst5); + dst6 = const_vec; + DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, dst6, + dst6, dst6, dst6); + + for (loop_cnt = height; loop_cnt--;) { + src7 = LD_SB(src_tmp); + src7 = (v16i8) __msa_xori_b((v16u8) src7, 128); + src_tmp += src_stride; + + VSHF_B4_SB(src7, src7, mask0, mask1, mask2, mask3, vec0, vec1, vec2, + vec3); + dst7 = const_vec; + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, dst7, + dst7, dst7, dst7); + + ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); + ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); + dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst0_l = HEVC_FILT_8TAP(dst10_l, dst32_l, dst54_l, dst76_l, filt_h0, + filt_h1, filt_h2, filt_h3); + dst0_r >>= 6; + dst0_l >>= 6; + + dst0_r = (v4i32) __msa_pckev_h((v8i16) dst0_l, (v8i16) dst0_r); + ST_SW(dst0_r, dst_tmp); + dst_tmp += dst_stride; + + dst0 = dst1; + dst1 = dst2; + dst2 = dst3; + dst3 = dst4; + dst4 = dst5; + dst5 = dst6; + dst6 = dst7; + } + + src += 8; + dst += 8; + + mask4 = LD_SB(ff_hevc_mask_arr + 16); + mask5 = mask4 + 2; + mask6 = mask4 + 4; + mask7 = mask4 + 6; + + LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); + src += (7 * src_stride); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + VSHF_B4_SB(src0, src3, mask4, mask5, mask6, mask7, vec0, vec1, vec2, vec3); + VSHF_B4_SB(src1, src4, mask4, mask5, mask6, mask7, vec4, vec5, vec6, vec7); + VSHF_B4_SB(src2, src5, mask4, mask5, mask6, mask7, vec8, vec9, vec10, + vec11); + VSHF_B4_SB(src3, src6, mask4, mask5, mask6, mask7, vec12, vec13, vec14, + vec15); + dst30 = const_vec; + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, dst30, + dst30, dst30, dst30); + dst41 = const_vec; + DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, dst41, + dst41, dst41, dst41); + dst52 = const_vec; + DPADD_SB4_SH(vec8, vec9, vec10, vec11, filt0, filt1, filt2, filt3, dst52, + dst52, dst52, dst52); + dst63 = const_vec; + DPADD_SB4_SH(vec12, vec13, vec14, vec15, filt0, filt1, filt2, filt3, dst63, + dst63, dst63, dst63); + + ILVRL_H2_SH(dst41, dst30, dst10_r, dst43_r); + ILVRL_H2_SH(dst52, dst41, dst21_r, dst54_r); + ILVRL_H2_SH(dst63, dst52, dst32_r, dst65_r); + + dst66 = (v8i16) __msa_splati_d((v2i64) dst63, 1); + + for (loop_cnt = height >> 2; loop_cnt--;) { + LD_SB4(src, src_stride, src7, src8, src9, src10); + src += (4 * src_stride); + XORI_B4_128_SB(src7, src8, src9, src10); + + VSHF_B4_SB(src7, src9, mask4, mask5, mask6, mask7, vec0, vec1, vec2, + vec3); + VSHF_B4_SB(src8, src10, mask4, mask5, mask6, mask7, vec4, vec5, vec6, + vec7); + dst97 = const_vec; + dst108 = const_vec; + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt1, filt2, filt3, dst97, + dst97, dst97, dst97); + DPADD_SB4_SH(vec4, vec5, vec6, vec7, filt0, filt1, filt2, filt3, dst108, + dst108, dst108, dst108); + + dst76_r = __msa_ilvr_h(dst97, dst66); + ILVRL_H2_SH(dst108, dst97, dst87_r, dst109_r); + dst66 = (v8i16) __msa_splati_d((v2i64) dst97, 1); + dst98_r = __msa_ilvr_h(dst66, dst108); + + dst0_r = HEVC_FILT_8TAP(dst10_r, dst32_r, dst54_r, dst76_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst1_r = HEVC_FILT_8TAP(dst21_r, dst43_r, dst65_r, dst87_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst2_r = HEVC_FILT_8TAP(dst32_r, dst54_r, dst76_r, dst98_r, filt_h0, + filt_h1, filt_h2, filt_h3); + dst3_r = HEVC_FILT_8TAP(dst43_r, dst65_r, dst87_r, dst109_r, filt_h0, + filt_h1, filt_h2, filt_h3); + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + PCKEV_H2_SW(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst2_r); + ST8x4_UB(dst0_r, dst2_r, dst, dst_stride_in_bytes); + dst += (4 * dst_stride); + + dst10_r = dst54_r; + dst32_r = dst76_r; + dst54_r = dst98_r; + dst21_r = dst65_r; + dst43_r = dst87_r; + dst65_r = dst109_r; + dst66 = (v8i16) __msa_splati_d((v2i64) dst108, 1); + } } static void hevc_hv_8t_16w_msa(uint8_t *src, int32_t src_stride, @@ -1588,7 +1802,7 @@ static void hevc_hv_8t_16w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter_x, const int8_t *filter_y, int32_t height) { - hevc_hv_8t_8multx2mult_msa(src, src_stride, dst, dst_stride, + hevc_hv_8t_8multx1mult_msa(src, src_stride, dst, dst_stride, filter_x, filter_y, height, 16); } @@ -1597,7 +1811,7 @@ static void hevc_hv_8t_24w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter_x, const int8_t *filter_y, int32_t height) { - hevc_hv_8t_8multx2mult_msa(src, src_stride, dst, dst_stride, + hevc_hv_8t_8multx1mult_msa(src, src_stride, dst, dst_stride, filter_x, filter_y, height, 24); } @@ -1606,7 +1820,7 @@ static void hevc_hv_8t_32w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter_x, const int8_t *filter_y, int32_t height) { - hevc_hv_8t_8multx2mult_msa(src, src_stride, dst, dst_stride, + hevc_hv_8t_8multx1mult_msa(src, src_stride, dst, dst_stride, filter_x, filter_y, height, 32); } @@ -1615,7 +1829,7 @@ static void hevc_hv_8t_48w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter_x, const int8_t *filter_y, int32_t height) { - hevc_hv_8t_8multx2mult_msa(src, src_stride, dst, dst_stride, + hevc_hv_8t_8multx1mult_msa(src, src_stride, dst, dst_stride, filter_x, filter_y, height, 48); } @@ -1624,7 +1838,7 @@ static void hevc_hv_8t_64w_msa(uint8_t *src, int32_t src_stride, const int8_t *filter_x, const int8_t *filter_y, int32_t height) { - hevc_hv_8t_8multx2mult_msa(src, src_stride, dst, dst_stride, + hevc_hv_8t_8multx1mult_msa(src, src_stride, dst, dst_stride, filter_x, filter_y, height, 64); } @@ -1639,7 +1853,7 @@ static void hevc_hz_4t_4x2_msa(uint8_t *src, v16i8 mask1, vec0, vec1; v8i16 dst0; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); src -= 1; @@ -1672,7 +1886,7 @@ static void hevc_hz_4t_4x4_msa(uint8_t *src, v16i8 mask1, vec0, vec1; v8i16 dst0, dst1; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); src -= 1; @@ -1711,7 +1925,7 @@ static void hevc_hz_4t_4x8multiple_msa(uint8_t *src, v16i8 mask1, vec0, vec1; v8i16 dst0, dst1, dst2, dst3; v8i16 filter_vec, const_vec; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 16, 17, 17, 18, 18, 19, 19, 20 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); src -= 1; @@ -1776,7 +1990,7 @@ static void hevc_hz_4t_6w_msa(uint8_t *src, uint32_t dst_val_int0, dst_val_int1, dst_val_int2, dst_val_int3; v8i16 filt0, filt1, dst0, dst1, dst2, dst3; v16i8 src0, src1, src2, src3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v16i8 vec0, vec1; v8i16 filter_vec, const_vec; @@ -1791,7 +2005,7 @@ static void hevc_hz_4t_6w_msa(uint8_t *src, const_vec = __msa_ldi_h(128); const_vec <<= 6; - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = 2; loop_cnt--;) { LD_SB4(src, src_stride, src0, src1, src2, src3); src += (4 * src_stride); @@ -1845,7 +2059,7 @@ static void hevc_hz_4t_8x2multiple_msa(uint8_t *src, uint32_t loop_cnt; v8i16 filt0, filt1, dst0, dst1; v16i8 src0, src1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v16i8 vec0, vec1; v8i16 filter_vec, const_vec; @@ -1889,7 +2103,7 @@ static void hevc_hz_4t_8x4multiple_msa(uint8_t *src, uint32_t loop_cnt; v8i16 filt0, filt1; v16i8 src0, src1, src2, src3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v16i8 vec0, vec1; v8i16 dst0, dst1, dst2, dst3; @@ -1963,7 +2177,7 @@ static void hevc_hz_4t_12w_msa(uint8_t *src, v8i16 dst0, dst1, dst2, dst3, dst4, dst5; v8i16 filter_vec, const_vec; v16i8 mask3; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask2 = { 8, 9, 9, 10, 10, 11, 11, 12, 24, 25, 25, 26, 26, 27, 27, 28 }; @@ -2020,7 +2234,7 @@ static void hevc_hz_4t_16w_msa(uint8_t *src, v16i8 src0, src1, src2, src3; v16i8 src4, src5, src6, src7; v8i16 filt0, filt1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; v16i8 vec0, vec1; @@ -2092,7 +2306,7 @@ static void hevc_hz_4t_24w_msa(uint8_t *src, int16_t *dst_tmp = dst + 16; v16i8 src0, src1, src2, src3, src4, src5, src6, src7; v8i16 filt0, filt1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1, mask00, mask11; v16i8 vec0, vec1; v8i16 dst0, dst1, dst2, dst3; @@ -2192,10 +2406,10 @@ static void hevc_hz_4t_32w_msa(uint8_t *src, uint32_t loop_cnt; v16i8 src0, src1, src2; v8i16 filt0, filt1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1, mask2, mask3; v8i16 dst0, dst1, dst2, dst3; - v16i8 vec0, vec1; + v16i8 vec0, vec1, vec2, vec3; v8i16 filter_vec, const_vec; src -= 1; @@ -2210,54 +2424,25 @@ static void hevc_hz_4t_32w_msa(uint8_t *src, mask2 = mask0 + 8; mask3 = mask0 + 10; - for (loop_cnt = (height >> 1); loop_cnt--;) { - LD_SB2(src, 16, src0, src1); - src2 = LD_SB(src + 24); - src += src_stride; - - XORI_B3_128_SB(src0, src1, src2); - - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - - VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); - dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - ST_SH4(dst0, dst1, dst2, dst3, dst, 8); - dst += dst_stride; - + for (loop_cnt = height; loop_cnt--;) { LD_SB2(src, 16, src0, src1); src2 = LD_SB(src + 24); src += src_stride; XORI_B3_128_SB(src0, src1, src2); - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - - VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); dst1 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst1, dst1); - - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec0, vec1); dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec0, vec1); dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - + VSHF_B2_SB(src0, src0, src0, src1, mask0, mask2, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask0, mask0, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt0, filt0, filt0, filt0, dst0, + dst1, dst2, dst3); + VSHF_B2_SB(src0, src0, src0, src1, mask1, mask3, vec0, vec1); + VSHF_B2_SB(src1, src1, src2, src2, mask1, mask1, vec2, vec3); + DPADD_SB4_SH(vec0, vec1, vec2, vec3, filt1, filt1, filt1, filt1, dst0, + dst1, dst2, dst3); ST_SH4(dst0, dst1, dst2, dst3, dst, 8); dst += dst_stride; } @@ -2333,18 +2518,17 @@ static void hevc_vt_4t_4x4_msa(uint8_t *src, ST8x4_UB(dst10, dst32, dst, 2 * dst_stride); } -static void hevc_vt_4t_4x8multiple_msa(uint8_t *src, - int32_t src_stride, - int16_t *dst, - int32_t dst_stride, - const int8_t *filter, - int32_t height) +static void hevc_vt_4t_4x8_msa(uint8_t *src, + int32_t src_stride, + int16_t *dst, + int32_t dst_stride, + const int8_t *filter, + int32_t height) { - int32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v16i8 src10_r, src32_r, src54_r, src76_r, src98_r; v16i8 src21_r, src43_r, src65_r, src87_r, src109_r; - v16i8 src2110, src4332, src6554, src8776; + v16i8 src2110, src4332, src6554, src8776, src10998; v8i16 dst10, dst32, dst54, dst76; v8i16 filt0, filt1; v8i16 filter_vec, const_vec; @@ -2363,35 +2547,96 @@ static void hevc_vt_4t_4x8multiple_msa(uint8_t *src, src2110 = (v16i8) __msa_ilvr_d((v2i64) src21_r, (v2i64) src10_r); src2110 = (v16i8) __msa_xori_b((v16u8) src2110, 128); - for (loop_cnt = (height >> 3); loop_cnt--;) { - LD_SB6(src, src_stride, src3, src4, src5, src6, src7, src8); - src += (6 * src_stride); + LD_SB8(src, src_stride, src3, src4, src5, src6, src7, src8, src9, src10); + src += (8 * src_stride); + ILVR_B4_SB(src3, src2, src4, src3, src5, src4, src6, src5, + src32_r, src43_r, src54_r, src65_r); + ILVR_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, + src76_r, src87_r, src98_r, src109_r); + ILVR_D4_SB(src43_r, src32_r, src65_r, src54_r, src87_r, src76_r, src109_r, + src98_r, src4332, src6554, src8776, src10998); + XORI_B4_128_SB(src4332, src6554, src8776, src10998); + dst10 = const_vec; + dst32 = const_vec; + dst54 = const_vec; + dst76 = const_vec; + DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst10, dst10); + DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst32, dst32); + DPADD_SB2_SH(src6554, src8776, filt0, filt1, dst54, dst54); + DPADD_SB2_SH(src8776, src10998, filt0, filt1, dst76, dst76); + ST8x8_UB(dst10, dst32, dst54, dst76, dst, 2 * dst_stride); + dst += (8 * dst_stride); +} - ILVR_B4_SB(src3, src2, src4, src3, src5, src4, src6, src5, - src32_r, src43_r, src54_r, src65_r); - ILVR_B2_SB(src7, src6, src8, src7, src76_r, src87_r); - ILVR_D3_SB(src43_r, src32_r, src65_r, src54_r, src87_r, src76_r, - src4332, src6554, src8776); - XORI_B3_128_SB(src4332, src6554, src8776); +static void hevc_vt_4t_4x16_msa(uint8_t *src, int32_t src_stride, + int16_t *dst, int32_t dst_stride, + const int8_t *filter, int32_t height) +{ + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 src10_r, src32_r, src54_r, src76_r, src98_r, src21_r, src43_r; + v16i8 src65_r, src87_r, src109_r, src2110, src4332, src6554, src8776; + v16i8 src10998; + v8i16 dst10, dst32, dst54, dst76, filt0, filt1, filter_vec, const_vec; - dst10 = const_vec; - DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst10, dst10); - dst32 = const_vec; - DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst32, dst32); - dst54 = const_vec; - DPADD_SB2_SH(src6554, src8776, filt0, filt1, dst54, dst54); + src -= src_stride; + const_vec = __msa_ldi_h(128); + const_vec <<= 6; - LD_SB2(src, src_stride, src9, src2); - src += (2 * src_stride); - ILVR_B2_SB(src9, src8, src2, src9, src98_r, src109_r); - src2110 = (v16i8) __msa_ilvr_d((v2i64) src109_r, (v2i64) src98_r); - src2110 = (v16i8) __msa_xori_b((v16u8) src2110, 128); - dst76 = const_vec; - DPADD_SB2_SH(src8776, src2110, filt0, filt1, dst76, dst76); + filter_vec = LD_SH(filter); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); - ST8x8_UB(dst10, dst32, dst54, dst76, dst, 2 * dst_stride); - dst += (8 * dst_stride); - } + LD_SB3(src, src_stride, src0, src1, src2); + src += (3 * src_stride); + + ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); + src2110 = (v16i8) __msa_ilvr_d((v2i64) src21_r, (v2i64) src10_r); + src2110 = (v16i8) __msa_xori_b((v16u8) src2110, 128); + + LD_SB8(src, src_stride, src3, src4, src5, src6, src7, src8, src9, src10); + src += (8 * src_stride); + ILVR_B4_SB(src3, src2, src4, src3, src5, src4, src6, src5, src32_r, src43_r, + src54_r, src65_r); + ILVR_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, src76_r, + src87_r, src98_r, src109_r); + ILVR_D4_SB(src43_r, src32_r, src65_r, src54_r, src87_r, src76_r, src109_r, + src98_r, src4332, src6554, src8776, src10998); + XORI_B4_128_SB(src4332, src6554, src8776, src10998); + + dst10 = const_vec; + dst32 = const_vec; + dst54 = const_vec; + dst76 = const_vec; + DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst10, dst10); + DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst32, dst32); + DPADD_SB2_SH(src6554, src8776, filt0, filt1, dst54, dst54); + DPADD_SB2_SH(src8776, src10998, filt0, filt1, dst76, dst76); + ST8x8_UB(dst10, dst32, dst54, dst76, dst, 2 * dst_stride); + dst += (8 * dst_stride); + + src2 = src10; + src2110 = src10998; + + LD_SB8(src, src_stride, src3, src4, src5, src6, src7, src8, src9, src10); + src += (8 * src_stride); + + ILVR_B4_SB(src3, src2, src4, src3, src5, src4, src6, src5, src32_r, src43_r, + src54_r, src65_r); + ILVR_B4_SB(src7, src6, src8, src7, src9, src8, src10, src9, src76_r, + src87_r, src98_r, src109_r); + ILVR_D4_SB(src43_r, src32_r, src65_r, src54_r, src87_r, src76_r, src109_r, + src98_r, src4332, src6554, src8776, src10998); + XORI_B4_128_SB(src4332, src6554, src8776, src10998); + + dst10 = const_vec; + dst32 = const_vec; + dst54 = const_vec; + dst76 = const_vec; + DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst10, dst10); + DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst32, dst32); + DPADD_SB2_SH(src6554, src8776, filt0, filt1, dst54, dst54); + DPADD_SB2_SH(src8776, src10998, filt0, filt1, dst76, dst76); + ST8x8_UB(dst10, dst32, dst54, dst76, dst, 2 * dst_stride); + dst += (8 * dst_stride); } static void hevc_vt_4t_4w_msa(uint8_t *src, @@ -2405,9 +2650,10 @@ static void hevc_vt_4t_4w_msa(uint8_t *src, hevc_vt_4t_4x2_msa(src, src_stride, dst, dst_stride, filter); } else if (4 == height) { hevc_vt_4t_4x4_msa(src, src_stride, dst, dst_stride, filter, height); - } else if (0 == (height % 8)) { - hevc_vt_4t_4x8multiple_msa(src, src_stride, dst, dst_stride, - filter, height); + } else if (8 == height) { + hevc_vt_4t_4x8_msa(src, src_stride, dst, dst_stride, filter, height); + } else if (16 == height) { + hevc_vt_4t_4x16_msa(src, src_stride, dst, dst_stride, filter, height); } } @@ -2590,9 +2836,9 @@ static void hevc_vt_4t_8x4multiple_msa(uint8_t *src, int32_t height) { int32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5; - v16i8 src10_r, src32_r, src21_r, src43_r; - v8i16 dst0_r, dst1_r; + v16i8 src0, src1, src2, src3, src4, src5, src6; + v16i8 src10_r, src32_r, src21_r, src43_r, src54_r, src65_r; + v8i16 dst0_r, dst1_r, dst2_r, dst3_r; v8i16 filt0, filt1; v8i16 filter_vec, const_vec; @@ -2609,29 +2855,25 @@ static void hevc_vt_4t_8x4multiple_msa(uint8_t *src, ILVR_B2_SB(src1, src0, src2, src1, src10_r, src21_r); for (loop_cnt = (height >> 2); loop_cnt--;) { - LD_SB2(src, src_stride, src3, src4); - src += (2 * src_stride); - XORI_B2_128_SB(src3, src4); + LD_SB4(src, src_stride, src3, src4, src5, src6); + src += (4 * src_stride); + XORI_B4_128_SB(src3, src4, src5, src6); ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); + ILVR_B2_SB(src5, src4, src6, src5, src54_r, src65_r); dst0_r = const_vec; - DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, dst0_r, dst0_r); dst1_r = const_vec; + dst2_r = const_vec; + dst3_r = const_vec; + DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, dst0_r, dst0_r); DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, dst1_r, dst1_r); + DPADD_SB2_SH(src32_r, src54_r, filt0, filt1, dst2_r, dst2_r); + DPADD_SB2_SH(src43_r, src65_r, filt0, filt1, dst3_r, dst3_r); + ST_SH4(dst0_r, dst1_r, dst2_r, dst3_r, dst, dst_stride); + dst += (4 * dst_stride); - ST_SH2(dst0_r, dst1_r, dst, dst_stride); - dst += (2 * dst_stride); - - LD_SB2(src, src_stride, src5, src2); - src += (2 * src_stride); - XORI_B2_128_SB(src5, src2); - ILVR_B2_SB(src5, src4, src2, src5, src10_r, src21_r); - dst0_r = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, dst0_r, dst0_r); - dst1_r = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, dst1_r, dst1_r); - - ST_SH2(dst0_r, dst1_r, dst, dst_stride); - dst += (2 * dst_stride); + src2 = src6; + src10_r = src54_r; + src21_r = src65_r; } } @@ -2660,11 +2902,12 @@ static void hevc_vt_4t_12w_msa(uint8_t *src, int32_t height) { int32_t loop_cnt; - v16i8 src0, src1, src2, src3, src4, src5; + v16i8 src0, src1, src2, src3, src4, src5, src6; v16i8 src10_r, src32_r, src21_r, src43_r; v8i16 dst0_r, dst1_r, dst2_r, dst3_r; v16i8 src10_l, src32_l, src54_l, src21_l, src43_l, src65_l; v16i8 src2110, src4332; + v16i8 src54_r, src65_r, src6554; v8i16 dst0_l, dst1_l; v8i16 filt0, filt1; v8i16 filter_vec, const_vec; @@ -2683,36 +2926,42 @@ static void hevc_vt_4t_12w_msa(uint8_t *src, ILVL_B2_SB(src1, src0, src2, src1, src10_l, src21_l); src2110 = (v16i8) __msa_ilvr_d((v2i64) src21_l, (v2i64) src10_l); - for (loop_cnt = (height >> 2); loop_cnt--;) { + for (loop_cnt = 4; loop_cnt--;) { LD_SB2(src, src_stride, src3, src4); src += (2 * src_stride); + LD_SB2(src, src_stride, src5, src6); + src += (2 * src_stride); XORI_B2_128_SB(src3, src4); + XORI_B2_128_SB(src5, src6); + ILVR_B2_SB(src3, src2, src4, src3, src32_r, src43_r); ILVL_B2_SB(src3, src2, src4, src3, src32_l, src43_l); src4332 = (v16i8) __msa_ilvr_d((v2i64) src43_l, (v2i64) src32_l); + ILVR_B2_SB(src5, src4, src6, src5, src54_r, src65_r); + ILVL_B2_SB(src5, src4, src6, src5, src54_l, src65_l); + src6554 = (v16i8) __msa_ilvr_d((v2i64) src65_l, (v2i64) src54_l); + dst0_r = const_vec; DPADD_SB2_SH(src10_r, src32_r, filt0, filt1, dst0_r, dst0_r); dst1_r = const_vec; DPADD_SB2_SH(src21_r, src43_r, filt0, filt1, dst1_r, dst1_r); - dst0_l = const_vec; - DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst0_l, dst0_l); - - LD_SB2(src, src_stride, src5, src2); - src += (2 * src_stride); - XORI_B2_128_SB(src5, src2); - ILVR_B2_SB(src5, src4, src2, src5, src10_r, src21_r); - ILVL_B2_SB(src5, src4, src2, src5, src54_l, src65_l); - src2110 = (v16i8) __msa_ilvr_d((v2i64) src65_l, (v2i64) src54_l); dst2_r = const_vec; - DPADD_SB2_SH(src32_r, src10_r, filt0, filt1, dst2_r, dst2_r); + DPADD_SB2_SH(src32_r, src54_r, filt0, filt1, dst2_r, dst2_r); dst3_r = const_vec; - DPADD_SB2_SH(src43_r, src21_r, filt0, filt1, dst3_r, dst3_r); + DPADD_SB2_SH(src43_r, src65_r, filt0, filt1, dst3_r, dst3_r); + dst0_l = const_vec; + DPADD_SB2_SH(src2110, src4332, filt0, filt1, dst0_l, dst0_l); dst1_l = const_vec; - DPADD_SB2_SH(src4332, src2110, filt0, filt1, dst1_l, dst1_l); + DPADD_SB2_SH(src4332, src6554, filt0, filt1, dst1_l, dst1_l); ST_SH4(dst0_r, dst1_r, dst2_r, dst3_r, dst, dst_stride); ST8x4_UB(dst0_l, dst1_l, dst + 8, (2 * dst_stride)); dst += (4 * dst_stride); + + src2 = src6; + src10_r = src54_r; + src21_r = src65_r; + src2110 = src6554; } } @@ -2994,69 +3243,52 @@ static void hevc_hv_4t_4x2_msa(uint8_t *src, const int8_t *filter_x, const int8_t *filter_y) { + int32_t dst_stride_in_bytes = 2 * dst_stride; v16i8 src0, src1, src2, src3, src4; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; v8i16 filter_vec, const_vec; v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4; - v4i32 dst0_r, dst1_r; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; + v8i16 dst20, dst31, dst42, dst10, dst32, dst21, dst43; + v4i32 dst0, dst1; src -= (src_stride + 1); filter_vec = LD_SH(filter_x); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; const_vec = __msa_ldi_h(128); const_vec <<= 6; - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); - - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); - - LD_SB2(src, src_stride, src3, src4); - XORI_B2_128_SB(src3, src4); - - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - - dst0_r = (v4i32) __msa_pckev_h((v8i16) dst1_r, (v8i16) dst0_r); - ST8x2_UB(dst0_r, dst, 2 * dst_stride); + LD_SB5(src, src_stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + VSHF_B2_SB(src0, src2, src0, src2, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src3, src1, src3, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src4, src2, src4, mask0, mask1, vec4, vec5); + + dst20 = const_vec; + dst31 = const_vec; + dst42 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst20, dst20); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst31, dst31); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst42, dst42); + ILVRL_H2_SH(dst31, dst20, dst10, dst32); + ILVRL_H2_SH(dst42, dst31, dst21, dst43); + + dst0 = HEVC_FILT_4TAP(dst10, dst32, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21, dst43, filt_h0, filt_h1); + dst0 >>= 6; + dst1 >>= 6; + dst0 = (v4i32) __msa_pckev_h((v8i16) dst1, (v8i16) dst0); + ST8x2_UB(dst0, dst, dst_stride_in_bytes); } static void hevc_hv_4t_4x4_msa(uint8_t *src, @@ -3066,16 +3298,16 @@ static void hevc_hv_4t_4x4_msa(uint8_t *src, const int8_t *filter_x, const int8_t *filter_y) { + int32_t dst_stride_in_bytes = 2 * dst_stride; v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; + v8i16 dst30, dst41, dst52, dst63, dst10, dst32, dst54, dst21, dst43, dst65; + v4i32 dst0, dst1, dst2, dst3; src -= (src_stride + 1); @@ -3083,71 +3315,43 @@ static void hevc_hv_4t_4x4_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; const_vec = __msa_ldi_h(128); const_vec <<= 6; - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); - - XORI_B3_128_SB(src0, src1, src2); - - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); - - LD_SB4(src, src_stride, src3, src4, src5, src6); - XORI_B4_128_SB(src3, src4, src5, src6); - - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - dst10_r = __msa_ilvr_h(dst5, dst4); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_r >>= 6; - - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); - dst21_r = __msa_ilvr_h(dst2, dst5); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_r >>= 6; + VSHF_B2_SB(src0, src3, src0, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src4, src1, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src5, src2, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src6, src3, src6, mask0, mask1, vec6, vec7); - PCKEV_H2_SW(dst1_r, dst0_r, dst3_r, dst2_r, dst0_r, dst1_r); - ST8x4_UB(dst0_r, dst1_r, dst, 2 * dst_stride); + dst30 = const_vec; + dst41 = const_vec; + dst52 = const_vec; + dst63 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst30, dst30); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst41, dst41); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst52, dst52); + DPADD_SB2_SH(vec6, vec7, filt0, filt1, dst63, dst63); + + ILVRL_H2_SH(dst41, dst30, dst10, dst43); + ILVRL_H2_SH(dst52, dst41, dst21, dst54); + ILVRL_H2_SH(dst63, dst52, dst32, dst65); + + dst0 = HEVC_FILT_4TAP(dst10, dst32, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21, dst43, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32, dst54, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43, dst65, filt_h0, filt_h1); + SRA_4V(dst0, dst1, dst2, dst3, 6); + PCKEV_H2_SW(dst1, dst0, dst3, dst2, dst0, dst2); + ST8x4_UB(dst0, dst2, dst, dst_stride_in_bytes); } @@ -3163,25 +3367,24 @@ static void hevc_hv_4t_4multx8mult_msa(uint8_t *src, v16i8 src0, src1, src2, src3, src4, src5, src6; v16i8 src7, src8, src9, src10; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr + 16); v16i8 mask1; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8, dst9; - v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r, dst6_r, dst7_r; - v8i16 dst10_r, dst32_r, dst54_r, dst76_r; - v8i16 dst21_r, dst43_r, dst65_r, dst87_r; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dst10, dst21, dst22, dst73, dst84, dst95, dst106; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r, dst98_r; + v8i16 dst21_r, dst43_r, dst65_r, dst87_r, dst109_r; + v4i32 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7; src -= (src_stride + 1); filter_vec = LD_SH(filter_x); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -3191,19 +3394,14 @@ static void hevc_hv_4t_4multx8mult_msa(uint8_t *src, LD_SB3(src, src_stride, src0, src1, src2); src += (3 * src_stride); XORI_B3_128_SB(src0, src1, src2); - - VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); - VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); - VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - - ILVR_H2_SH(dst1, dst0, dst2, dst1, dst10_r, dst21_r); + VSHF_B2_SB(src0, src1, src0, src1, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src2, src1, src2, mask0, mask1, vec2, vec3); + dst10 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst10, dst10); + dst21 = const_vec; + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst21, dst21); + ILVRL_H2_SH(dst21, dst10, dst10_r, dst21_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst21, 1); for (loop_cnt = height >> 3; loop_cnt--;) { LD_SB8(src, src_stride, @@ -3211,77 +3409,47 @@ static void hevc_hv_4t_4multx8mult_msa(uint8_t *src, src += (8 * src_stride); XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - dst32_r = __msa_ilvr_h(dst3, dst2); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_r >>= 6; - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); + VSHF_B2_SB(src3, src7, src3, src7, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src8, src4, src8, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src9, src5, src9, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src10, src6, src10, mask0, mask1, vec6, vec7); + + dst73 = const_vec; + dst84 = const_vec; + dst95 = const_vec; + dst106 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst73, dst73); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst84, dst84); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst95, dst95); + DPADD_SB2_SH(vec6, vec7, filt0, filt1, dst106, dst106); + + dst32_r = __msa_ilvr_h(dst73, dst22); + ILVRL_H2_SH(dst84, dst73, dst43_r, dst87_r); + ILVRL_H2_SH(dst95, dst84, dst54_r, dst98_r); + ILVRL_H2_SH(dst106, dst95, dst65_r, dst109_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst73, 1); + dst76_r = __msa_ilvr_h(dst22, dst106); + + dst0 = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1 = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2 = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3 = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4 = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5 = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6 = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7 = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + SRA_4V(dst0, dst1, dst2, dst3, 6); + SRA_4V(dst4, dst5, dst6, dst7, 6); + PCKEV_H4_SW(dst1, dst0, dst3, dst2, dst5, dst4, dst7, dst6, + dst0, dst1, dst2, dst3); + ST8x8_UB(dst0, dst1, dst2, dst3, dst, 2 * dst_stride); + dst += (8 * dst_stride); - dst43_r = __msa_ilvr_h(dst4, dst3); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_r >>= 6; - - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - dst54_r = __msa_ilvr_h(dst5, dst4); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); - dst2_r >>= 6; - - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - - dst65_r = __msa_ilvr_h(dst6, dst5); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); - dst3_r >>= 6; - - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); - - dst76_r = __msa_ilvr_h(dst7, dst6); - dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); - dst4_r >>= 6; - - VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec0, vec1); - dst8 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst8, dst8); - - dst87_r = __msa_ilvr_h(dst8, dst7); - dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); - dst5_r >>= 6; - - VSHF_B2_SB(src9, src9, src9, src9, mask0, mask1, vec0, vec1); - dst9 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst9, dst9); - - dst10_r = __msa_ilvr_h(dst9, dst8); - dst6_r = HEVC_FILT_4TAP(dst76_r, dst10_r, filt_h0, filt_h1); - dst6_r >>= 6; - - VSHF_B2_SB(src10, src10, src10, src10, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); - - dst21_r = __msa_ilvr_h(dst2, dst9); - dst7_r = HEVC_FILT_4TAP(dst87_r, dst21_r, filt_h0, filt_h1); - dst7_r >>= 6; - - PCKEV_H4_SW(dst1_r, dst0_r, dst3_r, dst2_r, - dst5_r, dst4_r, dst7_r, dst6_r, - dst0_r, dst1_r, dst2_r, dst3_r); - ST8x8_UB(dst0_r, dst1_r, dst2_r, dst3_r, dst, 2 * dst_stride); - dst += (8 * dst_stride); - } -} + dst10_r = dst98_r; + dst21_r = dst109_r; + dst22 = (v8i16) __msa_splati_d((v2i64) dst106, 1); + } +} static void hevc_hv_4t_4w_msa(uint8_t *src, int32_t src_stride, @@ -3311,30 +3479,31 @@ static void hevc_hv_4t_6w_msa(uint8_t *src, const int8_t *filter_y, int32_t height) { - uint32_t loop_cnt; - uint64_t dst_val0, dst_val1, dst_val2, dst_val3; - uint32_t dst_val_int0, dst_val_int1, dst_val_int2, dst_val_int3; - v16i8 src0, src1, src2, src3, src4, src5, src6; + int32_t dst_stride_in_bytes = 2 * dst_stride; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; - v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; - v8i16 dst10_l, dst32_l, dst21_l, dst43_l; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dsth0, dsth1, dsth2, dsth3, dsth4, dsth5, dsth6, dsth7, dsth8, dsth9; + v8i16 dsth10, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; + v8i16 dst10_r, dst32_r, dst54_r, dst76_r, dst98_r, dst21_r, dst43_r; + v8i16 dst65_r, dst87_r, dst109_r, dst10_l, dst32_l, dst54_l, dst76_l; + v8i16 dst98_l, dst21_l, dst43_l, dst65_l, dst87_l, dst109_l; + v8i16 dst1021_l, dst3243_l, dst5465_l, dst7687_l, dst98109_l; + v4i32 dst0_r, dst1_r, dst2_r, dst3_r, dst4_r, dst5_r, dst6_r, dst7_r; + v4i32 dst0_l, dst1_l, dst2_l, dst3_l; src -= (src_stride + 1); filter_vec = LD_SH(filter_x); SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; @@ -3349,89 +3518,83 @@ static void hevc_hv_4t_6w_msa(uint8_t *src, VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - dst0 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); - dst1 = const_vec; - DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); - dst2 = const_vec; - DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); - - ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); - ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - - for (loop_cnt = height >> 2; loop_cnt--;) { - LD_SB4(src, src_stride, src3, src4, src5, src6); - src += (4 * src_stride); - XORI_B4_128_SB(src3, src4, src5, src6); - - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); - dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); - dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); - dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - ILVRL_H2_SH(dst5, dst4, dst10_r, dst10_l); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_l = HEVC_FILT_4TAP(dst32_l, dst10_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; + dsth0 = const_vec; + dsth1 = const_vec; + dsth2 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dsth0, dsth0); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dsth1, dsth1); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dsth2, dsth2); - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + ILVRL_H2_SH(dsth1, dsth0, dst10_r, dst10_l); + ILVRL_H2_SH(dsth2, dsth1, dst21_r, dst21_l); - ILVRL_H2_SH(dst2, dst5, dst21_r, dst21_l); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_l = HEVC_FILT_4TAP(dst43_l, dst21_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; + LD_SB8(src, src_stride, src3, src4, src5, src6, src7, src8, src9, src10); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); - PCKEV_H4_SW(dst0_l, dst0_r, dst1_l, dst1_r, - dst2_l, dst2_r, dst3_l, dst3_r, - dst0_r, dst1_r, dst2_r, dst3_r); - - dst_val0 = __msa_copy_u_d((v2i64) dst0_r, 0); - dst_val1 = __msa_copy_u_d((v2i64) dst1_r, 0); - dst_val2 = __msa_copy_u_d((v2i64) dst2_r, 0); - dst_val3 = __msa_copy_u_d((v2i64) dst3_r, 0); - - dst_val_int0 = __msa_copy_u_w((v4i32) dst0_r, 2); - dst_val_int1 = __msa_copy_u_w((v4i32) dst1_r, 2); - dst_val_int2 = __msa_copy_u_w((v4i32) dst2_r, 2); - dst_val_int3 = __msa_copy_u_w((v4i32) dst3_r, 2); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + + dsth3 = const_vec; + dsth4 = const_vec; + dsth5 = const_vec; + dsth6 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dsth3, dsth3); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dsth4, dsth4); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dsth5, dsth5); + DPADD_SB2_SH(vec6, vec7, filt0, filt1, dsth6, dsth6); - SD(dst_val0, dst); - SW(dst_val_int0, dst + 4); - dst += dst_stride; - SD(dst_val1, dst); - SW(dst_val_int1, dst + 4); - dst += dst_stride; - SD(dst_val2, dst); - SW(dst_val_int2, dst + 4); - dst += dst_stride; - SD(dst_val3, dst); - SW(dst_val_int3, dst + 4); - dst += dst_stride; + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src9, src9, src9, src9, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src10, src10, src10, src10, mask0, mask1, vec6, vec7); + + dsth7 = const_vec; + dsth8 = const_vec; + dsth9 = const_vec; + dsth10 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dsth7, dsth7); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dsth8, dsth8); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dsth9, dsth9); + DPADD_SB2_SH(vec6, vec7, filt0, filt1, dsth10, dsth10); + + ILVRL_H2_SH(dsth3, dsth2, dst32_r, dst32_l); + ILVRL_H2_SH(dsth4, dsth3, dst43_r, dst43_l); + ILVRL_H2_SH(dsth5, dsth4, dst54_r, dst54_l); + ILVRL_H2_SH(dsth6, dsth5, dst65_r, dst65_l); + ILVRL_H2_SH(dsth7, dsth6, dst76_r, dst76_l); + ILVRL_H2_SH(dsth8, dsth7, dst87_r, dst87_l); + ILVRL_H2_SH(dsth9, dsth8, dst98_r, dst98_l); + ILVRL_H2_SH(dsth10, dsth9, dst109_r, dst109_l); + + PCKEV_D2_SH(dst21_l, dst10_l, dst43_l, dst32_l, dst1021_l, dst3243_l); + PCKEV_D2_SH(dst65_l, dst54_l, dst87_l, dst76_l, dst5465_l, dst7687_l); + dst98109_l = (v8i16) __msa_pckev_d((v2i64) dst109_l, (v2i64) dst98_l); - } + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + dst6_r = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + dst7_r = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst1021_l, dst3243_l, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst3243_l, dst5465_l, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst5465_l, dst7687_l, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst7687_l, dst98109_l, filt_h0, filt_h1); + SRA_4V(dst0_r, dst1_r, dst2_r, dst3_r, 6); + SRA_4V(dst4_r, dst5_r, dst6_r, dst7_r, 6); + SRA_4V(dst0_l, dst1_l, dst2_l, dst3_l, 6); + PCKEV_H2_SH(dst1_r, dst0_r, dst3_r, dst2_r, tmp0, tmp1); + PCKEV_H2_SH(dst5_r, dst4_r, dst7_r, dst6_r, tmp2, tmp3); + PCKEV_H2_SH(dst1_l, dst0_l, dst3_l, dst2_l, tmp4, tmp5); + ST8x4_UB(tmp0, tmp1, dst, dst_stride_in_bytes); + ST4x4_UB(tmp4, tmp4, 0, 1, 2, 3, dst + 4, dst_stride_in_bytes); + dst += 4 * dst_stride; + ST8x4_UB(tmp2, tmp3, dst, dst_stride_in_bytes); + ST4x4_UB(tmp5, tmp5, 0, 1, 2, 3, dst + 4, dst_stride_in_bytes); } static void hevc_hv_4t_8x2_msa(uint8_t *src, @@ -3439,16 +3602,15 @@ static void hevc_hv_4t_8x2_msa(uint8_t *src, int16_t *dst, int32_t dst_stride, const int8_t *filter_x, - const int8_t *filter_y, - int32_t height) + const int8_t *filter_y) { v16i8 src0, src1, src2, src3, src4; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; v8i16 dst0, dst1, dst2, dst3, dst4; v4i32 dst0_r, dst0_l, dst1_r, dst1_l; v8i16 dst10_r, dst32_r, dst21_r, dst43_r; @@ -3460,23 +3622,23 @@ static void hevc_hv_4t_8x2_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; const_vec = __msa_ldi_h(128); const_vec <<= 6; - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); - XORI_B3_128_SB(src0, src1, src2); + LD_SB5(src, src_stride, src0, src1, src2, src3, src4); + XORI_B5_128_SB(src0, src1, src2, src3, src4); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec8, vec9); dst0 = const_vec; DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); @@ -3484,53 +3646,123 @@ static void hevc_hv_4t_8x2_msa(uint8_t *src, DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); dst2 = const_vec; DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + dst3 = const_vec; + DPADD_SB2_SH(vec6, vec7, filt0, filt1, dst3, dst3); + dst4 = const_vec; + DPADD_SB2_SH(vec8, vec9, filt0, filt1, dst4, dst4); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - - LD_SB2(src, src_stride, src3, src4); - src += (2 * src_stride); - XORI_B2_128_SB(src3, src4); - - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - dst0_r >>= 6; - dst0_l >>= 6; - - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); PCKEV_H2_SW(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r, dst1_r); ST_SW2(dst0_r, dst1_r, dst, dst_stride); } +static void hevc_hv_4t_8multx4_msa(uint8_t *src, int32_t src_stride, + int16_t *dst, int32_t dst_stride, + const int8_t *filter_x, + const int8_t *filter_y, int32_t width8mult) +{ + int32_t cnt; + v16i8 src0, src1, src2, src3, src4, src5, src6, mask0, mask1; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 filt0, filt1, filt_h0, filt_h1, filter_vec, const_vec; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; + v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + + src -= (src_stride + 1); + + filter_vec = LD_SH(filter_x); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + + const_vec = __msa_ldi_h(128); + const_vec <<= 6; + + for (cnt = width8mult; cnt--;) { + LD_SB7(src, src_stride, src0, src1, src2, src3, src4, src5, src6); + src += 8; + XORI_B7_128_SB(src0, src1, src2, src3, src4, src5, src6); + + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + + dst0 = const_vec; + dst1 = const_vec; + dst2 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + + ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); + ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); + + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + dst3 = const_vec; + dst4 = const_vec; + dst5 = const_vec; + dst6 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst4, dst4); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst5, dst5); + DPADD_SB2_SH(vec6, vec7, filt0, filt1, dst6, dst6); + ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); + + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + PCKEV_H2_SW(dst0_l, dst0_r, dst1_l, dst1_r, dst0_r, dst1_r); + PCKEV_H2_SW(dst2_l, dst2_r, dst3_l, dst3_r, dst2_r, dst3_r); + + ST_SW4(dst0_r, dst1_r, dst2_r, dst3_r, dst, dst_stride); + dst += 8; + } +} + static void hevc_hv_4t_8x6_msa(uint8_t *src, int32_t src_stride, int16_t *dst, int32_t dst_stride, const int8_t *filter_x, - const int8_t *filter_y, - int32_t height) + const int8_t *filter_y) { v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7, vec8, vec9; + v16i8 vec10, vec11, vec12, vec13, vec14, vec15, vec16, vec17; v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst7, dst8; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; v4i32 dst4_r, dst4_l, dst5_r, dst5_l; @@ -3545,24 +3777,31 @@ static void hevc_hv_4t_8x6_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; const_vec = __msa_ldi_h(128); const_vec <<= 6; - LD_SB3(src, src_stride, src0, src1, src2); - src += (3 * src_stride); + LD_SB5(src, src_stride, src0, src1, src2, src3, src4); + src += (5 * src_stride); + LD_SB4(src, src_stride, src5, src6, src7, src8); - XORI_B3_128_SB(src0, src1, src2); + XORI_B5_128_SB(src0, src1, src2, src3, src4); + XORI_B4_128_SB(src5, src6, src7, src8); VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec6, vec7); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec8, vec9); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec10, vec11); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec12, vec13); + VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec14, vec15); + VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec16, vec17); dst0 = const_vec; DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); @@ -3570,91 +3809,44 @@ static void hevc_hv_4t_8x6_msa(uint8_t *src, DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); dst2 = const_vec; DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + dst3 = const_vec; + DPADD_SB2_SH(vec6, vec7, filt0, filt1, dst3, dst3); + dst4 = const_vec; + DPADD_SB2_SH(vec8, vec9, filt0, filt1, dst4, dst4); + dst5 = const_vec; + DPADD_SB2_SH(vec10, vec11, filt0, filt1, dst5, dst5); + dst6 = const_vec; + DPADD_SB2_SH(vec12, vec13, filt0, filt1, dst6, dst6); + dst7 = const_vec; + DPADD_SB2_SH(vec14, vec15, filt0, filt1, dst7, dst7); + dst8 = const_vec; + DPADD_SB2_SH(vec16, vec17, filt0, filt1, dst8, dst8); ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); - - LD_SB2(src, src_stride, src3, src4); - src += (2 * src_stride); - - XORI_B2_128_SB(src3, src4); - - /* row 3 */ - VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); - dst3 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); - ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); - dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); + ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - - dst0_r >>= 6; - dst0_l >>= 6; - - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - - LD_SB2(src, src_stride, src5, src6); - src += (2 * src_stride); - - XORI_B2_128_SB(src5, src6); - - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); - dst2_r >>= 6; - dst2_l >>= 6; - - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst6 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst6, dst6); - - ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); - dst3_r >>= 6; - dst3_l >>= 6; - - LD_SB2(src, src_stride, src7, src8); - - XORI_B2_128_SB(src7, src8); - - /* row 7 */ - VSHF_B2_SB(src7, src7, src7, src7, mask0, mask1, vec0, vec1); - dst7 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst7, dst7); - - ILVRL_H2_SH(dst7, dst6, dst76_r, dst76_l); dst4_r = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); dst4_l = HEVC_FILT_4TAP(dst54_l, dst76_l, filt_h0, filt_h1); - dst4_r >>= 6; - dst4_l >>= 6; - - /* row 8 */ - VSHF_B2_SB(src8, src8, src8, src8, mask0, mask1, vec0, vec1); - dst8 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst8, dst8); - - ILVRL_H2_SH(dst8, dst7, dst87_r, dst87_l); dst5_r = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); dst5_l = HEVC_FILT_4TAP(dst65_l, dst87_l, filt_h0, filt_h1); - dst5_r >>= 6; - dst5_l >>= 6; + + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + SRA_4V(dst4_r, dst4_l, dst5_r, dst5_l, 6); PCKEV_H4_SW(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r, dst2_r, dst3_r); @@ -3674,22 +3866,22 @@ static void hevc_hv_4t_8multx4mult_msa(uint8_t *src, const int8_t *filter_x, const int8_t *filter_y, int32_t height, - int32_t width) + int32_t width8mult) { uint32_t loop_cnt, cnt; uint8_t *src_tmp; int16_t *dst_tmp; v16i8 src0, src1, src2, src3, src4, src5, src6; v8i16 filt0, filt1; - v4i32 filt_h0, filt_h1; - v16i8 mask0 = { 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8 }; + v8i16 filt_h0, filt_h1; + v16i8 mask0 = LD_SB(ff_hevc_mask_arr); v16i8 mask1; v8i16 filter_vec, const_vec; - v16i8 vec0, vec1, vec2, vec3, vec4, vec5; - v8i16 dst0, dst1, dst2, dst3, dst4, dst5; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6; v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; - v8i16 dst10_r, dst32_r, dst21_r, dst43_r; - v8i16 dst10_l, dst32_l, dst21_l, dst43_l; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; src -= (src_stride + 1); @@ -3697,17 +3889,16 @@ static void hevc_hv_4t_8multx4mult_msa(uint8_t *src, SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); filter_vec = LD_SH(filter_y); - vec0 = __msa_clti_s_b((v16i8) filter_vec, 0); - filter_vec = (v8i16) __msa_ilvr_b(vec0, (v16i8) filter_vec); + UNPCK_R_SB_SH(filter_vec, filter_vec); - SPLATI_W2_SW(filter_vec, 0, filt_h0, filt_h1); + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); mask1 = mask0 + 2; const_vec = __msa_ldi_h(128); const_vec <<= 6; - for (cnt = width >> 3; cnt--;) { + for (cnt = width8mult; cnt--;) { src_tmp = src; dst_tmp = dst; @@ -3736,59 +3927,48 @@ static void hevc_hv_4t_8multx4mult_msa(uint8_t *src, XORI_B4_128_SB(src3, src4, src5, src6); VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + dst3 = const_vec; + dst4 = const_vec; + dst5 = const_vec; + dst6 = const_vec; DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst4, dst4); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst5, dst5); + DPADD_SB2_SH(vec6, vec7, filt0, filt1, dst6, dst6); ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); - - dst0_r >>= 6; - dst0_l >>= 6; - - /* row 4 */ - VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec0, vec1); - dst4 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst4, dst4); - - ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); - dst1_r >>= 6; - dst1_l >>= 6; - - /* row 5 */ - VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec0, vec1); - dst5 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst5, dst5); - - ILVRL_H2_SH(dst5, dst4, dst10_r, dst10_l); - dst2_r = HEVC_FILT_4TAP(dst32_r, dst10_r, filt_h0, filt_h1); - dst2_l = HEVC_FILT_4TAP(dst32_l, dst10_l, filt_h0, filt_h1); - - dst2_r >>= 6; - dst2_l >>= 6; - - /* row 6 */ - VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec0, vec1); - dst2 = const_vec; - DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst2, dst2); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); - ILVRL_H2_SH(dst2, dst5, dst21_r, dst21_l); - dst3_r = HEVC_FILT_4TAP(dst43_r, dst21_r, filt_h0, filt_h1); - dst3_l = HEVC_FILT_4TAP(dst43_l, dst21_l, filt_h0, filt_h1); - - dst3_r >>= 6; - dst3_l >>= 6; + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); PCKEV_H4_SW(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, dst3_r, dst0_r, dst1_r, dst2_r, dst3_r); - ST_SW2(dst0_r, dst1_r, dst_tmp, dst_stride); - dst_tmp += (2 * dst_stride); - ST_SW2(dst2_r, dst3_r, dst_tmp, dst_stride); - dst_tmp += (2 * dst_stride); + ST_SW4(dst0_r, dst1_r, dst2_r, dst3_r, dst_tmp, dst_stride); + dst_tmp += (4 * dst_stride); + + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dst2 = dst6; } src += 8; @@ -3807,13 +3987,16 @@ static void hevc_hv_4t_8w_msa(uint8_t *src, if (2 == height) { hevc_hv_4t_8x2_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height); + filter_x, filter_y); + } else if (4 == height) { + hevc_hv_4t_8multx4_msa(src, src_stride, dst, dst_stride, + filter_x, filter_y, 1); } else if (6 == height) { hevc_hv_4t_8x6_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height); + filter_x, filter_y); } else if (0 == (height % 4)) { hevc_hv_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 8); + filter_x, filter_y, height, 1); } } @@ -3825,12 +4008,169 @@ static void hevc_hv_4t_12w_msa(uint8_t *src, const int8_t *filter_y, int32_t height) { - hevc_hv_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 8); + uint32_t loop_cnt; + uint8_t *src_tmp; + int16_t *dst_tmp; + v16i8 src0, src1, src2, src3, src4, src5, src6, src7, src8, src9, src10; + v16i8 vec0, vec1, vec2, vec3, vec4, vec5, vec6, vec7; + v16i8 mask0, mask1, mask2, mask3; + v8i16 filt0, filt1, filt_h0, filt_h1, filter_vec, const_vec; + v8i16 dst0, dst1, dst2, dst3, dst4, dst5, dst6, dst10, dst21, dst22, dst73; + v8i16 dst84, dst95, dst106, dst76_r, dst98_r, dst87_r, dst109_r; + v8i16 dst10_r, dst32_r, dst54_r, dst21_r, dst43_r, dst65_r; + v8i16 dst10_l, dst32_l, dst54_l, dst21_l, dst43_l, dst65_l; + v4i32 dst0_r, dst0_l, dst1_r, dst1_l, dst2_r, dst2_l, dst3_r, dst3_l; + v4i32 tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + + src -= (src_stride + 1); + + filter_vec = LD_SH(filter_x); + SPLATI_H2_SH(filter_vec, 0, 1, filt0, filt1); + + filter_vec = LD_SH(filter_y); + UNPCK_R_SB_SH(filter_vec, filter_vec); + + SPLATI_W2_SH(filter_vec, 0, filt_h0, filt_h1); + + mask0 = LD_SB(ff_hevc_mask_arr); + mask1 = mask0 + 2; + + const_vec = __msa_ldi_h(128); + const_vec <<= 6; + + src_tmp = src; + dst_tmp = dst; + + LD_SB3(src_tmp, src_stride, src0, src1, src2); + src_tmp += (3 * src_stride); + + XORI_B3_128_SB(src0, src1, src2); + + VSHF_B2_SB(src0, src0, src0, src0, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src1, src1, src1, src1, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src2, src2, src2, src2, mask0, mask1, vec4, vec5); - hevc_hv_4t_4w_msa(src + 8, src_stride, dst + 8, dst_stride, - filter_x, filter_y, height); + dst0 = const_vec; + dst1 = const_vec; + dst2 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst0, dst0); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst1, dst1); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst2, dst2); + + ILVRL_H2_SH(dst1, dst0, dst10_r, dst10_l); + ILVRL_H2_SH(dst2, dst1, dst21_r, dst21_l); + + for (loop_cnt = 4; loop_cnt--;) { + LD_SB4(src_tmp, src_stride, src3, src4, src5, src6); + src_tmp += (4 * src_stride); + XORI_B4_128_SB(src3, src4, src5, src6); + VSHF_B2_SB(src3, src3, src3, src3, mask0, mask1, vec0, vec1); + VSHF_B2_SB(src4, src4, src4, src4, mask0, mask1, vec2, vec3); + VSHF_B2_SB(src5, src5, src5, src5, mask0, mask1, vec4, vec5); + VSHF_B2_SB(src6, src6, src6, src6, mask0, mask1, vec6, vec7); + + dst3 = const_vec; + dst4 = const_vec; + dst5 = const_vec; + dst6 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst3, dst3); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst4, dst4); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst5, dst5); + DPADD_SB2_SH(vec6, vec7, filt0, filt1, dst6, dst6); + + ILVRL_H2_SH(dst3, dst2, dst32_r, dst32_l); + ILVRL_H2_SH(dst4, dst3, dst43_r, dst43_l); + ILVRL_H2_SH(dst5, dst4, dst54_r, dst54_l); + ILVRL_H2_SH(dst6, dst5, dst65_r, dst65_l); + + dst0_r = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + dst0_l = HEVC_FILT_4TAP(dst10_l, dst32_l, filt_h0, filt_h1); + dst1_r = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + dst1_l = HEVC_FILT_4TAP(dst21_l, dst43_l, filt_h0, filt_h1); + dst2_r = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + dst2_l = HEVC_FILT_4TAP(dst32_l, dst54_l, filt_h0, filt_h1); + dst3_r = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + dst3_l = HEVC_FILT_4TAP(dst43_l, dst65_l, filt_h0, filt_h1); + + SRA_4V(dst0_r, dst0_l, dst1_r, dst1_l, 6); + SRA_4V(dst2_r, dst2_l, dst3_r, dst3_l, 6); + PCKEV_H4_SW(dst0_l, dst0_r, dst1_l, dst1_r, dst2_l, dst2_r, dst3_l, + dst3_r, dst0_r, dst1_r, dst2_r, dst3_r); + ST_SW4(dst0_r, dst1_r, dst2_r, dst3_r, dst_tmp, dst_stride); + dst_tmp += (4 * dst_stride); + + dst10_r = dst54_r; + dst10_l = dst54_l; + dst21_r = dst65_r; + dst21_l = dst65_l; + dst2 = dst6; + } + + src += 8; + dst += 8; + + mask2 = LD_SB(ff_hevc_mask_arr + 16); + mask3 = mask2 + 2; + + LD_SB3(src, src_stride, src0, src1, src2); + src += (3 * src_stride); + XORI_B3_128_SB(src0, src1, src2); + VSHF_B2_SB(src0, src1, src0, src1, mask2, mask3, vec0, vec1); + VSHF_B2_SB(src1, src2, src1, src2, mask2, mask3, vec2, vec3); + dst10 = const_vec; + dst21 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst10, dst10); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst21, dst21); + ILVRL_H2_SH(dst21, dst10, dst10_r, dst21_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst21, 1); + + for (loop_cnt = 2; loop_cnt--;) { + LD_SB8(src, src_stride, src3, src4, src5, src6, src7, src8, src9, + src10); + src += (8 * src_stride); + XORI_B8_128_SB(src3, src4, src5, src6, src7, src8, src9, src10); + VSHF_B2_SB(src3, src7, src3, src7, mask2, mask3, vec0, vec1); + VSHF_B2_SB(src4, src8, src4, src8, mask2, mask3, vec2, vec3); + VSHF_B2_SB(src5, src9, src5, src9, mask2, mask3, vec4, vec5); + VSHF_B2_SB(src6, src10, src6, src10, mask2, mask3, vec6, vec7); + + dst73 = const_vec; + dst84 = const_vec; + dst95 = const_vec; + dst106 = const_vec; + DPADD_SB2_SH(vec0, vec1, filt0, filt1, dst73, dst73); + DPADD_SB2_SH(vec2, vec3, filt0, filt1, dst84, dst84); + DPADD_SB2_SH(vec4, vec5, filt0, filt1, dst95, dst95); + DPADD_SB2_SH(vec6, vec7, filt0, filt1, dst106, dst106); + + dst32_r = __msa_ilvr_h(dst73, dst22); + ILVRL_H2_SH(dst84, dst73, dst43_r, dst87_r); + ILVRL_H2_SH(dst95, dst84, dst54_r, dst98_r); + ILVRL_H2_SH(dst106, dst95, dst65_r, dst109_r); + dst22 = (v8i16) __msa_splati_d((v2i64) dst73, 1); + dst76_r = __msa_ilvr_h(dst22, dst106); + + tmp0 = HEVC_FILT_4TAP(dst10_r, dst32_r, filt_h0, filt_h1); + tmp1 = HEVC_FILT_4TAP(dst21_r, dst43_r, filt_h0, filt_h1); + tmp2 = HEVC_FILT_4TAP(dst32_r, dst54_r, filt_h0, filt_h1); + tmp3 = HEVC_FILT_4TAP(dst43_r, dst65_r, filt_h0, filt_h1); + tmp4 = HEVC_FILT_4TAP(dst54_r, dst76_r, filt_h0, filt_h1); + tmp5 = HEVC_FILT_4TAP(dst65_r, dst87_r, filt_h0, filt_h1); + tmp6 = HEVC_FILT_4TAP(dst76_r, dst98_r, filt_h0, filt_h1); + tmp7 = HEVC_FILT_4TAP(dst87_r, dst109_r, filt_h0, filt_h1); + + SRA_4V(tmp0, tmp1, tmp2, tmp3, 6); + SRA_4V(tmp4, tmp5, tmp6, tmp7, 6); + PCKEV_H4_SW(tmp1, tmp0, tmp3, tmp2, tmp5, tmp4, tmp7, tmp6, tmp0, tmp1, + tmp2, tmp3); + ST8x8_UB(tmp0, tmp1, tmp2, tmp3, dst, 2 * dst_stride); + dst += (8 * dst_stride); + + dst10_r = dst98_r; + dst21_r = dst109_r; + dst22 = (v8i16) __msa_splati_d((v2i64) dst106, 1); + } } static void hevc_hv_4t_16w_msa(uint8_t *src, @@ -3841,8 +4181,13 @@ static void hevc_hv_4t_16w_msa(uint8_t *src, const int8_t *filter_y, int32_t height) { - hevc_hv_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 16); + if (4 == height) { + hevc_hv_4t_8multx4_msa(src, src_stride, dst, dst_stride, + filter_x, filter_y, 2); + } else { + hevc_hv_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, + filter_x, filter_y, height, 2); + } } static void hevc_hv_4t_24w_msa(uint8_t *src, @@ -3854,7 +4199,7 @@ static void hevc_hv_4t_24w_msa(uint8_t *src, int32_t height) { hevc_hv_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 24); + filter_x, filter_y, height, 3); } static void hevc_hv_4t_32w_msa(uint8_t *src, @@ -3866,7 +4211,7 @@ static void hevc_hv_4t_32w_msa(uint8_t *src, int32_t height) { hevc_hv_4t_8multx4mult_msa(src, src_stride, dst, dst_stride, - filter_x, filter_y, height, 32); + filter_x, filter_y, height, 4); } #define MC_COPY(WIDTH) \ @@ -3893,19 +4238,19 @@ MC_COPY(64); #undef MC_COPY -#define MC(PEL, DIR, WIDTH, TAP, DIR1, FILT_DIR) \ -void ff_hevc_put_hevc_##PEL##_##DIR##WIDTH##_8_msa(int16_t *dst, \ - uint8_t *src, \ - ptrdiff_t src_stride, \ - int height, \ - intptr_t mx, \ - intptr_t my, \ - int width) \ -{ \ - const int8_t *filter = ff_hevc_##PEL##_filters[FILT_DIR - 1]; \ - \ - hevc_##DIR1##_##TAP##t_##WIDTH##w_msa(src, src_stride, dst, \ - MAX_PB_SIZE, filter, height); \ +#define MC(PEL, DIR, WIDTH, TAP, DIR1, FILT_DIR) \ +void ff_hevc_put_hevc_##PEL##_##DIR##WIDTH##_8_msa(int16_t *dst, \ + uint8_t *src, \ + ptrdiff_t src_stride, \ + int height, \ + intptr_t mx, \ + intptr_t my, \ + int width) \ +{ \ + const int8_t *filter = ff_hevc_##PEL##_filters[FILT_DIR - 1]; \ + \ + hevc_##DIR1##_##TAP##t_##WIDTH##w_msa(src, src_stride, dst, \ + MAX_PB_SIZE, filter, height); \ } MC(qpel, h, 4, 8, hz, mx); @@ -3944,37 +4289,37 @@ MC(epel, v, 32, 4, vt, my); #undef MC -#define MC_HV(PEL, DIR, WIDTH, TAP, DIR1) \ -void ff_hevc_put_hevc_##PEL##_##DIR##WIDTH##_8_msa(int16_t *dst, \ - uint8_t *src, \ - ptrdiff_t src_stride, \ - int height, \ - intptr_t mx, \ - intptr_t my, \ - int width) \ -{ \ - const int8_t *filter_x = ff_hevc_##PEL##_filters[mx - 1]; \ - const int8_t *filter_y = ff_hevc_##PEL##_filters[my - 1]; \ - \ - hevc_##DIR1##_##TAP##t_##WIDTH##w_msa(src, src_stride, dst, MAX_PB_SIZE, \ - filter_x, filter_y, height); \ -} - -MC_HV(qpel, hv, 4, 8, hv); -MC_HV(qpel, hv, 8, 8, hv); -MC_HV(qpel, hv, 12, 8, hv); -MC_HV(qpel, hv, 16, 8, hv); -MC_HV(qpel, hv, 24, 8, hv); -MC_HV(qpel, hv, 32, 8, hv); -MC_HV(qpel, hv, 48, 8, hv); -MC_HV(qpel, hv, 64, 8, hv); - -MC_HV(epel, hv, 4, 4, hv); -MC_HV(epel, hv, 6, 4, hv); -MC_HV(epel, hv, 8, 4, hv); -MC_HV(epel, hv, 12, 4, hv); -MC_HV(epel, hv, 16, 4, hv); -MC_HV(epel, hv, 24, 4, hv); -MC_HV(epel, hv, 32, 4, hv); +#define MC_HV(PEL, WIDTH, TAP) \ +void ff_hevc_put_hevc_##PEL##_hv##WIDTH##_8_msa(int16_t *dst, \ + uint8_t *src, \ + ptrdiff_t src_stride, \ + int height, \ + intptr_t mx, \ + intptr_t my, \ + int width) \ +{ \ + const int8_t *filter_x = ff_hevc_##PEL##_filters[mx - 1]; \ + const int8_t *filter_y = ff_hevc_##PEL##_filters[my - 1]; \ + \ + hevc_hv_##TAP##t_##WIDTH##w_msa(src, src_stride, dst, MAX_PB_SIZE, \ + filter_x, filter_y, height); \ +} + +MC_HV(qpel, 4, 8); +MC_HV(qpel, 8, 8); +MC_HV(qpel, 12, 8); +MC_HV(qpel, 16, 8); +MC_HV(qpel, 24, 8); +MC_HV(qpel, 32, 8); +MC_HV(qpel, 48, 8); +MC_HV(qpel, 64, 8); + +MC_HV(epel, 4, 4); +MC_HV(epel, 6, 4); +MC_HV(epel, 8, 4); +MC_HV(epel, 12, 4); +MC_HV(epel, 16, 4); +MC_HV(epel, 24, 4); +MC_HV(epel, 32, 4); #undef MC_HV diff --git a/libavcodec/mjpegdec.c b/libavcodec/mjpegdec.c index 5b2409755cb32..22ca69f84127f 100644 --- a/libavcodec/mjpegdec.c +++ b/libavcodec/mjpegdec.c @@ -36,6 +36,7 @@ #include "avcodec.h" #include "blockdsp.h" #include "copy_block.h" +#include "hwaccel.h" #include "idctdsp.h" #include "internal.h" #include "jpegtables.h" @@ -147,6 +148,7 @@ av_cold int ff_mjpeg_decode_init(AVCodecContext *avctx) s->org_height = avctx->coded_height; avctx->chroma_sample_location = AVCHROMA_LOC_CENTER; avctx->colorspace = AVCOL_SPC_BT470BG; + s->hwaccel_pix_fmt = s->hwaccel_sw_pix_fmt = AV_PIX_FMT_NONE; if ((ret = build_basic_mjpeg_vlc(s)) < 0) return ret; @@ -279,13 +281,18 @@ int ff_mjpeg_decode_dht(MJpegDecodeContext *s) code_max + 1, 0, 0)) < 0) return ret; } + + for (i = 0; i < 16; i++) + s->raw_huffman_lengths[class][index][i] = bits_table[i + 1]; + for (i = 0; i < 256; i++) + s->raw_huffman_values[class][index][i] = val_table[i]; } return 0; } int ff_mjpeg_decode_sof(MJpegDecodeContext *s) { - int len, nb_components, i, width, height, bits, ret; + int len, nb_components, i, width, height, bits, ret, size_change; unsigned pix_fmt_id; int h_count[MAX_COMPONENTS] = { 0 }; int v_count[MAX_COMPONENTS] = { 0 }; @@ -328,6 +335,8 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) av_log(s->avctx, AV_LOG_DEBUG, "sof0: picture: %dx%d\n", width, height); if (av_image_check_size(width, height, 0, s->avctx) < 0) return AVERROR_INVALIDDATA; + if (s->buf_size && (width + 7) / 8 * ((height + 7) / 8) > s->buf_size * 4LL) + return AVERROR_INVALIDDATA; nb_components = get_bits(&s->gb, 8); if (nb_components <= 0 || @@ -392,6 +401,7 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) if (width != s->width || height != s->height || bits != s->bits || memcmp(s->h_count, h_count, sizeof(h_count)) || memcmp(s->v_count, v_count, sizeof(v_count))) { + size_change = 1; s->width = width; s->height = height; @@ -418,6 +428,8 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) return ret; s->first_picture = 0; + } else { + size_change = 0; } if (s->got_picture && s->interlaced && (s->bottom_field == !s->interlace_polarity)) { @@ -636,6 +648,27 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) return AVERROR_BUG; } + if (s->avctx->pix_fmt == s->hwaccel_sw_pix_fmt && !size_change) { + s->avctx->pix_fmt = s->hwaccel_pix_fmt; + } else { + enum AVPixelFormat pix_fmts[] = { +#if CONFIG_MJPEG_NVDEC_HWACCEL + AV_PIX_FMT_CUDA, +#endif +#if CONFIG_MJPEG_VAAPI_HWACCEL + AV_PIX_FMT_VAAPI, +#endif + s->avctx->pix_fmt, + AV_PIX_FMT_NONE, + }; + s->hwaccel_pix_fmt = ff_get_format(s->avctx, pix_fmts); + if (s->hwaccel_pix_fmt < 0) + return AVERROR(EINVAL); + + s->hwaccel_sw_pix_fmt = s->avctx->pix_fmt; + s->avctx->pix_fmt = s->hwaccel_pix_fmt; + } + if (s->avctx->skip_frame == AVDISCARD_ALL) { s->picture_ptr->pict_type = AV_PICTURE_TYPE_I; s->picture_ptr->key_frame = 1; @@ -683,6 +716,19 @@ int ff_mjpeg_decode_sof(MJpegDecodeContext *s) } memset(s->coefs_finished, 0, sizeof(s->coefs_finished)); } + + if (s->avctx->hwaccel) { + s->hwaccel_picture_private = + av_mallocz(s->avctx->hwaccel->frame_priv_data_size); + if (!s->hwaccel_picture_private) + return AVERROR(ENOMEM); + + ret = s->avctx->hwaccel->start_frame(s->avctx, s->raw_image_buffer, + s->raw_image_buffer_size); + if (ret < 0) + return ret; + } + return 0; } @@ -715,7 +761,7 @@ static int decode_block(MJpegDecodeContext *s, int16_t *block, int component, av_log(s->avctx, AV_LOG_ERROR, "error dc\n"); return AVERROR_INVALIDDATA; } - val = val * quant_matrix[0] + s->last_dc[component]; + val = val * (unsigned)quant_matrix[0] + s->last_dc[component]; val = av_clip_int16(val); s->last_dc[component] = val; block[0] = val; @@ -1510,7 +1556,6 @@ int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const uint8_t *mb_bitmask, } } - av_assert0(s->picture_ptr->data[0]); /* XXX: verify len field validity */ len = get_bits(&s->gb, 16); nb_components = get_bits(&s->gb, 8); @@ -1600,7 +1645,18 @@ int ff_mjpeg_decode_sos(MJpegDecodeContext *s, const uint8_t *mb_bitmask, for (i = 0; i < nb_components; i++) s->last_dc[i] = (4 << s->bits); - if (s->lossless) { + if (s->avctx->hwaccel) { + int bytes_to_start = get_bits_count(&s->gb) / 8; + av_assert0(bytes_to_start >= 0 && + s->raw_scan_buffer_size >= bytes_to_start); + + ret = s->avctx->hwaccel->decode_slice(s->avctx, + s->raw_scan_buffer + bytes_to_start, + s->raw_scan_buffer_size - bytes_to_start); + if (ret < 0) + return ret; + + } else if (s->lossless) { av_assert0(s->picture_ptr == s->picture); if (CONFIG_JPEGLS_DECODER && s->ls) { // for () { @@ -1867,7 +1923,7 @@ static int mjpeg_decode_app(MJpegDecodeContext *s) // read 0th IFD and store the metadata // (return values > 0 indicate the presence of subimage metadata) - ret = avpriv_exif_decode_ifd(s->avctx, &gbytes, le, 0, &s->exif_metadata); + ret = ff_exif_decode_ifd(s->avctx, &gbytes, le, 0, &s->exif_metadata); if (ret < 0) { av_log(s->avctx, AV_LOG_ERROR, "mjpeg: error decoding EXIF data\n"); } @@ -2193,6 +2249,8 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, int ret = 0; int is16bit; + s->buf_size = buf_size; + av_dict_free(&s->exif_metadata); av_freep(&s->stereo3d); s->adobe_transform = -1; @@ -2278,6 +2336,8 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, case SOI: s->restart_interval = 0; s->restart_count = 0; + s->raw_image_buffer = buf_ptr; + s->raw_image_buffer_size = buf_end - buf_ptr; /* nothing to do on SOI */ break; case DHT: @@ -2288,6 +2348,10 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, break; case SOF0: case SOF1: + if (start_code == SOF0) + s->avctx->profile = FF_PROFILE_MJPEG_HUFFMAN_BASELINE_DCT; + else + s->avctx->profile = FF_PROFILE_MJPEG_HUFFMAN_EXTENDED_SEQUENTIAL_DCT; s->lossless = 0; s->ls = 0; s->progressive = 0; @@ -2295,6 +2359,7 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, goto fail; break; case SOF2: + s->avctx->profile = FF_PROFILE_MJPEG_HUFFMAN_PROGRESSIVE_DCT; s->lossless = 0; s->ls = 0; s->progressive = 1; @@ -2302,6 +2367,7 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, goto fail; break; case SOF3: + s->avctx->profile = FF_PROFILE_MJPEG_HUFFMAN_LOSSLESS; s->avctx->properties |= FF_CODEC_PROPERTY_LOSSLESS; s->lossless = 1; s->ls = 0; @@ -2310,6 +2376,7 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, goto fail; break; case SOF48: + s->avctx->profile = FF_PROFILE_MJPEG_JPEG_LS; s->avctx->properties |= FF_CODEC_PROPERTY_LOSSLESS; s->lossless = 1; s->ls = 1; @@ -2324,7 +2391,8 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, break; case EOI: eoi_parser: - if (avctx->skip_frame != AVDISCARD_ALL && s->progressive && s->cur_scan && s->got_picture) + if (!avctx->hwaccel && avctx->skip_frame != AVDISCARD_ALL && + s->progressive && s->cur_scan && s->got_picture) mjpeg_idct_scan_progressive_ac(s); s->cur_scan = 0; if (!s->got_picture) { @@ -2342,6 +2410,13 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, s->got_picture = 0; goto the_end_no_picture; } + if (s->avctx->hwaccel) { + ret = s->avctx->hwaccel->end_frame(s->avctx); + if (ret < 0) + return ret; + + av_freep(&s->hwaccel_picture_private); + } if ((ret = av_frame_ref(frame, s->picture_ptr)) < 0) return ret; *got_frame = 1; @@ -2364,6 +2439,9 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, goto the_end; case SOS: + s->raw_scan_buffer = buf_ptr; + s->raw_scan_buffer_size = buf_end - buf_ptr; + s->cur_scan++; if (avctx->skip_frame == AVDISCARD_ALL) { skip_bits(&s->gb, get_bits_left(&s->gb)); @@ -2428,7 +2506,10 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, avctx->pix_fmt == AV_PIX_FMT_GBRP || avctx->pix_fmt == AV_PIX_FMT_GBRAP ); - avcodec_get_chroma_sub_sample(s->avctx->pix_fmt, &hshift, &vshift); + ret = av_pix_fmt_get_chroma_sub_sample(s->avctx->pix_fmt, &hshift, &vshift); + if (ret) + return ret; + av_assert0(s->nb_components == av_pix_fmt_count_planes(s->picture_ptr->format)); for (p = 0; pnb_components; p++) { uint8_t *line = s->picture_ptr->data[p]; @@ -2487,7 +2568,10 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, avctx->pix_fmt == AV_PIX_FMT_GBRP || avctx->pix_fmt == AV_PIX_FMT_GBRAP ); - avcodec_get_chroma_sub_sample(s->avctx->pix_fmt, &hshift, &vshift); + ret = av_pix_fmt_get_chroma_sub_sample(s->avctx->pix_fmt, &hshift, &vshift); + if (ret) + return ret; + av_assert0(s->nb_components == av_pix_fmt_count_planes(s->picture_ptr->format)); for (p = 0; p < s->nb_components; p++) { uint8_t *dst; @@ -2515,7 +2599,10 @@ int ff_mjpeg_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, } if (s->flipped && !s->rgb) { int j; - avcodec_get_chroma_sub_sample(s->avctx->pix_fmt, &hshift, &vshift); + ret = av_pix_fmt_get_chroma_sub_sample(s->avctx->pix_fmt, &hshift, &vshift); + if (ret) + return ret; + av_assert0(s->nb_components == av_pix_fmt_count_planes(s->picture_ptr->format)); for (index=0; indexnb_components; index++) { uint8_t *dst = s->picture_ptr->data[index]; @@ -2657,6 +2744,8 @@ av_cold int ff_mjpeg_decode_end(AVCodecContext *avctx) reset_icc_profile(s); + av_freep(&s->hwaccel_picture_private); + return 0; } @@ -2697,6 +2786,15 @@ AVCodec ff_mjpeg_decoder = { .priv_class = &mjpegdec_class, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, + .hw_configs = (const AVCodecHWConfigInternal*[]) { +#if CONFIG_MJPEG_NVDEC_HWACCEL + HWACCEL_NVDEC(mjpeg), +#endif +#if CONFIG_MJPEG_VAAPI_HWACCEL + HWACCEL_VAAPI(mjpeg), +#endif + NULL + }, }; #endif #if CONFIG_THP_DECODER diff --git a/libavcodec/mjpegdec.h b/libavcodec/mjpegdec.h index c84a40aa6e649..653fe7cae6eec 100644 --- a/libavcodec/mjpegdec.h +++ b/libavcodec/mjpegdec.h @@ -39,12 +39,15 @@ #include "hpeldsp.h" #include "idctdsp.h" +#undef near /* This file uses struct member 'near' which in windows.h is defined as empty. */ + #define MAX_COMPONENTS 4 typedef struct MJpegDecodeContext { AVClass *class; AVCodecContext *avctx; GetBitContext gb; + int buf_size; int start_code; /* current start code */ int buffer_size; @@ -135,6 +138,19 @@ typedef struct MJpegDecodeContext { int *iccdatalens; int iccnum; int iccread; + + // Raw stream data for hwaccel use. + const uint8_t *raw_image_buffer; + size_t raw_image_buffer_size; + const uint8_t *raw_scan_buffer; + size_t raw_scan_buffer_size; + + uint8_t raw_huffman_lengths[2][4][16]; + uint8_t raw_huffman_values[2][4][256]; + + enum AVPixelFormat hwaccel_sw_pix_fmt; + enum AVPixelFormat hwaccel_pix_fmt; + void *hwaccel_picture_private; } MJpegDecodeContext; int ff_mjpeg_decode_init(AVCodecContext *avctx); diff --git a/libavcodec/mjpegenc.c b/libavcodec/mjpegenc.c index e6cdaf63760f1..d2fcb8e19199a 100644 --- a/libavcodec/mjpegenc.c +++ b/libavcodec/mjpegenc.c @@ -358,12 +358,6 @@ static int amv_encode_picture(AVCodecContext *avctx, AVPacket *pkt, av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, &chroma_h_shift, &chroma_v_shift); -#if FF_API_EMU_EDGE - //CODEC_FLAG_EMU_EDGE have to be cleared - if(s->avctx->flags & CODEC_FLAG_EMU_EDGE) - return AVERROR(EINVAL); -#endif - if ((avctx->height & 15) && avctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) { av_log(avctx, AV_LOG_ERROR, "Heights which are not a multiple of 16 might fail with some decoders, " diff --git a/libavcodec/mlp_parser.c b/libavcodec/mlp_parser.c index 23601c8633168..185bd4d667f66 100644 --- a/libavcodec/mlp_parser.c +++ b/libavcodec/mlp_parser.c @@ -119,7 +119,7 @@ uint64_t ff_truehd_layout(int chanmap) return layout; } -static int ff_mlp_get_major_sync_size(const uint8_t * buf, int bufsize) +static int mlp_get_major_sync_size(const uint8_t * buf, int bufsize) { int has_extension, extensions = 0; int size = 28; @@ -149,7 +149,7 @@ int ff_mlp_read_major_sync(void *log, MLPHeaderInfo *mh, GetBitContext *gb) av_assert1(get_bits_count(gb) == 0); - header_size = ff_mlp_get_major_sync_size(gb->buffer, gb->size_in_bits >> 3); + header_size = mlp_get_major_sync_size(gb->buffer, gb->size_in_bits >> 3); if (header_size < 0 || gb->size_in_bits < header_size << 3) { av_log(log, AV_LOG_ERROR, "packet too short, unable to read major sync\n"); return -1; @@ -256,66 +256,70 @@ static int mlp_parse(AVCodecParserContext *s, if (buf_size == 0) return 0; - if (!mp->in_sync) { - // Not in sync - find a major sync header - - for (i = 0; i < buf_size; i++) { - mp->pc.state = (mp->pc.state << 8) | buf[i]; - if ((mp->pc.state & 0xfffffffe) == 0xf8726fba && - // ignore if we do not have the data for the start of header - mp->pc.index + i >= 7) { - mp->in_sync = 1; - mp->bytes_left = 0; - break; + if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { + next = buf_size; + } else { + if (!mp->in_sync) { + // Not in sync - find a major sync header + + for (i = 0; i < buf_size; i++) { + mp->pc.state = (mp->pc.state << 8) | buf[i]; + if ((mp->pc.state & 0xfffffffe) == 0xf8726fba && + // ignore if we do not have the data for the start of header + mp->pc.index + i >= 7) { + mp->in_sync = 1; + mp->bytes_left = 0; + break; + } } - } - if (!mp->in_sync) { - if (ff_combine_frame(&mp->pc, END_NOT_FOUND, &buf, &buf_size) != -1) + if (!mp->in_sync) { + if (ff_combine_frame(&mp->pc, END_NOT_FOUND, &buf, &buf_size) != -1) + av_log(avctx, AV_LOG_WARNING, "ff_combine_frame failed\n"); + return buf_size; + } + + if ((ret = ff_combine_frame(&mp->pc, i - 7, &buf, &buf_size)) < 0) { av_log(avctx, AV_LOG_WARNING, "ff_combine_frame failed\n"); - return buf_size; - } + return ret; + } - if ((ret = ff_combine_frame(&mp->pc, i - 7, &buf, &buf_size)) < 0) { - av_log(avctx, AV_LOG_WARNING, "ff_combine_frame failed\n"); - return ret; + return i - 7; } - return i - 7; - } + if (mp->bytes_left == 0) { + // Find length of this packet - if (mp->bytes_left == 0) { - // Find length of this packet + /* Copy overread bytes from last frame into buffer. */ + for(; mp->pc.overread>0; mp->pc.overread--) { + mp->pc.buffer[mp->pc.index++]= mp->pc.buffer[mp->pc.overread_index++]; + } - /* Copy overread bytes from last frame into buffer. */ - for(; mp->pc.overread>0; mp->pc.overread--) { - mp->pc.buffer[mp->pc.index++]= mp->pc.buffer[mp->pc.overread_index++]; - } + if (mp->pc.index + buf_size < 2) { + if (ff_combine_frame(&mp->pc, END_NOT_FOUND, &buf, &buf_size) != -1) + av_log(avctx, AV_LOG_WARNING, "ff_combine_frame failed\n"); + return buf_size; + } - if (mp->pc.index + buf_size < 2) { - if (ff_combine_frame(&mp->pc, END_NOT_FOUND, &buf, &buf_size) != -1) - av_log(avctx, AV_LOG_WARNING, "ff_combine_frame failed\n"); - return buf_size; + mp->bytes_left = ((mp->pc.index > 0 ? mp->pc.buffer[0] : buf[0]) << 8) + | (mp->pc.index > 1 ? mp->pc.buffer[1] : buf[1-mp->pc.index]); + mp->bytes_left = (mp->bytes_left & 0xfff) * 2; + if (mp->bytes_left <= 0) { // prevent infinite loop + goto lost_sync; + } + mp->bytes_left -= mp->pc.index; } - mp->bytes_left = ((mp->pc.index > 0 ? mp->pc.buffer[0] : buf[0]) << 8) - | (mp->pc.index > 1 ? mp->pc.buffer[1] : buf[1-mp->pc.index]); - mp->bytes_left = (mp->bytes_left & 0xfff) * 2; - if (mp->bytes_left <= 0) { // prevent infinite loop - goto lost_sync; - } - mp->bytes_left -= mp->pc.index; - } + next = (mp->bytes_left > buf_size) ? END_NOT_FOUND : mp->bytes_left; - next = (mp->bytes_left > buf_size) ? END_NOT_FOUND : mp->bytes_left; + if (ff_combine_frame(&mp->pc, next, &buf, &buf_size) < 0) { + mp->bytes_left -= buf_size; + return buf_size; + } - if (ff_combine_frame(&mp->pc, next, &buf, &buf_size) < 0) { - mp->bytes_left -= buf_size; - return buf_size; + mp->bytes_left = 0; } - mp->bytes_left = 0; - sync_present = (AV_RB32(buf + 4) & 0xfffffffe) == 0xf8726fba; if (!sync_present) { @@ -357,28 +361,11 @@ static int mlp_parse(AVCodecParserContext *s, if(!avctx->channels || !avctx->channel_layout) { if (mh.stream_type == 0xbb) { /* MLP stream */ - if (avctx->request_channel_layout && - (avctx->request_channel_layout & AV_CH_LAYOUT_STEREO) == - avctx->request_channel_layout && - mh.num_substreams > 1) { - avctx->channels = 2; - avctx->channel_layout = AV_CH_LAYOUT_STEREO; - } else { - avctx->channels = mh.channels_mlp; - avctx->channel_layout = mh.channel_layout_mlp; - } + avctx->channels = mh.channels_mlp; + avctx->channel_layout = mh.channel_layout_mlp; } else { /* mh.stream_type == 0xba */ /* TrueHD stream */ - if (avctx->request_channel_layout && - (avctx->request_channel_layout & AV_CH_LAYOUT_STEREO) == - avctx->request_channel_layout && - mh.num_substreams > 1) { - avctx->channels = 2; - avctx->channel_layout = AV_CH_LAYOUT_STEREO; - } else if (!mh.channels_thd_stream2 || - (avctx->request_channel_layout && - (avctx->request_channel_layout & mh.channel_layout_thd_stream1) == - avctx->request_channel_layout)) { + if (!mh.channels_thd_stream2) { avctx->channels = mh.channels_thd_stream1; avctx->channel_layout = mh.channel_layout_thd_stream1; } else { diff --git a/libavcodec/mlpdec.c b/libavcodec/mlpdec.c index d5585d308079b..63ec3e64bdffd 100644 --- a/libavcodec/mlpdec.c +++ b/libavcodec/mlpdec.c @@ -66,7 +66,7 @@ typedef struct SubStream { /// For each channel output by the matrix, the output channel to map it to uint8_t ch_assign[MAX_CHANNELS]; /// The channel layout for this substream - uint64_t ch_layout; + uint64_t mask; /// The matrix encoding mode for this substream enum AVMatrixEncoding matrix_encoding; @@ -180,6 +180,11 @@ static const uint64_t thd_channel_order[] = { AV_CH_LOW_FREQUENCY_2, // LFE2 }; +static int mlp_channel_layout_subset(uint64_t channel_layout, uint64_t mask) +{ + return channel_layout && ((channel_layout & mask) == channel_layout); +} + static uint64_t thd_channel_layout_extract_channel(uint64_t channel_layout, int index) { @@ -390,8 +395,8 @@ static int read_major_sync(MLPDecodeContext *m, GetBitContext *gb) return AVERROR_PATCHWELCOME; } if ((substr = (mh.num_substreams > 1))) - m->substream[0].ch_layout = AV_CH_LAYOUT_STEREO; - m->substream[substr].ch_layout = mh.channel_layout_mlp; + m->substream[0].mask = AV_CH_LAYOUT_STEREO; + m->substream[substr].mask = mh.channel_layout_mlp; } else { if (mh.stream_type != 0xba) { avpriv_request_sample(m->avctx, @@ -400,15 +405,15 @@ static int read_major_sync(MLPDecodeContext *m, GetBitContext *gb) return AVERROR_PATCHWELCOME; } if ((substr = (mh.num_substreams > 1))) - m->substream[0].ch_layout = AV_CH_LAYOUT_STEREO; + m->substream[0].mask = AV_CH_LAYOUT_STEREO; if (mh.num_substreams > 2) if (mh.channel_layout_thd_stream2) - m->substream[2].ch_layout = mh.channel_layout_thd_stream2; + m->substream[2].mask = mh.channel_layout_thd_stream2; else - m->substream[2].ch_layout = mh.channel_layout_thd_stream1; - m->substream[substr].ch_layout = mh.channel_layout_thd_stream1; + m->substream[2].mask = mh.channel_layout_thd_stream1; + m->substream[substr].mask = mh.channel_layout_thd_stream1; - if (m->avctx->channels<=2 && m->substream[substr].ch_layout == AV_CH_LAYOUT_MONO && m->max_decoded_substream == 1) { + if (m->avctx->channels<=2 && m->substream[substr].mask == AV_CH_LAYOUT_MONO && m->max_decoded_substream == 1) { av_log(m->avctx, AV_LOG_DEBUG, "Mono stream with 2 substreams, ignoring 2nd\n"); m->max_decoded_substream = 0; if (m->avctx->channels==2) @@ -533,12 +538,12 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp, s->max_channel = max_channel; s->max_matrix_channel = max_matrix_channel; - if (m->avctx->request_channel_layout && (s->ch_layout & m->avctx->request_channel_layout) == - m->avctx->request_channel_layout && m->max_decoded_substream > substr) { + if (mlp_channel_layout_subset(m->avctx->request_channel_layout, s->mask) && + m->max_decoded_substream > substr) { av_log(m->avctx, AV_LOG_DEBUG, "Extracting %d-channel downmix (0x%"PRIx64") from substream %d. " "Further substreams will be skipped.\n", - s->max_channel + 1, s->ch_layout, substr); + s->max_channel + 1, s->mask, substr); m->max_decoded_substream = substr; } @@ -565,9 +570,9 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp, for (ch = 0; ch <= s->max_matrix_channel; ch++) { int ch_assign = get_bits(gbp, 6); if (m->avctx->codec_id == AV_CODEC_ID_TRUEHD) { - uint64_t channel = thd_channel_layout_extract_channel(s->ch_layout, + uint64_t channel = thd_channel_layout_extract_channel(s->mask, ch_assign); - ch_assign = av_get_channel_layout_channel_index(s->ch_layout, + ch_assign = av_get_channel_layout_channel_index(s->mask, channel); } if (ch_assign < 0 || ch_assign > s->max_matrix_channel) { @@ -609,7 +614,7 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp, if (substr == m->max_decoded_substream) { m->avctx->channels = s->max_matrix_channel + 1; - m->avctx->channel_layout = s->ch_layout; + m->avctx->channel_layout = s->mask; m->dsp.mlp_pack_output = m->dsp.mlp_select_pack_output(s->ch_assign, s->output_shift, s->max_matrix_channel, diff --git a/libavcodec/mlpdsp.c b/libavcodec/mlpdsp.c index fbafa92d72cc3..32a4503b64ebe 100644 --- a/libavcodec/mlpdsp.c +++ b/libavcodec/mlpdsp.c @@ -117,7 +117,7 @@ int32_t ff_mlp_pack_output(int32_t lossless_check_data, (1U << output_shift[mat_ch]); lossless_check_data ^= (sample & 0xffffff) << mat_ch; if (is32) - *data_32++ = sample << 8; + *data_32++ = sample * 256U; else *data_16++ = sample >> 8; } diff --git a/libavcodec/mmaldec.c b/libavcodec/mmaldec.c index 0b1195dc3e6f0..647a22ef7c07c 100644 --- a/libavcodec/mmaldec.c +++ b/libavcodec/mmaldec.c @@ -34,6 +34,7 @@ #include #include "avcodec.h" +#include "hwaccel.h" #include "internal.h" #include "libavutil/avassert.h" #include "libavutil/buffer.h" @@ -807,32 +808,9 @@ static int ffmmal_decode(AVCodecContext *avctx, void *data, int *got_frame, return ret; } -AVHWAccel ff_h264_mmal_hwaccel = { - .name = "h264_mmal", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_H264, - .pix_fmt = AV_PIX_FMT_MMAL, -}; - -AVHWAccel ff_mpeg2_mmal_hwaccel = { - .name = "mpeg2_mmal", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_MPEG2VIDEO, - .pix_fmt = AV_PIX_FMT_MMAL, -}; - -AVHWAccel ff_mpeg4_mmal_hwaccel = { - .name = "mpeg4_mmal", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_MPEG4, - .pix_fmt = AV_PIX_FMT_MMAL, -}; - -AVHWAccel ff_vc1_mmal_hwaccel = { - .name = "vc1_mmal", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_VC1, - .pix_fmt = AV_PIX_FMT_MMAL, +static const AVCodecHWConfigInternal *mmal_hw_configs[] = { + HW_CONFIG_INTERNAL(MMAL), + NULL }; static const AVOption options[]={ @@ -844,6 +822,7 @@ static const AVOption options[]={ #define FFMMAL_DEC_CLASS(NAME) \ static const AVClass ffmmal_##NAME##_dec_class = { \ .class_name = "mmal_" #NAME "_dec", \ + .item_name = av_default_item_name, \ .option = options, \ .version = LIBAVUTIL_VERSION_INT, \ }; @@ -861,11 +840,13 @@ static const AVOption options[]={ .decode = ffmmal_decode, \ .flush = ffmmal_flush, \ .priv_class = &ffmmal_##NAME##_dec_class, \ - .capabilities = AV_CODEC_CAP_DELAY, \ + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, \ .caps_internal = FF_CODEC_CAP_SETS_PKT_DTS, \ .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_MMAL, \ AV_PIX_FMT_YUV420P, \ AV_PIX_FMT_NONE}, \ + .hw_configs = mmal_hw_configs, \ + .wrapper_name = "mmal", \ }; FFMMAL_DEC(h264, AV_CODEC_ID_H264) diff --git a/libavcodec/motion_est.c b/libavcodec/motion_est.c index 316d16a77b84d..8b5ce2117afc8 100644 --- a/libavcodec/motion_est.c +++ b/libavcodec/motion_est.c @@ -313,26 +313,6 @@ int ff_init_me(MpegEncContext *s){ return -1; } -#if FF_API_MOTION_EST - //special case of snow is needed because snow uses its own iterative ME code -FF_DISABLE_DEPRECATION_WARNINGS - if (s->motion_est == FF_ME_EPZS) { - if (s->me_method == ME_ZERO) - s->motion_est = FF_ME_ZERO; - else if (s->me_method == ME_EPZS) - s->motion_est = FF_ME_EPZS; - else if (s->me_method == ME_X1) - s->motion_est = FF_ME_XONE; - else if (s->avctx->codec_id != AV_CODEC_ID_SNOW) { - av_log(s->avctx, AV_LOG_ERROR, - "me_method is only allowed to be set to zero and epzs; " - "for hex,umh,full and others see dia_size\n"); - return -1; - } - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif - c->avctx= s->avctx; if(s->codec_id == AV_CODEC_ID_H261) diff --git a/libavcodec/movsub_bsf.c b/libavcodec/movsub_bsf.c index 3cb1183cd89e3..5878607061eab 100644 --- a/libavcodec/movsub_bsf.c +++ b/libavcodec/movsub_bsf.c @@ -62,35 +62,23 @@ const AVBitStreamFilter ff_text2movsub_bsf = { .filter = text2movsub, }; -static int mov2textsub(AVBSFContext *ctx, AVPacket *out) +static int mov2textsub(AVBSFContext *ctx, AVPacket *pkt) { - AVPacket *in; int ret = 0; - ret = ff_bsf_get_packet(ctx, &in); + ret = ff_bsf_get_packet_ref(ctx, pkt); if (ret < 0) return ret; - if (in->size < 2) { - ret = AVERROR_INVALIDDATA; - goto fail; + if (pkt->size < 2) { + av_packet_unref(pkt); + return AVERROR_INVALIDDATA; } - ret = av_new_packet(out, FFMIN(in->size - 2, AV_RB16(in->data))); - if (ret < 0) - goto fail; - - ret = av_packet_copy_props(out, in); - if (ret < 0) - goto fail; - - memcpy(out->data, in->data + 2, out->size); + pkt->data += 2; + pkt->size = FFMIN(pkt->size - 2, AV_RB16(pkt->data)); -fail: - if (ret < 0) - av_packet_unref(out); - av_packet_free(&in); - return ret; + return 0; } const AVBitStreamFilter ff_mov2textsub_bsf = { diff --git a/libavcodec/movtextdec.c b/libavcodec/movtextdec.c index fb5085c3e8222..c38c5edce6783 100644 --- a/libavcodec/movtextdec.c +++ b/libavcodec/movtextdec.c @@ -299,6 +299,14 @@ static int decode_styl(const uint8_t *tsmb, MovTextContext *m, AVPacket *avpkt) m->s_temp->style_start = AV_RB16(tsmb); tsmb += 2; m->s_temp->style_end = AV_RB16(tsmb); + + if ( m->s_temp->style_end < m->s_temp->style_start + || (m->count_s && m->s_temp->style_start < m->s[m->count_s - 1]->style_end)) { + av_freep(&m->s_temp); + mov_text_cleanup(m); + return AVERROR(ENOMEM); + } + tsmb += 2; m->s_temp->style_fontID = AV_RB16(tsmb); tsmb += 2; @@ -326,9 +334,24 @@ static const Box box_types[] = { const static size_t box_count = FF_ARRAY_ELEMS(box_types); +// Return byte length of the UTF-8 sequence starting at text[0]. 0 on error. +static int get_utf8_length_at(const char *text, const char *text_end) +{ + const char *start = text; + int err = 0; + uint32_t c; + GET_UTF8(c, text < text_end ? (uint8_t)*text++ : (err = 1, 0), goto error;); + if (err) + goto error; + return text - start; +error: + return 0; +} + static int text_to_ass(AVBPrint *buf, const char *text, const char *text_end, - MovTextContext *m) + AVCodecContext *avctx) { + MovTextContext *m = avctx->priv_data; int i = 0; int j = 0; int text_pos = 0; @@ -342,6 +365,8 @@ static int text_to_ass(AVBPrint *buf, const char *text, const char *text_end, } while (text < text_end) { + int len; + if (m->box_flags & STYL_BOX) { for (i = 0; i < m->style_entries; i++) { if (m->s[i]->style_flag && text_pos == m->s[i]->style_end) { @@ -388,17 +413,24 @@ static int text_to_ass(AVBPrint *buf, const char *text, const char *text_end, } } - switch (*text) { - case '\r': - break; - case '\n': - av_bprintf(buf, "\\N"); - break; - default: - av_bprint_chars(buf, *text, 1); - break; + len = get_utf8_length_at(text, text_end); + if (len < 1) { + av_log(avctx, AV_LOG_ERROR, "invalid UTF-8 byte in subtitle\n"); + len = 1; + } + for (i = 0; i < len; i++) { + switch (*text) { + case '\r': + break; + case '\n': + av_bprintf(buf, "\\N"); + break; + default: + av_bprint_chars(buf, *text, 1); + break; + } + text++; } - text++; text_pos++; } @@ -436,6 +468,7 @@ static int mov_text_decode_frame(AVCodecContext *avctx, int text_length, tsmb_type, ret_tsmb; uint64_t tsmb_size; const uint8_t *tsmb; + size_t i; if (!ptr || avpkt->size < 2) return AVERROR_INVALIDDATA; @@ -495,7 +528,7 @@ static int mov_text_decode_frame(AVCodecContext *avctx, if (tsmb_size > avpkt->size - m->tracksize) break; - for (size_t i = 0; i < box_count; i++) { + for (i = 0; i < box_count; i++) { if (tsmb_type == box_types[i].type) { if (m->tracksize + m->size_var + box_types[i].base_size > avpkt->size) break; @@ -506,10 +539,10 @@ static int mov_text_decode_frame(AVCodecContext *avctx, } m->tracksize = m->tracksize + tsmb_size; } - text_to_ass(&buf, ptr, end, m); + text_to_ass(&buf, ptr, end, avctx); mov_text_cleanup(m); } else - text_to_ass(&buf, ptr, end, m); + text_to_ass(&buf, ptr, end, avctx); ret = ff_ass_add_rect(sub, buf.str, m->readorder++, 0, NULL, NULL); av_bprint_finalize(&buf, NULL); diff --git a/libavcodec/movtextenc.c b/libavcodec/movtextenc.c index d795e317c3f9e..c19ef384bcf92 100644 --- a/libavcodec/movtextenc.c +++ b/libavcodec/movtextenc.c @@ -72,6 +72,7 @@ typedef struct { uint8_t style_fontsize; uint32_t style_color; uint16_t text_pos; + uint16_t byte_count; } MovTextContext; typedef struct { @@ -304,11 +305,34 @@ static void mov_text_color_cb(void *priv, unsigned int color, unsigned int color */ } +static uint16_t utf8_strlen(const char *text, int len) +{ + uint16_t i = 0, ret = 0; + while (i < len) { + char c = text[i]; + if ((c & 0x80) == 0) + i += 1; + else if ((c & 0xE0) == 0xC0) + i += 2; + else if ((c & 0xF0) == 0xE0) + i += 3; + else if ((c & 0xF8) == 0xF0) + i += 4; + else + return 0; + ret++; + } + return ret; +} + static void mov_text_text_cb(void *priv, const char *text, int len) { + uint16_t utf8_len = utf8_strlen(text, len); MovTextContext *s = priv; av_bprint_append_data(&s->buffer, text, len); - s->text_pos += len; + // If it's not utf-8, just use the byte length + s->text_pos += utf8_len ? utf8_len : len; + s->byte_count += len; } static void mov_text_new_line_cb(void *priv, int forced) @@ -316,6 +340,7 @@ static void mov_text_new_line_cb(void *priv, int forced) MovTextContext *s = priv; av_bprint_append_data(&s->buffer, "\n", 1); s->text_pos += 1; + s->byte_count += 1; } static const ASSCodesCallbacks mov_text_callbacks = { @@ -333,6 +358,7 @@ static int mov_text_encode_frame(AVCodecContext *avctx, unsigned char *buf, int i, length; size_t j; + s->byte_count = 0; s->text_pos = 0; s->count = 0; s->box_flags = 0; @@ -368,7 +394,7 @@ static int mov_text_encode_frame(AVCodecContext *avctx, unsigned char *buf, } } - AV_WB16(buf, s->text_pos); + AV_WB16(buf, s->byte_count); buf += 2; if (!av_bprint_is_complete(&s->buffer)) { diff --git a/libavcodec/mp3_header_decompress_bsf.c b/libavcodec/mp3_header_decompress_bsf.c index 22c1ef0220efe..294858953cbce 100644 --- a/libavcodec/mp3_header_decompress_bsf.c +++ b/libavcodec/mp3_header_decompress_bsf.c @@ -87,7 +87,7 @@ static int mp3_header_decompress(AVBSFContext *ctx, AVPacket *out) goto fail; ret = av_packet_copy_props(out, in); if (ret < 0) { - av_packet_free(&out); + av_packet_unref(out); goto fail; } memcpy(out->data + frame_size - buf_size, buf, buf_size + AV_INPUT_BUFFER_PADDING_SIZE); diff --git a/libavcodec/mpc8.c b/libavcodec/mpc8.c index 80e0e9e68df89..3be2f79a5a1a7 100644 --- a/libavcodec/mpc8.c +++ b/libavcodec/mpc8.c @@ -250,11 +250,6 @@ static int mpc8_decode_frame(AVCodecContext * avctx, void *data, int maxband, keyframe; int last[2]; - /* get output buffer */ - frame->nb_samples = MPC_FRAME_SIZE; - if ((res = ff_get_buffer(avctx, frame, 0)) < 0) - return res; - keyframe = c->cur_frame == 0; if(keyframe){ @@ -273,6 +268,11 @@ static int mpc8_decode_frame(AVCodecContext * avctx, void *data, if(maxband > 32) maxband -= 33; } + if (get_bits_left(gb) < 0) { + *got_frame_ptr = 0; + return buf_size; + } + if(maxband > c->maxbands + 1) { av_log(avctx, AV_LOG_ERROR, "maxband %d too large\n",maxband); return AVERROR_INVALIDDATA; @@ -410,6 +410,10 @@ static int mpc8_decode_frame(AVCodecContext * avctx, void *data, } } + frame->nb_samples = MPC_FRAME_SIZE; + if ((res = ff_get_buffer(avctx, frame, 0)) < 0) + return res; + ff_mpc_dequantize_and_synth(c, maxband - 1, (int16_t **)frame->extended_data, avctx->channels); @@ -419,11 +423,11 @@ static int mpc8_decode_frame(AVCodecContext * avctx, void *data, c->last_bits_used = get_bits_count(gb); if(c->cur_frame >= c->frames) c->cur_frame = 0; - if(c->cur_frame == 0 && get_bits_left(gb) < 8) {// we have only padding left - c->last_bits_used = buf_size << 3; - } else if (get_bits_left(gb) < 0) { + if (get_bits_left(gb) < 0) { av_log(avctx, AV_LOG_ERROR, "Overread %d\n", -get_bits_left(gb)); c->last_bits_used = buf_size << 3; + } else if (c->cur_frame == 0 && get_bits_left(gb) < 8) {// we have only padding left + c->last_bits_used = buf_size << 3; } *got_frame_ptr = 1; diff --git a/libavcodec/mpeg12.h b/libavcodec/mpeg12.h index f551504b8cc74..1ec99f17e16d7 100644 --- a/libavcodec/mpeg12.h +++ b/libavcodec/mpeg12.h @@ -73,4 +73,8 @@ void ff_mpeg1_encode_mb(MpegEncContext *s, int16_t block[8][64], void ff_mpeg1_encode_init(MpegEncContext *s); void ff_mpeg1_encode_slice_header(MpegEncContext *s); +void ff_mpeg12_find_best_frame_rate(AVRational frame_rate, + int *code, int *ext_n, int *ext_d, + int nonstandard); + #endif /* AVCODEC_MPEG12_H */ diff --git a/libavcodec/mpeg12dec.c b/libavcodec/mpeg12dec.c index 22c29c1505283..83e537884b694 100644 --- a/libavcodec/mpeg12dec.c +++ b/libavcodec/mpeg12dec.c @@ -36,6 +36,7 @@ #include "avcodec.h" #include "bytestream.h" #include "error_resilience.h" +#include "hwaccel.h" #include "idctdsp.h" #include "internal.h" #include "mpeg_er.h" @@ -47,7 +48,6 @@ #include "profiles.h" #include "thread.h" #include "version.h" -#include "vdpau_compat.h" #include "xvmc_internal.h" typedef struct Mpeg1Context { @@ -649,16 +649,6 @@ static inline int get_dmv(MpegEncContext *s) return 0; } -static inline int get_qscale(MpegEncContext *s) -{ - int qscale = get_bits(&s->gb, 5); - if (s->q_scale_type) - return ff_mpeg2_non_linear_qscale[qscale]; - else - return qscale << 1; -} - - /* motion type (for MPEG-2) */ #define MT_FIELD 1 #define MT_FRAME 2 @@ -751,7 +741,7 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) s->interlaced_dct = get_bits1(&s->gb); if (IS_QUANT(mb_type)) - s->qscale = get_qscale(s); + s->qscale = mpeg_get_qscale(s); if (s->concealment_motion_vectors) { /* just parse them */ @@ -819,7 +809,7 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) } if (IS_QUANT(mb_type)) - s->qscale = get_qscale(s); + s->qscale = mpeg_get_qscale(s); s->last_mv[0][0][0] = 0; s->last_mv[0][0][1] = 0; @@ -840,7 +830,7 @@ static int mpeg_decode_mb(MpegEncContext *s, int16_t block[12][64]) } if (IS_QUANT(mb_type)) - s->qscale = get_qscale(s); + s->qscale = mpeg_get_qscale(s); /* motion vectors */ s->mv_dir = (mb_type >> 13) & 3; @@ -1131,12 +1121,12 @@ static void quant_matrix_rebuild(uint16_t *matrix, const uint8_t *old_perm, } static const enum AVPixelFormat mpeg1_hwaccel_pixfmt_list_420[] = { +#if CONFIG_MPEG1_NVDEC_HWACCEL + AV_PIX_FMT_CUDA, +#endif #if CONFIG_MPEG1_XVMC_HWACCEL AV_PIX_FMT_XVMC, #endif -#if CONFIG_MPEG1_VDPAU_DECODER && FF_API_VDPAU - AV_PIX_FMT_VDPAU_MPEG1, -#endif #if CONFIG_MPEG1_VDPAU_HWACCEL AV_PIX_FMT_VDPAU, #endif @@ -1145,12 +1135,12 @@ static const enum AVPixelFormat mpeg1_hwaccel_pixfmt_list_420[] = { }; static const enum AVPixelFormat mpeg2_hwaccel_pixfmt_list_420[] = { +#if CONFIG_MPEG2_NVDEC_HWACCEL + AV_PIX_FMT_CUDA, +#endif #if CONFIG_MPEG2_XVMC_HWACCEL AV_PIX_FMT_XVMC, #endif -#if CONFIG_MPEG_VDPAU_DECODER && FF_API_VDPAU - AV_PIX_FMT_VDPAU_MPEG2, -#endif #if CONFIG_MPEG2_VDPAU_HWACCEL AV_PIX_FMT_VDPAU, #endif @@ -1181,12 +1171,6 @@ static const enum AVPixelFormat mpeg12_pixfmt_list_444[] = { AV_PIX_FMT_NONE }; -#if FF_API_VDPAU -static inline int uses_vdpau(AVCodecContext *avctx) { - return avctx->pix_fmt == AV_PIX_FMT_VDPAU_MPEG1 || avctx->pix_fmt == AV_PIX_FMT_VDPAU_MPEG2; -} -#endif - static enum AVPixelFormat mpeg_get_pixelformat(AVCodecContext *avctx) { Mpeg1Context *s1 = avctx->priv_data; @@ -1211,24 +1195,15 @@ static enum AVPixelFormat mpeg_get_pixelformat(AVCodecContext *avctx) static void setup_hwaccel_for_pixfmt(AVCodecContext *avctx) { // until then pix_fmt may be changed right after codec init - if (avctx->hwaccel -#if FF_API_VDPAU - || uses_vdpau(avctx) -#endif - ) + if (avctx->hwaccel) if (avctx->idct_algo == FF_IDCT_AUTO) - avctx->idct_algo = FF_IDCT_SIMPLE; + avctx->idct_algo = FF_IDCT_NONE; if (avctx->hwaccel && avctx->pix_fmt == AV_PIX_FMT_XVMC) { Mpeg1Context *s1 = avctx->priv_data; MpegEncContext *s = &s1->mpeg_enc_ctx; s->pack_pblocks = 1; -#if FF_API_XVMC -FF_DISABLE_DEPRECATION_WARNINGS - avctx->xvmc_acceleration = 2; -FF_ENABLE_DEPRECATION_WARNINGS -#endif /* FF_API_XVMC */ } } @@ -1743,7 +1718,7 @@ static int mpeg_decode_slice(MpegEncContext *s, int mb_y, ff_mpeg1_clean_buffers(s); s->interlaced_dct = 0; - s->qscale = get_qscale(s); + s->qscale = mpeg_get_qscale(s); if (s->qscale == 0) { av_log(s->avctx, AV_LOG_ERROR, "qscale == 0\n"); @@ -1984,6 +1959,8 @@ static int mpeg_decode_slice(MpegEncContext *s, int mb_y, s->mv[0][0][1] = s->last_mv[0][0][1]; s->mv[1][0][0] = s->last_mv[1][0][0]; s->mv[1][0][1] = s->last_mv[1][0][1]; + s->field_select[0][0] = (s->picture_structure - 1) & 1; + s->field_select[1][0] = (s->picture_structure - 1) & 1; } } } @@ -2257,8 +2234,52 @@ static int mpeg_decode_a53_cc(AVCodecContext *avctx, av_freep(&s1->a53_caption); s1->a53_caption_size = cc_count * 3; s1->a53_caption = av_malloc(s1->a53_caption_size); - if (s1->a53_caption) + if (!s1->a53_caption) { + s1->a53_caption_size = 0; + } else { memcpy(s1->a53_caption, p + 7, s1->a53_caption_size); + } + avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; + } + return 1; + } else if (buf_size >= 2 && + p[0] == 0x03 && (p[1]&0x7f) == 0x01) { + /* extract SCTE-20 CC data */ + GetBitContext gb; + int cc_count = 0; + int i; + + init_get_bits(&gb, p + 2, buf_size - 2); + cc_count = get_bits(&gb, 5); + if (cc_count > 0) { + av_freep(&s1->a53_caption); + s1->a53_caption_size = cc_count * 3; + s1->a53_caption = av_mallocz(s1->a53_caption_size); + if (!s1->a53_caption) { + s1->a53_caption_size = 0; + } else { + uint8_t field, cc1, cc2; + uint8_t *cap = s1->a53_caption; + for (i = 0; i < cc_count && get_bits_left(&gb) >= 26; i++) { + skip_bits(&gb, 2); // priority + field = get_bits(&gb, 2); + skip_bits(&gb, 5); // line_offset + cc1 = get_bits(&gb, 8); + cc2 = get_bits(&gb, 8); + skip_bits(&gb, 1); // marker + + if (!field) { // forbidden + cap[0] = cap[1] = cap[2] = 0x00; + } else { + field = (field == 2 ? 1 : 0); + if (!s1->mpeg_enc_ctx.top_field_first) field = !field; + cap[0] = 0x04 | field; + cap[1] = ff_reverse[cc1]; + cap[2] = ff_reverse[cc2]; + } + cap += 3; + } + } avctx->properties |= FF_CODEC_PROPERTY_CLOSED_CAPTIONS; } return 1; @@ -2300,7 +2321,9 @@ static int mpeg_decode_a53_cc(AVCodecContext *avctx, av_freep(&s1->a53_caption); s1->a53_caption_size = cc_count * 6; s1->a53_caption = av_malloc(s1->a53_caption_size); - if (s1->a53_caption) { + if (!s1->a53_caption) { + s1->a53_caption_size = 0; + } else { uint8_t field1 = !!(p[4] & 0x80); uint8_t *cap = s1->a53_caption; p += 5; @@ -2356,11 +2379,6 @@ static void mpeg_decode_user_data(AVCodecContext *avctx, if (flags & 0x40) { if (buf_end - p < 1) return; -#if FF_API_AFD -FF_DISABLE_DEPRECATION_WARNINGS - avctx->dtg_active_format = p[0] & 0x0f; -FF_ENABLE_DEPRECATION_WARNINGS -#endif /* FF_API_AFD */ s1->has_afd = 1; s1->afd = p[0] & 0x0f; } @@ -2460,12 +2478,6 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, s2->er.error_count += s2->thread_context[i]->er.error_count; } -#if FF_API_VDPAU - if ((CONFIG_MPEG_VDPAU_DECODER || CONFIG_MPEG1_VDPAU_DECODER) - && uses_vdpau(avctx)) - ff_vdpau_mpeg_picture_complete(s2, buf, buf_size, s->slice_count); -#endif - ret = slice_end(avctx, picture); if (ret < 0) return ret; @@ -2717,13 +2729,6 @@ static int decode_chunks(AVCodecContext *avctx, AVFrame *picture, return AVERROR_INVALIDDATA; } -#if FF_API_VDPAU - if (uses_vdpau(avctx)) { - s->slice_count++; - break; - } -#endif - if (HAVE_THREADS && (avctx->active_thread_type & FF_THREAD_SLICE) && !avctx->hwaccel) { @@ -2878,7 +2883,22 @@ AVCodec ff_mpeg1video_decoder = { .caps_internal = FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM, .flush = flush, .max_lowres = 3, - .update_thread_context = ONLY_IF_THREADS_ENABLED(mpeg_decode_update_thread_context) + .update_thread_context = ONLY_IF_THREADS_ENABLED(mpeg_decode_update_thread_context), + .hw_configs = (const AVCodecHWConfigInternal*[]) { +#if CONFIG_MPEG1_NVDEC_HWACCEL + HWACCEL_NVDEC(mpeg1), +#endif +#if CONFIG_MPEG1_VDPAU_HWACCEL + HWACCEL_VDPAU(mpeg1), +#endif +#if CONFIG_MPEG1_VIDEOTOOLBOX_HWACCEL + HWACCEL_VIDEOTOOLBOX(mpeg1), +#endif +#if CONFIG_MPEG1_XVMC_HWACCEL + HWACCEL_XVMC(mpeg1), +#endif + NULL + }, }; AVCodec ff_mpeg2video_decoder = { @@ -2897,6 +2917,33 @@ AVCodec ff_mpeg2video_decoder = { .flush = flush, .max_lowres = 3, .profiles = NULL_IF_CONFIG_SMALL(ff_mpeg2_video_profiles), + .hw_configs = (const AVCodecHWConfigInternal*[]) { +#if CONFIG_MPEG2_DXVA2_HWACCEL + HWACCEL_DXVA2(mpeg2), +#endif +#if CONFIG_MPEG2_D3D11VA_HWACCEL + HWACCEL_D3D11VA(mpeg2), +#endif +#if CONFIG_MPEG2_D3D11VA2_HWACCEL + HWACCEL_D3D11VA2(mpeg2), +#endif +#if CONFIG_MPEG2_NVDEC_HWACCEL + HWACCEL_NVDEC(mpeg2), +#endif +#if CONFIG_MPEG2_VAAPI_HWACCEL + HWACCEL_VAAPI(mpeg2), +#endif +#if CONFIG_MPEG2_VDPAU_HWACCEL + HWACCEL_VDPAU(mpeg2), +#endif +#if CONFIG_MPEG2_VIDEOTOOLBOX_HWACCEL + HWACCEL_VIDEOTOOLBOX(mpeg2), +#endif +#if CONFIG_MPEG2_XVMC_HWACCEL + HWACCEL_XVMC(mpeg2), +#endif + NULL + }, }; //legacy decoder @@ -2914,73 +2961,3 @@ AVCodec ff_mpegvideo_decoder = { .flush = flush, .max_lowres = 3, }; - -#if FF_API_XVMC -#if CONFIG_MPEG_XVMC_DECODER -FF_DISABLE_DEPRECATION_WARNINGS -static av_cold int mpeg_mc_decode_init(AVCodecContext *avctx) -{ - if (avctx->active_thread_type & FF_THREAD_SLICE) - return -1; - if (!(avctx->slice_flags & SLICE_FLAG_CODED_ORDER)) - return -1; - if (!(avctx->slice_flags & SLICE_FLAG_ALLOW_FIELD)) { - ff_dlog(avctx, "mpeg12.c: XvMC decoder will work better if SLICE_FLAG_ALLOW_FIELD is set\n"); - } - mpeg_decode_init(avctx); - - avctx->pix_fmt = AV_PIX_FMT_XVMC_MPEG2_IDCT; - avctx->xvmc_acceleration = 2; // 2 - the blocks are packed! - - return 0; -} - -AVCodec ff_mpeg_xvmc_decoder = { - .name = "mpegvideo_xvmc", - .long_name = NULL_IF_CONFIG_SMALL("MPEG-1/2 video XvMC (X-Video Motion Compensation)"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_MPEG2VIDEO_XVMC, - .priv_data_size = sizeof(Mpeg1Context), - .init = mpeg_mc_decode_init, - .close = mpeg_decode_end, - .decode = mpeg_decode_frame, - .capabilities = AV_CODEC_CAP_DRAW_HORIZ_BAND | AV_CODEC_CAP_DR1 | - AV_CODEC_CAP_TRUNCATED | CODEC_CAP_HWACCEL | - AV_CODEC_CAP_DELAY, - .flush = flush, -}; -FF_ENABLE_DEPRECATION_WARNINGS -#endif -#endif /* FF_API_XVMC */ - -#if CONFIG_MPEG_VDPAU_DECODER && FF_API_VDPAU -AVCodec ff_mpeg_vdpau_decoder = { - .name = "mpegvideo_vdpau", - .long_name = NULL_IF_CONFIG_SMALL("MPEG-1/2 video (VDPAU acceleration)"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_MPEG2VIDEO, - .priv_data_size = sizeof(Mpeg1Context), - .init = mpeg_decode_init, - .close = mpeg_decode_end, - .decode = mpeg_decode_frame, - .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_TRUNCATED | - AV_CODEC_CAP_HWACCEL_VDPAU | AV_CODEC_CAP_DELAY, - .flush = flush, -}; -#endif - -#if CONFIG_MPEG1_VDPAU_DECODER && FF_API_VDPAU -AVCodec ff_mpeg1_vdpau_decoder = { - .name = "mpeg1video_vdpau", - .long_name = NULL_IF_CONFIG_SMALL("MPEG-1 video (VDPAU acceleration)"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_MPEG1VIDEO, - .priv_data_size = sizeof(Mpeg1Context), - .init = mpeg_decode_init, - .close = mpeg_decode_end, - .decode = mpeg_decode_frame, - .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_TRUNCATED | - AV_CODEC_CAP_HWACCEL_VDPAU | AV_CODEC_CAP_DELAY, - .flush = flush, -}; -#endif diff --git a/libavcodec/mpeg12enc.c b/libavcodec/mpeg12enc.c index f45598a087022..d0b458e34bdb4 100644 --- a/libavcodec/mpeg12enc.c +++ b/libavcodec/mpeg12enc.c @@ -348,12 +348,13 @@ static void mpeg1_encode_sequence_header(MpegEncContext *s) height != s->height || s->avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || s->avctx->color_trc != AVCOL_TRC_UNSPECIFIED || - s->avctx->colorspace != AVCOL_SPC_UNSPECIFIED); + s->avctx->colorspace != AVCOL_SPC_UNSPECIFIED || + s->video_format != VIDEO_FORMAT_UNSPECIFIED); if (s->seq_disp_ext == 1 || (s->seq_disp_ext == -1 && use_seq_disp_ext)) { put_header(s, EXT_START_CODE); put_bits(&s->pb, 4, 2); // sequence display extension - put_bits(&s->pb, 3, 0); // video_format: 0 is components + put_bits(&s->pb, 3, s->video_format); // video_format put_bits(&s->pb, 1, 1); // colour_description put_bits(&s->pb, 8, s->avctx->color_primaries); // colour_primaries put_bits(&s->pb, 8, s->avctx->color_trc); // transfer_characteristics @@ -1125,6 +1126,13 @@ static const AVOption mpeg2_options[] = { { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, VE, "seq_disp_ext" }, { "never", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, VE, "seq_disp_ext" }, { "always", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, VE, "seq_disp_ext" }, + { "video_format", "Video_format in the sequence_display_extension indicating the source of the video.", OFFSET(video_format), AV_OPT_TYPE_INT, { .i64 = VIDEO_FORMAT_UNSPECIFIED }, 0, 7, VE, "video_format" }, + { "component", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = VIDEO_FORMAT_COMPONENT }, 0, 0, VE, "video_format" }, + { "pal", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = VIDEO_FORMAT_PAL }, 0, 0, VE, "video_format" }, + { "ntsc", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = VIDEO_FORMAT_NTSC }, 0, 0, VE, "video_format" }, + { "secam", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = VIDEO_FORMAT_SECAM }, 0, 0, VE, "video_format" }, + { "mac", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = VIDEO_FORMAT_MAC }, 0, 0, VE, "video_format" }, + { "unspecified", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = VIDEO_FORMAT_UNSPECIFIED}, 0, 0, VE, "video_format" }, FF_MPV_COMMON_OPTS { NULL }, }; diff --git a/libavcodec/mpeg12framerate.c b/libavcodec/mpeg12framerate.c index 094cd180a5f6e..ab3d351173bc1 100644 --- a/libavcodec/mpeg12framerate.c +++ b/libavcodec/mpeg12framerate.c @@ -18,6 +18,9 @@ #include "libavutil/rational.h" +#include "mpeg12.h" +#include "mpeg12data.h" + const AVRational ff_mpeg12_frame_rate_tab[16] = { { 0, 0}, {24000, 1001}, @@ -37,3 +40,64 @@ const AVRational ff_mpeg12_frame_rate_tab[16] = { { 15, 1}, { 0, 0}, }; + +void ff_mpeg12_find_best_frame_rate(AVRational frame_rate, + int *code, int *ext_n, int *ext_d, + int nonstandard) +{ + int mpeg2 = ext_n && ext_d; + int max_code = nonstandard ? 12 : 8; + int c, n, d, best_c, best_n, best_d; + AVRational best_error = { INT_MAX, 1 }; + + // Default to NTSC if the inputs make no sense. + best_c = 4; + best_n = best_d = 1; + + for (c = 1; c <= max_code; c++) { + if (av_cmp_q(frame_rate, ff_mpeg12_frame_rate_tab[c]) == 0) { + best_c = c; + goto found; + } + } + + for (c = 1; c <= max_code; c++) { + for (n = 1; n <= (mpeg2 ? 4 : 1); n++) { + for (d = 1; d <= (mpeg2 ? 32 : 1); d++) { + AVRational test, error; + int cmp; + + test = av_mul_q(ff_mpeg12_frame_rate_tab[c], + (AVRational) { n, d }); + + cmp = av_cmp_q(test, frame_rate); + if (cmp == 0) { + best_c = c; + best_n = n; + best_d = d; + goto found; + } + + if (cmp < 0) + error = av_div_q(frame_rate, test); + else + error = av_div_q(test, frame_rate); + + cmp = av_cmp_q(error, best_error); + if (cmp < 0 || (cmp == 0 && n == 1 && d == 1)) { + best_c = c; + best_n = n; + best_d = d; + best_error = error; + } + } + } + } + +found: + *code = best_c; + if (mpeg2) { + *ext_n = best_n - 1; + *ext_d = best_d - 1; + } +} diff --git a/libavcodec/mpeg2_metadata_bsf.c b/libavcodec/mpeg2_metadata_bsf.c new file mode 100644 index 0000000000000..e787cb37824ee --- /dev/null +++ b/libavcodec/mpeg2_metadata_bsf.c @@ -0,0 +1,314 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avstring.h" +#include "libavutil/common.h" +#include "libavutil/opt.h" + +#include "bsf.h" +#include "cbs.h" +#include "cbs_mpeg2.h" +#include "mpeg12.h" + +typedef struct MPEG2MetadataContext { + const AVClass *class; + + CodedBitstreamContext *cbc; + CodedBitstreamFragment fragment; + + MPEG2RawExtensionData sequence_display_extension; + + AVRational display_aspect_ratio; + + AVRational frame_rate; + + int video_format; + int colour_primaries; + int transfer_characteristics; + int matrix_coefficients; + + int mpeg1_warned; +} MPEG2MetadataContext; + + +static int mpeg2_metadata_update_fragment(AVBSFContext *bsf, + CodedBitstreamFragment *frag) +{ + MPEG2MetadataContext *ctx = bsf->priv_data; + MPEG2RawSequenceHeader *sh = NULL; + MPEG2RawSequenceExtension *se = NULL; + MPEG2RawSequenceDisplayExtension *sde = NULL; + int i, se_pos, add_sde = 0; + + for (i = 0; i < frag->nb_units; i++) { + if (frag->units[i].type == MPEG2_START_SEQUENCE_HEADER) { + sh = frag->units[i].content; + } else if (frag->units[i].type == MPEG2_START_EXTENSION) { + MPEG2RawExtensionData *ext = frag->units[i].content; + if (ext->extension_start_code_identifier == + MPEG2_EXTENSION_SEQUENCE) { + se = &ext->data.sequence; + se_pos = i; + } else if (ext->extension_start_code_identifier == + MPEG2_EXTENSION_SEQUENCE_DISPLAY) { + sde = &ext->data.sequence_display; + } + } + } + + if (!sh || !se) { + // No sequence header and sequence extension: not an MPEG-2 video + // sequence. + if (sh && !ctx->mpeg1_warned) { + av_log(bsf, AV_LOG_WARNING, "Stream contains a sequence " + "header but not a sequence extension: maybe it's " + "actually MPEG-1?\n"); + ctx->mpeg1_warned = 1; + } + return 0; + } + + if (ctx->display_aspect_ratio.num && ctx->display_aspect_ratio.den) { + int num, den; + + av_reduce(&num, &den, ctx->display_aspect_ratio.num, + ctx->display_aspect_ratio.den, 65535); + + if (num == 4 && den == 3) + sh->aspect_ratio_information = 2; + else if (num == 16 && den == 9) + sh->aspect_ratio_information = 3; + else if (num == 221 && den == 100) + sh->aspect_ratio_information = 4; + else + sh->aspect_ratio_information = 1; + } + + if (ctx->frame_rate.num && ctx->frame_rate.den) { + int code, ext_n, ext_d; + + ff_mpeg12_find_best_frame_rate(ctx->frame_rate, + &code, &ext_n, &ext_d, 0); + + sh->frame_rate_code = code; + se->frame_rate_extension_n = ext_n; + se->frame_rate_extension_d = ext_d; + } + + if (ctx->video_format >= 0 || + ctx->colour_primaries >= 0 || + ctx->transfer_characteristics >= 0 || + ctx->matrix_coefficients >= 0) { + if (!sde) { + add_sde = 1; + ctx->sequence_display_extension.extension_start_code = + MPEG2_START_EXTENSION; + ctx->sequence_display_extension.extension_start_code_identifier = + MPEG2_EXTENSION_SEQUENCE_DISPLAY; + sde = &ctx->sequence_display_extension.data.sequence_display; + + *sde = (MPEG2RawSequenceDisplayExtension) { + .video_format = 5, + + .colour_description = 0, + .colour_primaries = 2, + .transfer_characteristics = 2, + .matrix_coefficients = 2, + + .display_horizontal_size = + se->horizontal_size_extension << 12 | sh->horizontal_size_value, + .display_vertical_size = + se->vertical_size_extension << 12 | sh->vertical_size_value, + }; + } + + if (ctx->video_format >= 0) + sde->video_format = ctx->video_format; + + if (ctx->colour_primaries >= 0 || + ctx->transfer_characteristics >= 0 || + ctx->matrix_coefficients >= 0) { + sde->colour_description = 1; + + if (ctx->colour_primaries >= 0) + sde->colour_primaries = ctx->colour_primaries; + else if (add_sde) + sde->colour_primaries = 2; + + if (ctx->transfer_characteristics >= 0) + sde->transfer_characteristics = ctx->transfer_characteristics; + else if (add_sde) + sde->transfer_characteristics = 2; + + if (ctx->matrix_coefficients >= 0) + sde->matrix_coefficients = ctx->matrix_coefficients; + else if (add_sde) + sde->matrix_coefficients = 2; + } + } + + if (add_sde) { + int err; + + err = ff_cbs_insert_unit_content(ctx->cbc, frag, se_pos + 1, + MPEG2_START_EXTENSION, + &ctx->sequence_display_extension, + NULL); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to insert new sequence " + "display extension.\n"); + return err; + } + } + + return 0; +} + +static int mpeg2_metadata_filter(AVBSFContext *bsf, AVPacket *out) +{ + MPEG2MetadataContext *ctx = bsf->priv_data; + AVPacket *in = NULL; + CodedBitstreamFragment *frag = &ctx->fragment; + int err; + + err = ff_bsf_get_packet(bsf, &in); + if (err < 0) + return err; + + err = ff_cbs_read_packet(ctx->cbc, frag, in); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read packet.\n"); + goto fail; + } + + err = mpeg2_metadata_update_fragment(bsf, frag); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to update frame fragment.\n"); + goto fail; + } + + err = ff_cbs_write_packet(ctx->cbc, out, frag); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to write packet.\n"); + goto fail; + } + + err = av_packet_copy_props(out, in); + if (err < 0) + goto fail; + + err = 0; +fail: + ff_cbs_fragment_uninit(ctx->cbc, frag); + + if (err < 0) + av_packet_unref(out); + av_packet_free(&in); + + return err; +} + +static int mpeg2_metadata_init(AVBSFContext *bsf) +{ + MPEG2MetadataContext *ctx = bsf->priv_data; + CodedBitstreamFragment *frag = &ctx->fragment; + int err; + + err = ff_cbs_init(&ctx->cbc, AV_CODEC_ID_MPEG2VIDEO, bsf); + if (err < 0) + return err; + + if (bsf->par_in->extradata) { + err = ff_cbs_read_extradata(ctx->cbc, frag, bsf->par_in); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read extradata.\n"); + goto fail; + } + + err = mpeg2_metadata_update_fragment(bsf, frag); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to update metadata fragment.\n"); + goto fail; + } + + err = ff_cbs_write_extradata(ctx->cbc, bsf->par_out, frag); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to write extradata.\n"); + goto fail; + } + } + + err = 0; +fail: + ff_cbs_fragment_uninit(ctx->cbc, frag); + return err; +} + +static void mpeg2_metadata_close(AVBSFContext *bsf) +{ + MPEG2MetadataContext *ctx = bsf->priv_data; + ff_cbs_close(&ctx->cbc); +} + +#define OFFSET(x) offsetof(MPEG2MetadataContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM) +static const AVOption mpeg2_metadata_options[] = { + { "display_aspect_ratio", "Set display aspect ratio (table 6-3)", + OFFSET(display_aspect_ratio), AV_OPT_TYPE_RATIONAL, + { .dbl = 0.0 }, 0, 65535, FLAGS }, + + { "frame_rate", "Set frame rate", + OFFSET(frame_rate), AV_OPT_TYPE_RATIONAL, + { .dbl = 0.0 }, 0, UINT_MAX, FLAGS }, + + { "video_format", "Set video format (table 6-6)", + OFFSET(video_format), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 7, FLAGS }, + { "colour_primaries", "Set colour primaries (table 6-7)", + OFFSET(colour_primaries), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255, FLAGS }, + { "transfer_characteristics", "Set transfer characteristics (table 6-8)", + OFFSET(transfer_characteristics), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255, FLAGS }, + { "matrix_coefficients", "Set matrix coefficients (table 6-9)", + OFFSET(matrix_coefficients), AV_OPT_TYPE_INT, + { .i64 = -1 }, -1, 255, FLAGS }, + + { NULL } +}; + +static const AVClass mpeg2_metadata_class = { + .class_name = "mpeg2_metadata_bsf", + .item_name = av_default_item_name, + .option = mpeg2_metadata_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const enum AVCodecID mpeg2_metadata_codec_ids[] = { + AV_CODEC_ID_MPEG2VIDEO, AV_CODEC_ID_NONE, +}; + +const AVBitStreamFilter ff_mpeg2_metadata_bsf = { + .name = "mpeg2_metadata", + .priv_data_size = sizeof(MPEG2MetadataContext), + .priv_class = &mpeg2_metadata_class, + .init = &mpeg2_metadata_init, + .close = &mpeg2_metadata_close, + .filter = &mpeg2_metadata_filter, + .codec_ids = mpeg2_metadata_codec_ids, +}; diff --git a/libavcodec/mpeg4_unpack_bframes_bsf.c b/libavcodec/mpeg4_unpack_bframes_bsf.c index e227f58ec6df6..3a0ba105f532e 100644 --- a/libavcodec/mpeg4_unpack_bframes_bsf.c +++ b/libavcodec/mpeg4_unpack_bframes_bsf.c @@ -108,8 +108,8 @@ static int mpeg4_unpack_bframes_filter(AVBSFContext *ctx, AVPacket *out) s->b_frame_buf = create_new_buffer(in->data + pos_vop2, s->b_frame_buf_size); if (!s->b_frame_buf) { s->b_frame_buf_size = 0; - av_packet_free(&in); - return AVERROR(ENOMEM); + ret = AVERROR(ENOMEM); + goto fail; } } @@ -122,14 +122,12 @@ static int mpeg4_unpack_bframes_filter(AVBSFContext *ctx, AVPacket *out) /* use frame from BSFContext */ ret = av_packet_copy_props(out, in); if (ret < 0) { - av_packet_free(&in); - return ret; + goto fail; } ret = av_packet_from_data(out, s->b_frame_buf, s->b_frame_buf_size); if (ret < 0) { - av_packet_free(&in); - return ret; + goto fail; } if (in->size <= MAX_NVOP_SIZE) { /* N-VOP */ @@ -142,9 +140,8 @@ static int mpeg4_unpack_bframes_filter(AVBSFContext *ctx, AVPacket *out) s->b_frame_buf = create_new_buffer(in->data, in->size); if (!s->b_frame_buf) { s->b_frame_buf_size = 0; - av_packet_unref(out); - av_packet_free(&in); - return AVERROR(ENOMEM); + ret = AVERROR(ENOMEM); + goto fail; } } } else if (nb_vop >= 2) { @@ -152,6 +149,9 @@ static int mpeg4_unpack_bframes_filter(AVBSFContext *ctx, AVPacket *out) av_packet_move_ref(out, in); out->size = pos_vop2; } else if (pos_p >= 0) { + ret = av_packet_make_writable(in); + if (ret < 0) + goto fail; av_log(ctx, AV_LOG_DEBUG, "Updating DivX userdata (remove trailing 'p').\n"); av_packet_move_ref(out, in); /* remove 'p' (packed) from the end of the (DivX) userdata string */ @@ -161,9 +161,12 @@ static int mpeg4_unpack_bframes_filter(AVBSFContext *ctx, AVPacket *out) av_packet_move_ref(out, in); } +fail: + if (ret < 0) + av_packet_unref(out); av_packet_free(&in); - return 0; + return ret; } static int mpeg4_unpack_bframes_init(AVBSFContext *ctx) diff --git a/libavcodec/mpeg4audio.c b/libavcodec/mpeg4audio.c index b6bb323440073..219714752f952 100644 --- a/libavcodec/mpeg4audio.c +++ b/libavcodec/mpeg4audio.c @@ -167,43 +167,3 @@ int avpriv_mpeg4audio_get_config(MPEG4AudioConfig *c, const uint8_t *buf, return ff_mpeg4audio_get_config_gb(c, &gb, sync_extension); } - -static av_always_inline unsigned int copy_bits(PutBitContext *pb, - GetBitContext *gb, - int bits) -{ - unsigned int el = get_bits(gb, bits); - put_bits(pb, bits, el); - return el; -} - -int avpriv_copy_pce_data(PutBitContext *pb, GetBitContext *gb) -{ - int five_bit_ch, four_bit_ch, comment_size, bits; - int offset = put_bits_count(pb); - - copy_bits(pb, gb, 10); //Tag, Object Type, Frequency - five_bit_ch = copy_bits(pb, gb, 4); //Front - five_bit_ch += copy_bits(pb, gb, 4); //Side - five_bit_ch += copy_bits(pb, gb, 4); //Back - four_bit_ch = copy_bits(pb, gb, 2); //LFE - four_bit_ch += copy_bits(pb, gb, 3); //Data - five_bit_ch += copy_bits(pb, gb, 4); //Coupling - if (copy_bits(pb, gb, 1)) //Mono Mixdown - copy_bits(pb, gb, 4); - if (copy_bits(pb, gb, 1)) //Stereo Mixdown - copy_bits(pb, gb, 4); - if (copy_bits(pb, gb, 1)) //Matrix Mixdown - copy_bits(pb, gb, 3); - for (bits = five_bit_ch*5+four_bit_ch*4; bits > 16; bits -= 16) - copy_bits(pb, gb, 16); - if (bits) - copy_bits(pb, gb, bits); - avpriv_align_put_bits(pb); - align_get_bits(gb); - comment_size = copy_bits(pb, gb, 8); - for (; comment_size > 0; comment_size--) - copy_bits(pb, gb, 8); - - return put_bits_count(pb) - offset; -} diff --git a/libavcodec/mpeg4audio.h b/libavcodec/mpeg4audio.h index 8fd32f96b3c94..b9cea8af17f9e 100644 --- a/libavcodec/mpeg4audio.h +++ b/libavcodec/mpeg4audio.h @@ -23,7 +23,11 @@ #define AVCODEC_MPEG4AUDIO_H #include + +#include "libavutil/attributes.h" + #include "get_bits.h" +#include "internal.h" #include "put_bits.h" typedef struct MPEG4AudioConfig { @@ -41,7 +45,7 @@ typedef struct MPEG4AudioConfig { int frame_length_short; } MPEG4AudioConfig; -extern av_export const int avpriv_mpeg4audio_sample_rates[16]; +extern av_export_avcodec const int avpriv_mpeg4audio_sample_rates[16]; extern const uint8_t ff_mpeg4audio_channels[8]; /** @@ -115,6 +119,44 @@ enum AudioObjectType { #define MAX_PCE_SIZE 320 /// 16; bits -= 16) + ff_pce_copy_bits(pb, gb, 16); + if (bits) + ff_pce_copy_bits(pb, gb, bits); + avpriv_align_put_bits(pb); + align_get_bits(gb); + comment_size = ff_pce_copy_bits(pb, gb, 8); + for (; comment_size > 0; comment_size--) + ff_pce_copy_bits(pb, gb, 8); + + return put_bits_count(pb) - offset; +} #endif /* AVCODEC_MPEG4AUDIO_H */ diff --git a/libavcodec/mpeg4data.h b/libavcodec/mpeg4data.h index b7c3faba0d6dc..4756e9ea1d2b4 100644 --- a/libavcodec/mpeg4data.h +++ b/libavcodec/mpeg4data.h @@ -373,4 +373,120 @@ const uint8_t ff_mpeg4_dc_threshold[8]={ 99, 13, 15, 17, 19, 21, 23, 0 }; +/* Note these are different in studio mode */ +const uint16_t ff_mpeg4_studio_dc_luma[19][2]={ + {0x0e, 6}, {0x06, 5}, {0x00, 4}, {0x02, 4}, + {0x07, 3}, {0x05, 3}, {0x03, 3}, {0x02, 3}, + {0x04, 3}, {0x06, 3}, {0x01, 4}, {0x1e, 7}, + {0x3e, 8}, {0x7e, 9}, {0xfe, 10}, {0x1fe, 11}, + {0x3fe, 12}, {0x7fe, 13}, {0x7ff, 13} +}; + +const uint16_t ff_mpeg4_studio_dc_chroma[19][2]={ + {0x00, 4}, {0x02, 4}, {0x07, 3}, {0x05, 3}, + {0x03, 3}, {0x02, 3}, {0x04, 3}, {0x06, 3}, + {0x01, 4}, {0x06, 5}, {0x0e, 6}, {0x1e, 7}, + {0x3e, 8}, {0x7e, 9}, {0xfe, 10}, {0x1fe, 11}, + {0x3fe, 12}, {0x7fe, 13}, {0x7ff, 13} +}; + +const uint16_t ff_mpeg4_studio_intra[12][22][2]={ + { + {0x05, 4}, {0x04, 4}, {0x05, 7}, {0x09, 9}, + {0x21, 11}, {0x41, 12}, {0x81, 13}, {0x03, 4}, + {0x03, 5}, {0x05, 6}, {0x04, 7}, {0x03, 7}, + {0x05, 8}, {0x03, 2}, {0x05, 3}, {0x04, 3}, + {0x03, 3}, {0x02, 4}, {0x04, 6}, {0x03, 6}, + {0x11, 10}, {0x80, 13} + }, + { + {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, + {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, + {0x00, 0}, {0x00, 0}, {0x00, 0}, {0x00, 0}, + {0x00, 0}, {0x00, 0}, {0x01, 1}, {0x01, 2}, + {0x01, 3}, {0x01, 4}, {0x01, 5}, {0x03, 7}, + {0x05, 8}, {0x04, 8} + }, + { + {0x05, 3}, {0x03, 5}, {0x02, 5}, {0x03, 7}, + {0x09, 9}, {0x103, 14}, {0x102, 14}, {0x04, 3}, + {0x03, 3}, {0x03, 4}, {0x02, 4}, {0x03, 6}, + {0x11, 10}, {0x03, 2}, {0x02, 3}, {0x02, 6}, + {0x05, 8}, {0x21, 11}, {0x83, 13}, {0x101, 14}, + {0x201, 15}, {0x82, 13} + }, + { + {0x05, 5}, {0x05, 4}, {0x04, 5}, {0x03, 6}, + {0x09, 9}, {0x83, 13}, {0x82, 13}, {0x03, 3}, + {0x04, 4}, {0x03, 4}, {0x03, 5}, {0x05, 8}, + {0x81, 13}, {0x03, 2}, {0x02, 2}, {0x02, 5}, + {0x02, 6}, {0x03, 7}, {0x11, 10}, {0x43, 12}, + {0x80, 13}, {0x42, 12} + }, + { + {0x05, 7}, {0x03, 4}, {0x03, 5}, {0x04, 7}, + {0x09, 9}, {0x83, 13}, {0x101, 14}, {0x03, 3}, + {0x02, 4}, {0x05, 6}, {0x03, 7}, {0x11, 10}, + {0x201, 15}, {0x03, 2}, {0x02, 2}, {0x02, 3}, + {0x04, 6}, {0x03, 6}, {0x05, 8}, {0x21, 11}, + {0x82, 13}, {0x81, 13} + }, + { + {0x13, 10}, {0x03, 5}, {0x05, 7}, {0x12, 10}, + {0x43, 12}, {0x83, 13}, {0x82, 13}, {0x02, 5}, + {0x04, 7}, {0x05, 8}, {0x23, 11}, {0x81, 13}, + {0x101, 14}, {0x03, 2}, {0x02, 2}, {0x01, 2}, + {0x01, 3}, {0x03, 6}, {0x03, 7}, {0x22, 11}, + {0x201, 15}, {0x42, 12} + }, + { + {0x23, 11}, {0x01, 4}, {0x07, 8}, {0x13, 10}, + {0x22, 11}, {0x103, 14}, {0x102, 14}, {0x03, 6}, + {0x06, 8}, {0x12, 10}, {0x43, 12}, {0x101, 14}, + {0x201, 15}, {0x03, 3}, {0x02, 3}, {0x03, 2}, + {0x02, 2}, {0x01, 3}, {0x02, 6}, {0x05, 8}, + {0x42, 12}, {0x41, 12} + }, + { + {0x0b, 9}, {0x03, 5}, {0x07, 8}, {0x07, 7}, + {0x06, 7}, {0x23, 11}, {0x41, 12}, {0x05, 7}, + {0x06, 8}, {0x0a, 9}, {0x13, 10}, {0x22, 11}, + {0x40, 12}, {0x03, 4}, {0x02, 4}, {0x03, 2}, + {0x02, 2}, {0x01, 2}, {0x02, 5}, {0x04, 7}, + {0x12, 10}, {0x21, 11} + }, + { + {0x15, 10}, {0x03, 6}, {0x14, 10}, {0x23, 11}, + {0x07, 8}, {0x43, 12}, {0x81, 13}, {0x06, 8}, + {0x0b, 9}, {0x13, 10}, {0x12, 10}, {0x42, 12}, + {0x80, 13}, {0x01, 4}, {0x03, 3}, {0x02, 3}, + {0x03, 2}, {0x02, 2}, {0x01, 3}, {0x02, 6}, + {0x22, 11}, {0x41, 12} + }, + { + {0x43, 12}, {0x05, 6}, {0x07, 8}, {0x04, 6}, + {0x03, 6}, {0x13, 10}, {0x42, 12}, {0x05, 7}, + {0x04, 7}, {0x06, 8}, {0x12, 10}, {0x41, 12}, + {0x40, 12}, {0x03, 5}, {0x03, 4}, {0x03, 3}, + {0x02, 3}, {0x03, 2}, {0x02, 2}, {0x02, 4}, + {0x05, 8}, {0x11, 10} + }, + { + {0x83, 13}, {0x05, 7}, {0x07, 8}, {0x03, 4}, + {0x21, 11}, {0x82, 13}, {0x81, 13}, {0x04, 7}, + {0x06, 8}, {0x0b, 9}, {0x0a, 9}, {0x11, 10}, + {0x80, 13}, {0x03, 5}, {0x02, 5}, {0x02, 4}, + {0x03, 3}, {0x02, 3}, {0x03, 2}, {0x02, 2}, + {0x03, 6}, {0x09, 9} + }, + { + {0x13, 10}, {0x03, 5}, {0x03, 6}, {0x0d, 9}, + {0x0c, 9}, {0x21, 11}, {0x20, 11}, {0x02, 5}, + {0x02, 6}, {0x07, 8}, {0x0b, 9}, {0x12, 10}, + {0x11, 10}, {0x05, 3}, {0x04, 3}, {0x05, 4}, + {0x04, 4}, {0x03, 4}, {0x02, 4}, {0x03, 3}, + {0x03, 2}, {0x0a, 9} + } +}; + #endif /* AVCODEC_MPEG4DATA_H */ diff --git a/libavcodec/mpeg4video.h b/libavcodec/mpeg4video.h index 515b008ae45e7..f9747928877ec 100644 --- a/libavcodec/mpeg4video.h +++ b/libavcodec/mpeg4video.h @@ -43,6 +43,9 @@ #define ACE_VO_TYPE 12 #define ADV_SIMPLE_VO_TYPE 17 +#define VOT_VIDEO_ID 1 +#define VOT_STILL_TEXTURE_ID 2 + // aspect_ratio_info #define EXTENDED_PAR 15 @@ -58,6 +61,10 @@ #define GOP_STARTCODE 0x1B3 #define VISUAL_OBJ_STARTCODE 0x1B5 #define VOP_STARTCODE 0x1B6 +#define SLICE_STARTCODE 0x1B7 +#define EXT_STARTCODE 0x1B8 + +#define QUANT_MATRIX_EXT_ID 0x3 /* smaller packets likely don't contain a real frame */ #define MAX_NVOP_SIZE 19 @@ -105,8 +112,16 @@ typedef struct Mpeg4DecContext { int cplx_estimation_trash_i; int cplx_estimation_trash_p; int cplx_estimation_trash_b; + + VLC studio_intra_tab[12]; + VLC studio_luma_dc; + VLC studio_chroma_dc; + + int rgb; } Mpeg4DecContext; +static const uint8_t mpeg4_block_count[4] = {0, 6, 8, 12}; + /* dc encoding for MPEG-4 */ extern const uint8_t ff_mpeg4_DCtab_lum[13][2]; extern const uint8_t ff_mpeg4_DCtab_chrom[13][2]; @@ -134,6 +149,10 @@ extern const uint16_t ff_mpeg4_resync_prefix[8]; extern const uint8_t ff_mpeg4_dc_threshold[8]; +extern const uint16_t ff_mpeg4_studio_dc_luma[19][2]; +extern const uint16_t ff_mpeg4_studio_dc_chroma[19][2]; +extern const uint16_t ff_mpeg4_studio_intra[12][22][2]; + void ff_mpeg4_encode_mb(MpegEncContext *s, int16_t block[6][64], int motion_x, int motion_y); @@ -152,6 +171,7 @@ void ff_clean_mpeg4_qscales(MpegEncContext *s); int ff_mpeg4_decode_partitions(Mpeg4DecContext *ctx); int ff_mpeg4_get_video_packet_prefix_length(MpegEncContext *s); int ff_mpeg4_decode_video_packet_header(Mpeg4DecContext *ctx); +int ff_mpeg4_decode_studio_slice_header(Mpeg4DecContext *ctx); void ff_mpeg4_init_direct_mv(MpegEncContext *s); void ff_mpeg4videodec_static_init(void); int ff_mpeg4_workaround_bugs(AVCodecContext *avctx); @@ -236,12 +256,12 @@ static inline int ff_mpeg4_pred_dc(MpegEncContext *s, int n, int level, if (level < 0) { av_log(s->avctx, AV_LOG_ERROR, "dc<0 at %dx%d\n", s->mb_x, s->mb_y); - return -1; + return AVERROR_INVALIDDATA; } if (level > 2048 + scale) { av_log(s->avctx, AV_LOG_ERROR, "dc overflow at %dx%d\n", s->mb_x, s->mb_y); - return -1; + return AVERROR_INVALIDDATA; } } if (level < 0) diff --git a/libavcodec/mpeg4videodec.c b/libavcodec/mpeg4videodec.c index cd39131d55e92..32eb3d1ca8d67 100644 --- a/libavcodec/mpeg4videodec.c +++ b/libavcodec/mpeg4videodec.c @@ -25,6 +25,7 @@ #include "libavutil/internal.h" #include "libavutil/opt.h" #include "error_resilience.h" +#include "hwaccel.h" #include "idctdsp.h" #include "internal.h" #include "mpegutils.h" @@ -43,6 +44,7 @@ #define SPRITE_TRAJ_VLC_BITS 6 #define DC_VLC_BITS 9 #define MB_TYPE_B_VLC_BITS 4 +#define STUDIO_INTRA_BITS 9 static VLC dc_lum, dc_chrom; static VLC sprite_trajectory; @@ -189,6 +191,10 @@ static int mpeg4_decode_sprite_trajectory(Mpeg4DecContext *ctx, GetBitContext *g if (w <= 0 || h <= 0) return AVERROR_INVALIDDATA; + /* the decoder was not properly initialized and we cannot continue */ + if (sprite_trajectory.table == NULL) + return AVERROR_INVALIDDATA; + for (i = 0; i < ctx->num_sprite_warping_points; i++) { int length; int x = 0, y = 0; @@ -443,7 +449,7 @@ int ff_mpeg4_decode_video_packet_header(Mpeg4DecContext *ctx) /* is there enough space left for a video packet + header */ if (get_bits_count(&s->gb) > s->gb.size_in_bits - 20) - return -1; + return AVERROR_INVALIDDATA; for (len = 0; len < 32; len++) if (get_bits1(&s->gb)) @@ -451,7 +457,7 @@ int ff_mpeg4_decode_video_packet_header(Mpeg4DecContext *ctx) if (len != ff_mpeg4_get_video_packet_prefix_length(s)) { av_log(s->avctx, AV_LOG_ERROR, "marker does not match f_code\n"); - return -1; + return AVERROR_INVALIDDATA; } if (ctx->shape != RECT_SHAPE) { @@ -460,10 +466,10 @@ int ff_mpeg4_decode_video_packet_header(Mpeg4DecContext *ctx) } mb_num = get_bits(&s->gb, mb_num_bits); - if (mb_num >= s->mb_num) { + if (mb_num >= s->mb_num || !mb_num) { av_log(s->avctx, AV_LOG_ERROR, "illegal mb_num in video packet (%d %d) \n", mb_num, s->mb_num); - return -1; + return AVERROR_INVALIDDATA; } s->mb_x = mb_num % s->mb_width; @@ -523,6 +529,55 @@ int ff_mpeg4_decode_video_packet_header(Mpeg4DecContext *ctx) return 0; } +static void reset_studio_dc_predictors(MpegEncContext *s) +{ + /* Reset DC Predictors */ + s->last_dc[0] = + s->last_dc[1] = + s->last_dc[2] = 1 << (s->avctx->bits_per_raw_sample + s->dct_precision + s->intra_dc_precision - 1); +} + +/** + * Decode the next video packet. + * @return <0 if something went wrong + */ +int ff_mpeg4_decode_studio_slice_header(Mpeg4DecContext *ctx) +{ + MpegEncContext *s = &ctx->m; + GetBitContext *gb = &s->gb; + unsigned vlc_len; + uint16_t mb_num; + + if (get_bits_left(gb) >= 32 && get_bits_long(gb, 32) == SLICE_START_CODE) { + vlc_len = av_log2(s->mb_width * s->mb_height) + 1; + mb_num = get_bits(gb, vlc_len); + + if (mb_num >= s->mb_num) + return AVERROR_INVALIDDATA; + + s->mb_x = mb_num % s->mb_width; + s->mb_y = mb_num / s->mb_width; + + if (ctx->shape != BIN_ONLY_SHAPE) + s->qscale = mpeg_get_qscale(s); + + if (get_bits1(gb)) { /* slice_extension_flag */ + skip_bits1(gb); /* intra_slice */ + skip_bits1(gb); /* slice_VOP_id_enable */ + skip_bits(gb, 6); /* slice_VOP_id */ + while (get_bits1(gb)) /* extra_bit_slice */ + skip_bits(gb, 8); /* extra_information_slice */ + } + + reset_studio_dc_predictors(s); + } + else { + return AVERROR_INVALIDDATA; + } + + return 0; +} + /** * Get the average motion vector for a GMC MB. * @param n either 0 for the x component or 1 for y @@ -592,7 +647,7 @@ static inline int mpeg4_decode_dc(MpegEncContext *s, int n, int *dir_ptr) if (code < 0 || code > 9 /* && s->nbit < 9 */) { av_log(s->avctx, AV_LOG_ERROR, "illegal dc vlc\n"); - return -1; + return AVERROR_INVALIDDATA; } if (code == 0) { @@ -615,7 +670,7 @@ static inline int mpeg4_decode_dc(MpegEncContext *s, int n, int *dir_ptr) if (get_bits1(&s->gb) == 0) { /* marker */ if (s->avctx->err_recognition & (AV_EF_BITSTREAM|AV_EF_COMPLIANT)) { av_log(s->avctx, AV_LOG_ERROR, "dc marker bit missing\n"); - return -1; + return AVERROR_INVALIDDATA; } } } @@ -659,7 +714,7 @@ static int mpeg4_decode_partition_a(Mpeg4DecContext *ctx) if (cbpc < 0) { av_log(s->avctx, AV_LOG_ERROR, "mcbpc corrupted at %d %d\n", s->mb_x, s->mb_y); - return -1; + return AVERROR_INVALIDDATA; } } while (cbpc == 8); @@ -679,7 +734,7 @@ static int mpeg4_decode_partition_a(Mpeg4DecContext *ctx) if (dc < 0) { av_log(s->avctx, AV_LOG_ERROR, "DC corrupted at %d %d\n", s->mb_x, s->mb_y); - return -1; + return dc; } dir <<= 1; if (dc_pred_dir) @@ -731,7 +786,7 @@ static int mpeg4_decode_partition_a(Mpeg4DecContext *ctx) if (cbpc < 0) { av_log(s->avctx, AV_LOG_ERROR, "mcbpc corrupted at %d %d\n", s->mb_x, s->mb_y); - return -1; + return AVERROR_INVALIDDATA; } if (cbpc == 20) goto try_again; @@ -769,11 +824,11 @@ static int mpeg4_decode_partition_a(Mpeg4DecContext *ctx) if (!s->mcsel) { mx = ff_h263_decode_motion(s, pred_x, s->f_code); if (mx >= 0xffff) - return -1; + return AVERROR_INVALIDDATA; my = ff_h263_decode_motion(s, pred_y, s->f_code); if (my >= 0xffff) - return -1; + return AVERROR_INVALIDDATA; s->current_picture.mb_type[xy] = MB_TYPE_16x16 | MB_TYPE_L0; } else { @@ -800,11 +855,11 @@ static int mpeg4_decode_partition_a(Mpeg4DecContext *ctx) int16_t *mot_val = ff_h263_pred_motion(s, i, 0, &pred_x, &pred_y); mx = ff_h263_decode_motion(s, pred_x, s->f_code); if (mx >= 0xffff) - return -1; + return AVERROR_INVALIDDATA; my = ff_h263_decode_motion(s, pred_y, s->f_code); if (my >= 0xffff) - return -1; + return AVERROR_INVALIDDATA; mot_val[0] = mx; mot_val[1] = my; } @@ -845,7 +900,7 @@ static int mpeg4_decode_partition_b(MpegEncContext *s, int mb_count) if (cbpy < 0) { av_log(s->avctx, AV_LOG_ERROR, "cbpy corrupted at %d %d\n", s->mb_x, s->mb_y); - return -1; + return AVERROR_INVALIDDATA; } s->cbp_table[xy] |= cbpy << 2; @@ -860,7 +915,7 @@ static int mpeg4_decode_partition_b(MpegEncContext *s, int mb_count) if (cbpy < 0) { av_log(s->avctx, AV_LOG_ERROR, "I cbpy corrupted at %d %d\n", s->mb_x, s->mb_y); - return -1; + return AVERROR_INVALIDDATA; } if (s->cbp_table[xy] & 8) @@ -873,7 +928,7 @@ static int mpeg4_decode_partition_b(MpegEncContext *s, int mb_count) if (dc < 0) { av_log(s->avctx, AV_LOG_ERROR, "DC corrupted at %d %d\n", s->mb_x, s->mb_y); - return -1; + return dc; } dir <<= 1; if (dc_pred_dir) @@ -892,7 +947,7 @@ static int mpeg4_decode_partition_b(MpegEncContext *s, int mb_count) if (cbpy < 0) { av_log(s->avctx, AV_LOG_ERROR, "P cbpy corrupted at %d %d\n", s->mb_x, s->mb_y); - return -1; + return AVERROR_INVALIDDATA; } if (s->cbp_table[xy] & 8) @@ -919,6 +974,7 @@ int ff_mpeg4_decode_partitions(Mpeg4DecContext *ctx) { MpegEncContext *s = &ctx->m; int mb_num; + int ret; const int part_a_error = s->pict_type == AV_PICTURE_TYPE_I ? (ER_DC_ERROR | ER_MV_ERROR) : ER_MV_ERROR; const int part_a_end = s->pict_type == AV_PICTURE_TYPE_I ? (ER_DC_END | ER_MV_END) : ER_MV_END; @@ -926,14 +982,14 @@ int ff_mpeg4_decode_partitions(Mpeg4DecContext *ctx) if (mb_num <= 0) { ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y, part_a_error); - return -1; + return mb_num ? mb_num : AVERROR_INVALIDDATA; } if (s->resync_mb_x + s->resync_mb_y * s->mb_width + mb_num > s->mb_num) { av_log(s->avctx, AV_LOG_ERROR, "slice below monitor ...\n"); ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y, part_a_error); - return -1; + return AVERROR_INVALIDDATA; } s->mb_num_left = mb_num; @@ -945,7 +1001,7 @@ int ff_mpeg4_decode_partitions(Mpeg4DecContext *ctx) av_log(s->avctx, AV_LOG_ERROR, "marker missing after first I partition at %d %d\n", s->mb_x, s->mb_y); - return -1; + return AVERROR_INVALIDDATA; } } else { while (show_bits(&s->gb, 10) == 1) @@ -954,17 +1010,18 @@ int ff_mpeg4_decode_partitions(Mpeg4DecContext *ctx) av_log(s->avctx, AV_LOG_ERROR, "marker missing after first P partition at %d %d\n", s->mb_x, s->mb_y); - return -1; + return AVERROR_INVALIDDATA; } } ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, s->mb_x - 1, s->mb_y, part_a_end); - if (mpeg4_decode_partition_b(s, mb_num) < 0) { + ret = mpeg4_decode_partition_b(s, mb_num); + if (ret < 0) { if (s->pict_type == AV_PICTURE_TYPE_P) ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, s->mb_x, s->mb_y, ER_DC_ERROR); - return -1; + return ret; } else { if (s->pict_type == AV_PICTURE_TYPE_P) ff_er_add_slice(&s->er, s->resync_mb_x, s->resync_mb_y, @@ -1003,7 +1060,7 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, } else { level = mpeg4_decode_dc(s, n, &dc_pred_dir); if (level < 0) - return -1; + return level; } block[0] = level; i = 0; @@ -1071,7 +1128,7 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, if (SHOW_UBITS(re, &s->gb, 1) == 0) { av_log(s->avctx, AV_LOG_ERROR, "1. marker bit missing in rvlc esc\n"); - return -1; + return AVERROR_INVALIDDATA; } SKIP_CACHE(re, &s->gb, 1); @@ -1084,7 +1141,7 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, if (SHOW_UBITS(re, &s->gb, 1) == 0) { av_log(s->avctx, AV_LOG_ERROR, "2. marker bit missing in rvlc esc\n"); - return -1; + return AVERROR_INVALIDDATA; } SKIP_CACHE(re, &s->gb, 1); @@ -1093,7 +1150,7 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, if (SHOW_UBITS(re, &s->gb, 5) != 0x10) { av_log(s->avctx, AV_LOG_ERROR, "reverse esc missing\n"); - return -1; + return AVERROR_INVALIDDATA; } SKIP_CACHE(re, &s->gb, 5); @@ -1129,7 +1186,7 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, av_log(s->avctx, AV_LOG_ERROR, "1. marker bit missing in 3. esc\n"); if (!(s->avctx->err_recognition & AV_EF_IGNORE_ERR)) - return -1; + return AVERROR_INVALIDDATA; } SKIP_CACHE(re, &s->gb, 1); @@ -1140,7 +1197,7 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, av_log(s->avctx, AV_LOG_ERROR, "2. marker bit missing in 3. esc\n"); if (!(s->avctx->err_recognition & AV_EF_IGNORE_ERR)) - return -1; + return AVERROR_INVALIDDATA; } SKIP_COUNTER(re, &s->gb, 1 + 12 + 1); @@ -1153,16 +1210,16 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, const int run1= run - rl->max_run[last][abs_level] - 1; if (abs_level <= rl->max_level[last][run]) { av_log(s->avctx, AV_LOG_ERROR, "illegal 3. esc, vlc encoding possible\n"); - return -1; + return AVERROR_INVALIDDATA; } if (s->error_recognition > FF_ER_COMPLIANT) { if (abs_level <= rl->max_level[last][run]*2) { av_log(s->avctx, AV_LOG_ERROR, "illegal 3. esc, esc 1 encoding possible\n"); - return -1; + return AVERROR_INVALIDDATA; } if (run1 >= 0 && abs_level <= rl->max_level[last][run1]) { av_log(s->avctx, AV_LOG_ERROR, "illegal 3. esc, esc 2 encoding possible\n"); - return -1; + return AVERROR_INVALIDDATA; } } } @@ -1179,7 +1236,7 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, av_log(s->avctx, AV_LOG_ERROR, "|level| overflow in 3. esc, qp=%d\n", s->qscale); - return -1; + return AVERROR_INVALIDDATA; } } level = level < 0 ? -2048 : 2047; @@ -1217,7 +1274,7 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, if (i & (~63)) { av_log(s->avctx, AV_LOG_ERROR, "ac-tex damaged at %d %d\n", s->mb_x, s->mb_y); - return -1; + return AVERROR_INVALIDDATA; } block[scan_table[i]] = level; @@ -1251,10 +1308,12 @@ static inline int mpeg4_decode_block(Mpeg4DecContext *ctx, int16_t *block, */ static int mpeg4_decode_partitioned_mb(MpegEncContext *s, int16_t block[6][64]) { - Mpeg4DecContext *ctx = (Mpeg4DecContext *)s; + Mpeg4DecContext *ctx = s->avctx->priv_data; int cbp, mb_type; const int xy = s->mb_x + s->mb_y * s->mb_stride; + av_assert2(s == (void*)ctx); + mb_type = s->current_picture.mb_type[xy]; cbp = s->cbp_table[xy]; @@ -1312,7 +1371,7 @@ static int mpeg4_decode_partitioned_mb(MpegEncContext *s, int16_t block[6][64]) av_log(s->avctx, AV_LOG_ERROR, "texture corrupted at %d %d %d\n", s->mb_x, s->mb_y, s->mb_intra); - return -1; + return AVERROR_INVALIDDATA; } cbp += cbp; } @@ -1336,12 +1395,13 @@ static int mpeg4_decode_partitioned_mb(MpegEncContext *s, int16_t block[6][64]) static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) { - Mpeg4DecContext *ctx = (Mpeg4DecContext *)s; + Mpeg4DecContext *ctx = s->avctx->priv_data; int cbpc, cbpy, i, cbp, pred_x, pred_y, mx, my, dquant; int16_t *mot_val; static const int8_t quant_tab[4] = { -1, -2, 1, 2 }; const int xy = s->mb_x + s->mb_y * s->mb_stride; + av_assert2(s == (void*)ctx); av_assert2(s->h263_pred); if (s->pict_type == AV_PICTURE_TYPE_P || @@ -1379,7 +1439,7 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) if (cbpc < 0) { av_log(s->avctx, AV_LOG_ERROR, "mcbpc damaged at %d %d\n", s->mb_x, s->mb_y); - return -1; + return AVERROR_INVALIDDATA; } } while (cbpc == 20); @@ -1435,11 +1495,11 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) for (i = 0; i < 2; i++) { mx = ff_h263_decode_motion(s, pred_x, s->f_code); if (mx >= 0xffff) - return -1; + return AVERROR_INVALIDDATA; my = ff_h263_decode_motion(s, pred_y / 2, s->f_code); if (my >= 0xffff) - return -1; + return AVERROR_INVALIDDATA; s->mv[0][i][0] = mx; s->mv[0][i][1] = my; @@ -1452,12 +1512,12 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) mx = ff_h263_decode_motion(s, pred_x, s->f_code); if (mx >= 0xffff) - return -1; + return AVERROR_INVALIDDATA; my = ff_h263_decode_motion(s, pred_y, s->f_code); if (my >= 0xffff) - return -1; + return AVERROR_INVALIDDATA; s->mv[0][0][0] = mx; s->mv[0][0][1] = my; } @@ -1468,11 +1528,11 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) mot_val = ff_h263_pred_motion(s, i, 0, &pred_x, &pred_y); mx = ff_h263_decode_motion(s, pred_x, s->f_code); if (mx >= 0xffff) - return -1; + return AVERROR_INVALIDDATA; my = ff_h263_decode_motion(s, pred_y, s->f_code); if (my >= 0xffff) - return -1; + return AVERROR_INVALIDDATA; s->mv[0][i][0] = mx; s->mv[0][i][1] = my; mot_val[0] = mx; @@ -1528,7 +1588,7 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) mb_type = get_vlc2(&s->gb, mb_type_b_vlc.table, MB_TYPE_B_VLC_BITS, 1); if (mb_type < 0) { av_log(s->avctx, AV_LOG_ERROR, "illegal MB_type\n"); - return -1; + return AVERROR_INVALIDDATA; } mb_type = mb_type_b_map[mb_type]; if (modb2) { @@ -1639,7 +1699,7 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) if (cbpc < 0) { av_log(s->avctx, AV_LOG_ERROR, "I cbpc damaged at %d %d\n", s->mb_x, s->mb_y); - return -1; + return AVERROR_INVALIDDATA; } } while (cbpc == 8); @@ -1657,7 +1717,7 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) if (cbpy < 0) { av_log(s->avctx, AV_LOG_ERROR, "I cbpy damaged at %d %d\n", s->mb_x, s->mb_y); - return -1; + return AVERROR_INVALIDDATA; } cbp = (cbpc & 3) | (cbpy << 2); @@ -1673,7 +1733,7 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) /* decode each block */ for (i = 0; i < 6; i++) { if (mpeg4_decode_block(ctx, block[i], i, cbp & 32, 1, 0) < 0) - return -1; + return AVERROR_INVALIDDATA; cbp += cbp; } goto end; @@ -1682,7 +1742,7 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) /* decode each block */ for (i = 0; i < 6; i++) { if (mpeg4_decode_block(ctx, block[i], i, cbp & 32, 0, 0) < 0) - return -1; + return AVERROR_INVALIDDATA; cbp += cbp; } @@ -1692,7 +1752,7 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) int next = mpeg4_is_resync(ctx); if (next) { if (s->mb_x + s->mb_y*s->mb_width + 1 > next && (s->avctx->err_recognition & AV_EF_AGGRESSIVE)) { - return -1; + return AVERROR_INVALIDDATA; } else if (s->mb_x + s->mb_y*s->mb_width + 1 >= next) return SLICE_END; @@ -1713,13 +1773,196 @@ static int mpeg4_decode_mb(MpegEncContext *s, int16_t block[6][64]) return SLICE_OK; } +/* As per spec, studio start code search isn't the same as the old type of start code */ +static void next_start_code_studio(GetBitContext *gb) +{ + align_get_bits(gb); + + while (get_bits_left(gb) >= 24 && show_bits_long(gb, 24) != 0x1) { + get_bits(gb, 8); + } +} + +/* additional_code, vlc index */ +static const uint8_t ac_state_tab[22][2] = +{ + {0, 0}, + {0, 1}, + {1, 1}, + {2, 1}, + {3, 1}, + {4, 1}, + {5, 1}, + {1, 2}, + {2, 2}, + {3, 2}, + {4, 2}, + {5, 2}, + {6, 2}, + {1, 3}, + {2, 4}, + {3, 5}, + {4, 6}, + {5, 7}, + {6, 8}, + {7, 9}, + {8, 10}, + {0, 11} +}; + +static int mpeg4_decode_studio_block(MpegEncContext *s, int32_t block[64], int n) +{ + Mpeg4DecContext *ctx = s->avctx->priv_data; + + int cc, dct_dc_size, dct_diff, code, j, idx = 1, group = 0, run = 0, + additional_code_len, sign, mismatch; + VLC *cur_vlc = &ctx->studio_intra_tab[0]; + uint8_t *const scantable = s->intra_scantable.permutated; + const uint16_t *quant_matrix; + uint32_t flc; + const int min = -1 * (1 << (s->avctx->bits_per_raw_sample + 6)); + const int max = ((1 << (s->avctx->bits_per_raw_sample + 6)) - 1); + + mismatch = 1; + + memset(block, 0, 64 * sizeof(int32_t)); + + if (n < 4) { + cc = 0; + dct_dc_size = get_vlc2(&s->gb, ctx->studio_luma_dc.table, STUDIO_INTRA_BITS, 2); + quant_matrix = s->intra_matrix; + } else { + cc = (n & 1) + 1; + if (ctx->rgb) + dct_dc_size = get_vlc2(&s->gb, ctx->studio_luma_dc.table, STUDIO_INTRA_BITS, 2); + else + dct_dc_size = get_vlc2(&s->gb, ctx->studio_chroma_dc.table, STUDIO_INTRA_BITS, 2); + quant_matrix = s->chroma_intra_matrix; + } + + if (dct_dc_size < 0) { + av_log(s->avctx, AV_LOG_ERROR, "illegal dct_dc_size vlc\n"); + return AVERROR_INVALIDDATA; + } else if (dct_dc_size == 0) { + dct_diff = 0; + } else { + dct_diff = get_xbits(&s->gb, dct_dc_size); + + if (dct_dc_size > 8) { + if(!check_marker(s->avctx, &s->gb, "dct_dc_size > 8")) + return AVERROR_INVALIDDATA; + } + + } + + s->last_dc[cc] += dct_diff; + + if (s->mpeg_quant) + block[0] = s->last_dc[cc] * (8 >> s->intra_dc_precision); + else + block[0] = s->last_dc[cc] * (8 >> s->intra_dc_precision) * (8 >> s->dct_precision); + /* TODO: support mpeg_quant for AC coefficients */ + + block[0] = av_clip(block[0], min, max); + mismatch ^= block[0]; + + /* AC Coefficients */ + while (1) { + group = get_vlc2(&s->gb, cur_vlc->table, STUDIO_INTRA_BITS, 2); + + if (group < 0) { + av_log(s->avctx, AV_LOG_ERROR, "illegal ac coefficient group vlc\n"); + return AVERROR_INVALIDDATA; + } + + additional_code_len = ac_state_tab[group][0]; + cur_vlc = &ctx->studio_intra_tab[ac_state_tab[group][1]]; + + if (group == 0) { + /* End of Block */ + break; + } else if (group >= 1 && group <= 6) { + /* Zero run length (Table B.47) */ + run = 1 << additional_code_len; + if (additional_code_len) + run += get_bits(&s->gb, additional_code_len); + idx += run; + continue; + } else if (group >= 7 && group <= 12) { + /* Zero run length and +/-1 level (Table B.48) */ + code = get_bits(&s->gb, additional_code_len); + sign = code & 1; + code >>= 1; + run = (1 << (additional_code_len - 1)) + code; + idx += run; + j = scantable[idx++]; + block[j] = sign ? 1 : -1; + } else if (group >= 13 && group <= 20) { + /* Level value (Table B.49) */ + j = scantable[idx++]; + block[j] = get_xbits(&s->gb, additional_code_len); + } else if (group == 21) { + /* Escape */ + j = scantable[idx++]; + additional_code_len = s->avctx->bits_per_raw_sample + s->dct_precision + 4; + flc = get_bits(&s->gb, additional_code_len); + if (flc >> (additional_code_len-1)) + block[j] = -1 * (( flc ^ ((1 << additional_code_len) -1)) + 1); + else + block[j] = flc; + } + block[j] = ((8 * 2 * block[j] * quant_matrix[j] * s->qscale) >> s->dct_precision) / 32; + block[j] = av_clip(block[j], min, max); + mismatch ^= block[j]; + } + + block[63] ^= mismatch & 1; + + return 0; +} + +static int mpeg4_decode_studio_mb(MpegEncContext *s, int16_t block_[12][64]) +{ + int i; + + /* StudioMacroblock */ + /* Assumes I-VOP */ + s->mb_intra = 1; + if (get_bits1(&s->gb)) { /* compression_mode */ + /* DCT */ + /* macroblock_type, 1 or 2-bit VLC */ + if (!get_bits1(&s->gb)) { + skip_bits1(&s->gb); + s->qscale = mpeg_get_qscale(s); + } + + for (i = 0; i < mpeg4_block_count[s->chroma_format]; i++) { + if (mpeg4_decode_studio_block(s, (*s->block32)[i], i) < 0) + return AVERROR_INVALIDDATA; + } + } else { + /* DPCM */ + check_marker(s->avctx, &s->gb, "DPCM block start"); + avpriv_request_sample(s->avctx, "DPCM encoded block"); + next_start_code_studio(&s->gb); + return SLICE_ERROR; + } + + if (get_bits_left(&s->gb) >= 24 && show_bits(&s->gb, 23) == 0) { + next_start_code_studio(&s->gb); + return SLICE_END; + } + + return SLICE_OK; +} + static int mpeg4_decode_gop_header(MpegEncContext *s, GetBitContext *gb) { int hours, minutes, seconds; if (!show_bits(gb, 23)) { av_log(s->avctx, AV_LOG_WARNING, "GOP header invalid\n"); - return -1; + return AVERROR_INVALIDDATA; } hours = get_bits(gb, 5); @@ -1749,6 +1992,55 @@ static int mpeg4_decode_profile_level(MpegEncContext *s, GetBitContext *gb) return 0; } +static int mpeg4_decode_visual_object(MpegEncContext *s, GetBitContext *gb) +{ + int visual_object_type; + int is_visual_object_identifier = get_bits1(gb); + + if (is_visual_object_identifier) { + skip_bits(gb, 4+3); + } + visual_object_type = get_bits(gb, 4); + + if (visual_object_type == VOT_VIDEO_ID || + visual_object_type == VOT_STILL_TEXTURE_ID) { + int video_signal_type = get_bits1(gb); + if (video_signal_type) { + int video_range, color_description; + skip_bits(gb, 3); // video_format + video_range = get_bits1(gb); + color_description = get_bits1(gb); + + s->avctx->color_range = video_range ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG; + + if (color_description) { + s->avctx->color_primaries = get_bits(gb, 8); + s->avctx->color_trc = get_bits(gb, 8); + s->avctx->colorspace = get_bits(gb, 8); + } + } + } + + return 0; +} + +static void mpeg4_load_default_matrices(MpegEncContext *s) +{ + int i, v; + + /* load default matrices */ + for (i = 0; i < 64; i++) { + int j = s->idsp.idct_permutation[i]; + v = ff_mpeg4_default_intra_matrix[i]; + s->intra_matrix[j] = v; + s->chroma_intra_matrix[j] = v; + + v = ff_mpeg4_default_non_intra_matrix[i]; + s->inter_matrix[j] = v; + s->chroma_inter_matrix[j] = v; + } +} + static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) { MpegEncContext *s = &ctx->m; @@ -1912,17 +2204,7 @@ static int decode_vol_header(Mpeg4DecContext *ctx, GetBitContext *gb) if ((s->mpeg_quant = get_bits1(gb))) { /* vol_quant_type */ int i, v; - /* load default matrixes */ - for (i = 0; i < 64; i++) { - int j = s->idsp.idct_permutation[i]; - v = ff_mpeg4_default_intra_matrix[i]; - s->intra_matrix[j] = v; - s->chroma_intra_matrix[j] = v; - - v = ff_mpeg4_default_non_intra_matrix[i]; - s->inter_matrix[j] = v; - s->chroma_inter_matrix[j] = v; - } + mpeg4_load_default_matrices(s); /* load custom intra matrix */ if (get_bits1(gb)) { @@ -2149,8 +2431,15 @@ static int decode_user_data(Mpeg4DecContext *ctx, GetBitContext *gb) e = sscanf(buf, "FFmpeg v%d.%d.%d / libavcodec build: %d", &ver, &ver2, &ver3, &build); if (e != 4) { e = sscanf(buf, "Lavc%d.%d.%d", &ver, &ver2, &ver3) + 1; - if (e > 1) - build = (ver << 16) + (ver2 << 8) + ver3; + if (e > 1) { + if (ver > 0xFFU || ver2 > 0xFFU || ver3 > 0xFFU) { + av_log(s->avctx, AV_LOG_WARNING, + "Unknown Lavc version string encountered, %d.%d.%d; " + "clamping sub-version values to 8-bits.\n", + ver, ver2, ver3); + } + build = ((ver & 0xFF) << 16) + ((ver2 & 0xFF) << 8) + (ver3 & 0xFF); + } } if (e != 4) { if (strcmp(buf, "ffmpeg") == 0) @@ -2559,6 +2848,232 @@ static int decode_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb) return 0; } +static void read_quant_matrix_ext(MpegEncContext *s, GetBitContext *gb) +{ + int i, j, v; + + if (get_bits1(gb)) { + /* intra_quantiser_matrix */ + for (i = 0; i < 64; i++) { + v = get_bits(gb, 8); + j = s->idsp.idct_permutation[ff_zigzag_direct[i]]; + s->intra_matrix[j] = v; + s->chroma_intra_matrix[j] = v; + } + } + + if (get_bits1(gb)) { + /* non_intra_quantiser_matrix */ + for (i = 0; i < 64; i++) { + get_bits(gb, 8); + } + } + + if (get_bits1(gb)) { + /* chroma_intra_quantiser_matrix */ + for (i = 0; i < 64; i++) { + v = get_bits(gb, 8); + j = s->idsp.idct_permutation[ff_zigzag_direct[i]]; + s->chroma_intra_matrix[j] = v; + } + } + + if (get_bits1(gb)) { + /* chroma_non_intra_quantiser_matrix */ + for (i = 0; i < 64; i++) { + get_bits(gb, 8); + } + } + + next_start_code_studio(gb); +} + +static void extension_and_user_data(MpegEncContext *s, GetBitContext *gb, int id) +{ + uint32_t startcode; + uint8_t extension_type; + + startcode = show_bits_long(gb, 32); + if (startcode == USER_DATA_STARTCODE || startcode == EXT_STARTCODE) { + + if ((id == 2 || id == 4) && startcode == EXT_STARTCODE) { + skip_bits_long(gb, 32); + extension_type = get_bits(gb, 4); + if (extension_type == QUANT_MATRIX_EXT_ID) + read_quant_matrix_ext(s, gb); + } + } +} + +static void decode_smpte_tc(Mpeg4DecContext *ctx, GetBitContext *gb) +{ + MpegEncContext *s = &ctx->m; + + skip_bits(gb, 16); /* Time_code[63..48] */ + check_marker(s->avctx, gb, "after Time_code[63..48]"); + skip_bits(gb, 16); /* Time_code[47..32] */ + check_marker(s->avctx, gb, "after Time_code[47..32]"); + skip_bits(gb, 16); /* Time_code[31..16] */ + check_marker(s->avctx, gb, "after Time_code[31..16]"); + skip_bits(gb, 16); /* Time_code[15..0] */ + check_marker(s->avctx, gb, "after Time_code[15..0]"); + skip_bits(gb, 4); /* reserved_bits */ +} + +/** + * Decode the next studio vop header. + * @return <0 if something went wrong + */ +static int decode_studio_vop_header(Mpeg4DecContext *ctx, GetBitContext *gb) +{ + MpegEncContext *s = &ctx->m; + + if (get_bits_left(gb) <= 32) + return 0; + + if (get_bits_long(gb, 32) != VOP_STARTCODE) + return AVERROR_INVALIDDATA; + + s->decode_mb = mpeg4_decode_studio_mb; + + decode_smpte_tc(ctx, gb); + + skip_bits(gb, 10); /* temporal_reference */ + skip_bits(gb, 2); /* vop_structure */ + s->pict_type = get_bits(gb, 2) + AV_PICTURE_TYPE_I; /* vop_coding_type */ + if (get_bits1(gb)) { /* vop_coded */ + skip_bits1(gb); /* top_field_first */ + skip_bits1(gb); /* repeat_first_field */ + s->progressive_frame = get_bits1(gb) ^ 1; /* progressive_frame */ + } + + if (s->pict_type == AV_PICTURE_TYPE_I) { + if (get_bits1(gb)) + reset_studio_dc_predictors(s); + } + + if (ctx->shape != BIN_ONLY_SHAPE) { + s->alternate_scan = get_bits1(gb); + s->frame_pred_frame_dct = get_bits1(gb); + s->dct_precision = get_bits(gb, 2); + s->intra_dc_precision = get_bits(gb, 2); + s->q_scale_type = get_bits1(gb); + } + + if (s->alternate_scan) { + ff_init_scantable(s->idsp.idct_permutation, &s->inter_scantable, ff_alternate_vertical_scan); + ff_init_scantable(s->idsp.idct_permutation, &s->intra_scantable, ff_alternate_vertical_scan); + ff_init_scantable(s->idsp.idct_permutation, &s->intra_h_scantable, ff_alternate_vertical_scan); + ff_init_scantable(s->idsp.idct_permutation, &s->intra_v_scantable, ff_alternate_vertical_scan); + } else { + ff_init_scantable(s->idsp.idct_permutation, &s->inter_scantable, ff_zigzag_direct); + ff_init_scantable(s->idsp.idct_permutation, &s->intra_scantable, ff_zigzag_direct); + ff_init_scantable(s->idsp.idct_permutation, &s->intra_h_scantable, ff_alternate_horizontal_scan); + ff_init_scantable(s->idsp.idct_permutation, &s->intra_v_scantable, ff_alternate_vertical_scan); + } + + mpeg4_load_default_matrices(s); + + next_start_code_studio(gb); + extension_and_user_data(s, gb, 4); + + return 0; +} + +static int decode_studiovisualobject(Mpeg4DecContext *ctx, GetBitContext *gb) +{ + uint32_t startcode; + MpegEncContext *s = &ctx->m; + int visual_object_type, width, height; + + startcode = get_bits_long(gb, 32); + + /* StudioVisualObject() */ + if (startcode == VISUAL_OBJ_STARTCODE) { + skip_bits(gb, 4); /* visual_object_verid */ + visual_object_type = get_bits(gb, 4); + + next_start_code_studio(gb); + extension_and_user_data(s, gb, 1); + + if (visual_object_type == VOT_VIDEO_ID) { + /* StudioVideoObjectLayer */ + skip_bits_long(gb, 32); /* video_object_start_code */ + skip_bits_long(gb, 32); /* video_object_layer_start_code */ + skip_bits1(gb); /* random_accessible_vol */ + skip_bits(gb, 8); /* video_object_type_indication */ + skip_bits(gb, 4); /* video_object_layer_verid */ + ctx->shape = get_bits(gb, 2); /* video_object_layer_shape */ + skip_bits(gb, 4); /* video_object_layer_shape_extension */ + skip_bits1(gb); /* progressive_sequence */ + if (ctx->shape != BIN_ONLY_SHAPE) { + ctx->rgb = get_bits1(gb); /* rgb_components */ + s->chroma_format = get_bits(gb, 2); /* chroma_format */ + if (!s->chroma_format) { + av_log(s->avctx, AV_LOG_ERROR, "illegal chroma format\n"); + return AVERROR_INVALIDDATA; + } + + s->avctx->bits_per_raw_sample = get_bits(gb, 4); /* bit_depth */ + if (s->avctx->bits_per_raw_sample == 10) { + if (ctx->rgb) { + s->avctx->pix_fmt = AV_PIX_FMT_GBRP10; + } + else { + s->avctx->pix_fmt = s->chroma_format == CHROMA_422 ? AV_PIX_FMT_YUV422P10 : AV_PIX_FMT_YUV444P10; + } + } + else { + avpriv_request_sample(s->avctx, "MPEG-4 Studio profile bit-depth %u", s->avctx->bits_per_raw_sample); + return AVERROR_PATCHWELCOME; + } + } + if (ctx->shape == RECT_SHAPE) { + check_marker(s->avctx, gb, "before video_object_layer_width"); + width = get_bits(gb, 14); /* video_object_layer_width */ + check_marker(s->avctx, gb, "before video_object_layer_height"); + height = get_bits(gb, 14); /* video_object_layer_height */ + check_marker(s->avctx, gb, "after video_object_layer_height"); + + /* Do the same check as non-studio profile */ + if (width && height) { + if (s->width && s->height && + (s->width != width || s->height != height)) + s->context_reinit = 1; + s->width = width; + s->height = height; + } + } + s->aspect_ratio_info = get_bits(gb, 4); + if (s->aspect_ratio_info == FF_ASPECT_EXTENDED) { + s->avctx->sample_aspect_ratio.num = get_bits(gb, 8); // par_width + s->avctx->sample_aspect_ratio.den = get_bits(gb, 8); // par_height + } else { + s->avctx->sample_aspect_ratio = ff_h263_pixel_aspect[s->aspect_ratio_info]; + } + skip_bits(gb, 4); /* frame_rate_code */ + skip_bits(gb, 15); /* first_half_bit_rate */ + check_marker(s->avctx, gb, "after first_half_bit_rate"); + skip_bits(gb, 15); /* latter_half_bit_rate */ + check_marker(s->avctx, gb, "after latter_half_bit_rate"); + skip_bits(gb, 15); /* first_half_vbv_buffer_size */ + check_marker(s->avctx, gb, "after first_half_vbv_buffer_size"); + skip_bits(gb, 3); /* latter_half_vbv_buffer_size */ + skip_bits(gb, 11); /* first_half_vbv_buffer_size */ + check_marker(s->avctx, gb, "after first_half_vbv_buffer_size"); + skip_bits(gb, 15); /* latter_half_vbv_occupancy */ + check_marker(s->avctx, gb, "after latter_half_vbv_occupancy"); + s->low_delay = get_bits1(gb); + s->mpeg_quant = get_bits1(gb); /* mpeg2_stream */ + + next_start_code_studio(gb); + extension_and_user_data(s, gb, 2); + } + } + + return 0; +} + /** * Decode MPEG-4 headers. * @return <0 if no VOP found (or a damaged one) @@ -2589,7 +3104,7 @@ int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb) av_log(s->avctx, AV_LOG_VERBOSE, "frame skip %d\n", gb->size_in_bits); return FRAME_SKIPPED; // divx bug } else - return -1; // end of stream + return AVERROR_INVALIDDATA; // end of stream } /* use the bits after the test */ @@ -2660,8 +3175,8 @@ int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb) if (startcode >= 0x120 && startcode <= 0x12F) { if (vol) { - av_log(s->avctx, AV_LOG_ERROR, "Multiple VOL headers"); - return AVERROR_INVALIDDATA; + av_log(s->avctx, AV_LOG_WARNING, "Ignoring multiple VOL headers\n"); + continue; } vol++; if ((ret = decode_vol_header(ctx, gb)) < 0) @@ -2672,6 +3187,18 @@ int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb) mpeg4_decode_gop_header(s, gb); } else if (startcode == VOS_STARTCODE) { mpeg4_decode_profile_level(s, gb); + if (s->avctx->profile == FF_PROFILE_MPEG4_SIMPLE_STUDIO && + (s->avctx->level > 0 && s->avctx->level < 9)) { + s->studio_profile = 1; + next_start_code_studio(gb); + extension_and_user_data(s, gb, 0); + + if ((ret = decode_studiovisualobject(ctx, gb)) < 0) + return ret; + break; + } + } else if (startcode == VISUAL_OBJ_STARTCODE) { + mpeg4_decode_visual_object(s, gb); } else if (startcode == VOP_STARTCODE) { break; } @@ -2685,7 +3212,10 @@ int ff_mpeg4_decode_picture_header(Mpeg4DecContext *ctx, GetBitContext *gb) s->low_delay = 1; s->avctx->has_b_frames = !s->low_delay; - return decode_vop_header(ctx, gb); + if (s->studio_profile) + return decode_studio_vop_header(ctx, gb); + else + return decode_vop_header(ctx, gb); } av_cold void ff_mpeg4videodec_static_init(void) { @@ -2785,6 +3315,37 @@ static int mpeg4_update_thread_context(AVCodecContext *dst, } #endif +static av_cold int init_studio_vlcs(Mpeg4DecContext *ctx) +{ + int i, ret; + + for (i = 0; i < 12; i++) { + ret = init_vlc(&ctx->studio_intra_tab[i], STUDIO_INTRA_BITS, 22, + &ff_mpeg4_studio_intra[i][0][1], 4, 2, + &ff_mpeg4_studio_intra[i][0][0], 4, 2, + 0); + + if (ret < 0) + return ret; + } + + ret = init_vlc(&ctx->studio_luma_dc, STUDIO_INTRA_BITS, 19, + &ff_mpeg4_studio_dc_luma[0][1], 4, 2, + &ff_mpeg4_studio_dc_luma[0][0], 4, 2, + 0); + if (ret < 0) + return ret; + + ret = init_vlc(&ctx->studio_chroma_dc, STUDIO_INTRA_BITS, 19, + &ff_mpeg4_studio_dc_chroma[0][1], 4, 2, + &ff_mpeg4_studio_dc_chroma[0][0], 4, 2, + 0); + if (ret < 0) + return ret; + + return 0; +} + static av_cold int decode_init(AVCodecContext *avctx) { Mpeg4DecContext *ctx = avctx->priv_data; @@ -2800,6 +3361,8 @@ static av_cold int decode_init(AVCodecContext *avctx) return ret; ff_mpeg4videodec_static_init(); + if ((ret = init_studio_vlcs(ctx)) < 0) + return ret; s->h263_pred = 1; s->low_delay = 0; /* default, might be overridden in the vol header during header parsing */ @@ -2812,6 +3375,22 @@ static av_cold int decode_init(AVCodecContext *avctx) return 0; } +static av_cold int decode_end(AVCodecContext *avctx) +{ + Mpeg4DecContext *ctx = avctx->priv_data; + int i; + + if (!avctx->internal->is_copy) { + for (i = 0; i < 12; i++) + ff_free_vlc(&ctx->studio_intra_tab[i]); + + ff_free_vlc(&ctx->studio_luma_dc); + ff_free_vlc(&ctx->studio_chroma_dc); + } + + return ff_h263_decode_end(avctx); +} + static const AVOption mpeg4_options[] = { {"quarter_sample", "1/4 subpel MC", offsetof(MpegEncContext, quarter_sample), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, 0}, {"divx_packed", "divx style packed b frames", offsetof(MpegEncContext, divx_packed), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, 0}, @@ -2819,10 +3398,10 @@ static const AVOption mpeg4_options[] = { }; static const AVClass mpeg4_class = { - "MPEG4 Video Decoder", - av_default_item_name, - mpeg4_options, - LIBAVUTIL_VERSION_INT, + .class_name = "MPEG4 Video Decoder", + .item_name = av_default_item_name, + .option = mpeg4_options, + .version = LIBAVUTIL_VERSION_INT, }; AVCodec ff_mpeg4_decoder = { @@ -2832,7 +3411,7 @@ AVCodec ff_mpeg4_decoder = { .id = AV_CODEC_ID_MPEG4, .priv_data_size = sizeof(Mpeg4DecContext), .init = decode_init, - .close = ff_h263_decode_end, + .close = decode_end, .decode = ff_h263_decode_frame, .capabilities = AV_CODEC_CAP_DRAW_HORIZ_BAND | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_TRUNCATED | AV_CODEC_CAP_DELAY | @@ -2844,30 +3423,19 @@ AVCodec ff_mpeg4_decoder = { .profiles = NULL_IF_CONFIG_SMALL(ff_mpeg4_video_profiles), .update_thread_context = ONLY_IF_THREADS_ENABLED(mpeg4_update_thread_context), .priv_class = &mpeg4_class, -}; - - -#if CONFIG_MPEG4_VDPAU_DECODER && FF_API_VDPAU -static const AVClass mpeg4_vdpau_class = { - "MPEG4 Video VDPAU Decoder", - av_default_item_name, - mpeg4_options, - LIBAVUTIL_VERSION_INT, -}; - -AVCodec ff_mpeg4_vdpau_decoder = { - .name = "mpeg4_vdpau", - .long_name = NULL_IF_CONFIG_SMALL("MPEG-4 part 2 (VDPAU)"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_MPEG4, - .priv_data_size = sizeof(Mpeg4DecContext), - .init = decode_init, - .close = ff_h263_decode_end, - .decode = ff_h263_decode_frame, - .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_TRUNCATED | AV_CODEC_CAP_DELAY | - AV_CODEC_CAP_HWACCEL_VDPAU, - .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_VDPAU_MPEG4, - AV_PIX_FMT_NONE }, - .priv_class = &mpeg4_vdpau_class, -}; + .hw_configs = (const AVCodecHWConfigInternal*[]) { +#if CONFIG_MPEG4_NVDEC_HWACCEL + HWACCEL_NVDEC(mpeg4), #endif +#if CONFIG_MPEG4_VAAPI_HWACCEL + HWACCEL_VAAPI(mpeg4), +#endif +#if CONFIG_MPEG4_VDPAU_HWACCEL + HWACCEL_VDPAU(mpeg4), +#endif +#if CONFIG_MPEG4_VIDEOTOOLBOX_HWACCEL + HWACCEL_VIDEOTOOLBOX(mpeg4), +#endif + NULL + }, +}; diff --git a/libavcodec/mpegaudio_parser.c b/libavcodec/mpegaudio_parser.c index 8c39825792282..244281b56fa2b 100644 --- a/libavcodec/mpegaudio_parser.c +++ b/libavcodec/mpegaudio_parser.c @@ -23,6 +23,7 @@ #include "parser.h" #include "mpegaudiodecheader.h" #include "libavutil/common.h" +#include "libavformat/apetag.h" // for APE tag. #include "libavformat/id3v1.h" // for ID3v1_TAG_SIZE typedef struct MpegAudioParseContext { @@ -120,6 +121,12 @@ static int mpegaudio_parse(AVCodecParserContext *s1, return next; } + if (flush && buf_size >= APE_TAG_FOOTER_BYTES && memcmp(buf, APE_TAG_PREAMBLE, 8) == 0) { + *poutbuf = NULL; + *poutbuf_size = 0; + return next; + } + *poutbuf = buf; *poutbuf_size = buf_size; return next; diff --git a/libavcodec/mpegaudiodata.h b/libavcodec/mpegaudiodata.h index 29a26588b288b..a188150cbfb7f 100644 --- a/libavcodec/mpegaudiodata.h +++ b/libavcodec/mpegaudiodata.h @@ -29,13 +29,13 @@ #include -#include "libavutil/internal.h" +#include "internal.h" #define MODE_EXT_MS_STEREO 2 #define MODE_EXT_I_STEREO 1 -extern av_export const uint16_t avpriv_mpa_bitrate_tab[2][3][15]; -extern av_export const uint16_t avpriv_mpa_freq_tab[3]; +extern av_export_avcodec const uint16_t avpriv_mpa_bitrate_tab[2][3][15]; +extern av_export_avcodec const uint16_t avpriv_mpa_freq_tab[3]; extern const int ff_mpa_sblimit_table[5]; extern const int ff_mpa_quant_steps[17]; extern const int ff_mpa_quant_bits[17]; diff --git a/libavcodec/mpegaudiodecheader.c b/libavcodec/mpegaudiodecheader.c index ae86b087f3ee2..6cc79f18b566e 100644 --- a/libavcodec/mpegaudiodecheader.c +++ b/libavcodec/mpegaudiodecheader.c @@ -152,15 +152,3 @@ int ff_mpa_decode_header(uint32_t head, int *sample_rate, int *channels, int *fr *bit_rate = s->bit_rate; return s->frame_size; } - -#if LIBAVCODEC_VERSION_MAJOR < 58 -int avpriv_mpa_decode_header2(uint32_t head, int *sample_rate, int *channels, int *frame_size, int *bit_rate, enum AVCodecID *codec_id) -{ - return ff_mpa_decode_header(head, sample_rate, channels, frame_size, bit_rate, codec_id); -} - -int avpriv_mpa_decode_header(AVCodecContext *avctx, uint32_t head, int *sample_rate, int *channels, int *frame_size, int *bit_rate) -{ - return ff_mpa_decode_header(head, sample_rate, channels, frame_size, bit_rate, &avctx->codec_id); -} -#endif diff --git a/libavcodec/mpegaudiodecheader.h b/libavcodec/mpegaudiodecheader.h index 952ba174406fc..1cb9216461ab0 100644 --- a/libavcodec/mpegaudiodecheader.h +++ b/libavcodec/mpegaudiodecheader.h @@ -57,11 +57,6 @@ int avpriv_mpegaudio_decode_header(MPADecodeHeader *s, uint32_t header); int ff_mpa_decode_header(uint32_t head, int *sample_rate, int *channels, int *frame_size, int *bitrate, enum AVCodecID *codec_id); -#if LIBAVCODEC_VERSION_MAJOR < 58 -int avpriv_mpa_decode_header(AVCodecContext *avctx, uint32_t head, int *sample_rate, int *channels, int *frame_size, int *bitrate); -int avpriv_mpa_decode_header2(uint32_t head, int *sample_rate, int *channels, int *frame_size, int *bitrate, enum AVCodecID *codec_id); -#endif - /* fast header check for resync */ static inline int ff_mpa_check_header(uint32_t header){ /* header */ diff --git a/libavcodec/mpegaudiodsp.c b/libavcodec/mpegaudiodsp.c index a5d20df629095..3cafca27bfd8a 100644 --- a/libavcodec/mpegaudiodsp.c +++ b/libavcodec/mpegaudiodsp.c @@ -20,17 +20,21 @@ #include "config.h" #include "libavutil/attributes.h" +#include "libavutil/thread.h" #include "mpegaudiodsp.h" #include "dct.h" #include "dct32.h" +static AVOnce mpadsp_float_table_init = AV_ONCE_INIT; +static AVOnce mpadsp_fixed_table_init = AV_ONCE_INIT; + av_cold void ff_mpadsp_init(MPADSPContext *s) { DCTContext dct; ff_dct_init(&dct, 5, DCT_II); - ff_init_mpadsp_tabs_float(); - ff_init_mpadsp_tabs_fixed(); + ff_thread_once(&mpadsp_float_table_init, &ff_init_mpadsp_tabs_float); + ff_thread_once(&mpadsp_fixed_table_init, &ff_init_mpadsp_tabs_fixed); s->apply_window_float = ff_mpadsp_apply_window_float; s->apply_window_fixed = ff_mpadsp_apply_window_fixed; diff --git a/libavcodec/mpegpicture.c b/libavcodec/mpegpicture.c index 53fb35b4bdb49..c0e06900fe2a7 100644 --- a/libavcodec/mpegpicture.c +++ b/libavcodec/mpegpicture.c @@ -22,6 +22,7 @@ #include "libavutil/avassert.h" #include "libavutil/common.h" +#include "libavutil/pixdesc.h" #include "avcodec.h" #include "motion_est.h" @@ -58,11 +59,7 @@ int ff_mpeg_framesize_alloc(AVCodecContext *avctx, MotionEstContext *me, { int alloc_size = FFALIGN(FFABS(linesize) + 64, 32); - if (avctx->hwaccel -#if FF_API_CAP_VDPAU - || avctx->codec->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU -#endif - ) + if (avctx->hwaccel) return 0; if (linesize < 24) { @@ -151,15 +148,18 @@ static int alloc_frame_buffer(AVCodecContext *avctx, Picture *pic, } } - if (linesize && (linesize != pic->f->linesize[0] || - uvlinesize != pic->f->linesize[1])) { + if ((linesize && linesize != pic->f->linesize[0]) || + (uvlinesize && uvlinesize != pic->f->linesize[1])) { av_log(avctx, AV_LOG_ERROR, - "get_buffer() failed (stride changed)\n"); + "get_buffer() failed (stride changed: linesize=%d/%d uvlinesize=%d/%d)\n", + linesize, pic->f->linesize[0], + uvlinesize, pic->f->linesize[1]); ff_mpeg_unref_picture(avctx, pic); return -1; } - if (pic->f->linesize[1] != pic->f->linesize[2]) { + if (av_pix_fmt_count_planes(pic->f->format) > 2 && + pic->f->linesize[1] != pic->f->linesize[2]) { av_log(avctx, AV_LOG_ERROR, "get_buffer() failed (uv stride mismatch)\n"); ff_mpeg_unref_picture(avctx, pic); @@ -377,8 +377,10 @@ int ff_mpeg_ref_picture(AVCodecContext *avctx, Picture *dst, Picture *src) if (src->hwaccel_picture_private) { dst->hwaccel_priv_buf = av_buffer_ref(src->hwaccel_priv_buf); - if (!dst->hwaccel_priv_buf) + if (!dst->hwaccel_priv_buf) { + ret = AVERROR(ENOMEM); goto fail; + } dst->hwaccel_picture_private = dst->hwaccel_priv_buf->data; } diff --git a/libavcodec/mpegutils.c b/libavcodec/mpegutils.c index 62cc36aa6e0ca..3f945406162b4 100644 --- a/libavcodec/mpegutils.c +++ b/libavcodec/mpegutils.c @@ -23,10 +23,31 @@ #include "libavutil/common.h" #include "libavutil/frame.h" #include "libavutil/pixdesc.h" +#include "libavutil/motion_vector.h" +#include "libavutil/avassert.h" #include "avcodec.h" #include "mpegutils.h" +static int add_mb(AVMotionVector *mb, uint32_t mb_type, + int dst_x, int dst_y, + int motion_x, int motion_y, int motion_scale, + int direction) +{ + mb->w = IS_8X8(mb_type) || IS_8X16(mb_type) ? 8 : 16; + mb->h = IS_8X8(mb_type) || IS_16X8(mb_type) ? 8 : 16; + mb->motion_x = motion_x; + mb->motion_y = motion_y; + mb->motion_scale = motion_scale; + mb->dst_x = dst_x; + mb->dst_y = dst_y; + mb->src_x = dst_x + motion_x / motion_scale; + mb->src_y = dst_y + motion_y / motion_scale; + mb->source = direction ? 1 : -1; + mb->flags = 0; // XXX: does mb_type contain extra information that could be exported here? + return 1; +} + void ff_draw_horiz_band(AVCodecContext *avctx, AVFrame *cur, AVFrame *last, int y, int h, int picture_structure, @@ -78,3 +99,295 @@ void ff_draw_horiz_band(AVCodecContext *avctx, y, picture_structure, h); } } + +void ff_print_debug_info2(AVCodecContext *avctx, AVFrame *pict, uint8_t *mbskip_table, + uint32_t *mbtype_table, int8_t *qscale_table, int16_t (*motion_val[2])[2], + int *low_delay, + int mb_width, int mb_height, int mb_stride, int quarter_sample) +{ + if ((avctx->flags2 & AV_CODEC_FLAG2_EXPORT_MVS) && mbtype_table && motion_val[0]) { + const int shift = 1 + quarter_sample; + const int scale = 1 << shift; + const int mv_sample_log2 = avctx->codec_id == AV_CODEC_ID_H264 || avctx->codec_id == AV_CODEC_ID_SVQ3 ? 2 : 1; + const int mv_stride = (mb_width << mv_sample_log2) + + (avctx->codec->id == AV_CODEC_ID_H264 ? 0 : 1); + int mb_x, mb_y, mbcount = 0; + + /* size is width * height * 2 * 4 where 2 is for directions and 4 is + * for the maximum number of MB (4 MB in case of IS_8x8) */ + AVMotionVector *mvs = av_malloc_array(mb_width * mb_height, 2 * 4 * sizeof(AVMotionVector)); + if (!mvs) + return; + + for (mb_y = 0; mb_y < mb_height; mb_y++) { + for (mb_x = 0; mb_x < mb_width; mb_x++) { + int i, direction, mb_type = mbtype_table[mb_x + mb_y * mb_stride]; + for (direction = 0; direction < 2; direction++) { + if (!USES_LIST(mb_type, direction)) + continue; + if (IS_8X8(mb_type)) { + for (i = 0; i < 4; i++) { + int sx = mb_x * 16 + 4 + 8 * (i & 1); + int sy = mb_y * 16 + 4 + 8 * (i >> 1); + int xy = (mb_x * 2 + (i & 1) + + (mb_y * 2 + (i >> 1)) * mv_stride) << (mv_sample_log2 - 1); + int mx = motion_val[direction][xy][0]; + int my = motion_val[direction][xy][1]; + mbcount += add_mb(mvs + mbcount, mb_type, sx, sy, mx, my, scale, direction); + } + } else if (IS_16X8(mb_type)) { + for (i = 0; i < 2; i++) { + int sx = mb_x * 16 + 8; + int sy = mb_y * 16 + 4 + 8 * i; + int xy = (mb_x * 2 + (mb_y * 2 + i) * mv_stride) << (mv_sample_log2 - 1); + int mx = motion_val[direction][xy][0]; + int my = motion_val[direction][xy][1]; + + if (IS_INTERLACED(mb_type)) + my *= 2; + + mbcount += add_mb(mvs + mbcount, mb_type, sx, sy, mx, my, scale, direction); + } + } else if (IS_8X16(mb_type)) { + for (i = 0; i < 2; i++) { + int sx = mb_x * 16 + 4 + 8 * i; + int sy = mb_y * 16 + 8; + int xy = (mb_x * 2 + i + mb_y * 2 * mv_stride) << (mv_sample_log2 - 1); + int mx = motion_val[direction][xy][0]; + int my = motion_val[direction][xy][1]; + + if (IS_INTERLACED(mb_type)) + my *= 2; + + mbcount += add_mb(mvs + mbcount, mb_type, sx, sy, mx, my, scale, direction); + } + } else { + int sx = mb_x * 16 + 8; + int sy = mb_y * 16 + 8; + int xy = (mb_x + mb_y * mv_stride) << mv_sample_log2; + int mx = motion_val[direction][xy][0]; + int my = motion_val[direction][xy][1]; + mbcount += add_mb(mvs + mbcount, mb_type, sx, sy, mx, my, scale, direction); + } + } + } + } + + if (mbcount) { + AVFrameSideData *sd; + + av_log(avctx, AV_LOG_DEBUG, "Adding %d MVs info to frame %d\n", mbcount, avctx->frame_number); + sd = av_frame_new_side_data(pict, AV_FRAME_DATA_MOTION_VECTORS, mbcount * sizeof(AVMotionVector)); + if (!sd) { + av_freep(&mvs); + return; + } + memcpy(sd->data, mvs, mbcount * sizeof(AVMotionVector)); + } + + av_freep(&mvs); + } + + /* TODO: export all the following to make them accessible for users (and filters) */ + if (avctx->hwaccel || !mbtype_table) + return; + + + if (avctx->debug & (FF_DEBUG_SKIP | FF_DEBUG_QP | FF_DEBUG_MB_TYPE)) { + int x,y; + + av_log(avctx, AV_LOG_DEBUG, "New frame, type: %c\n", + av_get_picture_type_char(pict->pict_type)); + for (y = 0; y < mb_height; y++) { + for (x = 0; x < mb_width; x++) { + if (avctx->debug & FF_DEBUG_SKIP) { + int count = mbskip_table ? mbskip_table[x + y * mb_stride] : 0; + if (count > 9) + count = 9; + av_log(avctx, AV_LOG_DEBUG, "%1d", count); + } + if (avctx->debug & FF_DEBUG_QP) { + av_log(avctx, AV_LOG_DEBUG, "%2d", + qscale_table[x + y * mb_stride]); + } + if (avctx->debug & FF_DEBUG_MB_TYPE) { + int mb_type = mbtype_table[x + y * mb_stride]; + // Type & MV direction + if (IS_PCM(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "P"); + else if (IS_INTRA(mb_type) && IS_ACPRED(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "A"); + else if (IS_INTRA4x4(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "i"); + else if (IS_INTRA16x16(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "I"); + else if (IS_DIRECT(mb_type) && IS_SKIP(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "d"); + else if (IS_DIRECT(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "D"); + else if (IS_GMC(mb_type) && IS_SKIP(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "g"); + else if (IS_GMC(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "G"); + else if (IS_SKIP(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "S"); + else if (!USES_LIST(mb_type, 1)) + av_log(avctx, AV_LOG_DEBUG, ">"); + else if (!USES_LIST(mb_type, 0)) + av_log(avctx, AV_LOG_DEBUG, "<"); + else { + av_assert2(USES_LIST(mb_type, 0) && USES_LIST(mb_type, 1)); + av_log(avctx, AV_LOG_DEBUG, "X"); + } + + // segmentation + if (IS_8X8(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "+"); + else if (IS_16X8(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "-"); + else if (IS_8X16(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "|"); + else if (IS_INTRA(mb_type) || IS_16X16(mb_type)) + av_log(avctx, AV_LOG_DEBUG, " "); + else + av_log(avctx, AV_LOG_DEBUG, "?"); + + + if (IS_INTERLACED(mb_type)) + av_log(avctx, AV_LOG_DEBUG, "="); + else + av_log(avctx, AV_LOG_DEBUG, " "); + } + } + av_log(avctx, AV_LOG_DEBUG, "\n"); + } + } + +#if FF_API_DEBUG_MV + if ((avctx->debug & (FF_DEBUG_VIS_QP | FF_DEBUG_VIS_MB_TYPE)) || + (avctx->debug_mv)) { + int mb_y; + int i, ret; + int h_chroma_shift, v_chroma_shift, block_height; + const int mv_sample_log2 = avctx->codec_id == AV_CODEC_ID_H264 || avctx->codec_id == AV_CODEC_ID_SVQ3 ? 2 : 1; + const int mv_stride = (mb_width << mv_sample_log2) + + (avctx->codec->id == AV_CODEC_ID_H264 ? 0 : 1); + + if (low_delay) + *low_delay = 0; // needed to see the vectors without trashing the buffers + + ret = av_pix_fmt_get_chroma_sub_sample (avctx->pix_fmt, &h_chroma_shift, &v_chroma_shift); + if (ret) + return ret; + + av_frame_make_writable(pict); + + pict->opaque = NULL; + block_height = 16 >> v_chroma_shift; + + for (mb_y = 0; mb_y < mb_height; mb_y++) { + int mb_x; + for (mb_x = 0; mb_x < mb_width; mb_x++) { + const int mb_index = mb_x + mb_y * mb_stride; + if ((avctx->debug & FF_DEBUG_VIS_QP)) { + uint64_t c = (qscale_table[mb_index] * 128 / 31) * + 0x0101010101010101ULL; + int y; + for (y = 0; y < block_height; y++) { + *(uint64_t *)(pict->data[1] + 8 * mb_x + + (block_height * mb_y + y) * + pict->linesize[1]) = c; + *(uint64_t *)(pict->data[2] + 8 * mb_x + + (block_height * mb_y + y) * + pict->linesize[2]) = c; + } + } + if ((avctx->debug & FF_DEBUG_VIS_MB_TYPE) && + motion_val[0]) { + int mb_type = mbtype_table[mb_index]; + uint64_t u,v; + int y; +#define COLOR(theta, r) \ + u = (int)(128 + r * cos(theta * M_PI / 180)); \ + v = (int)(128 + r * sin(theta * M_PI / 180)); + + + u = v = 128; + if (IS_PCM(mb_type)) { + COLOR(120, 48) + } else if ((IS_INTRA(mb_type) && IS_ACPRED(mb_type)) || + IS_INTRA16x16(mb_type)) { + COLOR(30, 48) + } else if (IS_INTRA4x4(mb_type)) { + COLOR(90, 48) + } else if (IS_DIRECT(mb_type) && IS_SKIP(mb_type)) { + // COLOR(120, 48) + } else if (IS_DIRECT(mb_type)) { + COLOR(150, 48) + } else if (IS_GMC(mb_type) && IS_SKIP(mb_type)) { + COLOR(170, 48) + } else if (IS_GMC(mb_type)) { + COLOR(190, 48) + } else if (IS_SKIP(mb_type)) { + // COLOR(180, 48) + } else if (!USES_LIST(mb_type, 1)) { + COLOR(240, 48) + } else if (!USES_LIST(mb_type, 0)) { + COLOR(0, 48) + } else { + av_assert2(USES_LIST(mb_type, 0) && USES_LIST(mb_type, 1)); + COLOR(300,48) + } + + u *= 0x0101010101010101ULL; + v *= 0x0101010101010101ULL; + for (y = 0; y < block_height; y++) { + *(uint64_t *)(pict->data[1] + 8 * mb_x + + (block_height * mb_y + y) * pict->linesize[1]) = u; + *(uint64_t *)(pict->data[2] + 8 * mb_x + + (block_height * mb_y + y) * pict->linesize[2]) = v; + } + + // segmentation + if (IS_8X8(mb_type) || IS_16X8(mb_type)) { + *(uint64_t *)(pict->data[0] + 16 * mb_x + 0 + + (16 * mb_y + 8) * pict->linesize[0]) ^= 0x8080808080808080ULL; + *(uint64_t *)(pict->data[0] + 16 * mb_x + 8 + + (16 * mb_y + 8) * pict->linesize[0]) ^= 0x8080808080808080ULL; + } + if (IS_8X8(mb_type) || IS_8X16(mb_type)) { + for (y = 0; y < 16; y++) + pict->data[0][16 * mb_x + 8 + (16 * mb_y + y) * + pict->linesize[0]] ^= 0x80; + } + if (IS_8X8(mb_type) && mv_sample_log2 >= 2) { + int dm = 1 << (mv_sample_log2 - 2); + for (i = 0; i < 4; i++) { + int sx = mb_x * 16 + 8 * (i & 1); + int sy = mb_y * 16 + 8 * (i >> 1); + int xy = (mb_x * 2 + (i & 1) + + (mb_y * 2 + (i >> 1)) * mv_stride) << (mv_sample_log2 - 1); + // FIXME bidir + int32_t *mv = (int32_t *) &motion_val[0][xy]; + if (mv[0] != mv[dm] || + mv[dm * mv_stride] != mv[dm * (mv_stride + 1)]) + for (y = 0; y < 8; y++) + pict->data[0][sx + 4 + (sy + y) * pict->linesize[0]] ^= 0x80; + if (mv[0] != mv[dm * mv_stride] || mv[dm] != mv[dm * (mv_stride + 1)]) + *(uint64_t *)(pict->data[0] + sx + (sy + 4) * + pict->linesize[0]) ^= 0x8080808080808080ULL; + } + } + + if (IS_INTERLACED(mb_type) && + avctx->codec->id == AV_CODEC_ID_H264) { + // hmm + } + } + if (mbskip_table) + mbskip_table[mb_index] = 0; + } + } + } +#endif +} diff --git a/libavcodec/mpegutils.h b/libavcodec/mpegutils.h index 9cfadfc4cf308..1ed21c19be6ef 100644 --- a/libavcodec/mpegutils.h +++ b/libavcodec/mpegutils.h @@ -48,7 +48,6 @@ #define MAX_FCODE 7 /* MB types */ -#if !FF_API_MB_TYPE #define MB_TYPE_INTRA4x4 (1 << 0) #define MB_TYPE_INTRA16x16 (1 << 1) // FIXME H.264-specific #define MB_TYPE_INTRA_PCM (1 << 2) // FIXME H.264-specific @@ -70,7 +69,6 @@ #define MB_TYPE_L0L1 (MB_TYPE_L0 | MB_TYPE_L1) #define MB_TYPE_QUANT (1 << 16) #define MB_TYPE_CBP (1 << 17) -#endif #define MB_TYPE_INTRA MB_TYPE_INTRA4x4 // default mb_type if there is just one type @@ -139,4 +137,12 @@ void ff_draw_horiz_band(AVCodecContext *avctx, AVFrame *cur, AVFrame *last, int y, int h, int picture_structure, int first_field, int low_delay); +/** + * Print debugging info for the given picture. + */ +void ff_print_debug_info2(AVCodecContext *avctx, AVFrame *pict, uint8_t *mbskip_table, + uint32_t *mbtype_table, int8_t *qscale_table, int16_t (*motion_val[2])[2], + int *low_delay, + int mb_width, int mb_height, int mb_stride, int quarter_sample); + #endif /* AVCODEC_MPEGUTILS_H */ diff --git a/libavcodec/mpegvideo.c b/libavcodec/mpegvideo.c index c4089972f0143..45ea0f09e9cb1 100644 --- a/libavcodec/mpegvideo.c +++ b/libavcodec/mpegvideo.c @@ -386,6 +386,9 @@ static int init_duplicate_context(MpegEncContext *s) for (i = 0; i < 12; i++) { s->pblocks[i] = &s->block[i]; } + + FF_ALLOCZ_OR_GOTO(s->avctx, s->block32, sizeof(*s->block32), fail) + if (s->avctx->codec_tag == AV_RL32("VCR2")) { // exchange uv FFSWAP(void *, s->pblocks[4], s->pblocks[5]); @@ -421,6 +424,7 @@ static void free_duplicate_context(MpegEncContext *s) av_freep(&s->me.map); av_freep(&s->me.score_map); av_freep(&s->blocks); + av_freep(&s->block32); av_freep(&s->ac_val_base); s->block = NULL; } @@ -438,6 +442,7 @@ static void backup_duplicate_context(MpegEncContext *bak, MpegEncContext *src) COPY(me.score_map); COPY(blocks); COPY(block); + COPY(block32); COPY(start_mb_y); COPY(end_mb_y); COPY(me.map_generation); @@ -811,6 +816,7 @@ static void clear_context(MpegEncContext *s) s->dct_error_sum = NULL; s->block = NULL; s->blocks = NULL; + s->block32 = NULL; memset(s->pblocks, 0, sizeof(s->pblocks)); s->ac_val_base = NULL; s->ac_val[0] = @@ -876,7 +882,7 @@ static void clear_context(MpegEncContext *s) */ av_cold int ff_mpv_common_init(MpegEncContext *s) { - int i; + int i, ret; int nb_slices = (HAVE_THREADS && s->avctx->active_thread_type & FF_THREAD_SLICE) ? s->avctx->thread_count : 1; @@ -915,10 +921,11 @@ av_cold int ff_mpv_common_init(MpegEncContext *s) dct_init(s); /* set chroma shifts */ - avcodec_get_chroma_sub_sample(s->avctx->pix_fmt, - &s->chroma_x_shift, - &s->chroma_y_shift); - + ret = av_pix_fmt_get_chroma_sub_sample(s->avctx->pix_fmt, + &s->chroma_x_shift, + &s->chroma_y_shift); + if (ret) + return ret; FF_ALLOCZ_OR_GOTO(s->avctx, s->picture, MAX_PICTURE_COUNT * sizeof(Picture), fail); @@ -1311,11 +1318,7 @@ int ff_mpv_frame_start(MpegEncContext *s, AVCodecContext *avctx) return -1; } - if (!avctx->hwaccel -#if FF_API_CAP_VDPAU - && !(avctx->codec->capabilities&AV_CODEC_CAP_HWACCEL_VDPAU) -#endif - ) { + if (!avctx->hwaccel) { for(i=0; iheight; i++) memset(s->last_picture_ptr->f->data[0] + s->last_picture_ptr->f->linesize[0]*i, 0x80, avctx->width); @@ -1422,540 +1425,6 @@ void ff_mpv_frame_end(MpegEncContext *s) ff_thread_report_progress(&s->current_picture_ptr->tf, INT_MAX, 0); } - -#if FF_API_VISMV -static int clip_line(int *sx, int *sy, int *ex, int *ey, int maxx) -{ - if(*sx > *ex) - return clip_line(ex, ey, sx, sy, maxx); - - if (*sx < 0) { - if (*ex < 0) - return 1; - *sy = *ey + (*sy - *ey) * (int64_t)*ex / (*ex - *sx); - *sx = 0; - } - - if (*ex > maxx) { - if (*sx > maxx) - return 1; - *ey = *sy + (*ey - *sy) * (int64_t)(maxx - *sx) / (*ex - *sx); - *ex = maxx; - } - return 0; -} - - -/** - * Draw a line from (ex, ey) -> (sx, sy). - * @param w width of the image - * @param h height of the image - * @param stride stride/linesize of the image - * @param color color of the arrow - */ -static void draw_line(uint8_t *buf, int sx, int sy, int ex, int ey, - int w, int h, int stride, int color) -{ - int x, y, fr, f; - - if (clip_line(&sx, &sy, &ex, &ey, w - 1)) - return; - if (clip_line(&sy, &sx, &ey, &ex, h - 1)) - return; - - sx = av_clip(sx, 0, w - 1); - sy = av_clip(sy, 0, h - 1); - ex = av_clip(ex, 0, w - 1); - ey = av_clip(ey, 0, h - 1); - - buf[sy * stride + sx] += color; - - if (FFABS(ex - sx) > FFABS(ey - sy)) { - if (sx > ex) { - FFSWAP(int, sx, ex); - FFSWAP(int, sy, ey); - } - buf += sx + sy * stride; - ex -= sx; - f = ((ey - sy) << 16) / ex; - for (x = 0; x <= ex; x++) { - y = (x * f) >> 16; - fr = (x * f) & 0xFFFF; - buf[y * stride + x] += (color * (0x10000 - fr)) >> 16; - if(fr) buf[(y + 1) * stride + x] += (color * fr ) >> 16; - } - } else { - if (sy > ey) { - FFSWAP(int, sx, ex); - FFSWAP(int, sy, ey); - } - buf += sx + sy * stride; - ey -= sy; - if (ey) - f = ((ex - sx) << 16) / ey; - else - f = 0; - for(y= 0; y <= ey; y++){ - x = (y*f) >> 16; - fr = (y*f) & 0xFFFF; - buf[y * stride + x] += (color * (0x10000 - fr)) >> 16; - if(fr) buf[y * stride + x + 1] += (color * fr ) >> 16; - } - } -} - -/** - * Draw an arrow from (ex, ey) -> (sx, sy). - * @param w width of the image - * @param h height of the image - * @param stride stride/linesize of the image - * @param color color of the arrow - */ -static void draw_arrow(uint8_t *buf, int sx, int sy, int ex, - int ey, int w, int h, int stride, int color, int tail, int direction) -{ - int dx,dy; - - if (direction) { - FFSWAP(int, sx, ex); - FFSWAP(int, sy, ey); - } - - sx = av_clip(sx, -100, w + 100); - sy = av_clip(sy, -100, h + 100); - ex = av_clip(ex, -100, w + 100); - ey = av_clip(ey, -100, h + 100); - - dx = ex - sx; - dy = ey - sy; - - if (dx * dx + dy * dy > 3 * 3) { - int rx = dx + dy; - int ry = -dx + dy; - int length = ff_sqrt((rx * rx + ry * ry) << 8); - - // FIXME subpixel accuracy - rx = ROUNDED_DIV(rx * 3 << 4, length); - ry = ROUNDED_DIV(ry * 3 << 4, length); - - if (tail) { - rx = -rx; - ry = -ry; - } - - draw_line(buf, sx, sy, sx + rx, sy + ry, w, h, stride, color); - draw_line(buf, sx, sy, sx - ry, sy + rx, w, h, stride, color); - } - draw_line(buf, sx, sy, ex, ey, w, h, stride, color); -} -#endif - -static int add_mb(AVMotionVector *mb, uint32_t mb_type, - int dst_x, int dst_y, - int motion_x, int motion_y, int motion_scale, - int direction) -{ - mb->w = IS_8X8(mb_type) || IS_8X16(mb_type) ? 8 : 16; - mb->h = IS_8X8(mb_type) || IS_16X8(mb_type) ? 8 : 16; - mb->motion_x = motion_x; - mb->motion_y = motion_y; - mb->motion_scale = motion_scale; - mb->dst_x = dst_x; - mb->dst_y = dst_y; - mb->src_x = dst_x + motion_x / motion_scale; - mb->src_y = dst_y + motion_y / motion_scale; - mb->source = direction ? 1 : -1; - mb->flags = 0; // XXX: does mb_type contain extra information that could be exported here? - return 1; -} - -/** - * Print debugging info for the given picture. - */ -void ff_print_debug_info2(AVCodecContext *avctx, AVFrame *pict, uint8_t *mbskip_table, - uint32_t *mbtype_table, int8_t *qscale_table, int16_t (*motion_val[2])[2], - int *low_delay, - int mb_width, int mb_height, int mb_stride, int quarter_sample) -{ - if ((avctx->flags2 & AV_CODEC_FLAG2_EXPORT_MVS) && mbtype_table && motion_val[0]) { - const int shift = 1 + quarter_sample; - const int scale = 1 << shift; - const int mv_sample_log2 = avctx->codec_id == AV_CODEC_ID_H264 || avctx->codec_id == AV_CODEC_ID_SVQ3 ? 2 : 1; - const int mv_stride = (mb_width << mv_sample_log2) + - (avctx->codec->id == AV_CODEC_ID_H264 ? 0 : 1); - int mb_x, mb_y, mbcount = 0; - - /* size is width * height * 2 * 4 where 2 is for directions and 4 is - * for the maximum number of MB (4 MB in case of IS_8x8) */ - AVMotionVector *mvs = av_malloc_array(mb_width * mb_height, 2 * 4 * sizeof(AVMotionVector)); - if (!mvs) - return; - - for (mb_y = 0; mb_y < mb_height; mb_y++) { - for (mb_x = 0; mb_x < mb_width; mb_x++) { - int i, direction, mb_type = mbtype_table[mb_x + mb_y * mb_stride]; - for (direction = 0; direction < 2; direction++) { - if (!USES_LIST(mb_type, direction)) - continue; - if (IS_8X8(mb_type)) { - for (i = 0; i < 4; i++) { - int sx = mb_x * 16 + 4 + 8 * (i & 1); - int sy = mb_y * 16 + 4 + 8 * (i >> 1); - int xy = (mb_x * 2 + (i & 1) + - (mb_y * 2 + (i >> 1)) * mv_stride) << (mv_sample_log2 - 1); - int mx = motion_val[direction][xy][0]; - int my = motion_val[direction][xy][1]; - mbcount += add_mb(mvs + mbcount, mb_type, sx, sy, mx, my, scale, direction); - } - } else if (IS_16X8(mb_type)) { - for (i = 0; i < 2; i++) { - int sx = mb_x * 16 + 8; - int sy = mb_y * 16 + 4 + 8 * i; - int xy = (mb_x * 2 + (mb_y * 2 + i) * mv_stride) << (mv_sample_log2 - 1); - int mx = motion_val[direction][xy][0]; - int my = motion_val[direction][xy][1]; - - if (IS_INTERLACED(mb_type)) - my *= 2; - - mbcount += add_mb(mvs + mbcount, mb_type, sx, sy, mx, my, scale, direction); - } - } else if (IS_8X16(mb_type)) { - for (i = 0; i < 2; i++) { - int sx = mb_x * 16 + 4 + 8 * i; - int sy = mb_y * 16 + 8; - int xy = (mb_x * 2 + i + mb_y * 2 * mv_stride) << (mv_sample_log2 - 1); - int mx = motion_val[direction][xy][0]; - int my = motion_val[direction][xy][1]; - - if (IS_INTERLACED(mb_type)) - my *= 2; - - mbcount += add_mb(mvs + mbcount, mb_type, sx, sy, mx, my, scale, direction); - } - } else { - int sx = mb_x * 16 + 8; - int sy = mb_y * 16 + 8; - int xy = (mb_x + mb_y * mv_stride) << mv_sample_log2; - int mx = motion_val[direction][xy][0]; - int my = motion_val[direction][xy][1]; - mbcount += add_mb(mvs + mbcount, mb_type, sx, sy, mx, my, scale, direction); - } - } - } - } - - if (mbcount) { - AVFrameSideData *sd; - - av_log(avctx, AV_LOG_DEBUG, "Adding %d MVs info to frame %d\n", mbcount, avctx->frame_number); - sd = av_frame_new_side_data(pict, AV_FRAME_DATA_MOTION_VECTORS, mbcount * sizeof(AVMotionVector)); - if (!sd) { - av_freep(&mvs); - return; - } - memcpy(sd->data, mvs, mbcount * sizeof(AVMotionVector)); - } - - av_freep(&mvs); - } - - /* TODO: export all the following to make them accessible for users (and filters) */ - if (avctx->hwaccel || !mbtype_table -#if FF_API_CAP_VDPAU - || (avctx->codec->capabilities&AV_CODEC_CAP_HWACCEL_VDPAU) -#endif - ) - return; - - - if (avctx->debug & (FF_DEBUG_SKIP | FF_DEBUG_QP | FF_DEBUG_MB_TYPE)) { - int x,y; - - av_log(avctx, AV_LOG_DEBUG, "New frame, type: %c\n", - av_get_picture_type_char(pict->pict_type)); - for (y = 0; y < mb_height; y++) { - for (x = 0; x < mb_width; x++) { - if (avctx->debug & FF_DEBUG_SKIP) { - int count = mbskip_table ? mbskip_table[x + y * mb_stride] : 0; - if (count > 9) - count = 9; - av_log(avctx, AV_LOG_DEBUG, "%1d", count); - } - if (avctx->debug & FF_DEBUG_QP) { - av_log(avctx, AV_LOG_DEBUG, "%2d", - qscale_table[x + y * mb_stride]); - } - if (avctx->debug & FF_DEBUG_MB_TYPE) { - int mb_type = mbtype_table[x + y * mb_stride]; - // Type & MV direction - if (IS_PCM(mb_type)) - av_log(avctx, AV_LOG_DEBUG, "P"); - else if (IS_INTRA(mb_type) && IS_ACPRED(mb_type)) - av_log(avctx, AV_LOG_DEBUG, "A"); - else if (IS_INTRA4x4(mb_type)) - av_log(avctx, AV_LOG_DEBUG, "i"); - else if (IS_INTRA16x16(mb_type)) - av_log(avctx, AV_LOG_DEBUG, "I"); - else if (IS_DIRECT(mb_type) && IS_SKIP(mb_type)) - av_log(avctx, AV_LOG_DEBUG, "d"); - else if (IS_DIRECT(mb_type)) - av_log(avctx, AV_LOG_DEBUG, "D"); - else if (IS_GMC(mb_type) && IS_SKIP(mb_type)) - av_log(avctx, AV_LOG_DEBUG, "g"); - else if (IS_GMC(mb_type)) - av_log(avctx, AV_LOG_DEBUG, "G"); - else if (IS_SKIP(mb_type)) - av_log(avctx, AV_LOG_DEBUG, "S"); - else if (!USES_LIST(mb_type, 1)) - av_log(avctx, AV_LOG_DEBUG, ">"); - else if (!USES_LIST(mb_type, 0)) - av_log(avctx, AV_LOG_DEBUG, "<"); - else { - av_assert2(USES_LIST(mb_type, 0) && USES_LIST(mb_type, 1)); - av_log(avctx, AV_LOG_DEBUG, "X"); - } - - // segmentation - if (IS_8X8(mb_type)) - av_log(avctx, AV_LOG_DEBUG, "+"); - else if (IS_16X8(mb_type)) - av_log(avctx, AV_LOG_DEBUG, "-"); - else if (IS_8X16(mb_type)) - av_log(avctx, AV_LOG_DEBUG, "|"); - else if (IS_INTRA(mb_type) || IS_16X16(mb_type)) - av_log(avctx, AV_LOG_DEBUG, " "); - else - av_log(avctx, AV_LOG_DEBUG, "?"); - - - if (IS_INTERLACED(mb_type)) - av_log(avctx, AV_LOG_DEBUG, "="); - else - av_log(avctx, AV_LOG_DEBUG, " "); - } - } - av_log(avctx, AV_LOG_DEBUG, "\n"); - } - } - -#if FF_API_DEBUG_MV - if ((avctx->debug & (FF_DEBUG_VIS_QP | FF_DEBUG_VIS_MB_TYPE)) || - (avctx->debug_mv)) { - int mb_y; - int i; - int h_chroma_shift, v_chroma_shift, block_height; -#if FF_API_VISMV - const int shift = 1 + quarter_sample; - uint8_t *ptr; - const int width = avctx->width; - const int height = avctx->height; -#endif - const int mv_sample_log2 = avctx->codec_id == AV_CODEC_ID_H264 || avctx->codec_id == AV_CODEC_ID_SVQ3 ? 2 : 1; - const int mv_stride = (mb_width << mv_sample_log2) + - (avctx->codec->id == AV_CODEC_ID_H264 ? 0 : 1); - - if (low_delay) - *low_delay = 0; // needed to see the vectors without trashing the buffers - - avcodec_get_chroma_sub_sample(avctx->pix_fmt, &h_chroma_shift, &v_chroma_shift); - - av_frame_make_writable(pict); - - pict->opaque = NULL; -#if FF_API_VISMV - ptr = pict->data[0]; -#endif - block_height = 16 >> v_chroma_shift; - - for (mb_y = 0; mb_y < mb_height; mb_y++) { - int mb_x; - for (mb_x = 0; mb_x < mb_width; mb_x++) { - const int mb_index = mb_x + mb_y * mb_stride; -#if FF_API_VISMV - if ((avctx->debug_mv) && motion_val[0]) { - int type; - for (type = 0; type < 3; type++) { - int direction = 0; - switch (type) { - case 0: - if ((!(avctx->debug_mv & FF_DEBUG_VIS_MV_P_FOR)) || - (pict->pict_type!= AV_PICTURE_TYPE_P)) - continue; - direction = 0; - break; - case 1: - if ((!(avctx->debug_mv & FF_DEBUG_VIS_MV_B_FOR)) || - (pict->pict_type!= AV_PICTURE_TYPE_B)) - continue; - direction = 0; - break; - case 2: - if ((!(avctx->debug_mv & FF_DEBUG_VIS_MV_B_BACK)) || - (pict->pict_type!= AV_PICTURE_TYPE_B)) - continue; - direction = 1; - break; - } - if (!USES_LIST(mbtype_table[mb_index], direction)) - continue; - - if (IS_8X8(mbtype_table[mb_index])) { - int i; - for (i = 0; i < 4; i++) { - int sx = mb_x * 16 + 4 + 8 * (i & 1); - int sy = mb_y * 16 + 4 + 8 * (i >> 1); - int xy = (mb_x * 2 + (i & 1) + - (mb_y * 2 + (i >> 1)) * mv_stride) << (mv_sample_log2 - 1); - int mx = (motion_val[direction][xy][0] >> shift) + sx; - int my = (motion_val[direction][xy][1] >> shift) + sy; - draw_arrow(ptr, sx, sy, mx, my, width, - height, pict->linesize[0], 100, 0, direction); - } - } else if (IS_16X8(mbtype_table[mb_index])) { - int i; - for (i = 0; i < 2; i++) { - int sx = mb_x * 16 + 8; - int sy = mb_y * 16 + 4 + 8 * i; - int xy = (mb_x * 2 + (mb_y * 2 + i) * mv_stride) << (mv_sample_log2 - 1); - int mx = (motion_val[direction][xy][0] >> shift); - int my = (motion_val[direction][xy][1] >> shift); - - if (IS_INTERLACED(mbtype_table[mb_index])) - my *= 2; - - draw_arrow(ptr, sx, sy, mx + sx, my + sy, width, - height, pict->linesize[0], 100, 0, direction); - } - } else if (IS_8X16(mbtype_table[mb_index])) { - int i; - for (i = 0; i < 2; i++) { - int sx = mb_x * 16 + 4 + 8 * i; - int sy = mb_y * 16 + 8; - int xy = (mb_x * 2 + i + mb_y * 2 * mv_stride) << (mv_sample_log2 - 1); - int mx = motion_val[direction][xy][0] >> shift; - int my = motion_val[direction][xy][1] >> shift; - - if (IS_INTERLACED(mbtype_table[mb_index])) - my *= 2; - - draw_arrow(ptr, sx, sy, mx + sx, my + sy, width, - height, pict->linesize[0], 100, 0, direction); - } - } else { - int sx= mb_x * 16 + 8; - int sy= mb_y * 16 + 8; - int xy= (mb_x + mb_y * mv_stride) << mv_sample_log2; - int mx= (motion_val[direction][xy][0]>>shift) + sx; - int my= (motion_val[direction][xy][1]>>shift) + sy; - draw_arrow(ptr, sx, sy, mx, my, width, height, pict->linesize[0], 100, 0, direction); - } - } - } -#endif - if ((avctx->debug & FF_DEBUG_VIS_QP)) { - uint64_t c = (qscale_table[mb_index] * 128 / 31) * - 0x0101010101010101ULL; - int y; - for (y = 0; y < block_height; y++) { - *(uint64_t *)(pict->data[1] + 8 * mb_x + - (block_height * mb_y + y) * - pict->linesize[1]) = c; - *(uint64_t *)(pict->data[2] + 8 * mb_x + - (block_height * mb_y + y) * - pict->linesize[2]) = c; - } - } - if ((avctx->debug & FF_DEBUG_VIS_MB_TYPE) && - motion_val[0]) { - int mb_type = mbtype_table[mb_index]; - uint64_t u,v; - int y; -#define COLOR(theta, r) \ - u = (int)(128 + r * cos(theta * M_PI / 180)); \ - v = (int)(128 + r * sin(theta * M_PI / 180)); - - - u = v = 128; - if (IS_PCM(mb_type)) { - COLOR(120, 48) - } else if ((IS_INTRA(mb_type) && IS_ACPRED(mb_type)) || - IS_INTRA16x16(mb_type)) { - COLOR(30, 48) - } else if (IS_INTRA4x4(mb_type)) { - COLOR(90, 48) - } else if (IS_DIRECT(mb_type) && IS_SKIP(mb_type)) { - // COLOR(120, 48) - } else if (IS_DIRECT(mb_type)) { - COLOR(150, 48) - } else if (IS_GMC(mb_type) && IS_SKIP(mb_type)) { - COLOR(170, 48) - } else if (IS_GMC(mb_type)) { - COLOR(190, 48) - } else if (IS_SKIP(mb_type)) { - // COLOR(180, 48) - } else if (!USES_LIST(mb_type, 1)) { - COLOR(240, 48) - } else if (!USES_LIST(mb_type, 0)) { - COLOR(0, 48) - } else { - av_assert2(USES_LIST(mb_type, 0) && USES_LIST(mb_type, 1)); - COLOR(300,48) - } - - u *= 0x0101010101010101ULL; - v *= 0x0101010101010101ULL; - for (y = 0; y < block_height; y++) { - *(uint64_t *)(pict->data[1] + 8 * mb_x + - (block_height * mb_y + y) * pict->linesize[1]) = u; - *(uint64_t *)(pict->data[2] + 8 * mb_x + - (block_height * mb_y + y) * pict->linesize[2]) = v; - } - - // segmentation - if (IS_8X8(mb_type) || IS_16X8(mb_type)) { - *(uint64_t *)(pict->data[0] + 16 * mb_x + 0 + - (16 * mb_y + 8) * pict->linesize[0]) ^= 0x8080808080808080ULL; - *(uint64_t *)(pict->data[0] + 16 * mb_x + 8 + - (16 * mb_y + 8) * pict->linesize[0]) ^= 0x8080808080808080ULL; - } - if (IS_8X8(mb_type) || IS_8X16(mb_type)) { - for (y = 0; y < 16; y++) - pict->data[0][16 * mb_x + 8 + (16 * mb_y + y) * - pict->linesize[0]] ^= 0x80; - } - if (IS_8X8(mb_type) && mv_sample_log2 >= 2) { - int dm = 1 << (mv_sample_log2 - 2); - for (i = 0; i < 4; i++) { - int sx = mb_x * 16 + 8 * (i & 1); - int sy = mb_y * 16 + 8 * (i >> 1); - int xy = (mb_x * 2 + (i & 1) + - (mb_y * 2 + (i >> 1)) * mv_stride) << (mv_sample_log2 - 1); - // FIXME bidir - int32_t *mv = (int32_t *) &motion_val[0][xy]; - if (mv[0] != mv[dm] || - mv[dm * mv_stride] != mv[dm * (mv_stride + 1)]) - for (y = 0; y < 8; y++) - pict->data[0][sx + 4 + (sy + y) * pict->linesize[0]] ^= 0x80; - if (mv[0] != mv[dm * mv_stride] || mv[dm] != mv[dm * (mv_stride + 1)]) - *(uint64_t *)(pict->data[0] + sx + (sy + 4) * - pict->linesize[0]) ^= 0x8080808080808080ULL; - } - } - - if (IS_INTERLACED(mb_type) && - avctx->codec->id == AV_CODEC_ID_H264) { - // hmm - } - } - if (mbskip_table) - mbskip_table[mb_index] = 0; - } - } - } -#endif -} - void ff_print_debug_info(MpegEncContext *s, Picture *p, AVFrame *pict) { ff_print_debug_info2(s->avctx, pict, s->mbskip_table, p->mb_type, @@ -2657,8 +2126,31 @@ void mpv_reconstruct_mb_internal(MpegEncContext *s, int16_t block[12][64], ff_wmv2_add_mb(s, block, dest_y, dest_cb, dest_cr); } } else { + /* Only MPEG-4 Simple Studio Profile is supported in > 8-bit mode. + TODO: Integrate 10-bit properly into mpegvideo.c so that ER works properly */ + if (s->avctx->bits_per_raw_sample > 8){ + const int act_block_size = block_size * 2; + s->idsp.idct_put(dest_y, dct_linesize, (int16_t*)(*s->block32)[0]); + s->idsp.idct_put(dest_y + act_block_size, dct_linesize, (int16_t*)(*s->block32)[1]); + s->idsp.idct_put(dest_y + dct_offset, dct_linesize, (int16_t*)(*s->block32)[2]); + s->idsp.idct_put(dest_y + dct_offset + act_block_size, dct_linesize, (int16_t*)(*s->block32)[3]); + + dct_linesize = uvlinesize << s->interlaced_dct; + dct_offset = s->interlaced_dct ? uvlinesize : uvlinesize*block_size; + + s->idsp.idct_put(dest_cb, dct_linesize, (int16_t*)(*s->block32)[4]); + s->idsp.idct_put(dest_cr, dct_linesize, (int16_t*)(*s->block32)[5]); + s->idsp.idct_put(dest_cb + dct_offset, dct_linesize, (int16_t*)(*s->block32)[6]); + s->idsp.idct_put(dest_cr + dct_offset, dct_linesize, (int16_t*)(*s->block32)[7]); + if(!s->chroma_x_shift){//Chroma444 + s->idsp.idct_put(dest_cb + act_block_size, dct_linesize, (int16_t*)(*s->block32)[8]); + s->idsp.idct_put(dest_cr + act_block_size, dct_linesize, (int16_t*)(*s->block32)[9]); + s->idsp.idct_put(dest_cb + act_block_size + dct_offset, dct_linesize, (int16_t*)(*s->block32)[10]); + s->idsp.idct_put(dest_cr + act_block_size + dct_offset, dct_linesize, (int16_t*)(*s->block32)[11]); + } + } /* dct only in intra block */ - if(s->encoding || !(s->codec_id==AV_CODEC_ID_MPEG1VIDEO || s->codec_id==AV_CODEC_ID_MPEG2VIDEO)){ + else if(s->encoding || !(s->codec_id==AV_CODEC_ID_MPEG1VIDEO || s->codec_id==AV_CODEC_ID_MPEG2VIDEO)){ put_dct(s, block[0], 0, dest_y , dct_linesize, s->qscale); put_dct(s, block[1], 1, dest_y + block_size, dct_linesize, s->qscale); put_dct(s, block[2], 2, dest_y + dct_offset , dct_linesize, s->qscale); @@ -2739,7 +2231,8 @@ void ff_mpeg_draw_horiz_band(MpegEncContext *s, int y, int h) void ff_init_block_index(MpegEncContext *s){ //FIXME maybe rename const int linesize = s->current_picture.f->linesize[0]; //not s->linesize as this would be wrong for field pics const int uvlinesize = s->current_picture.f->linesize[1]; - const int mb_size= 4 - s->avctx->lowres; + const int width_of_mb = (4 + (s->avctx->bits_per_raw_sample > 8)) - s->avctx->lowres; + const int height_of_mb = 4 - s->avctx->lowres; s->block_index[0]= s->b8_stride*(s->mb_y*2 ) - 2 + s->mb_x*2; s->block_index[1]= s->b8_stride*(s->mb_y*2 ) - 1 + s->mb_x*2; @@ -2749,20 +2242,20 @@ void ff_init_block_index(MpegEncContext *s){ //FIXME maybe rename s->block_index[5]= s->mb_stride*(s->mb_y + s->mb_height + 2) + s->b8_stride*s->mb_height*2 + s->mb_x - 1; //block_index is not used by mpeg2, so it is not affected by chroma_format - s->dest[0] = s->current_picture.f->data[0] + (int)((s->mb_x - 1U) << mb_size); - s->dest[1] = s->current_picture.f->data[1] + (int)((s->mb_x - 1U) << (mb_size - s->chroma_x_shift)); - s->dest[2] = s->current_picture.f->data[2] + (int)((s->mb_x - 1U) << (mb_size - s->chroma_x_shift)); + s->dest[0] = s->current_picture.f->data[0] + (int)((s->mb_x - 1U) << width_of_mb); + s->dest[1] = s->current_picture.f->data[1] + (int)((s->mb_x - 1U) << (width_of_mb - s->chroma_x_shift)); + s->dest[2] = s->current_picture.f->data[2] + (int)((s->mb_x - 1U) << (width_of_mb - s->chroma_x_shift)); if(!(s->pict_type==AV_PICTURE_TYPE_B && s->avctx->draw_horiz_band && s->picture_structure==PICT_FRAME)) { if(s->picture_structure==PICT_FRAME){ - s->dest[0] += s->mb_y * linesize << mb_size; - s->dest[1] += s->mb_y * uvlinesize << (mb_size - s->chroma_y_shift); - s->dest[2] += s->mb_y * uvlinesize << (mb_size - s->chroma_y_shift); + s->dest[0] += s->mb_y * linesize << height_of_mb; + s->dest[1] += s->mb_y * uvlinesize << (height_of_mb - s->chroma_y_shift); + s->dest[2] += s->mb_y * uvlinesize << (height_of_mb - s->chroma_y_shift); }else{ - s->dest[0] += (s->mb_y>>1) * linesize << mb_size; - s->dest[1] += (s->mb_y>>1) * uvlinesize << (mb_size - s->chroma_y_shift); - s->dest[2] += (s->mb_y>>1) * uvlinesize << (mb_size - s->chroma_y_shift); + s->dest[0] += (s->mb_y>>1) * linesize << height_of_mb; + s->dest[1] += (s->mb_y>>1) * uvlinesize << (height_of_mb - s->chroma_y_shift); + s->dest[2] += (s->mb_y>>1) * uvlinesize << (height_of_mb - s->chroma_y_shift); av_assert1((s->mb_y&1) == (s->picture_structure == PICT_BOTTOM_FIELD)); } } diff --git a/libavcodec/mpegvideo.h b/libavcodec/mpegvideo.h index e9eb633d1b51d..541909cbb185a 100644 --- a/libavcodec/mpegvideo.h +++ b/libavcodec/mpegvideo.h @@ -45,6 +45,7 @@ #include "mpegpicture.h" #include "mpegvideodsp.h" #include "mpegvideoencdsp.h" +#include "mpegvideodata.h" #include "pixblockdsp.h" #include "put_bits.h" #include "ratecontrol.h" @@ -71,6 +72,8 @@ #define SLICE_MAX_START_CODE 0x000001af #define EXT_START_CODE 0x000001b5 #define USER_START_CODE 0x000001b2 +#define SLICE_START_CODE 0x000001b7 + /** * MpegEncContext. @@ -252,9 +255,6 @@ typedef struct MpegEncContext { int16_t (*b_field_mv_table[2][2][2])[2];///< MV table (4MV per MB) interlaced B-frame encoding uint8_t (*p_field_select_table[2]); uint8_t (*b_field_select_table[2][2]); -#if FF_API_MOTION_EST - int me_method; ///< ME algorithm -#endif int motion_est; ///< ME algorithm int me_penalty_compensation; int me_pre; ///< prepass for motion estimation @@ -381,6 +381,8 @@ typedef struct MpegEncContext { int custom_pcf; /* MPEG-4 specific */ + int studio_profile; + int dct_precision; ///< number of bits to represent the fractional part of time (encoder only) int time_increment_bits; int last_time_base; @@ -467,6 +469,13 @@ typedef struct MpegEncContext { int intra_vlc_format; int alternate_scan; int seq_disp_ext; + int video_format; +#define VIDEO_FORMAT_COMPONENT 0 +#define VIDEO_FORMAT_PAL 1 +#define VIDEO_FORMAT_NTSC 2 +#define VIDEO_FORMAT_SECAM 3 +#define VIDEO_FORMAT_MAC 4 +#define VIDEO_FORMAT_UNSPECIFIED 5 int repeat_first_field; int chroma_420_type; int chroma_format; @@ -497,7 +506,10 @@ typedef struct MpegEncContext { int16_t (*block)[64]; ///< points to one of the following blocks int16_t (*blocks)[12][64]; // for HQ mode we need to keep the best block - int (*decode_mb)(struct MpegEncContext *s, int16_t block[6][64]); // used by some codecs to avoid a switch() + int (*decode_mb)(struct MpegEncContext *s, int16_t block[12][64]); // used by some codecs to avoid a switch() + + int32_t (*block32)[12][64]; + #define SLICE_OK 0 #define SLICE_ERROR -1 #define SLICE_END -2 ///> s->avctx->lowres; + const int bytes_per_pixel = 1 + (s->avctx->bits_per_raw_sample > 8); + const int block_size= (8*bytes_per_pixel) >> s->avctx->lowres; s->block_index[0]+=2; s->block_index[1]+=2; @@ -738,8 +747,8 @@ static inline void ff_update_block_index(MpegEncContext *s){ s->block_index[4]++; s->block_index[5]++; s->dest[0]+= 2*block_size; - s->dest[1]+= block_size; - s->dest[2]+= block_size; + s->dest[1]+= (2 >> s->chroma_x_shift) * block_size; + s->dest[2]+= (2 >> s->chroma_x_shift) * block_size; } static inline int get_bits_diff(MpegEncContext *s){ @@ -751,4 +760,13 @@ static inline int get_bits_diff(MpegEncContext *s){ return bits - last; } +static inline int mpeg_get_qscale(MpegEncContext *s) +{ + int qscale = get_bits(&s->gb, 5); + if (s->q_scale_type) + return ff_mpeg2_non_linear_qscale[qscale]; + else + return qscale << 1; +} + #endif /* AVCODEC_MPEGVIDEO_H */ diff --git a/libavcodec/mpegvideo_enc.c b/libavcodec/mpegvideo_enc.c index 5765ef339f554..979e138b8895c 100644 --- a/libavcodec/mpegvideo_enc.c +++ b/libavcodec/mpegvideo_enc.c @@ -415,22 +415,9 @@ FF_ENABLE_DEPRECATION_WARNINGS s->intra_only = 0; } -#if FF_API_MOTION_EST -FF_DISABLE_DEPRECATION_WARNINGS - s->me_method = avctx->me_method; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - /* Fixed QSCALE */ s->fixed_qscale = !!(avctx->flags & AV_CODEC_FLAG_QSCALE); -#if FF_API_MPV_OPT - FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->border_masking != 0.0) - s->border_masking = avctx->border_masking; - FF_ENABLE_DEPRECATION_WARNINGS -#endif - s->adaptive_quant = (s->avctx->lumi_masking || s->avctx->dark_masking || s->avctx->temporal_cplx_masking || @@ -760,15 +747,6 @@ FF_ENABLE_DEPRECATION_WARNINGS return AVERROR(EINVAL); } -#if FF_API_QUANT_BIAS -FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->intra_quant_bias != FF_DEFAULT_QUANT_BIAS) - s->intra_quant_bias = avctx->intra_quant_bias; - if (avctx->inter_quant_bias != FF_DEFAULT_QUANT_BIAS) - s->inter_quant_bias = avctx->inter_quant_bias; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - av_log(avctx, AV_LOG_DEBUG, "intra_quant_bias = %d inter_quant_bias = %d\n",s->intra_quant_bias,s->inter_quant_bias); if (avctx->codec_id == AV_CODEC_ID_MPEG4 && @@ -1043,20 +1021,9 @@ FF_ENABLE_DEPRECATION_WARNINGS 31, 0); } -#if FF_API_RC_STRATEGY -FF_DISABLE_DEPRECATION_WARNINGS - if (!s->rc_strategy) - s->rc_strategy = s->avctx->rc_strategy; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - if (ff_rate_control_init(s) < 0) return -1; -#if FF_API_RC_STRATEGY - av_assert0(MPV_RC_STRATEGY_XVID == FF_RC_STRATEGY_XVID); -#endif - if ((s->avctx->flags & AV_CODEC_FLAG_PASS2) && s->rc_strategy == MPV_RC_STRATEGY_XVID) { #if CONFIG_LIBXVID ret = ff_xvid_rate_control_init(s); @@ -1069,53 +1036,6 @@ FF_ENABLE_DEPRECATION_WARNINGS return ret; } -#if FF_API_ERROR_RATE - FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->error_rate) - s->error_rate = avctx->error_rate; - FF_ENABLE_DEPRECATION_WARNINGS; -#endif - -#if FF_API_NORMALIZE_AQP - FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->flags & CODEC_FLAG_NORMALIZE_AQP) - s->mpv_flags |= FF_MPV_FLAG_NAQ; - FF_ENABLE_DEPRECATION_WARNINGS; -#endif - -#if FF_API_MV0 - FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->flags & CODEC_FLAG_MV0) - s->mpv_flags |= FF_MPV_FLAG_MV0; - FF_ENABLE_DEPRECATION_WARNINGS -#endif - -#if FF_API_MPV_OPT - FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->rc_qsquish != 0.0) - s->rc_qsquish = avctx->rc_qsquish; - if (avctx->rc_qmod_amp != 0.0) - s->rc_qmod_amp = avctx->rc_qmod_amp; - if (avctx->rc_qmod_freq) - s->rc_qmod_freq = avctx->rc_qmod_freq; - if (avctx->rc_buffer_aggressivity != 1.0) - s->rc_buffer_aggressivity = avctx->rc_buffer_aggressivity; - if (avctx->rc_initial_cplx != 0.0) - s->rc_initial_cplx = avctx->rc_initial_cplx; - if (avctx->lmin) - s->lmin = avctx->lmin; - if (avctx->lmax) - s->lmax = avctx->lmax; - - if (avctx->rc_eq) { - av_freep(&s->rc_eq); - s->rc_eq = av_strdup(avctx->rc_eq); - if (!s->rc_eq) - return AVERROR(ENOMEM); - } - FF_ENABLE_DEPRECATION_WARNINGS -#endif - #if FF_API_PRIVATE_OPT FF_DISABLE_DEPRECATION_WARNINGS if (avctx->brd_scale) @@ -2793,7 +2713,7 @@ static inline void encode_mb_hq(MpegEncContext *s, MpegEncContext *backup, MpegE } static int sse(MpegEncContext *s, uint8_t *src1, uint8_t *src2, int w, int h, int stride){ - uint32_t *sq = ff_square_tab + 256; + const uint32_t *sq = ff_square_tab + 256; int acc=0; int x,y; diff --git a/libavcodec/mpegvideo_motion.c b/libavcodec/mpegvideo_motion.c index c913504a657f2..5624c1062974c 100644 --- a/libavcodec/mpegvideo_motion.c +++ b/libavcodec/mpegvideo_motion.c @@ -239,20 +239,22 @@ void mpeg_motion_internal(MpegEncContext *s, int motion_y, int h, int is_mpeg12, + int is_16x8, int mb_y) { uint8_t *ptr_y, *ptr_cb, *ptr_cr; int dxy, uvdxy, mx, my, src_x, src_y, - uvsrc_x, uvsrc_y, v_edge_pos; + uvsrc_x, uvsrc_y, v_edge_pos, block_y_half; ptrdiff_t uvlinesize, linesize; v_edge_pos = s->v_edge_pos >> field_based; linesize = s->current_picture.f->linesize[0] << field_based; uvlinesize = s->current_picture.f->linesize[1] << field_based; + block_y_half = (field_based | is_16x8); dxy = ((motion_y & 1) << 1) | (motion_x & 1); src_x = s->mb_x * 16 + (motion_x >> 1); - src_y = (mb_y << (4 - field_based)) + (motion_y >> 1); + src_y = (mb_y << (4 - block_y_half)) + (motion_y >> 1); if (!is_mpeg12 && s->out_format == FMT_H263) { if ((s->workaround_bugs & FF_BUG_HPEL_CHROMA) && field_based) { @@ -260,7 +262,7 @@ void mpeg_motion_internal(MpegEncContext *s, my = motion_y >> 1; uvdxy = ((my & 1) << 1) | (mx & 1); uvsrc_x = s->mb_x * 8 + (mx >> 1); - uvsrc_y = (mb_y << (3 - field_based)) + (my >> 1); + uvsrc_y = (mb_y << (3 - block_y_half)) + (my >> 1); } else { uvdxy = dxy | (motion_y & 2) | ((motion_x & 2) >> 1); uvsrc_x = src_x >> 1; @@ -279,7 +281,7 @@ void mpeg_motion_internal(MpegEncContext *s, my = motion_y / 2; uvdxy = ((my & 1) << 1) | (mx & 1); uvsrc_x = s->mb_x * 8 + (mx >> 1); - uvsrc_y = (mb_y << (3 - field_based)) + (my >> 1); + uvsrc_y = (mb_y << (3 - block_y_half)) + (my >> 1); } else { if (s->chroma_x_shift) { // Chroma422 @@ -370,18 +372,18 @@ static void mpeg_motion(MpegEncContext *s, uint8_t *dest_y, uint8_t *dest_cb, uint8_t *dest_cr, int field_select, uint8_t **ref_picture, op_pixels_func (*pix_op)[4], - int motion_x, int motion_y, int h, int mb_y) + int motion_x, int motion_y, int h, int is_16x8, int mb_y) { #if !CONFIG_SMALL if (s->out_format == FMT_MPEG1) mpeg_motion_internal(s, dest_y, dest_cb, dest_cr, 0, 0, field_select, ref_picture, pix_op, - motion_x, motion_y, h, 1, mb_y); + motion_x, motion_y, h, 1, is_16x8, mb_y); else #endif mpeg_motion_internal(s, dest_y, dest_cb, dest_cr, 0, 0, field_select, ref_picture, pix_op, - motion_x, motion_y, h, 0, mb_y); + motion_x, motion_y, h, 0, is_16x8, mb_y); } static void mpeg_motion_field(MpegEncContext *s, uint8_t *dest_y, @@ -395,12 +397,12 @@ static void mpeg_motion_field(MpegEncContext *s, uint8_t *dest_y, if (s->out_format == FMT_MPEG1) mpeg_motion_internal(s, dest_y, dest_cb, dest_cr, 1, bottom_field, field_select, ref_picture, pix_op, - motion_x, motion_y, h, 1, mb_y); + motion_x, motion_y, h, 1, 0, mb_y); else #endif mpeg_motion_internal(s, dest_y, dest_cb, dest_cr, 1, bottom_field, field_select, ref_picture, pix_op, - motion_x, motion_y, h, 0, mb_y); + motion_x, motion_y, h, 0, 0, mb_y); } // FIXME: SIMDify, avg variant, 16x16 version @@ -870,7 +872,7 @@ static av_always_inline void mpv_motion_internal(MpegEncContext *s, } else { mpeg_motion(s, dest_y, dest_cb, dest_cr, 0, ref_picture, pix_op, - s->mv[dir][0][0], s->mv[dir][0][1], 16, mb_y); + s->mv[dir][0][0], s->mv[dir][0][1], 16, 0, mb_y); } break; case MV_TYPE_8X8: @@ -907,7 +909,7 @@ static av_always_inline void mpv_motion_internal(MpegEncContext *s, mpeg_motion(s, dest_y, dest_cb, dest_cr, s->field_select[dir][0], ref_picture, pix_op, - s->mv[dir][0][0], s->mv[dir][0][1], 16, mb_y >> 1); + s->mv[dir][0][0], s->mv[dir][0][1], 16, 0, mb_y >> 1); } break; case MV_TYPE_16X8: @@ -924,8 +926,8 @@ static av_always_inline void mpv_motion_internal(MpegEncContext *s, mpeg_motion(s, dest_y, dest_cb, dest_cr, s->field_select[dir][i], ref2picture, pix_op, - s->mv[dir][i][0], s->mv[dir][i][1] + 16 * i, - 8, mb_y >> 1); + s->mv[dir][i][0], s->mv[dir][i][1], + 8, 1, (mb_y & ~1) + i); dest_y += 16 * s->linesize; dest_cb += (16 >> s->chroma_y_shift) * s->uvlinesize; @@ -952,7 +954,7 @@ static av_always_inline void mpv_motion_internal(MpegEncContext *s, s->picture_structure != i + 1, ref_picture, pix_op, s->mv[dir][2 * i][0], s->mv[dir][2 * i][1], - 16, mb_y >> 1); + 16, 0, mb_y >> 1); // after put we make avg of the same block pix_op = s->hdsp.avg_pixels_tab; diff --git a/libavcodec/mpegvideo_parser.c b/libavcodec/mpegvideo_parser.c index de70cd5632da9..7a3c7abdb24e5 100644 --- a/libavcodec/mpegvideo_parser.c +++ b/libavcodec/mpegvideo_parser.c @@ -61,7 +61,7 @@ static void mpegvideo_extract_headers(AVCodecParserContext *s, if (bytes_left >= 2) { s->pict_type = (buf[1] >> 3) & 7; if (bytes_left >= 4) - vbv_delay = ((buf[1] & 0x07) << 13) | (buf[2] << 5) | (buf[3] >> 3); + vbv_delay = ((buf[1] & 0x07) << 13) | (buf[2] << 5) | (buf[3] >> 3); } break; case SEQ_START_CODE: @@ -131,7 +131,7 @@ static void mpegvideo_extract_headers(AVCodecParserContext *s, } } - if (!pc->progressive_sequence) { + if (!pc->progressive_sequence && !progressive_frame) { if (top_field_first) s->field_order = AV_FIELD_TT; else diff --git a/libavcodec/mpegvideo_xvmc.c b/libavcodec/mpegvideo_xvmc.c index 519a4481614cf..f06583768c42f 100644 --- a/libavcodec/mpegvideo_xvmc.c +++ b/libavcodec/mpegvideo_xvmc.c @@ -348,7 +348,7 @@ static void ff_xvmc_decode_mb(struct MpegEncContext *s) } #if CONFIG_MPEG1_XVMC_HWACCEL -AVHWAccel ff_mpeg1_xvmc_hwaccel = { +const AVHWAccel ff_mpeg1_xvmc_hwaccel = { .name = "mpeg1_xvmc", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG1VIDEO, @@ -362,7 +362,7 @@ AVHWAccel ff_mpeg1_xvmc_hwaccel = { #endif #if CONFIG_MPEG2_XVMC_HWACCEL -AVHWAccel ff_mpeg2_xvmc_hwaccel = { +const AVHWAccel ff_mpeg2_xvmc_hwaccel = { .name = "mpeg2_xvmc", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG2VIDEO, diff --git a/libavcodec/mpegvideoencdsp.c b/libavcodec/mpegvideoencdsp.c index 0af3d8bef8b8a..a34ab3553e37a 100644 --- a/libavcodec/mpegvideoencdsp.c +++ b/libavcodec/mpegvideoencdsp.c @@ -81,7 +81,7 @@ static int pix_sum_c(uint8_t *pix, int line_size) static int pix_norm1_c(uint8_t *pix, int line_size) { int s = 0, i, j; - uint32_t *sq = ff_square_tab + 256; + const uint32_t *sq = ff_square_tab + 256; for (i = 0; i < 16; i++) { for (j = 0; j < 16; j += 8) { diff --git a/libavcodec/msmpeg4dec.c b/libavcodec/msmpeg4dec.c index 4105d4ba7d061..457a37e745806 100644 --- a/libavcodec/msmpeg4dec.c +++ b/libavcodec/msmpeg4dec.c @@ -208,6 +208,9 @@ static int msmpeg4v34_decode_mb(MpegEncContext *s, int16_t block[6][64]) uint8_t *coded_val; uint32_t * const mb_type_ptr = &s->current_picture.mb_type[s->mb_x + s->mb_y*s->mb_stride]; + if (get_bits_left(&s->gb) <= 0) + return AVERROR_INVALIDDATA; + if (s->pict_type == AV_PICTURE_TYPE_P) { if (s->use_skip_mb_code) { if (get_bits1(&s->gb)) { diff --git a/libavcodec/mss2.c b/libavcodec/mss2.c index 9e7cc466decd6..3180af1d607bd 100644 --- a/libavcodec/mss2.c +++ b/libavcodec/mss2.c @@ -464,9 +464,9 @@ static int decode_wmv9(AVCodecContext *avctx, const uint8_t *buf, int buf_size, return 0; } -typedef struct Rectangle { +struct Rectangle { int coded, x, y, w, h; -} Rectangle; +}; #define MAX_WMV9_RECTANGLES 20 #define ARITH2_PADDING 2 @@ -485,7 +485,7 @@ static int mss2_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, int keyframe, has_wmv9, has_mv, is_rle, is_555, ret; - Rectangle wmv9rects[MAX_WMV9_RECTANGLES], *r; + struct Rectangle wmv9rects[MAX_WMV9_RECTANGLES], *r; int used_rects = 0, i, implicit_rect = 0, av_uninit(wmv9_mask); if ((ret = init_get_bits8(&gb, buf, buf_size)) < 0) diff --git a/libavcodec/noise_bsf.c b/libavcodec/noise_bsf.c index 84b94032ad3f3..d79f63b77797e 100644 --- a/libavcodec/noise_bsf.c +++ b/libavcodec/noise_bsf.c @@ -35,52 +35,46 @@ typedef struct NoiseContext { unsigned int state; } NoiseContext; -static int noise(AVBSFContext *ctx, AVPacket *out) +static int noise(AVBSFContext *ctx, AVPacket *pkt) { NoiseContext *s = ctx->priv_data; - AVPacket *in; int amount = s->amount > 0 ? s->amount : (s->state % 10001 + 1); int i, ret = 0; if (amount <= 0) return AVERROR(EINVAL); - ret = ff_bsf_get_packet(ctx, &in); + ret = ff_bsf_get_packet_ref(ctx, pkt); if (ret < 0) return ret; if (s->dropamount > 0 && s->state % s->dropamount == 0) { s->state++; - av_packet_free(&in); + av_packet_unref(pkt); return AVERROR(EAGAIN); } - ret = av_new_packet(out, in->size); + ret = av_packet_make_writable(pkt); if (ret < 0) goto fail; - ret = av_packet_copy_props(out, in); - if (ret < 0) - goto fail; - - memcpy(out->data, in->data, in->size); - - for (i = 0; i < out->size; i++) { - s->state += out->data[i] + 1; + for (i = 0; i < pkt->size; i++) { + s->state += pkt->data[i] + 1; if (s->state % amount == 0) - out->data[i] = s->state; + pkt->data[i] = s->state; } fail: if (ret < 0) - av_packet_unref(out); - av_packet_free(&in); + av_packet_unref(pkt); + return ret; } #define OFFSET(x) offsetof(NoiseContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_BSF_PARAM) static const AVOption options[] = { - { "amount", NULL, OFFSET(amount), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX }, - { "dropamount", NULL, OFFSET(dropamount), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX }, + { "amount", NULL, OFFSET(amount), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, + { "dropamount", NULL, OFFSET(dropamount), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, { NULL }, }; diff --git a/libavcodec/null_bsf.c b/libavcodec/null_bsf.c index feb71248a970d..24d26dfb1aad9 100644 --- a/libavcodec/null_bsf.c +++ b/libavcodec/null_bsf.c @@ -24,17 +24,9 @@ #include "avcodec.h" #include "bsf.h" -static int null_filter(AVBSFContext *ctx, AVPacket *out) +static int null_filter(AVBSFContext *ctx, AVPacket *pkt) { - AVPacket *in; - int ret; - - ret = ff_bsf_get_packet(ctx, &in); - if (ret < 0) - return ret; - av_packet_move_ref(out, in); - av_packet_free(&in); - return 0; + return ff_bsf_get_packet_ref(ctx, pkt); } const AVBitStreamFilter ff_null_bsf = { diff --git a/libavcodec/nuv.c b/libavcodec/nuv.c index ad6c029e5005f..32ed65899b13d 100644 --- a/libavcodec/nuv.c +++ b/libavcodec/nuv.c @@ -161,6 +161,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, int orig_size = buf_size; int keyframe, ret; int size_change = 0; + int minsize = 0; int result, init_frame = !avctx->frame_number; enum { NUV_UNCOMPRESSED = '0', @@ -198,6 +199,9 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, case NUV_RTJPEG_IN_LZO: case NUV_RTJPEG: keyframe = !buf[2]; + if (c->width < 16 || c->height < 16) { + return AVERROR_INVALIDDATA; + } break; case NUV_COPY_LAST: keyframe = 0; @@ -206,6 +210,16 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, keyframe = 1; break; } + switch (comptype) { + case NUV_UNCOMPRESSED: + minsize = c->width * c->height * 3 / 2; + break; + case NUV_RTJPEG: + minsize = c->width/16 * (c->height/16) * 6; + break; + } + if (buf_size < minsize / 4) + return AVERROR_INVALIDDATA; retry: // Skip the rest of the frame header. buf = &buf[12]; diff --git a/libavcodec/nvdec.c b/libavcodec/nvdec.c new file mode 100644 index 0000000000000..ab3cb88b27589 --- /dev/null +++ b/libavcodec/nvdec.c @@ -0,0 +1,584 @@ +/* + * HW decode acceleration through NVDEC + * + * Copyright (c) 2016 Anton Khirnov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "libavutil/common.h" +#include "libavutil/error.h" +#include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_cuda_internal.h" +#include "libavutil/pixdesc.h" +#include "libavutil/pixfmt.h" + +#include "avcodec.h" +#include "decode.h" +#include "nvdec.h" +#include "internal.h" + +typedef struct NVDECDecoder { + CUvideodecoder decoder; + + AVBufferRef *hw_device_ref; + CUcontext cuda_ctx; + + CudaFunctions *cudl; + CuvidFunctions *cvdl; +} NVDECDecoder; + +typedef struct NVDECFramePool { + unsigned int dpb_size; + unsigned int nb_allocated; +} NVDECFramePool; + +static int map_avcodec_id(enum AVCodecID id) +{ + switch (id) { + case AV_CODEC_ID_H264: return cudaVideoCodec_H264; + case AV_CODEC_ID_HEVC: return cudaVideoCodec_HEVC; + case AV_CODEC_ID_MJPEG: return cudaVideoCodec_JPEG; + case AV_CODEC_ID_MPEG1VIDEO: return cudaVideoCodec_MPEG1; + case AV_CODEC_ID_MPEG2VIDEO: return cudaVideoCodec_MPEG2; + case AV_CODEC_ID_MPEG4: return cudaVideoCodec_MPEG4; + case AV_CODEC_ID_VC1: return cudaVideoCodec_VC1; + case AV_CODEC_ID_VP8: return cudaVideoCodec_VP8; + case AV_CODEC_ID_VP9: return cudaVideoCodec_VP9; + case AV_CODEC_ID_WMV3: return cudaVideoCodec_VC1; + } + return -1; +} + +static int map_chroma_format(enum AVPixelFormat pix_fmt) +{ + int shift_h = 0, shift_v = 0; + + av_pix_fmt_get_chroma_sub_sample(pix_fmt, &shift_h, &shift_v); + + if (shift_h == 1 && shift_v == 1) + return cudaVideoChromaFormat_420; + else if (shift_h == 1 && shift_v == 0) + return cudaVideoChromaFormat_422; + else if (shift_h == 0 && shift_v == 0) + return cudaVideoChromaFormat_444; + + return -1; +} + +static int nvdec_test_capabilities(NVDECDecoder *decoder, + CUVIDDECODECREATEINFO *params, void *logctx) +{ + CUresult err; + CUVIDDECODECAPS caps = { 0 }; + + caps.eCodecType = params->CodecType; + caps.eChromaFormat = params->ChromaFormat; + caps.nBitDepthMinus8 = params->bitDepthMinus8; + + if (!decoder->cvdl->cuvidGetDecoderCaps) { + av_log(logctx, AV_LOG_WARNING, "Used Nvidia driver is too old to perform a capability check.\n"); + av_log(logctx, AV_LOG_WARNING, "The minimum required version is " +#if defined(_WIN32) || defined(__CYGWIN__) + "378.66" +#else + "378.13" +#endif + ". Continuing blind.\n"); + return 0; + } + + err = decoder->cvdl->cuvidGetDecoderCaps(&caps); + if (err != CUDA_SUCCESS) { + av_log(logctx, AV_LOG_ERROR, "Failed querying decoder capabilities\n"); + return AVERROR_UNKNOWN; + } + + av_log(logctx, AV_LOG_VERBOSE, "NVDEC capabilities:\n"); + av_log(logctx, AV_LOG_VERBOSE, "format supported: %s, max_mb_count: %d\n", + caps.bIsSupported ? "yes" : "no", caps.nMaxMBCount); + av_log(logctx, AV_LOG_VERBOSE, "min_width: %d, max_width: %d\n", + caps.nMinWidth, caps.nMaxWidth); + av_log(logctx, AV_LOG_VERBOSE, "min_height: %d, max_height: %d\n", + caps.nMinHeight, caps.nMaxHeight); + + if (!caps.bIsSupported) { + av_log(logctx, AV_LOG_ERROR, "Hardware is lacking required capabilities\n"); + return AVERROR(EINVAL); + } + + if (params->ulWidth > caps.nMaxWidth || params->ulWidth < caps.nMinWidth) { + av_log(logctx, AV_LOG_ERROR, "Video width %d not within range from %d to %d\n", + (int)params->ulWidth, caps.nMinWidth, caps.nMaxWidth); + return AVERROR(EINVAL); + } + + if (params->ulHeight > caps.nMaxHeight || params->ulHeight < caps.nMinHeight) { + av_log(logctx, AV_LOG_ERROR, "Video height %d not within range from %d to %d\n", + (int)params->ulHeight, caps.nMinHeight, caps.nMaxHeight); + return AVERROR(EINVAL); + } + + if ((params->ulWidth * params->ulHeight) / 256 > caps.nMaxMBCount) { + av_log(logctx, AV_LOG_ERROR, "Video macroblock count %d exceeds maximum of %d\n", + (int)(params->ulWidth * params->ulHeight) / 256, caps.nMaxMBCount); + return AVERROR(EINVAL); + } + + return 0; +} + +static void nvdec_decoder_free(void *opaque, uint8_t *data) +{ + NVDECDecoder *decoder = (NVDECDecoder*)data; + + if (decoder->decoder) + decoder->cvdl->cuvidDestroyDecoder(decoder->decoder); + + av_buffer_unref(&decoder->hw_device_ref); + + cuvid_free_functions(&decoder->cvdl); + + av_freep(&decoder); +} + +static int nvdec_decoder_create(AVBufferRef **out, AVBufferRef *hw_device_ref, + CUVIDDECODECREATEINFO *params, void *logctx) +{ + AVHWDeviceContext *hw_device_ctx = (AVHWDeviceContext*)hw_device_ref->data; + AVCUDADeviceContext *device_hwctx = hw_device_ctx->hwctx; + + AVBufferRef *decoder_ref; + NVDECDecoder *decoder; + + CUcontext dummy; + CUresult err; + int ret; + + decoder = av_mallocz(sizeof(*decoder)); + if (!decoder) + return AVERROR(ENOMEM); + + decoder_ref = av_buffer_create((uint8_t*)decoder, sizeof(*decoder), + nvdec_decoder_free, NULL, AV_BUFFER_FLAG_READONLY); + if (!decoder_ref) { + av_freep(&decoder); + return AVERROR(ENOMEM); + } + + decoder->hw_device_ref = av_buffer_ref(hw_device_ref); + if (!decoder->hw_device_ref) { + ret = AVERROR(ENOMEM); + goto fail; + } + decoder->cuda_ctx = device_hwctx->cuda_ctx; + decoder->cudl = device_hwctx->internal->cuda_dl; + + ret = cuvid_load_functions(&decoder->cvdl, logctx); + if (ret < 0) { + av_log(logctx, AV_LOG_ERROR, "Failed loading nvcuvid.\n"); + goto fail; + } + + err = decoder->cudl->cuCtxPushCurrent(decoder->cuda_ctx); + if (err != CUDA_SUCCESS) { + ret = AVERROR_UNKNOWN; + goto fail; + } + + ret = nvdec_test_capabilities(decoder, params, logctx); + if (ret < 0) { + decoder->cudl->cuCtxPopCurrent(&dummy); + goto fail; + } + + err = decoder->cvdl->cuvidCreateDecoder(&decoder->decoder, params); + + decoder->cudl->cuCtxPopCurrent(&dummy); + + if (err != CUDA_SUCCESS) { + av_log(logctx, AV_LOG_ERROR, "Error creating a NVDEC decoder: %d\n", err); + ret = AVERROR_UNKNOWN; + goto fail; + } + + *out = decoder_ref; + + return 0; +fail: + av_buffer_unref(&decoder_ref); + return ret; +} + +static AVBufferRef *nvdec_decoder_frame_alloc(void *opaque, int size) +{ + NVDECFramePool *pool = opaque; + AVBufferRef *ret; + + if (pool->nb_allocated >= pool->dpb_size) + return NULL; + + ret = av_buffer_alloc(sizeof(unsigned int)); + if (!ret) + return NULL; + + *(unsigned int*)ret->data = pool->nb_allocated++; + + return ret; +} + +int ff_nvdec_decode_uninit(AVCodecContext *avctx) +{ + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + + av_freep(&ctx->bitstream); + ctx->bitstream_len = 0; + ctx->bitstream_allocated = 0; + + av_freep(&ctx->slice_offsets); + ctx->nb_slices = 0; + ctx->slice_offsets_allocated = 0; + + av_buffer_unref(&ctx->decoder_ref); + av_buffer_pool_uninit(&ctx->decoder_pool); + + return 0; +} + +int ff_nvdec_decode_init(AVCodecContext *avctx) +{ + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + + NVDECFramePool *pool; + AVHWFramesContext *frames_ctx; + const AVPixFmtDescriptor *sw_desc; + + CUVIDDECODECREATEINFO params = { 0 }; + + int cuvid_codec_type, cuvid_chroma_format; + int ret = 0; + + sw_desc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); + if (!sw_desc) + return AVERROR_BUG; + + cuvid_codec_type = map_avcodec_id(avctx->codec_id); + if (cuvid_codec_type < 0) { + av_log(avctx, AV_LOG_ERROR, "Unsupported codec ID\n"); + return AVERROR_BUG; + } + + cuvid_chroma_format = map_chroma_format(avctx->sw_pix_fmt); + if (cuvid_chroma_format < 0) { + av_log(avctx, AV_LOG_ERROR, "Unsupported chroma format\n"); + return AVERROR(ENOSYS); + } + + if (!avctx->hw_frames_ctx) { + ret = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_CUDA); + if (ret < 0) + return ret; + } + + frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + + params.ulWidth = avctx->coded_width; + params.ulHeight = avctx->coded_height; + params.ulTargetWidth = avctx->coded_width; + params.ulTargetHeight = avctx->coded_height; + params.bitDepthMinus8 = sw_desc->comp[0].depth - 8; + params.OutputFormat = params.bitDepthMinus8 ? + cudaVideoSurfaceFormat_P016 : cudaVideoSurfaceFormat_NV12; + params.CodecType = cuvid_codec_type; + params.ChromaFormat = cuvid_chroma_format; + params.ulNumDecodeSurfaces = frames_ctx->initial_pool_size; + params.ulNumOutputSurfaces = 1; + + ret = nvdec_decoder_create(&ctx->decoder_ref, frames_ctx->device_ref, ¶ms, avctx); + if (ret < 0) { + if (params.ulNumDecodeSurfaces > 32) { + av_log(avctx, AV_LOG_WARNING, "Using more than 32 (%d) decode surfaces might cause nvdec to fail.\n", + (int)params.ulNumDecodeSurfaces); + av_log(avctx, AV_LOG_WARNING, "Try lowering the amount of threads. Using %d right now.\n", + avctx->thread_count); + } + return ret; + } + + pool = av_mallocz(sizeof(*pool)); + if (!pool) { + ret = AVERROR(ENOMEM); + goto fail; + } + pool->dpb_size = frames_ctx->initial_pool_size; + + ctx->decoder_pool = av_buffer_pool_init2(sizeof(int), pool, + nvdec_decoder_frame_alloc, av_free); + if (!ctx->decoder_pool) { + ret = AVERROR(ENOMEM); + goto fail; + } + + return 0; +fail: + ff_nvdec_decode_uninit(avctx); + return ret; +} + +static void nvdec_fdd_priv_free(void *priv) +{ + NVDECFrame *cf = priv; + + if (!cf) + return; + + av_buffer_unref(&cf->idx_ref); + av_buffer_unref(&cf->decoder_ref); + + av_freep(&priv); +} + +static int nvdec_retrieve_data(void *logctx, AVFrame *frame) +{ + FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data; + NVDECFrame *cf = (NVDECFrame*)fdd->hwaccel_priv; + NVDECDecoder *decoder = (NVDECDecoder*)cf->decoder_ref->data; + + CUVIDPROCPARAMS vpp = { .progressive_frame = 1 }; + + CUresult err; + CUcontext dummy; + CUdeviceptr devptr; + + unsigned int pitch, i; + unsigned int offset = 0; + int ret = 0; + + err = decoder->cudl->cuCtxPushCurrent(decoder->cuda_ctx); + if (err != CUDA_SUCCESS) + return AVERROR_UNKNOWN; + + err = decoder->cvdl->cuvidMapVideoFrame(decoder->decoder, cf->idx, &devptr, + &pitch, &vpp); + if (err != CUDA_SUCCESS) { + av_log(logctx, AV_LOG_ERROR, "Error mapping a picture with CUVID: %d\n", + err); + ret = AVERROR_UNKNOWN; + goto finish; + } + + for (i = 0; frame->data[i]; i++) { + CUDA_MEMCPY2D cpy = { + .srcMemoryType = CU_MEMORYTYPE_DEVICE, + .dstMemoryType = CU_MEMORYTYPE_DEVICE, + .srcDevice = devptr, + .dstDevice = (CUdeviceptr)frame->data[i], + .srcPitch = pitch, + .dstPitch = frame->linesize[i], + .srcY = offset, + .WidthInBytes = FFMIN(pitch, frame->linesize[i]), + .Height = frame->height >> (i ? 1 : 0), + }; + + err = decoder->cudl->cuMemcpy2D(&cpy); + if (err != CUDA_SUCCESS) { + av_log(logctx, AV_LOG_ERROR, "Error copying decoded frame: %d\n", + err); + ret = AVERROR_UNKNOWN; + goto copy_fail; + } + + offset += cpy.Height; + } + +copy_fail: + decoder->cvdl->cuvidUnmapVideoFrame(decoder->decoder, devptr); + +finish: + decoder->cudl->cuCtxPopCurrent(&dummy); + return ret; +} + +int ff_nvdec_start_frame(AVCodecContext *avctx, AVFrame *frame) +{ + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + FrameDecodeData *fdd = (FrameDecodeData*)frame->private_ref->data; + NVDECFrame *cf = NULL; + int ret; + + ctx->bitstream_len = 0; + ctx->nb_slices = 0; + + if (fdd->hwaccel_priv) + return 0; + + cf = av_mallocz(sizeof(*cf)); + if (!cf) + return AVERROR(ENOMEM); + + cf->decoder_ref = av_buffer_ref(ctx->decoder_ref); + if (!cf->decoder_ref) { + ret = AVERROR(ENOMEM); + goto fail; + } + + cf->idx_ref = av_buffer_pool_get(ctx->decoder_pool); + if (!cf->idx_ref) { + av_log(avctx, AV_LOG_ERROR, "No decoder surfaces left\n"); + ret = AVERROR(ENOMEM); + goto fail; + } + cf->idx = *(unsigned int*)cf->idx_ref->data; + + fdd->hwaccel_priv = cf; + fdd->hwaccel_priv_free = nvdec_fdd_priv_free; + fdd->post_process = nvdec_retrieve_data; + + return 0; +fail: + nvdec_fdd_priv_free(cf); + return ret; + +} + +int ff_nvdec_end_frame(AVCodecContext *avctx) +{ + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + NVDECDecoder *decoder = (NVDECDecoder*)ctx->decoder_ref->data; + CUVIDPICPARAMS *pp = &ctx->pic_params; + + CUresult err; + CUcontext dummy; + + int ret = 0; + + pp->nBitstreamDataLen = ctx->bitstream_len; + pp->pBitstreamData = ctx->bitstream; + pp->nNumSlices = ctx->nb_slices; + pp->pSliceDataOffsets = ctx->slice_offsets; + + err = decoder->cudl->cuCtxPushCurrent(decoder->cuda_ctx); + if (err != CUDA_SUCCESS) + return AVERROR_UNKNOWN; + + err = decoder->cvdl->cuvidDecodePicture(decoder->decoder, &ctx->pic_params); + if (err != CUDA_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Error decoding a picture with NVDEC: %d\n", + err); + ret = AVERROR_UNKNOWN; + goto finish; + } + +finish: + decoder->cudl->cuCtxPopCurrent(&dummy); + + return ret; +} + +int ff_nvdec_simple_end_frame(AVCodecContext *avctx) +{ + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + int ret = ff_nvdec_end_frame(avctx); + ctx->bitstream = NULL; + return ret; +} + +int ff_nvdec_simple_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, + uint32_t size) +{ + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + void *tmp; + + tmp = av_fast_realloc(ctx->slice_offsets, &ctx->slice_offsets_allocated, + (ctx->nb_slices + 1) * sizeof(*ctx->slice_offsets)); + if (!tmp) + return AVERROR(ENOMEM); + ctx->slice_offsets = tmp; + + if (!ctx->bitstream) + ctx->bitstream = (uint8_t*)buffer; + + ctx->slice_offsets[ctx->nb_slices] = buffer - ctx->bitstream; + ctx->bitstream_len += size; + ctx->nb_slices++; + + return 0; +} + +int ff_nvdec_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx, + int dpb_size) +{ + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hw_frames_ctx->data; + const AVPixFmtDescriptor *sw_desc; + int cuvid_codec_type, cuvid_chroma_format; + + sw_desc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); + if (!sw_desc) + return AVERROR_BUG; + + cuvid_codec_type = map_avcodec_id(avctx->codec_id); + if (cuvid_codec_type < 0) { + av_log(avctx, AV_LOG_ERROR, "Unsupported codec ID\n"); + return AVERROR_BUG; + } + + cuvid_chroma_format = map_chroma_format(avctx->sw_pix_fmt); + if (cuvid_chroma_format < 0) { + av_log(avctx, AV_LOG_VERBOSE, "Unsupported chroma format\n"); + return AVERROR(EINVAL); + } + + frames_ctx->format = AV_PIX_FMT_CUDA; + frames_ctx->width = (avctx->coded_width + 1) & ~1; + frames_ctx->height = (avctx->coded_height + 1) & ~1; + frames_ctx->initial_pool_size = dpb_size; + + switch (sw_desc->comp[0].depth) { + case 8: + frames_ctx->sw_format = AV_PIX_FMT_NV12; + break; + case 10: + frames_ctx->sw_format = AV_PIX_FMT_P010; + break; + case 12: + frames_ctx->sw_format = AV_PIX_FMT_P016; + break; + default: + return AVERROR(EINVAL); + } + + return 0; +} + +int ff_nvdec_get_ref_idx(AVFrame *frame) +{ + FrameDecodeData *fdd; + NVDECFrame *cf; + + if (!frame || !frame->private_ref) + return -1; + + fdd = (FrameDecodeData*)frame->private_ref->data; + cf = (NVDECFrame*)fdd->hwaccel_priv; + if (!cf) + return -1; + + return cf->idx; +} diff --git a/libavcodec/nvdec.h b/libavcodec/nvdec.h new file mode 100644 index 0000000000000..85a0fcf7259cb --- /dev/null +++ b/libavcodec/nvdec.h @@ -0,0 +1,78 @@ +/* + * HW decode acceleration through NVDEC + * + * Copyright (c) 2016 Anton Khirnov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_NVDEC_H +#define AVCODEC_NVDEC_H + +#include "compat/cuda/dynlink_loader.h" + +#include + +#include "libavutil/buffer.h" +#include "libavutil/frame.h" + +#include "avcodec.h" + +#if defined(NVDECAPI_MAJOR_VERSION) && defined(NVDECAPI_MINOR_VERSION) +# define NVDECAPI_CHECK_VERSION(major, minor) \ + ((major) < NVDECAPI_MAJOR_VERSION || ((major) == NVDECAPI_MAJOR_VERSION && (minor) <= NVDECAPI_MINOR_VERSION)) +#else +/* version macros were added in SDK 8.1 ffnvcodec */ +# define NVDECAPI_CHECK_VERSION(major, minor) \ + ((major) < 8 || ((major) == 8 && (minor) <= 0)) +#endif + +typedef struct NVDECFrame { + unsigned int idx; + AVBufferRef *idx_ref; + AVBufferRef *decoder_ref; +} NVDECFrame; + +typedef struct NVDECContext { + CUVIDPICPARAMS pic_params; + + AVBufferPool *decoder_pool; + + AVBufferRef *decoder_ref; + + uint8_t *bitstream; + int bitstream_len; + unsigned int bitstream_allocated; + + unsigned *slice_offsets; + int nb_slices; + unsigned int slice_offsets_allocated; +} NVDECContext; + +int ff_nvdec_decode_init(AVCodecContext *avctx); +int ff_nvdec_decode_uninit(AVCodecContext *avctx); +int ff_nvdec_start_frame(AVCodecContext *avctx, AVFrame *frame); +int ff_nvdec_end_frame(AVCodecContext *avctx); +int ff_nvdec_simple_end_frame(AVCodecContext *avctx); +int ff_nvdec_simple_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, + uint32_t size); +int ff_nvdec_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx, + int dpb_size); +int ff_nvdec_get_ref_idx(AVFrame *frame); + +#endif /* AVCODEC_NVDEC_H */ diff --git a/libavcodec/nvdec_h264.c b/libavcodec/nvdec_h264.c new file mode 100644 index 0000000000000..25b30329d0eff --- /dev/null +++ b/libavcodec/nvdec_h264.c @@ -0,0 +1,184 @@ +/* + * MPEG-4 Part 10 / AVC / H.264 HW decode acceleration through NVDEC + * + * Copyright (c) 2016 Anton Khirnov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "avcodec.h" +#include "nvdec.h" +#include "decode.h" +#include "internal.h" +#include "h264dec.h" + +static void dpb_add(const H264Context *h, CUVIDH264DPBENTRY *dst, const H264Picture *src, + int frame_idx) +{ + FrameDecodeData *fdd = (FrameDecodeData*)src->f->private_ref->data; + const NVDECFrame *cf = fdd->hwaccel_priv; + + dst->PicIdx = cf ? cf->idx : -1; + dst->FrameIdx = frame_idx; + dst->is_long_term = src->long_ref; + dst->not_existing = 0; + dst->used_for_reference = src->reference & 3; + dst->FieldOrderCnt[0] = src->field_poc[0]; + dst->FieldOrderCnt[1] = src->field_poc[1]; +} + +static int nvdec_h264_start_frame(AVCodecContext *avctx, + const uint8_t *buffer, uint32_t size) +{ + const H264Context *h = avctx->priv_data; + const PPS *pps = h->ps.pps; + const SPS *sps = h->ps.sps; + + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + CUVIDPICPARAMS *pp = &ctx->pic_params; + CUVIDH264PICPARAMS *ppc = &pp->CodecSpecific.h264; + FrameDecodeData *fdd; + NVDECFrame *cf; + + int i, dpb_size, ret; + + ret = ff_nvdec_start_frame(avctx, h->cur_pic_ptr->f); + if (ret < 0) + return ret; + + fdd = (FrameDecodeData*)h->cur_pic_ptr->f->private_ref->data; + cf = (NVDECFrame*)fdd->hwaccel_priv; + + *pp = (CUVIDPICPARAMS) { + .PicWidthInMbs = h->mb_width, + .FrameHeightInMbs = h->mb_height, + .CurrPicIdx = cf->idx, + .field_pic_flag = FIELD_PICTURE(h), + .bottom_field_flag = h->picture_structure == PICT_BOTTOM_FIELD, + .second_field = FIELD_PICTURE(h) && !h->first_field, + .ref_pic_flag = h->nal_ref_idc != 0, + .intra_pic_flag = 1, + + .CodecSpecific.h264 = { + .log2_max_frame_num_minus4 = sps->log2_max_frame_num - 4, + .pic_order_cnt_type = sps->poc_type, + .log2_max_pic_order_cnt_lsb_minus4 = FFMAX(sps->log2_max_poc_lsb - 4, 0), + .delta_pic_order_always_zero_flag = sps->delta_pic_order_always_zero_flag, + .frame_mbs_only_flag = sps->frame_mbs_only_flag, + .direct_8x8_inference_flag = sps->direct_8x8_inference_flag, + .num_ref_frames = sps->ref_frame_count, + .residual_colour_transform_flag = sps->residual_color_transform_flag, + .bit_depth_luma_minus8 = sps->bit_depth_luma - 8, + .bit_depth_chroma_minus8 = sps->bit_depth_chroma - 8, + .qpprime_y_zero_transform_bypass_flag = sps->transform_bypass, + + .entropy_coding_mode_flag = pps->cabac, + .pic_order_present_flag = pps->pic_order_present, + .num_ref_idx_l0_active_minus1 = pps->ref_count[0] - 1, + .num_ref_idx_l1_active_minus1 = pps->ref_count[1] - 1, + .weighted_pred_flag = pps->weighted_pred, + .weighted_bipred_idc = pps->weighted_bipred_idc, + .pic_init_qp_minus26 = pps->init_qp - 26, + .deblocking_filter_control_present_flag = pps->deblocking_filter_parameters_present, + .redundant_pic_cnt_present_flag = pps->redundant_pic_cnt_present, + .transform_8x8_mode_flag = pps->transform_8x8_mode, + .MbaffFrameFlag = sps->mb_aff && !FIELD_PICTURE(h), + .constrained_intra_pred_flag = pps->constrained_intra_pred, + .chroma_qp_index_offset = pps->chroma_qp_index_offset[0], + .second_chroma_qp_index_offset = pps->chroma_qp_index_offset[1], + .ref_pic_flag = h->nal_ref_idc != 0, + .frame_num = h->poc.frame_num, + .CurrFieldOrderCnt[0] = h->cur_pic_ptr->field_poc[0], + .CurrFieldOrderCnt[1] = h->cur_pic_ptr->field_poc[1], + }, + }; + + memcpy(ppc->WeightScale4x4, pps->scaling_matrix4, sizeof(ppc->WeightScale4x4)); + memcpy(ppc->WeightScale8x8[0], pps->scaling_matrix8[0], sizeof(ppc->WeightScale8x8[0])); + memcpy(ppc->WeightScale8x8[1], pps->scaling_matrix8[3], sizeof(ppc->WeightScale8x8[0])); + + dpb_size = 0; + for (i = 0; i < h->short_ref_count; i++) + dpb_add(h, &ppc->dpb[dpb_size++], h->short_ref[i], h->short_ref[i]->frame_num); + for (i = 0; i < 16; i++) { + if (h->long_ref[i]) + dpb_add(h, &ppc->dpb[dpb_size++], h->long_ref[i], i); + } + + for (i = dpb_size; i < FF_ARRAY_ELEMS(ppc->dpb); i++) + ppc->dpb[i].PicIdx = -1; + + return 0; +} + +static int nvdec_h264_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, + uint32_t size) +{ + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + CUVIDPICPARAMS *pp = &ctx->pic_params; + const H264Context *h = avctx->priv_data; + const H264SliceContext *sl = &h->slice_ctx[0]; + void *tmp; + + tmp = av_fast_realloc(ctx->bitstream, &ctx->bitstream_allocated, + ctx->bitstream_len + size + 3); + if (!tmp) + return AVERROR(ENOMEM); + ctx->bitstream = tmp; + + tmp = av_fast_realloc(ctx->slice_offsets, &ctx->slice_offsets_allocated, + (ctx->nb_slices + 1) * sizeof(*ctx->slice_offsets)); + if (!tmp) + return AVERROR(ENOMEM); + ctx->slice_offsets = tmp; + + AV_WB24(ctx->bitstream + ctx->bitstream_len, 1); + memcpy(ctx->bitstream + ctx->bitstream_len + 3, buffer, size); + ctx->slice_offsets[ctx->nb_slices] = ctx->bitstream_len ; + ctx->bitstream_len += size + 3; + ctx->nb_slices++; + + if (sl->slice_type != AV_PICTURE_TYPE_I && sl->slice_type != AV_PICTURE_TYPE_SI) + pp->intra_pic_flag = 0; + + return 0; +} + +static int nvdec_h264_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx) +{ + const H264Context *h = avctx->priv_data; + const SPS *sps = h->ps.sps; + return ff_nvdec_frame_params(avctx, hw_frames_ctx, sps->ref_frame_count + sps->num_reorder_frames); +} + +const AVHWAccel ff_h264_nvdec_hwaccel = { + .name = "h264_nvdec", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_H264, + .pix_fmt = AV_PIX_FMT_CUDA, + .start_frame = nvdec_h264_start_frame, + .end_frame = ff_nvdec_end_frame, + .decode_slice = nvdec_h264_decode_slice, + .frame_params = nvdec_h264_frame_params, + .init = ff_nvdec_decode_init, + .uninit = ff_nvdec_decode_uninit, + .priv_data_size = sizeof(NVDECContext), +}; diff --git a/libavcodec/nvdec_hevc.c b/libavcodec/nvdec_hevc.c new file mode 100644 index 0000000000000..008963130b018 --- /dev/null +++ b/libavcodec/nvdec_hevc.c @@ -0,0 +1,287 @@ +/* + * HEVC HW decode acceleration through NVDEC + * + * Copyright (c) 2017 Anton Khirnov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "avcodec.h" +#include "nvdec.h" +#include "decode.h" +#include "internal.h" +#include "hevcdec.h" +#include "hevc_data.h" + +static void dpb_add(CUVIDHEVCPICPARAMS *pp, int idx, const HEVCFrame *src) +{ + FrameDecodeData *fdd = (FrameDecodeData*)src->frame->private_ref->data; + const NVDECFrame *cf = fdd->hwaccel_priv; + + pp->RefPicIdx[idx] = cf ? cf->idx : -1; + pp->PicOrderCntVal[idx] = src->poc; + pp->IsLongTerm[idx] = !!(src->flags & HEVC_FRAME_FLAG_LONG_REF); +} + +static void fill_scaling_lists(CUVIDHEVCPICPARAMS *ppc, const HEVCContext *s) +{ + const ScalingList *sl = s->ps.pps->scaling_list_data_present_flag ? + &s->ps.pps->scaling_list : &s->ps.sps->scaling_list; + int i, j, pos; + + for (i = 0; i < 6; i++) { + for (j = 0; j < 16; j++) { + pos = 4 * ff_hevc_diag_scan4x4_y[j] + ff_hevc_diag_scan4x4_x[j]; + ppc->ScalingList4x4[i][j] = sl->sl[0][i][pos]; + } + + for (j = 0; j < 64; j++) { + pos = 8 * ff_hevc_diag_scan8x8_y[j] + ff_hevc_diag_scan8x8_x[j]; + ppc->ScalingList8x8[i][j] = sl->sl[1][i][pos]; + ppc->ScalingList16x16[i][j] = sl->sl[2][i][pos]; + + if (i < 2) + ppc->ScalingList32x32[i][j] = sl->sl[3][i][pos]; + } + } + + memcpy(ppc->ScalingListDCCoeff16x16, sl->sl_dc[0], sizeof(ppc->ScalingListDCCoeff16x16)); + memcpy(ppc->ScalingListDCCoeff32x32, sl->sl_dc[1], sizeof(ppc->ScalingListDCCoeff32x32)); +} + +static int nvdec_hevc_start_frame(AVCodecContext *avctx, + const uint8_t *buffer, uint32_t size) +{ + const HEVCContext *s = avctx->priv_data; + const HEVCPPS *pps = s->ps.pps; + const HEVCSPS *sps = s->ps.sps; + + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + CUVIDPICPARAMS *pp = &ctx->pic_params; + CUVIDHEVCPICPARAMS *ppc = &pp->CodecSpecific.hevc; + FrameDecodeData *fdd; + NVDECFrame *cf; + + int i, j, dpb_size, ret; + + ret = ff_nvdec_start_frame(avctx, s->ref->frame); + if (ret < 0) + return ret; + + fdd = (FrameDecodeData*)s->ref->frame->private_ref->data; + cf = (NVDECFrame*)fdd->hwaccel_priv; + + *pp = (CUVIDPICPARAMS) { + .PicWidthInMbs = sps->width / 16, + .FrameHeightInMbs = sps->height / 16, + .CurrPicIdx = cf->idx, + .ref_pic_flag = 1, + .intra_pic_flag = IS_IRAP(s), + + .CodecSpecific.hevc = { + .pic_width_in_luma_samples = sps->width, + .pic_height_in_luma_samples = sps->height, + .log2_min_luma_coding_block_size_minus3 = sps->log2_min_cb_size - 3, + .log2_diff_max_min_luma_coding_block_size = sps->log2_diff_max_min_coding_block_size, + .log2_min_transform_block_size_minus2 = sps->log2_min_tb_size - 2, + .log2_diff_max_min_transform_block_size = sps->log2_max_trafo_size - sps->log2_min_tb_size, + .pcm_enabled_flag = sps->pcm_enabled_flag, + .log2_min_pcm_luma_coding_block_size_minus3 = sps->pcm_enabled_flag ? sps->pcm.log2_min_pcm_cb_size - 3 : 0, + .log2_diff_max_min_pcm_luma_coding_block_size = sps->pcm.log2_max_pcm_cb_size - sps->pcm.log2_min_pcm_cb_size, + .pcm_sample_bit_depth_luma_minus1 = sps->pcm_enabled_flag ? sps->pcm.bit_depth - 1 : 0, + .pcm_sample_bit_depth_chroma_minus1 = sps->pcm_enabled_flag ? sps->pcm.bit_depth_chroma - 1 : 0, +#if NVDECAPI_CHECK_VERSION(8, 1) + .log2_max_transform_skip_block_size_minus2 = pps->log2_max_transform_skip_block_size - 2, + .log2_sao_offset_scale_luma = pps->log2_sao_offset_scale_luma, + .log2_sao_offset_scale_chroma = pps->log2_sao_offset_scale_chroma, + .high_precision_offsets_enabled_flag = sps->high_precision_offsets_enabled_flag, +#endif + .pcm_loop_filter_disabled_flag = sps->pcm.loop_filter_disable_flag, + .strong_intra_smoothing_enabled_flag = sps->sps_strong_intra_smoothing_enable_flag, + .max_transform_hierarchy_depth_intra = sps->max_transform_hierarchy_depth_intra, + .max_transform_hierarchy_depth_inter = sps->max_transform_hierarchy_depth_inter, + .amp_enabled_flag = sps->amp_enabled_flag, + .separate_colour_plane_flag = sps->separate_colour_plane_flag, + .log2_max_pic_order_cnt_lsb_minus4 = sps->log2_max_poc_lsb - 4, + .num_short_term_ref_pic_sets = sps->nb_st_rps, + .long_term_ref_pics_present_flag = sps->long_term_ref_pics_present_flag, + .num_long_term_ref_pics_sps = sps->num_long_term_ref_pics_sps, + .sps_temporal_mvp_enabled_flag = sps->sps_temporal_mvp_enabled_flag, + .sample_adaptive_offset_enabled_flag = sps->sao_enabled, + .scaling_list_enable_flag = sps->scaling_list_enable_flag, + .IrapPicFlag = IS_IRAP(s), + .IdrPicFlag = IS_IDR(s), + .bit_depth_luma_minus8 = sps->bit_depth - 8, + .bit_depth_chroma_minus8 = sps->bit_depth - 8, + + .dependent_slice_segments_enabled_flag = pps->dependent_slice_segments_enabled_flag, + .slice_segment_header_extension_present_flag = pps->slice_header_extension_present_flag, + .sign_data_hiding_enabled_flag = pps->sign_data_hiding_flag, + .cu_qp_delta_enabled_flag = pps->cu_qp_delta_enabled_flag, + .diff_cu_qp_delta_depth = pps->diff_cu_qp_delta_depth, + .init_qp_minus26 = pps->pic_init_qp_minus26, + .pps_cb_qp_offset = pps->cb_qp_offset, + .pps_cr_qp_offset = pps->cr_qp_offset, + .constrained_intra_pred_flag = pps->constrained_intra_pred_flag, + .weighted_pred_flag = pps->weighted_pred_flag, + .weighted_bipred_flag = pps->weighted_bipred_flag, + .transform_skip_enabled_flag = pps->transform_skip_enabled_flag, + .transquant_bypass_enabled_flag = pps->transquant_bypass_enable_flag, + .entropy_coding_sync_enabled_flag = pps->entropy_coding_sync_enabled_flag, + .log2_parallel_merge_level_minus2 = pps->log2_parallel_merge_level - 2, + .num_extra_slice_header_bits = pps->num_extra_slice_header_bits, + .loop_filter_across_tiles_enabled_flag = pps->loop_filter_across_tiles_enabled_flag, + .loop_filter_across_slices_enabled_flag = pps->seq_loop_filter_across_slices_enabled_flag, + .output_flag_present_flag = pps->output_flag_present_flag, + .num_ref_idx_l0_default_active_minus1 = pps->num_ref_idx_l0_default_active - 1, + .num_ref_idx_l1_default_active_minus1 = pps->num_ref_idx_l1_default_active - 1, + .lists_modification_present_flag = pps->lists_modification_present_flag, + .cabac_init_present_flag = pps->cabac_init_present_flag, + .pps_slice_chroma_qp_offsets_present_flag = pps->pic_slice_level_chroma_qp_offsets_present_flag, + .deblocking_filter_override_enabled_flag = pps->deblocking_filter_override_enabled_flag, + .pps_deblocking_filter_disabled_flag = pps->disable_dbf, + .pps_beta_offset_div2 = pps->beta_offset / 2, + .pps_tc_offset_div2 = pps->tc_offset / 2, + .tiles_enabled_flag = pps->tiles_enabled_flag, + .uniform_spacing_flag = pps->uniform_spacing_flag, + .num_tile_columns_minus1 = pps->num_tile_columns - 1, + .num_tile_rows_minus1 = pps->num_tile_rows - 1, + + .NumBitsForShortTermRPSInSlice = s->sh.short_term_rps ? s->sh.short_term_ref_pic_set_size : 0, + .NumDeltaPocsOfRefRpsIdx = s->sh.short_term_rps ? s->sh.short_term_rps->rps_idx_num_delta_pocs : 0, + .NumPocTotalCurr = s->rps[ST_CURR_BEF].nb_refs + s->rps[ST_CURR_AFT].nb_refs + + s->rps[LT_CURR].nb_refs, + .NumPocStCurrBefore = s->rps[ST_CURR_BEF].nb_refs, + .NumPocStCurrAfter = s->rps[ST_CURR_AFT].nb_refs, + .NumPocLtCurr = s->rps[LT_CURR].nb_refs, + .CurrPicOrderCntVal = s->ref->poc, + }, + }; + + if (pps->num_tile_columns > FF_ARRAY_ELEMS(ppc->column_width_minus1) || + pps->num_tile_rows > FF_ARRAY_ELEMS(ppc->row_height_minus1)) { + av_log(avctx, AV_LOG_ERROR, "Too many tiles\n"); + return AVERROR(ENOSYS); + } + for (i = 0; i < pps->num_tile_columns; i++) + ppc->column_width_minus1[i] = pps->column_width[i] - 1; + for (i = 0; i < pps->num_tile_rows; i++) + ppc->row_height_minus1[i] = pps->row_height[i] - 1; + + if (s->rps[LT_CURR].nb_refs > FF_ARRAY_ELEMS(ppc->RefPicSetLtCurr) || + s->rps[ST_CURR_BEF].nb_refs > FF_ARRAY_ELEMS(ppc->RefPicSetStCurrBefore) || + s->rps[ST_CURR_AFT].nb_refs > FF_ARRAY_ELEMS(ppc->RefPicSetStCurrAfter)) { + av_log(avctx, AV_LOG_ERROR, "Too many reference frames\n"); + return AVERROR(ENOSYS); + } + + dpb_size = 0; + for (i = 0; i < FF_ARRAY_ELEMS(s->DPB); i++) { + const HEVCFrame *ref = &s->DPB[i]; + if (!(ref->flags & (HEVC_FRAME_FLAG_SHORT_REF | HEVC_FRAME_FLAG_LONG_REF))) + continue; + if (dpb_size >= FF_ARRAY_ELEMS(ppc->RefPicIdx)) { + av_log(avctx, AV_LOG_ERROR, "Too many reference frames\n"); + return AVERROR_INVALIDDATA; + } + dpb_add(ppc, dpb_size++, ref); + + } + for (i = dpb_size; i < FF_ARRAY_ELEMS(ppc->RefPicIdx); i++) + ppc->RefPicIdx[i] = -1; + + for (i = 0; i < s->rps[ST_CURR_BEF].nb_refs; i++) { + for (j = 0; j < dpb_size; j++) { + if (ppc->PicOrderCntVal[j] == s->rps[ST_CURR_BEF].list[i]) { + ppc->RefPicSetStCurrBefore[i] = j; + break; + } + } + } + for (i = 0; i < s->rps[ST_CURR_AFT].nb_refs; i++) { + for (j = 0; j < dpb_size; j++) { + if (ppc->PicOrderCntVal[j] == s->rps[ST_CURR_AFT].list[i]) { + ppc->RefPicSetStCurrAfter[i] = j; + break; + } + } + } + for (i = 0; i < s->rps[LT_CURR].nb_refs; i++) { + for (j = 0; j < dpb_size; j++) { + if (ppc->PicOrderCntVal[j] == s->rps[LT_CURR].list[i]) { + ppc->RefPicSetLtCurr[i] = j; + break; + } + } + } + + fill_scaling_lists(ppc, s); + + return 0; +} + +static int nvdec_hevc_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, + uint32_t size) +{ + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + void *tmp; + + tmp = av_fast_realloc(ctx->bitstream, &ctx->bitstream_allocated, + ctx->bitstream_len + size + 3); + if (!tmp) + return AVERROR(ENOMEM); + ctx->bitstream = tmp; + + tmp = av_fast_realloc(ctx->slice_offsets, &ctx->slice_offsets_allocated, + (ctx->nb_slices + 1) * sizeof(*ctx->slice_offsets)); + if (!tmp) + return AVERROR(ENOMEM); + ctx->slice_offsets = tmp; + + AV_WB24(ctx->bitstream + ctx->bitstream_len, 1); + memcpy(ctx->bitstream + ctx->bitstream_len + 3, buffer, size); + ctx->slice_offsets[ctx->nb_slices] = ctx->bitstream_len ; + ctx->bitstream_len += size + 3; + ctx->nb_slices++; + + return 0; +} + +static int nvdec_hevc_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx) +{ + const HEVCContext *s = avctx->priv_data; + const HEVCSPS *sps = s->ps.sps; + return ff_nvdec_frame_params(avctx, hw_frames_ctx, sps->temporal_layer[sps->max_sub_layers - 1].max_dec_pic_buffering + 1); +} + +const AVHWAccel ff_hevc_nvdec_hwaccel = { + .name = "hevc_nvdec", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_HEVC, + .pix_fmt = AV_PIX_FMT_CUDA, + .start_frame = nvdec_hevc_start_frame, + .end_frame = ff_nvdec_end_frame, + .decode_slice = nvdec_hevc_decode_slice, + .frame_params = nvdec_hevc_frame_params, + .init = ff_nvdec_decode_init, + .uninit = ff_nvdec_decode_uninit, + .priv_data_size = sizeof(NVDECContext), +}; diff --git a/libavcodec/nvdec_mjpeg.c b/libavcodec/nvdec_mjpeg.c new file mode 100644 index 0000000000000..7e404246cec73 --- /dev/null +++ b/libavcodec/nvdec_mjpeg.c @@ -0,0 +1,86 @@ +/* + * MJPEG HW decode acceleration through NVDEC + * + * Copyright (c) 2017 Philip Langdale + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avcodec.h" +#include "internal.h" +#include "mjpegdec.h" +#include "nvdec.h" +#include "decode.h" + +static int nvdec_mjpeg_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +{ + MJpegDecodeContext *s = avctx->priv_data; + + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + CUVIDPICPARAMS *pp = &ctx->pic_params; + FrameDecodeData *fdd; + NVDECFrame *cf; + AVFrame *cur_frame = s->picture; + + int ret; + + ret = ff_nvdec_start_frame(avctx, cur_frame); + if (ret < 0) + return ret; + + fdd = (FrameDecodeData*)cur_frame->private_ref->data; + cf = (NVDECFrame*)fdd->hwaccel_priv; + + *pp = (CUVIDPICPARAMS) { + .PicWidthInMbs = (cur_frame->width + 15) / 16, + .FrameHeightInMbs = (cur_frame->height + 15) / 16, + .CurrPicIdx = cf->idx, + + .intra_pic_flag = 1, + .ref_pic_flag = 0, + }; + + return ff_nvdec_simple_decode_slice(avctx, buffer, size); +} + +static int nvdec_mjpeg_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +{ + return 0; +} + +static int nvdec_mjpeg_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx) +{ + // Only need storage for the current frame + return ff_nvdec_frame_params(avctx, hw_frames_ctx, 1); +} + +#if CONFIG_MJPEG_NVDEC_HWACCEL +AVHWAccel ff_mjpeg_nvdec_hwaccel = { + .name = "mjpeg_nvdec", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_MJPEG, + .pix_fmt = AV_PIX_FMT_CUDA, + .start_frame = nvdec_mjpeg_start_frame, + .end_frame = ff_nvdec_simple_end_frame, + .decode_slice = nvdec_mjpeg_decode_slice, + .frame_params = nvdec_mjpeg_frame_params, + .init = ff_nvdec_decode_init, + .uninit = ff_nvdec_decode_uninit, + .priv_data_size = sizeof(NVDECContext), +}; +#endif diff --git a/libavcodec/nvdec_mpeg12.c b/libavcodec/nvdec_mpeg12.c new file mode 100644 index 0000000000000..7293d50555480 --- /dev/null +++ b/libavcodec/nvdec_mpeg12.c @@ -0,0 +1,123 @@ +/* + * MPEG-1/2 HW decode acceleration through NVDEC + * + * Copyright (c) 2017 Philip Langdale + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avcodec.h" +#include "mpegvideo.h" +#include "nvdec.h" +#include "decode.h" + +static int nvdec_mpeg12_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +{ + MpegEncContext *s = avctx->priv_data; + + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + CUVIDPICPARAMS *pp = &ctx->pic_params; + CUVIDMPEG2PICPARAMS *ppc = &pp->CodecSpecific.mpeg2; + FrameDecodeData *fdd; + NVDECFrame *cf; + AVFrame *cur_frame = s->current_picture.f; + + int ret, i; + + ret = ff_nvdec_start_frame(avctx, cur_frame); + if (ret < 0) + return ret; + + fdd = (FrameDecodeData*)cur_frame->private_ref->data; + cf = (NVDECFrame*)fdd->hwaccel_priv; + + *pp = (CUVIDPICPARAMS) { + .PicWidthInMbs = (cur_frame->width + 15) / 16, + .FrameHeightInMbs = (cur_frame->height + 15) / 16, + .CurrPicIdx = cf->idx, + + .intra_pic_flag = s->pict_type == AV_PICTURE_TYPE_I, + .ref_pic_flag = s->pict_type == AV_PICTURE_TYPE_I || + s->pict_type == AV_PICTURE_TYPE_P, + + .CodecSpecific.mpeg2 = { + .ForwardRefIdx = ff_nvdec_get_ref_idx(s->last_picture.f), + .BackwardRefIdx = ff_nvdec_get_ref_idx(s->next_picture.f), + + .picture_coding_type = s->pict_type, + .full_pel_forward_vector = s->full_pel[0], + .full_pel_backward_vector = s->full_pel[1], + .f_code = { { s->mpeg_f_code[0][0], + s->mpeg_f_code[0][1] }, + { s->mpeg_f_code[1][0], + s->mpeg_f_code[1][1] } }, + .intra_dc_precision = s->intra_dc_precision, + .frame_pred_frame_dct = s->frame_pred_frame_dct, + .concealment_motion_vectors = s->concealment_motion_vectors, + .q_scale_type = s->q_scale_type, + .intra_vlc_format = s->intra_vlc_format, + .alternate_scan = s->alternate_scan, + .top_field_first = s->top_field_first, + } + }; + + for (i = 0; i < 64; ++i) { + ppc->QuantMatrixIntra[i] = s->intra_matrix[i]; + ppc->QuantMatrixInter[i] = s->inter_matrix[i]; + } + + return 0; +} + +static int nvdec_mpeg12_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx) +{ + // Each frame can at most have one P and one B reference + return ff_nvdec_frame_params(avctx, hw_frames_ctx, 2); +} + +#if CONFIG_MPEG2_NVDEC_HWACCEL +const AVHWAccel ff_mpeg2_nvdec_hwaccel = { + .name = "mpeg2_nvdec", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_MPEG2VIDEO, + .pix_fmt = AV_PIX_FMT_CUDA, + .start_frame = nvdec_mpeg12_start_frame, + .end_frame = ff_nvdec_simple_end_frame, + .decode_slice = ff_nvdec_simple_decode_slice, + .frame_params = nvdec_mpeg12_frame_params, + .init = ff_nvdec_decode_init, + .uninit = ff_nvdec_decode_uninit, + .priv_data_size = sizeof(NVDECContext), +}; +#endif + +#if CONFIG_MPEG1_NVDEC_HWACCEL +const AVHWAccel ff_mpeg1_nvdec_hwaccel = { + .name = "mpeg1_nvdec", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_MPEG1VIDEO, + .pix_fmt = AV_PIX_FMT_CUDA, + .start_frame = nvdec_mpeg12_start_frame, + .end_frame = ff_nvdec_simple_end_frame, + .decode_slice = ff_nvdec_simple_decode_slice, + .frame_params = nvdec_mpeg12_frame_params, + .init = ff_nvdec_decode_init, + .uninit = ff_nvdec_decode_uninit, + .priv_data_size = sizeof(NVDECContext), +}; +#endif diff --git a/libavcodec/nvdec_mpeg4.c b/libavcodec/nvdec_mpeg4.c new file mode 100644 index 0000000000000..907af1391a929 --- /dev/null +++ b/libavcodec/nvdec_mpeg4.c @@ -0,0 +1,121 @@ +/* + * MPEG-4 Part 2 HW decode acceleration through NVDEC + * + * Copyright (c) 2017 Philip Langdale + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avcodec.h" +#include "mpeg4video.h" +#include "nvdec.h" +#include "decode.h" + +static int nvdec_mpeg4_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +{ + Mpeg4DecContext *m = avctx->priv_data; + MpegEncContext *s = &m->m; + + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + CUVIDPICPARAMS *pp = &ctx->pic_params; + CUVIDMPEG4PICPARAMS *ppc = &pp->CodecSpecific.mpeg4; + FrameDecodeData *fdd; + NVDECFrame *cf; + AVFrame *cur_frame = s->current_picture.f; + + int ret, i; + + ret = ff_nvdec_start_frame(avctx, cur_frame); + if (ret < 0) + return ret; + + fdd = (FrameDecodeData*)cur_frame->private_ref->data; + cf = (NVDECFrame*)fdd->hwaccel_priv; + + *pp = (CUVIDPICPARAMS) { + .PicWidthInMbs = (cur_frame->width + 15) / 16, + .FrameHeightInMbs = (cur_frame->height + 15) / 16, + .CurrPicIdx = cf->idx, + + .intra_pic_flag = s->pict_type == AV_PICTURE_TYPE_I, + .ref_pic_flag = s->pict_type == AV_PICTURE_TYPE_I || + s->pict_type == AV_PICTURE_TYPE_P || + s->pict_type == AV_PICTURE_TYPE_S, + + .CodecSpecific.mpeg4 = { + .ForwardRefIdx = ff_nvdec_get_ref_idx(s->last_picture.f), + .BackwardRefIdx = ff_nvdec_get_ref_idx(s->next_picture.f), + + .video_object_layer_width = s->width, + .video_object_layer_height = s->height, + .vop_time_increment_bitcount = m->time_increment_bits, + .top_field_first = s->top_field_first, + .resync_marker_disable = !m->resync_marker, + .quant_type = s->mpeg_quant, + .quarter_sample = s->quarter_sample, + .short_video_header = avctx->codec->id == AV_CODEC_ID_H263, + .divx_flags = s->divx_packed ? 5 : 0, + + .vop_coding_type = s->pict_type - AV_PICTURE_TYPE_I, + .vop_coded = 1, + .vop_rounding_type = s->no_rounding, + .alternate_vertical_scan_flag = s->alternate_scan, + .interlaced = !s->progressive_sequence, + .vop_fcode_forward = s->f_code, + .vop_fcode_backward = s->b_code, + .trd = { s->pp_time, s->pp_field_time >> 1 }, + .trb = { s->pb_time, s->pb_field_time >> 1 }, + + .gmc_enabled = s->pict_type == AV_PICTURE_TYPE_S && + m->vol_sprite_usage == GMC_SPRITE, + } + }; + + for (i = 0; i < 64; ++i) { + ppc->QuantMatrixIntra[i] = s->intra_matrix[i]; + ppc->QuantMatrixInter[i] = s->inter_matrix[i]; + } + + // We need to pass the full frame buffer and not just the slice + return ff_nvdec_simple_decode_slice(avctx, buffer, size); +} + +static int nvdec_mpeg4_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +{ + return 0; +} + +static int nvdec_mpeg4_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx) +{ + // Each frame can at most have one P and one B reference + return ff_nvdec_frame_params(avctx, hw_frames_ctx, 2); +} + +const AVHWAccel ff_mpeg4_nvdec_hwaccel = { + .name = "mpeg4_nvdec", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_MPEG4, + .pix_fmt = AV_PIX_FMT_CUDA, + .start_frame = nvdec_mpeg4_start_frame, + .end_frame = ff_nvdec_simple_end_frame, + .decode_slice = nvdec_mpeg4_decode_slice, + .frame_params = nvdec_mpeg4_frame_params, + .init = ff_nvdec_decode_init, + .uninit = ff_nvdec_decode_uninit, + .priv_data_size = sizeof(NVDECContext), +}; diff --git a/libavcodec/nvdec_vc1.c b/libavcodec/nvdec_vc1.c new file mode 100644 index 0000000000000..7257692d66a35 --- /dev/null +++ b/libavcodec/nvdec_vc1.c @@ -0,0 +1,141 @@ +/* + * VC1 HW decode acceleration through NVDEC + * + * Copyright (c) 2017 Philip Langdale + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avcodec.h" +#include "nvdec.h" +#include "decode.h" +#include "vc1.h" + +static int nvdec_vc1_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +{ + VC1Context *v = avctx->priv_data; + MpegEncContext *s = &v->s; + + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + CUVIDPICPARAMS *pp = &ctx->pic_params; + FrameDecodeData *fdd; + NVDECFrame *cf; + AVFrame *cur_frame = s->current_picture.f; + + int ret; + + ret = ff_nvdec_start_frame(avctx, cur_frame); + if (ret < 0) + return ret; + + fdd = (FrameDecodeData*)cur_frame->private_ref->data; + cf = (NVDECFrame*)fdd->hwaccel_priv; + + *pp = (CUVIDPICPARAMS) { + .PicWidthInMbs = (cur_frame->width + 15) / 16, + .FrameHeightInMbs = (cur_frame->height + 15) / 16, + .CurrPicIdx = cf->idx, + .field_pic_flag = v->field_mode, + .bottom_field_flag = v->cur_field_type, + .second_field = v->second_field, + + .intra_pic_flag = s->pict_type == AV_PICTURE_TYPE_I || + s->pict_type == AV_PICTURE_TYPE_BI, + .ref_pic_flag = s->pict_type == AV_PICTURE_TYPE_I || + s->pict_type == AV_PICTURE_TYPE_P, + + .CodecSpecific.vc1 = { + .ForwardRefIdx = ff_nvdec_get_ref_idx(s->last_picture.f), + .BackwardRefIdx = ff_nvdec_get_ref_idx(s->next_picture.f), + .FrameWidth = cur_frame->width, + .FrameHeight = cur_frame->height, + + .intra_pic_flag = s->pict_type == AV_PICTURE_TYPE_I || + s->pict_type == AV_PICTURE_TYPE_BI, + .ref_pic_flag = s->pict_type == AV_PICTURE_TYPE_I || + s->pict_type == AV_PICTURE_TYPE_P, + .progressive_fcm = v->fcm == 0, + + .profile = v->profile, + .postprocflag = v->postprocflag, + .pulldown = v->broadcast, + .interlace = v->interlace, + .tfcntrflag = v->tfcntrflag, + .finterpflag = v->finterpflag, + .psf = v->psf, + .multires = v->multires, + .syncmarker = v->resync_marker, + .rangered = v->rangered, + .maxbframes = s->max_b_frames, + + .panscan_flag = v->panscanflag, + .refdist_flag = v->refdist_flag, + .extended_mv = v->extended_mv, + .dquant = v->dquant, + .vstransform = v->vstransform, + .loopfilter = v->s.loop_filter, + .fastuvmc = v->fastuvmc, + .overlap = v->overlap, + .quantizer = v->quantizer_mode, + .extended_dmv = v->extended_dmv, + .range_mapy_flag = v->range_mapy_flag, + .range_mapy = v->range_mapy, + .range_mapuv_flag = v->range_mapuv_flag, + .range_mapuv = v->range_mapuv, + .rangeredfrm = v->rangeredfrm, + } + }; + + return 0; +} + +static int nvdec_vc1_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx) +{ + // Each frame can at most have one P and one B reference + return ff_nvdec_frame_params(avctx, hw_frames_ctx, 2); +} + +const AVHWAccel ff_vc1_nvdec_hwaccel = { + .name = "vc1_nvdec", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_VC1, + .pix_fmt = AV_PIX_FMT_CUDA, + .start_frame = nvdec_vc1_start_frame, + .end_frame = ff_nvdec_simple_end_frame, + .decode_slice = ff_nvdec_simple_decode_slice, + .frame_params = nvdec_vc1_frame_params, + .init = ff_nvdec_decode_init, + .uninit = ff_nvdec_decode_uninit, + .priv_data_size = sizeof(NVDECContext), +}; + +#if CONFIG_WMV3_NVDEC_HWACCEL +const AVHWAccel ff_wmv3_nvdec_hwaccel = { + .name = "wmv3_nvdec", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_WMV3, + .pix_fmt = AV_PIX_FMT_CUDA, + .start_frame = nvdec_vc1_start_frame, + .end_frame = ff_nvdec_simple_end_frame, + .decode_slice = ff_nvdec_simple_decode_slice, + .frame_params = nvdec_vc1_frame_params, + .init = ff_nvdec_decode_init, + .uninit = ff_nvdec_decode_uninit, + .priv_data_size = sizeof(NVDECContext), +}; +#endif diff --git a/libavcodec/nvdec_vp8.c b/libavcodec/nvdec_vp8.c new file mode 100644 index 0000000000000..7b37445613b13 --- /dev/null +++ b/libavcodec/nvdec_vp8.c @@ -0,0 +1,105 @@ +/* + * VP8 HW decode acceleration through NVDEC + * + * Copyright (c) 2017 Philip Langdale + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avcodec.h" +#include "nvdec.h" +#include "decode.h" +#include "internal.h" +#include "vp8.h" + +static unsigned char safe_get_ref_idx(VP8Frame *frame) +{ + return frame ? ff_nvdec_get_ref_idx(frame->tf.f) : 255; +} + +static int nvdec_vp8_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +{ + VP8Context *h = avctx->priv_data; + + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + CUVIDPICPARAMS *pp = &ctx->pic_params; + FrameDecodeData *fdd; + NVDECFrame *cf; + AVFrame *cur_frame = h->framep[VP56_FRAME_CURRENT]->tf.f; + + int ret; + + ret = ff_nvdec_start_frame(avctx, cur_frame); + if (ret < 0) + return ret; + + fdd = (FrameDecodeData*)cur_frame->private_ref->data; + cf = (NVDECFrame*)fdd->hwaccel_priv; + + *pp = (CUVIDPICPARAMS) { + .PicWidthInMbs = (cur_frame->width + 15) / 16, + .FrameHeightInMbs = (cur_frame->height + 15) / 16, + .CurrPicIdx = cf->idx, + + .CodecSpecific.vp8 = { + .width = cur_frame->width, + .height = cur_frame->height, + + .first_partition_size = h->header_partition_size, + + .LastRefIdx = safe_get_ref_idx(h->framep[VP56_FRAME_PREVIOUS]), + .GoldenRefIdx = safe_get_ref_idx(h->framep[VP56_FRAME_GOLDEN]), + .AltRefIdx = safe_get_ref_idx(h->framep[VP56_FRAME_GOLDEN2]), + /* + * Explicit braces for anonymous inners and unnamed fields + * to work around limitations in ancient versions of gcc. + */ + { // union + { // struct + !h->keyframe, // frame_type + h->profile, // version + !h->invisible, // show_frame + h->segmentation.enabled ? // update_mb_segmentation_data + h->segmentation.update_feature_data : 0, + } + } + } + }; + + return 0; +} + +static int nvdec_vp8_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx) +{ + // VP8 uses a fixed size pool of 3 possible reference frames + return ff_nvdec_frame_params(avctx, hw_frames_ctx, 3); +} + +AVHWAccel ff_vp8_nvdec_hwaccel = { + .name = "vp8_nvdec", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_VP8, + .pix_fmt = AV_PIX_FMT_CUDA, + .start_frame = nvdec_vp8_start_frame, + .end_frame = ff_nvdec_simple_end_frame, + .decode_slice = ff_nvdec_simple_decode_slice, + .frame_params = nvdec_vp8_frame_params, + .init = ff_nvdec_decode_init, + .uninit = ff_nvdec_decode_uninit, + .priv_data_size = sizeof(NVDECContext), +}; diff --git a/libavcodec/nvdec_vp9.c b/libavcodec/nvdec_vp9.c new file mode 100644 index 0000000000000..3b665a9bc701c --- /dev/null +++ b/libavcodec/nvdec_vp9.c @@ -0,0 +1,184 @@ +/* + * VP9 HW decode acceleration through NVDEC + * + * Copyright (c) 2016 Timo Rothenpieler + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/pixdesc.h" + +#include "avcodec.h" +#include "nvdec.h" +#include "decode.h" +#include "internal.h" +#include "vp9shared.h" + +static int nvdec_vp9_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) +{ + VP9SharedContext *h = avctx->priv_data; + const AVPixFmtDescriptor *pixdesc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); + + NVDECContext *ctx = avctx->internal->hwaccel_priv_data; + CUVIDPICPARAMS *pp = &ctx->pic_params; + CUVIDVP9PICPARAMS *ppc = &pp->CodecSpecific.vp9; + FrameDecodeData *fdd; + NVDECFrame *cf; + AVFrame *cur_frame = h->frames[CUR_FRAME].tf.f; + + int ret, i; + + ret = ff_nvdec_start_frame(avctx, cur_frame); + if (ret < 0) + return ret; + + fdd = (FrameDecodeData*)cur_frame->private_ref->data; + cf = (NVDECFrame*)fdd->hwaccel_priv; + + *pp = (CUVIDPICPARAMS) { + .PicWidthInMbs = (cur_frame->width + 15) / 16, + .FrameHeightInMbs = (cur_frame->height + 15) / 16, + .CurrPicIdx = cf->idx, + + .CodecSpecific.vp9 = { + .width = cur_frame->width, + .height = cur_frame->height, + + .LastRefIdx = ff_nvdec_get_ref_idx(h->refs[h->h.refidx[0]].f), + .GoldenRefIdx = ff_nvdec_get_ref_idx(h->refs[h->h.refidx[1]].f), + .AltRefIdx = ff_nvdec_get_ref_idx(h->refs[h->h.refidx[2]].f), + + .profile = h->h.profile, + .frameContextIdx = h->h.framectxid, + .frameType = !h->h.keyframe, + .showFrame = !h->h.invisible, + .errorResilient = h->h.errorres, + .frameParallelDecoding = h->h.parallelmode, + .subSamplingX = pixdesc->log2_chroma_w, + .subSamplingY = pixdesc->log2_chroma_h, + .intraOnly = h->h.intraonly, + .allow_high_precision_mv = h->h.keyframe ? 0 : h->h.highprecisionmvs, + .refreshEntropyProbs = h->h.refreshctx, + + .bitDepthMinus8Luma = pixdesc->comp[0].depth - 8, + .bitDepthMinus8Chroma = pixdesc->comp[1].depth - 8, + + .loopFilterLevel = h->h.filter.level, + .loopFilterSharpness = h->h.filter.sharpness, + .modeRefLfEnabled = h->h.lf_delta.enabled, + + .log2_tile_columns = h->h.tiling.log2_tile_cols, + .log2_tile_rows = h->h.tiling.log2_tile_rows, + + .segmentEnabled = h->h.segmentation.enabled, + .segmentMapUpdate = h->h.segmentation.update_map, + .segmentMapTemporalUpdate = h->h.segmentation.temporal, + .segmentFeatureMode = h->h.segmentation.absolute_vals, + + .qpYAc = h->h.yac_qi, + .qpYDc = h->h.ydc_qdelta, + .qpChDc = h->h.uvdc_qdelta, + .qpChAc = h->h.uvac_qdelta, + + .resetFrameContext = h->h.resetctx, + .mcomp_filter_type = h->h.filtermode ^ (h->h.filtermode <= 1), + + .frameTagSize = h->h.uncompressed_header_size, + .offsetToDctParts = h->h.compressed_header_size, + + .refFrameSignBias[0] = 0, + } + }; + + for (i = 0; i < 2; i++) + ppc->mbModeLfDelta[i] = h->h.lf_delta.mode[i]; + + for (i = 0; i < 4; i++) + ppc->mbRefLfDelta[i] = h->h.lf_delta.ref[i]; + + for (i = 0; i < 7; i++) + ppc->mb_segment_tree_probs[i] = h->h.segmentation.prob[i]; + + for (i = 0; i < 3; i++) { + ppc->activeRefIdx[i] = h->h.refidx[i]; + ppc->segment_pred_probs[i] = h->h.segmentation.pred_prob[i]; + ppc->refFrameSignBias[i + 1] = h->h.signbias[i]; + } + + for (i = 0; i < 8; i++) { + ppc->segmentFeatureEnable[i][0] = h->h.segmentation.feat[i].q_enabled; + ppc->segmentFeatureEnable[i][1] = h->h.segmentation.feat[i].lf_enabled; + ppc->segmentFeatureEnable[i][2] = h->h.segmentation.feat[i].ref_enabled; + ppc->segmentFeatureEnable[i][3] = h->h.segmentation.feat[i].skip_enabled; + + ppc->segmentFeatureData[i][0] = h->h.segmentation.feat[i].q_val; + ppc->segmentFeatureData[i][1] = h->h.segmentation.feat[i].lf_val; + ppc->segmentFeatureData[i][2] = h->h.segmentation.feat[i].ref_val; + ppc->segmentFeatureData[i][3] = 0; + } + + switch (avctx->colorspace) { + default: + case AVCOL_SPC_UNSPECIFIED: + ppc->colorSpace = 0; + break; + case AVCOL_SPC_BT470BG: + ppc->colorSpace = 1; + break; + case AVCOL_SPC_BT709: + ppc->colorSpace = 2; + break; + case AVCOL_SPC_SMPTE170M: + ppc->colorSpace = 3; + break; + case AVCOL_SPC_SMPTE240M: + ppc->colorSpace = 4; + break; + case AVCOL_SPC_BT2020_NCL: + ppc->colorSpace = 5; + break; + case AVCOL_SPC_RESERVED: + ppc->colorSpace = 6; + break; + case AVCOL_SPC_RGB: + ppc->colorSpace = 7; + break; + } + + return 0; +} + +static int nvdec_vp9_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx) +{ + // VP9 uses a fixed size pool of 8 possible reference frames + return ff_nvdec_frame_params(avctx, hw_frames_ctx, 8); +} + +const AVHWAccel ff_vp9_nvdec_hwaccel = { + .name = "vp9_nvdec", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_VP9, + .pix_fmt = AV_PIX_FMT_CUDA, + .start_frame = nvdec_vp9_start_frame, + .end_frame = ff_nvdec_simple_end_frame, + .decode_slice = ff_nvdec_simple_decode_slice, + .frame_params = nvdec_vp9_frame_params, + .init = ff_nvdec_decode_init, + .uninit = ff_nvdec_decode_uninit, + .priv_data_size = sizeof(NVDECContext), +}; diff --git a/libavcodec/nvenc.c b/libavcodec/nvenc.c index e1d3316de39cf..c14112c3663dc 100644 --- a/libavcodec/nvenc.c +++ b/libavcodec/nvenc.c @@ -41,14 +41,19 @@ const enum AVPixelFormat ff_nvenc_pix_fmts[] = { AV_PIX_FMT_NV12, AV_PIX_FMT_P010, AV_PIX_FMT_YUV444P, - AV_PIX_FMT_YUV444P16, + AV_PIX_FMT_P016, // Truncated to 10bits + AV_PIX_FMT_YUV444P16, // Truncated to 10bits AV_PIX_FMT_0RGB32, AV_PIX_FMT_0BGR32, AV_PIX_FMT_CUDA, +#if CONFIG_D3D11VA + AV_PIX_FMT_D3D11, +#endif AV_PIX_FMT_NONE }; #define IS_10BIT(pix_fmt) (pix_fmt == AV_PIX_FMT_P010 || \ + pix_fmt == AV_PIX_FMT_P016 || \ pix_fmt == AV_PIX_FMT_YUV444P16) #define IS_YUV444(pix_fmt) (pix_fmt == AV_PIX_FMT_YUV444P || \ @@ -114,10 +119,18 @@ static int nvenc_print_error(void *log_ctx, NVENCSTATUS err, static void nvenc_print_driver_requirement(AVCodecContext *avctx, int level) { -#if defined(_WIN32) || defined(__CYGWIN__) - const char *minver = "378.66"; +#if NVENCAPI_CHECK_VERSION(8, 1) +# if defined(_WIN32) || defined(__CYGWIN__) + const char *minver = "390.77"; +# else + const char *minver = "390.25"; +# endif #else +# if defined(_WIN32) || defined(__CYGWIN__) + const char *minver = "378.66"; +# else const char *minver = "378.13"; +# endif #endif av_log(avctx, level, "The minimum required Nvidia driver for nvenc is %s or newer\n", minver); } @@ -130,11 +143,11 @@ static av_cold int nvenc_load_libraries(AVCodecContext *avctx) uint32_t nvenc_max_ver; int ret; - ret = cuda_load_functions(&dl_fn->cuda_dl); + ret = cuda_load_functions(&dl_fn->cuda_dl, avctx); if (ret < 0) return ret; - ret = nvenc_load_functions(&dl_fn->nvenc_dl); + ret = nvenc_load_functions(&dl_fn->nvenc_dl, avctx); if (ret < 0) { nvenc_print_driver_requirement(avctx, AV_LOG_ERROR); return ret; @@ -166,6 +179,43 @@ static av_cold int nvenc_load_libraries(AVCodecContext *avctx) return 0; } +static int nvenc_push_context(AVCodecContext *avctx) +{ + NvencContext *ctx = avctx->priv_data; + NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs; + CUresult cu_res; + + if (ctx->d3d11_device) + return 0; + + cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context); + if (cu_res != CUDA_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "cuCtxPushCurrent failed\n"); + return AVERROR_EXTERNAL; + } + + return 0; +} + +static int nvenc_pop_context(AVCodecContext *avctx) +{ + NvencContext *ctx = avctx->priv_data; + NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs; + CUresult cu_res; + CUcontext dummy; + + if (ctx->d3d11_device) + return 0; + + cu_res = dl_fn->cuda_dl->cuCtxPopCurrent(&dummy); + if (cu_res != CUDA_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "cuCtxPopCurrent failed\n"); + return AVERROR_EXTERNAL; + } + + return 0; +} + static av_cold int nvenc_open_session(AVCodecContext *avctx) { NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS params = { 0 }; @@ -175,8 +225,13 @@ static av_cold int nvenc_open_session(AVCodecContext *avctx) params.version = NV_ENC_OPEN_ENCODE_SESSION_EX_PARAMS_VER; params.apiVersion = NVENCAPI_VERSION; - params.device = ctx->cu_context; - params.deviceType = NV_ENC_DEVICE_TYPE_CUDA; + if (ctx->d3d11_device) { + params.device = ctx->d3d11_device; + params.deviceType = NV_ENC_DEVICE_TYPE_DIRECTX; + } else { + params.device = ctx->cu_context; + params.deviceType = NV_ENC_DEVICE_TYPE_CUDA; + } ret = p_nvenc->nvEncOpenEncodeSessionEx(¶ms, &ctx->nvencoder); if (ret != NV_ENC_SUCCESS) { @@ -323,6 +378,22 @@ static int nvenc_check_capabilities(AVCodecContext *avctx) return AVERROR(ENOSYS); } +#ifdef NVENC_HAVE_BFRAME_REF_MODE + ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_BFRAME_REF_MODE); + if (ctx->b_ref_mode == NV_ENC_BFRAME_REF_MODE_EACH && ret != 1) { + av_log(avctx, AV_LOG_VERBOSE, "Each B frame as reference is not supported\n"); + return AVERROR(ENOSYS); + } else if (ctx->b_ref_mode != NV_ENC_BFRAME_REF_MODE_DISABLED && ret == 0) { + av_log(avctx, AV_LOG_VERBOSE, "B frames as references are not supported\n"); + return AVERROR(ENOSYS); + } +#else + if (ctx->b_ref_mode != 0) { + av_log(avctx, AV_LOG_VERBOSE, "B frames as references need SDK 8.1 at build time\n"); + return AVERROR(ENOSYS); + } +#endif + return 0; } @@ -335,7 +406,6 @@ static av_cold int nvenc_check_device(AVCodecContext *avctx, int idx) int major, minor, ret; CUresult cu_res; CUdevice cu_device; - CUcontext dummy; int loglevel = AV_LOG_VERBOSE; if (ctx->device == LIST_DEVICES) @@ -378,11 +448,8 @@ static av_cold int nvenc_check_device(AVCodecContext *avctx, int idx) ctx->cu_context = ctx->cu_context_internal; - cu_res = dl_fn->cuda_dl->cuCtxPopCurrent(&dummy); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_FATAL, "Failed popping CUDA context: 0x%x\n", (int)cu_res); + if ((ret = nvenc_pop_context(avctx)) < 0) goto fail2; - } if ((ret = nvenc_open_session(avctx)) < 0) goto fail2; @@ -398,20 +465,14 @@ static av_cold int nvenc_check_device(AVCodecContext *avctx, int idx) return 0; fail3: - cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPushCurrent failed\n"); - return AVERROR_EXTERNAL; - } + if ((ret = nvenc_push_context(avctx)) < 0) + return ret; p_nvenc->nvEncDestroyEncoder(ctx->nvencoder); ctx->nvencoder = NULL; - cu_res = dl_fn->cuda_dl->cuCtxPopCurrent(&dummy); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPopCurrent failed\n"); - return AVERROR_EXTERNAL; - } + if ((ret = nvenc_pop_context(avctx)) < 0) + return ret; fail2: dl_fn->cuda_dl->cuCtxDestroy(ctx->cu_context_internal); @@ -437,23 +498,48 @@ static av_cold int nvenc_setup_device(AVCodecContext *avctx) return AVERROR_BUG; } - if (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->hw_frames_ctx || avctx->hw_device_ctx) { + if (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11 || avctx->hw_frames_ctx || avctx->hw_device_ctx) { AVHWFramesContext *frames_ctx; AVHWDeviceContext *hwdev_ctx; - AVCUDADeviceContext *device_hwctx; + AVCUDADeviceContext *cuda_device_hwctx = NULL; +#if CONFIG_D3D11VA + AVD3D11VADeviceContext *d3d11_device_hwctx = NULL; +#endif int ret; if (avctx->hw_frames_ctx) { frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; - device_hwctx = frames_ctx->device_ctx->hwctx; + if (frames_ctx->format == AV_PIX_FMT_CUDA) + cuda_device_hwctx = frames_ctx->device_ctx->hwctx; +#if CONFIG_D3D11VA + else if (frames_ctx->format == AV_PIX_FMT_D3D11) + d3d11_device_hwctx = frames_ctx->device_ctx->hwctx; +#endif + else + return AVERROR(EINVAL); } else if (avctx->hw_device_ctx) { hwdev_ctx = (AVHWDeviceContext*)avctx->hw_device_ctx->data; - device_hwctx = hwdev_ctx->hwctx; + if (hwdev_ctx->type == AV_HWDEVICE_TYPE_CUDA) + cuda_device_hwctx = hwdev_ctx->hwctx; +#if CONFIG_D3D11VA + else if (hwdev_ctx->type == AV_HWDEVICE_TYPE_D3D11VA) + d3d11_device_hwctx = hwdev_ctx->hwctx; +#endif + else + return AVERROR(EINVAL); } else { return AVERROR(EINVAL); } - ctx->cu_context = device_hwctx->cuda_ctx; + if (cuda_device_hwctx) { + ctx->cu_context = cuda_device_hwctx->cuda_ctx; + } +#if CONFIG_D3D11VA + else if (d3d11_device_hwctx) { + ctx->d3d11_device = d3d11_device_hwctx->device; + ID3D11Device_AddRef(ctx->d3d11_device); + } +#endif ret = nvenc_open_session(avctx); if (ret < 0) @@ -926,6 +1012,10 @@ static av_cold int nvenc_setup_h264_config(AVCodecContext *avctx) if (ctx->coder >= 0) h264->entropyCodingMode = ctx->coder; +#ifdef NVENC_HAVE_BFRAME_REF_MODE + h264->useBFramesAsRef = ctx->b_ref_mode; +#endif + return 0; } @@ -1031,8 +1121,6 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx) NV_ENC_PRESET_CONFIG preset_config = { 0 }; NVENCSTATUS nv_status = NV_ENC_SUCCESS; AVCPBProperties *cpb_props; - CUresult cu_res; - CUcontext dummy; int res = 0; int dw, dh; @@ -1123,19 +1211,15 @@ static av_cold int nvenc_setup_encoder(AVCodecContext *avctx) if (res) return res; - cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPushCurrent failed\n"); - return AVERROR_EXTERNAL; - } + res = nvenc_push_context(avctx); + if (res < 0) + return res; nv_status = p_nvenc->nvEncInitializeEncoder(ctx->nvencoder, &ctx->init_encode_params); - cu_res = dl_fn->cuda_dl->cuCtxPopCurrent(&dummy); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPopCurrent failed\n"); - return AVERROR_EXTERNAL; - } + res = nvenc_pop_context(avctx); + if (res < 0) + return res; if (nv_status != NV_ENC_SUCCESS) { return nvenc_print_error(avctx, nv_status, "InitializeEncoder failed"); @@ -1165,6 +1249,7 @@ static NV_ENC_BUFFER_FORMAT nvenc_map_buffer_format(enum AVPixelFormat pix_fmt) case AV_PIX_FMT_NV12: return NV_ENC_BUFFER_FORMAT_NV12_PL; case AV_PIX_FMT_P010: + case AV_PIX_FMT_P016: return NV_ENC_BUFFER_FORMAT_YUV420_10BIT; case AV_PIX_FMT_YUV444P: return NV_ENC_BUFFER_FORMAT_YUV444_PL; @@ -1190,7 +1275,7 @@ static av_cold int nvenc_alloc_surface(AVCodecContext *avctx, int idx) NV_ENC_CREATE_BITSTREAM_BUFFER allocOut = { 0 }; allocOut.version = NV_ENC_CREATE_BITSTREAM_BUFFER_VER; - if (avctx->pix_fmt == AV_PIX_FMT_CUDA) { + if (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11) { ctx->surfaces[idx].in_ref = av_frame_alloc(); if (!ctx->surfaces[idx].in_ref) return AVERROR(ENOMEM); @@ -1222,7 +1307,7 @@ static av_cold int nvenc_alloc_surface(AVCodecContext *avctx, int idx) nv_status = p_nvenc->nvEncCreateBitstreamBuffer(ctx->nvencoder, &allocOut); if (nv_status != NV_ENC_SUCCESS) { int err = nvenc_print_error(avctx, nv_status, "CreateBitstreamBuffer failed"); - if (avctx->pix_fmt != AV_PIX_FMT_CUDA) + if (avctx->pix_fmt != AV_PIX_FMT_CUDA && avctx->pix_fmt != AV_PIX_FMT_D3D11) p_nvenc->nvEncDestroyInputBuffer(ctx->nvencoder, ctx->surfaces[idx].input_surface); av_frame_free(&ctx->surfaces[idx].in_ref); return err; @@ -1239,10 +1324,7 @@ static av_cold int nvenc_alloc_surface(AVCodecContext *avctx, int idx) static av_cold int nvenc_setup_surfaces(AVCodecContext *avctx) { NvencContext *ctx = avctx->priv_data; - NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs; - CUresult cu_res; - CUcontext dummy; - int i, res; + int i, res = 0, res2; ctx->surfaces = av_mallocz_array(ctx->nb_surfaces, sizeof(*ctx->surfaces)); if (!ctx->surfaces) @@ -1263,31 +1345,21 @@ static av_cold int nvenc_setup_surfaces(AVCodecContext *avctx) if (!ctx->output_surface_ready_queue) return AVERROR(ENOMEM); - cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPushCurrent failed\n"); - return AVERROR_EXTERNAL; - } + res = nvenc_push_context(avctx); + if (res < 0) + return res; for (i = 0; i < ctx->nb_surfaces; i++) { if ((res = nvenc_alloc_surface(avctx, i)) < 0) - { - cu_res = dl_fn->cuda_dl->cuCtxPopCurrent(&dummy); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPopCurrent failed\n"); - return AVERROR_EXTERNAL; - } - return res; - } + goto fail; } - cu_res = dl_fn->cuda_dl->cuCtxPopCurrent(&dummy); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPopCurrent failed\n"); - return AVERROR_EXTERNAL; - } +fail: + res2 = nvenc_pop_context(avctx); + if (res2 < 0) + return res2; - return 0; + return res; } static av_cold int nvenc_setup_extradata(AVCodecContext *avctx) @@ -1328,20 +1400,16 @@ av_cold int ff_nvenc_encode_close(AVCodecContext *avctx) NvencContext *ctx = avctx->priv_data; NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs; NV_ENCODE_API_FUNCTION_LIST *p_nvenc = &dl_fn->nvenc_funcs; - CUresult cu_res; - CUcontext dummy; - int i; + int i, res; /* the encoder has to be flushed before it can be closed */ if (ctx->nvencoder) { NV_ENC_PIC_PARAMS params = { .version = NV_ENC_PIC_PARAMS_VER, .encodePicFlags = NV_ENC_PIC_FLAG_EOS }; - cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPushCurrent failed\n"); - return AVERROR_EXTERNAL; - } + res = nvenc_push_context(avctx); + if (res < 0) + return res; p_nvenc->nvEncEncodePicture(ctx->nvencoder, ¶ms); } @@ -1351,13 +1419,10 @@ av_cold int ff_nvenc_encode_close(AVCodecContext *avctx) av_fifo_freep(&ctx->output_surface_queue); av_fifo_freep(&ctx->unused_surface_queue); - if (ctx->surfaces && avctx->pix_fmt == AV_PIX_FMT_CUDA) { - for (i = 0; i < ctx->nb_surfaces; ++i) { - if (ctx->surfaces[i].input_surface) { - p_nvenc->nvEncUnmapInputResource(ctx->nvencoder, ctx->surfaces[i].in_map.mappedResource); - } - } + if (ctx->surfaces && (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11)) { for (i = 0; i < ctx->nb_registered_frames; i++) { + if (ctx->registered_frames[i].mapped) + p_nvenc->nvEncUnmapInputResource(ctx->nvencoder, ctx->registered_frames[i].in_map.mappedResource); if (ctx->registered_frames[i].regptr) p_nvenc->nvEncUnregisterResource(ctx->nvencoder, ctx->registered_frames[i].regptr); } @@ -1366,7 +1431,7 @@ av_cold int ff_nvenc_encode_close(AVCodecContext *avctx) if (ctx->surfaces) { for (i = 0; i < ctx->nb_surfaces; ++i) { - if (avctx->pix_fmt != AV_PIX_FMT_CUDA) + if (avctx->pix_fmt != AV_PIX_FMT_CUDA && avctx->pix_fmt != AV_PIX_FMT_D3D11) p_nvenc->nvEncDestroyInputBuffer(ctx->nvencoder, ctx->surfaces[i].input_surface); av_frame_free(&ctx->surfaces[i].in_ref); p_nvenc->nvEncDestroyBitstreamBuffer(ctx->nvencoder, ctx->surfaces[i].output_surface); @@ -1378,11 +1443,9 @@ av_cold int ff_nvenc_encode_close(AVCodecContext *avctx) if (ctx->nvencoder) { p_nvenc->nvEncDestroyEncoder(ctx->nvencoder); - cu_res = dl_fn->cuda_dl->cuCtxPopCurrent(&dummy); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPopCurrent failed\n"); - return AVERROR_EXTERNAL; - } + res = nvenc_pop_context(avctx); + if (res < 0) + return res; } ctx->nvencoder = NULL; @@ -1390,6 +1453,13 @@ av_cold int ff_nvenc_encode_close(AVCodecContext *avctx) dl_fn->cuda_dl->cuCtxDestroy(ctx->cu_context_internal); ctx->cu_context = ctx->cu_context_internal = NULL; +#if CONFIG_D3D11VA + if (ctx->d3d11_device) { + ID3D11Device_Release(ctx->d3d11_device); + ctx->d3d11_device = NULL; + } +#endif + nvenc_free_functions(&dl_fn->nvenc_dl); cuda_free_functions(&dl_fn->cuda_dl); @@ -1405,7 +1475,7 @@ av_cold int ff_nvenc_encode_init(AVCodecContext *avctx) NvencContext *ctx = avctx->priv_data; int ret; - if (avctx->pix_fmt == AV_PIX_FMT_CUDA) { + if (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11) { AVHWFramesContext *frames_ctx; if (!avctx->hw_frames_ctx) { av_log(avctx, AV_LOG_ERROR, @@ -1413,6 +1483,11 @@ av_cold int ff_nvenc_encode_init(AVCodecContext *avctx) return AVERROR(EINVAL); } frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + if (frames_ctx->format != avctx->pix_fmt) { + av_log(avctx, AV_LOG_ERROR, + "hw_frames_ctx must match the GPU frame type\n"); + return AVERROR(EINVAL); + } ctx->data_pix_fmt = frames_ctx->sw_format; } else { ctx->data_pix_fmt = avctx->pix_fmt; @@ -1485,6 +1560,7 @@ static int nvenc_find_free_reg_resource(AVCodecContext *avctx) NvencContext *ctx = avctx->priv_data; NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs; NV_ENCODE_API_FUNCTION_LIST *p_nvenc = &dl_fn->nvenc_funcs; + NVENCSTATUS nv_status; int i; @@ -1492,8 +1568,10 @@ static int nvenc_find_free_reg_resource(AVCodecContext *avctx) for (i = 0; i < ctx->nb_registered_frames; i++) { if (!ctx->registered_frames[i].mapped) { if (ctx->registered_frames[i].regptr) { - p_nvenc->nvEncUnregisterResource(ctx->nvencoder, - ctx->registered_frames[i].regptr); + nv_status = p_nvenc->nvEncUnregisterResource(ctx->nvencoder, ctx->registered_frames[i].regptr); + if (nv_status != NV_ENC_SUCCESS) + return nvenc_print_error(avctx, nv_status, "Failed unregistering unused input resource"); + ctx->registered_frames[i].ptr = NULL; ctx->registered_frames[i].regptr = NULL; } return i; @@ -1518,7 +1596,9 @@ static int nvenc_register_frame(AVCodecContext *avctx, const AVFrame *frame) int i, idx, ret; for (i = 0; i < ctx->nb_registered_frames; i++) { - if (ctx->registered_frames[i].ptr == (CUdeviceptr)frame->data[0]) + if (avctx->pix_fmt == AV_PIX_FMT_CUDA && ctx->registered_frames[i].ptr == frame->data[0]) + return i; + else if (avctx->pix_fmt == AV_PIX_FMT_D3D11 && ctx->registered_frames[i].ptr == frame->data[0] && ctx->registered_frames[i].ptr_index == (intptr_t)frame->data[1]) return i; } @@ -1527,12 +1607,19 @@ static int nvenc_register_frame(AVCodecContext *avctx, const AVFrame *frame) return idx; reg.version = NV_ENC_REGISTER_RESOURCE_VER; - reg.resourceType = NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR; reg.width = frames_ctx->width; reg.height = frames_ctx->height; reg.pitch = frame->linesize[0]; reg.resourceToRegister = frame->data[0]; + if (avctx->pix_fmt == AV_PIX_FMT_CUDA) { + reg.resourceType = NV_ENC_INPUT_RESOURCE_TYPE_CUDADEVICEPTR; + } + else if (avctx->pix_fmt == AV_PIX_FMT_D3D11) { + reg.resourceType = NV_ENC_INPUT_RESOURCE_TYPE_DIRECTX; + reg.subResourceIndex = (intptr_t)frame->data[1]; + } + reg.bufferFormat = nvenc_map_buffer_format(frames_ctx->sw_format); if (reg.bufferFormat == NV_ENC_BUFFER_FORMAT_UNDEFINED) { av_log(avctx, AV_LOG_FATAL, "Invalid input pixel format: %s\n", @@ -1546,8 +1633,9 @@ static int nvenc_register_frame(AVCodecContext *avctx, const AVFrame *frame) return AVERROR_UNKNOWN; } - ctx->registered_frames[idx].ptr = (CUdeviceptr)frame->data[0]; - ctx->registered_frames[idx].regptr = reg.registeredResource; + ctx->registered_frames[idx].ptr = frame->data[0]; + ctx->registered_frames[idx].ptr_index = reg.subResourceIndex; + ctx->registered_frames[idx].regptr = reg.registeredResource; return idx; } @@ -1561,10 +1649,10 @@ static int nvenc_upload_frame(AVCodecContext *avctx, const AVFrame *frame, int res; NVENCSTATUS nv_status; - if (avctx->pix_fmt == AV_PIX_FMT_CUDA) { + if (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11) { int reg_idx = nvenc_register_frame(avctx, frame); if (reg_idx < 0) { - av_log(avctx, AV_LOG_ERROR, "Could not register an input CUDA frame\n"); + av_log(avctx, AV_LOG_ERROR, "Could not register an input HW frame\n"); return reg_idx; } @@ -1572,19 +1660,23 @@ static int nvenc_upload_frame(AVCodecContext *avctx, const AVFrame *frame, if (res < 0) return res; - nvenc_frame->in_map.version = NV_ENC_MAP_INPUT_RESOURCE_VER; - nvenc_frame->in_map.registeredResource = ctx->registered_frames[reg_idx].regptr; - nv_status = p_nvenc->nvEncMapInputResource(ctx->nvencoder, &nvenc_frame->in_map); - if (nv_status != NV_ENC_SUCCESS) { - av_frame_unref(nvenc_frame->in_ref); - return nvenc_print_error(avctx, nv_status, "Error mapping an input resource"); + if (!ctx->registered_frames[reg_idx].mapped) { + ctx->registered_frames[reg_idx].in_map.version = NV_ENC_MAP_INPUT_RESOURCE_VER; + ctx->registered_frames[reg_idx].in_map.registeredResource = ctx->registered_frames[reg_idx].regptr; + nv_status = p_nvenc->nvEncMapInputResource(ctx->nvencoder, &ctx->registered_frames[reg_idx].in_map); + if (nv_status != NV_ENC_SUCCESS) { + av_frame_unref(nvenc_frame->in_ref); + return nvenc_print_error(avctx, nv_status, "Error mapping an input resource"); + } } - ctx->registered_frames[reg_idx].mapped = 1; + ctx->registered_frames[reg_idx].mapped += 1; + nvenc_frame->reg_idx = reg_idx; - nvenc_frame->input_surface = nvenc_frame->in_map.mappedResource; - nvenc_frame->format = nvenc_frame->in_map.mappedBufferFmt; + nvenc_frame->input_surface = ctx->registered_frames[reg_idx].in_map.mappedResource; + nvenc_frame->format = ctx->registered_frames[reg_idx].in_map.mappedBufferFmt; nvenc_frame->pitch = frame->linesize[0]; + return 0; } else { NV_ENC_LOCK_INPUT_BUFFER lockBufferParams = { 0 }; @@ -1706,8 +1798,10 @@ static int process_output_surface(AVCodecContext *avctx, AVPacket *pkt, NvencSur } slice_offsets = av_mallocz(slice_mode_data * sizeof(*slice_offsets)); - if (!slice_offsets) + if (!slice_offsets) { + res = AVERROR(ENOMEM); goto error; + } lock_params.version = NV_ENC_LOCK_BITSTREAM_VER; @@ -1729,14 +1823,33 @@ static int process_output_surface(AVCodecContext *avctx, AVPacket *pkt, NvencSur memcpy(pkt->data, lock_params.bitstreamBufferPtr, lock_params.bitstreamSizeInBytes); nv_status = p_nvenc->nvEncUnlockBitstream(ctx->nvencoder, tmpoutsurf->output_surface); - if (nv_status != NV_ENC_SUCCESS) - nvenc_print_error(avctx, nv_status, "Failed unlocking bitstream buffer, expect the gates of mordor to open"); + if (nv_status != NV_ENC_SUCCESS) { + res = nvenc_print_error(avctx, nv_status, "Failed unlocking bitstream buffer, expect the gates of mordor to open"); + goto error; + } - if (avctx->pix_fmt == AV_PIX_FMT_CUDA) { - p_nvenc->nvEncUnmapInputResource(ctx->nvencoder, tmpoutsurf->in_map.mappedResource); + if (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11) { + ctx->registered_frames[tmpoutsurf->reg_idx].mapped -= 1; + if (ctx->registered_frames[tmpoutsurf->reg_idx].mapped == 0) { + nv_status = p_nvenc->nvEncUnmapInputResource(ctx->nvencoder, ctx->registered_frames[tmpoutsurf->reg_idx].in_map.mappedResource); + if (nv_status != NV_ENC_SUCCESS) { + res = nvenc_print_error(avctx, nv_status, "Failed unmapping input resource"); + goto error; + } + nv_status = p_nvenc->nvEncUnregisterResource(ctx->nvencoder, ctx->registered_frames[tmpoutsurf->reg_idx].regptr); + if (nv_status != NV_ENC_SUCCESS) { + res = nvenc_print_error(avctx, nv_status, "Failed unregistering input resource"); + goto error; + } + ctx->registered_frames[tmpoutsurf->reg_idx].ptr = NULL; + ctx->registered_frames[tmpoutsurf->reg_idx].regptr = NULL; + } else if (ctx->registered_frames[tmpoutsurf->reg_idx].mapped < 0) { + res = AVERROR_BUG; + goto error; + } + av_frame_unref(tmpoutsurf->in_ref); - ctx->registered_frames[tmpoutsurf->reg_idx].mapped = 0; tmpoutsurf->input_surface = NULL; } @@ -1810,10 +1923,8 @@ static int output_ready(AVCodecContext *avctx, int flush) int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) { NVENCSTATUS nv_status; - CUresult cu_res; - CUcontext dummy; NvencSurface *tmp_out_surf, *in_surf; - int res; + int res, res2; NvencContext *ctx = avctx->priv_data; NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs; @@ -1822,7 +1933,7 @@ int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) NV_ENC_PIC_PARAMS pic_params = { 0 }; pic_params.version = NV_ENC_PIC_PARAMS_VER; - if (!ctx->cu_context || !ctx->nvencoder) + if ((!ctx->cu_context && !ctx->d3d11_device) || !ctx->nvencoder) return AVERROR(EINVAL); if (ctx->encoder_flushing) @@ -1833,19 +1944,15 @@ int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) if (!in_surf) return AVERROR(EAGAIN); - cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPushCurrent failed\n"); - return AVERROR_EXTERNAL; - } + res = nvenc_push_context(avctx); + if (res < 0) + return res; res = nvenc_upload_frame(avctx, frame, in_surf); - cu_res = dl_fn->cuda_dl->cuCtxPopCurrent(&dummy); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPopCurrent failed\n"); - return AVERROR_EXTERNAL; - } + res2 = nvenc_pop_context(avctx); + if (res2 < 0) + return res2; if (res) return res; @@ -1881,19 +1988,15 @@ int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) ctx->encoder_flushing = 1; } - cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPushCurrent failed\n"); - return AVERROR_EXTERNAL; - } + res = nvenc_push_context(avctx); + if (res < 0) + return res; nv_status = p_nvenc->nvEncEncodePicture(ctx->nvencoder, &pic_params); - cu_res = dl_fn->cuda_dl->cuCtxPopCurrent(&dummy); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPopCurrent failed\n"); - return AVERROR_EXTERNAL; - } + res = nvenc_pop_context(avctx); + if (res < 0) + return res; if (nv_status != NV_ENC_SUCCESS && nv_status != NV_ENC_ERR_NEED_MORE_INPUT) @@ -1922,33 +2025,26 @@ int ff_nvenc_send_frame(AVCodecContext *avctx, const AVFrame *frame) int ff_nvenc_receive_packet(AVCodecContext *avctx, AVPacket *pkt) { - CUresult cu_res; - CUcontext dummy; NvencSurface *tmp_out_surf; - int res; + int res, res2; NvencContext *ctx = avctx->priv_data; - NvencDynLoadFunctions *dl_fn = &ctx->nvenc_dload_funcs; - if (!ctx->cu_context || !ctx->nvencoder) + if ((!ctx->cu_context && !ctx->d3d11_device) || !ctx->nvencoder) return AVERROR(EINVAL); if (output_ready(avctx, ctx->encoder_flushing)) { av_fifo_generic_read(ctx->output_surface_ready_queue, &tmp_out_surf, sizeof(tmp_out_surf), NULL); - cu_res = dl_fn->cuda_dl->cuCtxPushCurrent(ctx->cu_context); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPushCurrent failed\n"); - return AVERROR_EXTERNAL; - } + res = nvenc_push_context(avctx); + if (res < 0) + return res; res = process_output_surface(avctx, pkt, tmp_out_surf); - cu_res = dl_fn->cuda_dl->cuCtxPopCurrent(&dummy); - if (cu_res != CUDA_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "cuCtxPopCurrent failed\n"); - return AVERROR_EXTERNAL; - } + res2 = nvenc_pop_context(avctx); + if (res2 < 0) + return res2; if (res) return res; diff --git a/libavcodec/nvenc.h b/libavcodec/nvenc.h index afb93cc22caed..c7506d6a1526f 100644 --- a/libavcodec/nvenc.h +++ b/libavcodec/nvenc.h @@ -19,10 +19,17 @@ #ifndef AVCODEC_NVENC_H #define AVCODEC_NVENC_H -#include "compat/nvenc/nvEncodeAPI.h" - #include "config.h" +#if CONFIG_D3D11VA +#define COBJMACROS +#include "libavutil/hwcontext_d3d11va.h" +#else +typedef void ID3D11Device; +#endif + +#include + #include "compat/cuda/dynlink_loader.h" #include "libavutil/fifo.h" #include "libavutil/opt.h" @@ -33,11 +40,19 @@ #define RC_MODE_DEPRECATED 0x800000 #define RCD(rc_mode) ((rc_mode) | RC_MODE_DEPRECATED) +#define NVENCAPI_CHECK_VERSION(major, minor) \ + ((major) < NVENCAPI_MAJOR_VERSION || ((major) == NVENCAPI_MAJOR_VERSION && (minor) <= NVENCAPI_MINOR_VERSION)) + +// SDK 8.1 compile time feature checks +#if NVENCAPI_CHECK_VERSION(8, 1) +#define NVENC_HAVE_BFRAME_REF_MODE +#define NVENC_HAVE_QP_MAP_MODE +#endif + typedef struct NvencSurface { NV_ENC_INPUT_PTR input_surface; AVFrame *in_ref; - NV_ENC_MAP_INPUT_RESOURCE in_map; int reg_idx; int width; int height; @@ -107,6 +122,7 @@ typedef struct NvencContext NV_ENC_CONFIG encode_config; CUcontext cu_context; CUcontext cu_context_internal; + ID3D11Device *d3d11_device; int nb_surfaces; NvencSurface *surfaces; @@ -119,9 +135,11 @@ typedef struct NvencContext int encoder_flushing; struct { - CUdeviceptr ptr; + void *ptr; + int ptr_index; NV_ENC_REGISTERED_PTR regptr; int mapped; + NV_ENC_MAP_INPUT_RESOURCE in_map; } registered_frames[MAX_REGISTERED_FRAMES]; int nb_registered_frames; @@ -165,6 +183,7 @@ typedef struct NvencContext int cqp; int weighted_pred; int coder; + int b_ref_mode; } NvencContext; int ff_nvenc_encode_init(AVCodecContext *avctx); diff --git a/libavcodec/nvenc_h264.c b/libavcodec/nvenc_h264.c index c3b4bac7494dc..d446f9b33cc1c 100644 --- a/libavcodec/nvenc_h264.c +++ b/libavcodec/nvenc_h264.c @@ -126,6 +126,17 @@ static const AVOption options[] = { { "cavlc", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_H264_ENTROPY_CODING_MODE_CAVLC }, 0, 0, VE, "coder" }, { "ac", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_H264_ENTROPY_CODING_MODE_CABAC }, 0, 0, VE, "coder" }, { "vlc", "", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_H264_ENTROPY_CODING_MODE_CAVLC }, 0, 0, VE, "coder" }, +#ifdef NVENC_HAVE_BFRAME_REF_MODE + { "b_ref_mode", "Use B frames as references", OFFSET(b_ref_mode), AV_OPT_TYPE_INT, { .i64 = NV_ENC_BFRAME_REF_MODE_DISABLED }, NV_ENC_BFRAME_REF_MODE_DISABLED, NV_ENC_BFRAME_REF_MODE_MIDDLE, VE, "b_ref_mode" }, + { "disabled", "B frames will not be used for reference", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_BFRAME_REF_MODE_DISABLED }, 0, 0, VE, "b_ref_mode" }, + { "each", "Each B frame will be used for reference", 0, AV_OPT_TYPE_CONST, { .i64 = NV_ENC_BFRAME_REF_MODE_EACH }, 0, 0, VE, "b_ref_mode" }, + { "middle", "Only (number of B frames)/2 will be used for reference", 0,AV_OPT_TYPE_CONST, { .i64 = NV_ENC_BFRAME_REF_MODE_MIDDLE }, 0, 0, VE, "b_ref_mode" }, +#else + { "b_ref_mode", "(not supported)", OFFSET(b_ref_mode), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE, "b_ref_mode" }, + { "disabled", "", 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, 0, 0, VE, "b_ref_mode" }, + { "each", "", 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, VE, "b_ref_mode" }, + { "middle", "", 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, 0, 0, VE, "b_ref_mode" }, +#endif { NULL } }; @@ -171,9 +182,10 @@ AVCodec ff_nvenc_encoder = { .priv_data_size = sizeof(NvencContext), .priv_class = &nvenc_class, .defaults = defaults, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .pix_fmts = ff_nvenc_pix_fmts, + .wrapper_name = "nvenc", }; #endif @@ -199,9 +211,10 @@ AVCodec ff_nvenc_h264_encoder = { .priv_data_size = sizeof(NvencContext), .priv_class = &nvenc_h264_class, .defaults = defaults, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .pix_fmts = ff_nvenc_pix_fmts, + .wrapper_name = "nvenc", }; #endif @@ -227,7 +240,8 @@ AVCodec ff_h264_nvenc_encoder = { .priv_data_size = sizeof(NvencContext), .priv_class = &h264_nvenc_class, .defaults = defaults, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .pix_fmts = ff_nvenc_pix_fmts, + .wrapper_name = "nvenc", }; diff --git a/libavcodec/nvenc_hevc.c b/libavcodec/nvenc_hevc.c index 89e8c3e53a433..0df7eab8cd2b0 100644 --- a/libavcodec/nvenc_hevc.c +++ b/libavcodec/nvenc_hevc.c @@ -161,8 +161,9 @@ AVCodec ff_nvenc_hevc_encoder = { .priv_class = &nvenc_hevc_class, .defaults = defaults, .pix_fmts = ff_nvenc_pix_fmts, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .wrapper_name = "nvenc", }; #endif @@ -188,6 +189,7 @@ AVCodec ff_hevc_nvenc_encoder = { .priv_class = &hevc_nvenc_class, .defaults = defaults, .pix_fmts = ff_nvenc_pix_fmts, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .wrapper_name = "nvenc", }; diff --git a/libavcodec/options.c b/libavcodec/options.c index 82e12179a6b5c..41b60521cc444 100644 --- a/libavcodec/options.c +++ b/libavcodec/options.c @@ -30,7 +30,6 @@ #include "libavutil/internal.h" #include "libavutil/mem.h" #include "libavutil/opt.h" -#include /* FLT_MIN, FLT_MAX */ #include FF_DISABLE_DEPRECATION_WARNINGS diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h index 2ac37c3ff17e4..099261e1684aa 100644 --- a/libavcodec/options_table.h +++ b/libavcodec/options_table.h @@ -54,26 +54,11 @@ static const AVOption avcodec_options[] = { {"qpel", "use 1/4-pel motion compensation", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_QPEL }, INT_MIN, INT_MAX, V|E, "flags"}, {"loop", "use loop filter", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_LOOP_FILTER }, INT_MIN, INT_MAX, V|E, "flags"}, {"qscale", "use fixed qscale", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_QSCALE }, INT_MIN, INT_MAX, 0, "flags"}, -#if FF_API_GMC -{"gmc", "use gmc", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG_GMC }, INT_MIN, INT_MAX, V|E, "flags"}, -#endif -#if FF_API_MV0 -{"mv0", "always try a mb with mv=<0,0>", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG_MV0 }, INT_MIN, INT_MAX, V|E, "flags"}, -#endif -#if FF_API_INPUT_PRESERVED -{"input_preserved", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG_INPUT_PRESERVED }, INT_MIN, INT_MAX, 0, "flags"}, -#endif {"pass1", "use internal 2-pass ratecontrol in first pass mode", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_PASS1 }, INT_MIN, INT_MAX, 0, "flags"}, {"pass2", "use internal 2-pass ratecontrol in second pass mode", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_PASS2 }, INT_MIN, INT_MAX, 0, "flags"}, {"gray", "only decode/encode grayscale", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_GRAY }, INT_MIN, INT_MAX, V|E|D, "flags"}, -#if FF_API_EMU_EDGE -{"emu_edge", "do not draw edges", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG_EMU_EDGE }, INT_MIN, INT_MAX, 0, "flags"}, -#endif {"psnr", "error[?] variables will be set during encoding", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_PSNR }, INT_MIN, INT_MAX, V|E, "flags"}, {"truncated", "Input bitstream might be randomly truncated", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_TRUNCATED }, INT_MIN, INT_MAX, V|D, "flags"}, -#if FF_API_NORMALIZE_AQP -{"naq", "normalize adaptive quantization", 0, AV_OPT_TYPE_CONST, {.i64 = CODEC_FLAG_NORMALIZE_AQP }, INT_MIN, INT_MAX, V|E, "flags"}, -#endif {"ildct", "use interlaced DCT", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_INTERLACED_DCT }, INT_MIN, INT_MAX, V|E, "flags"}, {"low_delay", "force low delay", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_LOW_DELAY }, INT_MIN, INT_MAX, V|D|E, "flags"}, {"global_header", "place global headers in extradata instead of every keyframe", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG_GLOBAL_HEADER }, INT_MIN, INT_MAX, V|A|E, "flags"}, @@ -91,21 +76,6 @@ static const AVOption avcodec_options[] = { {"export_mvs", "export motion vectors through frame side data", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_EXPORT_MVS}, INT_MIN, INT_MAX, V|D, "flags2"}, {"skip_manual", "do not skip samples and export skip information as frame side data", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_SKIP_MANUAL}, INT_MIN, INT_MAX, V|D, "flags2"}, {"ass_ro_flush_noop", "do not reset ASS ReadOrder field on flush", 0, AV_OPT_TYPE_CONST, {.i64 = AV_CODEC_FLAG2_RO_FLUSH_NOOP}, INT_MIN, INT_MAX, S|D, "flags2"}, -#if FF_API_MOTION_EST -{"me_method", "set motion estimation method", OFFSET(me_method), AV_OPT_TYPE_INT, {.i64 = ME_EPZS }, INT_MIN, INT_MAX, V|E, "me_method"}, -{"zero", "zero motion estimation (fastest)", 0, AV_OPT_TYPE_CONST, {.i64 = ME_ZERO }, INT_MIN, INT_MAX, V|E, "me_method" }, -{"full", "full motion estimation (slowest)", 0, AV_OPT_TYPE_CONST, {.i64 = ME_FULL }, INT_MIN, INT_MAX, V|E, "me_method" }, -{"epzs", "EPZS motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_EPZS }, INT_MIN, INT_MAX, V|E, "me_method" }, -{"esa", "esa motion estimation (alias for full)", 0, AV_OPT_TYPE_CONST, {.i64 = ME_FULL }, INT_MIN, INT_MAX, V|E, "me_method" }, -{"tesa", "tesa motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_TESA }, INT_MIN, INT_MAX, V|E, "me_method" }, -{"dia", "diamond motion estimation (alias for EPZS)", 0, AV_OPT_TYPE_CONST, {.i64 = ME_EPZS }, INT_MIN, INT_MAX, V|E, "me_method" }, -{"log", "log motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_LOG }, INT_MIN, INT_MAX, V|E, "me_method" }, -{"phods", "phods motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_PHODS }, INT_MIN, INT_MAX, V|E, "me_method" }, -{"x1", "X1 motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_X1 }, INT_MIN, INT_MAX, V|E, "me_method" }, -{"hex", "hex motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_HEX }, INT_MIN, INT_MAX, V|E, "me_method" }, -{"umh", "umh motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_UMH }, INT_MIN, INT_MAX, V|E, "me_method" }, -{"iter", "iter motion estimation", 0, AV_OPT_TYPE_CONST, {.i64 = ME_ITER }, INT_MIN, INT_MAX, V|E, "me_method" }, -#endif {"time_base", NULL, OFFSET(time_base), AV_OPT_TYPE_RATIONAL, {.dbl = 0}, 0, INT_MAX}, {"g", "set the group of picture (GOP) size", OFFSET(gop_size), AV_OPT_TYPE_INT, {.i64 = 12 }, INT_MIN, INT_MAX, V|E}, {"ar", "set audio sampling rate (in Hz)", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, A|D|E}, @@ -123,9 +93,6 @@ static const AVOption avcodec_options[] = { {"qdiff", "maximum difference between the quantizer scales (VBR)", OFFSET(max_qdiff), AV_OPT_TYPE_INT, {.i64 = 3 }, INT_MIN, INT_MAX, V|E}, {"bf", "set maximum number of B-frames between non-B-frames", OFFSET(max_b_frames), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, -1, INT_MAX, V|E}, {"b_qfactor", "QP factor between P- and B-frames", OFFSET(b_quant_factor), AV_OPT_TYPE_FLOAT, {.dbl = 1.25 }, -FLT_MAX, FLT_MAX, V|E}, -#if FF_API_RC_STRATEGY -{"rc_strategy", "ratecontrol method", OFFSET(rc_strategy), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, -#endif #if FF_API_PRIVATE_OPT {"b_strategy", "strategy to choose between I/P/B-frames", OFFSET(b_frame_strategy), AV_OPT_TYPE_INT, {.i64 = 0 }, INT_MIN, INT_MAX, V|E}, {"ps", "RTP payload size in bytes", OFFSET(rtp_payload_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, @@ -144,16 +111,10 @@ static const AVOption avcodec_options[] = { {"codec_tag", NULL, OFFSET(codec_tag), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, {"bug", "work around not autodetected encoder bugs", OFFSET(workaround_bugs), AV_OPT_TYPE_FLAGS, {.i64 = FF_BUG_AUTODETECT }, INT_MIN, INT_MAX, V|D, "bug"}, {"autodetect", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_AUTODETECT }, INT_MIN, INT_MAX, V|D, "bug"}, -#if FF_API_OLD_MSMPEG4 -{"old_msmpeg4", "some old lavc-generated MSMPEG4v3 files (no autodetection)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_OLD_MSMPEG4 }, INT_MIN, INT_MAX, V|D, "bug"}, -#endif {"xvid_ilace", "Xvid interlacing bug (autodetected if FOURCC == XVIX)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_XVID_ILACE }, INT_MIN, INT_MAX, V|D, "bug"}, {"ump4", "(autodetected if FOURCC == UMP4)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_UMP4 }, INT_MIN, INT_MAX, V|D, "bug"}, {"no_padding", "padding bug (autodetected)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_NO_PADDING }, INT_MIN, INT_MAX, V|D, "bug"}, {"amv", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_AMV }, INT_MIN, INT_MAX, V|D, "bug"}, -#if FF_API_AC_VLC -{"ac_vlc", "illegal VLC bug (autodetected per FOURCC)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_AC_VLC }, INT_MIN, INT_MAX, V|D, "bug"}, -#endif {"qpel_chroma", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_QPEL_CHROMA }, INT_MIN, INT_MAX, V|D, "bug"}, {"std_qpel", "old standard qpel (autodetected per FOURCC/version)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_STD_QPEL }, INT_MIN, INT_MAX, V|D, "bug"}, {"qpel_chroma2", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_BUG_QPEL_CHROMA2 }, INT_MIN, INT_MAX, V|D, "bug"}, @@ -185,27 +146,13 @@ static const AVOption avcodec_options[] = { #if FF_API_PRIVATE_OPT {"mpeg_quant", "use MPEG quantizers instead of H.263", OFFSET(mpeg_quant), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, #endif -#if FF_API_MPV_OPT -{"qsquish", "deprecated, use encoder private options instead", OFFSET(rc_qsquish), AV_OPT_TYPE_FLOAT, {.dbl = DEFAULT }, 0, 99, V|E}, -{"rc_qmod_amp", "deprecated, use encoder private options instead", OFFSET(rc_qmod_amp), AV_OPT_TYPE_FLOAT, {.dbl = DEFAULT }, -FLT_MAX, FLT_MAX, V|E}, -{"rc_qmod_freq", "deprecated, use encoder private options instead", OFFSET(rc_qmod_freq), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, -#endif {"rc_override_count", NULL, OFFSET(rc_override_count), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, -#if FF_API_MPV_OPT -{"rc_eq", "deprecated, use encoder private options instead", OFFSET(rc_eq), AV_OPT_TYPE_STRING, {.str = NULL}, CHAR_MIN, CHAR_MAX, V|E}, -#endif {"maxrate", "maximum bitrate (in bits/s). Used for VBV together with bufsize.", OFFSET(rc_max_rate), AV_OPT_TYPE_INT64, {.i64 = DEFAULT }, 0, INT_MAX, V|A|E}, {"minrate", "minimum bitrate (in bits/s). Most useful in setting up a CBR encode. It is of little use otherwise.", OFFSET(rc_min_rate), AV_OPT_TYPE_INT64, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|A|E}, {"bufsize", "set ratecontrol buffer size (in bits)", OFFSET(rc_buffer_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, A|V|E}, -#if FF_API_MPV_OPT -{"rc_buf_aggressivity", "deprecated, use encoder private options instead", OFFSET(rc_buffer_aggressivity), AV_OPT_TYPE_FLOAT, {.dbl = 1.0 }, -FLT_MAX, FLT_MAX, V|E}, -#endif {"i_qfactor", "QP factor between P- and I-frames", OFFSET(i_quant_factor), AV_OPT_TYPE_FLOAT, {.dbl = -0.8 }, -FLT_MAX, FLT_MAX, V|E}, {"i_qoffset", "QP offset between P- and I-frames", OFFSET(i_quant_offset), AV_OPT_TYPE_FLOAT, {.dbl = 0.0 }, -FLT_MAX, FLT_MAX, V|E}, -#if FF_API_MPV_OPT -{"rc_init_cplx", "deprecated, use encoder private options instead", OFFSET(rc_initial_cplx), AV_OPT_TYPE_FLOAT, {.dbl = DEFAULT }, -FLT_MAX, FLT_MAX, V|E}, -#endif {"dct", "DCT algorithm", OFFSET(dct_algo), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, INT_MAX, V|E, "dct"}, {"auto", "autoselect a good one", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_AUTO }, INT_MIN, INT_MAX, V|E, "dct"}, {"fastint", "fast integer", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DCT_FASTINT }, INT_MIN, INT_MAX, V|E, "dct"}, @@ -225,19 +172,10 @@ static const AVOption avcodec_options[] = { {"simplemmx", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEMMX }, INT_MIN, INT_MAX, V|E|D, "idct"}, {"arm", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_ARM }, INT_MIN, INT_MAX, V|E|D, "idct"}, {"altivec", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_ALTIVEC }, INT_MIN, INT_MAX, V|E|D, "idct"}, -#if FF_API_ARCH_SH4 -{"sh4", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SH4 }, INT_MIN, INT_MAX, V|E|D, "idct"}, -#endif {"simplearm", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEARM }, INT_MIN, INT_MAX, V|E|D, "idct"}, {"simplearmv5te", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEARMV5TE }, INT_MIN, INT_MAX, V|E|D, "idct"}, {"simplearmv6", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEARMV6 }, INT_MIN, INT_MAX, V|E|D, "idct"}, {"simpleneon", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLENEON }, INT_MIN, INT_MAX, V|E|D, "idct"}, -#if FF_API_ARCH_ALPHA -{"simplealpha", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_SIMPLEALPHA }, INT_MIN, INT_MAX, V|E|D, "idct"}, -#endif -#if FF_API_UNUSED_MEMBERS -{"ipp", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_IPP }, INT_MIN, INT_MAX, V|E|D, "idct"}, -#endif /* FF_API_UNUSED_MEMBERS */ {"xvid", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_XVID }, INT_MIN, INT_MAX, V|E|D, "idct"}, {"xvidmmx", "deprecated, for compatibility only", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_XVID }, INT_MIN, INT_MAX, V|E|D, "idct"}, {"faani", "floating point AAN IDCT", 0, AV_OPT_TYPE_CONST, {.i64 = FF_IDCT_FAAN }, INT_MIN, INT_MAX, V|D|E, "idct"}, @@ -269,9 +207,6 @@ static const AVOption avcodec_options[] = { {"green_metadata", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_GREEN_MD }, INT_MIN, INT_MAX, V|D, "debug"}, {"skip", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_SKIP }, INT_MIN, INT_MAX, V|D, "debug"}, {"startcode", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_STARTCODE }, INT_MIN, INT_MAX, V|D, "debug"}, -#if FF_API_UNUSED_MEMBERS -{"pts", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_PTS }, INT_MIN, INT_MAX, V|D, "debug"}, -#endif /* FF_API_UNUSED_MEMBERS */ {"er", "error recognition", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_ER }, INT_MIN, INT_MAX, V|D, "debug"}, {"mmco", "memory management control operations (H.264)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_MMCO }, INT_MIN, INT_MAX, V|D, "debug"}, {"bugs", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_BUGS }, INT_MIN, INT_MAX, V|D, "debug"}, @@ -282,12 +217,6 @@ static const AVOption avcodec_options[] = { {"buffers", "picture buffer allocations", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_BUFFERS }, INT_MIN, INT_MAX, V|D, "debug"}, {"thread_ops", "threading operations", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_THREADS }, INT_MIN, INT_MAX, V|A|D, "debug"}, {"nomc", "skip motion compensation", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_NOMC }, INT_MIN, INT_MAX, V|A|D, "debug"}, -#if FF_API_VISMV -{"vismv", "visualize motion vectors (MVs) (deprecated)", OFFSET(debug_mv), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT }, 0, INT_MAX, V|D, "debug_mv"}, -{"pf", "forward predicted MVs of P-frames", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_VIS_MV_P_FOR }, INT_MIN, INT_MAX, V|D, "debug_mv"}, -{"bf", "forward predicted MVs of B-frames", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_VIS_MV_B_FOR }, INT_MIN, INT_MAX, V|D, "debug_mv"}, -{"bb", "backward predicted MVs of B-frames", 0, AV_OPT_TYPE_CONST, {.i64 = FF_DEBUG_VIS_MV_B_BACK }, INT_MIN, INT_MAX, V|D, "debug_mv"}, -#endif {"cmp", "full-pel ME compare function", OFFSET(me_cmp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, {"subcmp", "sub-pel ME compare function", OFFSET(me_sub_cmp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, {"mbcmp", "macroblock compare function", OFFSET(mb_cmp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, "cmp_func"}, @@ -318,14 +247,7 @@ static const AVOption avcodec_options[] = { {"msad", "sum of absolute differences, median predicted", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CMP_MEDIAN_SAD }, INT_MIN, INT_MAX, V|E, "cmp_func"}, {"pre_dia_size", "diamond type & size for motion estimation pre-pass", OFFSET(pre_dia_size), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, {"subq", "sub-pel motion estimation quality", OFFSET(me_subpel_quality), AV_OPT_TYPE_INT, {.i64 = 8 }, INT_MIN, INT_MAX, V|E}, -#if FF_API_AFD -{"dtg_active_format", NULL, OFFSET(dtg_active_format), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, -#endif {"me_range", "limit motion vectors range (1023 for DivX player)", OFFSET(me_range), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, -#if FF_API_QUANT_BIAS -{"ibias", "intra quant bias", OFFSET(intra_quant_bias), AV_OPT_TYPE_INT, {.i64 = FF_DEFAULT_QUANT_BIAS }, INT_MIN, INT_MAX, V|E}, -{"pbias", "inter quant bias", OFFSET(inter_quant_bias), AV_OPT_TYPE_INT, {.i64 = FF_DEFAULT_QUANT_BIAS }, INT_MIN, INT_MAX, V|E}, -#endif {"global_quality", NULL, OFFSET(global_quality), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|A|E}, #if FF_API_CODER_TYPE {"coder", NULL, OFFSET(coder_type), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E, "coder"}, @@ -333,45 +255,25 @@ static const AVOption avcodec_options[] = { {"ac", "arithmetic coder", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CODER_TYPE_AC }, INT_MIN, INT_MAX, V|E, "coder"}, {"raw", "raw (no encoding)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CODER_TYPE_RAW }, INT_MIN, INT_MAX, V|E, "coder"}, {"rle", "run-length coder", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CODER_TYPE_RLE }, INT_MIN, INT_MAX, V|E, "coder"}, -#if FF_API_UNUSED_MEMBERS -{"deflate", "deflate-based coder", 0, AV_OPT_TYPE_CONST, {.i64 = FF_CODER_TYPE_DEFLATE }, INT_MIN, INT_MAX, V|E, "coder"}, -#endif /* FF_API_UNUSED_MEMBERS */ #endif /* FF_API_CODER_TYPE */ #if FF_API_PRIVATE_OPT {"context", "context model", OFFSET(context_model), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, #endif {"slice_flags", NULL, OFFSET(slice_flags), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, -#if FF_API_XVMC -{"xvmc_acceleration", NULL, OFFSET(xvmc_acceleration), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, -#endif /* FF_API_XVMC */ {"mbd", "macroblock decision algorithm (high quality mode)", OFFSET(mb_decision), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, 0, 2, V|E, "mbd"}, {"simple", "use mbcmp", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MB_DECISION_SIMPLE }, INT_MIN, INT_MAX, V|E, "mbd"}, {"bits", "use fewest bits", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MB_DECISION_BITS }, INT_MIN, INT_MAX, V|E, "mbd"}, {"rd", "use best rate distortion", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MB_DECISION_RD }, INT_MIN, INT_MAX, V|E, "mbd"}, -#if FF_API_STREAM_CODEC_TAG -{"stream_codec_tag", NULL, OFFSET(stream_codec_tag), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX}, -#endif #if FF_API_PRIVATE_OPT {"sc_threshold", "scene change threshold", OFFSET(scenechange_threshold), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, #endif -#if FF_API_MPV_OPT -{"lmin", "deprecated, use encoder private options instead", OFFSET(lmin), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, V|E}, -{"lmax", "deprecated, use encoder private options instead", OFFSET(lmax), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, V|E}, -#endif #if FF_API_PRIVATE_OPT {"nr", "noise reduction", OFFSET(noise_reduction), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, #endif {"rc_init_occupancy", "number of bits which should be loaded into the rc buffer before decoding starts", OFFSET(rc_initial_buffer_occupancy), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, {"flags2", NULL, OFFSET(flags2), AV_OPT_TYPE_FLAGS, {.i64 = DEFAULT}, 0, UINT_MAX, V|A|E|D, "flags2"}, -#if FF_API_ERROR_RATE -{"error", NULL, OFFSET(error_rate), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, -#endif {"threads", "set the number of threads", OFFSET(thread_count), AV_OPT_TYPE_INT, {.i64 = 1 }, 0, INT_MAX, V|A|E|D, "threads"}, {"auto", "autodetect a suitable number of threads to use", 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, INT_MIN, INT_MAX, V|E|D, "threads"}, -#if FF_API_MPV_OPT -{"me_threshold", "motion estimation threshold", OFFSET(me_threshold), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, -{"mb_threshold", "macroblock threshold", OFFSET(mb_threshold), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, -#endif {"dc", "intra_dc_precision", OFFSET(intra_dc_precision), AV_OPT_TYPE_INT, {.i64 = 0 }, -8, 16, V|E}, {"nssew", "nsse weight", OFFSET(nsse_weight), AV_OPT_TYPE_INT, {.i64 = 8 }, INT_MIN, INT_MAX, V|E}, {"skip_top", "number of macroblock rows at the top which are skipped", OFFSET(skip_top), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|D}, @@ -398,6 +300,7 @@ static const AVOption avcodec_options[] = { {"mpeg4_main", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_MPEG4_MAIN }, INT_MIN, INT_MAX, V|E, "profile"}, {"mpeg4_asp", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_MPEG4_ADVANCED_SIMPLE }, INT_MIN, INT_MAX, V|E, "profile"}, {"main10", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_HEVC_MAIN_10 }, INT_MIN, INT_MAX, V|E, "profile"}, +{"msbc", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_PROFILE_SBC_MSBC }, INT_MIN, INT_MAX, A|E, "profile"}, {"level", NULL, OFFSET(level), AV_OPT_TYPE_INT, {.i64 = FF_LEVEL_UNKNOWN }, INT_MIN, INT_MAX, V|A|E, "level"}, {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_LEVEL_UNKNOWN }, INT_MIN, INT_MAX, V|A|E, "level"}, {"lowres", "decode at 1= 1/2, 2=1/4, 3=1/8 resolutions", OFFSET(lowres), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, INT_MAX, V|A|D}, @@ -407,9 +310,6 @@ static const AVOption avcodec_options[] = { {"skip_exp", "frame skip exponent", OFFSET(frame_skip_exp), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, {"skipcmp", "frame skip compare function", OFFSET(frame_skip_cmp), AV_OPT_TYPE_INT, {.i64 = FF_CMP_DCTMAX }, INT_MIN, INT_MAX, V|E, "cmp_func"}, #endif -#if FF_API_MPV_OPT -{"border_mask", "deprecated, use encoder private options instead", OFFSET(border_masking), AV_OPT_TYPE_FLOAT, {.dbl = DEFAULT }, -FLT_MAX, FLT_MAX, V|E}, -#endif {"mblmin", "minimum macroblock Lagrange factor (VBR)", OFFSET(mb_lmin), AV_OPT_TYPE_INT, {.i64 = FF_QP2LAMBDA * 2 }, 1, FF_LAMBDA_MAX, V|E}, {"mblmax", "maximum macroblock Lagrange factor (VBR)", OFFSET(mb_lmax), AV_OPT_TYPE_INT, {.i64 = FF_QP2LAMBDA * 31 }, 1, FF_LAMBDA_MAX, V|E}, #if FF_API_PRIVATE_OPT @@ -435,9 +335,6 @@ static const AVOption avcodec_options[] = { {"chromaoffset", "chroma QP offset from luma", OFFSET(chromaoffset), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|E}, #endif {"trellis", "rate-distortion optimal quantization", OFFSET(trellis), AV_OPT_TYPE_INT, {.i64 = DEFAULT }, INT_MIN, INT_MAX, V|A|E}, -#if FF_API_UNUSED_MEMBERS -{"sc_factor", "multiplied by qscale for each frame and added to scene_change_score", OFFSET(scenechange_factor), AV_OPT_TYPE_INT, {.i64 = 6 }, 0, INT_MAX, V|E}, -#endif /* FF_API_UNUSED_MEMBERS */ {"mv0_threshold", NULL, OFFSET(mv0_threshold), AV_OPT_TYPE_INT, {.i64 = 256 }, 0, INT_MAX, V|E}, #if FF_API_PRIVATE_OPT {"b_sensitivity", "adjust sensitivity of b_frame_strategy 1", OFFSET(b_sensitivity), AV_OPT_TYPE_INT, {.i64 = 40 }, 1, INT_MAX, V|E}, @@ -550,6 +447,7 @@ static const AVOption avcodec_options[] = { {"do_nothing", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_SUB_CHARENC_MODE_DO_NOTHING}, INT_MIN, INT_MAX, S|D, "sub_charenc_mode"}, {"auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_SUB_CHARENC_MODE_AUTOMATIC}, INT_MIN, INT_MAX, S|D, "sub_charenc_mode"}, {"pre_decoder", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_SUB_CHARENC_MODE_PRE_DECODER}, INT_MIN, INT_MAX, S|D, "sub_charenc_mode"}, +{"ignore", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = FF_SUB_CHARENC_MODE_IGNORE}, INT_MIN, INT_MAX, S|D, "sub_charenc_mode"}, #if FF_API_ASS_TIMING {"sub_text_format", "set decoded text subtitle format", OFFSET(sub_text_format), AV_OPT_TYPE_INT, {.i64 = FF_SUB_TEXT_FMT_ASS_WITH_TIMINGS}, 0, 1, S|D, "sub_text_format"}, #else @@ -580,6 +478,7 @@ static const AVOption avcodec_options[] = { {"ignore_level", "ignore level even if the codec level used is unknown or higher than the maximum supported level reported by the hardware driver", 0, AV_OPT_TYPE_CONST, { .i64 = AV_HWACCEL_FLAG_IGNORE_LEVEL }, INT_MIN, INT_MAX, V | D, "hwaccel_flags" }, {"allow_high_depth", "allow to output YUV pixel formats with a different chroma sampling than 4:2:0 and/or other than 8 bits per component", 0, AV_OPT_TYPE_CONST, {.i64 = AV_HWACCEL_FLAG_ALLOW_HIGH_DEPTH }, INT_MIN, INT_MAX, V | D, "hwaccel_flags"}, {"allow_profile_mismatch", "attempt to decode anyway if HW accelerated decoder's supported profiles do not exactly match the stream", 0, AV_OPT_TYPE_CONST, {.i64 = AV_HWACCEL_FLAG_ALLOW_PROFILE_MISMATCH }, INT_MIN, INT_MAX, V | D, "hwaccel_flags"}, +{"extra_hw_frames", "Number of extra hardware frames to allocate for the user", OFFSET(extra_hw_frames), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, V|D }, {NULL}, }; diff --git a/libavcodec/opus.c b/libavcodec/opus.c index 5847e88e11d3e..aa827b604c533 100644 --- a/libavcodec/opus.c +++ b/libavcodec/opus.c @@ -29,7 +29,8 @@ #include "libavutil/error.h" #include "libavutil/ffmath.h" -#include "opus.h" +#include "opus_celt.h" +#include "opustab.h" #include "vorbis.h" static const uint16_t opus_frame_duration[32] = { @@ -438,3 +439,459 @@ av_cold int ff_opus_parse_extradata(AVCodecContext *avctx, return 0; } + +void ff_celt_quant_bands(CeltFrame *f, OpusRangeCoder *rc) +{ + float lowband_scratch[8 * 22]; + float norm1[2 * 8 * 100]; + float *norm2 = norm1 + 8 * 100; + + int totalbits = (f->framebits << 3) - f->anticollapse_needed; + + int update_lowband = 1; + int lowband_offset = 0; + + int i, j; + + for (i = f->start_band; i < f->end_band; i++) { + uint32_t cm[2] = { (1 << f->blocks) - 1, (1 << f->blocks) - 1 }; + int band_offset = ff_celt_freq_bands[i] << f->size; + int band_size = ff_celt_freq_range[i] << f->size; + float *X = f->block[0].coeffs + band_offset; + float *Y = (f->channels == 2) ? f->block[1].coeffs + band_offset : NULL; + float *norm_loc1, *norm_loc2; + + int consumed = opus_rc_tell_frac(rc); + int effective_lowband = -1; + int b = 0; + + /* Compute how many bits we want to allocate to this band */ + if (i != f->start_band) + f->remaining -= consumed; + f->remaining2 = totalbits - consumed - 1; + if (i <= f->coded_bands - 1) { + int curr_balance = f->remaining / FFMIN(3, f->coded_bands-i); + b = av_clip_uintp2(FFMIN(f->remaining2 + 1, f->pulses[i] + curr_balance), 14); + } + + if ((ff_celt_freq_bands[i] - ff_celt_freq_range[i] >= ff_celt_freq_bands[f->start_band] || + i == f->start_band + 1) && (update_lowband || lowband_offset == 0)) + lowband_offset = i; + + if (i == f->start_band + 1) { + /* Special Hybrid Folding (RFC 8251 section 9). Copy the first band into + the second to ensure the second band never has to use the LCG. */ + int count = (ff_celt_freq_range[i] - ff_celt_freq_range[i-1]) << f->size; + + memcpy(&norm1[band_offset], &norm1[band_offset - count], count * sizeof(float)); + + if (f->channels == 2) + memcpy(&norm2[band_offset], &norm2[band_offset - count], count * sizeof(float)); + } + + /* Get a conservative estimate of the collapse_mask's for the bands we're + going to be folding from. */ + if (lowband_offset != 0 && (f->spread != CELT_SPREAD_AGGRESSIVE || + f->blocks > 1 || f->tf_change[i] < 0)) { + int foldstart, foldend; + + /* This ensures we never repeat spectral content within one band */ + effective_lowband = FFMAX(ff_celt_freq_bands[f->start_band], + ff_celt_freq_bands[lowband_offset] - ff_celt_freq_range[i]); + foldstart = lowband_offset; + while (ff_celt_freq_bands[--foldstart] > effective_lowband); + foldend = lowband_offset - 1; + while (++foldend < i && ff_celt_freq_bands[foldend] < effective_lowband + ff_celt_freq_range[i]); + + cm[0] = cm[1] = 0; + for (j = foldstart; j < foldend; j++) { + cm[0] |= f->block[0].collapse_masks[j]; + cm[1] |= f->block[f->channels - 1].collapse_masks[j]; + } + } + + if (f->dual_stereo && i == f->intensity_stereo) { + /* Switch off dual stereo to do intensity */ + f->dual_stereo = 0; + for (j = ff_celt_freq_bands[f->start_band] << f->size; j < band_offset; j++) + norm1[j] = (norm1[j] + norm2[j]) / 2; + } + + norm_loc1 = effective_lowband != -1 ? norm1 + (effective_lowband << f->size) : NULL; + norm_loc2 = effective_lowband != -1 ? norm2 + (effective_lowband << f->size) : NULL; + + if (f->dual_stereo) { + cm[0] = f->pvq->quant_band(f->pvq, f, rc, i, X, NULL, band_size, b >> 1, + f->blocks, norm_loc1, f->size, + norm1 + band_offset, 0, 1.0f, + lowband_scratch, cm[0]); + + cm[1] = f->pvq->quant_band(f->pvq, f, rc, i, Y, NULL, band_size, b >> 1, + f->blocks, norm_loc2, f->size, + norm2 + band_offset, 0, 1.0f, + lowband_scratch, cm[1]); + } else { + cm[0] = f->pvq->quant_band(f->pvq, f, rc, i, X, Y, band_size, b >> 0, + f->blocks, norm_loc1, f->size, + norm1 + band_offset, 0, 1.0f, + lowband_scratch, cm[0] | cm[1]); + cm[1] = cm[0]; + } + + f->block[0].collapse_masks[i] = (uint8_t)cm[0]; + f->block[f->channels - 1].collapse_masks[i] = (uint8_t)cm[1]; + f->remaining += f->pulses[i] + consumed; + + /* Update the folding position only as long as we have 1 bit/sample depth */ + update_lowband = (b > band_size << 3); + } +} + +#define NORMC(bits) ((bits) << (f->channels - 1) << f->size >> 2) + +void ff_celt_bitalloc(CeltFrame *f, OpusRangeCoder *rc, int encode) +{ + int i, j, low, high, total, done, bandbits, remaining, tbits_8ths; + int skip_startband = f->start_band; + int skip_bit = 0; + int intensitystereo_bit = 0; + int dualstereo_bit = 0; + int dynalloc = 6; + int extrabits = 0; + + int boost[CELT_MAX_BANDS] = { 0 }; + int trim_offset[CELT_MAX_BANDS]; + int threshold[CELT_MAX_BANDS]; + int bits1[CELT_MAX_BANDS]; + int bits2[CELT_MAX_BANDS]; + + /* Spread */ + if (opus_rc_tell(rc) + 4 <= f->framebits) { + if (encode) + ff_opus_rc_enc_cdf(rc, f->spread, ff_celt_model_spread); + else + f->spread = ff_opus_rc_dec_cdf(rc, ff_celt_model_spread); + } else { + f->spread = CELT_SPREAD_NORMAL; + } + + /* Initialize static allocation caps */ + for (i = 0; i < CELT_MAX_BANDS; i++) + f->caps[i] = NORMC((ff_celt_static_caps[f->size][f->channels - 1][i] + 64) * ff_celt_freq_range[i]); + + /* Band boosts */ + tbits_8ths = f->framebits << 3; + for (i = f->start_band; i < f->end_band; i++) { + int quanta = ff_celt_freq_range[i] << (f->channels - 1) << f->size; + int b_dynalloc = dynalloc; + int boost_amount = f->alloc_boost[i]; + quanta = FFMIN(quanta << 3, FFMAX(6 << 3, quanta)); + + while (opus_rc_tell_frac(rc) + (b_dynalloc << 3) < tbits_8ths && boost[i] < f->caps[i]) { + int is_boost; + if (encode) { + is_boost = boost_amount--; + ff_opus_rc_enc_log(rc, is_boost, b_dynalloc); + } else { + is_boost = ff_opus_rc_dec_log(rc, b_dynalloc); + } + + if (!is_boost) + break; + + boost[i] += quanta; + tbits_8ths -= quanta; + + b_dynalloc = 1; + } + + if (boost[i]) + dynalloc = FFMAX(dynalloc - 1, 2); + } + + /* Allocation trim */ + if (opus_rc_tell_frac(rc) + (6 << 3) <= tbits_8ths) + if (encode) + ff_opus_rc_enc_cdf(rc, f->alloc_trim, ff_celt_model_alloc_trim); + else + f->alloc_trim = ff_opus_rc_dec_cdf(rc, ff_celt_model_alloc_trim); + + /* Anti-collapse bit reservation */ + tbits_8ths = (f->framebits << 3) - opus_rc_tell_frac(rc) - 1; + f->anticollapse_needed = 0; + if (f->transient && f->size >= 2 && tbits_8ths >= ((f->size + 2) << 3)) + f->anticollapse_needed = 1 << 3; + tbits_8ths -= f->anticollapse_needed; + + /* Band skip bit reservation */ + if (tbits_8ths >= 1 << 3) + skip_bit = 1 << 3; + tbits_8ths -= skip_bit; + + /* Intensity/dual stereo bit reservation */ + if (f->channels == 2) { + intensitystereo_bit = ff_celt_log2_frac[f->end_band - f->start_band]; + if (intensitystereo_bit <= tbits_8ths) { + tbits_8ths -= intensitystereo_bit; + if (tbits_8ths >= 1 << 3) { + dualstereo_bit = 1 << 3; + tbits_8ths -= 1 << 3; + } + } else { + intensitystereo_bit = 0; + } + } + + /* Trim offsets */ + for (i = f->start_band; i < f->end_band; i++) { + int trim = f->alloc_trim - 5 - f->size; + int band = ff_celt_freq_range[i] * (f->end_band - i - 1); + int duration = f->size + 3; + int scale = duration + f->channels - 1; + + /* PVQ minimum allocation threshold, below this value the band is + * skipped */ + threshold[i] = FFMAX(3 * ff_celt_freq_range[i] << duration >> 4, + f->channels << 3); + + trim_offset[i] = trim * (band << scale) >> 6; + + if (ff_celt_freq_range[i] << f->size == 1) + trim_offset[i] -= f->channels << 3; + } + + /* Bisection */ + low = 1; + high = CELT_VECTORS - 1; + while (low <= high) { + int center = (low + high) >> 1; + done = total = 0; + + for (i = f->end_band - 1; i >= f->start_band; i--) { + bandbits = NORMC(ff_celt_freq_range[i] * ff_celt_static_alloc[center][i]); + + if (bandbits) + bandbits = FFMAX(bandbits + trim_offset[i], 0); + bandbits += boost[i]; + + if (bandbits >= threshold[i] || done) { + done = 1; + total += FFMIN(bandbits, f->caps[i]); + } else if (bandbits >= f->channels << 3) { + total += f->channels << 3; + } + } + + if (total > tbits_8ths) + high = center - 1; + else + low = center + 1; + } + high = low--; + + /* Bisection */ + for (i = f->start_band; i < f->end_band; i++) { + bits1[i] = NORMC(ff_celt_freq_range[i] * ff_celt_static_alloc[low][i]); + bits2[i] = high >= CELT_VECTORS ? f->caps[i] : + NORMC(ff_celt_freq_range[i] * ff_celt_static_alloc[high][i]); + + if (bits1[i]) + bits1[i] = FFMAX(bits1[i] + trim_offset[i], 0); + if (bits2[i]) + bits2[i] = FFMAX(bits2[i] + trim_offset[i], 0); + + if (low) + bits1[i] += boost[i]; + bits2[i] += boost[i]; + + if (boost[i]) + skip_startband = i; + bits2[i] = FFMAX(bits2[i] - bits1[i], 0); + } + + /* Bisection */ + low = 0; + high = 1 << CELT_ALLOC_STEPS; + for (i = 0; i < CELT_ALLOC_STEPS; i++) { + int center = (low + high) >> 1; + done = total = 0; + + for (j = f->end_band - 1; j >= f->start_band; j--) { + bandbits = bits1[j] + (center * bits2[j] >> CELT_ALLOC_STEPS); + + if (bandbits >= threshold[j] || done) { + done = 1; + total += FFMIN(bandbits, f->caps[j]); + } else if (bandbits >= f->channels << 3) + total += f->channels << 3; + } + if (total > tbits_8ths) + high = center; + else + low = center; + } + + /* Bisection */ + done = total = 0; + for (i = f->end_band - 1; i >= f->start_band; i--) { + bandbits = bits1[i] + (low * bits2[i] >> CELT_ALLOC_STEPS); + + if (bandbits >= threshold[i] || done) + done = 1; + else + bandbits = (bandbits >= f->channels << 3) ? + f->channels << 3 : 0; + + bandbits = FFMIN(bandbits, f->caps[i]); + f->pulses[i] = bandbits; + total += bandbits; + } + + /* Band skipping */ + for (f->coded_bands = f->end_band; ; f->coded_bands--) { + int allocation; + j = f->coded_bands - 1; + + if (j == skip_startband) { + /* all remaining bands are not skipped */ + tbits_8ths += skip_bit; + break; + } + + /* determine the number of bits available for coding "do not skip" markers */ + remaining = tbits_8ths - total; + bandbits = remaining / (ff_celt_freq_bands[j+1] - ff_celt_freq_bands[f->start_band]); + remaining -= bandbits * (ff_celt_freq_bands[j+1] - ff_celt_freq_bands[f->start_band]); + allocation = f->pulses[j] + bandbits * ff_celt_freq_range[j]; + allocation += FFMAX(remaining - (ff_celt_freq_bands[j] - ff_celt_freq_bands[f->start_band]), 0); + + /* a "do not skip" marker is only coded if the allocation is + * above the chosen threshold */ + if (allocation >= FFMAX(threshold[j], (f->channels + 1) << 3)) { + int do_not_skip; + if (encode) { + do_not_skip = f->coded_bands <= f->skip_band_floor; + ff_opus_rc_enc_log(rc, do_not_skip, 1); + } else { + do_not_skip = ff_opus_rc_dec_log(rc, 1); + } + + if (do_not_skip) + break; + + total += 1 << 3; + allocation -= 1 << 3; + } + + /* the band is skipped, so reclaim its bits */ + total -= f->pulses[j]; + if (intensitystereo_bit) { + total -= intensitystereo_bit; + intensitystereo_bit = ff_celt_log2_frac[j - f->start_band]; + total += intensitystereo_bit; + } + + total += f->pulses[j] = (allocation >= f->channels << 3) ? f->channels << 3 : 0; + } + + /* IS start band */ + if (encode) { + if (intensitystereo_bit) { + f->intensity_stereo = FFMIN(f->intensity_stereo, f->coded_bands); + ff_opus_rc_enc_uint(rc, f->intensity_stereo, f->coded_bands + 1 - f->start_band); + } + } else { + f->intensity_stereo = f->dual_stereo = 0; + if (intensitystereo_bit) + f->intensity_stereo = f->start_band + ff_opus_rc_dec_uint(rc, f->coded_bands + 1 - f->start_band); + } + + /* DS flag */ + if (f->intensity_stereo <= f->start_band) + tbits_8ths += dualstereo_bit; /* no intensity stereo means no dual stereo */ + else if (dualstereo_bit) + if (encode) + ff_opus_rc_enc_log(rc, f->dual_stereo, 1); + else + f->dual_stereo = ff_opus_rc_dec_log(rc, 1); + + /* Supply the remaining bits in this frame to lower bands */ + remaining = tbits_8ths - total; + bandbits = remaining / (ff_celt_freq_bands[f->coded_bands] - ff_celt_freq_bands[f->start_band]); + remaining -= bandbits * (ff_celt_freq_bands[f->coded_bands] - ff_celt_freq_bands[f->start_band]); + for (i = f->start_band; i < f->coded_bands; i++) { + const int bits = FFMIN(remaining, ff_celt_freq_range[i]); + f->pulses[i] += bits + bandbits * ff_celt_freq_range[i]; + remaining -= bits; + } + + /* Finally determine the allocation */ + for (i = f->start_band; i < f->coded_bands; i++) { + int N = ff_celt_freq_range[i] << f->size; + int prev_extra = extrabits; + f->pulses[i] += extrabits; + + if (N > 1) { + int dof; /* degrees of freedom */ + int temp; /* dof * channels * log(dof) */ + int fine_bits; + int max_bits; + int offset; /* fine energy quantization offset, i.e. + * extra bits assigned over the standard + * totalbits/dof */ + + extrabits = FFMAX(f->pulses[i] - f->caps[i], 0); + f->pulses[i] -= extrabits; + + /* intensity stereo makes use of an extra degree of freedom */ + dof = N * f->channels + (f->channels == 2 && N > 2 && !f->dual_stereo && i < f->intensity_stereo); + temp = dof * (ff_celt_log_freq_range[i] + (f->size << 3)); + offset = (temp >> 1) - dof * CELT_FINE_OFFSET; + if (N == 2) /* dof=2 is the only case that doesn't fit the model */ + offset += dof << 1; + + /* grant an additional bias for the first and second pulses */ + if (f->pulses[i] + offset < 2 * (dof << 3)) + offset += temp >> 2; + else if (f->pulses[i] + offset < 3 * (dof << 3)) + offset += temp >> 3; + + fine_bits = (f->pulses[i] + offset + (dof << 2)) / (dof << 3); + max_bits = FFMIN((f->pulses[i] >> 3) >> (f->channels - 1), CELT_MAX_FINE_BITS); + max_bits = FFMAX(max_bits, 0); + f->fine_bits[i] = av_clip(fine_bits, 0, max_bits); + + /* If fine_bits was rounded down or capped, + * give priority for the final fine energy pass */ + f->fine_priority[i] = (f->fine_bits[i] * (dof << 3) >= f->pulses[i] + offset); + + /* the remaining bits are assigned to PVQ */ + f->pulses[i] -= f->fine_bits[i] << (f->channels - 1) << 3; + } else { + /* all bits go to fine energy except for the sign bit */ + extrabits = FFMAX(f->pulses[i] - (f->channels << 3), 0); + f->pulses[i] -= extrabits; + f->fine_bits[i] = 0; + f->fine_priority[i] = 1; + } + + /* hand back a limited number of extra fine energy bits to this band */ + if (extrabits > 0) { + int fineextra = FFMIN(extrabits >> (f->channels + 2), + CELT_MAX_FINE_BITS - f->fine_bits[i]); + f->fine_bits[i] += fineextra; + + fineextra <<= f->channels + 2; + f->fine_priority[i] = (fineextra >= extrabits - prev_extra); + extrabits -= fineextra; + } + } + f->remaining = extrabits; + + /* skipped bands dedicate all of their bits for fine energy */ + for (; i < f->end_band; i++) { + f->fine_bits[i] = f->pulses[i] >> (f->channels - 1) >> 3; + f->pulses[i] = 0; + f->fine_priority[i] = f->fine_bits[i] < 1; + } +} diff --git a/libavcodec/opus.h b/libavcodec/opus.h index c3cbaec35d60b..edbaab5ce7d06 100644 --- a/libavcodec/opus.h +++ b/libavcodec/opus.h @@ -150,7 +150,9 @@ typedef struct ChannelMap { } ChannelMap; typedef struct OpusContext { + AVClass *av_class; OpusStreamContext *streams; + int apply_phase_inv; /* current output buffers for each streams */ float **out; @@ -189,4 +191,10 @@ int ff_silk_decode_superframe(SilkContext *s, OpusRangeCoder *rc, enum OpusBandwidth bandwidth, int coded_channels, int duration_ms); +/* Encode or decode CELT bands */ +void ff_celt_quant_bands(CeltFrame *f, OpusRangeCoder *rc); + +/* Encode or decode CELT bitallocation */ +void ff_celt_bitalloc(CeltFrame *f, OpusRangeCoder *rc, int encode); + #endif /* AVCODEC_OPUS_H */ diff --git a/libavcodec/opus_celt.c b/libavcodec/opus_celt.c index 84d484753b361..115dd8c63e5b2 100644 --- a/libavcodec/opus_celt.c +++ b/libavcodec/opus_celt.c @@ -143,345 +143,14 @@ static void celt_decode_tf_changes(CeltFrame *f, OpusRangeCoder *rc) } } -static void celt_decode_allocation(CeltFrame *f, OpusRangeCoder *rc) -{ - // approx. maximum bit allocation for each band before boost/trim - int cap[CELT_MAX_BANDS]; - int boost[CELT_MAX_BANDS]; - int threshold[CELT_MAX_BANDS]; - int bits1[CELT_MAX_BANDS]; - int bits2[CELT_MAX_BANDS]; - int trim_offset[CELT_MAX_BANDS]; - - int skip_start_band = f->start_band; - int dynalloc = 6; - int alloctrim = 5; - int extrabits = 0; - - int skip_bit = 0; - int intensity_stereo_bit = 0; - int dual_stereo_bit = 0; - - int remaining, bandbits; - int low, high, total, done; - int totalbits; - int consumed; - int i, j; - - consumed = opus_rc_tell(rc); - - /* obtain spread flag */ - f->spread = CELT_SPREAD_NORMAL; - if (consumed + 4 <= f->framebits) - f->spread = ff_opus_rc_dec_cdf(rc, ff_celt_model_spread); - - /* generate static allocation caps */ - for (i = 0; i < CELT_MAX_BANDS; i++) { - cap[i] = (ff_celt_static_caps[f->size][f->channels - 1][i] + 64) - * ff_celt_freq_range[i] << (f->channels - 1) << f->size >> 2; - } - - /* obtain band boost */ - totalbits = f->framebits << 3; // convert to 1/8 bits - consumed = opus_rc_tell_frac(rc); - for (i = f->start_band; i < f->end_band; i++) { - int quanta, band_dynalloc; - - boost[i] = 0; - - quanta = ff_celt_freq_range[i] << (f->channels - 1) << f->size; - quanta = FFMIN(quanta << 3, FFMAX(6 << 3, quanta)); - band_dynalloc = dynalloc; - while (consumed + (band_dynalloc<<3) < totalbits && boost[i] < cap[i]) { - int add = ff_opus_rc_dec_log(rc, band_dynalloc); - consumed = opus_rc_tell_frac(rc); - if (!add) - break; - - boost[i] += quanta; - totalbits -= quanta; - band_dynalloc = 1; - } - /* dynalloc is more likely to occur if it's already been used for earlier bands */ - if (boost[i]) - dynalloc = FFMAX(2, dynalloc - 1); - } - - /* obtain allocation trim */ - if (consumed + (6 << 3) <= totalbits) - alloctrim = ff_opus_rc_dec_cdf(rc, ff_celt_model_alloc_trim); - - /* anti-collapse bit reservation */ - totalbits = (f->framebits << 3) - opus_rc_tell_frac(rc) - 1; - f->anticollapse_needed = 0; - if (f->blocks > 1 && f->size >= 2 && - totalbits >= ((f->size + 2) << 3)) - f->anticollapse_needed = 1 << 3; - totalbits -= f->anticollapse_needed; - - /* band skip bit reservation */ - if (totalbits >= 1 << 3) - skip_bit = 1 << 3; - totalbits -= skip_bit; - - /* intensity/dual stereo bit reservation */ - if (f->channels == 2) { - intensity_stereo_bit = ff_celt_log2_frac[f->end_band - f->start_band]; - if (intensity_stereo_bit <= totalbits) { - totalbits -= intensity_stereo_bit; - if (totalbits >= 1 << 3) { - dual_stereo_bit = 1 << 3; - totalbits -= 1 << 3; - } - } else - intensity_stereo_bit = 0; - } - - for (i = f->start_band; i < f->end_band; i++) { - int trim = alloctrim - 5 - f->size; - int band = ff_celt_freq_range[i] * (f->end_band - i - 1); - int duration = f->size + 3; - int scale = duration + f->channels - 1; - - /* PVQ minimum allocation threshold, below this value the band is - * skipped */ - threshold[i] = FFMAX(3 * ff_celt_freq_range[i] << duration >> 4, - f->channels << 3); - - trim_offset[i] = trim * (band << scale) >> 6; - - if (ff_celt_freq_range[i] << f->size == 1) - trim_offset[i] -= f->channels << 3; - } - - /* bisection */ - low = 1; - high = CELT_VECTORS - 1; - while (low <= high) { - int center = (low + high) >> 1; - done = total = 0; - - for (i = f->end_band - 1; i >= f->start_band; i--) { - bandbits = ff_celt_freq_range[i] * ff_celt_static_alloc[center][i] - << (f->channels - 1) << f->size >> 2; - - if (bandbits) - bandbits = FFMAX(0, bandbits + trim_offset[i]); - bandbits += boost[i]; - - if (bandbits >= threshold[i] || done) { - done = 1; - total += FFMIN(bandbits, cap[i]); - } else if (bandbits >= f->channels << 3) - total += f->channels << 3; - } - - if (total > totalbits) - high = center - 1; - else - low = center + 1; - } - high = low--; - - for (i = f->start_band; i < f->end_band; i++) { - bits1[i] = ff_celt_freq_range[i] * ff_celt_static_alloc[low][i] - << (f->channels - 1) << f->size >> 2; - bits2[i] = high >= CELT_VECTORS ? cap[i] : - ff_celt_freq_range[i] * ff_celt_static_alloc[high][i] - << (f->channels - 1) << f->size >> 2; - - if (bits1[i]) - bits1[i] = FFMAX(0, bits1[i] + trim_offset[i]); - if (bits2[i]) - bits2[i] = FFMAX(0, bits2[i] + trim_offset[i]); - if (low) - bits1[i] += boost[i]; - bits2[i] += boost[i]; - - if (boost[i]) - skip_start_band = i; - bits2[i] = FFMAX(0, bits2[i] - bits1[i]); - } - - /* bisection */ - low = 0; - high = 1 << CELT_ALLOC_STEPS; - for (i = 0; i < CELT_ALLOC_STEPS; i++) { - int center = (low + high) >> 1; - done = total = 0; - - for (j = f->end_band - 1; j >= f->start_band; j--) { - bandbits = bits1[j] + (center * bits2[j] >> CELT_ALLOC_STEPS); - - if (bandbits >= threshold[j] || done) { - done = 1; - total += FFMIN(bandbits, cap[j]); - } else if (bandbits >= f->channels << 3) - total += f->channels << 3; - } - if (total > totalbits) - high = center; - else - low = center; - } - - done = total = 0; - for (i = f->end_band - 1; i >= f->start_band; i--) { - bandbits = bits1[i] + (low * bits2[i] >> CELT_ALLOC_STEPS); - - if (bandbits >= threshold[i] || done) - done = 1; - else - bandbits = (bandbits >= f->channels << 3) ? - f->channels << 3 : 0; - - bandbits = FFMIN(bandbits, cap[i]); - f->pulses[i] = bandbits; - total += bandbits; - } - - /* band skipping */ - for (f->coded_bands = f->end_band; ; f->coded_bands--) { - int allocation; - j = f->coded_bands - 1; - - if (j == skip_start_band) { - /* all remaining bands are not skipped */ - totalbits += skip_bit; - break; - } - - /* determine the number of bits available for coding "do not skip" markers */ - remaining = totalbits - total; - bandbits = remaining / (ff_celt_freq_bands[j+1] - ff_celt_freq_bands[f->start_band]); - remaining -= bandbits * (ff_celt_freq_bands[j+1] - ff_celt_freq_bands[f->start_band]); - allocation = f->pulses[j] + bandbits * ff_celt_freq_range[j] - + FFMAX(0, remaining - (ff_celt_freq_bands[j] - ff_celt_freq_bands[f->start_band])); - - /* a "do not skip" marker is only coded if the allocation is - above the chosen threshold */ - if (allocation >= FFMAX(threshold[j], (f->channels + 1) <<3 )) { - if (ff_opus_rc_dec_log(rc, 1)) - break; - - total += 1 << 3; - allocation -= 1 << 3; - } - - /* the band is skipped, so reclaim its bits */ - total -= f->pulses[j]; - if (intensity_stereo_bit) { - total -= intensity_stereo_bit; - intensity_stereo_bit = ff_celt_log2_frac[j - f->start_band]; - total += intensity_stereo_bit; - } - - total += f->pulses[j] = (allocation >= f->channels << 3) ? - f->channels << 3 : 0; - } - - /* obtain stereo flags */ - f->intensity_stereo = 0; - f->dual_stereo = 0; - if (intensity_stereo_bit) - f->intensity_stereo = f->start_band + - ff_opus_rc_dec_uint(rc, f->coded_bands + 1 - f->start_band); - if (f->intensity_stereo <= f->start_band) - totalbits += dual_stereo_bit; /* no intensity stereo means no dual stereo */ - else if (dual_stereo_bit) - f->dual_stereo = ff_opus_rc_dec_log(rc, 1); - - /* supply the remaining bits in this frame to lower bands */ - remaining = totalbits - total; - bandbits = remaining / (ff_celt_freq_bands[f->coded_bands] - ff_celt_freq_bands[f->start_band]); - remaining -= bandbits * (ff_celt_freq_bands[f->coded_bands] - ff_celt_freq_bands[f->start_band]); - for (i = f->start_band; i < f->coded_bands; i++) { - int bits = FFMIN(remaining, ff_celt_freq_range[i]); - - f->pulses[i] += bits + bandbits * ff_celt_freq_range[i]; - remaining -= bits; - } - - for (i = f->start_band; i < f->coded_bands; i++) { - int N = ff_celt_freq_range[i] << f->size; - int prev_extra = extrabits; - f->pulses[i] += extrabits; - - if (N > 1) { - int dof; // degrees of freedom - int temp; // dof * channels * log(dof) - int offset; // fine energy quantization offset, i.e. - // extra bits assigned over the standard - // totalbits/dof - int fine_bits, max_bits; - - extrabits = FFMAX(0, f->pulses[i] - cap[i]); - f->pulses[i] -= extrabits; - - /* intensity stereo makes use of an extra degree of freedom */ - dof = N * f->channels - + (f->channels == 2 && N > 2 && !f->dual_stereo && i < f->intensity_stereo); - temp = dof * (ff_celt_log_freq_range[i] + (f->size<<3)); - offset = (temp >> 1) - dof * CELT_FINE_OFFSET; - if (N == 2) /* dof=2 is the only case that doesn't fit the model */ - offset += dof<<1; - - /* grant an additional bias for the first and second pulses */ - if (f->pulses[i] + offset < 2 * (dof << 3)) - offset += temp >> 2; - else if (f->pulses[i] + offset < 3 * (dof << 3)) - offset += temp >> 3; - - fine_bits = (f->pulses[i] + offset + (dof << 2)) / (dof << 3); - max_bits = FFMIN((f->pulses[i]>>3) >> (f->channels - 1), - CELT_MAX_FINE_BITS); - - max_bits = FFMAX(max_bits, 0); - - f->fine_bits[i] = av_clip(fine_bits, 0, max_bits); - - /* if fine_bits was rounded down or capped, - give priority for the final fine energy pass */ - f->fine_priority[i] = (f->fine_bits[i] * (dof<<3) >= f->pulses[i] + offset); - - /* the remaining bits are assigned to PVQ */ - f->pulses[i] -= f->fine_bits[i] << (f->channels - 1) << 3; - } else { - /* all bits go to fine energy except for the sign bit */ - extrabits = FFMAX(0, f->pulses[i] - (f->channels << 3)); - f->pulses[i] -= extrabits; - f->fine_bits[i] = 0; - f->fine_priority[i] = 1; - } - - /* hand back a limited number of extra fine energy bits to this band */ - if (extrabits > 0) { - int fineextra = FFMIN(extrabits >> (f->channels + 2), - CELT_MAX_FINE_BITS - f->fine_bits[i]); - f->fine_bits[i] += fineextra; - - fineextra <<= f->channels + 2; - f->fine_priority[i] = (fineextra >= extrabits - prev_extra); - extrabits -= fineextra; - } - } - f->remaining = extrabits; - - /* skipped bands dedicate all of their bits for fine energy */ - for (; i < f->end_band; i++) { - f->fine_bits[i] = f->pulses[i] >> (f->channels - 1) >> 3; - f->pulses[i] = 0; - f->fine_priority[i] = f->fine_bits[i] < 1; - } -} - static void celt_denormalize(CeltFrame *f, CeltBlock *block, float *data) { int i, j; for (i = f->start_band; i < f->end_band; i++) { float *dst = data + (ff_celt_freq_bands[i] << f->size); - float norm = exp2f(block->energy[i] + ff_celt_mean_energy[i]); + float log_norm = block->energy[i] + ff_celt_mean_energy[i]; + float norm = exp2f(FFMIN(log_norm, 32.0f)); for (j = 0; j < ff_celt_freq_range[i] << f->size; j++) dst[j] *= norm; @@ -675,98 +344,6 @@ static void process_anticollapse(CeltFrame *f, CeltBlock *block, float *X) } } -static void celt_decode_bands(CeltFrame *f, OpusRangeCoder *rc) -{ - float lowband_scratch[8 * 22]; - float norm[2 * 8 * 100]; - - int totalbits = (f->framebits << 3) - f->anticollapse_needed; - - int update_lowband = 1; - int lowband_offset = 0; - - int i, j; - - memset(f->block[0].coeffs, 0, sizeof(f->block[0].coeffs)); - memset(f->block[1].coeffs, 0, sizeof(f->block[0].coeffs)); - - for (i = f->start_band; i < f->end_band; i++) { - uint32_t cm[2] = { (1 << f->blocks) - 1, (1 << f->blocks) - 1 }; - int band_offset = ff_celt_freq_bands[i] << f->size; - int band_size = ff_celt_freq_range[i] << f->size; - float *X = f->block[0].coeffs + band_offset; - float *Y = (f->channels == 2) ? f->block[1].coeffs + band_offset : NULL; - - int consumed = opus_rc_tell_frac(rc); - float *norm2 = norm + 8 * 100; - int effective_lowband = -1; - int b = 0; - - /* Compute how many bits we want to allocate to this band */ - if (i != f->start_band) - f->remaining -= consumed; - f->remaining2 = totalbits - consumed - 1; - if (i <= f->coded_bands - 1) { - int curr_balance = f->remaining / FFMIN(3, f->coded_bands-i); - b = av_clip_uintp2(FFMIN(f->remaining2 + 1, f->pulses[i] + curr_balance), 14); - } - - if (ff_celt_freq_bands[i] - ff_celt_freq_range[i] >= ff_celt_freq_bands[f->start_band] && - (update_lowband || lowband_offset == 0)) - lowband_offset = i; - - /* Get a conservative estimate of the collapse_mask's for the bands we're - going to be folding from. */ - if (lowband_offset != 0 && (f->spread != CELT_SPREAD_AGGRESSIVE || - f->blocks > 1 || f->tf_change[i] < 0)) { - int foldstart, foldend; - - /* This ensures we never repeat spectral content within one band */ - effective_lowband = FFMAX(ff_celt_freq_bands[f->start_band], - ff_celt_freq_bands[lowband_offset] - ff_celt_freq_range[i]); - foldstart = lowband_offset; - while (ff_celt_freq_bands[--foldstart] > effective_lowband); - foldend = lowband_offset - 1; - while (ff_celt_freq_bands[++foldend] < effective_lowband + ff_celt_freq_range[i]); - - cm[0] = cm[1] = 0; - for (j = foldstart; j < foldend; j++) { - cm[0] |= f->block[0].collapse_masks[j]; - cm[1] |= f->block[f->channels - 1].collapse_masks[j]; - } - } - - if (f->dual_stereo && i == f->intensity_stereo) { - /* Switch off dual stereo to do intensity */ - f->dual_stereo = 0; - for (j = ff_celt_freq_bands[f->start_band] << f->size; j < band_offset; j++) - norm[j] = (norm[j] + norm2[j]) / 2; - } - - if (f->dual_stereo) { - cm[0] = f->pvq->decode_band(f->pvq, f, rc, i, X, NULL, band_size, b / 2, f->blocks, - effective_lowband != -1 ? norm + (effective_lowband << f->size) : NULL, f->size, - norm + band_offset, 0, 1.0f, lowband_scratch, cm[0]); - - cm[1] = f->pvq->decode_band(f->pvq, f, rc, i, Y, NULL, band_size, b/2, f->blocks, - effective_lowband != -1 ? norm2 + (effective_lowband << f->size) : NULL, f->size, - norm2 + band_offset, 0, 1.0f, lowband_scratch, cm[1]); - } else { - cm[0] = f->pvq->decode_band(f->pvq, f, rc, i, X, Y, band_size, b, f->blocks, - effective_lowband != -1 ? norm + (effective_lowband << f->size) : NULL, f->size, - norm + band_offset, 0, 1.0f, lowband_scratch, cm[0]|cm[1]); - cm[1] = cm[0]; - } - - f->block[0].collapse_masks[i] = (uint8_t)cm[0]; - f->block[f->channels - 1].collapse_masks[i] = (uint8_t)cm[1]; - f->remaining += f->pulses[i] + consumed; - - /* Update the folding position only as long as we have 1 bit/sample depth */ - update_lowband = (b > band_size << 3); - } -} - int ff_celt_decode_frame(CeltFrame *f, OpusRangeCoder *rc, float **output, int channels, int frame_size, int start_band, int end_band) @@ -806,8 +383,10 @@ int ff_celt_decode_frame(CeltFrame *f, OpusRangeCoder *rc, if (!f->output_channels) f->output_channels = channels; - memset(f->block[0].collapse_masks, 0, sizeof(f->block[0].collapse_masks)); - memset(f->block[1].collapse_masks, 0, sizeof(f->block[1].collapse_masks)); + for (i = 0; i < f->channels; i++) { + memset(f->block[i].coeffs, 0, sizeof(f->block[i].coeffs)); + memset(f->block[i].collapse_masks, 0, sizeof(f->block[i].collapse_masks)); + } consumed = opus_rc_tell(rc); @@ -842,9 +421,9 @@ int ff_celt_decode_frame(CeltFrame *f, OpusRangeCoder *rc, celt_decode_coarse_energy(f, rc); celt_decode_tf_changes (f, rc); - celt_decode_allocation (f, rc); + ff_celt_bitalloc (f, rc, 0); celt_decode_fine_energy (f, rc); - celt_decode_bands (f, rc); + ff_celt_quant_bands (f, rc); if (f->anticollapse_needed) f->anticollapse = ff_opus_rc_get_raw(rc, 1); @@ -984,7 +563,8 @@ void ff_celt_free(CeltFrame **f) av_freep(f); } -int ff_celt_init(AVCodecContext *avctx, CeltFrame **f, int output_channels) +int ff_celt_init(AVCodecContext *avctx, CeltFrame **f, int output_channels, + int apply_phase_inv) { CeltFrame *frm; int i, ret; @@ -1001,12 +581,13 @@ int ff_celt_init(AVCodecContext *avctx, CeltFrame **f, int output_channels) frm->avctx = avctx; frm->output_channels = output_channels; + frm->apply_phase_inv = apply_phase_inv; for (i = 0; i < FF_ARRAY_ELEMS(frm->imdct); i++) if ((ret = ff_mdct15_init(&frm->imdct[i], 1, i + 3, -1.0f/32768)) < 0) goto fail; - if ((ret = ff_celt_pvq_init(&frm->pvq)) < 0) + if ((ret = ff_celt_pvq_init(&frm->pvq, 0)) < 0) goto fail; frm->dsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT); diff --git a/libavcodec/opus_celt.h b/libavcodec/opus_celt.h index 45d50ab27b9f2..9289a1867af7e 100644 --- a/libavcodec/opus_celt.h +++ b/libavcodec/opus_celt.h @@ -98,6 +98,7 @@ struct CeltFrame { CeltPVQ *pvq; int channels; int output_channels; + int apply_phase_inv; enum CeltBlockSize size; int start_band; @@ -156,7 +157,8 @@ static av_always_inline void celt_renormalize_vector(float *X, int N, float gain X[i] *= g; } -int ff_celt_init(AVCodecContext *avctx, CeltFrame **f, int output_channels); +int ff_celt_init(AVCodecContext *avctx, CeltFrame **f, int output_channels, + int apply_phase_inv); void ff_celt_free(CeltFrame **f); diff --git a/libavcodec/opus_parser.c b/libavcodec/opus_parser.c index 893573eb82298..28b093390099e 100644 --- a/libavcodec/opus_parser.c +++ b/libavcodec/opus_parser.c @@ -43,6 +43,7 @@ static const uint8_t *parse_opus_ts_header(const uint8_t *start, int *payload_le const uint8_t *buf = start + 1; int start_trim_flag, end_trim_flag, control_extension_flag, control_extension_length; uint8_t flags; + uint64_t payload_len_tmp; GetByteContext gb; bytestream2_init(&gb, buf, buf_len); @@ -52,11 +53,11 @@ static const uint8_t *parse_opus_ts_header(const uint8_t *start, int *payload_le end_trim_flag = (flags >> 3) & 1; control_extension_flag = (flags >> 2) & 1; - *payload_len = 0; + payload_len_tmp = *payload_len = 0; while (bytestream2_peek_byte(&gb) == 0xff) - *payload_len += bytestream2_get_byte(&gb); + payload_len_tmp += bytestream2_get_byte(&gb); - *payload_len += bytestream2_get_byte(&gb); + payload_len_tmp += bytestream2_get_byte(&gb); if (start_trim_flag) bytestream2_skip(&gb, 2); @@ -67,6 +68,11 @@ static const uint8_t *parse_opus_ts_header(const uint8_t *start, int *payload_le bytestream2_skip(&gb, control_extension_length); } + if (bytestream2_tell(&gb) + payload_len_tmp > buf_len) + return NULL; + + *payload_len = payload_len_tmp; + return buf + bytestream2_tell(&gb); } @@ -104,6 +110,10 @@ static int opus_find_frame_end(AVCodecParserContext *ctx, AVCodecContext *avctx, state = (state << 8) | payload[i]; if ((state & OPUS_TS_MASK) == OPUS_TS_HEADER) { payload = parse_opus_ts_header(payload, &payload_len, buf_size - i); + if (!payload) { + av_log(avctx, AV_LOG_ERROR, "Error parsing Ogg TS header.\n"); + return AVERROR_INVALIDDATA; + } *header_len = payload - buf; start_found = 1; break; diff --git a/libavcodec/opus_pvq.c b/libavcodec/opus_pvq.c index f98b85d36fd33..0dbf14184d11e 100644 --- a/libavcodec/opus_pvq.c +++ b/libavcodec/opus_pvq.c @@ -486,8 +486,7 @@ static av_always_inline uint32_t quant_band_template(CeltPVQ *pvq, CeltFrame *f, int duration, float *lowband_out, int level, float gain, float *lowband_scratch, - int fill, int quant, - QUANT_FN(*rec)) + int fill, int quant) { int i; const uint8_t *cache; @@ -643,6 +642,7 @@ static av_always_inline uint32_t quant_band_template(CeltPVQ *pvq, CeltFrame *f, } } else { inv = (b > 2 << 3 && f->remaining2 > 2 << 3) ? ff_opus_rc_dec_log(rc, 2) : 0; + inv = f->apply_phase_inv ? inv : 0; } itheta = 0; } @@ -699,8 +699,8 @@ static av_always_inline uint32_t quant_band_template(CeltPVQ *pvq, CeltFrame *f, sign = 1 - 2 * sign; /* We use orig_fill here because we want to fold the side, but if itheta==16384, we'll have cleared the low bits of fill. */ - cm = rec(pvq, f, rc, band, x2, NULL, N, mbits, blocks, lowband, duration, - lowband_out, level, gain, lowband_scratch, orig_fill); + cm = pvq->quant_band(pvq, f, rc, band, x2, NULL, N, mbits, blocks, lowband, duration, + lowband_out, level, gain, lowband_scratch, orig_fill); /* We don't split N=2 bands, so cm is either 1 or 0 (for a fold-collapse), and there's no need to worry about mixing with the other channel. */ y2[0] = -sign * x2[1]; @@ -752,24 +752,25 @@ static av_always_inline uint32_t quant_band_template(CeltPVQ *pvq, CeltFrame *f, if (mbits >= sbits) { /* In stereo mode, we do not apply a scaling to the mid * because we need the normalized mid for folding later */ - cm = rec(pvq, f, rc, band, X, NULL, N, mbits, blocks, lowband, - duration, next_lowband_out1, next_level, - stereo ? 1.0f : (gain * mid), lowband_scratch, fill); + cm = pvq->quant_band(pvq, f, rc, band, X, NULL, N, mbits, blocks, + lowband, duration, next_lowband_out1, next_level, + stereo ? 1.0f : (gain * mid), lowband_scratch, fill); rebalance = mbits - (rebalance - f->remaining2); if (rebalance > 3 << 3 && itheta != 0) sbits += rebalance - (3 << 3); /* For a stereo split, the high bits of fill are always zero, * so no folding will be done to the side. */ - cmt = rec(pvq, f, rc, band, Y, NULL, N, sbits, blocks, next_lowband2, - duration, NULL, next_level, gain * side, NULL, - fill >> blocks); + cmt = pvq->quant_band(pvq, f, rc, band, Y, NULL, N, sbits, blocks, + next_lowband2, duration, NULL, next_level, + gain * side, NULL, fill >> blocks); cm |= cmt << ((B0 >> 1) & (stereo - 1)); } else { /* For a stereo split, the high bits of fill are always zero, * so no folding will be done to the side. */ - cm = rec(pvq, f, rc, band, Y, NULL, N, sbits, blocks, next_lowband2, - duration, NULL, next_level, gain * side, NULL, fill >> blocks); + cm = pvq->quant_band(pvq, f, rc, band, Y, NULL, N, sbits, blocks, + next_lowband2, duration, NULL, next_level, + gain * side, NULL, fill >> blocks); cm <<= ((B0 >> 1) & (stereo - 1)); rebalance = sbits - (rebalance - f->remaining2); if (rebalance > 3 << 3 && itheta != 16384) @@ -777,9 +778,9 @@ static av_always_inline uint32_t quant_band_template(CeltPVQ *pvq, CeltFrame *f, /* In stereo mode, we do not apply a scaling to the mid because * we need the normalized mid for folding later */ - cm |= rec(pvq, f, rc, band, X, NULL, N, mbits, blocks, lowband, duration, - next_lowband_out1, next_level, stereo ? 1.0f : (gain * mid), - lowband_scratch, fill); + cm |= pvq->quant_band(pvq, f, rc, band, X, NULL, N, mbits, blocks, + lowband, duration, next_lowband_out1, next_level, + stereo ? 1.0f : (gain * mid), lowband_scratch, fill); } } } else { @@ -873,80 +874,34 @@ static av_always_inline uint32_t quant_band_template(CeltPVQ *pvq, CeltFrame *f, return cm; } - static QUANT_FN(pvq_decode_band) { +#if CONFIG_OPUS_DECODER return quant_band_template(pvq, f, rc, band, X, Y, N, b, blocks, lowband, duration, - lowband_out, level, gain, lowband_scratch, fill, 0, - pvq->decode_band); + lowband_out, level, gain, lowband_scratch, fill, 0); +#else + return 0; +#endif } static QUANT_FN(pvq_encode_band) { +#if CONFIG_OPUS_ENCODER return quant_band_template(pvq, f, rc, band, X, Y, N, b, blocks, lowband, duration, - lowband_out, level, gain, lowband_scratch, fill, 1, - pvq->encode_band); -} - -static float pvq_band_cost(CeltPVQ *pvq, CeltFrame *f, OpusRangeCoder *rc, int band, - float *bits, float lambda) -{ - int i, b = 0; - uint32_t cm[2] = { (1 << f->blocks) - 1, (1 << f->blocks) - 1 }; - const int band_size = ff_celt_freq_range[band] << f->size; - float buf[176 * 2], lowband_scratch[176], norm1[176], norm2[176]; - float dist, cost, err_x = 0.0f, err_y = 0.0f; - float *X = buf; - float *X_orig = f->block[0].coeffs + (ff_celt_freq_bands[band] << f->size); - float *Y = (f->channels == 2) ? &buf[176] : NULL; - float *Y_orig = f->block[1].coeffs + (ff_celt_freq_bands[band] << f->size); - OPUS_RC_CHECKPOINT_SPAWN(rc); - - memcpy(X, X_orig, band_size*sizeof(float)); - if (Y) - memcpy(Y, Y_orig, band_size*sizeof(float)); - - f->remaining2 = ((f->framebits << 3) - f->anticollapse_needed) - opus_rc_tell_frac(rc) - 1; - if (band <= f->coded_bands - 1) { - int curr_balance = f->remaining / FFMIN(3, f->coded_bands - band); - b = av_clip_uintp2(FFMIN(f->remaining2 + 1, f->pulses[band] + curr_balance), 14); - } - - if (f->dual_stereo) { - pvq->encode_band(pvq, f, rc, band, X, NULL, band_size, b / 2, f->blocks, NULL, - f->size, norm1, 0, 1.0f, lowband_scratch, cm[0]); - - pvq->encode_band(pvq, f, rc, band, Y, NULL, band_size, b / 2, f->blocks, NULL, - f->size, norm2, 0, 1.0f, lowband_scratch, cm[1]); - } else { - pvq->encode_band(pvq, f, rc, band, X, Y, band_size, b, f->blocks, NULL, f->size, - norm1, 0, 1.0f, lowband_scratch, cm[0] | cm[1]); - } - - for (i = 0; i < band_size; i++) { - err_x += (X[i] - X_orig[i])*(X[i] - X_orig[i]); - err_y += (Y[i] - Y_orig[i])*(Y[i] - Y_orig[i]); - } - - dist = sqrtf(err_x) + sqrtf(err_y); - cost = OPUS_RC_CHECKPOINT_BITS(rc)/8.0f; - *bits += cost; - - OPUS_RC_CHECKPOINT_ROLLBACK(rc); - - return lambda*dist*cost; + lowband_out, level, gain, lowband_scratch, fill, 1); +#else + return 0; +#endif } -int av_cold ff_celt_pvq_init(CeltPVQ **pvq) +int av_cold ff_celt_pvq_init(CeltPVQ **pvq, int encode) { CeltPVQ *s = av_malloc(sizeof(CeltPVQ)); if (!s) return AVERROR(ENOMEM); - s->pvq_search = ppp_pvq_search_c; - s->decode_band = pvq_decode_band; - s->encode_band = pvq_encode_band; - s->band_cost = pvq_band_cost; + s->pvq_search = ppp_pvq_search_c; + s->quant_band = encode ? pvq_encode_band : pvq_decode_band; if (ARCH_X86) ff_opus_dsp_init_x86(s); diff --git a/libavcodec/opus_pvq.h b/libavcodec/opus_pvq.h index 92463373603bb..e2f01a01b5c68 100644 --- a/libavcodec/opus_pvq.h +++ b/libavcodec/opus_pvq.h @@ -37,15 +37,12 @@ struct CeltPVQ { DECLARE_ALIGNED(32, float, hadamard_tmp)[256]; float (*pvq_search)(float *X, int *y, int K, int N); - - QUANT_FN(*decode_band); - QUANT_FN(*encode_band); - float (*band_cost)(struct CeltPVQ *pvq, CeltFrame *f, OpusRangeCoder *rc, - int band, float *bits, float lambda); + QUANT_FN(*quant_band); }; -int ff_celt_pvq_init (struct CeltPVQ **pvq); void ff_opus_dsp_init_x86(struct CeltPVQ *s); + +int ff_celt_pvq_init(struct CeltPVQ **pvq, int encode); void ff_celt_pvq_uninit(struct CeltPVQ **pvq); #endif /* AVCODEC_OPUS_PVQ_H */ diff --git a/libavcodec/opus_silk.c b/libavcodec/opus_silk.c index 3c9c849c21de9..344333cc180f0 100644 --- a/libavcodec/opus_silk.c +++ b/libavcodec/opus_silk.c @@ -185,8 +185,15 @@ static inline int silk_is_lpc_stable(const int16_t lpc[16], int order) row = lpc32[k & 1]; for (j = 0; j < k; j++) { - int x = prevrow[j] - ROUND_MULL(prevrow[k - j - 1], rc, 31); - row[j] = ROUND_MULL(x, gain, fbits); + int x = av_sat_sub32(prevrow[j], ROUND_MULL(prevrow[k - j - 1], rc, 31)); + int64_t tmp = ROUND_MULL(x, gain, fbits); + + /* per RFC 8251 section 6, if this calculation overflows, the filter + is considered unstable. */ + if (tmp < INT32_MIN || tmp > INT32_MAX) + return 0; + + row[j] = (int32_t)tmp; } } } diff --git a/libavcodec/opusdec.c b/libavcodec/opusdec.c index 5a7ba9dbb4354..03086dea99e2c 100644 --- a/libavcodec/opusdec.c +++ b/libavcodec/opusdec.c @@ -687,7 +687,7 @@ static av_cold int opus_decode_init(AVCodecContext *avctx) if (ret < 0) goto fail; - ret = ff_celt_init(avctx, &s->celt, s->output_channels); + ret = ff_celt_init(avctx, &s->celt, s->output_channels, c->apply_phase_inv); if (ret < 0) goto fail; @@ -712,9 +712,24 @@ static av_cold int opus_decode_init(AVCodecContext *avctx) return ret; } +#define OFFSET(x) offsetof(OpusContext, x) +#define AD AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM +static const AVOption opus_options[] = { + { "apply_phase_inv", "Apply intensity stereo phase inversion", OFFSET(apply_phase_inv), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, AD }, + { NULL }, +}; + +static const AVClass opus_class = { + .class_name = "Opus Decoder", + .item_name = av_default_item_name, + .option = opus_options, + .version = LIBAVUTIL_VERSION_INT, +}; + AVCodec ff_opus_decoder = { .name = "opus", .long_name = NULL_IF_CONFIG_SMALL("Opus"), + .priv_class = &opus_class, .type = AVMEDIA_TYPE_AUDIO, .id = AV_CODEC_ID_OPUS, .priv_data_size = sizeof(OpusContext), diff --git a/libavcodec/opusenc.c b/libavcodec/opusenc.c index 79d20dc6e693c..4068c4359470e 100644 --- a/libavcodec/opusenc.c +++ b/libavcodec/opusenc.c @@ -255,7 +255,7 @@ static void celt_frame_mdct(OpusEncContext *s, CeltFrame *f) } } -static void celt_enc_tf(OpusRangeCoder *rc, CeltFrame *f) +static void celt_enc_tf(CeltFrame *f, OpusRangeCoder *rc) { int i, tf_select = 0, diff = 0, tf_changed = 0, tf_select_needed; int bits = f->transient ? 2 : 4; @@ -282,333 +282,6 @@ static void celt_enc_tf(OpusRangeCoder *rc, CeltFrame *f) f->tf_change[i] = ff_celt_tf_select[f->size][f->transient][tf_select][f->tf_change[i]]; } -void ff_celt_enc_bitalloc(OpusRangeCoder *rc, CeltFrame *f) -{ - int i, j, low, high, total, done, bandbits, remaining, tbits_8ths; - int skip_startband = f->start_band; - int skip_bit = 0; - int intensitystereo_bit = 0; - int dualstereo_bit = 0; - int dynalloc = 6; - int extrabits = 0; - - int *cap = f->caps; - int boost[CELT_MAX_BANDS]; - int trim_offset[CELT_MAX_BANDS]; - int threshold[CELT_MAX_BANDS]; - int bits1[CELT_MAX_BANDS]; - int bits2[CELT_MAX_BANDS]; - - /* Tell the spread to the decoder */ - if (opus_rc_tell(rc) + 4 <= f->framebits) - ff_opus_rc_enc_cdf(rc, f->spread, ff_celt_model_spread); - else - f->spread = CELT_SPREAD_NORMAL; - - /* Generate static allocation caps */ - for (i = 0; i < CELT_MAX_BANDS; i++) { - cap[i] = (ff_celt_static_caps[f->size][f->channels - 1][i] + 64) - * ff_celt_freq_range[i] << (f->channels - 1) << f->size >> 2; - } - - /* Band boosts */ - tbits_8ths = f->framebits << 3; - for (i = f->start_band; i < f->end_band; i++) { - int quanta, b_dynalloc, boost_amount = f->alloc_boost[i]; - - boost[i] = 0; - - quanta = ff_celt_freq_range[i] << (f->channels - 1) << f->size; - quanta = FFMIN(quanta << 3, FFMAX(6 << 3, quanta)); - b_dynalloc = dynalloc; - - while (opus_rc_tell_frac(rc) + (b_dynalloc << 3) < tbits_8ths && boost[i] < cap[i]) { - int is_boost = boost_amount--; - - ff_opus_rc_enc_log(rc, is_boost, b_dynalloc); - if (!is_boost) - break; - - boost[i] += quanta; - tbits_8ths -= quanta; - - b_dynalloc = 1; - } - - if (boost[i]) - dynalloc = FFMAX(2, dynalloc - 1); - } - - /* Put allocation trim */ - if (opus_rc_tell_frac(rc) + (6 << 3) <= tbits_8ths) - ff_opus_rc_enc_cdf(rc, f->alloc_trim, ff_celt_model_alloc_trim); - - /* Anti-collapse bit reservation */ - tbits_8ths = (f->framebits << 3) - opus_rc_tell_frac(rc) - 1; - f->anticollapse_needed = 0; - if (f->transient && f->size >= 2 && tbits_8ths >= ((f->size + 2) << 3)) - f->anticollapse_needed = 1 << 3; - tbits_8ths -= f->anticollapse_needed; - - /* Band skip bit reservation */ - if (tbits_8ths >= 1 << 3) - skip_bit = 1 << 3; - tbits_8ths -= skip_bit; - - /* Intensity/dual stereo bit reservation */ - if (f->channels == 2) { - intensitystereo_bit = ff_celt_log2_frac[f->end_band - f->start_band]; - if (intensitystereo_bit <= tbits_8ths) { - tbits_8ths -= intensitystereo_bit; - if (tbits_8ths >= 1 << 3) { - dualstereo_bit = 1 << 3; - tbits_8ths -= 1 << 3; - } - } else { - intensitystereo_bit = 0; - } - } - - /* Trim offsets */ - for (i = f->start_band; i < f->end_band; i++) { - int trim = f->alloc_trim - 5 - f->size; - int band = ff_celt_freq_range[i] * (f->end_band - i - 1); - int duration = f->size + 3; - int scale = duration + f->channels - 1; - - /* PVQ minimum allocation threshold, below this value the band is - * skipped */ - threshold[i] = FFMAX(3 * ff_celt_freq_range[i] << duration >> 4, - f->channels << 3); - - trim_offset[i] = trim * (band << scale) >> 6; - - if (ff_celt_freq_range[i] << f->size == 1) - trim_offset[i] -= f->channels << 3; - } - - /* Bisection */ - low = 1; - high = CELT_VECTORS - 1; - while (low <= high) { - int center = (low + high) >> 1; - done = total = 0; - - for (i = f->end_band - 1; i >= f->start_band; i--) { - bandbits = ff_celt_freq_range[i] * ff_celt_static_alloc[center][i] - << (f->channels - 1) << f->size >> 2; - - if (bandbits) - bandbits = FFMAX(0, bandbits + trim_offset[i]); - bandbits += boost[i]; - - if (bandbits >= threshold[i] || done) { - done = 1; - total += FFMIN(bandbits, cap[i]); - } else if (bandbits >= f->channels << 3) - total += f->channels << 3; - } - - if (total > tbits_8ths) - high = center - 1; - else - low = center + 1; - } - high = low--; - - /* Bisection */ - for (i = f->start_band; i < f->end_band; i++) { - bits1[i] = ff_celt_freq_range[i] * ff_celt_static_alloc[low][i] - << (f->channels - 1) << f->size >> 2; - bits2[i] = high >= CELT_VECTORS ? cap[i] : - ff_celt_freq_range[i] * ff_celt_static_alloc[high][i] - << (f->channels - 1) << f->size >> 2; - - if (bits1[i]) - bits1[i] = FFMAX(0, bits1[i] + trim_offset[i]); - if (bits2[i]) - bits2[i] = FFMAX(0, bits2[i] + trim_offset[i]); - if (low) - bits1[i] += boost[i]; - bits2[i] += boost[i]; - - if (boost[i]) - skip_startband = i; - bits2[i] = FFMAX(0, bits2[i] - bits1[i]); - } - - /* Bisection */ - low = 0; - high = 1 << CELT_ALLOC_STEPS; - for (i = 0; i < CELT_ALLOC_STEPS; i++) { - int center = (low + high) >> 1; - done = total = 0; - - for (j = f->end_band - 1; j >= f->start_band; j--) { - bandbits = bits1[j] + (center * bits2[j] >> CELT_ALLOC_STEPS); - - if (bandbits >= threshold[j] || done) { - done = 1; - total += FFMIN(bandbits, cap[j]); - } else if (bandbits >= f->channels << 3) - total += f->channels << 3; - } - if (total > tbits_8ths) - high = center; - else - low = center; - } - - /* Bisection */ - done = total = 0; - for (i = f->end_band - 1; i >= f->start_band; i--) { - bandbits = bits1[i] + (low * bits2[i] >> CELT_ALLOC_STEPS); - - if (bandbits >= threshold[i] || done) - done = 1; - else - bandbits = (bandbits >= f->channels << 3) ? - f->channels << 3 : 0; - - bandbits = FFMIN(bandbits, cap[i]); - f->pulses[i] = bandbits; - total += bandbits; - } - - /* Band skipping */ - for (f->coded_bands = f->end_band; ; f->coded_bands--) { - int allocation; - j = f->coded_bands - 1; - - if (j == skip_startband) { - /* all remaining bands are not skipped */ - tbits_8ths += skip_bit; - break; - } - - /* determine the number of bits available for coding "do not skip" markers */ - remaining = tbits_8ths - total; - bandbits = remaining / (ff_celt_freq_bands[j+1] - ff_celt_freq_bands[f->start_band]); - remaining -= bandbits * (ff_celt_freq_bands[j+1] - ff_celt_freq_bands[f->start_band]); - allocation = f->pulses[j] + bandbits * ff_celt_freq_range[j] - + FFMAX(0, remaining - (ff_celt_freq_bands[j] - ff_celt_freq_bands[f->start_band])); - - /* a "do not skip" marker is only coded if the allocation is - above the chosen threshold */ - if (allocation >= FFMAX(threshold[j], (f->channels + 1) << 3)) { - const int do_not_skip = f->coded_bands <= f->skip_band_floor; - ff_opus_rc_enc_log(rc, do_not_skip, 1); - if (do_not_skip) - break; - - total += 1 << 3; - allocation -= 1 << 3; - } - - /* the band is skipped, so reclaim its bits */ - total -= f->pulses[j]; - if (intensitystereo_bit) { - total -= intensitystereo_bit; - intensitystereo_bit = ff_celt_log2_frac[j - f->start_band]; - total += intensitystereo_bit; - } - - total += f->pulses[j] = (allocation >= f->channels << 3) ? f->channels << 3 : 0; - } - - /* Encode stereo flags */ - if (intensitystereo_bit) { - f->intensity_stereo = FFMIN(f->intensity_stereo, f->coded_bands); - ff_opus_rc_enc_uint(rc, f->intensity_stereo, f->coded_bands + 1 - f->start_band); - } - if (f->intensity_stereo <= f->start_band) - tbits_8ths += dualstereo_bit; /* no intensity stereo means no dual stereo */ - else if (dualstereo_bit) - ff_opus_rc_enc_log(rc, f->dual_stereo, 1); - - /* Supply the remaining bits in this frame to lower bands */ - remaining = tbits_8ths - total; - bandbits = remaining / (ff_celt_freq_bands[f->coded_bands] - ff_celt_freq_bands[f->start_band]); - remaining -= bandbits * (ff_celt_freq_bands[f->coded_bands] - ff_celt_freq_bands[f->start_band]); - for (i = f->start_band; i < f->coded_bands; i++) { - int bits = FFMIN(remaining, ff_celt_freq_range[i]); - - f->pulses[i] += bits + bandbits * ff_celt_freq_range[i]; - remaining -= bits; - } - - /* Finally determine the allocation */ - for (i = f->start_band; i < f->coded_bands; i++) { - int N = ff_celt_freq_range[i] << f->size; - int prev_extra = extrabits; - f->pulses[i] += extrabits; - - if (N > 1) { - int dof; // degrees of freedom - int temp; // dof * channels * log(dof) - int offset; // fine energy quantization offset, i.e. - // extra bits assigned over the standard - // totalbits/dof - int fine_bits, max_bits; - - extrabits = FFMAX(0, f->pulses[i] - cap[i]); - f->pulses[i] -= extrabits; - - /* intensity stereo makes use of an extra degree of freedom */ - dof = N * f->channels + (f->channels == 2 && N > 2 && !f->dual_stereo && i < f->intensity_stereo); - temp = dof * (ff_celt_log_freq_range[i] + (f->size << 3)); - offset = (temp >> 1) - dof * CELT_FINE_OFFSET; - if (N == 2) /* dof=2 is the only case that doesn't fit the model */ - offset += dof << 1; - - /* grant an additional bias for the first and second pulses */ - if (f->pulses[i] + offset < 2 * (dof << 3)) - offset += temp >> 2; - else if (f->pulses[i] + offset < 3 * (dof << 3)) - offset += temp >> 3; - - fine_bits = (f->pulses[i] + offset + (dof << 2)) / (dof << 3); - max_bits = FFMIN((f->pulses[i] >> 3) >> (f->channels - 1), CELT_MAX_FINE_BITS); - - max_bits = FFMAX(max_bits, 0); - - f->fine_bits[i] = av_clip(fine_bits, 0, max_bits); - - /* if fine_bits was rounded down or capped, - give priority for the final fine energy pass */ - f->fine_priority[i] = (f->fine_bits[i] * (dof << 3) >= f->pulses[i] + offset); - - /* the remaining bits are assigned to PVQ */ - f->pulses[i] -= f->fine_bits[i] << (f->channels - 1) << 3; - } else { - /* all bits go to fine energy except for the sign bit */ - extrabits = FFMAX(0, f->pulses[i] - (f->channels << 3)); - f->pulses[i] -= extrabits; - f->fine_bits[i] = 0; - f->fine_priority[i] = 1; - } - - /* hand back a limited number of extra fine energy bits to this band */ - if (extrabits > 0) { - int fineextra = FFMIN(extrabits >> (f->channels + 2), - CELT_MAX_FINE_BITS - f->fine_bits[i]); - f->fine_bits[i] += fineextra; - - fineextra <<= f->channels + 2; - f->fine_priority[i] = (fineextra >= extrabits - prev_extra); - extrabits -= fineextra; - } - } - f->remaining = extrabits; - - /* skipped bands dedicate all of their bits for fine energy */ - for (; i < f->end_band; i++) { - f->fine_bits[i] = f->pulses[i] >> (f->channels - 1) >> 3; - f->pulses[i] = 0; - f->fine_priority[i] = f->fine_bits[i] < 1; - } -} - static void celt_enc_quant_pfilter(OpusRangeCoder *rc, CeltFrame *f) { float gain = f->pf_gain; @@ -690,7 +363,7 @@ static void exp_quant_coarse(OpusRangeCoder *rc, CeltFrame *f, } } -static void celt_quant_coarse(OpusRangeCoder *rc, CeltFrame *f, +static void celt_quant_coarse(CeltFrame *f, OpusRangeCoder *rc, float last_energy[][CELT_MAX_BANDS]) { uint32_t inter, intra; @@ -710,7 +383,7 @@ static void celt_quant_coarse(OpusRangeCoder *rc, CeltFrame *f, } } -static void celt_quant_fine(OpusRangeCoder *rc, CeltFrame *f) +static void celt_quant_fine(CeltFrame *f, OpusRangeCoder *rc) { int i, ch; for (i = f->start_band; i < f->end_band; i++) { @@ -747,95 +420,6 @@ static void celt_quant_final(OpusEncContext *s, OpusRangeCoder *rc, CeltFrame *f } } -static void celt_quant_bands(OpusRangeCoder *rc, CeltFrame *f) -{ - float lowband_scratch[8 * 22]; - float norm[2 * 8 * 100]; - - int totalbits = (f->framebits << 3) - f->anticollapse_needed; - - int update_lowband = 1; - int lowband_offset = 0; - - int i, j; - - for (i = f->start_band; i < f->end_band; i++) { - uint32_t cm[2] = { (1 << f->blocks) - 1, (1 << f->blocks) - 1 }; - int band_offset = ff_celt_freq_bands[i] << f->size; - int band_size = ff_celt_freq_range[i] << f->size; - float *X = f->block[0].coeffs + band_offset; - float *Y = (f->channels == 2) ? f->block[1].coeffs + band_offset : NULL; - - int consumed = opus_rc_tell_frac(rc); - float *norm2 = norm + 8 * 100; - int effective_lowband = -1; - int b = 0; - - /* Compute how many bits we want to allocate to this band */ - if (i != f->start_band) - f->remaining -= consumed; - f->remaining2 = totalbits - consumed - 1; - if (i <= f->coded_bands - 1) { - int curr_balance = f->remaining / FFMIN(3, f->coded_bands-i); - b = av_clip_uintp2(FFMIN(f->remaining2 + 1, f->pulses[i] + curr_balance), 14); - } - - if (ff_celt_freq_bands[i] - ff_celt_freq_range[i] >= ff_celt_freq_bands[f->start_band] && - (update_lowband || lowband_offset == 0)) - lowband_offset = i; - - /* Get a conservative estimate of the collapse_mask's for the bands we're - going to be folding from. */ - if (lowband_offset != 0 && (f->spread != CELT_SPREAD_AGGRESSIVE || - f->blocks > 1 || f->tf_change[i] < 0)) { - int foldstart, foldend; - - /* This ensures we never repeat spectral content within one band */ - effective_lowband = FFMAX(ff_celt_freq_bands[f->start_band], - ff_celt_freq_bands[lowband_offset] - ff_celt_freq_range[i]); - foldstart = lowband_offset; - while (ff_celt_freq_bands[--foldstart] > effective_lowband); - foldend = lowband_offset - 1; - while (ff_celt_freq_bands[++foldend] < effective_lowband + ff_celt_freq_range[i]); - - cm[0] = cm[1] = 0; - for (j = foldstart; j < foldend; j++) { - cm[0] |= f->block[0].collapse_masks[j]; - cm[1] |= f->block[f->channels - 1].collapse_masks[j]; - } - } - - if (f->dual_stereo && i == f->intensity_stereo) { - /* Switch off dual stereo to do intensity */ - f->dual_stereo = 0; - for (j = ff_celt_freq_bands[f->start_band] << f->size; j < band_offset; j++) - norm[j] = (norm[j] + norm2[j]) / 2; - } - - if (f->dual_stereo) { - cm[0] = f->pvq->encode_band(f->pvq, f, rc, i, X, NULL, band_size, b / 2, f->blocks, - effective_lowband != -1 ? norm + (effective_lowband << f->size) : NULL, f->size, - norm + band_offset, 0, 1.0f, lowband_scratch, cm[0]); - - cm[1] = f->pvq->encode_band(f->pvq, f, rc, i, Y, NULL, band_size, b / 2, f->blocks, - effective_lowband != -1 ? norm2 + (effective_lowband << f->size) : NULL, f->size, - norm2 + band_offset, 0, 1.0f, lowband_scratch, cm[1]); - } else { - cm[0] = f->pvq->encode_band(f->pvq, f, rc, i, X, Y, band_size, b, f->blocks, - effective_lowband != -1 ? norm + (effective_lowband << f->size) : NULL, f->size, - norm + band_offset, 0, 1.0f, lowband_scratch, cm[0] | cm[1]); - cm[1] = cm[0]; - } - - f->block[0].collapse_masks[i] = (uint8_t)cm[0]; - f->block[f->channels - 1].collapse_masks[i] = (uint8_t)cm[1]; - f->remaining += f->pulses[i] + consumed; - - /* Update the folding position only as long as we have 1 bit/sample depth */ - update_lowband = (b > band_size << 3); - } -} - static void celt_encode_frame(OpusEncContext *s, OpusRangeCoder *rc, CeltFrame *f, int index) { @@ -883,11 +467,11 @@ static void celt_encode_frame(OpusEncContext *s, OpusRangeCoder *rc, ff_opus_rc_enc_log(rc, f->transient, 3); /* Main encoding */ - celt_quant_coarse(rc, f, s->last_quantized_energy); - celt_enc_tf (rc, f); - ff_celt_enc_bitalloc(rc, f); - celt_quant_fine (rc, f); - celt_quant_bands (rc, f); + celt_quant_coarse (f, rc, s->last_quantized_energy); + celt_enc_tf (f, rc); + ff_celt_bitalloc (f, rc, 1); + celt_quant_fine (f, rc); + ff_celt_quant_bands(f, rc); /* Anticollapse bit */ if (f->anticollapse_needed) @@ -1080,7 +664,7 @@ static av_cold int opus_encode_init(AVCodecContext *avctx) ff_af_queue_init(avctx, &s->afq); - if ((ret = ff_celt_pvq_init(&s->pvq)) < 0) + if ((ret = ff_celt_pvq_init(&s->pvq, 1)) < 0) return ret; if (!(s->dsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT))) @@ -1117,6 +701,7 @@ static av_cold int opus_encode_init(AVCodecContext *avctx) s->frame[i].avctx = s->avctx; s->frame[i].seed = 0; s->frame[i].pvq = s->pvq; + s->frame[i].apply_phase_inv = 1; s->frame[i].block[0].emph_coeff = s->frame[i].block[1].emph_coeff = 0.0f; } diff --git a/libavcodec/opusenc.h b/libavcodec/opusenc.h index 3273d0a9a2a78..b9162ebec64ce 100644 --- a/libavcodec/opusenc.h +++ b/libavcodec/opusenc.h @@ -51,6 +51,4 @@ typedef struct OpusPacketInfo { int frames; } OpusPacketInfo; -void ff_celt_enc_bitalloc(OpusRangeCoder *rc, CeltFrame *f); - #endif /* AVCODEC_OPUSENC_H */ diff --git a/libavcodec/opusenc_psy.c b/libavcodec/opusenc_psy.c index b446d41f755db..5a50db942f731 100644 --- a/libavcodec/opusenc_psy.c +++ b/libavcodec/opusenc_psy.c @@ -25,6 +25,56 @@ #include "mdct15.h" #include "libavutil/qsort.h" +static float pvq_band_cost(CeltPVQ *pvq, CeltFrame *f, OpusRangeCoder *rc, int band, + float *bits, float lambda) +{ + int i, b = 0; + uint32_t cm[2] = { (1 << f->blocks) - 1, (1 << f->blocks) - 1 }; + const int band_size = ff_celt_freq_range[band] << f->size; + float buf[176 * 2], lowband_scratch[176], norm1[176], norm2[176]; + float dist, cost, err_x = 0.0f, err_y = 0.0f; + float *X = buf; + float *X_orig = f->block[0].coeffs + (ff_celt_freq_bands[band] << f->size); + float *Y = (f->channels == 2) ? &buf[176] : NULL; + float *Y_orig = f->block[1].coeffs + (ff_celt_freq_bands[band] << f->size); + OPUS_RC_CHECKPOINT_SPAWN(rc); + + memcpy(X, X_orig, band_size*sizeof(float)); + if (Y) + memcpy(Y, Y_orig, band_size*sizeof(float)); + + f->remaining2 = ((f->framebits << 3) - f->anticollapse_needed) - opus_rc_tell_frac(rc) - 1; + if (band <= f->coded_bands - 1) { + int curr_balance = f->remaining / FFMIN(3, f->coded_bands - band); + b = av_clip_uintp2(FFMIN(f->remaining2 + 1, f->pulses[band] + curr_balance), 14); + } + + if (f->dual_stereo) { + pvq->quant_band(pvq, f, rc, band, X, NULL, band_size, b / 2, f->blocks, NULL, + f->size, norm1, 0, 1.0f, lowband_scratch, cm[0]); + + pvq->quant_band(pvq, f, rc, band, Y, NULL, band_size, b / 2, f->blocks, NULL, + f->size, norm2, 0, 1.0f, lowband_scratch, cm[1]); + } else { + pvq->quant_band(pvq, f, rc, band, X, Y, band_size, b, f->blocks, NULL, f->size, + norm1, 0, 1.0f, lowband_scratch, cm[0] | cm[1]); + } + + for (i = 0; i < band_size; i++) { + err_x += (X[i] - X_orig[i])*(X[i] - X_orig[i]); + if (Y) + err_y += (Y[i] - Y_orig[i])*(Y[i] - Y_orig[i]); + } + + dist = sqrtf(err_x) + sqrtf(err_y); + cost = OPUS_RC_CHECKPOINT_BITS(rc)/8.0f; + *bits += cost; + + OPUS_RC_CHECKPOINT_ROLLBACK(rc); + + return lambda*dist*cost; +} + /* Populate metrics without taking into consideration neighbouring steps */ static void step_collect_psy_metrics(OpusPsyContext *s, int index) { @@ -69,7 +119,7 @@ static void step_collect_psy_metrics(OpusPsyContext *s, int index) for (j = 0; j < range; j++) { const float c_s = coeffs[j]*coeffs[j]; - dist_dev = (avg_c_s - c_s)*(avg_c_s - c_s); + dist_dev += (avg_c_s - c_s)*(avg_c_s - c_s); } st->tone[ch][i] += sqrtf(dist_dev); @@ -316,11 +366,11 @@ static int bands_dist(OpusPsyContext *s, CeltFrame *f, float *total_dist) OpusRangeCoder dump; ff_opus_rc_enc_init(&dump); - ff_celt_enc_bitalloc(&dump, f); + ff_celt_bitalloc(f, &dump, 1); for (i = 0; i < CELT_MAX_BANDS; i++) { float bits = 0.0f; - float dist = f->pvq->band_cost(f->pvq, f, &dump, i, &bits, s->lambda); + float dist = pvq_band_cost(f->pvq, f, &dump, i, &bits, s->lambda); tdist += dist; } @@ -333,6 +383,10 @@ static void celt_search_for_dual_stereo(OpusPsyContext *s, CeltFrame *f) { float td1, td2; f->dual_stereo = 0; + + if (s->avctx->channels < 2) + return; + bands_dist(s, f, &td1); f->dual_stereo = 1; bands_dist(s, f, &td2); @@ -345,10 +399,12 @@ static void celt_search_for_intensity(OpusPsyContext *s, CeltFrame *f) { int i, best_band = CELT_MAX_BANDS - 1; float dist, best_dist = FLT_MAX; - /* TODO: fix, make some heuristic up here using the lambda value */ float end_band = 0; + if (s->avctx->channels < 2) + return; + for (i = f->end_band; i >= end_band; i--) { f->intensity_stereo = i; bands_dist(s, f, &dist); @@ -370,7 +426,6 @@ static int celt_search_for_tf(OpusPsyContext *s, OpusPsyStep **start, CeltFrame for (cway = 0; cway < 2; cway++) { int mag[2]; int base = f->transient ? 120 : 960; - int i; for (i = 0; i < 2; i++) { int c = ff_celt_tf_select[f->size][f->transient][cway][i]; diff --git a/libavcodec/pafvideo.c b/libavcodec/pafvideo.c index 91bfe16376be5..7c5861dfaf6c6 100644 --- a/libavcodec/pafvideo.c +++ b/libavcodec/pafvideo.c @@ -78,6 +78,7 @@ static av_cold int paf_video_init(AVCodecContext *avctx) { PAFVideoDecContext *c = avctx->priv_data; int i; + int ret; c->width = avctx->width; c->height = avctx->height; @@ -90,6 +91,9 @@ static av_cold int paf_video_init(AVCodecContext *avctx) } avctx->pix_fmt = AV_PIX_FMT_PAL8; + ret = av_image_check_size2(avctx->width, FFALIGN(avctx->height, 256), avctx->max_pixels, avctx->pix_fmt, 0, avctx); + if (ret < 0) + return ret; c->pic = av_frame_alloc(); if (!c->pic) @@ -181,6 +185,8 @@ static int decode_0(PAFVideoDecContext *c, uint8_t *pkt, uint8_t code) dend = c->frame[page] + c->frame_size; offset = (x & 0x7F) * 2; j = bytestream2_get_le16(&c->gb) + offset; + if (bytestream2_get_bytes_left(&c->gb) < (j - offset) * 16) + return AVERROR_INVALIDDATA; do { offset++; if (dst + 3 * c->width + 4 > dend) @@ -198,7 +204,8 @@ static int decode_0(PAFVideoDecContext *c, uint8_t *pkt, uint8_t code) do { set_src_position(c, &src, &send); if ((src + 3 * c->width + 4 > send) || - (dst + 3 * c->width + 4 > dend)) + (dst + 3 * c->width + 4 > dend) || + bytestream2_get_bytes_left(&c->gb) < 4) return AVERROR_INVALIDDATA; copy_block4(dst, src, c->width, c->width, 4); i++; diff --git a/libavcodec/parser.c b/libavcodec/parser.c index 670680ea7c1d4..f43b197d5eaca 100644 --- a/libavcodec/parser.c +++ b/libavcodec/parser.c @@ -25,40 +25,108 @@ #include #include "libavutil/avassert.h" -#include "libavutil/atomic.h" #include "libavutil/internal.h" #include "libavutil/mem.h" +#include "libavutil/thread.h" #include "internal.h" #include "parser.h" -static AVCodecParser *av_first_parser = NULL; +/* Parsers */ +extern AVCodecParser ff_aac_parser; +extern AVCodecParser ff_aac_latm_parser; +extern AVCodecParser ff_ac3_parser; +extern AVCodecParser ff_adx_parser; +extern AVCodecParser ff_bmp_parser; +extern AVCodecParser ff_cavsvideo_parser; +extern AVCodecParser ff_cook_parser; +extern AVCodecParser ff_dca_parser; +extern AVCodecParser ff_dirac_parser; +extern AVCodecParser ff_dnxhd_parser; +extern AVCodecParser ff_dpx_parser; +extern AVCodecParser ff_dvaudio_parser; +extern AVCodecParser ff_dvbsub_parser; +extern AVCodecParser ff_dvdsub_parser; +extern AVCodecParser ff_dvd_nav_parser; +extern AVCodecParser ff_flac_parser; +extern AVCodecParser ff_g729_parser; +extern AVCodecParser ff_gsm_parser; +extern AVCodecParser ff_h261_parser; +extern AVCodecParser ff_h263_parser; +extern AVCodecParser ff_h264_parser; +extern AVCodecParser ff_hevc_parser; +extern AVCodecParser ff_mjpeg_parser; +extern AVCodecParser ff_mlp_parser; +extern AVCodecParser ff_mpeg4video_parser; +extern AVCodecParser ff_mpegaudio_parser; +extern AVCodecParser ff_mpegvideo_parser; +extern AVCodecParser ff_opus_parser; +extern AVCodecParser ff_png_parser; +extern AVCodecParser ff_pnm_parser; +extern AVCodecParser ff_rv30_parser; +extern AVCodecParser ff_rv40_parser; +extern AVCodecParser ff_sbc_parser; +extern AVCodecParser ff_sipr_parser; +extern AVCodecParser ff_tak_parser; +extern AVCodecParser ff_vc1_parser; +extern AVCodecParser ff_vorbis_parser; +extern AVCodecParser ff_vp3_parser; +extern AVCodecParser ff_vp8_parser; +extern AVCodecParser ff_vp9_parser; +extern AVCodecParser ff_xma_parser; + +#include "libavcodec/parser_list.c" + +static AVOnce av_parser_next_init = AV_ONCE_INIT; + +static void av_parser_init_next(void) +{ + AVCodecParser *prev = NULL, *p; + int i = 0; + while ((p = (AVCodecParser*)parser_list[i++])) { + if (prev) + prev->next = p; + prev = p; + } +} AVCodecParser *av_parser_next(const AVCodecParser *p) { + ff_thread_once(&av_parser_next_init, av_parser_init_next); + if (p) return p->next; else - return av_first_parser; + return (AVCodecParser*)parser_list[0]; +} + +const AVCodecParser *av_parser_iterate(void **opaque) +{ + uintptr_t i = (uintptr_t)*opaque; + const AVCodecParser *p = parser_list[i]; + + if (p) + *opaque = (void*)(i + 1); + + return p; } void av_register_codec_parser(AVCodecParser *parser) { - do { - parser->next = av_first_parser; - } while (parser->next != avpriv_atomic_ptr_cas((void * volatile *)&av_first_parser, parser->next, parser)); + ff_thread_once(&av_parser_next_init, av_parser_init_next); } AVCodecParserContext *av_parser_init(int codec_id) { AVCodecParserContext *s = NULL; - AVCodecParser *parser; + const AVCodecParser *parser; + void *i = 0; int ret; if (codec_id == AV_CODEC_ID_NONE) return NULL; - for (parser = av_first_parser; parser; parser = parser->next) { + while ((parser = av_parser_iterate(&i))) { if (parser->codec_ids[0] == codec_id || parser->codec_ids[1] == codec_id || parser->codec_ids[2] == codec_id || @@ -72,7 +140,7 @@ AVCodecParserContext *av_parser_init(int codec_id) s = av_mallocz(sizeof(AVCodecParserContext)); if (!s) goto err_out; - s->parser = parser; + s->parser = (AVCodecParser*)parser; s->priv_data = av_mallocz(parser->priv_data_size); if (!s->priv_data) goto err_out; diff --git a/libavcodec/pixlet.c b/libavcodec/pixlet.c index a9cfe085c9283..03a2cdacc8ba1 100644 --- a/libavcodec/pixlet.c +++ b/libavcodec/pixlet.c @@ -28,12 +28,14 @@ #include "avcodec.h" #include "bytestream.h" #include "get_bits.h" -#include "unary.h" #include "internal.h" #include "thread.h" +#include "unary.h" #define NB_LEVELS 4 +#define PIXLET_MAGIC 0xDEADBEEF + #define H 0 #define V 1 @@ -47,11 +49,11 @@ typedef struct PixletContext { AVClass *class; GetByteContext gb; - GetBitContext gbit; + GetBitContext bc; int levels; int depth; - int h, w; + int w, h; int16_t *filter[2]; int16_t *prediction; @@ -59,6 +61,31 @@ typedef struct PixletContext { SubBand band[4][NB_LEVELS * 3 + 1]; } PixletContext; +static av_cold int pixlet_init(AVCodecContext *avctx) +{ + avctx->pix_fmt = AV_PIX_FMT_YUV420P16; + avctx->color_range = AVCOL_RANGE_JPEG; + return 0; +} + +static void free_buffers(AVCodecContext *avctx) +{ + PixletContext *ctx = avctx->priv_data; + + av_freep(&ctx->filter[0]); + av_freep(&ctx->filter[1]); + av_freep(&ctx->prediction); +} + +static av_cold int pixlet_close(AVCodecContext *avctx) +{ + PixletContext *ctx = avctx->priv_data; + free_buffers(avctx); + ctx->w = 0; + ctx->h = 0; + return 0; +} + static int init_decoder(AVCodecContext *avctx) { PixletContext *ctx = avctx->priv_data; @@ -72,19 +99,19 @@ static int init_decoder(AVCodecContext *avctx) for (plane = 0; plane < 3; plane++) { unsigned shift = plane > 0; - unsigned w = ctx->w >> shift; - unsigned h = ctx->h >> shift; + unsigned w = ctx->w >> shift; + unsigned h = ctx->h >> shift; - ctx->band[plane][0].width = w >> NB_LEVELS; - ctx->band[plane][0].height = h >> NB_LEVELS; - ctx->band[plane][0].size = (w >> NB_LEVELS) * (h >> NB_LEVELS); + ctx->band[plane][0].width = w >> NB_LEVELS; + ctx->band[plane][0].height = h >> NB_LEVELS; + ctx->band[plane][0].size = (w >> NB_LEVELS) * (h >> NB_LEVELS); for (i = 0; i < NB_LEVELS * 3; i++) { unsigned scale = ctx->levels - (i / 3); - ctx->band[plane][i + 1].width = w >> scale; - ctx->band[plane][i + 1].height = h >> scale; - ctx->band[plane][i + 1].size = (w >> scale) * (h >> scale); + ctx->band[plane][i + 1].width = w >> scale; + ctx->band[plane][i + 1].height = h >> scale; + ctx->band[plane][i + 1].size = (w >> scale) * (h >> scale); ctx->band[plane][i + 1].x = (w >> scale) * (((i + 1) % 3) != 2); ctx->band[plane][i + 1].y = (h >> scale) * (((i + 1) % 3) != 1); @@ -94,35 +121,11 @@ static int init_decoder(AVCodecContext *avctx) return 0; } -static void free_buffers(AVCodecContext *avctx) +static int read_low_coeffs(AVCodecContext *avctx, int16_t *dst, int size, + int width, ptrdiff_t stride) { PixletContext *ctx = avctx->priv_data; - - av_freep(&ctx->filter[0]); - av_freep(&ctx->filter[1]); - av_freep(&ctx->prediction); -} - -static av_cold int pixlet_close(AVCodecContext *avctx) -{ - PixletContext *ctx = avctx->priv_data; - free_buffers(avctx); - ctx->w = 0; - ctx->h = 0; - return 0; -} - -static av_cold int pixlet_init(AVCodecContext *avctx) -{ - avctx->pix_fmt = AV_PIX_FMT_YUV420P16; - avctx->color_range = AVCOL_RANGE_JPEG; - return 0; -} - -static int read_low_coeffs(AVCodecContext *avctx, int16_t *dst, int size, int width, ptrdiff_t stride) -{ - PixletContext *ctx = avctx->priv_data; - GetBitContext *b = &ctx->gbit; + GetBitContext *bc = &ctx->bc; unsigned cnt1, nbits, k, j = 0, i = 0; int64_t value, state = 3; int rlen, escape, flag = 0; @@ -130,45 +133,45 @@ static int read_low_coeffs(AVCodecContext *avctx, int16_t *dst, int size, int wi while (i < size) { nbits = FFMIN(ff_clz((state >> 8) + 3) ^ 0x1F, 14); - cnt1 = get_unary(b, 0, 8); + cnt1 = get_unary(bc, 0, 8); if (cnt1 < 8) { - value = show_bits(b, nbits); + value = show_bits(bc, nbits); if (value <= 1) { - skip_bits(b, nbits - 1); + skip_bits(bc, nbits - 1); escape = ((1 << nbits) - 1) * cnt1; } else { - skip_bits(b, nbits); + skip_bits(bc, nbits); escape = value + ((1 << nbits) - 1) * cnt1 - 1; } } else { - escape = get_bits(b, 16); + escape = get_bits(bc, 16); } - value = -((escape + flag) & 1) | 1; + value = -((escape + flag) & 1) | 1; dst[j++] = value * ((escape + flag + 1) >> 1); i++; if (j == width) { - j = 0; + j = 0; dst += stride; } state = 120 * (escape + flag) + state - (120 * state >> 8); - flag = 0; + flag = 0; if (state * 4ULL > 0xFF || i >= size) continue; - nbits = ((state + 8) >> 5) + (state ? ff_clz(state) : 32) - 24; + nbits = ((state + 8) >> 5) + (state ? ff_clz(state) : 32) - 24; escape = av_mod_uintp2(16383, nbits); - cnt1 = get_unary(b, 0, 8); + cnt1 = get_unary(bc, 0, 8); if (cnt1 > 7) { - rlen = get_bits(b, 16); + rlen = get_bits(bc, 16); } else { - value = show_bits(b, nbits); + value = show_bits(bc, nbits); if (value > 1) { - skip_bits(b, nbits); + skip_bits(bc, nbits); rlen = value + escape * cnt1 - 1; } else { - skip_bits(b, nbits - 1); + skip_bits(bc, nbits - 1); rlen = escape * cnt1; } } @@ -180,31 +183,32 @@ static int read_low_coeffs(AVCodecContext *avctx, int16_t *dst, int size, int wi for (k = 0; k < rlen; k++) { dst[j++] = 0; if (j == width) { - j = 0; + j = 0; dst += stride; } } state = 0; - flag = rlen < 0xFFFF ? 1 : 0; + flag = rlen < 0xFFFF ? 1 : 0; } - align_get_bits(b); - return get_bits_count(b) >> 3; + align_get_bits(bc); + return get_bits_count(bc) >> 3; } -static int read_high_coeffs(AVCodecContext *avctx, uint8_t *src, int16_t *dst, int size, - int c, int a, int d, +static int read_high_coeffs(AVCodecContext *avctx, uint8_t *src, int16_t *dst, + int size, int c, int a, int d, int width, ptrdiff_t stride) { PixletContext *ctx = avctx->priv_data; - GetBitContext *b = &ctx->gbit; + GetBitContext *bc = &ctx->bc; unsigned cnt1, shbits, rlen, nbits, length, i = 0, j = 0, k; int ret, escape, pfx, value, yflag, xflag, flag = 0; int64_t state = 3, tmp; - if ((ret = init_get_bits8(b, src, bytestream2_get_bytes_left(&ctx->gb))) < 0) - return ret; + ret = init_get_bits8(bc, src, bytestream2_get_bytes_left(&ctx->gb)); + if (ret < 0) + return ret; if (a ^ (a >> 31)) { nbits = 33 - ff_clz(a ^ (a >> 31)); @@ -217,26 +221,24 @@ static int read_high_coeffs(AVCodecContext *avctx, uint8_t *src, int16_t *dst, i length = 25 - nbits; while (i < size) { - if (state >> 8 != -3) { + if (state >> 8 != -3) value = ff_clz((state >> 8) + 3) ^ 0x1F; - } else { + else value = -1; - } - - cnt1 = get_unary(b, 0, length); + cnt1 = get_unary(bc, 0, length); if (cnt1 >= length) { - cnt1 = get_bits(b, nbits); + cnt1 = get_bits(bc, nbits); } else { pfx = 14 + ((((uint64_t)(value - 14)) >> 32) & (value - 14)); if (pfx < 1 || pfx > 25) return AVERROR_INVALIDDATA; cnt1 *= (1 << pfx) - 1; - shbits = show_bits(b, pfx); + shbits = show_bits(bc, pfx); if (shbits <= 1) { - skip_bits(b, pfx - 1); + skip_bits(bc, pfx - 1); } else { - skip_bits(b, pfx); + skip_bits(bc, pfx); cnt1 += shbits - 1; } } @@ -248,14 +250,14 @@ static int read_high_coeffs(AVCodecContext *avctx, uint8_t *src, int16_t *dst, i value = 0; } else { xflag &= 1u; - tmp = (int64_t)c * ((yflag + 1) >> 1) + (c >> 1); - value = xflag + (tmp ^ -xflag); + tmp = (int64_t)c * ((yflag + 1) >> 1) + (c >> 1); + value = xflag + (tmp ^ -xflag); } i++; dst[j++] = value; if (j == width) { - j = 0; + j = 0; dst += stride; } state += (int64_t)d * (uint64_t)yflag - ((int64_t)(d * (uint64_t)state) >> 8); @@ -265,25 +267,26 @@ static int read_high_coeffs(AVCodecContext *avctx, uint8_t *src, int16_t *dst, i if ((uint64_t)state > 0xFF / 4 || i >= size) continue; - pfx = ((state + 8) >> 5) + (state ? ff_clz(state): 32) - 24; + pfx = ((state + 8) >> 5) + (state ? ff_clz(state) : 32) - 24; escape = av_mod_uintp2(16383, pfx); - cnt1 = get_unary(b, 0, 8); + cnt1 = get_unary(bc, 0, 8); if (cnt1 < 8) { if (pfx < 1 || pfx > 25) return AVERROR_INVALIDDATA; - value = show_bits(b, pfx); + + value = show_bits(bc, pfx); if (value > 1) { - skip_bits(b, pfx); + skip_bits(bc, pfx); rlen = value + escape * cnt1 - 1; } else { - skip_bits(b, pfx - 1); + skip_bits(bc, pfx - 1); rlen = escape * cnt1; } } else { - if (get_bits1(b)) - value = get_bits(b, 16); + if (get_bits1(bc)) + value = get_bits(bc, 16); else - value = get_bits(b, 8); + value = get_bits(bc, 8); rlen = value + 8 * escape; } @@ -295,20 +298,21 @@ static int read_high_coeffs(AVCodecContext *avctx, uint8_t *src, int16_t *dst, i for (k = 0; k < rlen; k++) { dst[j++] = 0; if (j == width) { - j = 0; + j = 0; dst += stride; } } state = 0; - flag = rlen < 0xFFFF ? 1 : 0; + flag = rlen < 0xFFFF ? 1 : 0; } - align_get_bits(b); - return get_bits_count(b) >> 3; + align_get_bits(bc); + return get_bits_count(bc) >> 3; } -static int read_highpass(AVCodecContext *avctx, uint8_t *ptr, int plane, AVFrame *frame) +static int read_highpass(AVCodecContext *avctx, uint8_t *ptr, + int plane, AVFrame *frame) { PixletContext *ctx = avctx->priv_data; ptrdiff_t stride = frame->linesize[plane] / 2; @@ -319,15 +323,16 @@ static int read_highpass(AVCodecContext *avctx, uint8_t *ptr, int plane, AVFrame int32_t b = bytestream2_get_be32(&ctx->gb); int32_t c = bytestream2_get_be32(&ctx->gb); int32_t d = bytestream2_get_be32(&ctx->gb); - int16_t *dest = (int16_t *)frame->data[plane] + ctx->band[plane][i + 1].x + - stride * ctx->band[plane][i + 1].y; + int16_t *dest = (int16_t *)frame->data[plane] + + ctx->band[plane][i + 1].x + + ctx->band[plane][i + 1].y * stride; unsigned size = ctx->band[plane][i + 1].size; - uint32_t magic; + uint32_t magic = bytestream2_get_be32(&ctx->gb); - magic = bytestream2_get_be32(&ctx->gb); - if (magic != 0xDEADBEEF) { - av_log(avctx, AV_LOG_ERROR, "wrong magic number: 0x%08"PRIX32 - " for plane %d, band %d\n", magic, plane, i); + if (magic != PIXLET_MAGIC) { + av_log(avctx, AV_LOG_ERROR, + "wrong magic number: 0x%08"PRIX32" for plane %d, band %d\n", + magic, plane, i); return AVERROR_INVALIDDATA; } @@ -338,7 +343,9 @@ static int read_highpass(AVCodecContext *avctx, uint8_t *ptr, int plane, AVFrame c, (b >= FFABS(a)) ? b : a, d, ctx->band[plane][i + 1].width, stride); if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "error in highpass coefficients for plane %d, band %d\n", plane, i); + av_log(avctx, AV_LOG_ERROR, + "error in highpass coefficients for plane %d, band %d\n", + plane, i); return ret; } bytestream2_skip(&ctx->gb, ret); @@ -347,7 +354,8 @@ static int read_highpass(AVCodecContext *avctx, uint8_t *ptr, int plane, AVFrame return 0; } -static void lowpass_prediction(int16_t *dst, int16_t *pred, int width, int height, ptrdiff_t stride) +static void lowpass_prediction(int16_t *dst, int16_t *pred, + int width, int height, ptrdiff_t stride) { int16_t val; int i, j; @@ -373,8 +381,8 @@ static void filterfn(int16_t *dest, int16_t *tmp, unsigned size, int64_t scale) int64_t value; hsize = size >> 1; - low = tmp + 4; - high = &low[hsize + 8]; + low = tmp + 4; + high = &low[hsize + 8]; memcpy(low, dest, size); memcpy(high, dest + hsize, size); @@ -411,29 +419,28 @@ static void filterfn(int16_t *dest, int16_t *tmp, unsigned size, int64_t scale) } } -static void reconstruction(AVCodecContext *avctx, - int16_t *dest, unsigned width, unsigned height, ptrdiff_t stride, int nb_levels, - int64_t *scaling_H, int64_t *scaling_V) +static void reconstruction(AVCodecContext *avctx, int16_t *dest, + unsigned width, unsigned height, ptrdiff_t stride, + int64_t *scaling_h, int64_t *scaling_v) { PixletContext *ctx = avctx->priv_data; unsigned scaled_width, scaled_height; - int64_t scale_H, scale_V; int16_t *ptr, *tmp; int i, j, k; - scaled_height = height >> nb_levels; - scaled_width = width >> nb_levels; - tmp = ctx->filter[0]; + scaled_width = width >> NB_LEVELS; + scaled_height = height >> NB_LEVELS; + tmp = ctx->filter[0]; - for (i = 0; i < nb_levels; i++) { + for (i = 0; i < NB_LEVELS; i++) { + int64_t scale_v = scaling_v[i]; + int64_t scale_h = scaling_h[i]; scaled_width <<= 1; scaled_height <<= 1; - scale_H = scaling_H[i]; - scale_V = scaling_V[i]; ptr = dest; for (j = 0; j < scaled_height; j++) { - filterfn(ptr, ctx->filter[1], scaled_width, scale_V); + filterfn(ptr, ctx->filter[1], scaled_width, scale_v); ptr += stride; } @@ -441,10 +448,10 @@ static void reconstruction(AVCodecContext *avctx, ptr = dest + j; for (k = 0; k < scaled_height; k++) { tmp[k] = *ptr; - ptr += stride; + ptr += stride; } - filterfn(tmp, ctx->filter[1], scaled_height, scale_H); + filterfn(tmp, ctx->filter[1], scaled_height, scale_h); ptr = dest + j; for (k = 0; k < scaled_height; k++) { @@ -501,11 +508,12 @@ static void postprocess_chroma(AVFrame *frame, int w, int h, int depth) } } -static int decode_plane(AVCodecContext *avctx, int plane, AVPacket *avpkt, AVFrame *frame) +static int decode_plane(AVCodecContext *avctx, int plane, + AVPacket *avpkt, AVFrame *frame) { PixletContext *ctx = avctx->priv_data; - ptrdiff_t stride = frame->linesize[plane] / 2; - unsigned shift = plane > 0; + ptrdiff_t stride = frame->linesize[plane] / 2; + unsigned shift = plane > 0; int16_t *dst; int i, ret; @@ -522,22 +530,28 @@ static int decode_plane(AVCodecContext *avctx, int plane, AVPacket *avpkt, AVFra bytestream2_skip(&ctx->gb, 4); - dst = (int16_t *)frame->data[plane]; + dst = (int16_t *)frame->data[plane]; dst[0] = sign_extend(bytestream2_get_be16(&ctx->gb), 16); - if ((ret = init_get_bits8(&ctx->gbit, avpkt->data + bytestream2_tell(&ctx->gb), - bytestream2_get_bytes_left(&ctx->gb))) < 0) + ret = init_get_bits8(&ctx->bc, avpkt->data + bytestream2_tell(&ctx->gb), + bytestream2_get_bytes_left(&ctx->gb)); + if (ret < 0) return ret; - ret = read_low_coeffs(avctx, dst + 1, ctx->band[plane][0].width - 1, ctx->band[plane][0].width - 1, 0); + ret = read_low_coeffs(avctx, dst + 1, ctx->band[plane][0].width - 1, + ctx->band[plane][0].width - 1, 0); if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "error in lowpass coefficients for plane %d, top row\n", plane); + av_log(avctx, AV_LOG_ERROR, + "error in lowpass coefficients for plane %d, top row\n", plane); return ret; } - ret = read_low_coeffs(avctx, dst + stride, ctx->band[plane][0].height - 1, 1, stride); + ret = read_low_coeffs(avctx, dst + stride, + ctx->band[plane][0].height - 1, 1, stride); if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "error in lowpass coefficients for plane %d, left column\n", plane); + av_log(avctx, AV_LOG_ERROR, + "error in lowpass coefficients for plane %d, left column\n", + plane); return ret; } @@ -545,7 +559,8 @@ static int decode_plane(AVCodecContext *avctx, int plane, AVPacket *avpkt, AVFra (ctx->band[plane][0].width - 1) * (ctx->band[plane][0].height - 1), ctx->band[plane][0].width - 1, stride); if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "error in lowpass coefficients for plane %d, rest\n", plane); + av_log(avctx, AV_LOG_ERROR, + "error in lowpass coefficients for plane %d, rest\n", plane); return ret; } @@ -559,11 +574,12 @@ static int decode_plane(AVCodecContext *avctx, int plane, AVPacket *avpkt, AVFra if (ret < 0) return ret; - lowpass_prediction(dst, ctx->prediction, - ctx->band[plane][0].width, ctx->band[plane][0].height, stride); + lowpass_prediction(dst, ctx->prediction, ctx->band[plane][0].width, + ctx->band[plane][0].height, stride); - reconstruction(avctx, (int16_t *)frame->data[plane], ctx->w >> shift, ctx->h >> shift, - stride, NB_LEVELS, ctx->scaling[plane][H], ctx->scaling[plane][V]); + reconstruction(avctx, (int16_t *)frame->data[plane], ctx->w >> shift, + ctx->h >> shift, stride, ctx->scaling[plane][H], + ctx->scaling[plane][V]); return 0; } @@ -664,14 +680,15 @@ static int pixlet_init_thread_copy(AVCodecContext *avctx) { PixletContext *ctx = avctx->priv_data; - ctx->filter[0] = NULL; - ctx->filter[1] = NULL; + ctx->filter[0] = NULL; + ctx->filter[1] = NULL; ctx->prediction = NULL; - ctx->w = ctx->h = 0; + ctx->w = 0; + ctx->h = 0; return 0; } -#endif +#endif /* HAVE_THREADS */ AVCodec ff_pixlet_decoder = { .name = "pixlet", diff --git a/libavcodec/pngdec.c b/libavcodec/pngdec.c index 0d6612cccafb8..f93f200bb1524 100644 --- a/libavcodec/pngdec.c +++ b/libavcodec/pngdec.c @@ -25,6 +25,7 @@ #include "libavutil/bprint.h" #include "libavutil/imgutils.h" #include "libavutil/stereo3d.h" +#include "libavutil/mastering_display_metadata.h" #include "avcodec.h" #include "bytestream.h" @@ -523,9 +524,9 @@ static int decode_text_chunk(PNGDecContext *s, uint32_t length, int compressed, if ((ret = decode_zbuf(&bp, data, data_end)) < 0) return ret; text_len = bp.len; - av_bprint_finalize(&bp, (char **)&text); - if (!text) - return AVERROR(ENOMEM); + ret = av_bprint_finalize(&bp, (char **)&text); + if (ret < 0) + return ret; } else { text = (uint8_t *)data; text_len = data_end - text; @@ -661,10 +662,10 @@ static int decode_idat_chunk(AVCodecContext *avctx, PNGDecContext *s, s->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { avctx->pix_fmt = AV_PIX_FMT_YA16BE; } else { - av_log(avctx, AV_LOG_ERROR, "unsupported bit depth %d " - "and color type %d\n", - s->bit_depth, s->color_type); - return AVERROR_INVALIDDATA; + avpriv_report_missing_feature(avctx, + "Bit depth %d color type %d", + s->bit_depth, s->color_type); + return AVERROR_PATCHWELCOME; } if (s->has_trns && s->color_type != PNG_COLOR_TYPE_PALETTE) { @@ -861,7 +862,9 @@ static int decode_iccp_chunk(PNGDecContext *s, int length, AVFrame *f) if ((ret = decode_zbuf(&bp, s->gb.buffer, s->gb.buffer + length)) < 0) return ret; - av_bprint_finalize(&bp, (char **)&data); + ret = av_bprint_finalize(&bp, (char **)&data); + if (ret < 0) + return ret; sd = av_frame_new_side_data(f, AV_FRAME_DATA_ICC_PROFILE, bp.len); if (!sd) { @@ -1165,7 +1168,7 @@ static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s, AVDictionary **metadatap = NULL; uint32_t tag, length; int decode_next_dat = 0; - int ret; + int i, ret; for (;;) { length = bytestream2_get_bytes_left(&s->gb); @@ -1287,6 +1290,42 @@ static int decode_frame_common(AVCodecContext *avctx, PNGDecContext *s, goto fail; break; } + case MKTAG('c', 'H', 'R', 'M'): { + AVMasteringDisplayMetadata *mdm = av_mastering_display_metadata_create_side_data(p); + if (!mdm) { + ret = AVERROR(ENOMEM); + goto fail; + } + + mdm->white_point[0] = av_make_q(bytestream2_get_be32(&s->gb), 100000); + mdm->white_point[1] = av_make_q(bytestream2_get_be32(&s->gb), 100000); + + /* RGB Primaries */ + for (i = 0; i < 3; i++) { + mdm->display_primaries[i][0] = av_make_q(bytestream2_get_be32(&s->gb), 100000); + mdm->display_primaries[i][1] = av_make_q(bytestream2_get_be32(&s->gb), 100000); + } + + mdm->has_primaries = 1; + bytestream2_skip(&s->gb, 4); /* crc */ + break; + } + case MKTAG('g', 'A', 'M', 'A'): { + AVBPrint bp; + char *gamma_str; + int num = bytestream2_get_be32(&s->gb); + + av_bprint_init(&bp, 0, -1); + av_bprintf(&bp, "%i/%i", num, 100000); + ret = av_bprint_finalize(&bp, &gamma_str); + if (ret < 0) + return ret; + + av_dict_set(&p->metadata, "gamma", gamma_str, AV_DICT_DONT_STRDUP_VAL); + + bytestream2_skip(&s->gb, 4); /* crc */ + break; + } case MKTAG('I', 'E', 'N', 'D'): if (!(s->pic_state & PNG_ALLIMAGE)) av_log(avctx, AV_LOG_ERROR, "IEND without all image\n"); diff --git a/libavcodec/ppc/fft_init.c b/libavcodec/ppc/fft_init.c index 57d7c80ea4ccf..733e58b4c9c45 100644 --- a/libavcodec/ppc/fft_init.c +++ b/libavcodec/ppc/fft_init.c @@ -42,7 +42,7 @@ void ff_fft_calc_altivec(FFTContext *s, FFTComplex *z); void ff_fft_calc_interleave_altivec(FFTContext *s, FFTComplex *z); #endif -#if HAVE_GNU_AS && HAVE_ALTIVEC +#if HAVE_GNU_AS && HAVE_ALTIVEC && (HAVE_BIGENDIAN || HAVE_VSX) static void imdct_half_altivec(FFTContext *s, FFTSample *output, const FFTSample *input) { int j, k; @@ -146,11 +146,11 @@ static void imdct_calc_altivec(FFTContext *s, FFTSample *output, const FFTSample p1[k] = vec_perm(b, b, vcprm(3,2,1,0)); } } -#endif /* HAVE_GNU_AS && HAVE_ALTIVEC && HAVE_BIGENDIAN */ +#endif /* HAVE_GNU_AS && HAVE_ALTIVEC && (HAVE_BIGENDIAN || HAVE_VSX) */ av_cold void ff_fft_init_ppc(FFTContext *s) { -#if HAVE_GNU_AS && HAVE_ALTIVEC +#if HAVE_GNU_AS && HAVE_ALTIVEC && (HAVE_BIGENDIAN || HAVE_VSX) if (!PPC_ALTIVEC(av_get_cpu_flags())) return; diff --git a/libavcodec/ppc/h264dsp.c b/libavcodec/ppc/h264dsp.c index e84a058d04eb0..f510544dda581 100644 --- a/libavcodec/ppc/h264dsp.c +++ b/libavcodec/ppc/h264dsp.c @@ -771,12 +771,12 @@ void biweight_h264_W_altivec(uint8_t *dst, uint8_t *src, int stride, int height, } #define H264_WEIGHT(W) \ -static void weight_h264_pixels ## W ## _altivec(uint8_t *block, int stride, int height, \ +static void weight_h264_pixels ## W ## _altivec(uint8_t *block, ptrdiff_t stride, int height, \ int log2_denom, int weight, int offset) \ { \ weight_h264_W_altivec(block, stride, height, log2_denom, weight, offset, W); \ }\ -static void biweight_h264_pixels ## W ## _altivec(uint8_t *dst, uint8_t *src, int stride, int height, \ +static void biweight_h264_pixels ## W ## _altivec(uint8_t *dst, uint8_t *src, ptrdiff_t stride, int height, \ int log2_denom, int weightd, int weights, int offset) \ { \ biweight_h264_W_altivec(dst, src, stride, height, log2_denom, weightd, weights, offset, W); \ diff --git a/libavcodec/ppc/hpeldsp_altivec.c b/libavcodec/ppc/hpeldsp_altivec.c index 4f19521860317..a531b6b6ecd55 100644 --- a/libavcodec/ppc/hpeldsp_altivec.c +++ b/libavcodec/ppc/hpeldsp_altivec.c @@ -84,7 +84,7 @@ void ff_avg_pixels16_altivec(uint8_t *block, const uint8_t *pixels, ptrdiff_t li /* next one assumes that ((line_size % 8) == 0) */ static void avg_pixels8_altivec(uint8_t * block, const uint8_t * pixels, ptrdiff_t line_size, int h) { - register vector unsigned char pixelsv1, pixelsv2, pixelsv, blockv; + register vector unsigned char pixelsv, blockv; int i; for (i = 0; i < h; i++) { diff --git a/libavcodec/ppc/svq1enc_altivec.c b/libavcodec/ppc/svq1enc_altivec.c index f63f0866024e6..aa66b40996b23 100644 --- a/libavcodec/ppc/svq1enc_altivec.c +++ b/libavcodec/ppc/svq1enc_altivec.c @@ -31,7 +31,7 @@ #if HAVE_ALTIVEC static int ssd_int8_vs_int16_altivec(const int8_t *pix1, const int16_t *pix2, - int size) + intptr_t size) { int i, size16 = size >> 4; vector signed char vpix1; diff --git a/libavcodec/profiles.c b/libavcodec/profiles.c index 30498efedfc29..d7dc960f36bb5 100644 --- a/libavcodec/profiles.c +++ b/libavcodec/profiles.c @@ -140,4 +140,16 @@ const AVProfile ff_vp9_profiles[] = { { FF_PROFILE_UNKNOWN }, }; +const AVProfile ff_av1_profiles[] = { + { FF_PROFILE_AV1_MAIN, "Main" }, + { FF_PROFILE_AV1_HIGH, "High" }, + { FF_PROFILE_AV1_PROFESSIONAL, "Professional" }, + { FF_PROFILE_UNKNOWN }, +}; + +const AVProfile ff_sbc_profiles[] = { + { FF_PROFILE_SBC_MSBC, "mSBC" }, + { FF_PROFILE_UNKNOWN }, +}; + #endif /* !CONFIG_SMALL */ diff --git a/libavcodec/profiles.h b/libavcodec/profiles.h index eb18b406af4c7..9d7e211e15da3 100644 --- a/libavcodec/profiles.h +++ b/libavcodec/profiles.h @@ -31,5 +31,7 @@ extern const AVProfile ff_mpeg2_video_profiles[]; extern const AVProfile ff_mpeg4_video_profiles[]; extern const AVProfile ff_vc1_profiles[]; extern const AVProfile ff_vp9_profiles[]; +extern const AVProfile ff_av1_profiles[]; +extern const AVProfile ff_sbc_profiles[]; #endif /* AVCODEC_PROFILES_H */ diff --git a/libavcodec/proresdec2.c b/libavcodec/proresdec2.c index 0f791de97ba5f..d97e264e4492b 100644 --- a/libavcodec/proresdec2.c +++ b/libavcodec/proresdec2.c @@ -517,8 +517,8 @@ static int decode_slice_thread(AVCodecContext *avctx, void *arg, int jobnr, int int luma_stride, chroma_stride; int y_data_size, u_data_size, v_data_size, a_data_size; uint8_t *dest_y, *dest_u, *dest_v, *dest_a; - int16_t qmat_luma_scaled[64]; - int16_t qmat_chroma_scaled[64]; + LOCAL_ALIGNED_16(int16_t, qmat_luma_scaled, [64]); + LOCAL_ALIGNED_16(int16_t, qmat_chroma_scaled,[64]); int mb_x_shift; int ret; @@ -598,8 +598,9 @@ static int decode_slice_thread(AVCodecContext *avctx, void *arg, int jobnr, int } else { size_t mb_max_x = slice->mb_count << (mb_x_shift - 1); - for (size_t i = 0; i < 16; ++i) - for (size_t j = 0; j < mb_max_x; ++j) { + size_t i, j; + for (i = 0; i < 16; ++i) + for (j = 0; j < mb_max_x; ++j) { *(uint16_t*)(dest_u + (i * chroma_stride) + (j << 1)) = 511; *(uint16_t*)(dest_v + (i * chroma_stride) + (j << 1)) = 511; } diff --git a/libavcodec/proresdec_lgpl.c b/libavcodec/proresdec_lgpl.c index bc5bdb5a4d5ee..c86d433f50728 100644 --- a/libavcodec/proresdec_lgpl.c +++ b/libavcodec/proresdec_lgpl.c @@ -177,6 +177,7 @@ static int decode_frame_header(ProresContext *ctx, const uint8_t *buf, avctx->color_primaries = buf[14]; avctx->color_trc = buf[15]; avctx->colorspace = buf[16]; + avctx->color_range = AVCOL_RANGE_MPEG; ctx->qmat_changed = 0; ptr = buf + 20; diff --git a/libavcodec/proresenc_kostya.c b/libavcodec/proresenc_kostya.c index 149dc81b3c799..06d5aa31e8431 100644 --- a/libavcodec/proresenc_kostya.c +++ b/libavcodec/proresenc_kostya.c @@ -712,10 +712,9 @@ static int est_alpha_diff(int cur, int prev, int abits) return dbits + 1; } -static int estimate_alpha_plane(ProresContext *ctx, int *error, +static int estimate_alpha_plane(ProresContext *ctx, const uint16_t *src, ptrdiff_t linesize, - int mbs_per_slice, int quant, - int16_t *blocks) + int mbs_per_slice, int16_t *blocks) { const int abits = ctx->alpha_bits; const int mask = (1 << abits) - 1; @@ -725,7 +724,6 @@ static int estimate_alpha_plane(ProresContext *ctx, int *error, int run = 0; int bits; - *error = 0; cur = blocks[idx++]; bits = est_alpha_diff(cur, prev, abits); prev = cur; @@ -774,6 +772,7 @@ static int find_slice_quant(AVCodecContext *avctx, int overquant; uint16_t *qmat; int linesize[4], line_add; + int alpha_bits = 0; if (ctx->pictures_per_frame == 1) line_add = 0; @@ -819,9 +818,12 @@ static int find_slice_quant(AVCodecContext *avctx, td->nodes[trellis_node + q].quant = q; } + if (ctx->alpha_bits) + alpha_bits = estimate_alpha_plane(ctx, src, linesize[3], + mbs_per_slice, td->blocks[3]); // todo: maybe perform coarser quantising to fit into frame size when needed for (q = min_quant; q <= max_quant; q++) { - bits = 0; + bits = alpha_bits; error = 0; for (i = 0; i < ctx->num_planes - !!ctx->alpha_bits; i++) { bits += estimate_slice_plane(ctx, &error, i, @@ -830,9 +832,6 @@ static int find_slice_quant(AVCodecContext *avctx, num_cblocks[i], plane_factor[i], ctx->quants[q], td); } - if (ctx->alpha_bits) - bits += estimate_alpha_plane(ctx, &error, src, linesize[3], - mbs_per_slice, q, td->blocks[3]); if (bits > 65000 * 8) error = SCORE_LIMIT; @@ -845,7 +844,7 @@ static int find_slice_quant(AVCodecContext *avctx, overquant = max_quant; } else { for (q = max_quant + 1; q < 128; q++) { - bits = 0; + bits = alpha_bits; error = 0; if (q < MAX_STORED_Q) { qmat = ctx->quants[q]; @@ -861,9 +860,6 @@ static int find_slice_quant(AVCodecContext *avctx, num_cblocks[i], plane_factor[i], qmat, td); } - if (ctx->alpha_bits) - bits += estimate_alpha_plane(ctx, &error, src, linesize[3], - mbs_per_slice, q, td->blocks[3]); if (bits <= ctx->bits_per_mb * mbs_per_slice) break; } diff --git a/libavcodec/pthread_frame.c b/libavcodec/pthread_frame.c index 2c702c7372189..5104b1beba4b2 100644 --- a/libavcodec/pthread_frame.c +++ b/libavcodec/pthread_frame.c @@ -246,7 +246,7 @@ static int update_context_from_thread(AVCodecContext *dst, AVCodecContext *src, { int err = 0; - if (dst != src && (for_user || !(av_codec_get_codec_descriptor(src)->props & AV_CODEC_PROP_INTRA_ONLY))) { + if (dst != src && (for_user || !(src->codec_descriptor->props & AV_CODEC_PROP_INTRA_ONLY))) { dst->time_base = src->time_base; dst->framerate = src->framerate; dst->width = src->width; @@ -262,11 +262,6 @@ static int update_context_from_thread(AVCodecContext *dst, AVCodecContext *src, dst->bits_per_coded_sample = src->bits_per_coded_sample; dst->sample_aspect_ratio = src->sample_aspect_ratio; -#if FF_API_AFD -FF_DISABLE_DEPRECATION_WARNINGS - dst->dtg_active_format = src->dtg_active_format; -FF_ENABLE_DEPRECATION_WARNINGS -#endif /* FF_API_AFD */ dst->profile = src->profile; dst->level = src->level; @@ -733,10 +728,6 @@ int ff_frame_thread_init(AVCodecContext *avctx) FrameThreadContext *fctx; int i, err = 0; -#if HAVE_W32THREADS - w32thread_init(); -#endif - if (!thread_count) { int nb_cpus = av_cpu_count(); #if FF_API_DEBUG_MV @@ -895,8 +886,6 @@ static int thread_get_buffer_internal(AVCodecContext *avctx, ThreadFrame *f, int f->owner[0] = f->owner[1] = avctx; - ff_init_buffer_info(avctx, f->f); - if (!(avctx->active_thread_type & FF_THREAD_FRAME)) return ff_get_buffer(avctx, f->f, flags); diff --git a/libavcodec/pthread_slice.c b/libavcodec/pthread_slice.c index d659f9b0ba809..77cfe3c9f69b7 100644 --- a/libavcodec/pthread_slice.c +++ b/libavcodec/pthread_slice.c @@ -132,10 +132,6 @@ int ff_slice_thread_init(AVCodecContext *avctx) int thread_count = avctx->thread_count; static void (*mainfunc)(void *); -#if HAVE_W32THREADS - w32thread_init(); -#endif - // We cannot do this in the encoder init as the threads are created before if (av_codec_is_encoder(avctx->codec) && avctx->codec_id == AV_CODEC_ID_MPEG1VIDEO && diff --git a/libavcodec/qdmc.c b/libavcodec/qdmc.c index 1c8952b97be40..f1f86accd831b 100644 --- a/libavcodec/qdmc.c +++ b/libavcodec/qdmc.c @@ -26,6 +26,7 @@ #define BITSTREAM_READER_LE #include "libavutil/channel_layout.h" +#include "libavutil/thread.h" #include "avcodec.h" #include "bytestream.h" @@ -204,7 +205,7 @@ static const uint8_t phase_diff_codes[] = { INIT_VLC_LE | INIT_VLC_USE_NEW_STATIC); \ } while (0) -static av_cold void qdmc_init_static_data(AVCodec *codec) +static av_cold void qdmc_init_static_data(void) { int i; @@ -250,10 +251,13 @@ static void make_noises(QDMCContext *s) static av_cold int qdmc_decode_init(AVCodecContext *avctx) { + static AVOnce init_static_once = AV_ONCE_INIT; QDMCContext *s = avctx->priv_data; int fft_size, fft_order, size, g, j, x; GetByteContext b; + ff_thread_once(&init_static_once, qdmc_init_static_data); + if (!avctx->extradata || (avctx->extradata_size < 48)) { av_log(avctx, AV_LOG_ERROR, "extradata missing or truncated\n"); return AVERROR_INVALIDDATA; @@ -775,7 +779,6 @@ AVCodec ff_qdmc_decoder = { .id = AV_CODEC_ID_QDMC, .priv_data_size = sizeof(QDMCContext), .init = qdmc_decode_init, - .init_static_data = qdmc_init_static_data, .close = qdmc_decode_close, .decode = qdmc_decode_frame, .flush = qdmc_flush, diff --git a/libavcodec/qdrw.c b/libavcodec/qdrw.c index 3a0bc6f760a9c..82cc528a30f2d 100644 --- a/libavcodec/qdrw.c +++ b/libavcodec/qdrw.c @@ -434,7 +434,7 @@ static int decode_frame(AVCodecContext *avctx, av_log(avctx, AV_LOG_DEBUG, "bppcount %d bpp %d\n", bppcnt, bpp); if (bppcnt == 3 && bpp == 8) { avctx->pix_fmt = AV_PIX_FMT_RGB24; - } else if (bppcnt == 3 && bpp == 5) { + } else if (bppcnt == 3 && bpp == 5 || bppcnt == 2 && bpp == 8) { avctx->pix_fmt = AV_PIX_FMT_RGB555; } else if (bppcnt == 4 && bpp == 8) { avctx->pix_fmt = AV_PIX_FMT_ARGB; diff --git a/libavcodec/qsv.c b/libavcodec/qsv.c index 56ca9df262de5..45e1c25c68f69 100644 --- a/libavcodec/qsv.c +++ b/libavcodec/qsv.c @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -56,6 +57,8 @@ int ff_qsv_codec_id_to_mfx(enum AVCodecID codec_id) case AV_CODEC_ID_VP8: return MFX_CODEC_VP8; #endif + case AV_CODEC_ID_MJPEG: + return MFX_CODEC_JPEG; default: break; } @@ -192,6 +195,30 @@ int ff_qsv_find_surface_idx(QSVFramesContext *ctx, QSVFrame *frame) return AVERROR_BUG; } +enum AVPictureType ff_qsv_map_pictype(int mfx_pic_type) +{ + enum AVPictureType type; + switch (mfx_pic_type & 0x7) { + case MFX_FRAMETYPE_I: + if (mfx_pic_type & MFX_FRAMETYPE_S) + type = AV_PICTURE_TYPE_SI; + else + type = AV_PICTURE_TYPE_I; + break; + case MFX_FRAMETYPE_B: + type = AV_PICTURE_TYPE_B; + break; + case MFX_FRAMETYPE_P: + if (mfx_pic_type & MFX_FRAMETYPE_S) + type = AV_PICTURE_TYPE_SP; + else + type = AV_PICTURE_TYPE_P; + break; + } + + return type; +} + static int qsv_load_plugins(mfxSession session, const char *load_plugins, void *logctx) { @@ -386,7 +413,7 @@ static mfxStatus qsv_frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req, mfxFrameInfo *i = &req->Info; mfxFrameInfo *i1 = &frames_hwctx->surfaces[0].Info; - if (i->Width != i1->Width || i->Height != i1->Height || + if (i->Width > i1->Width || i->Height > i1->Height || i->FourCC != i1->FourCC || i->ChromaFormat != i1->ChromaFormat) { av_log(ctx->logctx, AV_LOG_ERROR, "Mismatching surface properties in an " "allocation request: %dx%d %d %d vs %dx%d %d %d\n", @@ -590,6 +617,13 @@ int ff_qsv_init_session_device(AVCodecContext *avctx, mfxSession *psession, "Error setting a HW handle"); } + if (QSV_RUNTIME_VERSION_ATLEAST(ver, 1, 25)) { + err = MFXJoinSession(parent_session, session); + if (err != MFX_ERR_NONE) + return ff_qsv_print_error(avctx, err, + "Error joining session"); + } + ret = qsv_load_plugins(session, load_plugins, avctx); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error loading plugins\n"); diff --git a/libavcodec/qsv_internal.h b/libavcodec/qsv_internal.h index c0305508dd552..394c55888314e 100644 --- a/libavcodec/qsv_internal.h +++ b/libavcodec/qsv_internal.h @@ -38,6 +38,10 @@ (MFX_VERSION_MAJOR > (MAJOR) || \ MFX_VERSION_MAJOR == (MAJOR) && MFX_VERSION_MINOR >= (MINOR)) +#define QSV_RUNTIME_VERSION_ATLEAST(MFX_VERSION, MAJOR, MINOR) \ + (MFX_VERSION.Major > (MAJOR)) || \ + (MFX_VERSION.Major == (MAJOR) && MFX_VERSION.Minor >= (MINOR)) + typedef struct QSVMid { AVBufferRef *hw_frames_ref; mfxHDL handle; @@ -51,6 +55,8 @@ typedef struct QSVFrame { AVFrame *frame; mfxFrameSurface1 surface; mfxEncodeCtrl enc_ctrl; + mfxExtDecodedFrameInfo dec_info; + mfxExtBuffer *ext_param; int queued; int used; @@ -86,6 +92,7 @@ int ff_qsv_codec_id_to_mfx(enum AVCodecID codec_id); int ff_qsv_profile_to_mfx(enum AVCodecID codec_id, int profile); int ff_qsv_map_pixfmt(enum AVPixelFormat format, uint32_t *fourcc); +enum AVPictureType ff_qsv_map_pictype(int mfx_pic_type); int ff_qsv_init_internal_session(AVCodecContext *avctx, mfxSession *session, const char *load_plugins); diff --git a/libavcodec/qsvdec.c b/libavcodec/qsvdec.c index c00817f1d93e5..32f1fe79d7992 100644 --- a/libavcodec/qsvdec.c +++ b/libavcodec/qsvdec.c @@ -41,6 +41,19 @@ #include "qsv_internal.h" #include "qsvdec.h" +const AVCodecHWConfigInternal *ff_qsv_hw_configs[] = { + &(const AVCodecHWConfigInternal) { + .public = { + .pix_fmt = AV_PIX_FMT_QSV, + .methods = AV_CODEC_HW_CONFIG_METHOD_HW_FRAMES_CTX | + AV_CODEC_HW_CONFIG_METHOD_AD_HOC, + .device_type = AV_HWDEVICE_TYPE_QSV, + }, + .hwaccel = NULL, + }, + NULL +}; + static int qsv_init_session(AVCodecContext *avctx, QSVContext *q, mfxSession session, AVBufferRef *hw_frames_ref, AVBufferRef *hw_device_ref) { @@ -136,9 +149,6 @@ static int qsv_decode_init(AVCodecContext *avctx, QSVContext *q) else if (frames_hwctx->frame_type & MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET) iopattern = MFX_IOPATTERN_OUT_VIDEO_MEMORY; } - - frame_width = frames_hwctx->surfaces[0].Info.Width; - frame_height = frames_hwctx->surfaces[0].Info.Height; } if (!iopattern) @@ -222,6 +232,11 @@ static int alloc_frame(AVCodecContext *avctx, QSVContext *q, QSVFrame *frame) frame->surface.Data.MemId = &q->frames_ctx.mids[ret]; } + frame->surface.Data.ExtParam = &frame->ext_param; + frame->surface.Data.NumExtParam = 1; + frame->ext_param = (mfxExtBuffer*)&frame->dec_info; + frame->dec_info.Header.BufferId = MFX_EXTBUFF_DECODED_FRAME_INFO; + frame->dec_info.Header.BufferSz = sizeof(frame->dec_info); frame->used = 1; @@ -308,6 +323,8 @@ static int qsv_decode(AVCodecContext *avctx, QSVContext *q, bs.DataLength = avpkt->size; bs.MaxLength = bs.DataLength; bs.TimeStamp = avpkt->pts; + if (avctx->field_order == AV_FIELD_PROGRESSIVE) + bs.DataFlag |= MFX_BITSTREAM_COMPLETE_FRAME; } sync = av_mallocz(sizeof(*sync)); @@ -406,6 +423,10 @@ FF_ENABLE_DEPRECATION_WARNINGS outsurf->Info.PicStruct & MFX_PICSTRUCT_FIELD_TFF; frame->interlaced_frame = !(outsurf->Info.PicStruct & MFX_PICSTRUCT_PROGRESSIVE); + frame->pict_type = ff_qsv_map_pictype(out_frame->dec_info.FrameType); + //Key frame is IDR frame is only suitable for H264. For HEVC, IRAPs are key frames. + if (avctx->codec_id == AV_CODEC_ID_H264) + frame->key_frame = !!(out_frame->dec_info.FrameType & MFX_FRAMETYPE_IDR); /* update the surface properties */ if (avctx->pix_fmt == AV_PIX_FMT_QSV) @@ -462,6 +483,7 @@ int ff_qsv_process_data(AVCodecContext *avctx, QSVContext *q, uint8_t *dummy_data; int dummy_size; int ret; + const AVPixFmtDescriptor *desc; if (!q->avctx_internal) { q->avctx_internal = avcodec_alloc_context3(NULL); @@ -486,10 +508,11 @@ int ff_qsv_process_data(AVCodecContext *avctx, QSVContext *q, pkt->data, pkt->size, pkt->pts, pkt->dts, pkt->pos); + avctx->field_order = q->parser->field_order; /* TODO: flush delayed frames on reinit */ if (q->parser->format != q->orig_pix_fmt || - q->parser->coded_width != avctx->coded_width || - q->parser->coded_height != avctx->coded_height) { + FFALIGN(q->parser->coded_width, 16) != FFALIGN(avctx->coded_width, 16) || + FFALIGN(q->parser->coded_height, 16) != FFALIGN(avctx->coded_height, 16)) { enum AVPixelFormat pix_fmts[3] = { AV_PIX_FMT_QSV, AV_PIX_FMT_NONE, AV_PIX_FMT_NONE }; @@ -508,9 +531,8 @@ int ff_qsv_process_data(AVCodecContext *avctx, QSVContext *q, avctx->pix_fmt = pix_fmts[1] = qsv_format; avctx->width = q->parser->width; avctx->height = q->parser->height; - avctx->coded_width = q->parser->coded_width; - avctx->coded_height = q->parser->coded_height; - avctx->field_order = q->parser->field_order; + avctx->coded_width = FFALIGN(q->parser->coded_width, 16); + avctx->coded_height = FFALIGN(q->parser->coded_height, 16); avctx->level = q->avctx_internal->level; avctx->profile = q->avctx_internal->profile; @@ -520,6 +542,15 @@ int ff_qsv_process_data(AVCodecContext *avctx, QSVContext *q, avctx->pix_fmt = ret; + desc = av_pix_fmt_desc_get(avctx->pix_fmt); + if (!desc) + goto reinit_fail; + + if (desc->comp[0].depth > 8) { + avctx->coded_width = FFALIGN(q->parser->coded_width, 32); + avctx->coded_height = FFALIGN(q->parser->coded_height, 32); + } + ret = qsv_decode_init(avctx, q); if (ret < 0) goto reinit_fail; diff --git a/libavcodec/qsvdec.h b/libavcodec/qsvdec.h index 4e86e4b7f8f89..5b7b03a48b5cd 100644 --- a/libavcodec/qsvdec.h +++ b/libavcodec/qsvdec.h @@ -33,6 +33,7 @@ #include "libavutil/pixfmt.h" #include "avcodec.h" +#include "hwaccel.h" #include "qsv_internal.h" typedef struct QSVContext { @@ -70,6 +71,8 @@ typedef struct QSVContext { int nb_ext_buffers; } QSVContext; +extern const AVCodecHWConfigInternal *ff_qsv_hw_configs[]; + int ff_qsv_process_data(AVCodecContext *avctx, QSVContext *q, AVFrame *frame, int *got_frame, AVPacket *pkt); diff --git a/libavcodec/qsvdec_h2645.c b/libavcodec/qsvdec_h2645.c index a6b53cce8db46..831252f2d785d 100644 --- a/libavcodec/qsvdec_h2645.c +++ b/libavcodec/qsvdec_h2645.c @@ -153,8 +153,12 @@ static int qsv_decode_frame(AVCodecContext *avctx, void *data, } ret = ff_qsv_process_data(avctx, &s->qsv, frame, got_frame, &s->buffer_pkt); - if (ret < 0) + if (ret < 0){ + /* Drop buffer_pkt when failed to decode the packet. Otherwise, + the decoder will keep decoding the failure packet. */ + av_packet_unref(&s->buffer_pkt); return ret; + } s->buffer_pkt.size -= ret; s->buffer_pkt.data += ret; @@ -171,23 +175,20 @@ static void qsv_decode_flush(AVCodecContext *avctx) ff_qsv_decode_flush(avctx, &s->qsv); } +#if defined(_WIN32) +#define LOAD_PLUGIN_DEFAULT LOAD_PLUGIN_HEVC_SW +#else +#define LOAD_PLUGIN_DEFAULT LOAD_PLUGIN_HEVC_HW +#endif + #define OFFSET(x) offsetof(QSVH2645Context, x) #define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM -#if CONFIG_HEVC_QSV_HWACCEL -AVHWAccel ff_hevc_qsv_hwaccel = { - .name = "hevc_qsv", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_HEVC, - .pix_fmt = AV_PIX_FMT_QSV, -}; -#endif - #if CONFIG_HEVC_QSV_DECODER static const AVOption hevc_options[] = { { "async_depth", "Internal parallelization depth, the higher the value the higher the latency.", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = ASYNC_DEPTH_DEFAULT }, 0, INT_MAX, VD }, - { "load_plugin", "A user plugin to load in an internal session", OFFSET(load_plugin), AV_OPT_TYPE_INT, { .i64 = LOAD_PLUGIN_HEVC_SW }, LOAD_PLUGIN_NONE, LOAD_PLUGIN_HEVC_HW, VD, "load_plugin" }, + { "load_plugin", "A user plugin to load in an internal session", OFFSET(load_plugin), AV_OPT_TYPE_INT, { .i64 = LOAD_PLUGIN_DEFAULT }, LOAD_PLUGIN_NONE, LOAD_PLUGIN_HEVC_HW, VD, "load_plugin" }, { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_NONE }, 0, 0, VD, "load_plugin" }, { "hevc_sw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_SW }, 0, 0, VD, "load_plugin" }, { "hevc_hw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_HW }, 0, 0, VD, "load_plugin" }, @@ -214,22 +215,15 @@ AVCodec ff_hevc_qsv_decoder = { .decode = qsv_decode_frame, .flush = qsv_decode_flush, .close = qsv_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HYBRID, .priv_class = &hevc_class, .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, AV_PIX_FMT_P010, AV_PIX_FMT_QSV, AV_PIX_FMT_NONE }, + .hw_configs = ff_qsv_hw_configs, .bsfs = "hevc_mp4toannexb", -}; -#endif - -#if CONFIG_H264_QSV_HWACCEL -AVHWAccel ff_h264_qsv_hwaccel = { - .name = "h264_qsv", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_H264, - .pix_fmt = AV_PIX_FMT_QSV, + .wrapper_name = "qsv", }; #endif @@ -256,12 +250,14 @@ AVCodec ff_h264_qsv_decoder = { .decode = qsv_decode_frame, .flush = qsv_decode_flush, .close = qsv_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HYBRID, .priv_class = &class, .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, AV_PIX_FMT_P010, AV_PIX_FMT_QSV, AV_PIX_FMT_NONE }, + .hw_configs = ff_qsv_hw_configs, .bsfs = "h264_mp4toannexb", + .wrapper_name = "qsv", }; #endif diff --git a/libavcodec/qsvdec_other.c b/libavcodec/qsvdec_other.c index b94093d53c793..3c872dcfc2a9c 100644 --- a/libavcodec/qsvdec_other.c +++ b/libavcodec/qsvdec_other.c @@ -60,6 +60,11 @@ static av_cold int qsv_decode_close(AVCodecContext *avctx) { QSVOtherContext *s = avctx->priv_data; +#if CONFIG_VP8_QSV_DECODER + if (avctx->codec_id == AV_CODEC_ID_VP8) + av_freep(&s->qsv.load_plugins); +#endif + ff_qsv_decode_close(&s->qsv); qsv_clear_buffers(s); @@ -158,15 +163,6 @@ static const AVOption options[] = { { NULL }, }; -#if CONFIG_MPEG2_QSV_HWACCEL -AVHWAccel ff_mpeg2_qsv_hwaccel = { - .name = "mpeg2_qsv", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_MPEG2VIDEO, - .pix_fmt = AV_PIX_FMT_QSV, -}; -#endif - #if CONFIG_MPEG2_QSV_DECODER static const AVClass mpeg2_qsv_class = { .class_name = "mpeg2_qsv", @@ -185,20 +181,13 @@ AVCodec ff_mpeg2_qsv_decoder = { .decode = qsv_decode_frame, .flush = qsv_decode_flush, .close = qsv_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HYBRID, .priv_class = &mpeg2_qsv_class, .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, AV_PIX_FMT_QSV, AV_PIX_FMT_NONE }, -}; -#endif - -#if CONFIG_VC1_QSV_HWACCEL -AVHWAccel ff_vc1_qsv_hwaccel = { - .name = "vc1_qsv", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_VC1, - .pix_fmt = AV_PIX_FMT_QSV, + .hw_configs = ff_qsv_hw_configs, + .wrapper_name = "qsv", }; #endif @@ -220,20 +209,13 @@ AVCodec ff_vc1_qsv_decoder = { .decode = qsv_decode_frame, .flush = qsv_decode_flush, .close = qsv_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HYBRID, .priv_class = &vc1_qsv_class, .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, AV_PIX_FMT_QSV, AV_PIX_FMT_NONE }, -}; -#endif - -#if CONFIG_VP8_QSV_HWACCEL -AVHWAccel ff_vp8_qsv_hwaccel = { - .name = "vp8_qsv", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_VP8, - .pix_fmt = AV_PIX_FMT_QSV, + .hw_configs = ff_qsv_hw_configs, + .wrapper_name = "qsv", }; #endif @@ -255,10 +237,12 @@ AVCodec ff_vp8_qsv_decoder = { .decode = qsv_decode_frame, .flush = qsv_decode_flush, .close = qsv_decode_close, - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HYBRID, .priv_class = &vp8_qsv_class, .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, AV_PIX_FMT_QSV, AV_PIX_FMT_NONE }, + .hw_configs = ff_qsv_hw_configs, + .wrapper_name = "qsv", }; #endif diff --git a/libavcodec/qsvenc.c b/libavcodec/qsvenc.c index 5eb506fb76224..3ce5ffecd5b8d 100644 --- a/libavcodec/qsvenc.c +++ b/libavcodec/qsvenc.c @@ -85,7 +85,9 @@ static const struct { { MFX_RATECONTROL_CBR, "CBR" }, { MFX_RATECONTROL_VBR, "VBR" }, { MFX_RATECONTROL_CQP, "CQP" }, +#if QSV_HAVE_AVBR { MFX_RATECONTROL_AVBR, "AVBR" }, +#endif #if QSV_HAVE_LA { MFX_RATECONTROL_LA, "LA" }, #endif @@ -161,11 +163,14 @@ static void dump_video_param(AVCodecContext *avctx, QSVEncContext *q, } else if (info->RateControlMethod == MFX_RATECONTROL_CQP) { av_log(avctx, AV_LOG_VERBOSE, "QPI: %"PRIu16"; QPP: %"PRIu16"; QPB: %"PRIu16"\n", info->QPI, info->QPP, info->QPB); - } else if (info->RateControlMethod == MFX_RATECONTROL_AVBR) { + } +#if QSV_HAVE_AVBR + else if (info->RateControlMethod == MFX_RATECONTROL_AVBR) { av_log(avctx, AV_LOG_VERBOSE, "TargetKbps: %"PRIu16"; Accuracy: %"PRIu16"; Convergence: %"PRIu16"\n", info->TargetKbps, info->Accuracy, info->Convergence); } +#endif #if QSV_HAVE_LA else if (info->RateControlMethod == MFX_RATECONTROL_LA #if QSV_HAVE_LA_HRD @@ -287,6 +292,12 @@ static int select_rc_mode(AVCodecContext *avctx, QSVEncContext *q) return AVERROR(EINVAL); } + if (!want_qscale && avctx->global_quality > 0 && !QSV_HAVE_ICQ){ + av_log(avctx, AV_LOG_ERROR, + "ICQ ratecontrol mode requested, but is not supported by this SDK version\n"); + return AVERROR(ENOSYS); + } + if (want_qscale) { rc_mode = MFX_RATECONTROL_CQP; rc_desc = "constant quantization parameter (CQP)"; @@ -319,10 +330,14 @@ static int select_rc_mode(AVCodecContext *avctx, QSVEncContext *q) else if (avctx->rc_max_rate == avctx->bit_rate) { rc_mode = MFX_RATECONTROL_CBR; rc_desc = "constant bitrate (CBR)"; - } else if (!avctx->rc_max_rate) { + } +#if QSV_HAVE_AVBR + else if (!avctx->rc_max_rate) { rc_mode = MFX_RATECONTROL_AVBR; rc_desc = "average variable bitrate (AVBR)"; - } else { + } +#endif + else { rc_mode = MFX_RATECONTROL_VBR; rc_desc = "variable bitrate (VBR)"; } @@ -333,18 +348,95 @@ static int select_rc_mode(AVCodecContext *avctx, QSVEncContext *q) return 0; } -static int rc_supported(QSVEncContext *q) +static int check_enc_param(AVCodecContext *avctx, QSVEncContext *q) { mfxVideoParam param_out = { .mfx.CodecId = q->param.mfx.CodecId }; mfxStatus ret; +#define UNMATCH(x) (param_out.mfx.x != q->param.mfx.x) + ret = MFXVideoENCODE_Query(q->session, &q->param, ¶m_out); - if (ret < 0 || - param_out.mfx.RateControlMethod != q->param.mfx.RateControlMethod) + + if (ret < 0) { + if (UNMATCH(CodecId)) + av_log(avctx, AV_LOG_ERROR, "Current codec type is unsupported\n"); + if (UNMATCH(CodecProfile)) + av_log(avctx, AV_LOG_ERROR, "Current profile is unsupported\n"); + if (UNMATCH(RateControlMethod)) + av_log(avctx, AV_LOG_ERROR, "Selected ratecontrol mode is unsupported\n"); + if (UNMATCH(LowPower)) + av_log(avctx, AV_LOG_ERROR, "Low power mode is unsupported\n"); + if (UNMATCH(FrameInfo.FrameRateExtN) || UNMATCH(FrameInfo.FrameRateExtD)) + av_log(avctx, AV_LOG_ERROR, "Current frame rate is unsupported\n"); + if (UNMATCH(FrameInfo.PicStruct)) + av_log(avctx, AV_LOG_ERROR, "Current picture structure is unsupported\n"); + if (UNMATCH(FrameInfo.Width) || UNMATCH(FrameInfo.Height)) + av_log(avctx, AV_LOG_ERROR, "Current resolution is unsupported\n"); + if (UNMATCH(FrameInfo.FourCC)) + av_log(avctx, AV_LOG_ERROR, "Current pixel format is unsupported\n"); return 0; + } return 1; } +static int init_video_param_jpeg(AVCodecContext *avctx, QSVEncContext *q) +{ + enum AVPixelFormat sw_format = avctx->pix_fmt == AV_PIX_FMT_QSV ? + avctx->sw_pix_fmt : avctx->pix_fmt; + const AVPixFmtDescriptor *desc; + int ret; + + ret = ff_qsv_codec_id_to_mfx(avctx->codec_id); + if (ret < 0) + return AVERROR_BUG; + q->param.mfx.CodecId = ret; + + if (avctx->level > 0) + q->param.mfx.CodecLevel = avctx->level; + q->param.mfx.CodecProfile = q->profile; + + desc = av_pix_fmt_desc_get(sw_format); + if (!desc) + return AVERROR_BUG; + + ff_qsv_map_pixfmt(sw_format, &q->param.mfx.FrameInfo.FourCC); + + q->param.mfx.FrameInfo.CropX = 0; + q->param.mfx.FrameInfo.CropY = 0; + q->param.mfx.FrameInfo.CropW = avctx->width; + q->param.mfx.FrameInfo.CropH = avctx->height; + q->param.mfx.FrameInfo.AspectRatioW = avctx->sample_aspect_ratio.num; + q->param.mfx.FrameInfo.AspectRatioH = avctx->sample_aspect_ratio.den; + q->param.mfx.FrameInfo.ChromaFormat = MFX_CHROMAFORMAT_YUV420; + q->param.mfx.FrameInfo.BitDepthLuma = desc->comp[0].depth; + q->param.mfx.FrameInfo.BitDepthChroma = desc->comp[0].depth; + q->param.mfx.FrameInfo.Shift = desc->comp[0].depth > 8; + + q->param.mfx.FrameInfo.Width = FFALIGN(avctx->width, 16); + q->param.mfx.FrameInfo.Height = FFALIGN(avctx->height, 16); + + if (avctx->hw_frames_ctx) { + AVHWFramesContext *frames_ctx = (AVHWFramesContext *)avctx->hw_frames_ctx->data; + AVQSVFramesContext *frames_hwctx = frames_ctx->hwctx; + q->param.mfx.FrameInfo.Width = frames_hwctx->surfaces[0].Info.Width; + q->param.mfx.FrameInfo.Height = frames_hwctx->surfaces[0].Info.Height; + } + + if (avctx->framerate.den > 0 && avctx->framerate.num > 0) { + q->param.mfx.FrameInfo.FrameRateExtN = avctx->framerate.num; + q->param.mfx.FrameInfo.FrameRateExtD = avctx->framerate.den; + } else { + q->param.mfx.FrameInfo.FrameRateExtN = avctx->time_base.den; + q->param.mfx.FrameInfo.FrameRateExtD = avctx->time_base.num; + } + + q->param.mfx.Interleaved = 1; + q->param.mfx.Quality = av_clip(avctx->global_quality, 1, 100); + q->param.mfx.RestartInterval = 0; + + return 0; +} + static int init_video_param(AVCodecContext *avctx, QSVEncContext *q) { enum AVPixelFormat sw_format = avctx->pix_fmt == AV_PIX_FMT_QSV ? @@ -437,6 +529,7 @@ static int init_video_param(AVCodecContext *avctx, QSVEncContext *q) #if QSV_HAVE_VCM case MFX_RATECONTROL_VCM: #endif + q->param.mfx.BufferSizeInKB = avctx->rc_buffer_size / 8000; q->param.mfx.InitialDelayInKB = avctx->rc_initial_buffer_occupancy / 1000; q->param.mfx.TargetKbps = avctx->bit_rate / 1000; q->param.mfx.MaxKbps = avctx->rc_max_rate / 1000; @@ -449,11 +542,13 @@ static int init_video_param(AVCodecContext *avctx, QSVEncContext *q) q->param.mfx.QPB = av_clip(quant * fabs(avctx->b_quant_factor) + avctx->b_quant_offset, 0, 51); break; +#if QSV_HAVE_AVBR case MFX_RATECONTROL_AVBR: q->param.mfx.TargetKbps = avctx->bit_rate / 1000; q->param.mfx.Convergence = q->avbr_convergence; q->param.mfx.Accuracy = q->avbr_accuracy; break; +#endif #if QSV_HAVE_LA case MFX_RATECONTROL_LA: q->param.mfx.TargetKbps = avctx->bit_rate / 1000; @@ -474,14 +569,6 @@ static int init_video_param(AVCodecContext *avctx, QSVEncContext *q) if (avctx->codec_id != AV_CODEC_ID_HEVC) { q->extco.Header.BufferId = MFX_EXTBUFF_CODING_OPTION; q->extco.Header.BufferSz = sizeof(q->extco); -#if FF_API_CODER_TYPE -FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->coder_type != 0) - q->cavlc = avctx->coder_type == FF_CODER_TYPE_VLC; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - q->extco.CAVLC = q->cavlc ? MFX_CODINGOPTION_ON - : MFX_CODINGOPTION_UNKNOWN; q->extco.PicTimingSEI = q->pic_timing_sei ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_UNKNOWN; @@ -490,6 +577,15 @@ FF_ENABLE_DEPRECATION_WARNINGS q->extco.RateDistortionOpt = q->rdo > 0 ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF; if (avctx->codec_id == AV_CODEC_ID_H264) { +#if FF_API_CODER_TYPE +FF_DISABLE_DEPRECATION_WARNINGS + if (avctx->coder_type >= 0) + q->cavlc = avctx->coder_type == FF_CODER_TYPE_VLC; +FF_ENABLE_DEPRECATION_WARNINGS +#endif + q->extco.CAVLC = q->cavlc ? MFX_CODINGOPTION_ON + : MFX_CODINGOPTION_UNKNOWN; + if (avctx->strict_std_compliance != FF_COMPLIANCE_NORMAL) q->extco.NalHrdConformance = avctx->strict_std_compliance > FF_COMPLIANCE_NORMAL ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF; @@ -499,6 +595,7 @@ FF_ENABLE_DEPRECATION_WARNINGS if (q->recovery_point_sei >= 0) q->extco.RecoveryPointSEI = q->recovery_point_sei ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF; q->extco.MaxDecFrameBuffering = q->max_dec_frame_buffering; + q->extco.AUDelimiter = q->aud ? MFX_CODINGOPTION_ON : MFX_CODINGOPTION_OFF; } q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->extco; @@ -533,6 +630,10 @@ FF_ENABLE_DEPRECATION_WARNINGS q->extco2.Trellis = q->trellis; #endif +#if QSV_HAVE_LA_DS + q->extco2.LookAheadDS = q->look_ahead_downsampling; +#endif + #if QSV_HAVE_BREF_TYPE #if FF_API_PRIVATE_OPT FF_DISABLE_DEPRECATION_WARNINGS @@ -549,24 +650,52 @@ FF_ENABLE_DEPRECATION_WARNINGS #endif q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->extco2; - -#if QSV_HAVE_LA_DS - q->extco2.LookAheadDS = q->look_ahead_downsampling; + } #endif +#if QSV_HAVE_MF + if (avctx->codec_id == AV_CODEC_ID_H264) { + mfxVersion ver; + ret = MFXQueryVersion(q->session,&ver); + if (ret >= MFX_ERR_NONE && QSV_RUNTIME_VERSION_ATLEAST(ver, 1, 25)) { + q->extmfp.Header.BufferId = MFX_EXTBUFF_MULTI_FRAME_PARAM; + q->extmfp.Header.BufferSz = sizeof(q->extmfp); + + q->extmfp.MFMode = q->mfmode; + av_log(avctx,AV_LOG_VERBOSE,"MFMode:%d\n", q->extmfp.MFMode); + q->extparam_internal[q->nb_extparam_internal++] = (mfxExtBuffer *)&q->extmfp; + } } #endif } - if (!rc_supported(q)) { + if (!check_enc_param(avctx,q)) { av_log(avctx, AV_LOG_ERROR, - "Selected ratecontrol mode is not supported by the QSV " - "runtime. Choose a different mode.\n"); + "some encoding parameters are not supported by the QSV " + "runtime. Please double check the input parameters.\n"); return AVERROR(ENOSYS); } return 0; } +static int qsv_retrieve_enc_jpeg_params(AVCodecContext *avctx, QSVEncContext *q) +{ + int ret = 0; + + ret = MFXVideoENCODE_GetVideoParam(q->session, &q->param); + if (ret < 0) + return ff_qsv_print_error(avctx, ret, + "Error calling GetVideoParam"); + + q->packet_size = q->param.mfx.BufferSizeInKB * 1000; + + // for qsv mjpeg the return value maybe 0 so alloc the buffer + if (q->packet_size == 0) + q->packet_size = q->param.mfx.FrameInfo.Height * q->param.mfx.FrameInfo.Width * 4; + + return 0; +} + static int qsv_retrieve_enc_params(AVCodecContext *avctx, QSVEncContext *q) { AVCPBProperties *cpb_props; @@ -760,7 +889,15 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q) if (ret < 0) return ret; - ret = init_video_param(avctx, q); + // in the mfxInfoMFX struct, JPEG is different from other codecs + switch (avctx->codec_id) { + case AV_CODEC_ID_MJPEG: + ret = init_video_param_jpeg(avctx, q); + break; + default: + ret = init_video_param(avctx, q); + break; + } if (ret < 0) return ret; @@ -820,7 +957,14 @@ int ff_qsv_enc_init(AVCodecContext *avctx, QSVEncContext *q) ff_qsv_print_warning(avctx, ret, "Warning in encoder initialization"); - ret = qsv_retrieve_enc_params(avctx, q); + switch (avctx->codec_id) { + case AV_CODEC_ID_MJPEG: + ret = qsv_retrieve_enc_jpeg_params(avctx, q); + break; + default: + ret = qsv_retrieve_enc_params(avctx, q); + break; + } if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error retrieving encoding parameters.\n"); return ret; diff --git a/libavcodec/qsvenc.h b/libavcodec/qsvenc.h index 12e3444b7584b..d48272224c3b7 100644 --- a/libavcodec/qsvenc.h +++ b/libavcodec/qsvenc.h @@ -44,9 +44,27 @@ #define QSV_HAVE_LA QSV_VERSION_ATLEAST(1, 7) #define QSV_HAVE_LA_DS QSV_VERSION_ATLEAST(1, 8) #define QSV_HAVE_LA_HRD QSV_VERSION_ATLEAST(1, 11) + +#if defined(_WIN32) +#define QSV_HAVE_AVBR QSV_VERSION_ATLEAST(1, 3) #define QSV_HAVE_ICQ QSV_VERSION_ATLEAST(1, 8) #define QSV_HAVE_VCM QSV_VERSION_ATLEAST(1, 8) #define QSV_HAVE_QVBR QSV_VERSION_ATLEAST(1, 11) +#define QSV_HAVE_MF 0 +#else +#define QSV_HAVE_AVBR 0 +#define QSV_HAVE_ICQ 0 +#define QSV_HAVE_VCM 0 +#define QSV_HAVE_QVBR 0 +#define QSV_HAVE_MF QSV_VERSION_ATLEAST(1, 25) +#endif + +#if !QSV_HAVE_LA_DS +#define MFX_LOOKAHEAD_DS_UNKNOWN 0 +#define MFX_LOOKAHEAD_DS_OFF 0 +#define MFX_LOOKAHEAD_DS_2x 0 +#define MFX_LOOKAHEAD_DS_4x 0 +#endif #define QSV_COMMON_OPTS \ { "async_depth", "Maximum processing parallelism", OFFSET(qsv.async_depth), AV_OPT_TYPE_INT, { .i64 = ASYNC_DEPTH_DEFAULT }, 0, INT_MAX, VE }, \ @@ -70,7 +88,6 @@ { "adaptive_i", "Adaptive I-frame placement", OFFSET(qsv.adaptive_i), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, \ { "adaptive_b", "Adaptive B-frame placement", OFFSET(qsv.adaptive_b), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, \ { "b_strategy", "Strategy to choose between I/P/B-frames", OFFSET(qsv.b_strategy), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, \ -{ "cavlc", "Enable CAVLC", OFFSET(qsv.cavlc), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, \ typedef int SetEncodeCtrlCB (AVCodecContext *avctx, const AVFrame *frame, mfxEncodeCtrl* enc_ctrl); @@ -93,12 +110,15 @@ typedef struct QSVEncContext { #if QSV_HAVE_CO2 mfxExtCodingOption2 extco2; #endif - +#if QSV_HAVE_MF + mfxExtMultiFrameParam extmfp; + mfxExtMultiFrameControl extmfc; +#endif mfxExtOpaqueSurfaceAlloc opaque_alloc; mfxFrameSurface1 **opaque_surfaces; AVBufferRef *opaque_alloc_buf; - mfxExtBuffer *extparam_internal[2 + QSV_HAVE_CO2]; + mfxExtBuffer *extparam_internal[2 + QSV_HAVE_CO2 + (QSV_HAVE_MF * 2)]; int nb_extparam_internal; mfxExtBuffer **extparam; @@ -123,6 +143,8 @@ typedef struct QSVEncContext { int max_frame_size; int max_slice_size; + int aud; + int single_sei_nal_unit; int max_dec_frame_buffering; int trellis; @@ -141,6 +163,10 @@ typedef struct QSVEncContext { int recovery_point_sei; int a53_cc; + +#if QSV_HAVE_MF + int mfmode; +#endif char *load_plugins; SetEncodeCtrlCB *set_encode_ctrl_cb; } QSVEncContext; diff --git a/libavcodec/qsvenc_h264.c b/libavcodec/qsvenc_h264.c index 389335f39d260..718bf9cb21658 100644 --- a/libavcodec/qsvenc_h264.c +++ b/libavcodec/qsvenc_h264.c @@ -102,20 +102,24 @@ static av_cold int qsv_enc_close(AVCodecContext *avctx) static const AVOption options[] = { QSV_COMMON_OPTS + { "cavlc", "Enable CAVLC", OFFSET(qsv.cavlc), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, { "idr_interval", "Distance (in I-frames) between IDR frames", OFFSET(qsv.idr_interval), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, { "pic_timing_sei", "Insert picture timing SEI with pic_struct_syntax element", OFFSET(qsv.pic_timing_sei), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, VE }, { "single_sei_nal_unit", "Put all the SEI messages into one NALU", OFFSET(qsv.single_sei_nal_unit), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, VE }, { "max_dec_frame_buffering", "Maximum number of frames buffered in the DPB", OFFSET(qsv.max_dec_frame_buffering), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, UINT16_MAX, VE }, #if QSV_HAVE_LA - { "look_ahead", "Use VBR algorithm with look ahead", OFFSET(qsv.look_ahead), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, VE }, + { "look_ahead", "Use VBR algorithm with look ahead", OFFSET(qsv.look_ahead), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE }, { "look_ahead_depth", "Depth of look ahead in number frames", OFFSET(qsv.look_ahead_depth), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 100, VE }, #endif #if QSV_HAVE_LA_DS - { "look_ahead_downsampling", NULL, OFFSET(qsv.look_ahead_downsampling), AV_OPT_TYPE_INT, { .i64 = MFX_LOOKAHEAD_DS_UNKNOWN }, MFX_LOOKAHEAD_DS_UNKNOWN, MFX_LOOKAHEAD_DS_2x, VE, "look_ahead_downsampling" }, + { "look_ahead_downsampling", "Downscaling factor for the frames saved for the lookahead analysis", OFFSET(qsv.look_ahead_downsampling), + AV_OPT_TYPE_INT, { .i64 = MFX_LOOKAHEAD_DS_UNKNOWN }, MFX_LOOKAHEAD_DS_UNKNOWN, MFX_LOOKAHEAD_DS_2x, VE, "look_ahead_downsampling" }, { "unknown" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_UNKNOWN }, INT_MIN, INT_MAX, VE, "look_ahead_downsampling" }, + { "auto" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_UNKNOWN }, INT_MIN, INT_MAX, VE, "look_ahead_downsampling" }, { "off" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_OFF }, INT_MIN, INT_MAX, VE, "look_ahead_downsampling" }, { "2x" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_2x }, INT_MIN, INT_MAX, VE, "look_ahead_downsampling" }, + { "4x" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_LOOKAHEAD_DS_4x }, INT_MIN, INT_MAX, VE, "look_ahead_downsampling" }, #endif { "int_ref_type", "Intra refresh type", OFFSET(qsv.int_ref_type), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, UINT16_MAX, VE, "int_ref_type" }, @@ -138,6 +142,13 @@ static const AVOption options[] = { { "high" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = MFX_PROFILE_AVC_HIGH }, INT_MIN, INT_MAX, VE, "profile" }, { "a53cc" , "Use A53 Closed Captions (if available)", OFFSET(qsv.a53_cc), AV_OPT_TYPE_INT, {.i64 = 1}, 0, 1, VE}, + + { "aud", "Insert the Access Unit Delimiter NAL", OFFSET(qsv.aud), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, VE}, + +#if QSV_HAVE_MF + { "mfmode", "Multi-Frame Mode", OFFSET(qsv.mfmode), AV_OPT_TYPE_INT, { .i64 = MFX_MF_AUTO }, 0, INT_MAX, VE }, +#endif + { NULL }, }; @@ -154,7 +165,9 @@ static const AVCodecDefault qsv_enc_defaults[] = { // same as the x264 default { "g", "250" }, { "bf", "3" }, - { "coder", "ac" }, +#if FF_API_CODER_TYPE + { "coder", "-1" }, +#endif { "flags", "+cgop" }, #if FF_API_PRIVATE_OPT @@ -172,7 +185,7 @@ AVCodec ff_h264_qsv_encoder = { .init = qsv_enc_init, .encode2 = qsv_enc_frame, .close = qsv_enc_close, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID, .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, AV_PIX_FMT_P010, AV_PIX_FMT_QSV, @@ -180,4 +193,5 @@ AVCodec ff_h264_qsv_encoder = { .priv_class = &class, .defaults = qsv_enc_defaults, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .wrapper_name = "qsv", }; diff --git a/libavcodec/qsvenc_hevc.c b/libavcodec/qsvenc_hevc.c index b0e5ace7c7d88..4339b316a3d5a 100644 --- a/libavcodec/qsvenc_hevc.c +++ b/libavcodec/qsvenc_hevc.c @@ -56,6 +56,7 @@ static int generate_fake_vps(QSVEncContext *q, AVCodecContext *avctx) PutByteContext pbc; GetBitContext gb; + H2645RBSP sps_rbsp = { NULL }; H2645NAL sps_nal = { NULL }; HEVCSPS sps = { 0 }; HEVCVPS vps = { 0 }; @@ -69,8 +70,12 @@ static int generate_fake_vps(QSVEncContext *q, AVCodecContext *avctx) return AVERROR_UNKNOWN; } + av_fast_padded_malloc(&sps_rbsp.rbsp_buffer, &sps_rbsp.rbsp_buffer_alloc_size, avctx->extradata_size); + if (!sps_rbsp.rbsp_buffer) + return AVERROR(ENOMEM); + /* parse the SPS */ - ret = ff_h2645_extract_rbsp(avctx->extradata + 4, avctx->extradata_size - 4, &sps_nal, 1); + ret = ff_h2645_extract_rbsp(avctx->extradata + 4, avctx->extradata_size - 4, &sps_rbsp, &sps_nal, 1); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error unescaping the SPS buffer\n"); return ret; @@ -78,7 +83,7 @@ static int generate_fake_vps(QSVEncContext *q, AVCodecContext *avctx) ret = init_get_bits8(&gb, sps_nal.data, sps_nal.size); if (ret < 0) { - av_freep(&sps_nal.rbsp_buffer); + av_freep(&sps_rbsp.rbsp_buffer); return ret; } @@ -87,13 +92,13 @@ static int generate_fake_vps(QSVEncContext *q, AVCodecContext *avctx) if (type != HEVC_NAL_SPS) { av_log(avctx, AV_LOG_ERROR, "Unexpected NAL type in the extradata: %d\n", type); - av_freep(&sps_nal.rbsp_buffer); + av_freep(&sps_rbsp.rbsp_buffer); return AVERROR_INVALIDDATA; } get_bits(&gb, 9); ret = ff_hevc_parse_sps(&sps, &gb, &sps_id, 0, NULL, avctx); - av_freep(&sps_nal.rbsp_buffer); + av_freep(&sps_rbsp.rbsp_buffer); if (ret < 0) { av_log(avctx, AV_LOG_ERROR, "Error parsing the SPS\n"); return ret; @@ -181,6 +186,9 @@ static av_cold int qsv_enc_init(AVCodecContext *avctx) } } + // HEVC and H264 meaning of the value is shifted by 1, make it consistent + q->qsv.idr_interval++; + ret = ff_qsv_enc_init(avctx, &q->qsv); if (ret < 0) return ret; @@ -209,12 +217,20 @@ static av_cold int qsv_enc_close(AVCodecContext *avctx) return ff_qsv_enc_close(avctx, &q->qsv); } +#if defined(_WIN32) +#define LOAD_PLUGIN_DEFAULT LOAD_PLUGIN_HEVC_SW +#else +#define LOAD_PLUGIN_DEFAULT LOAD_PLUGIN_HEVC_HW +#endif + #define OFFSET(x) offsetof(QSVHEVCEncContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { QSV_COMMON_OPTS - { "load_plugin", "A user plugin to load in an internal session", OFFSET(load_plugin), AV_OPT_TYPE_INT, { .i64 = LOAD_PLUGIN_HEVC_SW }, LOAD_PLUGIN_NONE, LOAD_PLUGIN_HEVC_HW, VE, "load_plugin" }, + { "idr_interval", "Distance (in I-frames) between IDR frames", OFFSET(qsv.idr_interval), AV_OPT_TYPE_INT, { .i64 = 0 }, -1, INT_MAX, VE, "idr_interval" }, + { "begin_only", "Output an IDR-frame only at the beginning of the stream", 0, AV_OPT_TYPE_CONST, { .i64 = -1 }, 0, 0, VE, "idr_interval" }, + { "load_plugin", "A user plugin to load in an internal session", OFFSET(load_plugin), AV_OPT_TYPE_INT, { .i64 = LOAD_PLUGIN_DEFAULT }, LOAD_PLUGIN_NONE, LOAD_PLUGIN_HEVC_HW, VE, "load_plugin" }, { "none", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_NONE }, 0, 0, VE, "load_plugin" }, { "hevc_sw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_SW }, 0, 0, VE, "load_plugin" }, { "hevc_hw", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = LOAD_PLUGIN_HEVC_HW }, 0, 0, VE, "load_plugin" }, @@ -261,7 +277,7 @@ AVCodec ff_hevc_qsv_encoder = { .init = qsv_enc_init, .encode2 = qsv_enc_frame, .close = qsv_enc_close, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID, .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, AV_PIX_FMT_P010, AV_PIX_FMT_QSV, @@ -269,4 +285,5 @@ AVCodec ff_hevc_qsv_encoder = { .priv_class = &class, .defaults = qsv_enc_defaults, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .wrapper_name = "qsv", }; diff --git a/libavcodec/qsvenc_jpeg.c b/libavcodec/qsvenc_jpeg.c new file mode 100644 index 0000000000000..c18fe91940bb3 --- /dev/null +++ b/libavcodec/qsvenc_jpeg.c @@ -0,0 +1,92 @@ +/* + * Intel MediaSDK QSV based MJPEG encoder + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include +#include + +#include + +#include "libavutil/common.h" +#include "libavutil/opt.h" + +#include "avcodec.h" +#include "internal.h" +#include "h264.h" +#include "qsv.h" +#include "qsv_internal.h" +#include "qsvenc.h" + +typedef struct QSVMJPEGEncContext { + AVClass *class; + QSVEncContext qsv; +} QSVMJPEGEncContext; + +static av_cold int qsv_enc_init(AVCodecContext *avctx) +{ + QSVMJPEGEncContext *q = avctx->priv_data; + + return ff_qsv_enc_init(avctx, &q->qsv); +} + +static int qsv_enc_frame(AVCodecContext *avctx, AVPacket *pkt, + const AVFrame *frame, int *got_packet) +{ + QSVMJPEGEncContext *q = avctx->priv_data; + + return ff_qsv_encode(avctx, &q->qsv, pkt, frame, got_packet); +} + +static av_cold int qsv_enc_close(AVCodecContext *avctx) +{ + QSVMJPEGEncContext *q = avctx->priv_data; + + return ff_qsv_enc_close(avctx, &q->qsv); +} + +#define OFFSET(x) offsetof(QSVMJPEGEncContext, x) +#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + { NULL }, +}; + +static const AVClass class = { + .class_name = "mjpeg_qsv encoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_mjpeg_qsv_encoder = { + .name = "mjpeg_qsv", + .long_name = NULL_IF_CONFIG_SMALL("MJPEG (Intel Quick Sync Video acceleration)"), + .priv_data_size = sizeof(QSVMJPEGEncContext), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_MJPEG, + .init = qsv_enc_init, + .encode2 = qsv_enc_frame, + .close = qsv_enc_close, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID, + .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, + AV_PIX_FMT_QSV, + AV_PIX_FMT_NONE }, + .priv_class = &class, + .wrapper_name = "qsv", +}; diff --git a/libavcodec/qsvenc_mpeg2.c b/libavcodec/qsvenc_mpeg2.c index 5b583fb4911a3..a7427d81099a9 100644 --- a/libavcodec/qsvenc_mpeg2.c +++ b/libavcodec/qsvenc_mpeg2.c @@ -104,11 +104,12 @@ AVCodec ff_mpeg2_qsv_encoder = { .init = qsv_enc_init, .encode2 = qsv_enc_frame, .close = qsv_enc_close, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HYBRID, .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_NV12, AV_PIX_FMT_QSV, AV_PIX_FMT_NONE }, .priv_class = &class, .defaults = qsv_enc_defaults, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, + .wrapper_name = "qsv", }; diff --git a/libavcodec/raw.h b/libavcodec/raw.h index 24bf4cc55acd9..28a27b1f9e8d7 100644 --- a/libavcodec/raw.h +++ b/libavcodec/raw.h @@ -28,6 +28,7 @@ #define AVCODEC_RAW_H #include "avcodec.h" +#include "internal.h" #include "libavutil/internal.h" typedef struct PixelFormatTag { @@ -41,7 +42,7 @@ const struct PixelFormatTag *avpriv_get_raw_pix_fmt_tags(void); enum AVPixelFormat avpriv_find_pix_fmt(const PixelFormatTag *tags, unsigned int fourcc); -extern av_export const PixelFormatTag avpriv_pix_fmt_bps_avi[]; -extern av_export const PixelFormatTag avpriv_pix_fmt_bps_mov[]; +extern av_export_avcodec const PixelFormatTag avpriv_pix_fmt_bps_avi[]; +extern av_export_avcodec const PixelFormatTag avpriv_pix_fmt_bps_mov[]; #endif /* AVCODEC_RAW_H */ diff --git a/libavcodec/rawdec.c b/libavcodec/rawdec.c index 1893b2644401a..53f5b76e93e7b 100644 --- a/libavcodec/rawdec.c +++ b/libavcodec/rawdec.c @@ -92,12 +92,14 @@ static av_cold int raw_init_decoder(AVCodecContext *avctx) return AVERROR(EINVAL); } - if (desc->flags & (AV_PIX_FMT_FLAG_PAL | AV_PIX_FMT_FLAG_PSEUDOPAL)) { + if (desc->flags & (AV_PIX_FMT_FLAG_PAL | FF_PSEUDOPAL)) { context->palette = av_buffer_alloc(AVPALETTE_SIZE); if (!context->palette) return AVERROR(ENOMEM); +#if FF_API_PSEUDOPAL if (desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) avpriv_set_systematic_pal2((uint32_t*)context->palette->data, avctx->pix_fmt); +#endif else { memset(context->palette->data, 0, AVPALETTE_SIZE); if (avctx->bits_per_coded_sample == 1) @@ -423,7 +425,7 @@ static int raw_decode(AVCodecContext *avctx, void *data, int *got_frame, } if ((avctx->pix_fmt == AV_PIX_FMT_PAL8 && buf_size < context->frame_size) || - (desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL)) { + (desc->flags & FF_PSEUDOPAL)) { frame->buf[1] = av_buffer_ref(context->palette); if (!frame->buf[1]) { av_buffer_unref(&frame->buf[0]); diff --git a/libavcodec/remove_extradata_bsf.c b/libavcodec/remove_extradata_bsf.c index a54bbdbacfcee..b762079e05b3d 100644 --- a/libavcodec/remove_extradata_bsf.c +++ b/libavcodec/remove_extradata_bsf.c @@ -38,30 +38,26 @@ typedef struct RemoveExtradataContext { AVCodecContext *avctx; } RemoveExtradataContext; -static int remove_extradata(AVBSFContext *ctx, AVPacket *out) +static int remove_extradata(AVBSFContext *ctx, AVPacket *pkt) { RemoveExtradataContext *s = ctx->priv_data; - AVPacket *in; int ret; - ret = ff_bsf_get_packet(ctx, &in); + ret = ff_bsf_get_packet_ref(ctx, pkt); if (ret < 0) return ret; if (s->parser && s->parser->parser->split) { if (s->freq == REMOVE_FREQ_ALL || - (s->freq == REMOVE_FREQ_NONKEYFRAME && !(in->flags & AV_PKT_FLAG_KEY)) || - (s->freq == REMOVE_FREQ_KEYFRAME && in->flags & AV_PKT_FLAG_KEY)) { - int i = s->parser->parser->split(s->avctx, in->data, in->size); - in->data += i; - in->size -= i; + (s->freq == REMOVE_FREQ_NONKEYFRAME && !(pkt->flags & AV_PKT_FLAG_KEY)) || + (s->freq == REMOVE_FREQ_KEYFRAME && pkt->flags & AV_PKT_FLAG_KEY)) { + int i = s->parser->parser->split(s->avctx, pkt->data, pkt->size); + pkt->data += i; + pkt->size -= i; } } - av_packet_move_ref(out, in); - av_packet_free(&in); - return 0; } @@ -94,12 +90,13 @@ static void remove_extradata_close(AVBSFContext *ctx) } #define OFFSET(x) offsetof(RemoveExtradataContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_BSF_PARAM) static const AVOption options[] = { - { "freq", NULL, OFFSET(freq), AV_OPT_TYPE_INT, { .i64 = REMOVE_FREQ_KEYFRAME }, REMOVE_FREQ_KEYFRAME, REMOVE_FREQ_NONKEYFRAME, 0, "freq" }, - { "k", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = REMOVE_FREQ_NONKEYFRAME }, .unit = "freq" }, - { "keyframe", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = REMOVE_FREQ_KEYFRAME }, .unit = "freq" }, - { "e", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = REMOVE_FREQ_ALL }, .unit = "freq" }, - { "all", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = REMOVE_FREQ_ALL }, .unit = "freq" }, + { "freq", NULL, OFFSET(freq), AV_OPT_TYPE_INT, { .i64 = REMOVE_FREQ_KEYFRAME }, REMOVE_FREQ_KEYFRAME, REMOVE_FREQ_NONKEYFRAME, FLAGS, "freq" }, + { "k", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = REMOVE_FREQ_NONKEYFRAME }, .flags = FLAGS, .unit = "freq" }, + { "keyframe", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = REMOVE_FREQ_KEYFRAME }, .flags = FLAGS, .unit = "freq" }, + { "e", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = REMOVE_FREQ_ALL }, .flags = FLAGS, .unit = "freq" }, + { "all", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = REMOVE_FREQ_ALL }, .flags = FLAGS, .unit = "freq" }, { NULL }, }; diff --git a/libavcodec/resample.c b/libavcodec/resample.c deleted file mode 100644 index 4c5eb9f10e672..0000000000000 --- a/libavcodec/resample.c +++ /dev/null @@ -1,439 +0,0 @@ -/* - * samplerate conversion for both audio and video - * Copyright (c) 2000 Fabrice Bellard - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file - * samplerate conversion for both audio and video - */ - -#include - -#include "avcodec.h" -#include "audioconvert.h" -#include "libavutil/opt.h" -#include "libavutil/mem.h" -#include "libavutil/samplefmt.h" - -#if FF_API_AVCODEC_RESAMPLE -FF_DISABLE_DEPRECATION_WARNINGS - -#define MAX_CHANNELS 8 - -struct AVResampleContext; - -static const char *context_to_name(void *ptr) -{ - return "audioresample"; -} - -static const AVOption options[] = {{NULL}}; -static const AVClass audioresample_context_class = { - "ReSampleContext", context_to_name, options, LIBAVUTIL_VERSION_INT -}; - -struct ReSampleContext { - struct AVResampleContext *resample_context; - short *temp[MAX_CHANNELS]; - int temp_len; - float ratio; - /* channel convert */ - int input_channels, output_channels, filter_channels; - AVAudioConvert *convert_ctx[2]; - enum AVSampleFormat sample_fmt[2]; ///< input and output sample format - unsigned sample_size[2]; ///< size of one sample in sample_fmt - short *buffer[2]; ///< buffers used for conversion to S16 - unsigned buffer_size[2]; ///< sizes of allocated buffers -}; - -/* n1: number of samples */ -static void stereo_to_mono(short *output, short *input, int n1) -{ - short *p, *q; - int n = n1; - - p = input; - q = output; - while (n >= 4) { - q[0] = (p[0] + p[1]) >> 1; - q[1] = (p[2] + p[3]) >> 1; - q[2] = (p[4] + p[5]) >> 1; - q[3] = (p[6] + p[7]) >> 1; - q += 4; - p += 8; - n -= 4; - } - while (n > 0) { - q[0] = (p[0] + p[1]) >> 1; - q++; - p += 2; - n--; - } -} - -/* n1: number of samples */ -static void mono_to_stereo(short *output, short *input, int n1) -{ - short *p, *q; - int n = n1; - int v; - - p = input; - q = output; - while (n >= 4) { - v = p[0]; q[0] = v; q[1] = v; - v = p[1]; q[2] = v; q[3] = v; - v = p[2]; q[4] = v; q[5] = v; - v = p[3]; q[6] = v; q[7] = v; - q += 8; - p += 4; - n -= 4; - } - while (n > 0) { - v = p[0]; q[0] = v; q[1] = v; - q += 2; - p += 1; - n--; - } -} - -/* -5.1 to stereo input: [fl, fr, c, lfe, rl, rr] -- Left = front_left + rear_gain * rear_left + center_gain * center -- Right = front_right + rear_gain * rear_right + center_gain * center -Where rear_gain is usually around 0.5-1.0 and - center_gain is almost always 0.7 (-3 dB) -*/ -static void surround_to_stereo(short **output, short *input, int channels, int samples) -{ - int i; - short l, r; - - for (i = 0; i < samples; i++) { - int fl,fr,c,rl,rr; - fl = input[0]; - fr = input[1]; - c = input[2]; - // lfe = input[3]; - rl = input[4]; - rr = input[5]; - - l = av_clip_int16(fl + (0.5 * rl) + (0.7 * c)); - r = av_clip_int16(fr + (0.5 * rr) + (0.7 * c)); - - /* output l & r. */ - *output[0]++ = l; - *output[1]++ = r; - - /* increment input. */ - input += channels; - } -} - -static void deinterleave(short **output, short *input, int channels, int samples) -{ - int i, j; - - for (i = 0; i < samples; i++) { - for (j = 0; j < channels; j++) { - *output[j]++ = *input++; - } - } -} - -static void interleave(short *output, short **input, int channels, int samples) -{ - int i, j; - - for (i = 0; i < samples; i++) { - for (j = 0; j < channels; j++) { - *output++ = *input[j]++; - } - } -} - -static void ac3_5p1_mux(short *output, short *input1, short *input2, int n) -{ - int i; - short l, r; - - for (i = 0; i < n; i++) { - l = *input1++; - r = *input2++; - *output++ = l; /* left */ - *output++ = (l / 2) + (r / 2); /* center */ - *output++ = r; /* right */ - *output++ = 0; /* left surround */ - *output++ = 0; /* right surroud */ - *output++ = 0; /* low freq */ - } -} - -#define SUPPORT_RESAMPLE(ch1, ch2, ch3, ch4, ch5, ch6, ch7, ch8) \ - ch8<<7 | ch7<<6 | ch6<<5 | ch5<<4 | ch4<<3 | ch3<<2 | ch2<<1 | ch1<<0 - -static const uint8_t supported_resampling[MAX_CHANNELS] = { - // output ch: 1 2 3 4 5 6 7 8 - SUPPORT_RESAMPLE(1, 1, 0, 0, 0, 0, 0, 0), // 1 input channel - SUPPORT_RESAMPLE(1, 1, 0, 0, 0, 1, 0, 0), // 2 input channels - SUPPORT_RESAMPLE(0, 0, 1, 0, 0, 0, 0, 0), // 3 input channels - SUPPORT_RESAMPLE(0, 0, 0, 1, 0, 0, 0, 0), // 4 input channels - SUPPORT_RESAMPLE(0, 0, 0, 0, 1, 0, 0, 0), // 5 input channels - SUPPORT_RESAMPLE(0, 1, 0, 0, 0, 1, 0, 0), // 6 input channels - SUPPORT_RESAMPLE(0, 0, 0, 0, 0, 0, 1, 0), // 7 input channels - SUPPORT_RESAMPLE(0, 0, 0, 0, 0, 0, 0, 1), // 8 input channels -}; - -ReSampleContext *av_audio_resample_init(int output_channels, int input_channels, - int output_rate, int input_rate, - enum AVSampleFormat sample_fmt_out, - enum AVSampleFormat sample_fmt_in, - int filter_length, int log2_phase_count, - int linear, double cutoff) -{ - ReSampleContext *s; - - if (input_channels > MAX_CHANNELS) { - av_log(NULL, AV_LOG_ERROR, - "Resampling with input channels greater than %d is unsupported.\n", - MAX_CHANNELS); - return NULL; - } - if (!(supported_resampling[input_channels-1] & (1<<(output_channels-1)))) { - int i; - av_log(NULL, AV_LOG_ERROR, "Unsupported audio resampling. Allowed " - "output channels for %d input channel%s", input_channels, - input_channels > 1 ? "s:" : ":"); - for (i = 0; i < MAX_CHANNELS; i++) - if (supported_resampling[input_channels-1] & (1<ratio = (float)output_rate / (float)input_rate; - - s->input_channels = input_channels; - s->output_channels = output_channels; - - s->filter_channels = s->input_channels; - if (s->output_channels < s->filter_channels) - s->filter_channels = s->output_channels; - - s->sample_fmt[0] = sample_fmt_in; - s->sample_fmt[1] = sample_fmt_out; - s->sample_size[0] = av_get_bytes_per_sample(s->sample_fmt[0]); - s->sample_size[1] = av_get_bytes_per_sample(s->sample_fmt[1]); - - if (s->sample_fmt[0] != AV_SAMPLE_FMT_S16) { - if (!(s->convert_ctx[0] = av_audio_convert_alloc(AV_SAMPLE_FMT_S16, 1, - s->sample_fmt[0], 1, NULL, 0))) { - av_log(s, AV_LOG_ERROR, - "Cannot convert %s sample format to s16 sample format\n", - av_get_sample_fmt_name(s->sample_fmt[0])); - av_free(s); - return NULL; - } - } - - if (s->sample_fmt[1] != AV_SAMPLE_FMT_S16) { - if (!(s->convert_ctx[1] = av_audio_convert_alloc(s->sample_fmt[1], 1, - AV_SAMPLE_FMT_S16, 1, NULL, 0))) { - av_log(s, AV_LOG_ERROR, - "Cannot convert s16 sample format to %s sample format\n", - av_get_sample_fmt_name(s->sample_fmt[1])); - av_audio_convert_free(s->convert_ctx[0]); - av_free(s); - return NULL; - } - } - - s->resample_context = av_resample_init(output_rate, input_rate, - filter_length, log2_phase_count, - linear, cutoff); - - *(const AVClass**)s->resample_context = &audioresample_context_class; - - return s; -} - -/* resample audio. 'nb_samples' is the number of input samples */ -/* XXX: optimize it ! */ -int audio_resample(ReSampleContext *s, short *output, short *input, int nb_samples) -{ - int i, nb_samples1; - short *bufin[MAX_CHANNELS]; - short *bufout[MAX_CHANNELS]; - short *buftmp2[MAX_CHANNELS], *buftmp3[MAX_CHANNELS]; - short *output_bak = NULL; - int lenout; - - if (s->sample_fmt[0] != AV_SAMPLE_FMT_S16) { - int istride[1] = { s->sample_size[0] }; - int ostride[1] = { 2 }; - const void *ibuf[1] = { input }; - void *obuf[1]; - unsigned input_size = nb_samples * s->input_channels * 2; - - if (!s->buffer_size[0] || s->buffer_size[0] < input_size) { - av_free(s->buffer[0]); - s->buffer_size[0] = input_size; - s->buffer[0] = av_malloc(s->buffer_size[0]); - if (!s->buffer[0]) { - av_log(s->resample_context, AV_LOG_ERROR, "Could not allocate buffer\n"); - return 0; - } - } - - obuf[0] = s->buffer[0]; - - if (av_audio_convert(s->convert_ctx[0], obuf, ostride, - ibuf, istride, nb_samples * s->input_channels) < 0) { - av_log(s->resample_context, AV_LOG_ERROR, - "Audio sample format conversion failed\n"); - return 0; - } - - input = s->buffer[0]; - } - - lenout= 2*s->output_channels*nb_samples * s->ratio + 16; - - if (s->sample_fmt[1] != AV_SAMPLE_FMT_S16) { - int out_size = lenout * av_get_bytes_per_sample(s->sample_fmt[1]) * - s->output_channels; - output_bak = output; - - if (!s->buffer_size[1] || s->buffer_size[1] < out_size) { - av_free(s->buffer[1]); - s->buffer_size[1] = out_size; - s->buffer[1] = av_malloc(s->buffer_size[1]); - if (!s->buffer[1]) { - av_log(s->resample_context, AV_LOG_ERROR, "Could not allocate buffer\n"); - return 0; - } - } - - output = s->buffer[1]; - } - - /* XXX: move those malloc to resample init code */ - for (i = 0; i < s->filter_channels; i++) { - bufin[i] = av_malloc_array((nb_samples + s->temp_len), sizeof(short)); - bufout[i] = av_malloc_array(lenout, sizeof(short)); - - if (!bufin[i] || !bufout[i]) { - av_log(s->resample_context, AV_LOG_ERROR, "Could not allocate buffer\n"); - nb_samples1 = 0; - goto fail; - } - - memcpy(bufin[i], s->temp[i], s->temp_len * sizeof(short)); - buftmp2[i] = bufin[i] + s->temp_len; - } - - if (s->input_channels == 2 && s->output_channels == 1) { - buftmp3[0] = output; - stereo_to_mono(buftmp2[0], input, nb_samples); - } else if (s->output_channels >= 2 && s->input_channels == 1) { - buftmp3[0] = bufout[0]; - memcpy(buftmp2[0], input, nb_samples * sizeof(short)); - } else if (s->input_channels == 6 && s->output_channels ==2) { - buftmp3[0] = bufout[0]; - buftmp3[1] = bufout[1]; - surround_to_stereo(buftmp2, input, s->input_channels, nb_samples); - } else if (s->output_channels >= s->input_channels && s->input_channels >= 2) { - for (i = 0; i < s->input_channels; i++) { - buftmp3[i] = bufout[i]; - } - deinterleave(buftmp2, input, s->input_channels, nb_samples); - } else { - buftmp3[0] = output; - memcpy(buftmp2[0], input, nb_samples * sizeof(short)); - } - - nb_samples += s->temp_len; - - /* resample each channel */ - nb_samples1 = 0; /* avoid warning */ - for (i = 0; i < s->filter_channels; i++) { - int consumed; - int is_last = i + 1 == s->filter_channels; - - nb_samples1 = av_resample(s->resample_context, buftmp3[i], bufin[i], - &consumed, nb_samples, lenout, is_last); - s->temp_len = nb_samples - consumed; - s->temp[i] = av_realloc_array(s->temp[i], s->temp_len, sizeof(short)); - memcpy(s->temp[i], bufin[i] + consumed, s->temp_len * sizeof(short)); - } - - if (s->output_channels == 2 && s->input_channels == 1) { - mono_to_stereo(output, buftmp3[0], nb_samples1); - } else if (s->output_channels == 6 && s->input_channels == 2) { - ac3_5p1_mux(output, buftmp3[0], buftmp3[1], nb_samples1); - } else if ((s->output_channels == s->input_channels && s->input_channels >= 2) || - (s->output_channels == 2 && s->input_channels == 6)) { - interleave(output, buftmp3, s->output_channels, nb_samples1); - } - - if (s->sample_fmt[1] != AV_SAMPLE_FMT_S16) { - int istride[1] = { 2 }; - int ostride[1] = { s->sample_size[1] }; - const void *ibuf[1] = { output }; - void *obuf[1] = { output_bak }; - - if (av_audio_convert(s->convert_ctx[1], obuf, ostride, - ibuf, istride, nb_samples1 * s->output_channels) < 0) { - av_log(s->resample_context, AV_LOG_ERROR, - "Audio sample format conversion failed\n"); - return 0; - } - } - -fail: - for (i = 0; i < s->filter_channels; i++) { - av_free(bufin[i]); - av_free(bufout[i]); - } - - return nb_samples1; -} - -void audio_resample_close(ReSampleContext *s) -{ - int i; - av_resample_close(s->resample_context); - for (i = 0; i < s->filter_channels; i++) - av_freep(&s->temp[i]); - av_freep(&s->buffer[0]); - av_freep(&s->buffer[1]); - av_audio_convert_free(s->convert_ctx[0]); - av_audio_convert_free(s->convert_ctx[1]); - av_free(s); -} - -FF_ENABLE_DEPRECATION_WARNINGS -#endif diff --git a/libavcodec/resample2.c b/libavcodec/resample2.c deleted file mode 100644 index 56ae9f72294ba..0000000000000 --- a/libavcodec/resample2.c +++ /dev/null @@ -1,319 +0,0 @@ -/* - * audio resampling - * Copyright (c) 2004 Michael Niedermayer - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file - * audio resampling - * @author Michael Niedermayer - */ - -#include "libavutil/avassert.h" -#include "avcodec.h" -#include "libavutil/common.h" - -#if FF_API_AVCODEC_RESAMPLE - -#ifndef CONFIG_RESAMPLE_HP -#define FILTER_SHIFT 15 - -typedef int16_t FELEM; -typedef int32_t FELEM2; -typedef int64_t FELEML; -#define FELEM_MAX INT16_MAX -#define FELEM_MIN INT16_MIN -#define WINDOW_TYPE 9 -#elif !defined(CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE) -#define FILTER_SHIFT 30 - -#define FELEM int32_t -#define FELEM2 int64_t -#define FELEML int64_t -#define FELEM_MAX INT32_MAX -#define FELEM_MIN INT32_MIN -#define WINDOW_TYPE 12 -#else -#define FILTER_SHIFT 0 - -typedef double FELEM; -typedef double FELEM2; -typedef double FELEML; -#define WINDOW_TYPE 24 -#endif - - -typedef struct AVResampleContext{ - const AVClass *av_class; - FELEM *filter_bank; - int filter_length; - int ideal_dst_incr; - int dst_incr; - int index; - int frac; - int src_incr; - int compensation_distance; - int phase_shift; - int phase_mask; - int linear; -}AVResampleContext; - -/** - * 0th order modified bessel function of the first kind. - */ -static double bessel(double x){ - double v=1; - double lastv=0; - double t=1; - int i; - - x= x*x/4; - for(i=1; v != lastv; i++){ - lastv=v; - t *= x/(i*i); - v += t; - } - return v; -} - -/** - * Build a polyphase filterbank. - * @param factor resampling factor - * @param scale wanted sum of coefficients for each filter - * @param type 0->cubic, 1->blackman nuttall windowed sinc, 2..16->kaiser windowed sinc beta=2..16 - * @return 0 on success, negative on error - */ -static int build_filter(FELEM *filter, double factor, int tap_count, int phase_count, int scale, int type){ - int ph, i; - double x, y, w; - double *tab = av_malloc_array(tap_count, sizeof(*tab)); - const int center= (tap_count-1)/2; - - if (!tab) - return AVERROR(ENOMEM); - - /* if upsampling, only need to interpolate, no filter */ - if (factor > 1.0) - factor = 1.0; - - for(ph=0;phphase_shift= phase_shift; - c->phase_mask= phase_count-1; - c->linear= linear; - - c->filter_length= FFMAX((int)ceil(filter_size/factor), 1); - c->filter_bank= av_mallocz_array(c->filter_length, (phase_count+1)*sizeof(FELEM)); - if (!c->filter_bank) - goto error; - if (build_filter(c->filter_bank, factor, c->filter_length, phase_count, 1<filter_bank[c->filter_length*phase_count+1], c->filter_bank, (c->filter_length-1)*sizeof(FELEM)); - c->filter_bank[c->filter_length*phase_count]= c->filter_bank[c->filter_length - 1]; - - if(!av_reduce(&c->src_incr, &c->dst_incr, out_rate, in_rate * (int64_t)phase_count, INT32_MAX/2)) - goto error; - c->ideal_dst_incr= c->dst_incr; - - c->index= -phase_count*((c->filter_length-1)/2); - - return c; -error: - av_free(c->filter_bank); - av_free(c); - return NULL; -} - -void av_resample_close(AVResampleContext *c){ - av_freep(&c->filter_bank); - av_freep(&c); -} - -void av_resample_compensate(AVResampleContext *c, int sample_delta, int compensation_distance){ -// sample_delta += (c->ideal_dst_incr - c->dst_incr)*(int64_t)c->compensation_distance / c->ideal_dst_incr; - c->compensation_distance= compensation_distance; - c->dst_incr = c->ideal_dst_incr - c->ideal_dst_incr * (int64_t)sample_delta / compensation_distance; -} - -int av_resample(AVResampleContext *c, short *dst, short *src, int *consumed, int src_size, int dst_size, int update_ctx){ - int dst_index, i; - int index= c->index; - int frac= c->frac; - int dst_incr_frac= c->dst_incr % c->src_incr; - int dst_incr= c->dst_incr / c->src_incr; - int compensation_distance= c->compensation_distance; - - if(compensation_distance == 0 && c->filter_length == 1 && c->phase_shift==0){ - int64_t index2= ((int64_t)index)<<32; - int64_t incr= (1LL<<32) * c->dst_incr / c->src_incr; - dst_size= FFMIN(dst_size, (src_size-1-index) * (int64_t)c->src_incr / c->dst_incr); - - for(dst_index=0; dst_index < dst_size; dst_index++){ - dst[dst_index] = src[index2>>32]; - index2 += incr; - } - index += dst_index * dst_incr; - index += (frac + dst_index * (int64_t)dst_incr_frac) / c->src_incr; - frac = (frac + dst_index * (int64_t)dst_incr_frac) % c->src_incr; - }else{ - for(dst_index=0; dst_index < dst_size; dst_index++){ - FELEM *filter= c->filter_bank + c->filter_length*(index & c->phase_mask); - int sample_index= index >> c->phase_shift; - FELEM2 val=0; - - if(sample_index < 0){ - for(i=0; ifilter_length; i++) - val += src[FFABS(sample_index + i) % src_size] * filter[i]; - }else if(sample_index + c->filter_length > src_size){ - break; - }else if(c->linear){ - FELEM2 v2=0; - for(i=0; ifilter_length; i++){ - val += src[sample_index + i] * (FELEM2)filter[i]; - v2 += src[sample_index + i] * (FELEM2)filter[i + c->filter_length]; - } - val+=(v2-val)*(FELEML)frac / c->src_incr; - }else{ - for(i=0; ifilter_length; i++){ - val += src[sample_index + i] * (FELEM2)filter[i]; - } - } - -#ifdef CONFIG_RESAMPLE_AUDIOPHILE_KIDDY_MODE - dst[dst_index] = av_clip_int16(lrintf(val)); -#else - val = (val + (1<<(FILTER_SHIFT-1)))>>FILTER_SHIFT; - dst[dst_index] = (unsigned)(val + 32768) > 65535 ? (val>>31) ^ 32767 : val; -#endif - - frac += dst_incr_frac; - index += dst_incr; - if(frac >= c->src_incr){ - frac -= c->src_incr; - index++; - } - - if(dst_index + 1 == compensation_distance){ - compensation_distance= 0; - dst_incr_frac= c->ideal_dst_incr % c->src_incr; - dst_incr= c->ideal_dst_incr / c->src_incr; - } - } - } - *consumed= FFMAX(index, 0) >> c->phase_shift; - if(index>=0) index &= c->phase_mask; - - if(compensation_distance){ - compensation_distance -= dst_index; - av_assert2(compensation_distance > 0); - } - if(update_ctx){ - c->frac= frac; - c->index= index; - c->dst_incr= dst_incr_frac + c->src_incr*dst_incr; - c->compensation_distance= compensation_distance; - } - - return dst_index; -} - -#endif diff --git a/libavcodec/rkmppdec.c b/libavcodec/rkmppdec.c index bdf4dc4208c3c..143d05bd51753 100644 --- a/libavcodec/rkmppdec.c +++ b/libavcodec/rkmppdec.c @@ -28,6 +28,7 @@ #include "avcodec.h" #include "decode.h" +#include "hwaccel.h" #include "internal.h" #include "libavutil/buffer.h" #include "libavutil/common.h" @@ -39,13 +40,13 @@ #define RECEIVE_FRAME_TIMEOUT 100 #define FRAMEGROUP_MAX_FRAMES 16 +#define INPUT_MAX_PACKETS 4 typedef struct { MppCtx ctx; MppApi *mpi; MppBufferGroup frame_group; - char first_frame; char first_packet; char eos_reached; @@ -327,28 +328,14 @@ static int rkmpp_retrieve_frame(AVCodecContext *avctx, AVFrame *frame) MppBuffer buffer = NULL; AVDRMFrameDescriptor *desc = NULL; AVDRMLayerDescriptor *layer = NULL; - int retrycount = 0; int mode; MppFrameFormat mppformat; uint32_t drmformat; - // on start of decoding, MPP can return -1, which is supposed to be expected - // this is due to some internal MPP init which is not completed, that will - // only happen in the first few frames queries, but should not be interpreted - // as an error, Therefore we need to retry a couple times when we get -1 - // in order to let it time to complete it's init, then we sleep a bit between retries. -retry_get_frame: ret = decoder->mpi->decode_get_frame(decoder->ctx, &mppframe); - if (ret != MPP_OK && ret != MPP_ERR_TIMEOUT && !decoder->first_frame) { - if (retrycount < 5) { - av_log(avctx, AV_LOG_DEBUG, "Failed to get a frame, retrying (code = %d, retrycount = %d)\n", ret, retrycount); - usleep(10000); - retrycount++; - goto retry_get_frame; - } else { - av_log(avctx, AV_LOG_ERROR, "Failed to get a frame from MPP (code = %d)\n", ret); - goto fail; - } + if (ret != MPP_OK && ret != MPP_ERR_TIMEOUT) { + av_log(avctx, AV_LOG_ERROR, "Failed to get a frame from MPP (code = %d)\n", ret); + goto fail; } if (mppframe) { @@ -364,7 +351,6 @@ static int rkmpp_retrieve_frame(AVCodecContext *avctx, AVFrame *frame) avctx->height = mpp_frame_get_height(mppframe); decoder->mpi->control(decoder->ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL); - decoder->first_frame = 1; av_buffer_unref(&decoder->frames_ref); @@ -478,7 +464,6 @@ static int rkmpp_retrieve_frame(AVCodecContext *avctx, AVFrame *frame) goto fail; } - decoder->first_frame = 0; return 0; } else { av_log(avctx, AV_LOG_ERROR, "Failed to retrieve the frame buffer, frame is dropped (code = %d)\n", ret); @@ -514,16 +499,17 @@ static int rkmpp_receive_frame(AVCodecContext *avctx, AVFrame *frame) RKMPPDecoder *decoder = (RKMPPDecoder *)rk_context->decoder_ref->data; int ret = MPP_NOK; AVPacket pkt = {0}; - RK_S32 freeslots; + RK_S32 usedslots, freeslots; if (!decoder->eos_reached) { // we get the available slots in decoder - ret = decoder->mpi->control(decoder->ctx, MPP_DEC_GET_FREE_PACKET_SLOT_COUNT, &freeslots); + ret = decoder->mpi->control(decoder->ctx, MPP_DEC_GET_STREAM_COUNT, &usedslots); if (ret != MPP_OK) { - av_log(avctx, AV_LOG_ERROR, "Failed to get decoder free slots (code = %d).\n", ret); + av_log(avctx, AV_LOG_ERROR, "Failed to get decoder used slots (code = %d).\n", ret); return ret; } + freeslots = INPUT_MAX_PACKETS - usedslots; if (freeslots > 0) { ret = ff_decode_get_packet(avctx, &pkt); if (ret < 0 && ret != AVERROR_EOF) { @@ -540,7 +526,7 @@ static int rkmpp_receive_frame(AVCodecContext *avctx, AVFrame *frame) } // make sure we keep decoder full - if (freeslots > 1 && decoder->first_frame) + if (freeslots > 1) return AVERROR(EAGAIN); } @@ -557,12 +543,15 @@ static void rkmpp_flush(AVCodecContext *avctx) ret = decoder->mpi->reset(decoder->ctx); if (ret == MPP_OK) { - decoder->first_frame = 1; decoder->first_packet = 1; } else av_log(avctx, AV_LOG_ERROR, "Failed to reset MPI (code = %d)\n", ret); } +static const AVCodecHWConfigInternal *rkmpp_hw_configs[] = { + HW_CONFIG_INTERNAL(DRM_PRIME), + NULL +}; #define RKMPP_DEC_CLASS(NAME) \ static const AVClass rkmpp_##NAME##_dec_class = { \ @@ -583,11 +572,12 @@ static void rkmpp_flush(AVCodecContext *avctx) .receive_frame = rkmpp_receive_frame, \ .flush = rkmpp_flush, \ .priv_class = &rkmpp_##NAME##_dec_class, \ - .capabilities = AV_CODEC_CAP_DELAY, \ - .caps_internal = AV_CODEC_CAP_AVOID_PROBING, \ + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \ .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_DRM_PRIME, \ AV_PIX_FMT_NONE}, \ + .hw_configs = rkmpp_hw_configs, \ .bsfs = BSFS, \ + .wrapper_name = "rkmpp", \ }; RKMPP_DEC(h264, AV_CODEC_ID_H264, "h264_mp4toannexb") diff --git a/libavcodec/rscc.c b/libavcodec/rscc.c index f270cd535113c..dae5e84634520 100644 --- a/libavcodec/rscc.c +++ b/libavcodec/rscc.c @@ -157,6 +157,12 @@ static int rscc_decode_frame(AVCodecContext *avctx, void *data, /* Read number of tiles, and allocate the array */ tiles_nb = bytestream2_get_le16(gbc); + + if (tiles_nb == 0) { + av_log(avctx, AV_LOG_DEBUG, "no tiles\n"); + return avpkt->size; + } + av_fast_malloc(&ctx->tiles, &ctx->tiles_size, tiles_nb * sizeof(*ctx->tiles)); if (!ctx->tiles) { diff --git a/libavcodec/rv34.c b/libavcodec/rv34.c index f1495fb5a8f8e..d171e6e1bdef2 100644 --- a/libavcodec/rv34.c +++ b/libavcodec/rv34.c @@ -1585,7 +1585,7 @@ int ff_rv34_decode_update_thread_context(AVCodecContext *dst, const AVCodecConte // Do no call ff_mpeg_update_thread_context on a partially initialized // decoder context. - if (!s1->linesize) + if (!s1->context_initialized) return 0; return ff_mpeg_update_thread_context(dst, src); @@ -1733,6 +1733,8 @@ int ff_rv34_decode_frame(AVCodecContext *avctx, if ((err = rv34_decoder_realloc(r)) < 0) return err; } + if (faulty_b) + return AVERROR_INVALIDDATA; s->pict_type = si.type ? si.type : AV_PICTURE_TYPE_I; if (ff_mpv_frame_start(s, s->avctx) < 0) return -1; @@ -1786,8 +1788,6 @@ int ff_rv34_decode_frame(AVCodecContext *avctx, "multithreading mode (start MB is %d).\n", si.start); return AVERROR_INVALIDDATA; } - if (faulty_b) - return AVERROR_INVALIDDATA; for(i = 0; i < slice_count; i++){ int offset = get_slice_offset(avctx, slices_hdr, i , slice_count, buf_size); diff --git a/libavcodec/s302m.c b/libavcodec/s302m.c index 4350d97f0a407..584b58e28e323 100644 --- a/libavcodec/s302m.c +++ b/libavcodec/s302m.c @@ -212,10 +212,10 @@ static const AVOption s302m_options[] = { }; static const AVClass s302m_class = { - "SMPTE 302M Decoder", - av_default_item_name, - s302m_options, - LIBAVUTIL_VERSION_INT, + .class_name = "SMPTE 302M Decoder", + .item_name = av_default_item_name, + .option = s302m_options, + .version = LIBAVUTIL_VERSION_INT, }; AVCodec ff_s302m_decoder = { diff --git a/libavcodec/samidec.c b/libavcodec/samidec.c index 2620424750859..e32f238c629ca 100644 --- a/libavcodec/samidec.c +++ b/libavcodec/samidec.c @@ -48,6 +48,9 @@ static int sami_paragraph_to_ass(AVCodecContext *avctx, const char *src) AVBPrint *dst_content = &sami->encoded_content; AVBPrint *dst_source = &sami->encoded_source; + if (!dupsrc) + return AVERROR(ENOMEM); + av_bprint_clear(&sami->encoded_content); av_bprint_clear(&sami->content); av_bprint_clear(&sami->encoded_source); @@ -135,9 +138,12 @@ static int sami_decode_frame(AVCodecContext *avctx, const char *ptr = avpkt->data; SAMIContext *sami = avctx->priv_data; - if (ptr && avpkt->size > 0 && !sami_paragraph_to_ass(avctx, ptr)) { + if (ptr && avpkt->size > 0) { + int ret = sami_paragraph_to_ass(avctx, ptr); + if (ret < 0) + return ret; // TODO: pass escaped sami->encoded_source.str as source - int ret = ff_ass_add_rect(sub, sami->full.str, sami->readorder++, 0, NULL, NULL); + ret = ff_ass_add_rect(sub, sami->full.str, sami->readorder++, 0, NULL, NULL); if (ret < 0) return ret; } diff --git a/libavcodec/sbc.c b/libavcodec/sbc.c new file mode 100644 index 0000000000000..b43b66e3f5192 --- /dev/null +++ b/libavcodec/sbc.c @@ -0,0 +1,271 @@ +/* + * Bluetooth low-complexity, subband codec (SBC) + * + * Copyright (C) 2017 Aurelien Jacobs + * Copyright (C) 2012-2013 Intel Corporation + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2008 Brad Midgley + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * SBC common functions for the encoder and decoder + */ + +#include "avcodec.h" +#include "sbc.h" + +/* A2DP specification: Appendix B, page 69 */ +static const int sbc_offset4[4][4] = { + { -1, 0, 0, 0 }, + { -2, 0, 0, 1 }, + { -2, 0, 0, 1 }, + { -2, 0, 0, 1 } +}; + +/* A2DP specification: Appendix B, page 69 */ +static const int sbc_offset8[4][8] = { + { -2, 0, 0, 0, 0, 0, 0, 1 }, + { -3, 0, 0, 0, 0, 0, 1, 2 }, + { -4, 0, 0, 0, 0, 0, 1, 2 }, + { -4, 0, 0, 0, 0, 0, 1, 2 } +}; + +/* + * Calculates the CRC-8 of the first len bits in data + */ +uint8_t ff_sbc_crc8(const AVCRC *ctx, const uint8_t *data, size_t len) +{ + size_t byte_length = len >> 3; + int bit_length = len & 7; + uint8_t crc; + + crc = av_crc(ctx, 0x0F, data, byte_length); + + if (bit_length) { + uint8_t bits = data[byte_length]; + while (bit_length--) { + int8_t mask = bits ^ crc; + crc = (crc << 1) ^ ((mask >> 7) & 0x1D); + bits <<= 1; + } + } + + return crc; +} + +/* + * Code straight from the spec to calculate the bits array + * Takes a pointer to the frame in question and a pointer to the bits array + */ +void ff_sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8]) +{ + int subbands = frame->subbands; + uint8_t sf = frame->frequency; + + if (frame->mode == MONO || frame->mode == DUAL_CHANNEL) { + int bitneed[2][8], loudness, max_bitneed, bitcount, slicecount, bitslice; + int ch, sb; + + for (ch = 0; ch < frame->channels; ch++) { + max_bitneed = 0; + if (frame->allocation == SNR) { + for (sb = 0; sb < subbands; sb++) { + bitneed[ch][sb] = frame->scale_factor[ch][sb]; + if (bitneed[ch][sb] > max_bitneed) + max_bitneed = bitneed[ch][sb]; + } + } else { + for (sb = 0; sb < subbands; sb++) { + if (frame->scale_factor[ch][sb] == 0) + bitneed[ch][sb] = -5; + else { + if (subbands == 4) + loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb]; + else + loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb]; + if (loudness > 0) + bitneed[ch][sb] = loudness / 2; + else + bitneed[ch][sb] = loudness; + } + if (bitneed[ch][sb] > max_bitneed) + max_bitneed = bitneed[ch][sb]; + } + } + + bitcount = 0; + slicecount = 0; + bitslice = max_bitneed + 1; + do { + bitslice--; + bitcount += slicecount; + slicecount = 0; + for (sb = 0; sb < subbands; sb++) { + if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16)) + slicecount++; + else if (bitneed[ch][sb] == bitslice + 1) + slicecount += 2; + } + } while (bitcount + slicecount < frame->bitpool); + + if (bitcount + slicecount == frame->bitpool) { + bitcount += slicecount; + bitslice--; + } + + for (sb = 0; sb < subbands; sb++) { + if (bitneed[ch][sb] < bitslice + 2) + bits[ch][sb] = 0; + else { + bits[ch][sb] = bitneed[ch][sb] - bitslice; + if (bits[ch][sb] > 16) + bits[ch][sb] = 16; + } + } + + for (sb = 0; bitcount < frame->bitpool && + sb < subbands; sb++) { + if ((bits[ch][sb] >= 2) && (bits[ch][sb] < 16)) { + bits[ch][sb]++; + bitcount++; + } else if ((bitneed[ch][sb] == bitslice + 1) && (frame->bitpool > bitcount + 1)) { + bits[ch][sb] = 2; + bitcount += 2; + } + } + + for (sb = 0; bitcount < frame->bitpool && + sb < subbands; sb++) { + if (bits[ch][sb] < 16) { + bits[ch][sb]++; + bitcount++; + } + } + + } + + } else if (frame->mode == STEREO || frame->mode == JOINT_STEREO) { + int bitneed[2][8], loudness, max_bitneed, bitcount, slicecount, bitslice; + int ch, sb; + + max_bitneed = 0; + if (frame->allocation == SNR) { + for (ch = 0; ch < 2; ch++) { + for (sb = 0; sb < subbands; sb++) { + bitneed[ch][sb] = frame->scale_factor[ch][sb]; + if (bitneed[ch][sb] > max_bitneed) + max_bitneed = bitneed[ch][sb]; + } + } + } else { + for (ch = 0; ch < 2; ch++) { + for (sb = 0; sb < subbands; sb++) { + if (frame->scale_factor[ch][sb] == 0) + bitneed[ch][sb] = -5; + else { + if (subbands == 4) + loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb]; + else + loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb]; + if (loudness > 0) + bitneed[ch][sb] = loudness / 2; + else + bitneed[ch][sb] = loudness; + } + if (bitneed[ch][sb] > max_bitneed) + max_bitneed = bitneed[ch][sb]; + } + } + } + + bitcount = 0; + slicecount = 0; + bitslice = max_bitneed + 1; + do { + bitslice--; + bitcount += slicecount; + slicecount = 0; + for (ch = 0; ch < 2; ch++) { + for (sb = 0; sb < subbands; sb++) { + if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16)) + slicecount++; + else if (bitneed[ch][sb] == bitslice + 1) + slicecount += 2; + } + } + } while (bitcount + slicecount < frame->bitpool); + + if (bitcount + slicecount == frame->bitpool) { + bitcount += slicecount; + bitslice--; + } + + for (ch = 0; ch < 2; ch++) { + for (sb = 0; sb < subbands; sb++) { + if (bitneed[ch][sb] < bitslice + 2) { + bits[ch][sb] = 0; + } else { + bits[ch][sb] = bitneed[ch][sb] - bitslice; + if (bits[ch][sb] > 16) + bits[ch][sb] = 16; + } + } + } + + ch = 0; + sb = 0; + while (bitcount < frame->bitpool) { + if ((bits[ch][sb] >= 2) && (bits[ch][sb] < 16)) { + bits[ch][sb]++; + bitcount++; + } else if ((bitneed[ch][sb] == bitslice + 1) && (frame->bitpool > bitcount + 1)) { + bits[ch][sb] = 2; + bitcount += 2; + } + if (ch == 1) { + ch = 0; + sb++; + if (sb >= subbands) + break; + } else + ch = 1; + } + + ch = 0; + sb = 0; + while (bitcount < frame->bitpool) { + if (bits[ch][sb] < 16) { + bits[ch][sb]++; + bitcount++; + } + if (ch == 1) { + ch = 0; + sb++; + if (sb >= subbands) + break; + } else + ch = 1; + } + + } + +} diff --git a/libavcodec/sbc.h b/libavcodec/sbc.h new file mode 100644 index 0000000000000..de9c8d9aed352 --- /dev/null +++ b/libavcodec/sbc.h @@ -0,0 +1,118 @@ +/* + * Bluetooth low-complexity, subband codec (SBC) + * + * Copyright (C) 2017 Aurelien Jacobs + * Copyright (C) 2012-2014 Intel Corporation + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2006 Brad Midgley + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * SBC common definitions for the encoder and decoder + */ + +#ifndef AVCODEC_SBC_H +#define AVCODEC_SBC_H + +#include "avcodec.h" +#include "libavutil/crc.h" + +#define MSBC_BLOCKS 15 + +/* sampling frequency */ +#define SBC_FREQ_16000 0x00 +#define SBC_FREQ_32000 0x01 +#define SBC_FREQ_44100 0x02 +#define SBC_FREQ_48000 0x03 + +/* blocks */ +#define SBC_BLK_4 0x00 +#define SBC_BLK_8 0x01 +#define SBC_BLK_12 0x02 +#define SBC_BLK_16 0x03 + +/* channel mode */ +#define SBC_MODE_MONO 0x00 +#define SBC_MODE_DUAL_CHANNEL 0x01 +#define SBC_MODE_STEREO 0x02 +#define SBC_MODE_JOINT_STEREO 0x03 + +/* allocation method */ +#define SBC_AM_LOUDNESS 0x00 +#define SBC_AM_SNR 0x01 + +/* subbands */ +#define SBC_SB_4 0x00 +#define SBC_SB_8 0x01 + +/* synchronisation words */ +#define SBC_SYNCWORD 0x9C +#define MSBC_SYNCWORD 0xAD + +/* extra bits of precision for the synthesis filter input data */ +#define SBCDEC_FIXED_EXTRA_BITS 2 + +/* + * Enforce 16 byte alignment for the data, which is supposed to be used + * with SIMD optimized code. + */ +#define SBC_ALIGN 16 + +/* This structure contains an unpacked SBC frame. + Yes, there is probably quite some unused space herein */ +struct sbc_frame { + uint8_t frequency; + uint8_t blocks; + enum { + MONO = SBC_MODE_MONO, + DUAL_CHANNEL = SBC_MODE_DUAL_CHANNEL, + STEREO = SBC_MODE_STEREO, + JOINT_STEREO = SBC_MODE_JOINT_STEREO + } mode; + uint8_t channels; + enum { + LOUDNESS = SBC_AM_LOUDNESS, + SNR = SBC_AM_SNR + } allocation; + uint8_t subbands; + uint8_t bitpool; + uint16_t codesize; + + /* bit number x set means joint stereo has been used in subband x */ + uint8_t joint; + + /* only the lower 4 bits of every element are to be used */ + DECLARE_ALIGNED(SBC_ALIGN, uint32_t, scale_factor)[2][8]; + + /* raw integer subband samples in the frame */ + DECLARE_ALIGNED(SBC_ALIGN, int32_t, sb_sample_f)[16][2][8]; + + /* modified subband samples */ + DECLARE_ALIGNED(SBC_ALIGN, int32_t, sb_sample)[16][2][8]; + + const AVCRC *crc_ctx; +}; + +uint8_t ff_sbc_crc8(const AVCRC *crc_ctx, const uint8_t *data, size_t len); +void ff_sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8]); + +#endif /* AVCODEC_SBC_H */ diff --git a/libavcodec/sbc_parser.c b/libavcodec/sbc_parser.c new file mode 100644 index 0000000000000..f56564147a43e --- /dev/null +++ b/libavcodec/sbc_parser.c @@ -0,0 +1,122 @@ +/* + * SBC parser + * + * Copyright (C) 2017 Aurelien Jacobs + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "sbc.h" +#include "parser.h" + +typedef struct SBCParseContext { + ParseContext pc; + uint8_t header[3]; + int header_size; + int buffered_size; +} SBCParseContext; + +static int sbc_parse_header(AVCodecParserContext *s, AVCodecContext *avctx, + const uint8_t *data, size_t len) +{ + static const int sample_rates[4] = { 16000, 32000, 44100, 48000 }; + int sr, blocks, mode, subbands, bitpool, channels, joint; + int length; + + if (len < 3) + return -1; + + if (data[0] == MSBC_SYNCWORD && data[1] == 0 && data[2] == 0) { + avctx->channels = 1; + avctx->sample_fmt = AV_SAMPLE_FMT_S16; + avctx->sample_rate = 16000; + avctx->frame_size = 120; + s->duration = avctx->frame_size; + return 57; + } + + if (data[0] != SBC_SYNCWORD) + return -2; + + sr = (data[1] >> 6) & 0x03; + blocks = (((data[1] >> 4) & 0x03) + 1) << 2; + mode = (data[1] >> 2) & 0x03; + subbands = (((data[1] >> 0) & 0x01) + 1) << 2; + bitpool = data[2]; + + channels = mode == SBC_MODE_MONO ? 1 : 2; + joint = mode == SBC_MODE_JOINT_STEREO; + + length = 4 + (subbands * channels) / 2 + + ((((mode == SBC_MODE_DUAL_CHANNEL) + 1) * blocks * bitpool + + (joint * subbands)) + 7) / 8; + + avctx->channels = channels; + avctx->sample_fmt = AV_SAMPLE_FMT_S16; + avctx->sample_rate = sample_rates[sr]; + avctx->frame_size = subbands * blocks; + s->duration = avctx->frame_size; + return length; +} + +static int sbc_parse(AVCodecParserContext *s, AVCodecContext *avctx, + const uint8_t **poutbuf, int *poutbuf_size, + const uint8_t *buf, int buf_size) +{ + SBCParseContext *pc = s->priv_data; + int next; + + if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) { + next = buf_size; + } else { + if (pc->header_size) { + memcpy(pc->header + pc->header_size, buf, + sizeof(pc->header) - pc->header_size); + next = sbc_parse_header(s, avctx, pc->header, sizeof(pc->header)) + - pc->buffered_size; + pc->header_size = 0; + } else { + next = sbc_parse_header(s, avctx, buf, buf_size); + if (next >= buf_size) + next = -1; + } + + if (next < 0) { + pc->header_size = FFMIN(sizeof(pc->header), buf_size); + memcpy(pc->header, buf, pc->header_size); + pc->buffered_size = buf_size; + next = END_NOT_FOUND; + } + + if (ff_combine_frame(&pc->pc, next, &buf, &buf_size) < 0) { + *poutbuf = NULL; + *poutbuf_size = 0; + return buf_size; + } + } + + *poutbuf = buf; + *poutbuf_size = buf_size; + return next; +} + +AVCodecParser ff_sbc_parser = { + .codec_ids = { AV_CODEC_ID_SBC }, + .priv_data_size = sizeof(SBCParseContext), + .parser_parse = sbc_parse, + .parser_close = ff_parse_close, +}; diff --git a/libavcodec/sbcdec.c b/libavcodec/sbcdec.c new file mode 100644 index 0000000000000..546b38c106860 --- /dev/null +++ b/libavcodec/sbcdec.c @@ -0,0 +1,379 @@ +/* + * Bluetooth low-complexity, subband codec (SBC) + * + * Copyright (C) 2017 Aurelien Jacobs + * Copyright (C) 2012-2013 Intel Corporation + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2008 Brad Midgley + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * SBC decoder implementation + */ + +#include +#include "avcodec.h" +#include "internal.h" +#include "libavutil/intreadwrite.h" +#include "sbc.h" +#include "sbcdec_data.h" + +struct sbc_decoder_state { + int32_t V[2][170]; + int offset[2][16]; +}; + +typedef struct SBCDecContext { + AVClass *class; + DECLARE_ALIGNED(SBC_ALIGN, struct sbc_frame, frame); + DECLARE_ALIGNED(SBC_ALIGN, struct sbc_decoder_state, dsp); +} SBCDecContext; + +/* + * Unpacks a SBC frame at the beginning of the stream in data, + * which has at most len bytes into frame. + * Returns the length in bytes of the packed frame, or a negative + * value on error. The error codes are: + * + * -1 Data stream too short + * -2 Sync byte incorrect + * -3 CRC8 incorrect + * -4 Bitpool value out of bounds + */ +static int sbc_unpack_frame(const uint8_t *data, struct sbc_frame *frame, + size_t len) +{ + unsigned int consumed; + /* Will copy the parts of the header that are relevant to crc + * calculation here */ + uint8_t crc_header[11] = { 0 }; + int crc_pos; + int32_t temp; + + uint32_t audio_sample; + int ch, sb, blk, bit; /* channel, subband, block and bit standard + counters */ + int bits[2][8]; /* bits distribution */ + uint32_t levels[2][8]; /* levels derived from that */ + + if (len < 4) + return -1; + + if (data[0] == MSBC_SYNCWORD) { + if (data[1] != 0) + return -2; + if (data[2] != 0) + return -2; + + frame->frequency = SBC_FREQ_16000; + frame->blocks = MSBC_BLOCKS; + frame->allocation = LOUDNESS; + frame->mode = MONO; + frame->channels = 1; + frame->subbands = 8; + frame->bitpool = 26; + } else if (data[0] == SBC_SYNCWORD) { + frame->frequency = (data[1] >> 6) & 0x03; + frame->blocks = 4 * ((data[1] >> 4) & 0x03) + 4; + frame->mode = (data[1] >> 2) & 0x03; + frame->channels = frame->mode == MONO ? 1 : 2; + frame->allocation = (data[1] >> 1) & 0x01; + frame->subbands = data[1] & 0x01 ? 8 : 4; + frame->bitpool = data[2]; + + if ((frame->mode == MONO || frame->mode == DUAL_CHANNEL) && + frame->bitpool > 16 * frame->subbands) + return -4; + + if ((frame->mode == STEREO || frame->mode == JOINT_STEREO) && + frame->bitpool > 32 * frame->subbands) + return -4; + } else + return -2; + + consumed = 32; + crc_header[0] = data[1]; + crc_header[1] = data[2]; + crc_pos = 16; + + if (frame->mode == JOINT_STEREO) { + if (len * 8 < consumed + frame->subbands) + return -1; + + frame->joint = 0x00; + for (sb = 0; sb < frame->subbands - 1; sb++) + frame->joint |= ((data[4] >> (7 - sb)) & 0x01) << sb; + if (frame->subbands == 4) + crc_header[crc_pos / 8] = data[4] & 0xf0; + else + crc_header[crc_pos / 8] = data[4]; + + consumed += frame->subbands; + crc_pos += frame->subbands; + } + + if (len * 8 < consumed + (4 * frame->subbands * frame->channels)) + return -1; + + for (ch = 0; ch < frame->channels; ch++) { + for (sb = 0; sb < frame->subbands; sb++) { + /* FIXME assert(consumed % 4 == 0); */ + frame->scale_factor[ch][sb] = + (data[consumed >> 3] >> (4 - (consumed & 0x7))) & 0x0F; + crc_header[crc_pos >> 3] |= + frame->scale_factor[ch][sb] << (4 - (crc_pos & 0x7)); + + consumed += 4; + crc_pos += 4; + } + } + + if (data[3] != ff_sbc_crc8(frame->crc_ctx, crc_header, crc_pos)) + return -3; + + ff_sbc_calculate_bits(frame, bits); + + for (ch = 0; ch < frame->channels; ch++) { + for (sb = 0; sb < frame->subbands; sb++) + levels[ch][sb] = (1 << bits[ch][sb]) - 1; + } + + for (blk = 0; blk < frame->blocks; blk++) { + for (ch = 0; ch < frame->channels; ch++) { + for (sb = 0; sb < frame->subbands; sb++) { + uint32_t shift; + + if (levels[ch][sb] == 0) { + frame->sb_sample[blk][ch][sb] = 0; + continue; + } + + shift = frame->scale_factor[ch][sb] + + 1 + SBCDEC_FIXED_EXTRA_BITS; + + audio_sample = 0; + for (bit = 0; bit < bits[ch][sb]; bit++) { + if (consumed > len * 8) + return -1; + + if ((data[consumed >> 3] >> (7 - (consumed & 0x7))) & 0x01) + audio_sample |= 1 << (bits[ch][sb] - bit - 1); + + consumed++; + } + + frame->sb_sample[blk][ch][sb] = (int32_t) + (((((uint64_t) audio_sample << 1) | 1) << shift) / + levels[ch][sb]) - (1 << shift); + } + } + } + + if (frame->mode == JOINT_STEREO) { + for (blk = 0; blk < frame->blocks; blk++) { + for (sb = 0; sb < frame->subbands; sb++) { + if (frame->joint & (0x01 << sb)) { + temp = frame->sb_sample[blk][0][sb] + + frame->sb_sample[blk][1][sb]; + frame->sb_sample[blk][1][sb] = + frame->sb_sample[blk][0][sb] - + frame->sb_sample[blk][1][sb]; + frame->sb_sample[blk][0][sb] = temp; + } + } + } + } + + if ((consumed & 0x7) != 0) + consumed += 8 - (consumed & 0x7); + + return consumed >> 3; +} + +static inline void sbc_synthesize_four(struct sbc_decoder_state *state, + struct sbc_frame *frame, + int ch, int blk, AVFrame *output_frame) +{ + int i, k, idx; + int32_t *v = state->V[ch]; + int *offset = state->offset[ch]; + + for (i = 0; i < 8; i++) { + /* Shifting */ + offset[i]--; + if (offset[i] < 0) { + offset[i] = 79; + memcpy(v + 80, v, 9 * sizeof(*v)); + } + + /* Distribute the new matrix value to the shifted position */ + v[offset[i]] = + ( ff_synmatrix4[i][0] * frame->sb_sample[blk][ch][0] + + ff_synmatrix4[i][1] * frame->sb_sample[blk][ch][1] + + ff_synmatrix4[i][2] * frame->sb_sample[blk][ch][2] + + ff_synmatrix4[i][3] * frame->sb_sample[blk][ch][3] ) >> 15; + } + + /* Compute the samples */ + for (idx = 0, i = 0; i < 4; i++, idx += 5) { + k = (i + 4) & 0xf; + + /* Store in output, Q0 */ + AV_WN16A(&output_frame->data[ch][blk * 8 + i * 2], av_clip_int16( + ( v[offset[i] + 0] * ff_sbc_proto_4_40m0[idx + 0] + + v[offset[k] + 1] * ff_sbc_proto_4_40m1[idx + 0] + + v[offset[i] + 2] * ff_sbc_proto_4_40m0[idx + 1] + + v[offset[k] + 3] * ff_sbc_proto_4_40m1[idx + 1] + + v[offset[i] + 4] * ff_sbc_proto_4_40m0[idx + 2] + + v[offset[k] + 5] * ff_sbc_proto_4_40m1[idx + 2] + + v[offset[i] + 6] * ff_sbc_proto_4_40m0[idx + 3] + + v[offset[k] + 7] * ff_sbc_proto_4_40m1[idx + 3] + + v[offset[i] + 8] * ff_sbc_proto_4_40m0[idx + 4] + + v[offset[k] + 9] * ff_sbc_proto_4_40m1[idx + 4] ) >> 15)); + } +} + +static inline void sbc_synthesize_eight(struct sbc_decoder_state *state, + struct sbc_frame *frame, + int ch, int blk, AVFrame *output_frame) +{ + int i, k, idx; + int32_t *v = state->V[ch]; + int *offset = state->offset[ch]; + + for (i = 0; i < 16; i++) { + /* Shifting */ + offset[i]--; + if (offset[i] < 0) { + offset[i] = 159; + memcpy(v + 160, v, 9 * sizeof(*v)); + } + + /* Distribute the new matrix value to the shifted position */ + v[offset[i]] = + ( ff_synmatrix8[i][0] * frame->sb_sample[blk][ch][0] + + ff_synmatrix8[i][1] * frame->sb_sample[blk][ch][1] + + ff_synmatrix8[i][2] * frame->sb_sample[blk][ch][2] + + ff_synmatrix8[i][3] * frame->sb_sample[blk][ch][3] + + ff_synmatrix8[i][4] * frame->sb_sample[blk][ch][4] + + ff_synmatrix8[i][5] * frame->sb_sample[blk][ch][5] + + ff_synmatrix8[i][6] * frame->sb_sample[blk][ch][6] + + ff_synmatrix8[i][7] * frame->sb_sample[blk][ch][7] ) >> 15; + } + + /* Compute the samples */ + for (idx = 0, i = 0; i < 8; i++, idx += 5) { + k = (i + 8) & 0xf; + + /* Store in output, Q0 */ + AV_WN16A(&output_frame->data[ch][blk * 16 + i * 2], av_clip_int16( + ( v[offset[i] + 0] * ff_sbc_proto_8_80m0[idx + 0] + + v[offset[k] + 1] * ff_sbc_proto_8_80m1[idx + 0] + + v[offset[i] + 2] * ff_sbc_proto_8_80m0[idx + 1] + + v[offset[k] + 3] * ff_sbc_proto_8_80m1[idx + 1] + + v[offset[i] + 4] * ff_sbc_proto_8_80m0[idx + 2] + + v[offset[k] + 5] * ff_sbc_proto_8_80m1[idx + 2] + + v[offset[i] + 6] * ff_sbc_proto_8_80m0[idx + 3] + + v[offset[k] + 7] * ff_sbc_proto_8_80m1[idx + 3] + + v[offset[i] + 8] * ff_sbc_proto_8_80m0[idx + 4] + + v[offset[k] + 9] * ff_sbc_proto_8_80m1[idx + 4] ) >> 15)); + } +} + +static void sbc_synthesize_audio(struct sbc_decoder_state *state, + struct sbc_frame *frame, AVFrame *output_frame) +{ + int ch, blk; + + switch (frame->subbands) { + case 4: + for (ch = 0; ch < frame->channels; ch++) + for (blk = 0; blk < frame->blocks; blk++) + sbc_synthesize_four(state, frame, ch, blk, output_frame); + break; + + case 8: + for (ch = 0; ch < frame->channels; ch++) + for (blk = 0; blk < frame->blocks; blk++) + sbc_synthesize_eight(state, frame, ch, blk, output_frame); + break; + } +} + +static int sbc_decode_init(AVCodecContext *avctx) +{ + SBCDecContext *sbc = avctx->priv_data; + int i, ch; + + sbc->frame.crc_ctx = av_crc_get_table(AV_CRC_8_EBU); + + memset(sbc->dsp.V, 0, sizeof(sbc->dsp.V)); + for (ch = 0; ch < 2; ch++) + for (i = 0; i < FF_ARRAY_ELEMS(sbc->dsp.offset[0]); i++) + sbc->dsp.offset[ch][i] = (10 * i + 10); + return 0; +} + +static int sbc_decode_frame(AVCodecContext *avctx, + void *data, int *got_frame_ptr, + AVPacket *avpkt) +{ + SBCDecContext *sbc = avctx->priv_data; + AVFrame *frame = data; + int ret, frame_length; + + if (!sbc) + return AVERROR(EIO); + + frame_length = sbc_unpack_frame(avpkt->data, &sbc->frame, avpkt->size); + if (frame_length <= 0) + return frame_length; + + frame->channels = sbc->frame.channels; + frame->format = AV_SAMPLE_FMT_S16P; + frame->nb_samples = sbc->frame.blocks * sbc->frame.subbands; + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + + sbc_synthesize_audio(&sbc->dsp, &sbc->frame, frame); + + *got_frame_ptr = 1; + + return frame_length; +} + +AVCodec ff_sbc_decoder = { + .name = "sbc", + .long_name = NULL_IF_CONFIG_SMALL("SBC (low-complexity subband codec)"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_SBC, + .priv_data_size = sizeof(SBCDecContext), + .init = sbc_decode_init, + .decode = sbc_decode_frame, + .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, + .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_MONO, + AV_CH_LAYOUT_STEREO, 0}, + .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16P, + AV_SAMPLE_FMT_NONE }, + .supported_samplerates = (const int[]) { 16000, 32000, 44100, 48000, 0 }, +}; diff --git a/libavcodec/sbcdec_data.c b/libavcodec/sbcdec_data.c new file mode 100644 index 0000000000000..21521622075f3 --- /dev/null +++ b/libavcodec/sbcdec_data.c @@ -0,0 +1,127 @@ +/* + * Bluetooth low-complexity, subband codec (SBC) + * + * Copyright (C) 2017 Aurelien Jacobs + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2006 Brad Midgley + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * SBC decoder tables + */ + +#include +#include "sbcdec_data.h" +#include "sbc.h" + +#define SS4(val) ((int32_t)val >> 12) +#define SS8(val) ((int32_t)val >> 14) +#define SN4(val) ((int32_t)val >> 11 + 1 + SBCDEC_FIXED_EXTRA_BITS) +#define SN8(val) ((int32_t)val >> 11 + 1 + SBCDEC_FIXED_EXTRA_BITS) + +const int32_t ff_sbc_proto_4_40m0[] = { + SS4(0x00000000), SS4(0xffa6982f), SS4(0xfba93848), SS4(0x0456c7b8), + SS4(0x005967d1), SS4(0xfffb9ac7), SS4(0xff589157), SS4(0xf9c2a8d8), + SS4(0x027c1434), SS4(0x0019118b), SS4(0xfff3c74c), SS4(0xff137330), + SS4(0xf81b8d70), SS4(0x00ec1b8b), SS4(0xfff0b71a), SS4(0xffe99b00), + SS4(0xfef84470), SS4(0xf6fb4370), SS4(0xffcdc351), SS4(0xffe01dc7) +}; + +const int32_t ff_sbc_proto_4_40m1[] = { + SS4(0xffe090ce), SS4(0xff2c0475), SS4(0xf694f800), SS4(0xff2c0475), + SS4(0xffe090ce), SS4(0xffe01dc7), SS4(0xffcdc351), SS4(0xf6fb4370), + SS4(0xfef84470), SS4(0xffe99b00), SS4(0xfff0b71a), SS4(0x00ec1b8b), + SS4(0xf81b8d70), SS4(0xff137330), SS4(0xfff3c74c), SS4(0x0019118b), + SS4(0x027c1434), SS4(0xf9c2a8d8), SS4(0xff589157), SS4(0xfffb9ac7) +}; + +const int32_t ff_sbc_proto_8_80m0[] = { + SS8(0x00000000), SS8(0xfe8d1970), SS8(0xee979f00), SS8(0x11686100), + SS8(0x0172e690), SS8(0xfff5bd1a), SS8(0xfdf1c8d4), SS8(0xeac182c0), + SS8(0x0d9daee0), SS8(0x00e530da), SS8(0xffe9811d), SS8(0xfd52986c), + SS8(0xe7054ca0), SS8(0x0a00d410), SS8(0x006c1de4), SS8(0xffdba705), + SS8(0xfcbc98e8), SS8(0xe3889d20), SS8(0x06af2308), SS8(0x000bb7db), + SS8(0xffca00ed), SS8(0xfc3fbb68), SS8(0xe071bc00), SS8(0x03bf7948), + SS8(0xffc4e05c), SS8(0xffb54b3b), SS8(0xfbedadc0), SS8(0xdde26200), + SS8(0x0142291c), SS8(0xff960e94), SS8(0xff9f3e17), SS8(0xfbd8f358), + SS8(0xdbf79400), SS8(0xff405e01), SS8(0xff7d4914), SS8(0xff8b1a31), + SS8(0xfc1417b8), SS8(0xdac7bb40), SS8(0xfdbb828c), SS8(0xff762170) +}; + +const int32_t ff_sbc_proto_8_80m1[] = { + SS8(0xff7c272c), SS8(0xfcb02620), SS8(0xda612700), SS8(0xfcb02620), + SS8(0xff7c272c), SS8(0xff762170), SS8(0xfdbb828c), SS8(0xdac7bb40), + SS8(0xfc1417b8), SS8(0xff8b1a31), SS8(0xff7d4914), SS8(0xff405e01), + SS8(0xdbf79400), SS8(0xfbd8f358), SS8(0xff9f3e17), SS8(0xff960e94), + SS8(0x0142291c), SS8(0xdde26200), SS8(0xfbedadc0), SS8(0xffb54b3b), + SS8(0xffc4e05c), SS8(0x03bf7948), SS8(0xe071bc00), SS8(0xfc3fbb68), + SS8(0xffca00ed), SS8(0x000bb7db), SS8(0x06af2308), SS8(0xe3889d20), + SS8(0xfcbc98e8), SS8(0xffdba705), SS8(0x006c1de4), SS8(0x0a00d410), + SS8(0xe7054ca0), SS8(0xfd52986c), SS8(0xffe9811d), SS8(0x00e530da), + SS8(0x0d9daee0), SS8(0xeac182c0), SS8(0xfdf1c8d4), SS8(0xfff5bd1a) +}; + +const int32_t ff_synmatrix4[8][4] = { + { SN4(0x05a82798), SN4(0xfa57d868), SN4(0xfa57d868), SN4(0x05a82798) }, + { SN4(0x030fbc54), SN4(0xf89be510), SN4(0x07641af0), SN4(0xfcf043ac) }, + { SN4(0x00000000), SN4(0x00000000), SN4(0x00000000), SN4(0x00000000) }, + { SN4(0xfcf043ac), SN4(0x07641af0), SN4(0xf89be510), SN4(0x030fbc54) }, + { SN4(0xfa57d868), SN4(0x05a82798), SN4(0x05a82798), SN4(0xfa57d868) }, + { SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) }, + { SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000) }, + { SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) } +}; + +const int32_t ff_synmatrix8[16][8] = { + { SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798), + SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798) }, + { SN8(0x0471ced0), SN8(0xf8275a10), SN8(0x018f8b84), SN8(0x06a6d988), + SN8(0xf9592678), SN8(0xfe70747c), SN8(0x07d8a5f0), SN8(0xfb8e3130) }, + { SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac), + SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54) }, + { SN8(0x018f8b84), SN8(0xfb8e3130), SN8(0x06a6d988), SN8(0xf8275a10), + SN8(0x07d8a5f0), SN8(0xf9592678), SN8(0x0471ced0), SN8(0xfe70747c) }, + { SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), + SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000) }, + { SN8(0xfe70747c), SN8(0x0471ced0), SN8(0xf9592678), SN8(0x07d8a5f0), + SN8(0xf8275a10), SN8(0x06a6d988), SN8(0xfb8e3130), SN8(0x018f8b84) }, + { SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54), + SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac) }, + { SN8(0xfb8e3130), SN8(0x07d8a5f0), SN8(0xfe70747c), SN8(0xf9592678), + SN8(0x06a6d988), SN8(0x018f8b84), SN8(0xf8275a10), SN8(0x0471ced0) }, + { SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868), + SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868) }, + { SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0), + SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) }, + { SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0), + SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) }, + { SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c), + SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) }, + { SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), + SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000) }, + { SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c), + SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) }, + { SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0), + SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) }, + { SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0), + SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) } +}; diff --git a/libavcodec/sbcdec_data.h b/libavcodec/sbcdec_data.h new file mode 100644 index 0000000000000..1b79d1de237f7 --- /dev/null +++ b/libavcodec/sbcdec_data.h @@ -0,0 +1,44 @@ +/* + * Bluetooth low-complexity, subband codec (SBC) + * + * Copyright (C) 2017 Aurelien Jacobs + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2006 Brad Midgley + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * SBC decoder tables + */ + +#ifndef AVCODEC_SBCDEC_DATA_H +#define AVCODEC_SBCDEC_DATA_H + +#include + +extern const int32_t ff_sbc_proto_4_40m0[]; +extern const int32_t ff_sbc_proto_4_40m1[]; +extern const int32_t ff_sbc_proto_8_80m0[]; +extern const int32_t ff_sbc_proto_8_80m1[]; +extern const int32_t ff_synmatrix4[8][4]; +extern const int32_t ff_synmatrix8[16][8]; + +#endif /* AVCODEC_SBCDEC_DATA_H */ diff --git a/libavcodec/sbcdsp.c b/libavcodec/sbcdsp.c new file mode 100644 index 0000000000000..e745595da012c --- /dev/null +++ b/libavcodec/sbcdsp.c @@ -0,0 +1,387 @@ +/* + * Bluetooth low-complexity, subband codec (SBC) + * + * Copyright (C) 2017 Aurelien Jacobs + * Copyright (C) 2012-2013 Intel Corporation + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2006 Brad Midgley + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * SBC basic "building bricks" + */ + +#include +#include +#include +#include "libavutil/common.h" +#include "libavutil/intmath.h" +#include "libavutil/intreadwrite.h" +#include "sbc.h" +#include "sbcdsp.h" +#include "sbcdsp_data.h" + +/* + * A reference C code of analysis filter with SIMD-friendly tables + * reordering and code layout. This code can be used to develop platform + * specific SIMD optimizations. Also it may be used as some kind of test + * for compiler autovectorization capabilities (who knows, if the compiler + * is very good at this stuff, hand optimized assembly may be not strictly + * needed for some platform). + * + * Note: It is also possible to make a simple variant of analysis filter, + * which needs only a single constants table without taking care about + * even/odd cases. This simple variant of filter can be implemented without + * input data permutation. The only thing that would be lost is the + * possibility to use pairwise SIMD multiplications. But for some simple + * CPU cores without SIMD extensions it can be useful. If anybody is + * interested in implementing such variant of a filter, sourcecode from + * bluez versions 4.26/4.27 can be used as a reference and the history of + * the changes in git repository done around that time may be worth checking. + */ + +static av_always_inline void sbc_analyze_simd(const int16_t *in, int32_t *out, + const int16_t *consts, + unsigned subbands) +{ + int32_t t1[8]; + int16_t t2[8]; + int i, j, hop = 0; + + /* rounding coefficient */ + for (i = 0; i < subbands; i++) + t1[i] = 1 << (SBC_PROTO_FIXED_SCALE - 1); + + /* low pass polyphase filter */ + for (hop = 0; hop < 10*subbands; hop += 2*subbands) + for (i = 0; i < 2*subbands; i++) + t1[i >> 1] += in[hop + i] * consts[hop + i]; + + /* scaling */ + for (i = 0; i < subbands; i++) + t2[i] = t1[i] >> SBC_PROTO_FIXED_SCALE; + + memset(t1, 0, sizeof(t1)); + + /* do the cos transform */ + for (i = 0; i < subbands/2; i++) + for (j = 0; j < 2*subbands; j++) + t1[j>>1] += t2[i * 2 + (j&1)] * consts[10*subbands + i*2*subbands + j]; + + for (i = 0; i < subbands; i++) + out[i] = t1[i] >> (SBC_COS_TABLE_FIXED_SCALE - SCALE_OUT_BITS); +} + +static void sbc_analyze_4_simd(const int16_t *in, int32_t *out, + const int16_t *consts) +{ + sbc_analyze_simd(in, out, consts, 4); +} + +static void sbc_analyze_8_simd(const int16_t *in, int32_t *out, + const int16_t *consts) +{ + sbc_analyze_simd(in, out, consts, 8); +} + +static inline void sbc_analyze_4b_4s_simd(SBCDSPContext *s, + int16_t *x, int32_t *out, int out_stride) +{ + /* Analyze blocks */ + s->sbc_analyze_4(x + 12, out, ff_sbcdsp_analysis_consts_fixed4_simd_odd); + out += out_stride; + s->sbc_analyze_4(x + 8, out, ff_sbcdsp_analysis_consts_fixed4_simd_even); + out += out_stride; + s->sbc_analyze_4(x + 4, out, ff_sbcdsp_analysis_consts_fixed4_simd_odd); + out += out_stride; + s->sbc_analyze_4(x + 0, out, ff_sbcdsp_analysis_consts_fixed4_simd_even); +} + +static inline void sbc_analyze_4b_8s_simd(SBCDSPContext *s, + int16_t *x, int32_t *out, int out_stride) +{ + /* Analyze blocks */ + s->sbc_analyze_8(x + 24, out, ff_sbcdsp_analysis_consts_fixed8_simd_odd); + out += out_stride; + s->sbc_analyze_8(x + 16, out, ff_sbcdsp_analysis_consts_fixed8_simd_even); + out += out_stride; + s->sbc_analyze_8(x + 8, out, ff_sbcdsp_analysis_consts_fixed8_simd_odd); + out += out_stride; + s->sbc_analyze_8(x + 0, out, ff_sbcdsp_analysis_consts_fixed8_simd_even); +} + +static inline void sbc_analyze_1b_8s_simd_even(SBCDSPContext *s, + int16_t *x, int32_t *out, + int out_stride); + +static inline void sbc_analyze_1b_8s_simd_odd(SBCDSPContext *s, + int16_t *x, int32_t *out, + int out_stride) +{ + s->sbc_analyze_8(x, out, ff_sbcdsp_analysis_consts_fixed8_simd_odd); + s->sbc_analyze_8s = sbc_analyze_1b_8s_simd_even; +} + +static inline void sbc_analyze_1b_8s_simd_even(SBCDSPContext *s, + int16_t *x, int32_t *out, + int out_stride) +{ + s->sbc_analyze_8(x, out, ff_sbcdsp_analysis_consts_fixed8_simd_even); + s->sbc_analyze_8s = sbc_analyze_1b_8s_simd_odd; +} + +/* + * Input data processing functions. The data is endian converted if needed, + * channels are deintrleaved and audio samples are reordered for use in + * SIMD-friendly analysis filter function. The results are put into "X" + * array, getting appended to the previous data (or it is better to say + * prepended, as the buffer is filled from top to bottom). Old data is + * discarded when neededed, but availability of (10 * nrof_subbands) + * contiguous samples is always guaranteed for the input to the analysis + * filter. This is achieved by copying a sufficient part of old data + * to the top of the buffer on buffer wraparound. + */ + +static int sbc_enc_process_input_4s(int position, const uint8_t *pcm, + int16_t X[2][SBC_X_BUFFER_SIZE], + int nsamples, int nchannels) +{ + int c; + + /* handle X buffer wraparound */ + if (position < nsamples) { + for (c = 0; c < nchannels; c++) + memcpy(&X[c][SBC_X_BUFFER_SIZE - 40], &X[c][position], + 36 * sizeof(int16_t)); + position = SBC_X_BUFFER_SIZE - 40; + } + + /* copy/permutate audio samples */ + for (; nsamples >= 8; nsamples -= 8, pcm += 16 * nchannels) { + position -= 8; + for (c = 0; c < nchannels; c++) { + int16_t *x = &X[c][position]; + x[0] = AV_RN16(pcm + 14*nchannels + 2*c); + x[1] = AV_RN16(pcm + 6*nchannels + 2*c); + x[2] = AV_RN16(pcm + 12*nchannels + 2*c); + x[3] = AV_RN16(pcm + 8*nchannels + 2*c); + x[4] = AV_RN16(pcm + 0*nchannels + 2*c); + x[5] = AV_RN16(pcm + 4*nchannels + 2*c); + x[6] = AV_RN16(pcm + 2*nchannels + 2*c); + x[7] = AV_RN16(pcm + 10*nchannels + 2*c); + } + } + + return position; +} + +static int sbc_enc_process_input_8s(int position, const uint8_t *pcm, + int16_t X[2][SBC_X_BUFFER_SIZE], + int nsamples, int nchannels) +{ + int c; + + /* handle X buffer wraparound */ + if (position < nsamples) { + for (c = 0; c < nchannels; c++) + memcpy(&X[c][SBC_X_BUFFER_SIZE - 72], &X[c][position], + 72 * sizeof(int16_t)); + position = SBC_X_BUFFER_SIZE - 72; + } + + if (position % 16 == 8) { + position -= 8; + nsamples -= 8; + for (c = 0; c < nchannels; c++) { + int16_t *x = &X[c][position]; + x[0] = AV_RN16(pcm + 14*nchannels + 2*c); + x[2] = AV_RN16(pcm + 12*nchannels + 2*c); + x[3] = AV_RN16(pcm + 0*nchannels + 2*c); + x[4] = AV_RN16(pcm + 10*nchannels + 2*c); + x[5] = AV_RN16(pcm + 2*nchannels + 2*c); + x[6] = AV_RN16(pcm + 8*nchannels + 2*c); + x[7] = AV_RN16(pcm + 4*nchannels + 2*c); + x[8] = AV_RN16(pcm + 6*nchannels + 2*c); + } + pcm += 16 * nchannels; + } + + /* copy/permutate audio samples */ + for (; nsamples >= 16; nsamples -= 16, pcm += 32 * nchannels) { + position -= 16; + for (c = 0; c < nchannels; c++) { + int16_t *x = &X[c][position]; + x[0] = AV_RN16(pcm + 30*nchannels + 2*c); + x[1] = AV_RN16(pcm + 14*nchannels + 2*c); + x[2] = AV_RN16(pcm + 28*nchannels + 2*c); + x[3] = AV_RN16(pcm + 16*nchannels + 2*c); + x[4] = AV_RN16(pcm + 26*nchannels + 2*c); + x[5] = AV_RN16(pcm + 18*nchannels + 2*c); + x[6] = AV_RN16(pcm + 24*nchannels + 2*c); + x[7] = AV_RN16(pcm + 20*nchannels + 2*c); + x[8] = AV_RN16(pcm + 22*nchannels + 2*c); + x[9] = AV_RN16(pcm + 6*nchannels + 2*c); + x[10] = AV_RN16(pcm + 12*nchannels + 2*c); + x[11] = AV_RN16(pcm + 0*nchannels + 2*c); + x[12] = AV_RN16(pcm + 10*nchannels + 2*c); + x[13] = AV_RN16(pcm + 2*nchannels + 2*c); + x[14] = AV_RN16(pcm + 8*nchannels + 2*c); + x[15] = AV_RN16(pcm + 4*nchannels + 2*c); + } + } + + if (nsamples == 8) { + position -= 8; + for (c = 0; c < nchannels; c++) { + int16_t *x = &X[c][position]; + x[-7] = AV_RN16(pcm + 14*nchannels + 2*c); + x[1] = AV_RN16(pcm + 6*nchannels + 2*c); + x[2] = AV_RN16(pcm + 12*nchannels + 2*c); + x[3] = AV_RN16(pcm + 0*nchannels + 2*c); + x[4] = AV_RN16(pcm + 10*nchannels + 2*c); + x[5] = AV_RN16(pcm + 2*nchannels + 2*c); + x[6] = AV_RN16(pcm + 8*nchannels + 2*c); + x[7] = AV_RN16(pcm + 4*nchannels + 2*c); + } + } + + return position; +} + +static void sbc_calc_scalefactors(int32_t sb_sample_f[16][2][8], + uint32_t scale_factor[2][8], + int blocks, int channels, int subbands) +{ + int ch, sb, blk; + for (ch = 0; ch < channels; ch++) { + for (sb = 0; sb < subbands; sb++) { + uint32_t x = 1 << SCALE_OUT_BITS; + for (blk = 0; blk < blocks; blk++) { + int32_t tmp = FFABS(sb_sample_f[blk][ch][sb]); + if (tmp != 0) + x |= tmp - 1; + } + scale_factor[ch][sb] = (31 - SCALE_OUT_BITS) - ff_clz(x); + } + } +} + +static int sbc_calc_scalefactors_j(int32_t sb_sample_f[16][2][8], + uint32_t scale_factor[2][8], + int blocks, int subbands) +{ + int blk, joint = 0; + int32_t tmp0, tmp1; + uint32_t x, y; + + /* last subband does not use joint stereo */ + int sb = subbands - 1; + x = 1 << SCALE_OUT_BITS; + y = 1 << SCALE_OUT_BITS; + for (blk = 0; blk < blocks; blk++) { + tmp0 = FFABS(sb_sample_f[blk][0][sb]); + tmp1 = FFABS(sb_sample_f[blk][1][sb]); + if (tmp0 != 0) + x |= tmp0 - 1; + if (tmp1 != 0) + y |= tmp1 - 1; + } + scale_factor[0][sb] = (31 - SCALE_OUT_BITS) - ff_clz(x); + scale_factor[1][sb] = (31 - SCALE_OUT_BITS) - ff_clz(y); + + /* the rest of subbands can use joint stereo */ + while (--sb >= 0) { + int32_t sb_sample_j[16][2]; + x = 1 << SCALE_OUT_BITS; + y = 1 << SCALE_OUT_BITS; + for (blk = 0; blk < blocks; blk++) { + tmp0 = sb_sample_f[blk][0][sb]; + tmp1 = sb_sample_f[blk][1][sb]; + sb_sample_j[blk][0] = (tmp0 >> 1) + (tmp1 >> 1); + sb_sample_j[blk][1] = (tmp0 >> 1) - (tmp1 >> 1); + tmp0 = FFABS(tmp0); + tmp1 = FFABS(tmp1); + if (tmp0 != 0) + x |= tmp0 - 1; + if (tmp1 != 0) + y |= tmp1 - 1; + } + scale_factor[0][sb] = (31 - SCALE_OUT_BITS) - + ff_clz(x); + scale_factor[1][sb] = (31 - SCALE_OUT_BITS) - + ff_clz(y); + x = 1 << SCALE_OUT_BITS; + y = 1 << SCALE_OUT_BITS; + for (blk = 0; blk < blocks; blk++) { + tmp0 = FFABS(sb_sample_j[blk][0]); + tmp1 = FFABS(sb_sample_j[blk][1]); + if (tmp0 != 0) + x |= tmp0 - 1; + if (tmp1 != 0) + y |= tmp1 - 1; + } + x = (31 - SCALE_OUT_BITS) - ff_clz(x); + y = (31 - SCALE_OUT_BITS) - ff_clz(y); + + /* decide whether to use joint stereo for this subband */ + if ((scale_factor[0][sb] + scale_factor[1][sb]) > x + y) { + joint |= 1 << (subbands - 1 - sb); + scale_factor[0][sb] = x; + scale_factor[1][sb] = y; + for (blk = 0; blk < blocks; blk++) { + sb_sample_f[blk][0][sb] = sb_sample_j[blk][0]; + sb_sample_f[blk][1][sb] = sb_sample_j[blk][1]; + } + } + } + + /* bitmask with the information about subbands using joint stereo */ + return joint; +} + +/* + * Detect CPU features and setup function pointers + */ +av_cold void ff_sbcdsp_init(SBCDSPContext *s) +{ + /* Default implementation for analyze functions */ + s->sbc_analyze_4 = sbc_analyze_4_simd; + s->sbc_analyze_8 = sbc_analyze_8_simd; + s->sbc_analyze_4s = sbc_analyze_4b_4s_simd; + if (s->increment == 1) + s->sbc_analyze_8s = sbc_analyze_1b_8s_simd_odd; + else + s->sbc_analyze_8s = sbc_analyze_4b_8s_simd; + + /* Default implementation for input reordering / deinterleaving */ + s->sbc_enc_process_input_4s = sbc_enc_process_input_4s; + s->sbc_enc_process_input_8s = sbc_enc_process_input_8s; + + /* Default implementation for scale factors calculation */ + s->sbc_calc_scalefactors = sbc_calc_scalefactors; + s->sbc_calc_scalefactors_j = sbc_calc_scalefactors_j; + + if (ARCH_ARM) + ff_sbcdsp_init_arm(s); + if (ARCH_X86) + ff_sbcdsp_init_x86(s); +} diff --git a/libavcodec/sbcdsp.h b/libavcodec/sbcdsp.h new file mode 100644 index 0000000000000..334c058e6de02 --- /dev/null +++ b/libavcodec/sbcdsp.h @@ -0,0 +1,86 @@ +/* + * Bluetooth low-complexity, subband codec (SBC) + * + * Copyright (C) 2017 Aurelien Jacobs + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2006 Brad Midgley + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * SBC basic "building bricks" + */ + +#ifndef AVCODEC_SBCDSP_H +#define AVCODEC_SBCDSP_H + +#include "sbc.h" +#include "sbcdsp_data.h" + +#define SCALE_OUT_BITS 15 +#define SBC_X_BUFFER_SIZE 328 + +typedef struct sbc_dsp_context SBCDSPContext; + +struct sbc_dsp_context { + int position; + /* Number of consecutive blocks handled by the encoder */ + uint8_t increment; + DECLARE_ALIGNED(SBC_ALIGN, int16_t, X)[2][SBC_X_BUFFER_SIZE]; + void (*sbc_analyze_4)(const int16_t *in, int32_t *out, const int16_t *consts); + void (*sbc_analyze_8)(const int16_t *in, int32_t *out, const int16_t *consts); + /* Polyphase analysis filter for 4 subbands configuration, + * it handles "increment" blocks at once */ + void (*sbc_analyze_4s)(SBCDSPContext *s, + int16_t *x, int32_t *out, int out_stride); + /* Polyphase analysis filter for 8 subbands configuration, + * it handles "increment" blocks at once */ + void (*sbc_analyze_8s)(SBCDSPContext *s, + int16_t *x, int32_t *out, int out_stride); + /* Process input data (deinterleave, endian conversion, reordering), + * depending on the number of subbands and input data byte order */ + int (*sbc_enc_process_input_4s)(int position, const uint8_t *pcm, + int16_t X[2][SBC_X_BUFFER_SIZE], + int nsamples, int nchannels); + int (*sbc_enc_process_input_8s)(int position, const uint8_t *pcm, + int16_t X[2][SBC_X_BUFFER_SIZE], + int nsamples, int nchannels); + /* Scale factors calculation */ + void (*sbc_calc_scalefactors)(int32_t sb_sample_f[16][2][8], + uint32_t scale_factor[2][8], + int blocks, int channels, int subbands); + /* Scale factors calculation with joint stereo support */ + int (*sbc_calc_scalefactors_j)(int32_t sb_sample_f[16][2][8], + uint32_t scale_factor[2][8], + int blocks, int subbands); +}; + +/* + * Initialize pointers to the functions which are the basic "building bricks" + * of SBC codec. Best implementation is selected based on target CPU + * capabilities. + */ +void ff_sbcdsp_init(SBCDSPContext *s); + +void ff_sbcdsp_init_arm(SBCDSPContext *s); +void ff_sbcdsp_init_x86(SBCDSPContext *s); + +#endif /* AVCODEC_SBCDSP_H */ diff --git a/libavcodec/sbcdsp_data.c b/libavcodec/sbcdsp_data.c new file mode 100644 index 0000000000000..78c07c0077181 --- /dev/null +++ b/libavcodec/sbcdsp_data.c @@ -0,0 +1,329 @@ +/* + * Bluetooth low-complexity, subband codec (SBC) + * + * Copyright (C) 2017 Aurelien Jacobs + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2006 Brad Midgley + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * miscellaneous SBC tables + */ + +#include "sbcdsp_data.h" + +#define F_PROTO(x) ((int32_t) (((x) * 2) * ((int32_t) 1 << 15) + 0.5)) +#define F_COS(x) ((int32_t) (((x) ) * ((int32_t) 1 << 15) + 0.5)) + +/* + * Constant tables for the use in SIMD optimized analysis filters + * Each table consists of two parts: + * 1. reordered "proto" table + * 2. reordered "cos" table + * + * Due to non-symmetrical reordering, separate tables for "even" + * and "odd" cases are needed + */ + +DECLARE_ALIGNED(SBC_ALIGN, const int16_t, ff_sbcdsp_analysis_consts_fixed4_simd_even)[40 + 16] = { +#define C0 1.0932568993 +#define C1 1.3056875580 +#define C2 1.3056875580 +#define C3 1.6772280856 + +#define F(x) F_PROTO(x) + F(0.00000000E+00 * C0), F(3.83720193E-03 * C0), + F(5.36548976E-04 * C1), F(2.73370904E-03 * C1), + F(3.06012286E-03 * C2), F(3.89205149E-03 * C2), + F(0.00000000E+00 * C3), -F(1.49188357E-03 * C3), + F(1.09137620E-02 * C0), F(2.58767811E-02 * C0), + F(2.04385087E-02 * C1), F(3.21939290E-02 * C1), + F(7.76463494E-02 * C2), F(6.13245186E-03 * C2), + F(0.00000000E+00 * C3), -F(2.88757392E-02 * C3), + F(1.35593274E-01 * C0), F(2.94315332E-01 * C0), + F(1.94987841E-01 * C1), F(2.81828203E-01 * C1), + -F(1.94987841E-01 * C2), F(2.81828203E-01 * C2), + F(0.00000000E+00 * C3), -F(2.46636662E-01 * C3), + -F(1.35593274E-01 * C0), F(2.58767811E-02 * C0), + -F(7.76463494E-02 * C1), F(6.13245186E-03 * C1), + -F(2.04385087E-02 * C2), F(3.21939290E-02 * C2), + F(0.00000000E+00 * C3), F(2.88217274E-02 * C3), + -F(1.09137620E-02 * C0), F(3.83720193E-03 * C0), + -F(3.06012286E-03 * C1), F(3.89205149E-03 * C1), + -F(5.36548976E-04 * C2), F(2.73370904E-03 * C2), + F(0.00000000E+00 * C3), -F(1.86581691E-03 * C3), +#undef F +#define F(x) F_COS(x) + F(0.7071067812 / C0), F(0.9238795325 / C1), + -F(0.7071067812 / C0), F(0.3826834324 / C1), + -F(0.7071067812 / C0), -F(0.3826834324 / C1), + F(0.7071067812 / C0), -F(0.9238795325 / C1), + F(0.3826834324 / C2), -F(1.0000000000 / C3), + -F(0.9238795325 / C2), -F(1.0000000000 / C3), + F(0.9238795325 / C2), -F(1.0000000000 / C3), + -F(0.3826834324 / C2), -F(1.0000000000 / C3), +#undef F + +#undef C0 +#undef C1 +#undef C2 +#undef C3 +}; + +DECLARE_ALIGNED(SBC_ALIGN, const int16_t, ff_sbcdsp_analysis_consts_fixed4_simd_odd)[40 + 16] = { +#define C0 1.3056875580 +#define C1 1.6772280856 +#define C2 1.0932568993 +#define C3 1.3056875580 + +#define F(x) F_PROTO(x) + F(2.73370904E-03 * C0), F(5.36548976E-04 * C0), + -F(1.49188357E-03 * C1), F(0.00000000E+00 * C1), + F(3.83720193E-03 * C2), F(1.09137620E-02 * C2), + F(3.89205149E-03 * C3), F(3.06012286E-03 * C3), + F(3.21939290E-02 * C0), F(2.04385087E-02 * C0), + -F(2.88757392E-02 * C1), F(0.00000000E+00 * C1), + F(2.58767811E-02 * C2), F(1.35593274E-01 * C2), + F(6.13245186E-03 * C3), F(7.76463494E-02 * C3), + F(2.81828203E-01 * C0), F(1.94987841E-01 * C0), + -F(2.46636662E-01 * C1), F(0.00000000E+00 * C1), + F(2.94315332E-01 * C2), -F(1.35593274E-01 * C2), + F(2.81828203E-01 * C3), -F(1.94987841E-01 * C3), + F(6.13245186E-03 * C0), -F(7.76463494E-02 * C0), + F(2.88217274E-02 * C1), F(0.00000000E+00 * C1), + F(2.58767811E-02 * C2), -F(1.09137620E-02 * C2), + F(3.21939290E-02 * C3), -F(2.04385087E-02 * C3), + F(3.89205149E-03 * C0), -F(3.06012286E-03 * C0), + -F(1.86581691E-03 * C1), F(0.00000000E+00 * C1), + F(3.83720193E-03 * C2), F(0.00000000E+00 * C2), + F(2.73370904E-03 * C3), -F(5.36548976E-04 * C3), +#undef F +#define F(x) F_COS(x) + F(0.9238795325 / C0), -F(1.0000000000 / C1), + F(0.3826834324 / C0), -F(1.0000000000 / C1), + -F(0.3826834324 / C0), -F(1.0000000000 / C1), + -F(0.9238795325 / C0), -F(1.0000000000 / C1), + F(0.7071067812 / C2), F(0.3826834324 / C3), + -F(0.7071067812 / C2), -F(0.9238795325 / C3), + -F(0.7071067812 / C2), F(0.9238795325 / C3), + F(0.7071067812 / C2), -F(0.3826834324 / C3), +#undef F + +#undef C0 +#undef C1 +#undef C2 +#undef C3 +}; + +DECLARE_ALIGNED(SBC_ALIGN, const int16_t, ff_sbcdsp_analysis_consts_fixed8_simd_even)[80 + 64] = { +#define C0 2.7906148894 +#define C1 2.4270044280 +#define C2 2.8015616024 +#define C3 3.1710363741 +#define C4 2.5377944043 +#define C5 2.4270044280 +#define C6 2.8015616024 +#define C7 3.1710363741 + +#define F(x) F_PROTO(x) + F(0.00000000E+00 * C0), F(2.01182542E-03 * C0), + F(1.56575398E-04 * C1), F(1.78371725E-03 * C1), + F(3.43256425E-04 * C2), F(1.47640169E-03 * C2), + F(5.54620202E-04 * C3), F(1.13992507E-03 * C3), + -F(8.23919506E-04 * C4), F(0.00000000E+00 * C4), + F(2.10371989E-03 * C5), F(3.49717454E-03 * C5), + F(1.99454554E-03 * C6), F(1.64973098E-03 * C6), + F(1.61656283E-03 * C7), F(1.78805361E-04 * C7), + F(5.65949473E-03 * C0), F(1.29371806E-02 * C0), + F(8.02941163E-03 * C1), F(1.53184106E-02 * C1), + F(1.04584443E-02 * C2), F(1.62208471E-02 * C2), + F(1.27472335E-02 * C3), F(1.59045603E-02 * C3), + -F(1.46525263E-02 * C4), F(0.00000000E+00 * C4), + F(8.85757540E-03 * C5), F(5.31873032E-02 * C5), + F(2.92408442E-03 * C6), F(3.90751381E-02 * C6), + -F(4.91578024E-03 * C7), F(2.61098752E-02 * C7), + F(6.79989431E-02 * C0), F(1.46955068E-01 * C0), + F(8.29847578E-02 * C1), F(1.45389847E-01 * C1), + F(9.75753918E-02 * C2), F(1.40753505E-01 * C2), + F(1.11196689E-01 * C3), F(1.33264415E-01 * C3), + -F(1.23264548E-01 * C4), F(0.00000000E+00 * C4), + F(1.45389847E-01 * C5), -F(8.29847578E-02 * C5), + F(1.40753505E-01 * C6), -F(9.75753918E-02 * C6), + F(1.33264415E-01 * C7), -F(1.11196689E-01 * C7), + -F(6.79989431E-02 * C0), F(1.29371806E-02 * C0), + -F(5.31873032E-02 * C1), F(8.85757540E-03 * C1), + -F(3.90751381E-02 * C2), F(2.92408442E-03 * C2), + -F(2.61098752E-02 * C3), -F(4.91578024E-03 * C3), + F(1.46404076E-02 * C4), F(0.00000000E+00 * C4), + F(1.53184106E-02 * C5), -F(8.02941163E-03 * C5), + F(1.62208471E-02 * C6), -F(1.04584443E-02 * C6), + F(1.59045603E-02 * C7), -F(1.27472335E-02 * C7), + -F(5.65949473E-03 * C0), F(2.01182542E-03 * C0), + -F(3.49717454E-03 * C1), F(2.10371989E-03 * C1), + -F(1.64973098E-03 * C2), F(1.99454554E-03 * C2), + -F(1.78805361E-04 * C3), F(1.61656283E-03 * C3), + -F(9.02154502E-04 * C4), F(0.00000000E+00 * C4), + F(1.78371725E-03 * C5), -F(1.56575398E-04 * C5), + F(1.47640169E-03 * C6), -F(3.43256425E-04 * C6), + F(1.13992507E-03 * C7), -F(5.54620202E-04 * C7), +#undef F +#define F(x) F_COS(x) + F(0.7071067812 / C0), F(0.8314696123 / C1), + -F(0.7071067812 / C0), -F(0.1950903220 / C1), + -F(0.7071067812 / C0), -F(0.9807852804 / C1), + F(0.7071067812 / C0), -F(0.5555702330 / C1), + F(0.7071067812 / C0), F(0.5555702330 / C1), + -F(0.7071067812 / C0), F(0.9807852804 / C1), + -F(0.7071067812 / C0), F(0.1950903220 / C1), + F(0.7071067812 / C0), -F(0.8314696123 / C1), + F(0.9238795325 / C2), F(0.9807852804 / C3), + F(0.3826834324 / C2), F(0.8314696123 / C3), + -F(0.3826834324 / C2), F(0.5555702330 / C3), + -F(0.9238795325 / C2), F(0.1950903220 / C3), + -F(0.9238795325 / C2), -F(0.1950903220 / C3), + -F(0.3826834324 / C2), -F(0.5555702330 / C3), + F(0.3826834324 / C2), -F(0.8314696123 / C3), + F(0.9238795325 / C2), -F(0.9807852804 / C3), + -F(1.0000000000 / C4), F(0.5555702330 / C5), + -F(1.0000000000 / C4), -F(0.9807852804 / C5), + -F(1.0000000000 / C4), F(0.1950903220 / C5), + -F(1.0000000000 / C4), F(0.8314696123 / C5), + -F(1.0000000000 / C4), -F(0.8314696123 / C5), + -F(1.0000000000 / C4), -F(0.1950903220 / C5), + -F(1.0000000000 / C4), F(0.9807852804 / C5), + -F(1.0000000000 / C4), -F(0.5555702330 / C5), + F(0.3826834324 / C6), F(0.1950903220 / C7), + -F(0.9238795325 / C6), -F(0.5555702330 / C7), + F(0.9238795325 / C6), F(0.8314696123 / C7), + -F(0.3826834324 / C6), -F(0.9807852804 / C7), + -F(0.3826834324 / C6), F(0.9807852804 / C7), + F(0.9238795325 / C6), -F(0.8314696123 / C7), + -F(0.9238795325 / C6), F(0.5555702330 / C7), + F(0.3826834324 / C6), -F(0.1950903220 / C7), +#undef F + +#undef C0 +#undef C1 +#undef C2 +#undef C3 +#undef C4 +#undef C5 +#undef C6 +#undef C7 +}; + +DECLARE_ALIGNED(SBC_ALIGN, const int16_t, ff_sbcdsp_analysis_consts_fixed8_simd_odd)[80 + 64] = { +#define C0 2.5377944043 +#define C1 2.4270044280 +#define C2 2.8015616024 +#define C3 3.1710363741 +#define C4 2.7906148894 +#define C5 2.4270044280 +#define C6 2.8015616024 +#define C7 3.1710363741 + +#define F(x) F_PROTO(x) + F(0.00000000E+00 * C0), -F(8.23919506E-04 * C0), + F(1.56575398E-04 * C1), F(1.78371725E-03 * C1), + F(3.43256425E-04 * C2), F(1.47640169E-03 * C2), + F(5.54620202E-04 * C3), F(1.13992507E-03 * C3), + F(2.01182542E-03 * C4), F(5.65949473E-03 * C4), + F(2.10371989E-03 * C5), F(3.49717454E-03 * C5), + F(1.99454554E-03 * C6), F(1.64973098E-03 * C6), + F(1.61656283E-03 * C7), F(1.78805361E-04 * C7), + F(0.00000000E+00 * C0), -F(1.46525263E-02 * C0), + F(8.02941163E-03 * C1), F(1.53184106E-02 * C1), + F(1.04584443E-02 * C2), F(1.62208471E-02 * C2), + F(1.27472335E-02 * C3), F(1.59045603E-02 * C3), + F(1.29371806E-02 * C4), F(6.79989431E-02 * C4), + F(8.85757540E-03 * C5), F(5.31873032E-02 * C5), + F(2.92408442E-03 * C6), F(3.90751381E-02 * C6), + -F(4.91578024E-03 * C7), F(2.61098752E-02 * C7), + F(0.00000000E+00 * C0), -F(1.23264548E-01 * C0), + F(8.29847578E-02 * C1), F(1.45389847E-01 * C1), + F(9.75753918E-02 * C2), F(1.40753505E-01 * C2), + F(1.11196689E-01 * C3), F(1.33264415E-01 * C3), + F(1.46955068E-01 * C4), -F(6.79989431E-02 * C4), + F(1.45389847E-01 * C5), -F(8.29847578E-02 * C5), + F(1.40753505E-01 * C6), -F(9.75753918E-02 * C6), + F(1.33264415E-01 * C7), -F(1.11196689E-01 * C7), + F(0.00000000E+00 * C0), F(1.46404076E-02 * C0), + -F(5.31873032E-02 * C1), F(8.85757540E-03 * C1), + -F(3.90751381E-02 * C2), F(2.92408442E-03 * C2), + -F(2.61098752E-02 * C3), -F(4.91578024E-03 * C3), + F(1.29371806E-02 * C4), -F(5.65949473E-03 * C4), + F(1.53184106E-02 * C5), -F(8.02941163E-03 * C5), + F(1.62208471E-02 * C6), -F(1.04584443E-02 * C6), + F(1.59045603E-02 * C7), -F(1.27472335E-02 * C7), + F(0.00000000E+00 * C0), -F(9.02154502E-04 * C0), + -F(3.49717454E-03 * C1), F(2.10371989E-03 * C1), + -F(1.64973098E-03 * C2), F(1.99454554E-03 * C2), + -F(1.78805361E-04 * C3), F(1.61656283E-03 * C3), + F(2.01182542E-03 * C4), F(0.00000000E+00 * C4), + F(1.78371725E-03 * C5), -F(1.56575398E-04 * C5), + F(1.47640169E-03 * C6), -F(3.43256425E-04 * C6), + F(1.13992507E-03 * C7), -F(5.54620202E-04 * C7), +#undef F +#define F(x) F_COS(x) + -F(1.0000000000 / C0), F(0.8314696123 / C1), + -F(1.0000000000 / C0), -F(0.1950903220 / C1), + -F(1.0000000000 / C0), -F(0.9807852804 / C1), + -F(1.0000000000 / C0), -F(0.5555702330 / C1), + -F(1.0000000000 / C0), F(0.5555702330 / C1), + -F(1.0000000000 / C0), F(0.9807852804 / C1), + -F(1.0000000000 / C0), F(0.1950903220 / C1), + -F(1.0000000000 / C0), -F(0.8314696123 / C1), + F(0.9238795325 / C2), F(0.9807852804 / C3), + F(0.3826834324 / C2), F(0.8314696123 / C3), + -F(0.3826834324 / C2), F(0.5555702330 / C3), + -F(0.9238795325 / C2), F(0.1950903220 / C3), + -F(0.9238795325 / C2), -F(0.1950903220 / C3), + -F(0.3826834324 / C2), -F(0.5555702330 / C3), + F(0.3826834324 / C2), -F(0.8314696123 / C3), + F(0.9238795325 / C2), -F(0.9807852804 / C3), + F(0.7071067812 / C4), F(0.5555702330 / C5), + -F(0.7071067812 / C4), -F(0.9807852804 / C5), + -F(0.7071067812 / C4), F(0.1950903220 / C5), + F(0.7071067812 / C4), F(0.8314696123 / C5), + F(0.7071067812 / C4), -F(0.8314696123 / C5), + -F(0.7071067812 / C4), -F(0.1950903220 / C5), + -F(0.7071067812 / C4), F(0.9807852804 / C5), + F(0.7071067812 / C4), -F(0.5555702330 / C5), + F(0.3826834324 / C6), F(0.1950903220 / C7), + -F(0.9238795325 / C6), -F(0.5555702330 / C7), + F(0.9238795325 / C6), F(0.8314696123 / C7), + -F(0.3826834324 / C6), -F(0.9807852804 / C7), + -F(0.3826834324 / C6), F(0.9807852804 / C7), + F(0.9238795325 / C6), -F(0.8314696123 / C7), + -F(0.9238795325 / C6), F(0.5555702330 / C7), + F(0.3826834324 / C6), -F(0.1950903220 / C7), +#undef F + +#undef C0 +#undef C1 +#undef C2 +#undef C3 +#undef C4 +#undef C5 +#undef C6 +#undef C7 +}; diff --git a/libavcodec/sbcdsp_data.h b/libavcodec/sbcdsp_data.h new file mode 100644 index 0000000000000..10fad5caa5e0e --- /dev/null +++ b/libavcodec/sbcdsp_data.h @@ -0,0 +1,55 @@ +/* + * Bluetooth low-complexity, subband codec (SBC) + * + * Copyright (C) 2017 Aurelien Jacobs + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2006 Brad Midgley + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * miscellaneous SBC tables + */ + +#ifndef AVCODEC_SBCDSP_DATA_H +#define AVCODEC_SBCDSP_DATA_H + +#include "sbc.h" + +#define SBC_PROTO_FIXED_SCALE 16 +#define SBC_COS_TABLE_FIXED_SCALE 15 + +/* + * Constant tables for the use in SIMD optimized analysis filters + * Each table consists of two parts: + * 1. reordered "proto" table + * 2. reordered "cos" table + * + * Due to non-symmetrical reordering, separate tables for "even" + * and "odd" cases are needed + */ + +extern const int16_t ff_sbcdsp_analysis_consts_fixed4_simd_even[]; +extern const int16_t ff_sbcdsp_analysis_consts_fixed4_simd_odd[]; +extern const int16_t ff_sbcdsp_analysis_consts_fixed8_simd_even[]; +extern const int16_t ff_sbcdsp_analysis_consts_fixed8_simd_odd[]; + +#endif /* AVCODEC_SBCDSP_DATA_H */ diff --git a/libavcodec/sbcenc.c b/libavcodec/sbcenc.c new file mode 100644 index 0000000000000..e2929e22ac52e --- /dev/null +++ b/libavcodec/sbcenc.c @@ -0,0 +1,361 @@ +/* + * Bluetooth low-complexity, subband codec (SBC) + * + * Copyright (C) 2017 Aurelien Jacobs + * Copyright (C) 2012-2013 Intel Corporation + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2008 Brad Midgley + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * SBC encoder implementation + */ + +#include +#include "libavutil/opt.h" +#include "avcodec.h" +#include "internal.h" +#include "profiles.h" +#include "put_bits.h" +#include "sbc.h" +#include "sbcdsp.h" + +typedef struct SBCEncContext { + AVClass *class; + int64_t max_delay; + int msbc; + DECLARE_ALIGNED(SBC_ALIGN, struct sbc_frame, frame); + DECLARE_ALIGNED(SBC_ALIGN, SBCDSPContext, dsp); +} SBCEncContext; + +static int sbc_analyze_audio(SBCDSPContext *s, struct sbc_frame *frame) +{ + int ch, blk; + int16_t *x; + + switch (frame->subbands) { + case 4: + for (ch = 0; ch < frame->channels; ch++) { + x = &s->X[ch][s->position - 4 * + s->increment + frame->blocks * 4]; + for (blk = 0; blk < frame->blocks; + blk += s->increment) { + s->sbc_analyze_4s( + s, x, + frame->sb_sample_f[blk][ch], + frame->sb_sample_f[blk + 1][ch] - + frame->sb_sample_f[blk][ch]); + x -= 4 * s->increment; + } + } + return frame->blocks * 4; + + case 8: + for (ch = 0; ch < frame->channels; ch++) { + x = &s->X[ch][s->position - 8 * + s->increment + frame->blocks * 8]; + for (blk = 0; blk < frame->blocks; + blk += s->increment) { + s->sbc_analyze_8s( + s, x, + frame->sb_sample_f[blk][ch], + frame->sb_sample_f[blk + 1][ch] - + frame->sb_sample_f[blk][ch]); + x -= 8 * s->increment; + } + } + return frame->blocks * 8; + + default: + return AVERROR(EIO); + } +} + +/* + * Packs the SBC frame from frame into the memory in avpkt. + * Returns the length of the packed frame. + */ +static size_t sbc_pack_frame(AVPacket *avpkt, struct sbc_frame *frame, + int joint, bool msbc) +{ + PutBitContext pb; + + /* Will copy the header parts for CRC-8 calculation here */ + uint8_t crc_header[11] = { 0 }; + int crc_pos; + + uint32_t audio_sample; + + int ch, sb, blk; /* channel, subband, block and bit counters */ + int bits[2][8]; /* bits distribution */ + uint32_t levels[2][8]; /* levels are derived from that */ + uint32_t sb_sample_delta[2][8]; + + if (msbc) { + avpkt->data[0] = MSBC_SYNCWORD; + avpkt->data[1] = 0; + avpkt->data[2] = 0; + } else { + avpkt->data[0] = SBC_SYNCWORD; + + avpkt->data[1] = (frame->frequency & 0x03) << 6; + avpkt->data[1] |= (((frame->blocks >> 2) - 1) & 0x03) << 4; + avpkt->data[1] |= (frame->mode & 0x03) << 2; + avpkt->data[1] |= (frame->allocation & 0x01) << 1; + avpkt->data[1] |= ((frame->subbands == 8) & 0x01) << 0; + + avpkt->data[2] = frame->bitpool; + + if (frame->bitpool > frame->subbands << (4 + (frame->mode == STEREO + || frame->mode == JOINT_STEREO))) + return -5; + } + + /* Can't fill in crc yet */ + crc_header[0] = avpkt->data[1]; + crc_header[1] = avpkt->data[2]; + crc_pos = 16; + + init_put_bits(&pb, avpkt->data + 4, avpkt->size); + + if (frame->mode == JOINT_STEREO) { + put_bits(&pb, frame->subbands, joint); + crc_header[crc_pos >> 3] = joint; + crc_pos += frame->subbands; + } + + for (ch = 0; ch < frame->channels; ch++) { + for (sb = 0; sb < frame->subbands; sb++) { + put_bits(&pb, 4, frame->scale_factor[ch][sb] & 0x0F); + crc_header[crc_pos >> 3] <<= 4; + crc_header[crc_pos >> 3] |= frame->scale_factor[ch][sb] & 0x0F; + crc_pos += 4; + } + } + + /* align the last crc byte */ + if (crc_pos % 8) + crc_header[crc_pos >> 3] <<= 8 - (crc_pos % 8); + + avpkt->data[3] = ff_sbc_crc8(frame->crc_ctx, crc_header, crc_pos); + + ff_sbc_calculate_bits(frame, bits); + + for (ch = 0; ch < frame->channels; ch++) { + for (sb = 0; sb < frame->subbands; sb++) { + levels[ch][sb] = ((1 << bits[ch][sb]) - 1) << + (32 - (frame->scale_factor[ch][sb] + + SCALE_OUT_BITS + 2)); + sb_sample_delta[ch][sb] = (uint32_t) 1 << + (frame->scale_factor[ch][sb] + + SCALE_OUT_BITS + 1); + } + } + + for (blk = 0; blk < frame->blocks; blk++) { + for (ch = 0; ch < frame->channels; ch++) { + for (sb = 0; sb < frame->subbands; sb++) { + + if (bits[ch][sb] == 0) + continue; + + audio_sample = ((uint64_t) levels[ch][sb] * + (sb_sample_delta[ch][sb] + + frame->sb_sample_f[blk][ch][sb])) >> 32; + + put_bits(&pb, bits[ch][sb], audio_sample); + } + } + } + + flush_put_bits(&pb); + + return (put_bits_count(&pb) + 7) / 8; +} + +static int sbc_encode_init(AVCodecContext *avctx) +{ + SBCEncContext *sbc = avctx->priv_data; + struct sbc_frame *frame = &sbc->frame; + + if (avctx->profile == FF_PROFILE_SBC_MSBC) + sbc->msbc = 1; + + if (sbc->msbc) { + if (avctx->channels != 1) { + av_log(avctx, AV_LOG_ERROR, "mSBC require mono channel.\n"); + return AVERROR(EINVAL); + } + + if (avctx->sample_rate != 16000) { + av_log(avctx, AV_LOG_ERROR, "mSBC require 16 kHz samplerate.\n"); + return AVERROR(EINVAL); + } + + frame->mode = SBC_MODE_MONO; + frame->subbands = 8; + frame->blocks = MSBC_BLOCKS; + frame->allocation = SBC_AM_LOUDNESS; + frame->bitpool = 26; + + avctx->frame_size = 8 * MSBC_BLOCKS; + } else { + int d; + + if (avctx->global_quality > 255*FF_QP2LAMBDA) { + av_log(avctx, AV_LOG_ERROR, "bitpool > 255 is not allowed.\n"); + return AVERROR(EINVAL); + } + + if (avctx->channels == 1) { + frame->mode = SBC_MODE_MONO; + if (sbc->max_delay <= 3000 || avctx->bit_rate > 270000) + frame->subbands = 4; + else + frame->subbands = 8; + } else { + if (avctx->bit_rate < 180000 || avctx->bit_rate > 420000) + frame->mode = SBC_MODE_JOINT_STEREO; + else + frame->mode = SBC_MODE_STEREO; + if (sbc->max_delay <= 4000 || avctx->bit_rate > 420000) + frame->subbands = 4; + else + frame->subbands = 8; + } + /* sbc algorithmic delay is ((blocks + 10) * subbands - 2) / sample_rate */ + frame->blocks = av_clip(((sbc->max_delay * avctx->sample_rate + 2) + / (1000000 * frame->subbands)) - 10, 4, 16) & ~3; + + frame->allocation = SBC_AM_LOUDNESS; + + d = frame->blocks * ((frame->mode == SBC_MODE_DUAL_CHANNEL) + 1); + frame->bitpool = (((avctx->bit_rate * frame->subbands * frame->blocks) / avctx->sample_rate) + - 4 * frame->subbands * avctx->channels + - (frame->mode == SBC_MODE_JOINT_STEREO)*frame->subbands - 32 + d/2) / d; + if (avctx->global_quality > 0) + frame->bitpool = avctx->global_quality / FF_QP2LAMBDA; + + avctx->frame_size = 4*((frame->subbands >> 3) + 1) * 4*(frame->blocks >> 2); + } + + for (int i = 0; avctx->codec->supported_samplerates[i]; i++) + if (avctx->sample_rate == avctx->codec->supported_samplerates[i]) + frame->frequency = i; + + frame->channels = avctx->channels; + frame->codesize = frame->subbands * frame->blocks * avctx->channels * 2; + frame->crc_ctx = av_crc_get_table(AV_CRC_8_EBU); + + memset(&sbc->dsp.X, 0, sizeof(sbc->dsp.X)); + sbc->dsp.position = (SBC_X_BUFFER_SIZE - frame->subbands * 9) & ~7; + sbc->dsp.increment = sbc->msbc ? 1 : 4; + ff_sbcdsp_init(&sbc->dsp); + + return 0; +} + +static int sbc_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *av_frame, int *got_packet_ptr) +{ + SBCEncContext *sbc = avctx->priv_data; + struct sbc_frame *frame = &sbc->frame; + uint8_t joint = frame->mode == SBC_MODE_JOINT_STEREO; + uint8_t dual = frame->mode == SBC_MODE_DUAL_CHANNEL; + int ret, j = 0; + + int frame_length = 4 + (4 * frame->subbands * frame->channels) / 8 + + ((frame->blocks * frame->bitpool * (1 + dual) + + joint * frame->subbands) + 7) / 8; + + /* input must be large enough to encode a complete frame */ + if (av_frame->nb_samples * frame->channels * 2 < frame->codesize) + return 0; + + if ((ret = ff_alloc_packet2(avctx, avpkt, frame_length, 0)) < 0) + return ret; + + /* Select the needed input data processing function and call it */ + if (frame->subbands == 8) + sbc->dsp.position = sbc->dsp.sbc_enc_process_input_8s( + sbc->dsp.position, av_frame->data[0], sbc->dsp.X, + frame->subbands * frame->blocks, frame->channels); + else + sbc->dsp.position = sbc->dsp.sbc_enc_process_input_4s( + sbc->dsp.position, av_frame->data[0], sbc->dsp.X, + frame->subbands * frame->blocks, frame->channels); + + sbc_analyze_audio(&sbc->dsp, &sbc->frame); + + if (frame->mode == JOINT_STEREO) + j = sbc->dsp.sbc_calc_scalefactors_j(frame->sb_sample_f, + frame->scale_factor, + frame->blocks, + frame->subbands); + else + sbc->dsp.sbc_calc_scalefactors(frame->sb_sample_f, + frame->scale_factor, + frame->blocks, + frame->channels, + frame->subbands); + emms_c(); + sbc_pack_frame(avpkt, frame, j, sbc->msbc); + + *got_packet_ptr = 1; + return 0; +} + +#define OFFSET(x) offsetof(SBCEncContext, x) +#define AE AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + { "sbc_delay", "set maximum algorithmic latency", + OFFSET(max_delay), AV_OPT_TYPE_DURATION, {.i64 = 13000}, 1000,13000, AE }, + { "msbc", "use mSBC mode (wideband speech mono SBC)", + OFFSET(msbc), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AE }, + { NULL }, +}; + +static const AVClass sbc_class = { + .class_name = "sbc encoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_sbc_encoder = { + .name = "sbc", + .long_name = NULL_IF_CONFIG_SMALL("SBC (low-complexity subband codec)"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_SBC, + .priv_data_size = sizeof(SBCEncContext), + .init = sbc_encode_init, + .encode2 = sbc_encode_frame, + .capabilities = AV_CODEC_CAP_SMALL_LAST_FRAME, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, + .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_MONO, + AV_CH_LAYOUT_STEREO, 0}, + .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16, + AV_SAMPLE_FMT_NONE }, + .supported_samplerates = (const int[]) { 16000, 32000, 44100, 48000, 0 }, + .priv_class = &sbc_class, + .profiles = NULL_IF_CONFIG_SMALL(ff_sbc_profiles), +}; diff --git a/libavcodec/sbrdsp_fixed.c b/libavcodec/sbrdsp_fixed.c index 896b2d75c6c6c..57d98da97997f 100644 --- a/libavcodec/sbrdsp_fixed.c +++ b/libavcodec/sbrdsp_fixed.c @@ -133,7 +133,7 @@ static av_always_inline SoftFloat autocorr_calc(int64_t accu) round = 1U << (nz-1); mant = (int)((accu + round) >> nz); - mant = (mant + 0x40)>>7; + mant = (mant + 0x40LL)>>7; mant *= 64; expo = nz + 15; return av_int2sf(mant, 30 - expo); @@ -244,12 +244,14 @@ static void sbr_hf_g_filt_c(int (*Y)[2], const int (*X_high)[40][2], int64_t accu; for (m = 0; m < m_max; m++) { - int64_t r = 1LL << (22-g_filt[m].exp); - accu = (int64_t)X_high[m][ixh][0] * ((g_filt[m].mant + 0x40)>>7); - Y[m][0] = (int)((accu + r) >> (23-g_filt[m].exp)); + if (22 - g_filt[m].exp < 61) { + int64_t r = 1LL << (22-g_filt[m].exp); + accu = (int64_t)X_high[m][ixh][0] * ((g_filt[m].mant + 0x40)>>7); + Y[m][0] = (int)((accu + r) >> (23-g_filt[m].exp)); - accu = (int64_t)X_high[m][ixh][1] * ((g_filt[m].mant + 0x40)>>7); - Y[m][1] = (int)((accu + r) >> (23-g_filt[m].exp)); + accu = (int64_t)X_high[m][ixh][1] * ((g_filt[m].mant + 0x40)>>7); + Y[m][1] = (int)((accu + r) >> (23-g_filt[m].exp)); + } } } diff --git a/libavcodec/scpr.c b/libavcodec/scpr.c index cbe1bc40d9c81..72f59d5917142 100644 --- a/libavcodec/scpr.c +++ b/libavcodec/scpr.c @@ -211,6 +211,10 @@ static int decode_value(SCPRContext *s, unsigned *cnt, unsigned maxc, unsigned s break; c++; } + + if (c >= maxc) + return AVERROR_INVALIDDATA; + if ((ret = s->decode(gb, rc, cumfr, cnt_c, totfr)) < 0) return ret; @@ -442,13 +446,13 @@ static int decompress_i(AVCodecContext *avctx, uint32_t *dst, int linesize) } r = odst[(ly * linesize + lx) * 4] + - odst[((y * linesize + x) + off - z) * 4 + 4] - + odst[((y * linesize + x) + off) * 4 + 4] - odst[((y * linesize + x) + off - z) * 4]; g = odst[(ly * linesize + lx) * 4 + 1] + - odst[((y * linesize + x) + off - z) * 4 + 5] - + odst[((y * linesize + x) + off) * 4 + 5] - odst[((y * linesize + x) + off - z) * 4 + 1]; b = odst[(ly * linesize + lx) * 4 + 2] + - odst[((y * linesize + x) + off - z) * 4 + 6] - + odst[((y * linesize + x) + off) * 4 + 6] - odst[((y * linesize + x) + off - z) * 4 + 2]; clr = ((b & 0xFF) << 16) + ((g & 0xFF) << 8) + (r & 0xFF); dst[y * linesize + x] = clr; @@ -681,6 +685,8 @@ static int decompress_p(AVCodecContext *avctx, return AVERROR_INVALIDDATA; if (bx == 0) { + if (by < 2) + return AVERROR_INVALIDDATA; z = backstep; } else { z = 0; @@ -710,6 +716,8 @@ static int decompress_p(AVCodecContext *avctx, return AVERROR_INVALIDDATA; if (bx == 0) { + if (by < 2) + return AVERROR_INVALIDDATA; z = backstep; } else { z = 0; diff --git a/libavcodec/sheervideo.c b/libavcodec/sheervideo.c index 6f99b5c869398..50c3ebcee72a0 100644 --- a/libavcodec/sheervideo.c +++ b/libavcodec/sheervideo.c @@ -28,6 +28,7 @@ #include "get_bits.h" #include "internal.h" #include "thread.h" +#include "sheervideodata.h" typedef struct SheerVideoContext { unsigned format; @@ -36,1076 +37,6 @@ typedef struct SheerVideoContext { void (*decode_frame)(AVCodecContext *avctx, AVFrame *p, GetBitContext *gb); } SheerVideoContext; -static const uint8_t l_r_rgb[256] = { - 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 7, 7, 8, - 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, - 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, - 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, - 8, 8, 8, 7, 7, 7, 7, 7, 6, 6, 6, 5, 5, 4, 4, 4, -}; - -static const uint8_t l_r_rgbi[256] = { - 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 7, 7, 7, - 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, - 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 4, 4, 4, -}; - -static const uint8_t l_g_rgbi[256] = { - 1, 3, 4, 5, 6, 7, 7, 8, 9, 9, 10, 10, 10, 10, 11, 11, - 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, - 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, - 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, - 11, 11, 11, 10, 10, 10, 9, 9, 9, 8, 8, 7, 6, 5, 5, 3, -}; - -static const uint8_t l_g_rgb[256] = { - 2, 2, 4, 4, 6, 7, 9, 9, 10, 11, 11, 11, 12, 12, 12, 13, - 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, - 13, 13, 12, 12, 12, 11, 11, 11, 10, 9, 9, 8, 6, 4, 3, 3, -}; - -static const uint8_t l_y_ybr[256] = { - 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, - 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, - 10, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 8, 8, - 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 5, 4, 4, 3, -}; - -static const uint8_t l_u_ybr[256] = { - 1, 2, 4, 6, 9, 10, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, - 14, 14, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, - 14, 14, 14, 14, 14, 13, 13, 13, 12, 12, 11, 11, 10, 8, 5, 3, -}; - -static const uint8_t l_y_ybyr[256] = { - 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 7, 7, 8, - 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, - 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, - 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, - 8, 8, 8, 7, 7, 7, 7, 7, 6, 6, 6, 5, 5, 4, 4, 4, -}; - -static const uint8_t l_u_ybyr[256] = { - 1, 2, 4, 6, 8, 9, 10, 10, 11, 11, 12, 12, 12, 13, 13, 14, - 14, 14, 14, 14, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 14, 14, - 14, 14, 13, 13, 13, 12, 12, 11, 11, 10, 10, 9, 8, 7, 6, 3, -}; - -static const uint8_t l_y_byry[256] = { - 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, - 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, - 10, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, - 11, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 8, 8, - 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 5, 4, 4, 3, -}; - -static const uint8_t l_u_byry[256] = { - 1, 2, 4, 6, 8, 9, 9, 10, 11, 11, 12, 12, 13, 13, 13, 14, - 14, 14, 14, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, - 14, 14, 14, 13, 13, 12, 12, 12, 11, 11, 10, 9, 8, 7, 6, 3, -}; - -static const uint8_t l_y_ybr10i[1024] = { - 3, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, -}; - -static const uint8_t l_y_ybr10[1024] = { - 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, - 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, - 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, -}; - -static const uint8_t l_u_ybr10i[1024] = { - 2, 3, 4, 4, 5, 5, 6, 7, 7, 8, 8, 9, 9, 9, 9, 10, - 10, 10, 10, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 10, 10, - 10, 10, 10, 9, 9, 9, 8, 8, 8, 7, 6, 5, 5, 4, 4, 3, -}; - -static const uint8_t l_u_ybr10[1024] = { - 2, 3, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 10, 10, 11, 11, - 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 12, 12, 12, - 12, 11, 11, 11, 10, 10, 9, 9, 8, 8, 7, 6, 5, 4, 4, 3, -}; - -static const uint8_t l_r_rgbx[1024] = { - 4, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, - 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, - 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, -}; - -static const uint8_t l_g_rgbx[1024] = { - 3, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, - 8, 8, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 12, - 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, - 12, 12, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 9, 9, 9, 9, - 8, 7, 7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 5, 4, 4, 4, -}; - -static const uint8_t l_y_yry10[1024] = { - 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, - 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, - 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, -}; - -static const uint8_t l_y_yry10i[1024] = { - 3, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, - 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, -}; - -static const uint8_t l_u_yry10[1024] = { - 2, 3, 3, 4, 5, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, - 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, - 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, - 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, - 10, 10, 10, 10, 9, 9, 9, 8, 8, 7, 7, 6, 5, 4, 4, 3, -}; - -static const uint8_t l_u_yry10i[1024] = { - 2, 4, 4, 4, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, - 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, - 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, - 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 9, 9, 9, - 9, 9, 8, 8, 8, 8, 7, 7, 7, 6, 6, 5, 5, 4, 4, 3, -}; - -static const uint8_t l_y_ybri[256] = { - 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, - 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 8, 8, - 8, 8, 8, 7, 7, 7, 7, 7, 6, 6, 6, 5, 5, 5, 4, 3, -}; - -static const uint8_t l_u_ybri[256] = { - 1, 3, 5, 6, 8, 8, 9, 10, 10, 11, 11, 12, 12, 13, 13, 13, - 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, - 14, 13, 13, 13, 12, 12, 11, 11, 10, 10, 9, 8, 8, 6, 5, 2, -}; - -static const uint8_t l_y_byryi[256] = { - 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, - 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, - 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, - 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 8, 8, - 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 5, 4, 4, 3, -}; - -static const uint8_t l_u_byryi[256] = { - 1, 3, 4, 6, 6, 7, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, - 12, 12, 12, 12, 13, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, - 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, - 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, 13, 12, 12, 12, - 12, 11, 11, 11, 10, 10, 10, 9, 9, 8, 8, 7, 7, 5, 4, 3, -}; - -static const uint8_t l_r_rgbxi[1024] = { - 3, 4, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, - 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, - 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 5, 5, 4, 4, 4, -}; - -static const uint8_t l_g_rgbxi[1024] = { - 2, 3, 4, 4, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, - 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, - 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, - 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, - 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, - 9, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 4, 4, 3, -}; - static void decode_ca4i(AVCodecContext *avctx, AVFrame *p, GetBitContext *gb) { SheerVideoContext *s = avctx->priv_data; diff --git a/libavcodec/sheervideodata.h b/libavcodec/sheervideodata.h new file mode 100644 index 0000000000000..3b6e2f6591256 --- /dev/null +++ b/libavcodec/sheervideodata.h @@ -0,0 +1,1097 @@ +/* + * BitJazz SheerVideo decoder + * Copyright (c) 2016 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_SHEERVIDEODATA_H +#define AVCODEC_SHEERVIDEODATA_H + +#include "libavutil/common.h" + +static const uint8_t l_r_rgb[256] = { + 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 7, 7, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, + 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, + 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, + 8, 8, 8, 7, 7, 7, 7, 7, 6, 6, 6, 5, 5, 4, 4, 4, +}; + +static const uint8_t l_r_rgbi[256] = { + 3, 4, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 7, 7, 7, + 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 8, + 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 5, 5, 4, 4, 4, +}; + +static const uint8_t l_g_rgbi[256] = { + 1, 3, 4, 5, 6, 7, 7, 8, 9, 9, 10, 10, 10, 10, 11, 11, + 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, + 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, + 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, + 11, 11, 11, 10, 10, 10, 9, 9, 9, 8, 8, 7, 6, 5, 5, 3, +}; + +static const uint8_t l_g_rgb[256] = { + 2, 2, 4, 4, 6, 7, 9, 9, 10, 11, 11, 11, 12, 12, 12, 13, + 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, + 13, 13, 12, 12, 12, 11, 11, 11, 10, 9, 9, 8, 6, 4, 3, 3, +}; + +static const uint8_t l_y_ybr[256] = { + 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, + 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, + 10, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 8, 8, + 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 5, 4, 4, 3, +}; + +static const uint8_t l_u_ybr[256] = { + 1, 2, 4, 6, 9, 10, 11, 11, 12, 12, 13, 13, 13, 14, 14, 14, + 14, 14, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, + 14, 14, 14, 14, 14, 13, 13, 13, 12, 12, 11, 11, 10, 8, 5, 3, +}; + +static const uint8_t l_y_ybyr[256] = { + 3, 3, 4, 4, 5, 5, 5, 6, 6, 6, 7, 7, 7, 7, 7, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, + 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, + 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, + 8, 8, 8, 7, 7, 7, 7, 7, 6, 6, 6, 5, 5, 4, 4, 4, +}; + +static const uint8_t l_u_ybyr[256] = { + 1, 2, 4, 6, 8, 9, 10, 10, 11, 11, 12, 12, 12, 13, 13, 14, + 14, 14, 14, 14, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 14, 14, + 14, 14, 13, 13, 13, 12, 12, 11, 11, 10, 10, 9, 8, 7, 6, 3, +}; + +static const uint8_t l_y_byry[256] = { + 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, + 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, + 10, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, + 11, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 8, 8, + 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 6, 5, 4, 4, 3, +}; + +static const uint8_t l_u_byry[256] = { + 1, 2, 4, 6, 8, 9, 9, 10, 11, 11, 12, 12, 13, 13, 13, 14, + 14, 14, 14, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, + 14, 14, 14, 13, 13, 12, 12, 12, 11, 11, 10, 9, 8, 7, 6, 3, +}; + +static const uint8_t l_y_ybr10i[1024] = { + 3, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, +}; + +static const uint8_t l_y_ybr10[1024] = { + 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, + 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, + 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, +}; + +static const uint8_t l_u_ybr10i[1024] = { + 2, 3, 4, 4, 5, 5, 6, 7, 7, 8, 8, 9, 9, 9, 9, 10, + 10, 10, 10, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 10, 10, + 10, 10, 10, 9, 9, 9, 8, 8, 8, 7, 6, 5, 5, 4, 4, 3, +}; + +static const uint8_t l_u_ybr10[1024] = { + 2, 3, 3, 4, 5, 5, 6, 7, 8, 9, 9, 10, 10, 10, 11, 11, + 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 12, 12, 12, + 12, 11, 11, 11, 10, 10, 9, 9, 8, 8, 7, 6, 5, 4, 4, 3, +}; + +static const uint8_t l_r_rgbx[1024] = { + 4, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, +}; + +static const uint8_t l_g_rgbx[1024] = { + 3, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, + 8, 8, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 12, + 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, + 12, 12, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 9, 9, 9, 9, + 8, 7, 7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 5, 4, 4, 4, +}; + +static const uint8_t l_y_yry10[1024] = { + 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, + 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, + 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, +}; + +static const uint8_t l_y_yry10i[1024] = { + 3, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, +}; + +static const uint8_t l_u_yry10[1024] = { + 2, 3, 3, 4, 5, 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, + 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, + 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, + 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, + 10, 10, 10, 10, 9, 9, 9, 8, 8, 7, 7, 6, 5, 4, 4, 3, +}; + +static const uint8_t l_u_yry10i[1024] = { + 2, 4, 4, 4, 5, 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, + 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, + 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, + 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 9, 9, 9, + 9, 9, 8, 8, 8, 8, 7, 7, 7, 6, 6, 5, 5, 4, 4, 3, +}; + +static const uint8_t l_y_ybri[256] = { + 3, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, + 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 8, 8, + 8, 8, 8, 7, 7, 7, 7, 7, 6, 6, 6, 5, 5, 5, 4, 3, +}; + +static const uint8_t l_u_ybri[256] = { + 1, 3, 5, 6, 8, 8, 9, 10, 10, 11, 11, 12, 12, 13, 13, 13, + 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, + 14, 13, 13, 13, 12, 12, 11, 11, 10, 10, 9, 8, 8, 6, 5, 2, +}; + +static const uint8_t l_y_byryi[256] = { + 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, + 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, + 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10, + 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 8, 8, + 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 5, 4, 4, 3, +}; + +static const uint8_t l_u_byryi[256] = { + 1, 3, 4, 6, 6, 7, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, + 12, 12, 12, 12, 13, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, + 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, 15, 15, + 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, 13, 12, 12, 12, + 12, 11, 11, 11, 10, 10, 10, 9, 9, 8, 8, 7, 7, 5, 4, 3, +}; + +static const uint8_t l_r_rgbxi[1024] = { + 3, 4, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, + 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, 8, + 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 6, 5, 5, 4, 4, 4, +}; + +static const uint8_t l_g_rgbxi[1024] = { + 2, 3, 4, 4, 6, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, + 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, + 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, + 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, + 9, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 4, 4, 3, +}; + +#endif /* AVCODEC_SHEERVIDEODATA_H */ diff --git a/libavcodec/simple_idct.c b/libavcodec/simple_idct.c index 1d05b2fe08cb8..78b29c0fe3e03 100644 --- a/libavcodec/simple_idct.c +++ b/libavcodec/simple_idct.c @@ -30,6 +30,8 @@ #include "mathops.h" #include "simple_idct.h" +#define IN_IDCT_DEPTH 16 + #define BIT_DEPTH 8 #include "simple_idct_template.c" #undef BIT_DEPTH @@ -46,6 +48,13 @@ #define BIT_DEPTH 12 #include "simple_idct_template.c" #undef BIT_DEPTH +#undef IN_IDCT_DEPTH + +#define IN_IDCT_DEPTH 32 +#define BIT_DEPTH 10 +#include "simple_idct_template.c" +#undef BIT_DEPTH +#undef IN_IDCT_DEPTH /* 2x4x8 idct */ @@ -115,7 +124,7 @@ void ff_simple_idct248_put(uint8_t *dest, ptrdiff_t line_size, int16_t *block) /* IDCT8 on each line */ for(i=0; i<8; i++) { - idctRowCondDC_8(block + i*8, 0); + idctRowCondDC_int16_8bit(block + i*8, 0); } /* IDCT4 and store */ @@ -188,7 +197,7 @@ void ff_simple_idct84_add(uint8_t *dest, ptrdiff_t line_size, int16_t *block) /* IDCT8 on each line */ for(i=0; i<4; i++) { - idctRowCondDC_8(block + i*8, 0); + idctRowCondDC_int16_8bit(block + i*8, 0); } /* IDCT4 and store */ @@ -208,7 +217,7 @@ void ff_simple_idct48_add(uint8_t *dest, ptrdiff_t line_size, int16_t *block) /* IDCT8 and store */ for(i=0; i<4; i++){ - idctSparseColAdd_8(dest + i, line_size, block + i); + idctSparseColAdd_int16_8bit(dest + i, line_size, block + i); } } diff --git a/libavcodec/simple_idct.h b/libavcodec/simple_idct.h index 2a5e1d7f6dab8..39df2308caa5a 100644 --- a/libavcodec/simple_idct.h +++ b/libavcodec/simple_idct.h @@ -31,20 +31,24 @@ #include #include -void ff_simple_idct_put_8(uint8_t *dest, ptrdiff_t line_size, int16_t *block); -void ff_simple_idct_add_8(uint8_t *dest, ptrdiff_t line_size, int16_t *block); -void ff_simple_idct_8(int16_t *block); +void ff_simple_idct_put_int16_8bit(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_simple_idct_add_int16_8bit(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_simple_idct_int16_8bit(int16_t *block); -void ff_simple_idct_put_10(uint8_t *dest, ptrdiff_t line_size, int16_t *block); -void ff_simple_idct_add_10(uint8_t *dest, ptrdiff_t line_size, int16_t *block); -void ff_simple_idct_10(int16_t *block); +void ff_simple_idct_put_int16_10bit(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_simple_idct_add_int16_10bit(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_simple_idct_int16_10bit(int16_t *block); -void ff_simple_idct_put_12(uint8_t *dest, ptrdiff_t line_size, int16_t *block); -void ff_simple_idct_add_12(uint8_t *dest, ptrdiff_t line_size, int16_t *block); -void ff_simple_idct_12(int16_t *block); +void ff_simple_idct_put_int32_10bit(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_simple_idct_add_int32_10bit(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_simple_idct_int32_10bit(int16_t *block); + +void ff_simple_idct_put_int16_12bit(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_simple_idct_add_int16_12bit(uint8_t *dest, ptrdiff_t line_size, int16_t *block); +void ff_simple_idct_int16_12bit(int16_t *block); /** - * Special version of ff_simple_idct_10() which does dequantization + * Special version of ff_simple_idct_int16_10bit() which does dequantization * and scales by a factor of 2 more between the two IDCTs to account * for larger scale of input coefficients. */ diff --git a/libavcodec/simple_idct_template.c b/libavcodec/simple_idct_template.c index f532313441c05..904263fc7142a 100644 --- a/libavcodec/simple_idct_template.c +++ b/libavcodec/simple_idct_template.c @@ -77,6 +77,10 @@ #define ROW_SHIFT 13 #define COL_SHIFT 18 #define DC_SHIFT 1 +# elif IN_IDCT_DEPTH == 32 +#define ROW_SHIFT 13 +#define COL_SHIFT 21 +#define DC_SHIFT 2 # else #define ROW_SHIFT 12 #define COL_SHIFT 19 @@ -109,11 +113,13 @@ #ifdef EXTRA_SHIFT static inline void FUNC(idctRowCondDC_extrashift)(int16_t *row, int extra_shift) #else -static inline void FUNC(idctRowCondDC)(int16_t *row, int extra_shift) +static inline void FUNC6(idctRowCondDC)(idctin *row, int extra_shift) #endif { SUINT a0, a1, a2, a3, b0, b1, b2, b3; +// TODO: Add DC-only support for int32_t input +#if IN_IDCT_DEPTH == 16 #if HAVE_FAST_64BIT #define ROW0_MASK (0xffffLL << 48 * HAVE_BIGENDIAN) if (((AV_RN64A(row) & ~ROW0_MASK) | AV_RN64A(row+4)) == 0) { @@ -147,6 +153,7 @@ static inline void FUNC(idctRowCondDC)(int16_t *row, int extra_shift) AV_WN32A(row+6, temp); return; } +#endif #endif a0 = (W4 * row[0]) + (1 << (ROW_SHIFT + extra_shift - 1)); @@ -168,7 +175,11 @@ static inline void FUNC(idctRowCondDC)(int16_t *row, int extra_shift) b3 = MUL(W7, row[1]); MAC(b3, -W5, row[3]); +#if IN_IDCT_DEPTH == 32 + if (AV_RN64A(row + 4) | AV_RN64A(row + 6)) { +#else if (AV_RN64A(row + 4)) { +#endif a0 += W4*row[4] + W6*row[6]; a1 += - W4*row[4] - W2*row[6]; a2 += - W4*row[4] + W2*row[6]; @@ -250,8 +261,8 @@ static inline void FUNC(idctRowCondDC)(int16_t *row, int extra_shift) #ifdef EXTRA_SHIFT static inline void FUNC(idctSparseCol_extrashift)(int16_t *col) #else -static inline void FUNC(idctSparseColPut)(pixel *dest, ptrdiff_t line_size, - int16_t *col) +static inline void FUNC6(idctSparseColPut)(pixel *dest, ptrdiff_t line_size, + idctin *col) { SUINT a0, a1, a2, a3, b0, b1, b2, b3; @@ -274,8 +285,8 @@ static inline void FUNC(idctSparseColPut)(pixel *dest, ptrdiff_t line_size, dest[0] = av_clip_pixel((int)(a0 - b0) >> COL_SHIFT); } -static inline void FUNC(idctSparseColAdd)(pixel *dest, ptrdiff_t line_size, - int16_t *col) +static inline void FUNC6(idctSparseColAdd)(pixel *dest, ptrdiff_t line_size, + idctin *col) { int a0, a1, a2, a3, b0, b1, b2, b3; @@ -298,7 +309,7 @@ static inline void FUNC(idctSparseColAdd)(pixel *dest, ptrdiff_t line_size, dest[0] = av_clip_pixel(dest[0] + ((a0 - b0) >> COL_SHIFT)); } -static inline void FUNC(idctSparseCol)(int16_t *col) +static inline void FUNC6(idctSparseCol)(idctin *col) #endif { int a0, a1, a2, a3, b0, b1, b2, b3; @@ -316,21 +327,23 @@ static inline void FUNC(idctSparseCol)(int16_t *col) } #ifndef EXTRA_SHIFT -void FUNC(ff_simple_idct_put)(uint8_t *dest_, ptrdiff_t line_size, int16_t *block) +void FUNC6(ff_simple_idct_put)(uint8_t *dest_, ptrdiff_t line_size, int16_t *block_) { + idctin *block = (idctin *)block_; pixel *dest = (pixel *)dest_; int i; line_size /= sizeof(pixel); for (i = 0; i < 8; i++) - FUNC(idctRowCondDC)(block + i*8, 0); + FUNC6(idctRowCondDC)(block + i*8, 0); for (i = 0; i < 8; i++) - FUNC(idctSparseColPut)(dest + i, line_size, block + i); + FUNC6(idctSparseColPut)(dest + i, line_size, block + i); } -void FUNC(ff_simple_idct_add)(uint8_t *dest_, ptrdiff_t line_size, int16_t *block) +#if IN_IDCT_DEPTH == 16 +void FUNC6(ff_simple_idct_add)(uint8_t *dest_, ptrdiff_t line_size, int16_t *block) { pixel *dest = (pixel *)dest_; int i; @@ -338,20 +351,21 @@ void FUNC(ff_simple_idct_add)(uint8_t *dest_, ptrdiff_t line_size, int16_t *bloc line_size /= sizeof(pixel); for (i = 0; i < 8; i++) - FUNC(idctRowCondDC)(block + i*8, 0); + FUNC6(idctRowCondDC)(block + i*8, 0); for (i = 0; i < 8; i++) - FUNC(idctSparseColAdd)(dest + i, line_size, block + i); + FUNC6(idctSparseColAdd)(dest + i, line_size, block + i); } -void FUNC(ff_simple_idct)(int16_t *block) +void FUNC6(ff_simple_idct)(int16_t *block) { int i; for (i = 0; i < 8; i++) - FUNC(idctRowCondDC)(block + i*8, 0); + FUNC6(idctRowCondDC)(block + i*8, 0); for (i = 0; i < 8; i++) - FUNC(idctSparseCol)(block + i); + FUNC6(idctSparseCol)(block + i); } #endif +#endif diff --git a/libavcodec/smacker.c b/libavcodec/smacker.c index 2d20be9c10e23..61e316916bf20 100644 --- a/libavcodec/smacker.c +++ b/libavcodec/smacker.c @@ -43,6 +43,8 @@ #define SMKTREE_BITS 9 #define SMK_NODE 0x80000000 +#define SMKTREE_DECODE_MAX_RECURSION 32 +#define SMKTREE_DECODE_BIG_MAX_RECURSION 500 typedef struct SmackVContext { AVCodecContext *avctx; @@ -95,10 +97,11 @@ enum SmkBlockTypes { */ static int smacker_decode_tree(GetBitContext *gb, HuffContext *hc, uint32_t prefix, int length) { - if(length > 32 || length > 3*SMKTREE_BITS) { - av_log(NULL, AV_LOG_ERROR, "length too long\n"); + if (length > SMKTREE_DECODE_MAX_RECURSION || length > 3 * SMKTREE_BITS) { + av_log(NULL, AV_LOG_ERROR, "Maximum tree recursion level exceeded.\n"); return AVERROR_INVALIDDATA; } + if(!get_bits1(gb)){ //Leaf if(hc->current >= hc->length){ av_log(NULL, AV_LOG_ERROR, "Tree size exceeded!\n"); @@ -129,12 +132,15 @@ static int smacker_decode_tree(GetBitContext *gb, HuffContext *hc, uint32_t pref /** * Decode header tree */ -static int smacker_decode_bigtree(GetBitContext *gb, HuffContext *hc, DBCtx *ctx, int length) +static int smacker_decode_bigtree(GetBitContext *gb, HuffContext *hc, + DBCtx *ctx, int length) { - if(length > 500) { // Larger length can cause segmentation faults due to too deep recursion. - av_log(NULL, AV_LOG_ERROR, "length too long\n"); + // Larger length can cause segmentation faults due to too deep recursion. + if (length > SMKTREE_DECODE_BIG_MAX_RECURSION) { + av_log(NULL, AV_LOG_ERROR, "Maximum bigtree recursion level exceeded.\n"); return AVERROR_INVALIDDATA; } + if (hc->current + 1 >= hc->length) { av_log(NULL, AV_LOG_ERROR, "Tree size exceeded!\n"); return AVERROR_INVALIDDATA; @@ -279,8 +285,9 @@ static int smacker_decode_header_tree(SmackVContext *smk, GetBitContext *gb, int goto error; } - if (smacker_decode_bigtree(gb, &huff, &ctx, 0) < 0) - err = -1; + res = smacker_decode_bigtree(gb, &huff, &ctx, 0); + if (res < 0) + err = res; skip_bits1(gb); if(ctx.last[0] == -1) ctx.last[0] = huff.current++; if(ctx.last[1] == -1) ctx.last[1] = huff.current++; @@ -600,7 +607,7 @@ static av_cold int smka_decode_init(AVCodecContext *avctx) { if (avctx->channels < 1 || avctx->channels > 2) { av_log(avctx, AV_LOG_ERROR, "invalid number of channels\n"); - return AVERROR(EINVAL); + return AVERROR_INVALIDDATA; } avctx->channel_layout = (avctx->channels==2) ? AV_CH_LAYOUT_STEREO : AV_CH_LAYOUT_MONO; avctx->sample_fmt = avctx->bits_per_coded_sample == 8 ? AV_SAMPLE_FMT_U8 : AV_SAMPLE_FMT_S16; @@ -630,7 +637,7 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data, if (buf_size <= 4) { av_log(avctx, AV_LOG_ERROR, "packet is too small\n"); - return AVERROR(EINVAL); + return AVERROR_INVALIDDATA; } unp_size = AV_RL32(buf); @@ -652,18 +659,19 @@ static int smka_decode_frame(AVCodecContext *avctx, void *data, bits = get_bits1(&gb); if (stereo ^ (avctx->channels != 1)) { av_log(avctx, AV_LOG_ERROR, "channels mismatch\n"); - return AVERROR(EINVAL); + return AVERROR_INVALIDDATA; } if (bits == (avctx->sample_fmt == AV_SAMPLE_FMT_U8)) { av_log(avctx, AV_LOG_ERROR, "sample format mismatch\n"); - return AVERROR(EINVAL); + return AVERROR_INVALIDDATA; } /* get output buffer */ frame->nb_samples = unp_size / (avctx->channels * (bits + 1)); if (unp_size % (avctx->channels * (bits + 1))) { - av_log(avctx, AV_LOG_ERROR, "unp_size %d is odd\n", unp_size); - return AVERROR(EINVAL); + av_log(avctx, AV_LOG_ERROR, + "The buffer does not contain an integer number of samples\n"); + return AVERROR_INVALIDDATA; } if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) return ret; diff --git a/libavcodec/smc.c b/libavcodec/smc.c index 79f9a757a0502..3cb48347378da 100644 --- a/libavcodec/smc.c +++ b/libavcodec/smc.c @@ -438,6 +438,10 @@ static int smc_decode_frame(AVCodecContext *avctx, int pal_size; const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, &pal_size); int ret; + int total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4); + + if (total_blocks / 1024 > avpkt->size) + return AVERROR_INVALIDDATA; bytestream2_init(&s->gb, buf, buf_size); diff --git a/libavcodec/smvjpegdec.c b/libavcodec/smvjpegdec.c index 018e135b30010..7ea82ebfeed5e 100644 --- a/libavcodec/smvjpegdec.c +++ b/libavcodec/smvjpegdec.c @@ -71,7 +71,7 @@ static inline void smv_img_pnt(uint8_t *dst_data[4], uint8_t *src_data[4], src_linesizes[i], h, nlines); } if (desc->flags & AV_PIX_FMT_FLAG_PAL || - desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) + desc->flags & FF_PSEUDOPAL) dst_data[1] = src_data[1]; } @@ -193,7 +193,6 @@ static int smvjpeg_decode_frame(AVCodecContext *avctx, void *data, int *data_siz s->picture[1]->width = avctx->width; s->picture[1]->height = avctx->height; s->picture[1]->format = avctx->pix_fmt; - /* ff_init_buffer_info(avctx, &s->picture[1]); */ smv_img_pnt(s->picture[1]->data, mjpeg_data->data, mjpeg_data->linesize, avctx->pix_fmt, avctx->width, avctx->height, cur_frame); for (i = 0; i < AV_NUM_DATA_POINTERS; i++) diff --git a/libavcodec/snow_dwt.h b/libavcodec/snow_dwt.h index e2d7528056f40..ee699de35ed45 100644 --- a/libavcodec/snow_dwt.h +++ b/libavcodec/snow_dwt.h @@ -24,6 +24,8 @@ #include #include +struct MpegEncContext; + typedef int DWTELEM; typedef short IDWTELEM; diff --git a/libavcodec/snowdec.c b/libavcodec/snowdec.c index b74c468ce32cf..0146a2a4c9ba0 100644 --- a/libavcodec/snowdec.c +++ b/libavcodec/snowdec.c @@ -183,13 +183,22 @@ static int decode_q_branch(SnowContext *s, int level, int x, int y){ int my_context= av_log2(2*FFABS(left->my - top->my)) + 0*av_log2(2*FFABS(tr->my - top->my)); type= get_rac(&s->c, &s->block_state[1 + left->type + top->type]) ? BLOCK_INTRA : 0; - if(type){ + int ld, cbd, crd; pred_mv(s, &mx, &my, 0, left, top, tr); - l += get_symbol(&s->c, &s->block_state[32], 1); + ld = get_symbol(&s->c, &s->block_state[32], 1); + if (ld < -255 || ld > 255) { + return AVERROR_INVALIDDATA; + } + l += ld; if (s->nb_planes > 2) { - cb+= get_symbol(&s->c, &s->block_state[64], 1); - cr+= get_symbol(&s->c, &s->block_state[96], 1); + cbd = get_symbol(&s->c, &s->block_state[64], 1); + crd = get_symbol(&s->c, &s->block_state[96], 1); + if (cbd < -255 || cbd > 255 || crd < -255 || crd > 255) { + return AVERROR_INVALIDDATA; + } + cb += cbd; + cr += crd; } }else{ if(s->ref_frames > 1) @@ -354,9 +363,10 @@ static int decode_header(SnowContext *s){ int htaps, i, sum=0; Plane *p= &s->plane[plane_index]; p->diag_mc= get_rac(&s->c, s->header_state); - htaps= get_symbol(&s->c, s->header_state, 0)*2 + 2; - if((unsigned)htaps >= HTAPS_MAX || htaps==0) + htaps= get_symbol(&s->c, s->header_state, 0); + if((unsigned)htaps >= HTAPS_MAX/2 - 1) return AVERROR_INVALIDDATA; + htaps = htaps*2 + 2; p->htaps= htaps; for(i= htaps/2; i; i--){ p->hcoeff[i]= get_symbol(&s->c, s->header_state, 0) * (1-2*(i&1)); @@ -374,7 +384,7 @@ static int decode_header(SnowContext *s){ } } - s->spatial_decomposition_type+= get_symbol(&s->c, s->header_state, 1); + s->spatial_decomposition_type+= (unsigned)get_symbol(&s->c, s->header_state, 1); if(s->spatial_decomposition_type > 1U){ av_log(s->avctx, AV_LOG_ERROR, "spatial_decomposition_type %d not supported\n", s->spatial_decomposition_type); return AVERROR_INVALIDDATA; @@ -390,13 +400,14 @@ static int decode_header(SnowContext *s){ } - s->qlog += get_symbol(&s->c, s->header_state, 1); - s->mv_scale += get_symbol(&s->c, s->header_state, 1); - s->qbias += get_symbol(&s->c, s->header_state, 1); - s->block_max_depth+= get_symbol(&s->c, s->header_state, 1); - if(s->block_max_depth > 1 || s->block_max_depth < 0){ + s->qlog += (unsigned)get_symbol(&s->c, s->header_state, 1); + s->mv_scale += (unsigned)get_symbol(&s->c, s->header_state, 1); + s->qbias += (unsigned)get_symbol(&s->c, s->header_state, 1); + s->block_max_depth+= (unsigned)get_symbol(&s->c, s->header_state, 1); + if(s->block_max_depth > 1 || s->block_max_depth < 0 || s->mv_scale > 256U){ av_log(s->avctx, AV_LOG_ERROR, "block_max_depth= %d is too large\n", s->block_max_depth); s->block_max_depth= 0; + s->mv_scale = 0; return AVERROR_INVALIDDATA; } if (FFABS(s->qbias) > 127) { @@ -427,6 +438,8 @@ static int decode_blocks(SnowContext *s){ for(y=0; yc.bytestream >= s->c.bytestream_end) + return AVERROR_INVALIDDATA; if ((res = decode_q_branch(s, 0, x, y)) < 0) return res; } diff --git a/libavcodec/snowenc.c b/libavcodec/snowenc.c index 0d800b9f49325..61a658fa4401a 100644 --- a/libavcodec/snowenc.c +++ b/libavcodec/snowenc.c @@ -22,6 +22,7 @@ #include "libavutil/libm.h" #include "libavutil/log.h" #include "libavutil/opt.h" +#include "libavutil/pixdesc.h" #include "avcodec.h" #include "internal.h" #include "snow_dwt.h" @@ -52,12 +53,6 @@ FF_ENABLE_DEPRECATION_WARNINGS av_log(avctx, AV_LOG_ERROR, "The 9/7 wavelet is incompatible with lossless mode.\n"); return AVERROR(EINVAL); } -#if FF_API_MOTION_EST -FF_DISABLE_DEPRECATION_WARNINGS - if (avctx->me_method == ME_ITER) - s->motion_est = FF_ME_ITER; -FF_ENABLE_DEPRECATION_WARNINGS -#endif s->spatial_decomposition_type= s->pred; //FIXME add decorrelator type r transform_type @@ -133,7 +128,13 @@ FF_ENABLE_DEPRECATION_WARNINGS av_log(avctx, AV_LOG_ERROR, "pixel format not supported\n"); return AVERROR_PATCHWELCOME; } - avcodec_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_h_shift, &s->chroma_v_shift); + + ret = av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_h_shift, + &s->chroma_v_shift); + if (ret) { + av_log(avctx, AV_LOG_ERROR, "pixel format invalid or unknown\n"); + return ret; + } ff_set_cmp(&s->mecc, s->mecc.me_cmp, s->avctx->me_cmp); ff_set_cmp(&s->mecc, s->mecc.me_sub_cmp, s->avctx->me_sub_cmp); @@ -178,7 +179,7 @@ static int pix_sum(uint8_t * pix, int line_size, int w, int h) static int pix_norm1(uint8_t * pix, int line_size, int w) { int s, i, j; - uint32_t *sq = ff_square_tab + 256; + const uint32_t *sq = ff_square_tab + 256; s = 0; for (i = 0; i < w; i++) { @@ -1622,11 +1623,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt, s->lambda = 0; }//else keep previous frame's qlog until after motion estimation - if (s->current_picture->data[0] -#if FF_API_EMU_EDGE - && !(s->avctx->flags&CODEC_FLAG_EMU_EDGE) -#endif - ) { + if (s->current_picture->data[0]) { int w = s->avctx->width; int h = s->avctx->height; @@ -1679,11 +1676,6 @@ FF_ENABLE_DEPRECATION_WARNINGS s->m.b8_stride= 2*s->m.mb_width+1; s->m.f_code=1; s->m.pict_type = pic->pict_type; -#if FF_API_MOTION_EST -FF_DISABLE_DEPRECATION_WARNINGS - s->m.me_method= s->avctx->me_method; -FF_ENABLE_DEPRECATION_WARNINGS -#endif s->m.motion_est= s->motion_est; s->m.me.scene_change_score=0; s->m.me.dia_size = avctx->dia_size; diff --git a/libavcodec/svq1enc.c b/libavcodec/svq1enc.c index d78ede72cdae6..80a8af1ef7991 100644 --- a/libavcodec/svq1enc.c +++ b/libavcodec/svq1enc.c @@ -283,19 +283,6 @@ static int svq1_encode_plane(SVQ1EncContext *s, int plane, s->m.b8_stride = 2 * s->m.mb_width + 1; s->m.f_code = 1; s->m.pict_type = s->pict_type; -#if FF_API_MOTION_EST -FF_DISABLE_DEPRECATION_WARNINGS - s->m.me_method = s->avctx->me_method; - if (s->motion_est == FF_ME_EPZS) { - if (s->avctx->me_method == ME_ZERO) - s->motion_est = FF_ME_ZERO; - else if (s->avctx->me_method == ME_EPZS) - s->motion_est = FF_ME_EPZS; - else if (s->avctx->me_method == ME_X1) - s->motion_est = FF_ME_XONE; - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif s->m.motion_est = s->motion_est; s->m.me.scene_change_score = 0; // s->m.out_format = FMT_H263; diff --git a/libavcodec/svq3.c b/libavcodec/svq3.c index a937b2f951349..fc17081ecf412 100644 --- a/libavcodec/svq3.c +++ b/libavcodec/svq3.c @@ -1048,12 +1048,12 @@ static int svq3_decode_slice_header(AVCodecContext *avctx) } memcpy(s->slice_buf, s->gb.buffer + s->gb.index / 8, slice_bytes); - init_get_bits(&s->gb_slice, s->slice_buf, slice_bits); - if (s->watermark_key) { - uint32_t header = AV_RL32(&s->gb_slice.buffer[1]); - AV_WL32(&s->gb_slice.buffer[1], header ^ s->watermark_key); + uint32_t header = AV_RL32(&s->slice_buf[1]); + AV_WL32(&s->slice_buf[1], header ^ s->watermark_key); } + init_get_bits(&s->gb_slice, s->slice_buf, slice_bits); + if (length > 0) { memmove(s->slice_buf, &s->slice_buf[slice_length], length - 1); } diff --git a/libavcodec/tableprint_vlc.h b/libavcodec/tableprint_vlc.h index 675251a836654..3004be3f9c859 100644 --- a/libavcodec/tableprint_vlc.h +++ b/libavcodec/tableprint_vlc.h @@ -35,6 +35,7 @@ #define av_freep(p) while(0) #define AVCODEC_AVCODEC_H #define AVCODEC_INTERNAL_H +#define AV_INPUT_BUFFER_PADDING_SIZE 64 // the value does not matter for this #include "tableprint.h" #include "get_bits.h" #include "mathtables.c" diff --git a/libavcodec/tak.c b/libavcodec/tak.c index d2670e00ff279..8aa956b661e19 100644 --- a/libavcodec/tak.c +++ b/libavcodec/tak.c @@ -90,7 +90,7 @@ int ff_tak_check_crc(const uint8_t *buf, unsigned int buf_size) return 0; } -void avpriv_tak_parse_streaminfo(GetBitContext *gb, TAKStreamInfo *s) +void ff_tak_parse_streaminfo(TAKStreamInfo *s, GetBitContext *gb) { uint64_t channel_mask = 0; int frame_type, i; @@ -125,6 +125,19 @@ void avpriv_tak_parse_streaminfo(GetBitContext *gb, TAKStreamInfo *s) s->frame_samples = tak_get_nb_samples(s->sample_rate, frame_type); } +int avpriv_tak_parse_streaminfo(TAKStreamInfo *s, const uint8_t *buf, int size) +{ + GetBitContext gb; + int ret = init_get_bits8(&gb, buf, size); + + if (ret < 0) + return AVERROR_INVALIDDATA; + + ff_tak_parse_streaminfo(s, &gb); + + return 0; +} + int ff_tak_decode_frame_header(AVCodecContext *avctx, GetBitContext *gb, TAKStreamInfo *ti, int log_level_offset) { @@ -144,7 +157,7 @@ int ff_tak_decode_frame_header(AVCodecContext *avctx, GetBitContext *gb, } if (ti->flags & TAK_FRAME_FLAG_HAS_INFO) { - avpriv_tak_parse_streaminfo(gb, ti); + ff_tak_parse_streaminfo(ti, gb); if (get_bits(gb, 6)) skip_bits(gb, 25); diff --git a/libavcodec/tak.h b/libavcodec/tak.h index 4fa1239093bc9..dc45a8c070897 100644 --- a/libavcodec/tak.h +++ b/libavcodec/tak.h @@ -143,10 +143,14 @@ int ff_tak_check_crc(const uint8_t *buf, unsigned int buf_size); /** * Parse the Streaminfo metadata block. - * @param[in] gb pointer to GetBitContext * @param[out] s storage for parsed information + * @param[in] buf input buffer + * @param[in] size size of input buffer in bytes + * @return non-zero on error, 0 if OK */ -void avpriv_tak_parse_streaminfo(GetBitContext *gb, TAKStreamInfo *s); +int avpriv_tak_parse_streaminfo(TAKStreamInfo *s, const uint8_t *buf, int size); + +void ff_tak_parse_streaminfo(TAKStreamInfo *s, GetBitContext *gb); /** * Validate and decode a frame header. diff --git a/libavcodec/tests/.gitignore b/libavcodec/tests/.gitignore index 7f9e3825b6148..350fb2990cd62 100644 --- a/libavcodec/tests/.gitignore +++ b/libavcodec/tests/.gitignore @@ -14,6 +14,7 @@ /mathops /mjpegenc_huffman /motion +/mpeg12framerate /options /rangecoder /snowenc diff --git a/libavcodec/tests/codec_desc.c b/libavcodec/tests/codec_desc.c new file mode 100644 index 0000000000000..c9b3497343af0 --- /dev/null +++ b/libavcodec/tests/codec_desc.c @@ -0,0 +1,45 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavcodec/avcodec.h" + +int main(int argc, char **argv) +{ + const AVCodecDescriptor *old_desc = NULL, *desc; + + while (desc = avcodec_descriptor_next(old_desc)) { + if (old_desc && old_desc->id >= desc->id) { + av_log(NULL, AV_LOG_FATAL, "Unsorted codec_descriptors '%s' and '%s'.\n", old_desc->name, desc->name); + return 1; + } + + if (avcodec_descriptor_get(desc->id) != desc) { + av_log(NULL, AV_LOG_FATAL, "avcodec_descriptor_get() failed with '%s'.\n", desc->name); + return 1; + } + + if (avcodec_descriptor_get_by_name(desc->name) != desc) { + av_log(NULL, AV_LOG_FATAL, "avcodec_descriptor_get_by_name() failed with '%s'.\n", desc->name); + return 1; + } + + old_desc = desc; + } + + return 0; +} diff --git a/libavcodec/tests/dct.c b/libavcodec/tests/dct.c index b44c66f427494..e8fa4a3cc1a40 100644 --- a/libavcodec/tests/dct.c +++ b/libavcodec/tests/dct.c @@ -82,9 +82,9 @@ static void ff_prores_idct_wrap(int16_t *dst){ static const struct algo idct_tab[] = { { "REF-DBL", ff_ref_idct, FF_IDCT_PERM_NONE }, { "INT", ff_j_rev_dct, FF_IDCT_PERM_LIBMPEG2 }, - { "SIMPLE-C", ff_simple_idct_8, FF_IDCT_PERM_NONE }, - { "SIMPLE-C10", ff_simple_idct_10, FF_IDCT_PERM_NONE }, - { "SIMPLE-C12", ff_simple_idct_12, FF_IDCT_PERM_NONE, 0, 1 }, + { "SIMPLE-C", ff_simple_idct_int16_8bit, FF_IDCT_PERM_NONE }, + { "SIMPLE-C10", ff_simple_idct_int16_10bit, FF_IDCT_PERM_NONE }, + { "SIMPLE-C12", ff_simple_idct_int16_12bit, FF_IDCT_PERM_NONE, 0, 1 }, { "PR-C", ff_prores_idct_wrap, FF_IDCT_PERM_NONE, 0, 1 }, #if CONFIG_FAANIDCT { "FAANI", ff_faanidct, FF_IDCT_PERM_NONE }, diff --git a/libavcodec/tests/mpeg12framerate.c b/libavcodec/tests/mpeg12framerate.c new file mode 100644 index 0000000000000..595bdb278a0ed --- /dev/null +++ b/libavcodec/tests/mpeg12framerate.c @@ -0,0 +1,87 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavcodec/mpeg12.h" +#include "libavcodec/mpeg12data.h" + +int main(void) +{ + int i; + +#define TEST_MATCH(frame_rate, code, ext_n, ext_d) do { \ + AVRational fr = frame_rate; \ + int c, n, d; \ + ff_mpeg12_find_best_frame_rate(fr, &c, &n, &d, 0); \ + if (c != code || n != ext_n || d != ext_d) { \ + av_log(NULL, AV_LOG_ERROR, "Failed to match %d/%d: " \ + "code = %d, ext_n = %d, ext_d = %d.\n", \ + fr.num, fr.den, c, n, d); \ + return 1; \ + } \ + } while (0) +#define TEST_EXACT(frn, frd) do { \ + AVRational fr = (AVRational) { frn, frd }; \ + int c, n, d; \ + ff_mpeg12_find_best_frame_rate(fr, &c, &n, &d, 0); \ + if (av_cmp_q(fr, av_mul_q(ff_mpeg12_frame_rate_tab[c], \ + (AVRational) { n + 1, d + 1 })) != 0) { \ + av_log(NULL, AV_LOG_ERROR, "Failed to find exact %d/%d: " \ + "code = %d, ext_n = %d, ext_d = %d.\n", \ + fr.num, fr.den, c, n, d); \ + return 1; \ + } \ + } while (0) + + // Framerates in the table must be chosen exactly. + for (i = 1; i <= 8; i++) + TEST_MATCH(ff_mpeg12_frame_rate_tab[i], i, 0, 0); + + // As should the same ones with small perturbations. + // (1/1000 used here to be smaller than half the difference + // between 24 and 24000/1001.) + for (i = 1; i <= 8; i++) { + TEST_MATCH(av_sub_q(ff_mpeg12_frame_rate_tab[i], + (AVRational) { 1, 1000 }), i, 0, 0); + TEST_MATCH(av_add_q(ff_mpeg12_frame_rate_tab[i], + (AVRational) { 1, 1000 }), i, 0, 0); + } + + // Exactly constructable framerates should be exact. Note that some + // values can be made in multiple ways (e.g. 12 = 24 / 2 == 60 / 5), + // and there is no reason to favour any particular choice. + TEST_EXACT( 1, 1); + TEST_EXACT( 2, 1); + TEST_EXACT( 12, 1); + TEST_EXACT( 15000, 1001); + TEST_EXACT( 15, 1); + TEST_EXACT( 120, 1); + TEST_EXACT(120000, 1001); + TEST_EXACT( 200, 1); + TEST_EXACT( 240, 1); + + // Values higher than 240 (the highest representable, as 60 * 4 / 1) + // should be mapped to 240. + for (i = 240; i < 1000; i += 10) + TEST_MATCH(((AVRational) { i, 1 }), 8, 3, 0); + // Values lower than 24000/32032 (the lowest representable, as + // 24000/1001 * 1 / 32) should be mapped to 24000/32032. + for (i = 74; i > 0; i--) + TEST_MATCH(((AVRational) { i, 100 }), 1, 0, 31); + + return 0; +} diff --git a/libavcodec/tests/utils.c b/libavcodec/tests/utils.c index e2891fb389fdf..f6ba7fe66e3f9 100644 --- a/libavcodec/tests/utils.c +++ b/libavcodec/tests/utils.c @@ -21,7 +21,6 @@ int main(void){ AVCodec *codec = NULL; int ret = 0; - avcodec_register_all(); while (codec = av_codec_next(codec)) { if (av_codec_is_encoder(codec)) { diff --git a/libavcodec/texturedsp.c b/libavcodec/texturedsp.c index 90b1eb4f115d1..b7dd8baa12185 100644 --- a/libavcodec/texturedsp.c +++ b/libavcodec/texturedsp.c @@ -413,7 +413,7 @@ static int dxt5ys_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) static inline void rgtc_block_internal(uint8_t *dst, ptrdiff_t stride, const uint8_t *block, - const int *color_tab) + const int *color_tab, int mono, int offset, int pix_size) { uint8_t indices[16]; int x, y; @@ -429,14 +429,20 @@ static inline void rgtc_block_internal(uint8_t *dst, ptrdiff_t stride, int i = indices[x + y * 4]; /* Interval expansion from [-1 1] or [0 1] to [0 255]. */ int c = color_tab[i]; - uint32_t pixel = RGBA(c, c, c, 255U); - AV_WL32(dst + x * 4 + y * stride, pixel); + + if (mono){ + dst [x * pix_size + y * stride + offset] = (uint8_t)c; + } + else{ + uint32_t pixel = RGBA(c, c, c, 255U); + AV_WL32(dst + x * pix_size + y * stride, pixel); + } } } } static inline void rgtc1_block_internal(uint8_t *dst, ptrdiff_t stride, - const uint8_t *block, int sign) + const uint8_t *block, int sign, int mono, int offset, int pix_size) { int color_table[8]; int r0, r1; @@ -472,7 +478,7 @@ static inline void rgtc1_block_internal(uint8_t *dst, ptrdiff_t stride, color_table[7] = 255; /* max range */ // bit code 111 } - rgtc_block_internal(dst, stride, block, color_table); + rgtc_block_internal(dst, stride, block, color_table, mono, offset, pix_size); } /** @@ -486,7 +492,7 @@ static inline void rgtc1_block_internal(uint8_t *dst, ptrdiff_t stride, */ static int rgtc1s_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) { - rgtc1_block_internal(dst, stride, block, 1); + rgtc1_block_internal(dst, stride, block, 1, 0, 0, 4); return 8; } @@ -502,7 +508,39 @@ static int rgtc1s_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) */ static int rgtc1u_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) { - rgtc1_block_internal(dst, stride, block, 0); + rgtc1_block_internal(dst, stride, block, 0, 0, 0, 4); + + return 8; +} + +/** + * Decompress one block of a RGTC1 texture with unsigned components + * and overwrite the alpha component in 'dst' (RGBA data). + * + * @param dst output buffer. + * @param stride scanline in bytes. + * @param block block to decompress. + * @return how much texture data has been consumed. + */ +static int rgtc1u_alpha_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) +{ + rgtc1_block_internal(dst, stride, block, 0, 1, 3, 4); + + return 8; +} + +/** + * Decompress one block of a RGTC1 texture with unsigned components + * to Gray 8. + * + * @param dst output buffer. + * @param stride scanline in bytes. + * @param block block to decompress. + * @return how much texture data has been consumed. + */ +static int rgtc1u_gray_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) +{ + rgtc1_block_internal(dst, stride, block, 0, 1, 0, 1); return 8; } @@ -516,8 +554,8 @@ static inline void rgtc2_block_internal(uint8_t *dst, ptrdiff_t stride, int x, y; /* Decompress the two channels separately and interleave them afterwards. */ - rgtc1_block_internal(c0, 16, block, sign); - rgtc1_block_internal(c1, 16, block + 8, sign); + rgtc1_block_internal(c0, 16, block, sign, 0, 0, 4); + rgtc1_block_internal(c1, 16, block + 8, sign, 0, 0, 4); /* B is rebuilt exactly like a normal map. */ for (y = 0; y < 4; y++) { @@ -598,17 +636,19 @@ static int dxn3dc_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) av_cold void ff_texturedsp_init(TextureDSPContext *c) { - c->dxt1_block = dxt1_block; - c->dxt1a_block = dxt1a_block; - c->dxt2_block = dxt2_block; - c->dxt3_block = dxt3_block; - c->dxt4_block = dxt4_block; - c->dxt5_block = dxt5_block; - c->dxt5y_block = dxt5y_block; - c->dxt5ys_block = dxt5ys_block; - c->rgtc1s_block = rgtc1s_block; - c->rgtc1u_block = rgtc1u_block; - c->rgtc2s_block = rgtc2s_block; - c->rgtc2u_block = rgtc2u_block; - c->dxn3dc_block = dxn3dc_block; + c->dxt1_block = dxt1_block; + c->dxt1a_block = dxt1a_block; + c->dxt2_block = dxt2_block; + c->dxt3_block = dxt3_block; + c->dxt4_block = dxt4_block; + c->dxt5_block = dxt5_block; + c->dxt5y_block = dxt5y_block; + c->dxt5ys_block = dxt5ys_block; + c->rgtc1s_block = rgtc1s_block; + c->rgtc1u_block = rgtc1u_block; + c->rgtc1u_gray_block = rgtc1u_gray_block; + c->rgtc1u_alpha_block = rgtc1u_alpha_block; + c->rgtc2s_block = rgtc2s_block; + c->rgtc2u_block = rgtc2u_block; + c->dxn3dc_block = dxn3dc_block; } diff --git a/libavcodec/texturedsp.h b/libavcodec/texturedsp.h index 26f3b6473fc1e..90ceb2b6aa530 100644 --- a/libavcodec/texturedsp.h +++ b/libavcodec/texturedsp.h @@ -43,19 +43,21 @@ #define TEXTURE_BLOCK_H 4 typedef struct TextureDSPContext { - int (*dxt1_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*dxt1a_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*dxt2_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*dxt3_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*dxt4_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*dxt5_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*dxt5y_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*dxt5ys_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*rgtc1s_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*rgtc1u_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*rgtc2s_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*rgtc2u_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block); - int (*dxn3dc_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*dxt1_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*dxt1a_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*dxt2_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*dxt3_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*dxt4_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*dxt5_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*dxt5y_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*dxt5ys_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*rgtc1s_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*rgtc1u_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*rgtc1u_gray_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*rgtc1u_alpha_block)(uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*rgtc2s_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*rgtc2u_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); + int (*dxn3dc_block) (uint8_t *dst, ptrdiff_t stride, const uint8_t *block); } TextureDSPContext; void ff_texturedsp_init(TextureDSPContext *c); diff --git a/libavcodec/texturedspenc.c b/libavcodec/texturedspenc.c index 8b2863033b6a5..3d68e0cf39d98 100644 --- a/libavcodec/texturedspenc.c +++ b/libavcodec/texturedspenc.c @@ -647,9 +647,26 @@ static int dxt5ys_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) return 16; } +/** + * Compress one block of RGBA pixels in a RGTC1U texture and store the + * resulting bytes in 'dst'. Use the alpha channel of the input image. + * + * @param dst output buffer. + * @param stride scanline in bytes. + * @param block block to compress. + * @return how much texture data has been written. + */ +static int rgtc1u_alpha_block(uint8_t *dst, ptrdiff_t stride, const uint8_t *block) +{ + compress_alpha(dst, stride, block); + + return 8; +} + av_cold void ff_texturedspenc_init(TextureDSPContext *c) { - c->dxt1_block = dxt1_block; - c->dxt5_block = dxt5_block; - c->dxt5ys_block = dxt5ys_block; + c->dxt1_block = dxt1_block; + c->dxt5_block = dxt5_block; + c->dxt5ys_block = dxt5ys_block; + c->rgtc1u_alpha_block = rgtc1u_alpha_block; } diff --git a/libavcodec/thread.h b/libavcodec/thread.h index 318619316c988..540135fbc922e 100644 --- a/libavcodec/thread.h +++ b/libavcodec/thread.h @@ -29,7 +29,6 @@ #include "libavutil/buffer.h" -#include "config.h" #include "avcodec.h" typedef struct ThreadFrame { diff --git a/libavcodec/trace_headers_bsf.c b/libavcodec/trace_headers_bsf.c new file mode 100644 index 0000000000000..94a3ef72a2224 --- /dev/null +++ b/libavcodec/trace_headers_bsf.c @@ -0,0 +1,117 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/avstring.h" +#include "libavutil/common.h" +#include "libavutil/log.h" + +#include "bsf.h" +#include "cbs.h" + + +typedef struct TraceHeadersContext { + CodedBitstreamContext *cbc; +} TraceHeadersContext; + + +static int trace_headers_init(AVBSFContext *bsf) +{ + TraceHeadersContext *ctx = bsf->priv_data; + int err; + + err = ff_cbs_init(&ctx->cbc, bsf->par_in->codec_id, bsf); + if (err < 0) + return err; + + ctx->cbc->trace_enable = 1; + ctx->cbc->trace_level = AV_LOG_INFO; + + if (bsf->par_in->extradata) { + CodedBitstreamFragment ps; + + av_log(bsf, AV_LOG_INFO, "Extradata\n"); + + err = ff_cbs_read_extradata(ctx->cbc, &ps, bsf->par_in); + if (err < 0) { + av_log(bsf, AV_LOG_ERROR, "Failed to read extradata.\n"); + return err; + } + + ff_cbs_fragment_uninit(ctx->cbc, &ps); + } + + return 0; +} + +static void trace_headers_close(AVBSFContext *bsf) +{ + TraceHeadersContext *ctx = bsf->priv_data; + + ff_cbs_close(&ctx->cbc); +} + +static int trace_headers(AVBSFContext *bsf, AVPacket *pkt) +{ + TraceHeadersContext *ctx = bsf->priv_data; + CodedBitstreamFragment au; + char tmp[256] = { 0 }; + int err; + + err = ff_bsf_get_packet_ref(bsf, pkt); + if (err < 0) + return err; + + if (pkt->flags & AV_PKT_FLAG_KEY) + av_strlcat(tmp, ", key frame", sizeof(tmp)); + if (pkt->flags & AV_PKT_FLAG_CORRUPT) + av_strlcat(tmp, ", corrupt", sizeof(tmp)); + + if (pkt->pts != AV_NOPTS_VALUE) + av_strlcatf(tmp, sizeof(tmp), ", pts %"PRId64, pkt->pts); + else + av_strlcat(tmp, ", no pts", sizeof(tmp)); + if (pkt->dts != AV_NOPTS_VALUE) + av_strlcatf(tmp, sizeof(tmp), ", dts %"PRId64, pkt->dts); + else + av_strlcat(tmp, ", no dts", sizeof(tmp)); + if (pkt->duration > 0) + av_strlcatf(tmp, sizeof(tmp), ", duration %"PRId64, pkt->duration); + + av_log(bsf, AV_LOG_INFO, "Packet: %d bytes%s.\n", pkt->size, tmp); + + err = ff_cbs_read_packet(ctx->cbc, &au, pkt); + if (err < 0) { + av_packet_unref(pkt); + return err; + } + + ff_cbs_fragment_uninit(ctx->cbc, &au); + + return 0; +} + +const AVBitStreamFilter ff_trace_headers_bsf = { + .name = "trace_headers", + .priv_data_size = sizeof(TraceHeadersContext), + .init = &trace_headers_init, + .close = &trace_headers_close, + .filter = &trace_headers, + .codec_ids = ff_cbs_all_codec_ids, +}; diff --git a/libavcodec/truemotion2.c b/libavcodec/truemotion2.c index f077f0e4bd990..f7dbe047c78a8 100644 --- a/libavcodec/truemotion2.c +++ b/libavcodec/truemotion2.c @@ -63,6 +63,7 @@ typedef struct TM2Context { AVFrame *pic; GetBitContext gb; + int error; BswapDSPContext bdsp; uint8_t *buffer; @@ -398,6 +399,7 @@ static inline int GET_TOK(TM2Context *ctx,int type) { if (ctx->tok_ptrs[type] >= ctx->tok_lens[type]) { av_log(ctx->avctx, AV_LOG_ERROR, "Read token from stream %i out of bounds (%i>=%i)\n", type, ctx->tok_ptrs[type], ctx->tok_lens[type]); + ctx->error = 1; return 0; } if (type <= TM2_MOT) { @@ -441,8 +443,8 @@ static inline int GET_TOK(TM2Context *ctx,int type) /* recalculate last and delta values for next blocks */ #define TM2_RECALC_BLOCK(CHR, stride, last, CD) {\ - CD[0] = CHR[1] - last[1];\ - CD[1] = (int)CHR[stride + 1] - (int)CHR[1];\ + CD[0] = (unsigned)CHR[ 1] - (unsigned)last[1];\ + CD[1] = (unsigned)CHR[stride + 1] - (unsigned) CHR[1];\ last[0] = (int)CHR[stride + 0];\ last[1] = (int)CHR[stride + 1];} @@ -809,6 +811,8 @@ static int tm2_decode_blocks(TM2Context *ctx, AVFrame *p) default: av_log(ctx->avctx, AV_LOG_ERROR, "Skipping unknown block type %i\n", type); } + if (ctx->error) + return AVERROR_INVALIDDATA; } } @@ -889,6 +893,8 @@ static int decode_frame(AVCodecContext *avctx, int offset = TM2_HEADER_SIZE; int i, t, ret; + l->error = 0; + av_fast_padded_malloc(&l->buffer, &l->buffer_size, buf_size); if (!l->buffer) { av_log(avctx, AV_LOG_ERROR, "Cannot allocate temporary buffer\n"); diff --git a/libavcodec/truemotion2rt.c b/libavcodec/truemotion2rt.c index d63918742dbe1..9df0b527bbdfb 100644 --- a/libavcodec/truemotion2rt.c +++ b/libavcodec/truemotion2rt.c @@ -116,6 +116,9 @@ static int truemotion2rt_decode_frame(AVCodecContext *avctx, void *data, if (ret < 0) return ret; + if (avctx->width / s->hscale * avctx->height * s->delta_size > avpkt->size * 8LL * 4) + return AVERROR_INVALIDDATA; + ret = init_get_bits8(gb, avpkt->data + ret, avpkt->size - ret); if (ret < 0) return ret; diff --git a/libavcodec/ulti.c b/libavcodec/ulti.c index e6f43749811cc..9e4c088b101c7 100644 --- a/libavcodec/ulti.c +++ b/libavcodec/ulti.c @@ -50,6 +50,8 @@ static av_cold int ulti_decode_init(AVCodecContext *avctx) s->width = avctx->width; s->height = avctx->height; s->blocks = (s->width / 8) * (s->height / 8); + if (s->blocks == 0) + return AVERROR_INVALIDDATA; avctx->pix_fmt = AV_PIX_FMT_YUV410P; s->ulti_codebook = ulti_codebook; diff --git a/libavcodec/utils.c b/libavcodec/utils.c index 9551f312e7224..59d41ccbb64db 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -26,7 +26,6 @@ */ #include "config.h" -#include "libavutil/atomic.h" #include "libavutil/attributes.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" @@ -45,8 +44,8 @@ #include "libavutil/thread.h" #include "avcodec.h" #include "decode.h" +#include "hwaccel.h" #include "libavutil/opt.h" -#include "me_cmp.h" #include "mpegvideo.h" #include "thread.h" #include "frame_thread_encoder.h" @@ -56,6 +55,7 @@ #include "version.h" #include #include +#include #include #include #if CONFIG_ICONV @@ -65,58 +65,7 @@ #include "libavutil/ffversion.h" const char av_codec_ffversion[] = "FFmpeg version " FFMPEG_VERSION; -#if HAVE_PTHREADS || HAVE_W32THREADS || HAVE_OS2THREADS -static int default_lockmgr_cb(void **arg, enum AVLockOp op) -{ - void * volatile * mutex = arg; - int err; - - switch (op) { - case AV_LOCK_CREATE: - return 0; - case AV_LOCK_OBTAIN: - if (!*mutex) { - pthread_mutex_t *tmp = av_malloc(sizeof(pthread_mutex_t)); - if (!tmp) - return AVERROR(ENOMEM); - if ((err = pthread_mutex_init(tmp, NULL))) { - av_free(tmp); - return AVERROR(err); - } - if (avpriv_atomic_ptr_cas(mutex, NULL, tmp)) { - pthread_mutex_destroy(tmp); - av_free(tmp); - } - } - - if ((err = pthread_mutex_lock(*mutex))) - return AVERROR(err); - - return 0; - case AV_LOCK_RELEASE: - if ((err = pthread_mutex_unlock(*mutex))) - return AVERROR(err); - - return 0; - case AV_LOCK_DESTROY: - if (*mutex) - pthread_mutex_destroy(*mutex); - av_free(*mutex); - avpriv_atomic_ptr_cas(mutex, *mutex, NULL); - return 0; - } - return 1; -} -static int (*lockmgr_cb)(void **mutex, enum AVLockOp op) = default_lockmgr_cb; -#else -static int (*lockmgr_cb)(void **mutex, enum AVLockOp op) = NULL; -#endif - - -volatile int ff_avcodec_locked; -static int volatile entangled_thread_counter = 0; -static void *codec_mutex; -static void *avformat_mutex; +static AVMutex codec_mutex = AV_MUTEX_INITIALIZER; void av_fast_padded_malloc(void *ptr, unsigned int *size, size_t min_size) { @@ -142,30 +91,6 @@ void av_fast_padded_mallocz(void *ptr, unsigned int *size, size_t min_size) memset(*p, 0, min_size + AV_INPUT_BUFFER_PADDING_SIZE); } -/* encoder management */ -static AVCodec *first_avcodec = NULL; -static AVCodec **last_avcodec = &first_avcodec; - -AVCodec *av_codec_next(const AVCodec *c) -{ - if (c) - return c->next; - else - return first_avcodec; -} - -static av_cold void avcodec_init(void) -{ - static int initialized = 0; - - if (initialized != 0) - return; - initialized = 1; - - if (CONFIG_ME_CMP) - ff_me_cmp_init_static(); -} - int av_codec_is_encoder(const AVCodec *codec) { return codec && (codec->encode_sub || codec->encode2 ||codec->send_frame); @@ -176,38 +101,6 @@ int av_codec_is_decoder(const AVCodec *codec) return codec && (codec->decode || codec->receive_frame); } -av_cold void avcodec_register(AVCodec *codec) -{ - AVCodec **p; - avcodec_init(); - p = last_avcodec; - codec->next = NULL; - - while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, codec)) - p = &(*p)->next; - last_avcodec = &codec->next; - - if (codec->init_static_data) - codec->init_static_data(codec); -} - -#if FF_API_EMU_EDGE -unsigned avcodec_get_edge_width(void) -{ - return EDGE_WIDTH; -} -#endif - -#if FF_API_SET_DIMENSIONS -void avcodec_set_dimensions(AVCodecContext *s, int width, int height) -{ - int ret = ff_set_dimensions(s, width, height); - if (ret < 0) { - av_log(s, AV_LOG_WARNING, "Failed to set dimensions %d %d\n", width, height); - } -} -#endif - int ff_set_dimensions(AVCodecContext *s, int width, int height) { int ret = av_image_check_size2(width, height, s->max_pixels, AV_PIX_FMT_NONE, 0, s); @@ -419,7 +312,10 @@ void avcodec_align_dimensions2(AVCodecContext *s, int *width, int *height, *width = FFALIGN(*width, w_align); *height = FFALIGN(*height, h_align); - if (s->codec_id == AV_CODEC_ID_H264 || s->lowres) { + if (s->codec_id == AV_CODEC_ID_H264 || s->lowres || + s->codec_id == AV_CODEC_ID_VP5 || s->codec_id == AV_CODEC_ID_VP6 || + s->codec_id == AV_CODEC_ID_VP6F || s->codec_id == AV_CODEC_ID_VP6A + ) { // some of the optimized chroma MC reads one line too much // which is also done in mpeg decoders with lowres > 0 *height += 2; @@ -569,6 +465,7 @@ enum AVPixelFormat avpriv_find_pix_fmt(const PixelFormatTag *tags, return AV_PIX_FMT_NONE; } +#if FF_API_CODEC_GET_SET MAKE_ACCESSORS(AVCodecContext, codec, AVRational, pkt_timebase) MAKE_ACCESSORS(AVCodecContext, codec, const AVCodecDescriptor *, codec_descriptor) MAKE_ACCESSORS(AVCodecContext, codec, int, lowres) @@ -584,6 +481,7 @@ int av_codec_get_max_lowres(const AVCodec *codec) { return codec->max_lowres; } +#endif int avpriv_codec_get_cap_skip_frame_fill_param(const AVCodec *codec){ return !!(codec->caps_internal & FF_CODEC_CAP_SKIP_FRAME_FILL_PARAM); @@ -612,6 +510,19 @@ static int64_t get_bit_rate(AVCodecContext *ctx) return bit_rate; } + +static void ff_lock_avcodec(AVCodecContext *log_ctx, const AVCodec *codec) +{ + if (!(codec->caps_internal & FF_CODEC_CAP_INIT_THREADSAFE) && codec->init) + ff_mutex_lock(&codec_mutex); +} + +static void ff_unlock_avcodec(const AVCodec *codec) +{ + if (!(codec->caps_internal & FF_CODEC_CAP_INIT_THREADSAFE) && codec->init) + ff_mutex_unlock(&codec_mutex); +} + int attribute_align_arg ff_codec_open2_recursive(AVCodecContext *avctx, const AVCodec *codec, AVDictionary **options) { int ret = 0; @@ -651,11 +562,9 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code if (options) av_dict_copy(&tmp, *options, 0); - ret = ff_lock_avcodec(avctx, codec); - if (ret < 0) - return ret; + ff_lock_avcodec(avctx, codec); - avctx->internal = av_mallocz(sizeof(AVCodecInternal)); + avctx->internal = av_mallocz(sizeof(*avctx->internal)); if (!avctx->internal) { ret = AVERROR(ENOMEM); goto end; @@ -833,12 +742,6 @@ int attribute_align_arg avcodec_open2(AVCodecContext *avctx, const AVCodec *code avctx->lowres = avctx->codec->max_lowres; } -#if FF_API_VISMV - if (avctx->debug_mv) - av_log(avctx, AV_LOG_WARNING, "The 'vismv' option is deprecated, " - "see the codecview filter instead.\n"); -#endif - if (av_codec_is_encoder(avctx->codec)) { int i; #if FF_API_CODED_FRAME @@ -1025,11 +928,6 @@ FF_ENABLE_DEPRECATION_WARNINGS ret=0; -#if FF_API_AUDIOENC_DELAY - if (av_codec_is_encoder(avctx->codec)) - avctx->delay = avctx->initial_padding; -#endif - if (av_codec_is_decoder(avctx->codec)) { if (!avctx->bit_rate) avctx->bit_rate = get_bit_rate(avctx); @@ -1157,7 +1055,7 @@ void avsubtitle_free(AVSubtitle *sub) av_freep(&sub->rects); - memset(sub, 0, sizeof(AVSubtitle)); + memset(sub, 0, sizeof(*sub)); } av_cold int avcodec_close(AVCodecContext *avctx) @@ -1226,71 +1124,6 @@ FF_ENABLE_DEPRECATION_WARNINGS return 0; } -static enum AVCodecID remap_deprecated_codec_id(enum AVCodecID id) -{ - switch(id){ - //This is for future deprecatec codec ids, its empty since - //last major bump but will fill up again over time, please don't remove it - default : return id; - } -} - -static AVCodec *find_encdec(enum AVCodecID id, int encoder) -{ - AVCodec *p, *experimental = NULL; - p = first_avcodec; - id= remap_deprecated_codec_id(id); - while (p) { - if ((encoder ? av_codec_is_encoder(p) : av_codec_is_decoder(p)) && - p->id == id) { - if (p->capabilities & AV_CODEC_CAP_EXPERIMENTAL && !experimental) { - experimental = p; - } else - return p; - } - p = p->next; - } - return experimental; -} - -AVCodec *avcodec_find_encoder(enum AVCodecID id) -{ - return find_encdec(id, 1); -} - -AVCodec *avcodec_find_encoder_by_name(const char *name) -{ - AVCodec *p; - if (!name) - return NULL; - p = first_avcodec; - while (p) { - if (av_codec_is_encoder(p) && strcmp(name, p->name) == 0) - return p; - p = p->next; - } - return NULL; -} - -AVCodec *avcodec_find_decoder(enum AVCodecID id) -{ - return find_encdec(id, 0); -} - -AVCodec *avcodec_find_decoder_by_name(const char *name) -{ - AVCodec *p; - if (!name) - return NULL; - p = first_avcodec; - while (p) { - if (av_codec_is_decoder(p) && strcmp(name, p->name) == 0) - return p; - p = p->next; - } - return NULL; -} - const char *avcodec_get_name(enum AVCodecID id) { const AVCodecDescriptor *cd; @@ -1836,13 +1669,13 @@ static int get_audio_frame_duration(enum AVCodecID id, int sr, int ch, int ba, /* calc from frame_bytes, channels, and bits_per_coded_sample */ switch (id) { case AV_CODEC_ID_PCM_DVD: - if(bps<4) + if(bps<4 || frame_bytes<3) return 0; - return 2 * (frame_bytes / ((bps * 2 / 8) * ch)); + return 2 * ((frame_bytes - 3) / ((bps * 2 / 8) * ch)); case AV_CODEC_ID_PCM_BLURAY: - if(bps<4) + if(bps<4 || frame_bytes<4) return 0; - return frame_bytes / ((FFALIGN(ch, 2) * bps) / 8); + return (frame_bytes - 4) / ((FFALIGN(ch, 2) * bps) / 8); case AV_CODEC_ID_S302M: return 2 * (frame_bytes / ((bps + 4) / 4)) / ch; } @@ -1911,143 +1744,34 @@ int ff_match_2uint16(const uint16_t(*tab)[2], int size, int a, int b) return i; } -#if FF_API_MISSING_SAMPLE -FF_DISABLE_DEPRECATION_WARNINGS -void av_log_missing_feature(void *avc, const char *feature, int want_sample) +const AVCodecHWConfig *avcodec_get_hw_config(const AVCodec *codec, int index) { - av_log(avc, AV_LOG_WARNING, "%s is not implemented. Update your FFmpeg " - "version to the newest one from Git. If the problem still " - "occurs, it means that your file has a feature which has not " - "been implemented.\n", feature); - if(want_sample) - av_log_ask_for_sample(avc, NULL); + int i; + if (!codec->hw_configs || index < 0) + return NULL; + for (i = 0; i <= index; i++) + if (!codec->hw_configs[i]) + return NULL; + return &codec->hw_configs[index]->public; } -void av_log_ask_for_sample(void *avc, const char *msg, ...) +#if FF_API_USER_VISIBLE_AVHWACCEL +AVHWAccel *av_hwaccel_next(const AVHWAccel *hwaccel) { - va_list argument_list; - - va_start(argument_list, msg); - - if (msg) - av_vlog(avc, AV_LOG_WARNING, msg, argument_list); - av_log(avc, AV_LOG_WARNING, "If you want to help, upload a sample " - "of this file to ftp://upload.ffmpeg.org/incoming/ " - "and contact the ffmpeg-devel mailing list. (ffmpeg-devel@ffmpeg.org)\n"); - - va_end(argument_list); + return NULL; } -FF_ENABLE_DEPRECATION_WARNINGS -#endif /* FF_API_MISSING_SAMPLE */ - -static AVHWAccel *first_hwaccel = NULL; -static AVHWAccel **last_hwaccel = &first_hwaccel; void av_register_hwaccel(AVHWAccel *hwaccel) { - AVHWAccel **p = last_hwaccel; - hwaccel->next = NULL; - while(*p || avpriv_atomic_ptr_cas((void * volatile *)p, NULL, hwaccel)) - p = &(*p)->next; - last_hwaccel = &hwaccel->next; -} - -AVHWAccel *av_hwaccel_next(const AVHWAccel *hwaccel) -{ - return hwaccel ? hwaccel->next : first_hwaccel; } +#endif +#if FF_API_LOCKMGR int av_lockmgr_register(int (*cb)(void **mutex, enum AVLockOp op)) { - if (lockmgr_cb) { - // There is no good way to rollback a failure to destroy the - // mutex, so we ignore failures. - lockmgr_cb(&codec_mutex, AV_LOCK_DESTROY); - lockmgr_cb(&avformat_mutex, AV_LOCK_DESTROY); - lockmgr_cb = NULL; - codec_mutex = NULL; - avformat_mutex = NULL; - } - - if (cb) { - void *new_codec_mutex = NULL; - void *new_avformat_mutex = NULL; - int err; - if (err = cb(&new_codec_mutex, AV_LOCK_CREATE)) { - return err > 0 ? AVERROR_UNKNOWN : err; - } - if (err = cb(&new_avformat_mutex, AV_LOCK_CREATE)) { - // Ignore failures to destroy the newly created mutex. - cb(&new_codec_mutex, AV_LOCK_DESTROY); - return err > 0 ? AVERROR_UNKNOWN : err; - } - lockmgr_cb = cb; - codec_mutex = new_codec_mutex; - avformat_mutex = new_avformat_mutex; - } - - return 0; -} - -int ff_lock_avcodec(AVCodecContext *log_ctx, const AVCodec *codec) -{ - if (codec->caps_internal & FF_CODEC_CAP_INIT_THREADSAFE || !codec->init) - return 0; - - if (lockmgr_cb) { - if ((*lockmgr_cb)(&codec_mutex, AV_LOCK_OBTAIN)) - return -1; - } - - if (avpriv_atomic_int_add_and_fetch(&entangled_thread_counter, 1) != 1) { - av_log(log_ctx, AV_LOG_ERROR, - "Insufficient thread locking. At least %d threads are " - "calling avcodec_open2() at the same time right now.\n", - entangled_thread_counter); - if (!lockmgr_cb) - av_log(log_ctx, AV_LOG_ERROR, "No lock manager is set, please see av_lockmgr_register()\n"); - ff_avcodec_locked = 1; - ff_unlock_avcodec(codec); - return AVERROR(EINVAL); - } - av_assert0(!ff_avcodec_locked); - ff_avcodec_locked = 1; - return 0; -} - -int ff_unlock_avcodec(const AVCodec *codec) -{ - if (codec->caps_internal & FF_CODEC_CAP_INIT_THREADSAFE || !codec->init) - return 0; - - av_assert0(ff_avcodec_locked); - ff_avcodec_locked = 0; - avpriv_atomic_int_add_and_fetch(&entangled_thread_counter, -1); - if (lockmgr_cb) { - if ((*lockmgr_cb)(&codec_mutex, AV_LOCK_RELEASE)) - return -1; - } - - return 0; -} - -int avpriv_lock_avformat(void) -{ - if (lockmgr_cb) { - if ((*lockmgr_cb)(&avformat_mutex, AV_LOCK_OBTAIN)) - return -1; - } - return 0; -} - -int avpriv_unlock_avformat(void) -{ - if (lockmgr_cb) { - if ((*lockmgr_cb)(&avformat_mutex, AV_LOCK_RELEASE)) - return -1; - } return 0; } +#endif unsigned int avpriv_toupper4(unsigned int x) { diff --git a/libavcodec/utvideo.h b/libavcodec/utvideo.h index a8117851a7c39..cf0bb28c44e10 100644 --- a/libavcodec/utvideo.h +++ b/libavcodec/utvideo.h @@ -72,17 +72,23 @@ typedef struct UtvideoContext { LLVidDSPContext llviddsp; LLVidEncDSPContext llvidencdsp; - uint32_t frame_info_size, flags, frame_info; + uint32_t frame_info_size, flags, frame_info, offset; int planes; int slices; int compression; int interlaced; int frame_pred; int pro; + int pack; ptrdiff_t slice_stride; uint8_t *slice_bits, *slice_buffer[4]; int slice_bits_size; + + const uint8_t *packed_stream[4][256]; + size_t packed_stream_size[4][256]; + const uint8_t *control_stream[4][256]; + size_t control_stream_size[4][256]; } UtvideoContext; typedef struct HuffEntry { diff --git a/libavcodec/utvideodec.c b/libavcodec/utvideodec.c index 40c12772b34e4..82cb038ccd9f8 100644 --- a/libavcodec/utvideodec.c +++ b/libavcodec/utvideodec.c @@ -30,6 +30,7 @@ #define UNCHECKED_BITSTREAM_READER 1 #include "libavutil/intreadwrite.h" +#include "libavutil/pixdesc.h" #include "avcodec.h" #include "bswapdsp.h" #include "bytestream.h" @@ -126,7 +127,7 @@ static int build_huff(const uint8_t *src, VLC *vlc, int *fsym) } static int decode_plane10(UtvideoContext *c, int plane_no, - uint16_t *dst, int step, ptrdiff_t stride, + uint16_t *dst, ptrdiff_t stride, int width, int height, const uint8_t *src, const uint8_t *huff, int use_pred) @@ -152,7 +153,7 @@ static int decode_plane10(UtvideoContext *c, int plane_no, prev = 0x200; for (j = sstart; j < send; j++) { - for (i = 0; i < width * step; i += step) { + for (i = 0; i < width; i++) { pix = fsym; if (use_pred) { prev += pix; @@ -195,8 +196,7 @@ static int decode_plane10(UtvideoContext *c, int plane_no, prev = 0x200; for (j = sstart; j < send; j++) { - int ws = width * step; - for (i = 0; i < ws; i += step) { + for (i = 0; i < width; i++) { pix = get_vlc2(&gb, vlc.table, VLC_BITS, 3); if (pix < 0) { av_log(c->avctx, AV_LOG_ERROR, "Decoding error\n"); @@ -229,8 +229,18 @@ static int decode_plane10(UtvideoContext *c, int plane_no, return AVERROR_INVALIDDATA; } +static int compute_cmask(int plane_no, int interlaced, enum AVPixelFormat pix_fmt) +{ + const int is_luma = (pix_fmt == AV_PIX_FMT_YUV420P) && !plane_no; + + if (interlaced) + return ~(1 + 2 * is_luma); + + return ~is_luma; +} + static int decode_plane(UtvideoContext *c, int plane_no, - uint8_t *dst, int step, ptrdiff_t stride, + uint8_t *dst, ptrdiff_t stride, int width, int height, const uint8_t *src, int use_pred) { @@ -238,8 +248,55 @@ static int decode_plane(UtvideoContext *c, int plane_no, int sstart, send; VLC vlc; GetBitContext gb; - int prev, fsym; - const int cmask = c->interlaced ? ~(1 + 2 * (!plane_no && c->avctx->pix_fmt == AV_PIX_FMT_YUV420P)) : ~(!plane_no && c->avctx->pix_fmt == AV_PIX_FMT_YUV420P); + int ret, prev, fsym; + const int cmask = compute_cmask(plane_no, c->interlaced, c->avctx->pix_fmt); + + if (c->pack) { + send = 0; + for (slice = 0; slice < c->slices; slice++) { + GetBitContext cbit, pbit; + uint8_t *dest, *p; + + ret = init_get_bits8(&cbit, c->control_stream[plane_no][slice], c->control_stream_size[plane_no][slice]); + if (ret < 0) + return ret; + + ret = init_get_bits8(&pbit, c->packed_stream[plane_no][slice], c->packed_stream_size[plane_no][slice]); + if (ret < 0) + return ret; + + sstart = send; + send = (height * (slice + 1) / c->slices) & cmask; + dest = dst + sstart * stride; + + if (3 * ((dst + send * stride - dest + 7)/8) > get_bits_left(&cbit)) + return AVERROR_INVALIDDATA; + + for (p = dest; p < dst + send * stride; p += 8) { + int bits = get_bits_le(&cbit, 3); + + if (bits == 0) { + *(uint64_t *) p = 0; + } else { + uint32_t sub = 0x80 >> (8 - (bits + 1)), add; + int k; + + if ((bits + 1) * 8 > get_bits_left(&pbit)) + return AVERROR_INVALIDDATA; + + for (k = 0; k < 8; k++) { + + p[k] = get_bits_le(&pbit, bits + 1); + add = (~p[k] & sub) << (8 - bits); + p[k] -= sub; + p[k] += add; + } + } + } + } + + return 0; + } if (build_huff(src, &vlc, &fsym)) { av_log(c->avctx, AV_LOG_ERROR, "Cannot build Huffman codes\n"); @@ -256,7 +313,7 @@ static int decode_plane(UtvideoContext *c, int plane_no, prev = 0x80; for (j = sstart; j < send; j++) { - for (i = 0; i < width * step; i += step) { + for (i = 0; i < width; i++) { pix = fsym; if (use_pred) { prev += pix; @@ -300,8 +357,7 @@ static int decode_plane(UtvideoContext *c, int plane_no, prev = 0x80; for (j = sstart; j < send; j++) { - int ws = width * step; - for (i = 0; i < ws; i += step) { + for (i = 0; i < width; i++) { pix = get_vlc2(&gb, vlc.table, VLC_BITS, 3); if (pix < 0) { av_log(c->avctx, AV_LOG_ERROR, "Decoding error\n"); @@ -365,12 +421,16 @@ static void restore_median_planar(UtvideoContext *c, uint8_t *src, ptrdiff_t str C = bsrc[-stride]; bsrc[0] += C; A = bsrc[0]; - for (i = 1; i < width; i++) { + for (i = 1; i < FFMIN(width, 16); i++) { /* scalar loop (DSP need align 16) */ B = bsrc[i - stride]; bsrc[i] += mid_pred(A, B, (uint8_t)(A + B - C)); C = B; A = bsrc[i]; } + if (width > 16) + c->llviddsp.add_median_pred(bsrc + 16, bsrc - stride + 16, + bsrc + 16, width - 16, &A, &B); + bsrc += stride; // the rest of lines use continuous median prediction for (j = 2; j < slice_height; j++) { @@ -416,12 +476,16 @@ static void restore_median_planar_il(UtvideoContext *c, uint8_t *src, ptrdiff_t C = bsrc[-stride2]; bsrc[0] += C; A = bsrc[0]; - for (i = 1; i < width; i++) { + for (i = 1; i < FFMIN(width, 16); i++) { /* scalar loop (DSP need align 16) */ B = bsrc[i - stride2]; bsrc[i] += mid_pred(A, B, (uint8_t)(A + B - C)); C = B; A = bsrc[i]; } + if (width > 16) + c->llviddsp.add_median_pred(bsrc + 16, bsrc - stride2 + 16, + bsrc + 16, width - 16, &A, &B); + c->llviddsp.add_median_pred(bsrc + stride, bsrc - stride, bsrc + stride, width, &A, &B); bsrc += stride2; @@ -444,6 +508,7 @@ static void restore_gradient_planar(UtvideoContext *c, uint8_t *src, ptrdiff_t s uint8_t *bsrc; int slice_start, slice_height; const int cmask = ~rmode; + int min_width = FFMIN(width, 32); for (slice = 0; slice < slices; slice++) { slice_start = ((slice * height) / slices) & cmask; @@ -463,12 +528,14 @@ static void restore_gradient_planar(UtvideoContext *c, uint8_t *src, ptrdiff_t s for (j = 1; j < slice_height; j++) { // second line - first element has top prediction, the rest uses gradient bsrc[0] = (bsrc[0] + bsrc[-stride]) & 0xFF; - for (i = 1; i < width; i++) { + for (i = 1; i < min_width; i++) { /* dsp need align 32 */ A = bsrc[i - stride]; B = bsrc[i - (stride + 1)]; C = bsrc[i - 1]; bsrc[i] = (A - B + C + bsrc[i]) & 0xFF; } + if (width > 32) + c->llviddsp.add_gradient_pred(bsrc + 32, stride, width - 32); bsrc += stride; } } @@ -483,6 +550,7 @@ static void restore_gradient_planar_il(UtvideoContext *c, uint8_t *src, ptrdiff_ int slice_start, slice_height; const int cmask = ~(rmode ? 3 : 1); const ptrdiff_t stride2 = stride << 1; + int min_width = FFMIN(width, 32); for (slice = 0; slice < slices; slice++) { slice_start = ((slice * height) / slices) & cmask; @@ -504,12 +572,15 @@ static void restore_gradient_planar_il(UtvideoContext *c, uint8_t *src, ptrdiff_ for (j = 1; j < slice_height; j++) { // second line - first element has top prediction, the rest uses gradient bsrc[0] = (bsrc[0] + bsrc[-stride2]) & 0xFF; - for (i = 1; i < width; i++) { + for (i = 1; i < min_width; i++) { /* dsp need align 32 */ A = bsrc[i - stride2]; B = bsrc[i - (stride2 + 1)]; C = bsrc[i - 1]; bsrc[i] = (A - B + C + bsrc[i]) & 0xFF; } + if (width > 32) + c->llviddsp.add_gradient_pred(bsrc + 32, stride2, width - 32); + A = bsrc[-stride]; B = bsrc[-(1 + stride + stride - width)]; C = bsrc[width - 1]; @@ -543,7 +614,58 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, /* parse plane structure to get frame flags and validate slice offsets */ bytestream2_init(&gb, buf, buf_size); - if (c->pro) { + + if (c->pack) { + const uint8_t *packed_stream; + const uint8_t *control_stream; + GetByteContext pb; + uint32_t nb_cbs; + int left; + + c->frame_info = PRED_GRADIENT << 8; + + if (bytestream2_get_byte(&gb) != 1) + return AVERROR_INVALIDDATA; + bytestream2_skip(&gb, 3); + c->offset = bytestream2_get_le32(&gb); + + if (buf_size <= c->offset + 8LL) + return AVERROR_INVALIDDATA; + + bytestream2_init(&pb, buf + 8 + c->offset, buf_size - 8 - c->offset); + + nb_cbs = bytestream2_get_le32(&pb); + if (nb_cbs > c->offset) + return AVERROR_INVALIDDATA; + + packed_stream = buf + 8; + control_stream = packed_stream + (c->offset - nb_cbs); + left = control_stream - packed_stream; + + for (i = 0; i < c->planes; i++) { + for (j = 0; j < c->slices; j++) { + c->packed_stream[i][j] = packed_stream; + c->packed_stream_size[i][j] = bytestream2_get_le32(&pb); + if (c->packed_stream_size[i][j] > left) + return AVERROR_INVALIDDATA; + left -= c->packed_stream_size[i][j]; + packed_stream += c->packed_stream_size[i][j]; + } + } + + left = buf + buf_size - control_stream; + + for (i = 0; i < c->planes; i++) { + for (j = 0; j < c->slices; j++) { + c->control_stream[i][j] = control_stream; + c->control_stream_size[i][j] = bytestream2_get_le32(&pb); + if (c->control_stream_size[i][j] > left) + return AVERROR_INVALIDDATA; + left -= c->control_stream_size[i][j]; + control_stream += c->control_stream_size[i][j]; + } + } + } else if (c->pro) { if (bytestream2_get_bytes_left(&gb) < c->frame_info_size) { av_log(avctx, AV_LOG_ERROR, "Not enough data for frame information\n"); return AVERROR_INVALIDDATA; @@ -561,7 +683,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, for (j = 0; j < c->slices; j++) { slice_end = bytestream2_get_le32u(&gb); if (slice_end < 0 || slice_end < slice_start || - bytestream2_get_bytes_left(&gb) < slice_end) { + bytestream2_get_bytes_left(&gb) < slice_end + 1024LL) { av_log(avctx, AV_LOG_ERROR, "Incorrect slice size\n"); return AVERROR_INVALIDDATA; } @@ -612,19 +734,21 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, max_slice_size += 4*avctx->width; - av_fast_malloc(&c->slice_bits, &c->slice_bits_size, - max_slice_size + AV_INPUT_BUFFER_PADDING_SIZE); + if (!c->pack) { + av_fast_malloc(&c->slice_bits, &c->slice_bits_size, + max_slice_size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!c->slice_bits) { - av_log(avctx, AV_LOG_ERROR, "Cannot allocate temporary buffer\n"); - return AVERROR(ENOMEM); + if (!c->slice_bits) { + av_log(avctx, AV_LOG_ERROR, "Cannot allocate temporary buffer\n"); + return AVERROR(ENOMEM); + } } switch (c->avctx->pix_fmt) { case AV_PIX_FMT_GBRP: case AV_PIX_FMT_GBRAP: for (i = 0; i < c->planes; i++) { - ret = decode_plane(c, i, frame.f->data[i], 1, + ret = decode_plane(c, i, frame.f->data[i], frame.f->linesize[i], avctx->width, avctx->height, plane_start[i], c->frame_pred == PRED_LEFT); @@ -661,7 +785,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, case AV_PIX_FMT_GBRAP10: case AV_PIX_FMT_GBRP10: for (i = 0; i < c->planes; i++) { - ret = decode_plane10(c, i, (uint16_t *)frame.f->data[i], 1, + ret = decode_plane10(c, i, (uint16_t *)frame.f->data[i], frame.f->linesize[i] / 2, avctx->width, avctx->height, plane_start[i], plane_start[i + 1] - 1024, @@ -675,7 +799,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, break; case AV_PIX_FMT_YUV420P: for (i = 0; i < 3; i++) { - ret = decode_plane(c, i, frame.f->data[i], 1, frame.f->linesize[i], + ret = decode_plane(c, i, frame.f->data[i], frame.f->linesize[i], avctx->width >> !!i, avctx->height >> !!i, plane_start[i], c->frame_pred == PRED_LEFT); if (ret) @@ -707,7 +831,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, break; case AV_PIX_FMT_YUV422P: for (i = 0; i < 3; i++) { - ret = decode_plane(c, i, frame.f->data[i], 1, frame.f->linesize[i], + ret = decode_plane(c, i, frame.f->data[i], frame.f->linesize[i], avctx->width >> !!i, avctx->height, plane_start[i], c->frame_pred == PRED_LEFT); if (ret) @@ -737,7 +861,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, break; case AV_PIX_FMT_YUV444P: for (i = 0; i < 3; i++) { - ret = decode_plane(c, i, frame.f->data[i], 1, frame.f->linesize[i], + ret = decode_plane(c, i, frame.f->data[i], frame.f->linesize[i], avctx->width, avctx->height, plane_start[i], c->frame_pred == PRED_LEFT); if (ret) @@ -767,7 +891,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, break; case AV_PIX_FMT_YUV422P10: for (i = 0; i < 3; i++) { - ret = decode_plane10(c, i, (uint16_t *)frame.f->data[i], 1, frame.f->linesize[i] / 2, + ret = decode_plane10(c, i, (uint16_t *)frame.f->data[i], frame.f->linesize[i] / 2, avctx->width >> !!i, avctx->height, plane_start[i], plane_start[i + 1] - 1024, c->frame_pred == PRED_LEFT); if (ret) @@ -789,6 +913,7 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, static av_cold int decode_init(AVCodecContext *avctx) { UtvideoContext * const c = avctx->priv_data; + int h_shift, v_shift; c->avctx = avctx; @@ -796,37 +921,6 @@ static av_cold int decode_init(AVCodecContext *avctx) ff_bswapdsp_init(&c->bdsp); ff_llviddsp_init(&c->llviddsp); - if (avctx->extradata_size >= 16) { - av_log(avctx, AV_LOG_DEBUG, "Encoder version %d.%d.%d.%d\n", - avctx->extradata[3], avctx->extradata[2], - avctx->extradata[1], avctx->extradata[0]); - av_log(avctx, AV_LOG_DEBUG, "Original format %"PRIX32"\n", - AV_RB32(avctx->extradata + 4)); - c->frame_info_size = AV_RL32(avctx->extradata + 8); - c->flags = AV_RL32(avctx->extradata + 12); - - if (c->frame_info_size != 4) - avpriv_request_sample(avctx, "Frame info not 4 bytes"); - av_log(avctx, AV_LOG_DEBUG, "Encoding parameters %08"PRIX32"\n", c->flags); - c->slices = (c->flags >> 24) + 1; - c->compression = c->flags & 1; - c->interlaced = c->flags & 0x800; - } else if (avctx->extradata_size == 8) { - av_log(avctx, AV_LOG_DEBUG, "Encoder version %d.%d.%d.%d\n", - avctx->extradata[3], avctx->extradata[2], - avctx->extradata[1], avctx->extradata[0]); - av_log(avctx, AV_LOG_DEBUG, "Original format %"PRIX32"\n", - AV_RB32(avctx->extradata + 4)); - c->interlaced = 0; - c->pro = 1; - c->frame_info_size = 4; - } else { - av_log(avctx, AV_LOG_ERROR, - "Insufficient extradata size %d, should be at least 16\n", - avctx->extradata_size); - return AVERROR_INVALIDDATA; - } - c->slice_bits_size = 0; switch (avctx->codec_tag) { @@ -855,14 +949,17 @@ static av_cold int decode_init(AVCodecContext *avctx) break; case MKTAG('U', 'Q', 'Y', '2'): c->planes = 3; + c->pro = 1; avctx->pix_fmt = AV_PIX_FMT_YUV422P10; break; case MKTAG('U', 'Q', 'R', 'G'): c->planes = 3; + c->pro = 1; avctx->pix_fmt = AV_PIX_FMT_GBRP10; break; case MKTAG('U', 'Q', 'R', 'A'): c->planes = 4; + c->pro = 1; avctx->pix_fmt = AV_PIX_FMT_GBRAP10; break; case MKTAG('U', 'L', 'H', '0'): @@ -880,12 +977,93 @@ static av_cold int decode_init(AVCodecContext *avctx) avctx->pix_fmt = AV_PIX_FMT_YUV444P; avctx->colorspace = AVCOL_SPC_BT709; break; + case MKTAG('U', 'M', 'Y', '2'): + c->planes = 3; + c->pack = 1; + avctx->pix_fmt = AV_PIX_FMT_YUV422P; + avctx->colorspace = AVCOL_SPC_BT470BG; + break; + case MKTAG('U', 'M', 'H', '2'): + c->planes = 3; + c->pack = 1; + avctx->pix_fmt = AV_PIX_FMT_YUV422P; + avctx->colorspace = AVCOL_SPC_BT709; + break; + case MKTAG('U', 'M', 'Y', '4'): + c->planes = 3; + c->pack = 1; + avctx->pix_fmt = AV_PIX_FMT_YUV444P; + avctx->colorspace = AVCOL_SPC_BT470BG; + break; + case MKTAG('U', 'M', 'H', '4'): + c->planes = 3; + c->pack = 1; + avctx->pix_fmt = AV_PIX_FMT_YUV444P; + avctx->colorspace = AVCOL_SPC_BT709; + break; + case MKTAG('U', 'M', 'R', 'G'): + c->planes = 3; + c->pack = 1; + avctx->pix_fmt = AV_PIX_FMT_GBRP; + break; + case MKTAG('U', 'M', 'R', 'A'): + c->planes = 4; + c->pack = 1; + avctx->pix_fmt = AV_PIX_FMT_GBRAP; + break; default: av_log(avctx, AV_LOG_ERROR, "Unknown Ut Video FOURCC provided (%08X)\n", avctx->codec_tag); return AVERROR_INVALIDDATA; } + av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, &h_shift, &v_shift); + if ((avctx->width & ((1<height & ((1<pack && avctx->extradata_size >= 16) { + av_log(avctx, AV_LOG_DEBUG, "Encoder version %d.%d.%d.%d\n", + avctx->extradata[3], avctx->extradata[2], + avctx->extradata[1], avctx->extradata[0]); + av_log(avctx, AV_LOG_DEBUG, "Original format %"PRIX32"\n", + AV_RB32(avctx->extradata + 4)); + c->compression = avctx->extradata[8]; + if (c->compression != 2) + avpriv_request_sample(avctx, "Unknown compression type"); + c->slices = avctx->extradata[9] + 1; + } else if (!c->pro && avctx->extradata_size >= 16) { + av_log(avctx, AV_LOG_DEBUG, "Encoder version %d.%d.%d.%d\n", + avctx->extradata[3], avctx->extradata[2], + avctx->extradata[1], avctx->extradata[0]); + av_log(avctx, AV_LOG_DEBUG, "Original format %"PRIX32"\n", + AV_RB32(avctx->extradata + 4)); + c->frame_info_size = AV_RL32(avctx->extradata + 8); + c->flags = AV_RL32(avctx->extradata + 12); + + if (c->frame_info_size != 4) + avpriv_request_sample(avctx, "Frame info not 4 bytes"); + av_log(avctx, AV_LOG_DEBUG, "Encoding parameters %08"PRIX32"\n", c->flags); + c->slices = (c->flags >> 24) + 1; + c->compression = c->flags & 1; + c->interlaced = c->flags & 0x800; + } else if (c->pro && avctx->extradata_size == 8) { + av_log(avctx, AV_LOG_DEBUG, "Encoder version %d.%d.%d.%d\n", + avctx->extradata[3], avctx->extradata[2], + avctx->extradata[1], avctx->extradata[0]); + av_log(avctx, AV_LOG_DEBUG, "Original format %"PRIX32"\n", + AV_RB32(avctx->extradata + 4)); + c->interlaced = 0; + c->frame_info_size = 4; + } else { + av_log(avctx, AV_LOG_ERROR, + "Insufficient extradata size %d, should be at least 16\n", + avctx->extradata_size); + return AVERROR_INVALIDDATA; + } + return 0; } diff --git a/libavcodec/utvideoenc.c b/libavcodec/utvideoenc.c index 840742caf7130..db00e1eff5f29 100644 --- a/libavcodec/utvideoenc.c +++ b/libavcodec/utvideoenc.c @@ -67,12 +67,12 @@ static av_cold int utvideo_encode_init(AVCodecContext *avctx) c->slice_stride = FFALIGN(avctx->width, 32); switch (avctx->pix_fmt) { - case AV_PIX_FMT_RGB24: + case AV_PIX_FMT_GBRP: c->planes = 3; avctx->codec_tag = MKTAG('U', 'L', 'R', 'G'); original_format = UTVIDEO_RGB; break; - case AV_PIX_FMT_RGBA: + case AV_PIX_FMT_GBRAP: c->planes = 4; avctx->codec_tag = MKTAG('U', 'L', 'R', 'A'); original_format = UTVIDEO_RGBA; @@ -243,53 +243,43 @@ FF_ENABLE_DEPRECATION_WARNINGS } static void mangle_rgb_planes(uint8_t *dst[4], ptrdiff_t dst_stride, - uint8_t *src, int step, ptrdiff_t stride, + uint8_t *const src[4], int planes, const int stride[4], int width, int height) { int i, j; int k = 2 * dst_stride; + const uint8_t *sg = src[0]; + const uint8_t *sb = src[1]; + const uint8_t *sr = src[2]; + const uint8_t *sa = src[3]; unsigned int g; for (j = 0; j < height; j++) { - if (step == 3) { - for (i = 0; i < width * step; i += step) { - g = src[i + 1]; + if (planes == 3) { + for (i = 0; i < width; i++) { + g = sg[i]; dst[0][k] = g; g += 0x80; - dst[1][k] = src[i + 2] - g; - dst[2][k] = src[i + 0] - g; + dst[1][k] = sb[i] - g; + dst[2][k] = sr[i] - g; k++; } } else { - for (i = 0; i < width * step; i += step) { - g = src[i + 1]; + for (i = 0; i < width; i++) { + g = sg[i]; dst[0][k] = g; g += 0x80; - dst[1][k] = src[i + 2] - g; - dst[2][k] = src[i + 0] - g; - dst[3][k] = src[i + 3]; + dst[1][k] = sb[i] - g; + dst[2][k] = sr[i] - g; + dst[3][k] = sa[i]; k++; } + sa += stride[3]; } k += dst_stride - width; - src += stride; - } -} - -/* Write data to a plane with left prediction */ -static void left_predict(uint8_t *src, uint8_t *dst, ptrdiff_t stride, - int width, int height) -{ - int i, j; - uint8_t prev; - - prev = 0x80; /* Set the initial value */ - for (j = 0; j < height; j++) { - for (i = 0; i < width; i++) { - *dst++ = src[i] - prev; - prev = src[i]; - } - src += stride; + sg += stride[0]; + sb += stride[1]; + sr += stride[2]; } } @@ -429,8 +419,7 @@ static int encode_plane(AVCodecContext *avctx, uint8_t *src, for (i = 0; i < c->slices; i++) { sstart = send; send = height * (i + 1) / c->slices & cmask; - left_predict(src + sstart * stride, dst + sstart * width, - stride, width, send - sstart); + c->llvidencdsp.sub_left_predict(dst + sstart * width, src + sstart * stride, stride, width, send - sstart); } break; case PRED_MEDIAN: @@ -572,14 +561,14 @@ static int utvideo_encode_frame(AVCodecContext *avctx, AVPacket *pkt, } /* In case of RGB, mangle the planes to Ut Video's format */ - if (avctx->pix_fmt == AV_PIX_FMT_RGBA || avctx->pix_fmt == AV_PIX_FMT_RGB24) - mangle_rgb_planes(c->slice_buffer, c->slice_stride, pic->data[0], - c->planes, pic->linesize[0], width, height); + if (avctx->pix_fmt == AV_PIX_FMT_GBRAP || avctx->pix_fmt == AV_PIX_FMT_GBRP) + mangle_rgb_planes(c->slice_buffer, c->slice_stride, pic->data, + c->planes, pic->linesize, width, height); /* Deal with the planes */ switch (avctx->pix_fmt) { - case AV_PIX_FMT_RGB24: - case AV_PIX_FMT_RGBA: + case AV_PIX_FMT_GBRP: + case AV_PIX_FMT_GBRAP: for (i = 0; i < c->planes; i++) { ret = encode_plane(avctx, c->slice_buffer[i] + 2 * c->slice_stride, c->slice_buffer[i], c->slice_stride, i, @@ -690,7 +679,7 @@ AVCodec ff_utvideo_encoder = { .close = utvideo_encode_close, .capabilities = AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_INTRA_ONLY, .pix_fmts = (const enum AVPixelFormat[]) { - AV_PIX_FMT_RGB24, AV_PIX_FMT_RGBA, AV_PIX_FMT_YUV422P, + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRAP, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_NONE }, }; diff --git a/libavcodec/v210dec.c b/libavcodec/v210dec.c index 9af9af67972c1..99199ddc157a7 100644 --- a/libavcodec/v210dec.c +++ b/libavcodec/v210dec.c @@ -162,10 +162,10 @@ static const AVOption v210dec_options[] = { }; static const AVClass v210dec_class = { - "V210 Decoder", - av_default_item_name, - v210dec_options, - LIBAVUTIL_VERSION_INT, + .class_name = "V210 Decoder", + .item_name = av_default_item_name, + .option = v210dec_options, + .version = LIBAVUTIL_VERSION_INT, }; AVCodec ff_v210_decoder = { diff --git a/libavcodec/v4l2_buffers.c b/libavcodec/v4l2_buffers.c index ba70c5d14bcc2..aef911f3bbcff 100644 --- a/libavcodec/v4l2_buffers.c +++ b/libavcodec/v4l2_buffers.c @@ -69,7 +69,8 @@ static inline uint64_t v4l2_get_pts(V4L2Buffer *avbuf) int64_t v4l2_pts; /* convert pts back to encoder timebase */ - v4l2_pts = avbuf->buf.timestamp.tv_sec * USEC_PER_SEC + avbuf->buf.timestamp.tv_usec; + v4l2_pts = (int64_t)avbuf->buf.timestamp.tv_sec * USEC_PER_SEC + + avbuf->buf.timestamp.tv_usec; return av_rescale_q(v4l2_pts, v4l2_timebase, s->avctx->time_base); } @@ -207,20 +208,23 @@ static void v4l2_free_buffer(void *opaque, uint8_t *unused) V4L2Buffer* avbuf = opaque; V4L2m2mContext *s = buf_to_m2mctx(avbuf); - atomic_fetch_sub_explicit(&s->refcount, 1, memory_order_acq_rel); - if (s->reinit) { - if (!atomic_load(&s->refcount)) - sem_post(&s->refsync); - return; - } + if (atomic_fetch_sub(&avbuf->context_refcount, 1) == 1) { + atomic_fetch_sub_explicit(&s->refcount, 1, memory_order_acq_rel); - if (avbuf->context->streamon) { - ff_v4l2_buffer_enqueue(avbuf); - return; - } + if (s->reinit) { + if (!atomic_load(&s->refcount)) + sem_post(&s->refsync); + } else { + if (s->draining) { + /* no need to queue more buffers to the driver */ + avbuf->status = V4L2BUF_AVAILABLE; + } + else if (avbuf->context->streamon) + ff_v4l2_buffer_enqueue(avbuf); + } - if (!atomic_load(&s->refcount)) - ff_v4l2_m2m_codec_end(s->avctx); + av_buffer_unref(&avbuf->context_ref); + } } static int v4l2_buf_to_bufref(V4L2Buffer *in, int plane, AVBufferRef **buf) @@ -236,6 +240,17 @@ static int v4l2_buf_to_bufref(V4L2Buffer *in, int plane, AVBufferRef **buf) if (!*buf) return AVERROR(ENOMEM); + if (in->context_ref) + atomic_fetch_add(&in->context_refcount, 1); + else { + in->context_ref = av_buffer_ref(s->self_ref); + if (!in->context_ref) { + av_buffer_unref(buf); + return AVERROR(ENOMEM); + } + in->context_refcount = 1; + } + in->status = V4L2BUF_RET_USER; atomic_fetch_add_explicit(&s->refcount, 1, memory_order_relaxed); diff --git a/libavcodec/v4l2_buffers.h b/libavcodec/v4l2_buffers.h index e28a4a650d763..dc5cc9e26717b 100644 --- a/libavcodec/v4l2_buffers.h +++ b/libavcodec/v4l2_buffers.h @@ -24,6 +24,7 @@ #ifndef AVCODEC_V4L2_BUFFERS_H #define AVCODEC_V4L2_BUFFERS_H +#include #include #include "avcodec.h" @@ -41,6 +42,11 @@ typedef struct V4L2Buffer { /* each buffer needs to have a reference to its context */ struct V4L2Context *context; + /* This object is refcounted per-plane, so we need to keep track + * of how many context-refs we are holding. */ + AVBufferRef *context_ref; + atomic_uint context_refcount; + /* keep track of the mmap address and mmap length */ struct V4L2Plane_info { int bytesperline; diff --git a/libavcodec/v4l2_context.c b/libavcodec/v4l2_context.c index 9f3b56ddabf7d..efcb0426e4906 100644 --- a/libavcodec/v4l2_context.c +++ b/libavcodec/v4l2_context.c @@ -217,6 +217,7 @@ static int v4l2_stop_decode(V4L2Context *ctx) { struct v4l2_decoder_cmd cmd = { .cmd = V4L2_DEC_CMD_STOP, + .flags = 0, }; int ret; @@ -234,6 +235,7 @@ static int v4l2_stop_encode(V4L2Context *ctx) { struct v4l2_encoder_cmd cmd = { .cmd = V4L2_ENC_CMD_STOP, + .flags = 0, }; int ret; @@ -256,10 +258,26 @@ static V4L2Buffer* v4l2_dequeue_v4l2buf(V4L2Context *ctx, int timeout) .events = POLLIN | POLLRDNORM | POLLPRI | POLLOUT | POLLWRNORM, /* default blocking capture */ .fd = ctx_to_m2mctx(ctx)->fd, }; - int ret; + int i, ret; + + /* if we are draining and there are no more capture buffers queued in the driver we are done */ + if (!V4L2_TYPE_IS_OUTPUT(ctx->type) && ctx_to_m2mctx(ctx)->draining) { + for (i = 0; i < ctx->num_buffers; i++) { + if (ctx->buffers[i].status == V4L2BUF_IN_DRIVER) + goto start; + } + ctx->done = 1; + return NULL; + } +start: if (V4L2_TYPE_IS_OUTPUT(ctx->type)) pfd.events = POLLOUT | POLLWRNORM; + else { + /* no need to listen to requests for more input while draining */ + if (ctx_to_m2mctx(ctx)->draining) + pfd.events = POLLIN | POLLRDNORM | POLLPRI; + } for (;;) { ret = poll(&pfd, 1, timeout); @@ -267,17 +285,22 @@ static V4L2Buffer* v4l2_dequeue_v4l2buf(V4L2Context *ctx, int timeout) break; if (errno == EINTR) continue; - - /* timeout is being used to indicate last valid bufer when draining */ - if (ctx_to_m2mctx(ctx)->draining) - ctx->done = 1; - return NULL; } /* 0. handle errors */ if (pfd.revents & POLLERR) { - av_log(logger(ctx), AV_LOG_WARNING, "%s POLLERR\n", ctx->name); + /* if we are trying to get free buffers but none have been queued yet + no need to raise a warning */ + if (timeout == 0) { + for (i = 0; i < ctx->num_buffers; i++) { + if (ctx->buffers[i].status != V4L2BUF_AVAILABLE) + av_log(logger(ctx), AV_LOG_WARNING, "%s POLLERR\n", ctx->name); + } + } + else + av_log(logger(ctx), AV_LOG_WARNING, "%s POLLERR\n", ctx->name); + return NULL; } @@ -286,7 +309,7 @@ static V4L2Buffer* v4l2_dequeue_v4l2buf(V4L2Context *ctx, int timeout) ret = v4l2_handle_event(ctx); if (ret < 0) { /* if re-init failed, abort */ - ctx->done = EINVAL; + ctx->done = 1; return NULL; } if (ret) { @@ -325,23 +348,25 @@ static V4L2Buffer* v4l2_dequeue_v4l2buf(V4L2Context *ctx, int timeout) ret = ioctl(ctx_to_m2mctx(ctx)->fd, VIDIOC_DQBUF, &buf); if (ret) { if (errno != EAGAIN) { - ctx->done = errno; + ctx->done = 1; if (errno != EPIPE) av_log(logger(ctx), AV_LOG_DEBUG, "%s VIDIOC_DQBUF, errno (%s)\n", ctx->name, av_err2str(AVERROR(errno))); } - } else { - avbuf = &ctx->buffers[buf.index]; - avbuf->status = V4L2BUF_AVAILABLE; - avbuf->buf = buf; - if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) { - memcpy(avbuf->planes, planes, sizeof(planes)); - avbuf->buf.m.planes = avbuf->planes; - } + return NULL; } + + avbuf = &ctx->buffers[buf.index]; + avbuf->status = V4L2BUF_AVAILABLE; + avbuf->buf = buf; + if (V4L2_TYPE_IS_MULTIPLANAR(ctx->type)) { + memcpy(avbuf->planes, planes, sizeof(planes)); + avbuf->buf.m.planes = avbuf->planes; + } + return avbuf; } - return avbuf; + return NULL; } static V4L2Buffer* v4l2_getfree_v4l2buf(V4L2Context *ctx) @@ -421,9 +446,7 @@ static int v4l2_get_raw_format(V4L2Context* ctx, enum AVPixelFormat *p) if (pixfmt != AV_PIX_FMT_NONE) { ret = v4l2_try_raw_format(ctx, pixfmt); - if (ret) - pixfmt = AV_PIX_FMT_NONE; - else + if (!ret) return 0; } @@ -484,7 +507,7 @@ static int v4l2_get_coded_format(V4L2Context* ctx, uint32_t *p) * *****************************************************************************/ -int ff_v4l2_context_set_status(V4L2Context* ctx, int cmd) +int ff_v4l2_context_set_status(V4L2Context* ctx, uint32_t cmd) { int type = ctx->type; int ret; @@ -552,14 +575,12 @@ int ff_v4l2_context_dequeue_frame(V4L2Context* ctx, AVFrame* frame) { V4L2Buffer* avbuf = NULL; - /* if we are draining, we are no longer inputing data, therefore enable a - * timeout so we can dequeue and flag the last valid buffer. - * + /* * blocks until: * 1. decoded frame available * 2. an input buffer is ready to be dequeued */ - avbuf = v4l2_dequeue_v4l2buf(ctx, ctx_to_m2mctx(ctx)->draining ? 200 : -1); + avbuf = v4l2_dequeue_v4l2buf(ctx, -1); if (!avbuf) { if (ctx->done) return AVERROR_EOF; @@ -574,14 +595,12 @@ int ff_v4l2_context_dequeue_packet(V4L2Context* ctx, AVPacket* pkt) { V4L2Buffer* avbuf = NULL; - /* if we are draining, we are no longer inputing data, therefore enable a - * timeout so we can dequeue and flag the last valid buffer. - * + /* * blocks until: * 1. encoded packet available * 2. an input buffer ready to be dequeued */ - avbuf = v4l2_dequeue_v4l2buf(ctx, ctx_to_m2mctx(ctx)->draining ? 200 : -1); + avbuf = v4l2_dequeue_v4l2buf(ctx, -1); if (!avbuf) { if (ctx->done) return AVERROR_EOF; diff --git a/libavcodec/v4l2_context.h b/libavcodec/v4l2_context.h index 503cc36dc4a2b..632f1d0aac019 100644 --- a/libavcodec/v4l2_context.h +++ b/libavcodec/v4l2_context.h @@ -135,7 +135,7 @@ void ff_v4l2_context_release(V4L2Context* ctx); * those frames will be dropped. * @return 0 in case of success, a negative value representing the error otherwise. */ -int ff_v4l2_context_set_status(V4L2Context* ctx, int cmd); +int ff_v4l2_context_set_status(V4L2Context* ctx, uint32_t cmd); /** * Dequeues a buffer from a V4L2Context to an AVPacket. diff --git a/libavcodec/v4l2_m2m.c b/libavcodec/v4l2_m2m.c index 1d7a8521d80fd..427e165f586f9 100644 --- a/libavcodec/v4l2_m2m.c +++ b/libavcodec/v4l2_m2m.c @@ -222,8 +222,6 @@ int ff_v4l2_m2m_codec_reinit(V4L2m2mContext* s) } /* 5. complete reinit */ - sem_destroy(&s->refsync); - sem_init(&s->refsync, 0, 0); s->draining = 0; s->reinit = 0; @@ -241,24 +239,26 @@ int ff_v4l2_m2m_codec_full_reinit(V4L2m2mContext *s) if (atomic_load(&s->refcount)) while(sem_wait(&s->refsync) == -1 && errno == EINTR); - /* close the driver */ - ff_v4l2_m2m_codec_end(s->avctx); + ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMOFF); + if (ret) { + av_log(s->avctx, AV_LOG_ERROR, "output VIDIOC_STREAMOFF\n"); + goto error; + } + + ret = ff_v4l2_context_set_status(&s->capture, VIDIOC_STREAMOFF); + if (ret) { + av_log(s->avctx, AV_LOG_ERROR, "capture VIDIOC_STREAMOFF\n"); + goto error; + } + + /* release and unmmap the buffers */ + ff_v4l2_context_release(&s->output); + ff_v4l2_context_release(&s->capture); /* start again now that we know the stream dimensions */ s->draining = 0; s->reinit = 0; - s->fd = open(s->devname, O_RDWR | O_NONBLOCK, 0); - if (s->fd < 0) - return AVERROR(errno); - - ret = v4l2_prepare_contexts(s); - if (ret < 0) - goto error; - - /* if a full re-init was requested - probe didn't run - we need to populate - * the format for each context - */ ret = ff_v4l2_context_get_format(&s->output); if (ret) { av_log(log_ctx, AV_LOG_DEBUG, "v4l2 output format not supported\n"); @@ -301,19 +301,25 @@ int ff_v4l2_m2m_codec_full_reinit(V4L2m2mContext *s) return 0; error: - if (close(s->fd) < 0) { - ret = AVERROR(errno); - av_log(log_ctx, AV_LOG_ERROR, "error closing %s (%s)\n", - s->devname, av_err2str(AVERROR(errno))); - } - s->fd = -1; - return ret; } +static void v4l2_m2m_destroy_context(void *opaque, uint8_t *context) +{ + V4L2m2mContext *s = (V4L2m2mContext*)context; + + ff_v4l2_context_release(&s->capture); + sem_destroy(&s->refsync); + + close(s->fd); + + av_free(s); +} + int ff_v4l2_m2m_codec_end(AVCodecContext *avctx) { - V4L2m2mContext* s = avctx->priv_data; + V4L2m2mPriv *priv = avctx->priv_data; + V4L2m2mContext* s = priv->context; int ret; ret = ff_v4l2_context_set_status(&s->output, VIDIOC_STREAMOFF); @@ -326,17 +332,8 @@ int ff_v4l2_m2m_codec_end(AVCodecContext *avctx) ff_v4l2_context_release(&s->output); - if (atomic_load(&s->refcount)) - av_log(avctx, AV_LOG_ERROR, "ff_v4l2m2m_codec_end leaving pending buffers\n"); - - ff_v4l2_context_release(&s->capture); - sem_destroy(&s->refsync); - - /* release the hardware */ - if (close(s->fd) < 0 ) - av_log(avctx, AV_LOG_ERROR, "failure closing %s (%s)\n", s->devname, av_err2str(AVERROR(errno))); - - s->fd = -1; + s->self_ref = NULL; + av_buffer_unref(&priv->context_ref); return 0; } @@ -348,7 +345,7 @@ int ff_v4l2_m2m_codec_init(AVCodecContext *avctx) char node[PATH_MAX]; DIR *dirp; - V4L2m2mContext *s = avctx->priv_data; + V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context; s->avctx = avctx; dirp = opendir("/dev"); @@ -381,3 +378,29 @@ int ff_v4l2_m2m_codec_init(AVCodecContext *avctx) return v4l2_configure_contexts(s); } + +int ff_v4l2_m2m_create_context(AVCodecContext *avctx, V4L2m2mContext **s) +{ + V4L2m2mPriv *priv = avctx->priv_data; + + *s = av_mallocz(sizeof(V4L2m2mContext)); + if (!*s) + return AVERROR(ENOMEM); + + priv->context_ref = av_buffer_create((uint8_t *) *s, sizeof(V4L2m2mContext), + &v4l2_m2m_destroy_context, NULL, 0); + if (!priv->context_ref) { + av_freep(s); + return AVERROR(ENOMEM); + } + + /* assign the context */ + priv->context = *s; + + /* populate it */ + priv->context->capture.num_buffers = priv->num_capture_buffers; + priv->context->output.num_buffers = priv->num_output_buffers; + priv->context->self_ref = priv->context_ref; + + return 0; +} diff --git a/libavcodec/v4l2_m2m.h b/libavcodec/v4l2_m2m.h index afa3987c46635..452bf0d9bc258 100644 --- a/libavcodec/v4l2_m2m.h +++ b/libavcodec/v4l2_m2m.h @@ -38,11 +38,9 @@ #define V4L_M2M_DEFAULT_OPTS \ { "num_output_buffers", "Number of buffers in the output context",\ - OFFSET(output.num_buffers), AV_OPT_TYPE_INT, { .i64 = 16 }, 6, INT_MAX, FLAGS } + OFFSET(num_output_buffers), AV_OPT_TYPE_INT, { .i64 = 16 }, 6, INT_MAX, FLAGS } -typedef struct V4L2m2mContext -{ - AVClass *class; +typedef struct V4L2m2mContext { char devname[PATH_MAX]; int fd; @@ -50,18 +48,41 @@ typedef struct V4L2m2mContext V4L2Context capture; V4L2Context output; - /* refcount of buffers held by the user */ - atomic_uint refcount; - /* dynamic stream reconfig */ AVCodecContext *avctx; sem_t refsync; + atomic_uint refcount; int reinit; /* null frame/packet received */ int draining; + + /* Reference to self; only valid while codec is active. */ + AVBufferRef *self_ref; } V4L2m2mContext; +typedef struct V4L2m2mPriv +{ + AVClass *class; + + V4L2m2mContext *context; + AVBufferRef *context_ref; + + int num_output_buffers; + int num_capture_buffers; +} V4L2m2mPriv; + +/** + * Allocate a new context and references for a V4L2 M2M instance. + * + * @param[in] ctx The AVCodecContext instantiated by the encoder/decoder. + * @param[out] ctx The V4L2m2mContext. + * + * @returns 0 in success, a negative error code otherwise. + */ +int ff_v4l2_m2m_create_context(AVCodecContext *avctx, V4L2m2mContext **s); + + /** * Probes the video nodes looking for the required codec capabilities. * diff --git a/libavcodec/v4l2_m2m_dec.c b/libavcodec/v4l2_m2m_dec.c index 958cdc522b91a..bca45be148461 100644 --- a/libavcodec/v4l2_m2m_dec.c +++ b/libavcodec/v4l2_m2m_dec.c @@ -35,7 +35,7 @@ static int v4l2_try_start(AVCodecContext *avctx) { - V4L2m2mContext *s = avctx->priv_data; + V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context; V4L2Context *const capture = &s->capture; V4L2Context *const output = &s->output; struct v4l2_selection selection; @@ -127,7 +127,7 @@ static int v4l2_prepare_decoder(V4L2m2mContext *s) static int v4l2_receive_frame(AVCodecContext *avctx, AVFrame *frame) { - V4L2m2mContext *s = avctx->priv_data; + V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context; V4L2Context *const capture = &s->capture; V4L2Context *const output = &s->output; AVPacket avpkt = {0}; @@ -159,11 +159,17 @@ static int v4l2_receive_frame(AVCodecContext *avctx, AVFrame *frame) static av_cold int v4l2_decode_init(AVCodecContext *avctx) { - V4L2m2mContext *s = avctx->priv_data; - V4L2Context *capture = &s->capture; - V4L2Context *output = &s->output; + V4L2Context *capture, *output; + V4L2m2mContext *s; int ret; + ret = ff_v4l2_m2m_create_context(avctx, &s); + if (ret < 0) + return ret; + + capture = &s->capture; + output = &s->output; + /* if these dimensions are invalid (ie, 0 or too small) an event will be raised * by the v4l2 driver; this event will trigger a full pipeline reconfig and * the proper values will be retrieved from the kernel driver. @@ -186,13 +192,13 @@ static av_cold int v4l2_decode_init(AVCodecContext *avctx) return v4l2_prepare_decoder(s); } -#define OFFSET(x) offsetof(V4L2m2mContext, x) +#define OFFSET(x) offsetof(V4L2m2mPriv, x) #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM static const AVOption options[] = { V4L_M2M_DEFAULT_OPTS, { "num_capture_buffers", "Number of buffers in the capture context", - OFFSET(capture.num_buffers), AV_OPT_TYPE_INT, {.i64 = 20}, 20, INT_MAX, FLAGS }, + OFFSET(num_capture_buffers), AV_OPT_TYPE_INT, {.i64 = 20}, 20, INT_MAX, FLAGS }, { NULL}, }; @@ -209,12 +215,14 @@ AVCodec ff_ ## NAME ## _v4l2m2m_decoder = { \ .long_name = NULL_IF_CONFIG_SMALL("V4L2 mem2mem " LONGNAME " decoder wrapper"),\ .type = AVMEDIA_TYPE_VIDEO,\ .id = CODEC ,\ - .priv_data_size = sizeof(V4L2m2mContext),\ + .priv_data_size = sizeof(V4L2m2mPriv),\ .priv_class = &v4l2_m2m_ ## NAME ## _dec_class,\ .init = v4l2_decode_init,\ .receive_frame = v4l2_receive_frame,\ .close = ff_v4l2_m2m_codec_end,\ .bsfs = bsf_name, \ + .capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY, \ + .wrapper_name = "v4l2m2m", \ }; M2MDEC(h264, "H.264", AV_CODEC_ID_H264, "h264_mp4toannexb"); diff --git a/libavcodec/v4l2_m2m_enc.c b/libavcodec/v4l2_m2m_enc.c index f71ce5fb74af1..4c9ea1fd92b72 100644 --- a/libavcodec/v4l2_m2m_enc.c +++ b/libavcodec/v4l2_m2m_enc.c @@ -204,7 +204,7 @@ static int v4l2_prepare_encoder(V4L2m2mContext *s) v4l2_set_ext_ctrl(s, MPEG_CID(MPEG4_PROFILE), val, "mpeg4 profile"); qmin_cid = MPEG_CID(MPEG4_MIN_QP); qmax_cid = MPEG_CID(MPEG4_MAX_QP); - if (avctx->flags & CODEC_FLAG_QPEL) + if (avctx->flags & AV_CODEC_FLAG_QPEL) v4l2_set_ext_ctrl(s, MPEG_CID(MPEG4_QPEL), 1, "qpel"); qmin = 1; qmax = 31; @@ -242,7 +242,7 @@ static int v4l2_prepare_encoder(V4L2m2mContext *s) static int v4l2_send_frame(AVCodecContext *avctx, const AVFrame *frame) { - V4L2m2mContext *s = avctx->priv_data; + V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context; V4L2Context *const output = &s->output; return ff_v4l2_context_enqueue_frame(output, frame); @@ -250,7 +250,7 @@ static int v4l2_send_frame(AVCodecContext *avctx, const AVFrame *frame) static int v4l2_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) { - V4L2m2mContext *s = avctx->priv_data; + V4L2m2mContext *s = ((V4L2m2mPriv*)avctx->priv_data)->context; V4L2Context *const capture = &s->capture; V4L2Context *const output = &s->output; int ret; @@ -280,11 +280,17 @@ static int v4l2_receive_packet(AVCodecContext *avctx, AVPacket *avpkt) static av_cold int v4l2_encode_init(AVCodecContext *avctx) { - V4L2m2mContext *s = avctx->priv_data; - V4L2Context *capture = &s->capture; - V4L2Context *output = &s->output; + V4L2Context *capture, *output; + V4L2m2mContext *s; int ret; + ret = ff_v4l2_m2m_create_context(avctx, &s); + if (ret < 0) + return ret; + + capture = &s->capture; + output = &s->output; + /* common settings output/capture */ output->height = capture->height = avctx->height; output->width = capture->width = avctx->width; @@ -306,13 +312,13 @@ static av_cold int v4l2_encode_init(AVCodecContext *avctx) return v4l2_prepare_encoder(s); } -#define OFFSET(x) offsetof(V4L2m2mContext, x) +#define OFFSET(x) offsetof(V4L2m2mPriv, x) #define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { V4L_M2M_DEFAULT_OPTS, { "num_capture_buffers", "Number of buffers in the capture context", - OFFSET(capture.num_buffers), AV_OPT_TYPE_INT, {.i64 = 4 }, 4, INT_MAX, FLAGS }, + OFFSET(num_capture_buffers), AV_OPT_TYPE_INT, {.i64 = 4 }, 4, INT_MAX, FLAGS }, { NULL }, }; @@ -329,12 +335,14 @@ AVCodec ff_ ## NAME ## _v4l2m2m_encoder = { \ .long_name = NULL_IF_CONFIG_SMALL("V4L2 mem2mem " LONGNAME " encoder wrapper"),\ .type = AVMEDIA_TYPE_VIDEO,\ .id = CODEC ,\ - .priv_data_size = sizeof(V4L2m2mContext),\ + .priv_data_size = sizeof(V4L2m2mPriv),\ .priv_class = &v4l2_m2m_ ## NAME ##_enc_class,\ .init = v4l2_encode_init,\ .send_frame = v4l2_send_frame,\ .receive_packet = v4l2_receive_packet,\ .close = ff_v4l2_m2m_codec_end,\ + .capabilities = AV_CODEC_CAP_HARDWARE | AV_CODEC_CAP_DELAY, \ + .wrapper_name = "v4l2m2m", \ }; M2MENC(mpeg4,"MPEG4", AV_CODEC_ID_MPEG4); diff --git a/libavcodec/vaapi.h b/libavcodec/vaapi.h index bb28455329362..2cf7da5889ab4 100644 --- a/libavcodec/vaapi.h +++ b/libavcodec/vaapi.h @@ -77,115 +77,6 @@ struct attribute_deprecated vaapi_context { * - decoding: Set by user */ uint32_t context_id; - -#if FF_API_VAAPI_CONTEXT - /** - * VAPictureParameterBuffer ID - * - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - uint32_t pic_param_buf_id; - - /** - * VAIQMatrixBuffer ID - * - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - uint32_t iq_matrix_buf_id; - - /** - * VABitPlaneBuffer ID (for VC-1 decoding) - * - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - uint32_t bitplane_buf_id; - - /** - * Slice parameter/data buffer IDs - * - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - uint32_t *slice_buf_ids; - - /** - * Number of effective slice buffer IDs to send to the HW - * - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - unsigned int n_slice_buf_ids; - - /** - * Size of pre-allocated slice_buf_ids - * - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - unsigned int slice_buf_ids_alloc; - - /** - * Pointer to VASliceParameterBuffers - * - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - void *slice_params; - - /** - * Size of a VASliceParameterBuffer element - * - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - unsigned int slice_param_size; - - /** - * Size of pre-allocated slice_params - * - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - unsigned int slice_params_alloc; - - /** - * Number of slices currently filled in - * - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - unsigned int slice_count; - - /** - * Pointer to slice data buffer base - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - const uint8_t *slice_data; - - /** - * Current size of slice data - * - * - encoding: unused - * - decoding: Set by libavcodec - */ - attribute_deprecated - uint32_t slice_data_size; -#endif }; /* @} */ diff --git a/libavcodec/vaapi_decode.c b/libavcodec/vaapi_decode.c index 27ef33837c18e..d0a6b5817d794 100644 --- a/libavcodec/vaapi_decode.c +++ b/libavcodec/vaapi_decode.c @@ -21,6 +21,7 @@ #include "libavutil/pixdesc.h" #include "avcodec.h" +#include "decode.h" #include "internal.h" #include "vaapi_decode.h" @@ -231,6 +232,132 @@ int ff_vaapi_decode_cancel(AVCodecContext *avctx, return 0; } +static const struct { + uint32_t fourcc; + enum AVPixelFormat pix_fmt; +} vaapi_format_map[] = { +#define MAP(va, av) { VA_FOURCC_ ## va, AV_PIX_FMT_ ## av } + // 4:0:0 + MAP(Y800, GRAY8), + // 4:2:0 + MAP(NV12, NV12), + MAP(YV12, YUV420P), + MAP(IYUV, YUV420P), +#ifdef VA_FOURCC_I420 + MAP(I420, YUV420P), +#endif + MAP(IMC3, YUV420P), + // 4:1:1 + MAP(411P, YUV411P), + // 4:2:2 + MAP(422H, YUV422P), +#ifdef VA_FOURCC_YV16 + MAP(YV16, YUV422P), +#endif + // 4:4:0 + MAP(422V, YUV440P), + // 4:4:4 + MAP(444P, YUV444P), + // 4:2:0 10-bit +#ifdef VA_FOURCC_P010 + MAP(P010, P010), +#endif +#ifdef VA_FOURCC_I010 + MAP(I010, YUV420P10), +#endif +#undef MAP +}; + +static int vaapi_decode_find_best_format(AVCodecContext *avctx, + AVHWDeviceContext *device, + VAConfigID config_id, + AVHWFramesContext *frames) +{ + AVVAAPIDeviceContext *hwctx = device->hwctx; + VAStatus vas; + VASurfaceAttrib *attr; + enum AVPixelFormat source_format, best_format, format; + uint32_t best_fourcc, fourcc; + int i, j, nb_attr; + + source_format = avctx->sw_pix_fmt; + av_assert0(source_format != AV_PIX_FMT_NONE); + + vas = vaQuerySurfaceAttributes(hwctx->display, config_id, + NULL, &nb_attr); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to query surface attributes: " + "%d (%s).\n", vas, vaErrorStr(vas)); + return AVERROR(ENOSYS); + } + + attr = av_malloc_array(nb_attr, sizeof(*attr)); + if (!attr) + return AVERROR(ENOMEM); + + vas = vaQuerySurfaceAttributes(hwctx->display, config_id, + attr, &nb_attr); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to query surface attributes: " + "%d (%s).\n", vas, vaErrorStr(vas)); + av_freep(&attr); + return AVERROR(ENOSYS); + } + + best_format = AV_PIX_FMT_NONE; + + for (i = 0; i < nb_attr; i++) { + if (attr[i].type != VASurfaceAttribPixelFormat) + continue; + + fourcc = attr[i].value.value.i; + for (j = 0; j < FF_ARRAY_ELEMS(vaapi_format_map); j++) { + if (fourcc == vaapi_format_map[j].fourcc) + break; + } + if (j >= FF_ARRAY_ELEMS(vaapi_format_map)) { + av_log(avctx, AV_LOG_DEBUG, "Ignoring unknown format %#x.\n", + fourcc); + continue; + } + format = vaapi_format_map[j].pix_fmt; + av_log(avctx, AV_LOG_DEBUG, "Considering format %#x -> %s.\n", + fourcc, av_get_pix_fmt_name(format)); + + best_format = av_find_best_pix_fmt_of_2(format, best_format, + source_format, 0, NULL); + if (format == best_format) + best_fourcc = fourcc; + } + + av_freep(&attr); + + if (best_format == AV_PIX_FMT_NONE) { + av_log(avctx, AV_LOG_ERROR, "No usable formats for decoding!\n"); + return AVERROR(EINVAL); + } + + av_log(avctx, AV_LOG_DEBUG, "Picked %s (%#x) as best match for %s.\n", + av_get_pix_fmt_name(best_format), best_fourcc, + av_get_pix_fmt_name(source_format)); + + frames->sw_format = best_format; + if (avctx->internal->hwaccel_priv_data) { + VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data; + AVVAAPIFramesContext *avfc = frames->hwctx; + + ctx->pixel_format_attribute = (VASurfaceAttrib) { + .type = VASurfaceAttribPixelFormat, + .value.value.i = best_fourcc, + }; + + avfc->attributes = &ctx->pixel_format_attribute; + avfc->nb_attributes = 1; + } + + return 0; +} + static const struct { enum AVCodecID codec_id; int codec_profile; @@ -252,6 +379,8 @@ static const struct { MAP(HEVC, HEVC_MAIN, HEVCMain ), MAP(HEVC, HEVC_MAIN_10, HEVCMain10 ), #endif + MAP(MJPEG, MJPEG_HUFFMAN_BASELINE_DCT, + JPEGBaseline), MAP(WMV3, VC1_SIMPLE, VC1Simple ), MAP(WMV3, VC1_MAIN, VC1Main ), MAP(WMV3, VC1_COMPLEX, VC1Advanced ), @@ -272,18 +401,25 @@ static const struct { #undef MAP }; -static int vaapi_decode_make_config(AVCodecContext *avctx) +/* + * Set *va_config and the frames_ref fields from the current codec parameters + * in avctx. + */ +static int vaapi_decode_make_config(AVCodecContext *avctx, + AVBufferRef *device_ref, + VAConfigID *va_config, + AVBufferRef *frames_ref) { - VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data; - AVVAAPIHWConfig *hwconfig = NULL; AVHWFramesConstraints *constraints = NULL; VAStatus vas; int err, i, j; const AVCodecDescriptor *codec_desc; - VAProfile profile, va_profile, *profile_list = NULL; - int profile_count, exact_match, alt_profile; - const AVPixFmtDescriptor *sw_desc, *desc; + VAProfile *profile_list = NULL, matched_va_profile; + int profile_count, exact_match, matched_ff_profile; + + AVHWDeviceContext *device = (AVHWDeviceContext*)device_ref->data; + AVVAAPIDeviceContext *hwctx = device->hwctx; codec_desc = avcodec_descriptor_get(avctx->codec_id); if (!codec_desc) { @@ -291,7 +427,7 @@ static int vaapi_decode_make_config(AVCodecContext *avctx) goto fail; } - profile_count = vaMaxNumProfiles(ctx->hwctx->display); + profile_count = vaMaxNumProfiles(hwctx->display); profile_list = av_malloc_array(profile_count, sizeof(VAProfile)); if (!profile_list) { @@ -299,7 +435,7 @@ static int vaapi_decode_make_config(AVCodecContext *avctx) goto fail; } - vas = vaQueryConfigProfiles(ctx->hwctx->display, + vas = vaQueryConfigProfiles(hwctx->display, profile_list, &profile_count); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to query profiles: " @@ -308,32 +444,32 @@ static int vaapi_decode_make_config(AVCodecContext *avctx) goto fail; } - profile = VAProfileNone; + matched_va_profile = VAProfileNone; exact_match = 0; for (i = 0; i < FF_ARRAY_ELEMS(vaapi_profile_map); i++) { int profile_match = 0; if (avctx->codec_id != vaapi_profile_map[i].codec_id) continue; - if (avctx->profile == vaapi_profile_map[i].codec_profile) + if (avctx->profile == vaapi_profile_map[i].codec_profile || + vaapi_profile_map[i].codec_profile == FF_PROFILE_UNKNOWN) profile_match = 1; - profile = vaapi_profile_map[i].va_profile; for (j = 0; j < profile_count; j++) { - if (profile == profile_list[j]) { + if (vaapi_profile_map[i].va_profile == profile_list[j]) { exact_match = profile_match; break; } } if (j < profile_count) { + matched_va_profile = vaapi_profile_map[i].va_profile; + matched_ff_profile = vaapi_profile_map[i].codec_profile; if (exact_match) break; - alt_profile = vaapi_profile_map[i].codec_profile; - va_profile = vaapi_profile_map[i].va_profile; } } av_freep(&profile_list); - if (profile == VAProfileNone) { + if (matched_va_profile == VAProfileNone) { av_log(avctx, AV_LOG_ERROR, "No support for codec %s " "profile %d.\n", codec_desc->name, avctx->profile); err = AVERROR(ENOSYS); @@ -347,8 +483,7 @@ static int vaapi_decode_make_config(AVCodecContext *avctx) codec_desc->name, avctx->profile); av_log(avctx, AV_LOG_WARNING, "Using possibly-" "incompatible profile %d instead.\n", - alt_profile); - profile = va_profile; + matched_ff_profile); } else { av_log(avctx, AV_LOG_VERBOSE, "Codec %s profile %d not " "supported for hardware decode.\n", @@ -358,12 +493,9 @@ static int vaapi_decode_make_config(AVCodecContext *avctx) } } - ctx->va_profile = profile; - ctx->va_entrypoint = VAEntrypointVLD; - - vas = vaCreateConfig(ctx->hwctx->display, ctx->va_profile, - ctx->va_entrypoint, NULL, 0, - &ctx->va_config); + vas = vaCreateConfig(hwctx->display, matched_va_profile, + VAEntrypointVLD, NULL, 0, + va_config); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to create decode " "configuration: %d (%s).\n", vas, vaErrorStr(vas)); @@ -371,20 +503,15 @@ static int vaapi_decode_make_config(AVCodecContext *avctx) goto fail; } - hwconfig = av_hwdevice_hwconfig_alloc(avctx->hw_device_ctx ? - avctx->hw_device_ctx : - ctx->frames->device_ref); + hwconfig = av_hwdevice_hwconfig_alloc(device_ref); if (!hwconfig) { err = AVERROR(ENOMEM); goto fail; } - hwconfig->config_id = ctx->va_config; + hwconfig->config_id = *va_config; constraints = - av_hwdevice_get_hwframe_constraints(avctx->hw_device_ctx ? - avctx->hw_device_ctx : - ctx->frames->device_ref, - hwconfig); + av_hwdevice_get_hwframe_constraints(device_ref, hwconfig); if (!constraints) { err = AVERROR(ENOMEM); goto fail; @@ -410,48 +537,35 @@ static int vaapi_decode_make_config(AVCodecContext *avctx) goto fail; } - // Find the first format in the list which matches the expected - // bit depth and subsampling. If none are found (this can happen - // when 10-bit streams are decoded to 8-bit surfaces, for example) - // then just take the first format on the list. - ctx->surface_format = constraints->valid_sw_formats[0]; - sw_desc = av_pix_fmt_desc_get(avctx->sw_pix_fmt); - for (i = 0; constraints->valid_sw_formats[i] != AV_PIX_FMT_NONE; i++) { - desc = av_pix_fmt_desc_get(constraints->valid_sw_formats[i]); - if (desc->nb_components != sw_desc->nb_components || - desc->log2_chroma_w != sw_desc->log2_chroma_w || - desc->log2_chroma_h != sw_desc->log2_chroma_h) - continue; - for (j = 0; j < desc->nb_components; j++) { - if (desc->comp[j].depth != sw_desc->comp[j].depth) - break; + if (frames_ref) { + AVHWFramesContext *frames = (AVHWFramesContext *)frames_ref->data; + + frames->format = AV_PIX_FMT_VAAPI; + frames->width = avctx->coded_width; + frames->height = avctx->coded_height; + + err = vaapi_decode_find_best_format(avctx, device, + *va_config, frames); + if (err < 0) + goto fail; + + frames->initial_pool_size = 1; + // Add per-codec number of surfaces used for storing reference frames. + switch (avctx->codec_id) { + case AV_CODEC_ID_H264: + case AV_CODEC_ID_HEVC: + frames->initial_pool_size += 16; + break; + case AV_CODEC_ID_VP9: + frames->initial_pool_size += 8; + break; + case AV_CODEC_ID_VP8: + frames->initial_pool_size += 3; + break; + default: + frames->initial_pool_size += 2; } - if (j < desc->nb_components) - continue; - ctx->surface_format = constraints->valid_sw_formats[i]; - break; - } - - // Start with at least four surfaces. - ctx->surface_count = 4; - // Add per-codec number of surfaces used for storing reference frames. - switch (avctx->codec_id) { - case AV_CODEC_ID_H264: - case AV_CODEC_ID_HEVC: - ctx->surface_count += 16; - break; - case AV_CODEC_ID_VP9: - ctx->surface_count += 8; - break; - case AV_CODEC_ID_VP8: - ctx->surface_count += 3; - break; - default: - ctx->surface_count += 2; - } - // Add an additional surface per thread is frame threading is enabled. - if (avctx->active_thread_type & FF_THREAD_FRAME) - ctx->surface_count += avctx->thread_count; + } av_hwframe_constraints_free(&constraints); av_freep(&hwconfig); @@ -461,14 +575,38 @@ static int vaapi_decode_make_config(AVCodecContext *avctx) fail: av_hwframe_constraints_free(&constraints); av_freep(&hwconfig); - if (ctx->va_config != VA_INVALID_ID) { - vaDestroyConfig(ctx->hwctx->display, ctx->va_config); - ctx->va_config = VA_INVALID_ID; + if (*va_config != VA_INVALID_ID) { + vaDestroyConfig(hwctx->display, *va_config); + *va_config = VA_INVALID_ID; } av_freep(&profile_list); return err; } +int ff_vaapi_common_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx) +{ + AVHWFramesContext *hw_frames = (AVHWFramesContext *)hw_frames_ctx->data; + AVHWDeviceContext *device_ctx = hw_frames->device_ctx; + AVVAAPIDeviceContext *hwctx; + VAConfigID va_config = VA_INVALID_ID; + int err; + + if (device_ctx->type != AV_HWDEVICE_TYPE_VAAPI) + return AVERROR(EINVAL); + hwctx = device_ctx->hwctx; + + err = vaapi_decode_make_config(avctx, hw_frames->device_ref, &va_config, + hw_frames_ctx); + if (err) + return err; + + if (va_config != VA_INVALID_ID) + vaDestroyConfig(hwctx->display, va_config); + + return 0; +} + int ff_vaapi_decode_init(AVCodecContext *avctx) { VAAPIDecodeContext *ctx = avctx->internal->hwaccel_priv_data; @@ -505,36 +643,8 @@ int ff_vaapi_decode_init(AVCodecContext *avctx) ctx->hwctx->driver_quirks = AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS; - } else -#endif - if (avctx->hw_frames_ctx) { - // This structure has a shorter lifetime than the enclosing - // AVCodecContext, so we inherit the references from there - // and do not need to make separate ones. - - ctx->frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data; - ctx->hwfc = ctx->frames->hwctx; - ctx->device = ctx->frames->device_ctx; - ctx->hwctx = ctx->device->hwctx; - - } else if (avctx->hw_device_ctx) { - ctx->device = (AVHWDeviceContext*)avctx->hw_device_ctx->data; - ctx->hwctx = ctx->device->hwctx; - - if (ctx->device->type != AV_HWDEVICE_TYPE_VAAPI) { - av_log(avctx, AV_LOG_ERROR, "Device supplied for VAAPI " - "decoding must be a VAAPI device (not %d).\n", - ctx->device->type); - err = AVERROR(EINVAL); - goto fail; - } - - } else { - av_log(avctx, AV_LOG_ERROR, "A hardware device or frames context " - "is required for VAAPI decoding.\n"); - err = AVERROR(EINVAL); - goto fail; } +#endif #if FF_API_STRUCT_VAAPI_CONTEXT if (ctx->have_old_context) { @@ -546,34 +656,19 @@ int ff_vaapi_decode_init(AVCodecContext *avctx) } else { #endif - err = vaapi_decode_make_config(avctx); - if (err) + err = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_VAAPI); + if (err < 0) goto fail; - if (!avctx->hw_frames_ctx) { - avctx->hw_frames_ctx = av_hwframe_ctx_alloc(avctx->hw_device_ctx); - if (!avctx->hw_frames_ctx) { - err = AVERROR(ENOMEM); - goto fail; - } - ctx->frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + ctx->frames = (AVHWFramesContext*)avctx->hw_frames_ctx->data; + ctx->hwfc = ctx->frames->hwctx; + ctx->device = ctx->frames->device_ctx; + ctx->hwctx = ctx->device->hwctx; - ctx->frames->format = AV_PIX_FMT_VAAPI; - ctx->frames->width = avctx->coded_width; - ctx->frames->height = avctx->coded_height; - - ctx->frames->sw_format = ctx->surface_format; - ctx->frames->initial_pool_size = ctx->surface_count; - - err = av_hwframe_ctx_init(avctx->hw_frames_ctx); - if (err < 0) { - av_log(avctx, AV_LOG_ERROR, "Failed to initialise internal " - "frames context: %d.\n", err); - goto fail; - } - - ctx->hwfc = ctx->frames->hwctx; - } + err = vaapi_decode_make_config(avctx, ctx->frames->device_ref, + &ctx->va_config, avctx->hw_frames_ctx); + if (err) + goto fail; vas = vaCreateContext(ctx->hwctx->display, ctx->va_config, avctx->coded_width, avctx->coded_height, diff --git a/libavcodec/vaapi_decode.h b/libavcodec/vaapi_decode.h index 550ee0543252a..6b415dd1d36d0 100644 --- a/libavcodec/vaapi_decode.h +++ b/libavcodec/vaapi_decode.h @@ -53,8 +53,6 @@ typedef struct VAAPIDecodePicture { } VAAPIDecodePicture; typedef struct VAAPIDecodeContext { - VAProfile va_profile; - VAEntrypoint va_entrypoint; VAConfigID va_config; VAContextID va_context; @@ -74,6 +72,8 @@ FF_ENABLE_DEPRECATION_WARNINGS enum AVPixelFormat surface_format; int surface_count; + + VASurfaceAttrib pixel_format_attribute; } VAAPIDecodeContext; @@ -98,4 +98,7 @@ int ff_vaapi_decode_cancel(AVCodecContext *avctx, int ff_vaapi_decode_init(AVCodecContext *avctx); int ff_vaapi_decode_uninit(AVCodecContext *avctx); +int ff_vaapi_common_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx); + #endif /* AVCODEC_VAAPI_DECODE_H */ diff --git a/libavcodec/vaapi_encode.c b/libavcodec/vaapi_encode.c index 590f4be4ed041..36c85a381547a 100644 --- a/libavcodec/vaapi_encode.c +++ b/libavcodec/vaapi_encode.c @@ -321,10 +321,12 @@ static int vaapi_encode_issue(AVCodecContext *avctx, } } - pic->slices = av_mallocz_array(pic->nb_slices, sizeof(*pic->slices)); - if (!pic->slices) { - err = AVERROR(ENOMEM); - goto fail; + if (pic->nb_slices > 0) { + pic->slices = av_mallocz_array(pic->nb_slices, sizeof(*pic->slices)); + if (!pic->slices) { + err = AVERROR(ENOMEM); + goto fail; + } } for (i = 0; i < pic->nb_slices; i++) { slice = &pic->slices[i]; @@ -1036,6 +1038,8 @@ static av_cold int vaapi_encode_config_attributes(AVCodecContext *avctx) // Unfortunately we have to treat this as "don't know" and hope // for the best, because the Intel MJPEG encoder returns this // for all the interesting attributes. + av_log(avctx, AV_LOG_DEBUG, "Attribute (%d) is not supported.\n", + attr[i].type); continue; } switch (attr[i].type) { @@ -1092,10 +1096,10 @@ static av_cold int vaapi_encode_config_attributes(AVCodecContext *avctx) goto fail; } if (avctx->max_b_frames > 0 && ref_l1 < 1) { - av_log(avctx, AV_LOG_ERROR, "B frames are not " - "supported (%#x).\n", attr[i].value); - err = AVERROR(EINVAL); - goto fail; + av_log(avctx, AV_LOG_WARNING, "B frames are not " + "supported (%#x) by the underlying driver.\n", + attr[i].value); + avctx->max_b_frames = 0; } } break; @@ -1560,6 +1564,8 @@ av_cold int ff_vaapi_encode_close(AVCodecContext *avctx) vaapi_encode_free(avctx, pic); } + av_buffer_pool_uninit(&ctx->output_buffer_pool); + if (ctx->va_context != VA_INVALID_ID) { vaDestroyContext(ctx->hwctx->display, ctx->va_context); ctx->va_context = VA_INVALID_ID; @@ -1570,8 +1576,6 @@ av_cold int ff_vaapi_encode_close(AVCodecContext *avctx) ctx->va_config = VA_INVALID_ID; } - av_buffer_pool_uninit(&ctx->output_buffer_pool); - av_freep(&ctx->codec_sequence_params); av_freep(&ctx->codec_picture_params); diff --git a/libavcodec/vaapi_encode_h264.c b/libavcodec/vaapi_encode_h264.c index efde80b08ee9c..56ad217b4a53f 100644 --- a/libavcodec/vaapi_encode_h264.c +++ b/libavcodec/vaapi_encode_h264.c @@ -16,128 +16,37 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include #include #include "libavutil/avassert.h" +#include "libavutil/common.h" #include "libavutil/internal.h" #include "libavutil/opt.h" -#include "libavutil/pixfmt.h" #include "avcodec.h" +#include "cbs.h" +#include "cbs_h264.h" #include "h264.h" #include "h264_sei.h" #include "internal.h" #include "vaapi_encode.h" -#include "vaapi_encode_h26x.h" enum { - SLICE_TYPE_P = 0, - SLICE_TYPE_B = 1, - SLICE_TYPE_I = 2, - SLICE_TYPE_SP = 3, - SLICE_TYPE_SI = 4, + SEI_TIMING = 0x01, + SEI_IDENTIFIER = 0x02, + SEI_RECOVERY_POINT = 0x04, }; -// This structure contains all possibly-useful per-sequence syntax elements -// which are not already contained in the various VAAPI structures. -typedef struct VAAPIEncodeH264MiscSequenceParams { - unsigned int profile_idc; - char constraint_set0_flag; - char constraint_set1_flag; - char constraint_set2_flag; - char constraint_set3_flag; - char constraint_set4_flag; - char constraint_set5_flag; - - char separate_colour_plane_flag; - char qpprime_y_zero_transform_bypass_flag; - - char gaps_in_frame_num_allowed_flag; - char delta_pic_order_always_zero_flag; - char bottom_field_pic_order_in_frame_present_flag; - - unsigned int num_slice_groups_minus1; - unsigned int slice_group_map_type; - - int pic_init_qs_minus26; - - char overscan_info_present_flag; - char overscan_appropriate_flag; - - char video_signal_type_present_flag; - unsigned int video_format; - char video_full_range_flag; - char colour_description_present_flag; - unsigned int colour_primaries; - unsigned int transfer_characteristics; - unsigned int matrix_coefficients; - - char chroma_loc_info_present_flag; - unsigned int chroma_sample_loc_type_top_field; - unsigned int chroma_sample_loc_type_bottom_field; - - // Some timing elements are in VAEncSequenceParameterBufferH264. - char fixed_frame_rate_flag; - - char nal_hrd_parameters_present_flag; - char vcl_hrd_parameters_present_flag; - char low_delay_hrd_flag; - char pic_struct_present_flag; - - char motion_vectors_over_pic_boundaries_flag; - unsigned int max_bytes_per_pic_denom; - unsigned int max_bits_per_mb_denom; - unsigned int max_num_reorder_frames; - unsigned int max_dec_pic_buffering; - - unsigned int cpb_cnt_minus1; - unsigned int bit_rate_scale; - unsigned int cpb_size_scale; - unsigned int bit_rate_value_minus1[32]; - unsigned int cpb_size_value_minus1[32]; - char cbr_flag[32]; - unsigned int initial_cpb_removal_delay_length_minus1; - unsigned int cpb_removal_delay_length_minus1; - unsigned int dpb_output_delay_length_minus1; - unsigned int time_offset_length; - - unsigned int initial_cpb_removal_delay; - unsigned int initial_cpb_removal_delay_offset; - - unsigned int pic_struct; -} VAAPIEncodeH264MiscSequenceParams; - -// This structure contains all possibly-useful per-slice syntax elements -// which are not already contained in the various VAAPI structures. -typedef struct VAAPIEncodeH264MiscSliceParams { - unsigned int nal_unit_type; - unsigned int nal_ref_idc; - - unsigned int colour_plane_id; - char field_pic_flag; - char bottom_field_flag; - - unsigned int redundant_pic_cnt; - - char sp_for_switch_flag; - int slice_qs_delta; - - char ref_pic_list_modification_flag_l0; - char ref_pic_list_modification_flag_l1; - - char no_output_of_prior_pics_flag; - char long_term_reference_flag; - char adaptive_ref_pic_marking_mode_flag; -} VAAPIEncodeH264MiscSliceParams; - -typedef struct VAAPIEncodeH264Slice { - VAAPIEncodeH264MiscSliceParams misc_slice_params; -} VAAPIEncodeH264Slice; +// Random (version 4) ISO 11578 UUID. +static const uint8_t vaapi_encode_h264_sei_identifier_uuid[16] = { + 0x59, 0x94, 0x8b, 0x28, 0x11, 0xec, 0x45, 0xaf, + 0x96, 0x75, 0x19, 0xd4, 0x1f, 0xea, 0xa9, 0x4d, +}; typedef struct VAAPIEncodeH264Context { - VAAPIEncodeH264MiscSequenceParams misc_sequence_params; - int mb_width; int mb_height; @@ -145,15 +54,35 @@ typedef struct VAAPIEncodeH264Context { int fixed_qp_p; int fixed_qp_b; + H264RawAUD aud; + H264RawSPS sps; + H264RawPPS pps; + H264RawSEI sei; + H264RawSlice slice; + + H264RawSEIBufferingPeriod buffering_period; + H264RawSEIPicTiming pic_timing; + H264RawSEIRecoveryPoint recovery_point; + H264RawSEIUserDataUnregistered identifier; + char *identifier_string; + + int frame_num; + int pic_order_cnt; int next_frame_num; int64_t last_idr_frame; int64_t idr_pic_count; + int primary_pic_type; + int slice_type; + int cpb_delay; int dpb_delay; - // Rate control configuration. - int send_timing_sei; + CodedBitstreamContext *cbc; + CodedBitstreamFragment current_access_unit; + int aud_needed; + int sei_needed; + int sei_cbr_workaround_needed; } VAAPIEncodeH264Context; typedef struct VAAPIEncodeH264Options { @@ -162,785 +91,484 @@ typedef struct VAAPIEncodeH264Options { int low_power; // Entropy encoder type. int coder; + int aud; + int sei; + int profile; + int level; } VAAPIEncodeH264Options; -#define vseq_var(name) vseq->name, name -#define vseq_field(name) vseq->seq_fields.bits.name, name -#define vvui_field(name) vseq->vui_fields.bits.name, name -#define vpic_var(name) vpic->name, name -#define vpic_field(name) vpic->pic_fields.bits.name, name -#define vslice_var(name) vslice->name, name -#define vslice_field(name) vslice->slice_fields.bits.name, name -#define mseq_var(name) mseq->name, name -#define mslice_var(name) mslice->name, name - -static void vaapi_encode_h264_write_nal_header(PutBitContext *pbc, - int nal_unit_type, int nal_ref_idc) -{ - u(1, 0, forbidden_zero_bit); - u(2, nal_ref_idc, nal_ref_idc); - u(5, nal_unit_type, nal_unit_type); -} - -static void vaapi_encode_h264_write_trailing_rbsp(PutBitContext *pbc) -{ - u(1, 1, rbsp_stop_one_bit); - while (put_bits_count(pbc) & 7) - u(1, 0, rbsp_alignment_zero_bit); -} - -static void vaapi_encode_h264_write_vui(PutBitContext *pbc, - VAAPIEncodeContext *ctx) +static int vaapi_encode_h264_write_access_unit(AVCodecContext *avctx, + char *data, size_t *data_len, + CodedBitstreamFragment *au) { - VAEncSequenceParameterBufferH264 *vseq = ctx->codec_sequence_params; - VAAPIEncodeH264Context *priv = ctx->priv_data; - VAAPIEncodeH264MiscSequenceParams *mseq = &priv->misc_sequence_params; - int i; - - u(1, vvui_field(aspect_ratio_info_present_flag)); - if (vseq->vui_fields.bits.aspect_ratio_info_present_flag) { - u(8, vseq_var(aspect_ratio_idc)); - if (vseq->aspect_ratio_idc == 255) { - u(16, vseq_var(sar_width)); - u(16, vseq_var(sar_height)); - } - } - - u(1, mseq_var(overscan_info_present_flag)); - if (mseq->overscan_info_present_flag) - u(1, mseq_var(overscan_appropriate_flag)); - - u(1, mseq_var(video_signal_type_present_flag)); - if (mseq->video_signal_type_present_flag) { - u(3, mseq_var(video_format)); - u(1, mseq_var(video_full_range_flag)); - u(1, mseq_var(colour_description_present_flag)); - if (mseq->colour_description_present_flag) { - u(8, mseq_var(colour_primaries)); - u(8, mseq_var(transfer_characteristics)); - u(8, mseq_var(matrix_coefficients)); - } - } + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH264Context *priv = ctx->priv_data; + int err; - u(1, mseq_var(chroma_loc_info_present_flag)); - if (mseq->chroma_loc_info_present_flag) { - ue(mseq_var(chroma_sample_loc_type_top_field)); - ue(mseq_var(chroma_sample_loc_type_bottom_field)); + err = ff_cbs_write_fragment_data(priv->cbc, au); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to write packed header.\n"); + return err; } - u(1, vvui_field(timing_info_present_flag)); - if (vseq->vui_fields.bits.timing_info_present_flag) { - u(32, vseq_var(num_units_in_tick)); - u(32, vseq_var(time_scale)); - u(1, mseq_var(fixed_frame_rate_flag)); + if (*data_len < 8 * au->data_size - au->data_bit_padding) { + av_log(avctx, AV_LOG_ERROR, "Access unit too large: " + "%zu < %zu.\n", *data_len, + 8 * au->data_size - au->data_bit_padding); + return AVERROR(ENOSPC); } - u(1, mseq_var(nal_hrd_parameters_present_flag)); - if (mseq->nal_hrd_parameters_present_flag) { - ue(mseq_var(cpb_cnt_minus1)); - u(4, mseq_var(bit_rate_scale)); - u(4, mseq_var(cpb_size_scale)); - for (i = 0; i <= mseq->cpb_cnt_minus1; i++) { - ue(mseq_var(bit_rate_value_minus1[i])); - ue(mseq_var(cpb_size_value_minus1[i])); - u(1, mseq_var(cbr_flag[i])); - } - u(5, mseq_var(initial_cpb_removal_delay_length_minus1)); - u(5, mseq_var(cpb_removal_delay_length_minus1)); - u(5, mseq_var(dpb_output_delay_length_minus1)); - u(5, mseq_var(time_offset_length)); - } - u(1, mseq_var(vcl_hrd_parameters_present_flag)); - if (mseq->vcl_hrd_parameters_present_flag) { - av_assert0(0 && "vcl hrd parameters not supported"); - } + memcpy(data, au->data, au->data_size); + *data_len = 8 * au->data_size - au->data_bit_padding; - if (mseq->nal_hrd_parameters_present_flag || - mseq->vcl_hrd_parameters_present_flag) - u(1, mseq_var(low_delay_hrd_flag)); - u(1, mseq_var(pic_struct_present_flag)); - - u(1, vvui_field(bitstream_restriction_flag)); - if (vseq->vui_fields.bits.bitstream_restriction_flag) { - u(1, mseq_var(motion_vectors_over_pic_boundaries_flag)); - ue(mseq_var(max_bytes_per_pic_denom)); - ue(mseq_var(max_bits_per_mb_denom)); - ue(vvui_field(log2_max_mv_length_horizontal)); - ue(vvui_field(log2_max_mv_length_vertical)); - ue(mseq_var(max_num_reorder_frames)); - ue(mseq_var(max_dec_pic_buffering)); - } + return 0; } -static void vaapi_encode_h264_write_sps(PutBitContext *pbc, - VAAPIEncodeContext *ctx) +static int vaapi_encode_h264_add_nal(AVCodecContext *avctx, + CodedBitstreamFragment *au, + void *nal_unit) { - VAEncSequenceParameterBufferH264 *vseq = ctx->codec_sequence_params; - VAAPIEncodeH264Context *priv = ctx->priv_data; - VAAPIEncodeH264MiscSequenceParams *mseq = &priv->misc_sequence_params; - int i; - - vaapi_encode_h264_write_nal_header(pbc, H264_NAL_SPS, 3); - - u(8, mseq_var(profile_idc)); - u(1, mseq_var(constraint_set0_flag)); - u(1, mseq_var(constraint_set1_flag)); - u(1, mseq_var(constraint_set2_flag)); - u(1, mseq_var(constraint_set3_flag)); - u(1, mseq_var(constraint_set4_flag)); - u(1, mseq_var(constraint_set5_flag)); - u(2, 0, reserved_zero_2bits); - - u(8, vseq_var(level_idc)); - - ue(vseq_var(seq_parameter_set_id)); - - if (mseq->profile_idc == 100 || mseq->profile_idc == 110 || - mseq->profile_idc == 122 || mseq->profile_idc == 244 || - mseq->profile_idc == 44 || mseq->profile_idc == 83 || - mseq->profile_idc == 86 || mseq->profile_idc == 118 || - mseq->profile_idc == 128 || mseq->profile_idc == 138) { - ue(vseq_field(chroma_format_idc)); - - if (vseq->seq_fields.bits.chroma_format_idc == 3) - u(1, mseq_var(separate_colour_plane_flag)); - - ue(vseq_var(bit_depth_luma_minus8)); - ue(vseq_var(bit_depth_chroma_minus8)); - - u(1, mseq_var(qpprime_y_zero_transform_bypass_flag)); - - u(1, vseq_field(seq_scaling_matrix_present_flag)); - if (vseq->seq_fields.bits.seq_scaling_matrix_present_flag) { - av_assert0(0 && "scaling matrices not supported"); - } - } - - ue(vseq_field(log2_max_frame_num_minus4)); - ue(vseq_field(pic_order_cnt_type)); - - if (vseq->seq_fields.bits.pic_order_cnt_type == 0) { - ue(vseq_field(log2_max_pic_order_cnt_lsb_minus4)); - } else if (vseq->seq_fields.bits.pic_order_cnt_type == 1) { - u(1, mseq_var(delta_pic_order_always_zero_flag)); - se(vseq_var(offset_for_non_ref_pic)); - se(vseq_var(offset_for_top_to_bottom_field)); - ue(vseq_var(num_ref_frames_in_pic_order_cnt_cycle)); - - for (i = 0; i < vseq->num_ref_frames_in_pic_order_cnt_cycle; i++) - se(vseq_var(offset_for_ref_frame[i])); - } - - ue(vseq_var(max_num_ref_frames)); - u(1, mseq_var(gaps_in_frame_num_allowed_flag)); - - ue(vseq->picture_width_in_mbs - 1, pic_width_in_mbs_minus1); - ue(vseq->picture_height_in_mbs - 1, pic_height_in_mbs_minus1); - - u(1, vseq_field(frame_mbs_only_flag)); - if (!vseq->seq_fields.bits.frame_mbs_only_flag) - u(1, vseq_field(mb_adaptive_frame_field_flag)); - - u(1, vseq_field(direct_8x8_inference_flag)); + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH264Context *priv = ctx->priv_data; + H264RawNALUnitHeader *header = nal_unit; + int err; - u(1, vseq_var(frame_cropping_flag)); - if (vseq->frame_cropping_flag) { - ue(vseq_var(frame_crop_left_offset)); - ue(vseq_var(frame_crop_right_offset)); - ue(vseq_var(frame_crop_top_offset)); - ue(vseq_var(frame_crop_bottom_offset)); + err = ff_cbs_insert_unit_content(priv->cbc, au, -1, + header->nal_unit_type, nal_unit, NULL); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to add NAL unit: " + "type = %d.\n", header->nal_unit_type); + return err; } - u(1, vseq_var(vui_parameters_present_flag)); - if (vseq->vui_parameters_present_flag) - vaapi_encode_h264_write_vui(pbc, ctx); - - vaapi_encode_h264_write_trailing_rbsp(pbc); + return 0; } -static void vaapi_encode_h264_write_pps(PutBitContext *pbc, - VAAPIEncodeContext *ctx) +static int vaapi_encode_h264_write_sequence_header(AVCodecContext *avctx, + char *data, size_t *data_len) { - VAEncPictureParameterBufferH264 *vpic = ctx->codec_picture_params; - VAAPIEncodeH264Context *priv = ctx->priv_data; - VAAPIEncodeH264MiscSequenceParams *mseq = &priv->misc_sequence_params; - - vaapi_encode_h264_write_nal_header(pbc, H264_NAL_PPS, 3); - - ue(vpic_var(pic_parameter_set_id)); - ue(vpic_var(seq_parameter_set_id)); - - u(1, vpic_field(entropy_coding_mode_flag)); - u(1, mseq_var(bottom_field_pic_order_in_frame_present_flag)); + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH264Context *priv = ctx->priv_data; + CodedBitstreamFragment *au = &priv->current_access_unit; + int err; - ue(mseq_var(num_slice_groups_minus1)); - if (mseq->num_slice_groups_minus1 > 0) { - ue(mseq_var(slice_group_map_type)); - av_assert0(0 && "slice groups not supported"); + if (priv->aud_needed) { + err = vaapi_encode_h264_add_nal(avctx, au, &priv->aud); + if (err < 0) + goto fail; + priv->aud_needed = 0; } - ue(vpic_var(num_ref_idx_l0_active_minus1)); - ue(vpic_var(num_ref_idx_l1_active_minus1)); - - u(1, vpic_field(weighted_pred_flag)); - u(2, vpic_field(weighted_bipred_idc)); - - se(vpic->pic_init_qp - 26, pic_init_qp_minus26); - se(mseq_var(pic_init_qs_minus26)); - se(vpic_var(chroma_qp_index_offset)); - - u(1, vpic_field(deblocking_filter_control_present_flag)); - u(1, vpic_field(constrained_intra_pred_flag)); - u(1, vpic_field(redundant_pic_cnt_present_flag)); - u(1, vpic_field(transform_8x8_mode_flag)); - - u(1, vpic_field(pic_scaling_matrix_present_flag)); - if (vpic->pic_fields.bits.pic_scaling_matrix_present_flag) { - av_assert0(0 && "scaling matrices not supported"); - } + err = vaapi_encode_h264_add_nal(avctx, au, &priv->sps); + if (err < 0) + goto fail; - se(vpic_var(second_chroma_qp_index_offset)); + err = vaapi_encode_h264_add_nal(avctx, au, &priv->pps); + if (err < 0) + goto fail; - vaapi_encode_h264_write_trailing_rbsp(pbc); + err = vaapi_encode_h264_write_access_unit(avctx, data, data_len, au); +fail: + ff_cbs_fragment_uninit(priv->cbc, au); + return err; } -static void vaapi_encode_h264_write_slice_header2(PutBitContext *pbc, - VAAPIEncodeContext *ctx, - VAAPIEncodePicture *pic, - VAAPIEncodeSlice *slice) +static int vaapi_encode_h264_write_slice_header(AVCodecContext *avctx, + VAAPIEncodePicture *pic, + VAAPIEncodeSlice *slice, + char *data, size_t *data_len) { - VAEncSequenceParameterBufferH264 *vseq = ctx->codec_sequence_params; - VAEncPictureParameterBufferH264 *vpic = pic->codec_picture_params; - VAEncSliceParameterBufferH264 *vslice = slice->codec_slice_params; - VAAPIEncodeH264Context *priv = ctx->priv_data; - VAAPIEncodeH264MiscSequenceParams *mseq = &priv->misc_sequence_params; - VAAPIEncodeH264Slice *pslice = slice->priv_data; - VAAPIEncodeH264MiscSliceParams *mslice = &pslice->misc_slice_params; - - vaapi_encode_h264_write_nal_header(pbc, mslice->nal_unit_type, - mslice->nal_ref_idc); - - ue(vslice->macroblock_address, first_mb_in_slice); - ue(vslice_var(slice_type)); - ue(vpic_var(pic_parameter_set_id)); - - if (mseq->separate_colour_plane_flag) { - u(2, mslice_var(colour_plane_id)); - } - - u(4 + vseq->seq_fields.bits.log2_max_frame_num_minus4, - (vpic->frame_num & - ((1 << (4 + vseq->seq_fields.bits.log2_max_frame_num_minus4)) - 1)), - frame_num); + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH264Context *priv = ctx->priv_data; + CodedBitstreamFragment *au = &priv->current_access_unit; + int err; - if (!vseq->seq_fields.bits.frame_mbs_only_flag) { - u(1, mslice_var(field_pic_flag)); - if (mslice->field_pic_flag) - u(1, mslice_var(bottom_field_flag)); + if (priv->aud_needed) { + err = vaapi_encode_h264_add_nal(avctx, au, &priv->aud); + if (err < 0) + goto fail; + priv->aud_needed = 0; } - if (vpic->pic_fields.bits.idr_pic_flag) { - ue(vslice_var(idr_pic_id)); - } + err = vaapi_encode_h264_add_nal(avctx, au, &priv->slice); + if (err < 0) + goto fail; - if (vseq->seq_fields.bits.pic_order_cnt_type == 0) { - u(4 + vseq->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4, - vslice_var(pic_order_cnt_lsb)); - if (mseq->bottom_field_pic_order_in_frame_present_flag && - !mslice->field_pic_flag) { - se(vslice_var(delta_pic_order_cnt_bottom)); - } - } + err = vaapi_encode_h264_write_access_unit(avctx, data, data_len, au); +fail: + ff_cbs_fragment_uninit(priv->cbc, au); + return err; +} - if (vseq->seq_fields.bits.pic_order_cnt_type == 1 && - !vseq->seq_fields.bits.delta_pic_order_always_zero_flag) { - se(vslice_var(delta_pic_order_cnt[0])); - if (mseq->bottom_field_pic_order_in_frame_present_flag && - !mslice->field_pic_flag) { - se(vslice_var(delta_pic_order_cnt[1])); +static int vaapi_encode_h264_write_extra_header(AVCodecContext *avctx, + VAAPIEncodePicture *pic, + int index, int *type, + char *data, size_t *data_len) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH264Context *priv = ctx->priv_data; + VAAPIEncodeH264Options *opt = ctx->codec_options; + CodedBitstreamFragment *au = &priv->current_access_unit; + int err, i; + + if (priv->sei_needed) { + if (priv->aud_needed) { + err = vaapi_encode_h264_add_nal(avctx, au, &priv->aud); + if (err < 0) + goto fail; + priv->aud_needed = 0; } - } - if (vpic->pic_fields.bits.redundant_pic_cnt_present_flag) { - ue(mslice_var(redundant_pic_cnt)); - } + memset(&priv->sei, 0, sizeof(priv->sei)); + priv->sei.nal_unit_header.nal_unit_type = H264_NAL_SEI; - if (vslice->slice_type == SLICE_TYPE_B) { - u(1, vslice_var(direct_spatial_mv_pred_flag)); - } - - if (vslice->slice_type == SLICE_TYPE_P || - vslice->slice_type == SLICE_TYPE_SP || - vslice->slice_type == SLICE_TYPE_B) { - u(1, vslice_var(num_ref_idx_active_override_flag)); - if (vslice->num_ref_idx_active_override_flag) { - ue(vslice_var(num_ref_idx_l0_active_minus1)); - if (vslice->slice_type == SLICE_TYPE_B) - ue(vslice_var(num_ref_idx_l1_active_minus1)); + i = 0; + if (pic->encode_order == 0 && opt->sei & SEI_IDENTIFIER) { + priv->sei.payload[i].payload_type = H264_SEI_TYPE_USER_DATA_UNREGISTERED; + priv->sei.payload[i].payload.user_data_unregistered = priv->identifier; + ++i; } - } - - if (mslice->nal_unit_type == 20 || mslice->nal_unit_type == 21) { - av_assert0(0 && "no MVC support"); - } else { - if (vslice->slice_type % 5 != 2 && vslice->slice_type % 5 != 4) { - u(1, mslice_var(ref_pic_list_modification_flag_l0)); - if (mslice->ref_pic_list_modification_flag_l0) { - av_assert0(0 && "ref pic list modification"); + if (opt->sei & SEI_TIMING) { + if (pic->type == PICTURE_TYPE_IDR) { + priv->sei.payload[i].payload_type = H264_SEI_TYPE_BUFFERING_PERIOD; + priv->sei.payload[i].payload.buffering_period = priv->buffering_period; + ++i; } + priv->sei.payload[i].payload_type = H264_SEI_TYPE_PIC_TIMING; + priv->sei.payload[i].payload.pic_timing = priv->pic_timing; + ++i; } - if (vslice->slice_type % 5 == 1) { - u(1, mslice_var(ref_pic_list_modification_flag_l1)); - if (mslice->ref_pic_list_modification_flag_l1) { - av_assert0(0 && "ref pic list modification"); - } + if (opt->sei & SEI_RECOVERY_POINT && pic->type == PICTURE_TYPE_I) { + priv->sei.payload[i].payload_type = H264_SEI_TYPE_RECOVERY_POINT; + priv->sei.payload[i].payload.recovery_point = priv->recovery_point; + ++i; } - } - if ((vpic->pic_fields.bits.weighted_pred_flag && - (vslice->slice_type == SLICE_TYPE_P || - vslice->slice_type == SLICE_TYPE_SP)) || - (vpic->pic_fields.bits.weighted_bipred_idc == 1 && - vslice->slice_type == SLICE_TYPE_B)) { - av_assert0(0 && "prediction weights not supported"); - } + priv->sei.payload_count = i; + av_assert0(priv->sei.payload_count > 0); - av_assert0(mslice->nal_ref_idc > 0 == - vpic->pic_fields.bits.reference_pic_flag); - if (mslice->nal_ref_idc != 0) { - if (vpic->pic_fields.bits.idr_pic_flag) { - u(1, mslice_var(no_output_of_prior_pics_flag)); - u(1, mslice_var(long_term_reference_flag)); - } else { - u(1, mslice_var(adaptive_ref_pic_marking_mode_flag)); - if (mslice->adaptive_ref_pic_marking_mode_flag) { - av_assert0(0 && "MMCOs not supported"); - } - } - } + err = vaapi_encode_h264_add_nal(avctx, au, &priv->sei); + if (err < 0) + goto fail; + priv->sei_needed = 0; - if (vpic->pic_fields.bits.entropy_coding_mode_flag && - vslice->slice_type != SLICE_TYPE_I && - vslice->slice_type != SLICE_TYPE_SI) { - ue(vslice_var(cabac_init_idc)); - } + err = vaapi_encode_h264_write_access_unit(avctx, data, data_len, au); + if (err < 0) + goto fail; - se(vslice_var(slice_qp_delta)); - if (vslice->slice_type == SLICE_TYPE_SP || - vslice->slice_type == SLICE_TYPE_SI) { - if (vslice->slice_type == SLICE_TYPE_SP) - u(1, mslice_var(sp_for_switch_flag)); - se(mslice_var(slice_qs_delta)); - } + ff_cbs_fragment_uninit(priv->cbc, au); - if (vpic->pic_fields.bits.deblocking_filter_control_present_flag) { - ue(vslice_var(disable_deblocking_filter_idc)); - if (vslice->disable_deblocking_filter_idc != 1) { - se(vslice_var(slice_alpha_c0_offset_div2)); - se(vslice_var(slice_beta_offset_div2)); - } - } - - if (mseq->num_slice_groups_minus1 > 0 && - mseq->slice_group_map_type >= 3 && mseq->slice_group_map_type <= 5) { - av_assert0(0 && "slice groups not supported"); - } - - // No alignment - this need not be a byte boundary. -} - -static void vaapi_encode_h264_write_buffering_period(PutBitContext *pbc, - VAAPIEncodeContext *ctx, - VAAPIEncodePicture *pic) -{ - VAAPIEncodeH264Context *priv = ctx->priv_data; - VAAPIEncodeH264MiscSequenceParams *mseq = &priv->misc_sequence_params; - VAEncPictureParameterBufferH264 *vpic = pic->codec_picture_params; - int i; + *type = VAEncPackedHeaderRawData; + return 0; - ue(vpic_var(seq_parameter_set_id)); - - if (mseq->nal_hrd_parameters_present_flag) { - for (i = 0; i <= mseq->cpb_cnt_minus1; i++) { - u(mseq->initial_cpb_removal_delay_length_minus1 + 1, - mseq_var(initial_cpb_removal_delay)); - u(mseq->initial_cpb_removal_delay_length_minus1 + 1, - mseq_var(initial_cpb_removal_delay_offset)); - } - } - if (mseq->vcl_hrd_parameters_present_flag) { - av_assert0(0 && "vcl hrd parameters not supported"); - } -} - -static void vaapi_encode_h264_write_pic_timing(PutBitContext *pbc, - VAAPIEncodeContext *ctx, - VAAPIEncodePicture *pic) -{ - VAEncSequenceParameterBufferH264 *vseq = ctx->codec_sequence_params; - VAAPIEncodeH264Context *priv = ctx->priv_data; - VAAPIEncodeH264MiscSequenceParams *mseq = &priv->misc_sequence_params; - int i, num_clock_ts; - - if (mseq->nal_hrd_parameters_present_flag || - mseq->vcl_hrd_parameters_present_flag) { - u(mseq->cpb_removal_delay_length_minus1 + 1, - 2 * vseq->num_units_in_tick * priv->cpb_delay, - cpb_removal_delay); - u(mseq->dpb_output_delay_length_minus1 + 1, - 2 * vseq->num_units_in_tick * priv->dpb_delay, - dpb_output_delay); - } - if (mseq->pic_struct_present_flag) { - u(4, mseq_var(pic_struct)); - num_clock_ts = (mseq->pic_struct <= 2 ? 1 : - mseq->pic_struct <= 4 ? 2 : - mseq->pic_struct <= 8 ? 3 : 0); - for (i = 0; i < num_clock_ts; i++) { - u(1, 0, clock_timestamp_flag[i]); - // No full timestamp information. - } - } -} - -static void vaapi_encode_h264_write_identifier(PutBitContext *pbc, - VAAPIEncodeContext *ctx, - VAAPIEncodePicture *pic) -{ - const char *lavc = LIBAVCODEC_IDENT; - const char *vaapi = VA_VERSION_S; - const char *driver = vaQueryVendorString(ctx->hwctx->display); - char tmp[256]; - int i; - - // Random (version 4) ISO 11578 UUID. - uint8_t uuid[16] = { - 0x59, 0x94, 0x8b, 0x28, 0x11, 0xec, 0x45, 0xaf, - 0x96, 0x75, 0x19, 0xd4, 0x1f, 0xea, 0xa9, 0x4d, - }; - - for (i = 0; i < 16; i++) - u(8, uuid[i], uuid_iso_iec_11578); - - snprintf(tmp, sizeof(tmp), "%s / VAAPI %s / %s", lavc, vaapi, driver); - for (i = 0; i < sizeof(tmp) && tmp[i]; i++) - u(8, tmp[i], user_data_payload_byte); -} - -static void vaapi_encode_h264_write_sei(PutBitContext *pbc, - VAAPIEncodeContext *ctx, - VAAPIEncodePicture *pic) -{ - VAAPIEncodeH264Context *priv = ctx->priv_data; - PutBitContext payload_bits; - char payload[256]; - int payload_type, payload_size, i; - void (*write_payload)(PutBitContext *pbc, - VAAPIEncodeContext *ctx, - VAAPIEncodePicture *pic) = NULL; - - vaapi_encode_h264_write_nal_header(pbc, H264_NAL_SEI, 0); - - for (payload_type = 0; payload_type < 64; payload_type++) { - switch (payload_type) { - case H264_SEI_TYPE_BUFFERING_PERIOD: - if (!priv->send_timing_sei || - pic->type != PICTURE_TYPE_IDR) - continue; - write_payload = &vaapi_encode_h264_write_buffering_period; - break; - case H264_SEI_TYPE_PIC_TIMING: - if (!priv->send_timing_sei) - continue; - write_payload = &vaapi_encode_h264_write_pic_timing; - break; - case H264_SEI_TYPE_USER_DATA_UNREGISTERED: - if (pic->encode_order != 0) - continue; - write_payload = &vaapi_encode_h264_write_identifier; - break; - default: - continue; - } - - init_put_bits(&payload_bits, payload, sizeof(payload)); - write_payload(&payload_bits, ctx, pic); - if (put_bits_count(&payload_bits) & 7) { - write_u(&payload_bits, 1, 1, bit_equal_to_one); - while (put_bits_count(&payload_bits) & 7) - write_u(&payload_bits, 1, 0, bit_equal_to_zero); - } - payload_size = put_bits_count(&payload_bits) / 8; - flush_put_bits(&payload_bits); +#if !CONFIG_VAAPI_1 + } else if (priv->sei_cbr_workaround_needed) { + // Insert a zero-length header using the old SEI type. This is + // required to avoid triggering broken behaviour on Intel platforms + // in CBR mode where an invalid SEI message is generated by the + // driver and inserted into the stream. + *data_len = 0; + *type = VAEncPackedHeaderH264_SEI; + priv->sei_cbr_workaround_needed = 0; + return 0; +#endif - u(8, payload_type, last_payload_type_byte); - u(8, payload_size, last_payload_size_byte); - for (i = 0; i < payload_size; i++) - u(8, payload[i] & 0xff, sei_payload); + } else { + return AVERROR_EOF; } - vaapi_encode_h264_write_trailing_rbsp(pbc); +fail: + ff_cbs_fragment_uninit(priv->cbc, au); + return err; } -static int vaapi_encode_h264_write_sequence_header(AVCodecContext *avctx, - char *data, size_t *data_len) +static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; - PutBitContext pbc; - char tmp[256]; - int err; - size_t nal_len, bit_len, bit_pos, next_len; - - bit_len = *data_len; - bit_pos = 0; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH264Context *priv = ctx->priv_data; + VAAPIEncodeH264Options *opt = ctx->codec_options; + H264RawSPS *sps = &priv->sps; + H264RawPPS *pps = &priv->pps; + VAEncSequenceParameterBufferH264 *vseq = ctx->codec_sequence_params; + VAEncPictureParameterBufferH264 *vpic = ctx->codec_picture_params; - init_put_bits(&pbc, tmp, sizeof(tmp)); - vaapi_encode_h264_write_sps(&pbc, ctx); - nal_len = put_bits_count(&pbc); - flush_put_bits(&pbc); + memset(&priv->current_access_unit, 0, + sizeof(priv->current_access_unit)); - next_len = bit_len - bit_pos; - err = ff_vaapi_encode_h26x_nal_unit_to_byte_stream(data + bit_pos / 8, - &next_len, - tmp, nal_len); - if (err < 0) - return err; - bit_pos += next_len; + memset(sps, 0, sizeof(*sps)); + memset(pps, 0, sizeof(*pps)); - init_put_bits(&pbc, tmp, sizeof(tmp)); - vaapi_encode_h264_write_pps(&pbc, ctx); - nal_len = put_bits_count(&pbc); - flush_put_bits(&pbc); + sps->nal_unit_header.nal_ref_idc = 3; + sps->nal_unit_header.nal_unit_type = H264_NAL_SPS; - next_len = bit_len - bit_pos; - err = ff_vaapi_encode_h26x_nal_unit_to_byte_stream(data + bit_pos / 8, - &next_len, - tmp, nal_len); - if (err < 0) - return err; - bit_pos += next_len; - - *data_len = bit_pos; - return 0; -} + sps->profile_idc = avctx->profile & 0xff; + sps->constraint_set1_flag = + !!(avctx->profile & FF_PROFILE_H264_CONSTRAINED); + sps->constraint_set3_flag = + !!(avctx->profile & FF_PROFILE_H264_INTRA); -static int vaapi_encode_h264_write_slice_header(AVCodecContext *avctx, - VAAPIEncodePicture *pic, - VAAPIEncodeSlice *slice, - char *data, size_t *data_len) -{ - VAAPIEncodeContext *ctx = avctx->priv_data; - PutBitContext pbc; - char tmp[256]; - size_t header_len; + sps->level_idc = avctx->level; - init_put_bits(&pbc, tmp, sizeof(tmp)); - vaapi_encode_h264_write_slice_header2(&pbc, ctx, pic, slice); - header_len = put_bits_count(&pbc); - flush_put_bits(&pbc); + sps->seq_parameter_set_id = 0; + sps->chroma_format_idc = 1; - return ff_vaapi_encode_h26x_nal_unit_to_byte_stream(data, data_len, - tmp, header_len); -} + sps->log2_max_frame_num_minus4 = 4; + sps->pic_order_cnt_type = 0; + sps->log2_max_pic_order_cnt_lsb_minus4 = + av_clip(av_log2(ctx->b_per_p + 1) - 2, 0, 12); -static int vaapi_encode_h264_write_extra_header(AVCodecContext *avctx, - VAAPIEncodePicture *pic, - int index, int *type, - char *data, size_t *data_len) -{ - VAAPIEncodeContext *ctx = avctx->priv_data; - PutBitContext pbc; - char tmp[256]; - size_t header_len; + sps->max_num_ref_frames = + (avctx->profile & FF_PROFILE_H264_INTRA) ? 0 : + 1 + (ctx->b_per_p > 0); - if (index == 0 && ctx->va_rc_mode == VA_RC_CBR) { - *type = VAEncPackedHeaderH264_SEI; + sps->pic_width_in_mbs_minus1 = priv->mb_width - 1; + sps->pic_height_in_map_units_minus1 = priv->mb_height - 1; - init_put_bits(&pbc, tmp, sizeof(tmp)); - vaapi_encode_h264_write_sei(&pbc, ctx, pic); - header_len = put_bits_count(&pbc); - flush_put_bits(&pbc); + sps->frame_mbs_only_flag = 1; + sps->direct_8x8_inference_flag = 1; - return ff_vaapi_encode_h26x_nal_unit_to_byte_stream(data, data_len, - tmp, header_len); + if (avctx->width != 16 * priv->mb_width || + avctx->height != 16 * priv->mb_height) { + sps->frame_cropping_flag = 1; + sps->frame_crop_left_offset = 0; + sps->frame_crop_right_offset = + (16 * priv->mb_width - avctx->width) / 2; + sps->frame_crop_top_offset = 0; + sps->frame_crop_bottom_offset = + (16 * priv->mb_height - avctx->height) / 2; } else { - return AVERROR_EOF; + sps->frame_cropping_flag = 0; } -} - -static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx) -{ - VAAPIEncodeContext *ctx = avctx->priv_data; - VAEncSequenceParameterBufferH264 *vseq = ctx->codec_sequence_params; - VAEncPictureParameterBufferH264 *vpic = ctx->codec_picture_params; - VAAPIEncodeH264Context *priv = ctx->priv_data; - VAAPIEncodeH264MiscSequenceParams *mseq = &priv->misc_sequence_params; - VAAPIEncodeH264Options *opt = - (VAAPIEncodeH264Options*)ctx->codec_options_data; - int i; - - { - vseq->seq_parameter_set_id = 0; - - vseq->level_idc = avctx->level; - - vseq->max_num_ref_frames = 1 + (avctx->max_b_frames > 0); - - vseq->picture_width_in_mbs = priv->mb_width; - vseq->picture_height_in_mbs = priv->mb_height; - - vseq->seq_fields.bits.chroma_format_idc = 1; - vseq->seq_fields.bits.frame_mbs_only_flag = 1; - vseq->seq_fields.bits.direct_8x8_inference_flag = 1; - vseq->seq_fields.bits.log2_max_frame_num_minus4 = 4; - vseq->seq_fields.bits.pic_order_cnt_type = 0; - vseq->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 = - av_clip(av_log2(avctx->max_b_frames + 1) - 2, 0, 12); - if (avctx->width != ctx->surface_width || - avctx->height != ctx->surface_height) { - vseq->frame_cropping_flag = 1; - - vseq->frame_crop_left_offset = 0; - vseq->frame_crop_right_offset = - (ctx->surface_width - avctx->width) / 2; - vseq->frame_crop_top_offset = 0; - vseq->frame_crop_bottom_offset = - (ctx->surface_height - avctx->height) / 2; - } else { - vseq->frame_cropping_flag = 0; - } - - vseq->vui_parameters_present_flag = 1; - if (avctx->sample_aspect_ratio.num != 0) { - vseq->vui_fields.bits.aspect_ratio_info_present_flag = 1; - // There is a large enum of these which we could support - // individually rather than using the generic X/Y form? - if (avctx->sample_aspect_ratio.num == - avctx->sample_aspect_ratio.den) { - vseq->aspect_ratio_idc = 1; - } else { - vseq->aspect_ratio_idc = 255; // Extended SAR. - vseq->sar_width = avctx->sample_aspect_ratio.num; - vseq->sar_height = avctx->sample_aspect_ratio.den; + sps->vui_parameters_present_flag = 1; + + if (avctx->sample_aspect_ratio.num != 0 && + avctx->sample_aspect_ratio.den != 0) { + static const AVRational sar_idc[] = { + { 0, 0 }, + { 1, 1 }, { 12, 11 }, { 10, 11 }, { 16, 11 }, + { 40, 33 }, { 24, 11 }, { 20, 11 }, { 32, 11 }, + { 80, 33 }, { 18, 11 }, { 15, 11 }, { 64, 33 }, + { 160, 99 }, { 4, 3 }, { 3, 2 }, { 2, 1 }, + }; + int i; + for (i = 0; i < FF_ARRAY_ELEMS(sar_idc); i++) { + if (avctx->sample_aspect_ratio.num == sar_idc[i].num && + avctx->sample_aspect_ratio.den == sar_idc[i].den) { + sps->vui.aspect_ratio_idc = i; + break; } } + if (i >= FF_ARRAY_ELEMS(sar_idc)) { + sps->vui.aspect_ratio_idc = 255; + sps->vui.sar_width = avctx->sample_aspect_ratio.num; + sps->vui.sar_height = avctx->sample_aspect_ratio.den; + } + sps->vui.aspect_ratio_info_present_flag = 1; + } + + if (avctx->color_range != AVCOL_RANGE_UNSPECIFIED || + avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || + avctx->color_trc != AVCOL_TRC_UNSPECIFIED || + avctx->colorspace != AVCOL_SPC_UNSPECIFIED) { + sps->vui.video_signal_type_present_flag = 1; + sps->vui.video_format = 5; // Unspecified. + sps->vui.video_full_range_flag = + avctx->color_range == AVCOL_RANGE_JPEG; + if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || avctx->color_trc != AVCOL_TRC_UNSPECIFIED || avctx->colorspace != AVCOL_SPC_UNSPECIFIED) { - mseq->video_signal_type_present_flag = 1; - mseq->video_format = 5; // Unspecified. - mseq->video_full_range_flag = 0; - mseq->colour_description_present_flag = 1; - // These enums are derived from the standard and hence - // we can just use the values directly. - mseq->colour_primaries = avctx->color_primaries; - mseq->transfer_characteristics = avctx->color_trc; - mseq->matrix_coefficients = avctx->colorspace; + sps->vui.colour_description_present_flag = 1; + sps->vui.colour_primaries = avctx->color_primaries; + sps->vui.transfer_characteristics = avctx->color_trc; + sps->vui.matrix_coefficients = avctx->colorspace; } + } else { + sps->vui.video_format = 5; + sps->vui.video_full_range_flag = 0; + sps->vui.colour_primaries = avctx->color_primaries; + sps->vui.transfer_characteristics = avctx->color_trc; + sps->vui.matrix_coefficients = avctx->colorspace; + } - vseq->vui_fields.bits.bitstream_restriction_flag = 1; - mseq->motion_vectors_over_pic_boundaries_flag = 1; - mseq->max_bytes_per_pic_denom = 0; - mseq->max_bits_per_mb_denom = 0; - vseq->vui_fields.bits.log2_max_mv_length_horizontal = 16; - vseq->vui_fields.bits.log2_max_mv_length_vertical = 16; - - mseq->max_num_reorder_frames = (avctx->max_b_frames > 0); - mseq->max_dec_pic_buffering = vseq->max_num_ref_frames; - - vseq->bits_per_second = avctx->bit_rate; + if (avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED) { + sps->vui.chroma_loc_info_present_flag = 1; + sps->vui.chroma_sample_loc_type_top_field = + sps->vui.chroma_sample_loc_type_bottom_field = + avctx->chroma_sample_location - 1; + } - vseq->vui_fields.bits.timing_info_present_flag = 1; - if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { - vseq->num_units_in_tick = avctx->framerate.den; - vseq->time_scale = 2 * avctx->framerate.num; - mseq->fixed_frame_rate_flag = 1; - } else { - vseq->num_units_in_tick = avctx->time_base.num; - vseq->time_scale = 2 * avctx->time_base.den; - mseq->fixed_frame_rate_flag = 0; - } + sps->vui.timing_info_present_flag = 1; + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { + sps->vui.num_units_in_tick = avctx->framerate.den; + sps->vui.time_scale = 2 * avctx->framerate.num; + sps->vui.fixed_frame_rate_flag = 1; + } else { + sps->vui.num_units_in_tick = avctx->time_base.num; + sps->vui.time_scale = 2 * avctx->time_base.den; + sps->vui.fixed_frame_rate_flag = 0; + } - if (ctx->va_rc_mode == VA_RC_CBR) { - priv->send_timing_sei = 1; - mseq->nal_hrd_parameters_present_flag = 1; + if (opt->sei & SEI_TIMING) { + H264RawHRD *hrd = &sps->vui.nal_hrd_parameters; - mseq->cpb_cnt_minus1 = 0; + sps->vui.nal_hrd_parameters_present_flag = 1; - // Try to scale these to a sensible range so that the - // golomb encode of the value is not overlong. - mseq->bit_rate_scale = - av_clip_uintp2(av_log2(avctx->bit_rate) - 15 - 6, 4); - mseq->bit_rate_value_minus1[0] = - (avctx->bit_rate >> mseq->bit_rate_scale + 6) - 1; + hrd->cpb_cnt_minus1 = 0; - mseq->cpb_size_scale = - av_clip_uintp2(av_log2(ctx->hrd_params.hrd.buffer_size) - 15 - 4, 4); - mseq->cpb_size_value_minus1[0] = - (ctx->hrd_params.hrd.buffer_size >> mseq->cpb_size_scale + 4) - 1; + // Try to scale these to a sensible range so that the + // golomb encode of the value is not overlong. + hrd->bit_rate_scale = + av_clip_uintp2(av_log2(avctx->bit_rate) - 15 - 6, 4); + hrd->bit_rate_value_minus1[0] = + (avctx->bit_rate >> hrd->bit_rate_scale + 6) - 1; - // CBR mode isn't actually available here, despite naming. - mseq->cbr_flag[0] = 0; + hrd->cpb_size_scale = + av_clip_uintp2(av_log2(ctx->hrd_params.hrd.buffer_size) - 15 - 4, 4); + hrd->cpb_size_value_minus1[0] = + (ctx->hrd_params.hrd.buffer_size >> hrd->cpb_size_scale + 4) - 1; - mseq->initial_cpb_removal_delay_length_minus1 = 23; - mseq->cpb_removal_delay_length_minus1 = 23; - mseq->dpb_output_delay_length_minus1 = 7; - mseq->time_offset_length = 0; + // CBR mode as defined for the HRD cannot be achieved without filler + // data, so this flag cannot be set even with VAAPI CBR modes. + hrd->cbr_flag[0] = 0; - // This calculation can easily overflow 32 bits. - mseq->initial_cpb_removal_delay = 90000 * - (uint64_t)ctx->hrd_params.hrd.initial_buffer_fullness / - ctx->hrd_params.hrd.buffer_size; + hrd->initial_cpb_removal_delay_length_minus1 = 23; + hrd->cpb_removal_delay_length_minus1 = 23; + hrd->dpb_output_delay_length_minus1 = 7; + hrd->time_offset_length = 0; - mseq->initial_cpb_removal_delay_offset = 0; - } else { - priv->send_timing_sei = 0; - mseq->nal_hrd_parameters_present_flag = 0; - } + priv->buffering_period.seq_parameter_set_id = sps->seq_parameter_set_id; - vseq->intra_period = avctx->gop_size; - vseq->intra_idr_period = avctx->gop_size; - vseq->ip_period = ctx->b_per_p + 1; + // This calculation can easily overflow 32 bits. + priv->buffering_period.nal.initial_cpb_removal_delay[0] = 90000 * + (uint64_t)ctx->hrd_params.hrd.initial_buffer_fullness / + ctx->hrd_params.hrd.buffer_size; + priv->buffering_period.nal.initial_cpb_removal_delay_offset[0] = 0; + } else { + sps->vui.nal_hrd_parameters_present_flag = 0; + sps->vui.low_delay_hrd_flag = 1 - sps->vui.fixed_frame_rate_flag; } - { - vpic->CurrPic.picture_id = VA_INVALID_ID; - vpic->CurrPic.flags = VA_PICTURE_H264_INVALID; + sps->vui.bitstream_restriction_flag = 1; + sps->vui.motion_vectors_over_pic_boundaries_flag = 1; + sps->vui.log2_max_mv_length_horizontal = 16; + sps->vui.log2_max_mv_length_vertical = 16; + sps->vui.max_num_reorder_frames = (ctx->b_per_p > 0); + sps->vui.max_dec_frame_buffering = sps->max_num_ref_frames; - for (i = 0; i < FF_ARRAY_ELEMS(vpic->ReferenceFrames); i++) { - vpic->ReferenceFrames[i].picture_id = VA_INVALID_ID; - vpic->ReferenceFrames[i].flags = VA_PICTURE_H264_INVALID; - } + pps->nal_unit_header.nal_ref_idc = 3; + pps->nal_unit_header.nal_unit_type = H264_NAL_PPS; - vpic->coded_buf = VA_INVALID_ID; + pps->pic_parameter_set_id = 0; + pps->seq_parameter_set_id = 0; - vpic->pic_parameter_set_id = 0; - vpic->seq_parameter_set_id = 0; + pps->entropy_coding_mode_flag = + !(sps->profile_idc == FF_PROFILE_H264_BASELINE || + sps->profile_idc == FF_PROFILE_H264_EXTENDED || + sps->profile_idc == FF_PROFILE_H264_CAVLC_444); + if (!opt->coder && pps->entropy_coding_mode_flag) + pps->entropy_coding_mode_flag = 0; - vpic->num_ref_idx_l0_active_minus1 = 0; - vpic->num_ref_idx_l1_active_minus1 = 0; + pps->num_ref_idx_l0_default_active_minus1 = 0; + pps->num_ref_idx_l1_default_active_minus1 = 0; - vpic->pic_fields.bits.entropy_coding_mode_flag = - opt->coder ? ((avctx->profile & 0xff) != 66) : 0; - vpic->pic_fields.bits.weighted_pred_flag = 0; - vpic->pic_fields.bits.weighted_bipred_idc = 0; - vpic->pic_fields.bits.transform_8x8_mode_flag = - ((avctx->profile & 0xff) >= 100); + pps->pic_init_qp_minus26 = priv->fixed_qp_idr - 26; + + if (sps->profile_idc == FF_PROFILE_H264_BASELINE || + sps->profile_idc == FF_PROFILE_H264_EXTENDED || + sps->profile_idc == FF_PROFILE_H264_MAIN) { + pps->more_rbsp_data = 0; + } else { + pps->more_rbsp_data = 1; - vpic->pic_init_qp = priv->fixed_qp_idr; + pps->transform_8x8_mode_flag = 1; } - { - mseq->profile_idc = avctx->profile & 0xff; + *vseq = (VAEncSequenceParameterBufferH264) { + .seq_parameter_set_id = sps->seq_parameter_set_id, + .level_idc = sps->level_idc, + .intra_period = avctx->gop_size, + .intra_idr_period = avctx->gop_size, + .ip_period = ctx->b_per_p + 1, + + .bits_per_second = avctx->bit_rate, + .max_num_ref_frames = sps->max_num_ref_frames, + .picture_width_in_mbs = sps->pic_width_in_mbs_minus1 + 1, + .picture_height_in_mbs = sps->pic_height_in_map_units_minus1 + 1, + + .seq_fields.bits = { + .chroma_format_idc = sps->chroma_format_idc, + .frame_mbs_only_flag = sps->frame_mbs_only_flag, + .mb_adaptive_frame_field_flag = sps->mb_adaptive_frame_field_flag, + .seq_scaling_matrix_present_flag = sps->seq_scaling_matrix_present_flag, + .direct_8x8_inference_flag = sps->direct_8x8_inference_flag, + .log2_max_frame_num_minus4 = sps->log2_max_frame_num_minus4, + .pic_order_cnt_type = sps->pic_order_cnt_type, + .log2_max_pic_order_cnt_lsb_minus4 = sps->log2_max_pic_order_cnt_lsb_minus4, + .delta_pic_order_always_zero_flag = sps->delta_pic_order_always_zero_flag, + }, + + .bit_depth_luma_minus8 = sps->bit_depth_luma_minus8, + .bit_depth_chroma_minus8 = sps->bit_depth_chroma_minus8, + + .frame_cropping_flag = sps->frame_cropping_flag, + .frame_crop_left_offset = sps->frame_crop_left_offset, + .frame_crop_right_offset = sps->frame_crop_right_offset, + .frame_crop_top_offset = sps->frame_crop_top_offset, + .frame_crop_bottom_offset = sps->frame_crop_bottom_offset, + + .vui_parameters_present_flag = sps->vui_parameters_present_flag, + + .vui_fields.bits = { + .aspect_ratio_info_present_flag = sps->vui.aspect_ratio_info_present_flag, + .timing_info_present_flag = sps->vui.timing_info_present_flag, + .bitstream_restriction_flag = sps->vui.bitstream_restriction_flag, + .log2_max_mv_length_horizontal = sps->vui.log2_max_mv_length_horizontal, + .log2_max_mv_length_vertical = sps->vui.log2_max_mv_length_vertical, + }, + + .aspect_ratio_idc = sps->vui.aspect_ratio_idc, + .sar_width = sps->vui.sar_width, + .sar_height = sps->vui.sar_height, + .num_units_in_tick = sps->vui.num_units_in_tick, + .time_scale = sps->vui.time_scale, + }; - if (avctx->profile & FF_PROFILE_H264_CONSTRAINED) - mseq->constraint_set1_flag = 1; - if (avctx->profile & FF_PROFILE_H264_INTRA) - mseq->constraint_set3_flag = 1; - } + *vpic = (VAEncPictureParameterBufferH264) { + .CurrPic = { + .picture_id = VA_INVALID_ID, + .flags = VA_PICTURE_H264_INVALID, + }, + + .coded_buf = VA_INVALID_ID, + + .pic_parameter_set_id = pps->pic_parameter_set_id, + .seq_parameter_set_id = pps->seq_parameter_set_id, + + .pic_init_qp = pps->pic_init_qp_minus26 + 26, + .num_ref_idx_l0_active_minus1 = pps->num_ref_idx_l0_default_active_minus1, + .num_ref_idx_l1_active_minus1 = pps->num_ref_idx_l1_default_active_minus1, + + .chroma_qp_index_offset = pps->chroma_qp_index_offset, + .second_chroma_qp_index_offset = pps->second_chroma_qp_index_offset, + + .pic_fields.bits = { + .entropy_coding_mode_flag = pps->entropy_coding_mode_flag, + .weighted_pred_flag = pps->weighted_pred_flag, + .weighted_bipred_idc = pps->weighted_bipred_idc, + .constrained_intra_pred_flag = pps->constrained_intra_pred_flag, + .transform_8x8_mode_flag = pps->transform_8x8_mode_flag, + .deblocking_filter_control_present_flag = + pps->deblocking_filter_control_present_flag, + .redundant_pic_cnt_present_flag = pps->redundant_pic_cnt_present_flag, + .pic_order_present_flag = + pps->bottom_field_pic_order_in_frame_present_flag, + .pic_scaling_matrix_present_flag = pps->pic_scaling_matrix_present_flag, + }, + }; return 0; } @@ -948,54 +576,117 @@ static int vaapi_encode_h264_init_sequence_params(AVCodecContext *avctx) static int vaapi_encode_h264_init_picture_params(AVCodecContext *avctx, VAAPIEncodePicture *pic) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAEncSequenceParameterBufferH264 *vseq = ctx->codec_sequence_params; - VAEncPictureParameterBufferH264 *vpic = pic->codec_picture_params; - VAAPIEncodeH264Context *priv = ctx->priv_data; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH264Context *priv = ctx->priv_data; + VAAPIEncodeH264Options *opt = ctx->codec_options; + H264RawSPS *sps = &priv->sps; + VAEncPictureParameterBufferH264 *vpic = pic->codec_picture_params; int i; + memset(&priv->current_access_unit, 0, + sizeof(priv->current_access_unit)); + if (pic->type == PICTURE_TYPE_IDR) { av_assert0(pic->display_order == pic->encode_order); - vpic->frame_num = 0; + priv->frame_num = 0; priv->next_frame_num = 1; - priv->cpb_delay = 0; + priv->cpb_delay = 0; priv->last_idr_frame = pic->display_order; + ++priv->idr_pic_count; + + priv->slice_type = 7; + priv->primary_pic_type = 0; } else { - vpic->frame_num = priv->next_frame_num; + priv->frame_num = priv->next_frame_num; + if (pic->type != PICTURE_TYPE_B) { - // nal_ref_idc != 0 - ++priv->next_frame_num; + // Reference picture, so frame_num advances. + priv->next_frame_num = (priv->frame_num + 1) & + ((1 << (4 + sps->log2_max_frame_num_minus4)) - 1); } ++priv->cpb_delay; + + if (pic->type == PICTURE_TYPE_I) { + priv->slice_type = 7; + priv->primary_pic_type = 0; + } else if (pic->type == PICTURE_TYPE_P) { + priv->slice_type = 5; + priv->primary_pic_type = 1; + } else { + priv->slice_type = 6; + priv->primary_pic_type = 2; + } + } + priv->pic_order_cnt = pic->display_order - priv->last_idr_frame; + priv->dpb_delay = pic->display_order - pic->encode_order + 1; + + if (opt->aud) { + priv->aud_needed = 1; + priv->aud.nal_unit_header.nal_unit_type = H264_NAL_AUD; + priv->aud.primary_pic_type = priv->primary_pic_type; + } else { + priv->aud_needed = 0; } - priv->dpb_delay = pic->display_order - pic->encode_order + 1; - vpic->frame_num = vpic->frame_num & - ((1 << (4 + vseq->seq_fields.bits.log2_max_frame_num_minus4)) - 1); + if (opt->sei & SEI_IDENTIFIER && pic->encode_order == 0) + priv->sei_needed = 1; +#if !CONFIG_VAAPI_1 + if (ctx->va_rc_mode == VA_RC_CBR) + priv->sei_cbr_workaround_needed = 1; +#endif + + if (opt->sei & SEI_TIMING) { + memset(&priv->pic_timing, 0, sizeof(priv->pic_timing)); + + priv->pic_timing.cpb_removal_delay = 2 * priv->cpb_delay; + priv->pic_timing.dpb_output_delay = 2 * priv->dpb_delay; + + priv->sei_needed = 1; + } + + if (opt->sei & SEI_RECOVERY_POINT && pic->type == PICTURE_TYPE_I) { + priv->recovery_point.recovery_frame_cnt = 0; + priv->recovery_point.exact_match_flag = 1; + priv->recovery_point.broken_link_flag = ctx->b_per_p > 0; + + priv->sei_needed = 1; + } - vpic->CurrPic.picture_id = pic->recon_surface; - vpic->CurrPic.frame_idx = vpic->frame_num; - vpic->CurrPic.flags = 0; - vpic->CurrPic.TopFieldOrderCnt = pic->display_order - priv->last_idr_frame; - vpic->CurrPic.BottomFieldOrderCnt = pic->display_order - priv->last_idr_frame; + vpic->CurrPic = (VAPictureH264) { + .picture_id = pic->recon_surface, + .frame_idx = priv->frame_num, + .flags = 0, + .TopFieldOrderCnt = priv->pic_order_cnt, + .BottomFieldOrderCnt = priv->pic_order_cnt, + }; for (i = 0; i < pic->nb_refs; i++) { VAAPIEncodePicture *ref = pic->refs[i]; + unsigned int frame_num = (ref->encode_order - priv->last_idr_frame) & + ((1 << (4 + sps->log2_max_frame_num_minus4)) - 1); + unsigned int pic_order_cnt = ref->display_order - priv->last_idr_frame; + av_assert0(ref && ref->encode_order < pic->encode_order); - vpic->ReferenceFrames[i].picture_id = ref->recon_surface; - vpic->ReferenceFrames[i].frame_idx = ref->encode_order; - vpic->ReferenceFrames[i].flags = VA_PICTURE_H264_SHORT_TERM_REFERENCE; - vpic->ReferenceFrames[i].TopFieldOrderCnt = ref->display_order - priv->last_idr_frame; - vpic->ReferenceFrames[i].BottomFieldOrderCnt = ref->display_order - priv->last_idr_frame; + vpic->ReferenceFrames[i] = (VAPictureH264) { + .picture_id = ref->recon_surface, + .frame_idx = frame_num, + .flags = VA_PICTURE_H264_SHORT_TERM_REFERENCE, + .TopFieldOrderCnt = pic_order_cnt, + .BottomFieldOrderCnt = pic_order_cnt, + }; } for (; i < FF_ARRAY_ELEMS(vpic->ReferenceFrames); i++) { - vpic->ReferenceFrames[i].picture_id = VA_INVALID_ID; - vpic->ReferenceFrames[i].flags = VA_PICTURE_H264_INVALID; + vpic->ReferenceFrames[i] = (VAPictureH264) { + .picture_id = VA_INVALID_ID, + .flags = VA_PICTURE_H264_INVALID, + }; } vpic->coded_buf = pic->output_buffer; - vpic->pic_fields.bits.idr_pic_flag = (pic->type == PICTURE_TYPE_IDR); + vpic->frame_num = priv->frame_num; + + vpic->pic_fields.bits.idr_pic_flag = (pic->type == PICTURE_TYPE_IDR); vpic->pic_fields.bits.reference_pic_flag = (pic->type != PICTURE_TYPE_B); pic->nb_slices = 1; @@ -1007,58 +698,57 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx, VAAPIEncodePicture *pic, VAAPIEncodeSlice *slice) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAEncSequenceParameterBufferH264 *vseq = ctx->codec_sequence_params; - VAEncPictureParameterBufferH264 *vpic = pic->codec_picture_params; - VAEncSliceParameterBufferH264 *vslice = slice->codec_slice_params; - VAAPIEncodeH264Context *priv = ctx->priv_data; - VAAPIEncodeH264Slice *pslice; - VAAPIEncodeH264MiscSliceParams *mslice; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH264Context *priv = ctx->priv_data; + H264RawSPS *sps = &priv->sps; + H264RawPPS *pps = &priv->pps; + H264RawSliceHeader *sh = &priv->slice.header; + VAEncPictureParameterBufferH264 *vpic = pic->codec_picture_params; + VAEncSliceParameterBufferH264 *vslice = slice->codec_slice_params; int i; - slice->priv_data = av_mallocz(sizeof(*pslice)); - if (!slice->priv_data) - return AVERROR(ENOMEM); - pslice = slice->priv_data; - mslice = &pslice->misc_slice_params; + if (pic->type == PICTURE_TYPE_IDR) { + sh->nal_unit_header.nal_unit_type = H264_NAL_IDR_SLICE; + sh->nal_unit_header.nal_ref_idc = 3; + } else { + sh->nal_unit_header.nal_unit_type = H264_NAL_SLICE; + sh->nal_unit_header.nal_ref_idc = pic->type != PICTURE_TYPE_B; + } + + // Only one slice per frame. + sh->first_mb_in_slice = 0; + sh->slice_type = priv->slice_type; + + sh->pic_parameter_set_id = pps->pic_parameter_set_id; + + sh->frame_num = priv->frame_num; + sh->idr_pic_id = priv->idr_pic_count; + + sh->pic_order_cnt_lsb = priv->pic_order_cnt & + ((1 << (4 + sps->log2_max_pic_order_cnt_lsb_minus4)) - 1); - if (pic->type == PICTURE_TYPE_IDR) - mslice->nal_unit_type = H264_NAL_IDR_SLICE; + sh->direct_spatial_mv_pred_flag = 1; + + if (pic->type == PICTURE_TYPE_B) + sh->slice_qp_delta = priv->fixed_qp_b - (pps->pic_init_qp_minus26 + 26); + else if (pic->type == PICTURE_TYPE_P) + sh->slice_qp_delta = priv->fixed_qp_p - (pps->pic_init_qp_minus26 + 26); else - mslice->nal_unit_type = H264_NAL_SLICE; + sh->slice_qp_delta = priv->fixed_qp_idr - (pps->pic_init_qp_minus26 + 26); - switch (pic->type) { - case PICTURE_TYPE_IDR: - vslice->slice_type = SLICE_TYPE_I; - mslice->nal_ref_idc = 3; - break; - case PICTURE_TYPE_I: - vslice->slice_type = SLICE_TYPE_I; - mslice->nal_ref_idc = 2; - break; - case PICTURE_TYPE_P: - vslice->slice_type = SLICE_TYPE_P; - mslice->nal_ref_idc = 1; - break; - case PICTURE_TYPE_B: - vslice->slice_type = SLICE_TYPE_B; - mslice->nal_ref_idc = 0; - break; - default: - av_assert0(0 && "invalid picture type"); - } - // Only one slice per frame. - vslice->macroblock_address = 0; - vslice->num_macroblocks = priv->mb_width * priv->mb_height; + vslice->macroblock_address = sh->first_mb_in_slice; + vslice->num_macroblocks = priv->mb_width * priv->mb_height; vslice->macroblock_info = VA_INVALID_ID; - vslice->pic_parameter_set_id = vpic->pic_parameter_set_id; - vslice->idr_pic_id = priv->idr_pic_count++; + vslice->slice_type = sh->slice_type % 5; + vslice->pic_parameter_set_id = sh->pic_parameter_set_id; + vslice->idr_pic_id = sh->idr_pic_id; + + vslice->pic_order_cnt_lsb = sh->pic_order_cnt_lsb; - vslice->pic_order_cnt_lsb = (pic->display_order - priv->last_idr_frame) & - ((1 << (4 + vseq->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4)) - 1); + vslice->direct_spatial_mv_pred_flag = sh->direct_spatial_mv_pred_flag; for (i = 0; i < FF_ARRAY_ELEMS(vslice->RefPicList0); i++) { vslice->RefPicList0[i].picture_id = VA_INVALID_ID; @@ -1072,26 +762,15 @@ static int vaapi_encode_h264_init_slice_params(AVCodecContext *avctx, // Backward reference for P- or B-frame. av_assert0(pic->type == PICTURE_TYPE_P || pic->type == PICTURE_TYPE_B); - - vslice->num_ref_idx_l0_active_minus1 = 0; vslice->RefPicList0[0] = vpic->ReferenceFrames[0]; } if (pic->nb_refs >= 2) { // Forward reference for B-frame. av_assert0(pic->type == PICTURE_TYPE_B); - - vslice->num_ref_idx_l1_active_minus1 = 0; vslice->RefPicList1[0] = vpic->ReferenceFrames[1]; } - if (pic->type == PICTURE_TYPE_B) - vslice->slice_qp_delta = priv->fixed_qp_b - vpic->pic_init_qp; - else if (pic->type == PICTURE_TYPE_P) - vslice->slice_qp_delta = priv->fixed_qp_p - vpic->pic_init_qp; - else - vslice->slice_qp_delta = priv->fixed_qp_idr - vpic->pic_init_qp; - - vslice->direct_spatial_mv_pred_flag = 1; + vslice->slice_qp_delta = sh->slice_qp_delta; return 0; } @@ -1101,6 +780,11 @@ static av_cold int vaapi_encode_h264_configure(AVCodecContext *avctx) VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeH264Context *priv = ctx->priv_data; VAAPIEncodeH264Options *opt = ctx->codec_options; + int err; + + err = ff_cbs_init(&priv->cbc, AV_CODEC_ID_H264, avctx); + if (err < 0) + return err; priv->mb_width = FFALIGN(avctx->width, 16) / 16; priv->mb_height = FFALIGN(avctx->height, 16) / 16; @@ -1118,6 +802,8 @@ static av_cold int vaapi_encode_h264_configure(AVCodecContext *avctx) else priv->fixed_qp_b = priv->fixed_qp_p; + opt->sei &= ~SEI_TIMING; + av_log(avctx, AV_LOG_DEBUG, "Using fixed QP = " "%d / %d / %d for IDR- / P- / B-frames.\n", priv->fixed_qp_idr, priv->fixed_qp_p, priv->fixed_qp_b); @@ -1140,6 +826,34 @@ static av_cold int vaapi_encode_h264_configure(AVCodecContext *avctx) if (avctx->compression_level == FF_COMPRESSION_DEFAULT) avctx->compression_level = opt->quality; + if (opt->sei & SEI_IDENTIFIER) { + const char *lavc = LIBAVCODEC_IDENT; + const char *vaapi = VA_VERSION_S; + const char *driver; + int len; + + memcpy(priv->identifier.uuid_iso_iec_11578, + vaapi_encode_h264_sei_identifier_uuid, + sizeof(priv->identifier.uuid_iso_iec_11578)); + + driver = vaQueryVendorString(ctx->hwctx->display); + if (!driver) + driver = "unknown driver"; + + len = snprintf(NULL, 0, "%s / VAAPI %s / %s", lavc, vaapi, driver); + if (len >= 0) { + priv->identifier_string = av_malloc(len + 1); + if (!priv->identifier_string) + return AVERROR(ENOMEM); + + snprintf(priv->identifier_string, len + 1, + "%s / VAAPI %s / %s", lavc, vaapi, driver); + + priv->identifier.data = priv->identifier_string; + priv->identifier.data_length = len + 1; + } + } + return 0; } @@ -1174,6 +888,11 @@ static av_cold int vaapi_encode_h264_init(AVCodecContext *avctx) ctx->codec = &vaapi_encode_type_h264; + if (avctx->profile == FF_PROFILE_UNKNOWN) + avctx->profile = opt->profile; + if (avctx->level == FF_LEVEL_UNKNOWN) + avctx->level = opt->level; + switch (avctx->profile) { case FF_PROFILE_H264_BASELINE: av_log(avctx, AV_LOG_WARNING, "H.264 baseline profile is not " @@ -1251,6 +970,19 @@ static av_cold int vaapi_encode_h264_init(AVCodecContext *avctx) return ff_vaapi_encode_init(avctx); } +static av_cold int vaapi_encode_h264_close(AVCodecContext *avctx) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH264Context *priv = ctx->priv_data; + + if (priv) { + ff_cbs_close(&priv->cbc); + av_freep(&priv->identifier_string); + } + + return ff_vaapi_encode_close(avctx); +} + #define OFFSET(x) (offsetof(VAAPIEncodeContext, codec_options_data) + \ offsetof(VAAPIEncodeH264Options, x)) #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) @@ -1268,12 +1000,66 @@ static const AVOption vaapi_encode_h264_options[] = { { "cabac", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, FLAGS, "coder" }, { "vlc", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 0 }, INT_MIN, INT_MAX, FLAGS, "coder" }, { "ac", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, INT_MIN, INT_MAX, FLAGS, "coder" }, + + { "aud", "Include AUD", + OFFSET(aud), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS }, + + { "sei", "Set SEI to include", + OFFSET(sei), AV_OPT_TYPE_FLAGS, + { .i64 = SEI_IDENTIFIER | SEI_TIMING | SEI_RECOVERY_POINT }, + 0, INT_MAX, FLAGS, "sei" }, + { "identifier", "Include encoder version identifier", + 0, AV_OPT_TYPE_CONST, { .i64 = SEI_IDENTIFIER }, + INT_MIN, INT_MAX, FLAGS, "sei" }, + { "timing", "Include timing parameters (buffering_period and pic_timing)", + 0, AV_OPT_TYPE_CONST, { .i64 = SEI_TIMING }, + INT_MIN, INT_MAX, FLAGS, "sei" }, + { "recovery_point", "Include recovery points where appropriate", + 0, AV_OPT_TYPE_CONST, { .i64 = SEI_RECOVERY_POINT }, + INT_MIN, INT_MAX, FLAGS, "sei" }, + + { "profile", "Set profile (profile_idc and constraint_set*_flag)", + OFFSET(profile), AV_OPT_TYPE_INT, + { .i64 = FF_PROFILE_H264_HIGH }, 0x0000, 0xffff, FLAGS, "profile" }, + +#define PROFILE(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = value }, 0, 0, FLAGS, "profile" + { PROFILE("constrained_baseline", FF_PROFILE_H264_CONSTRAINED_BASELINE) }, + { PROFILE("main", FF_PROFILE_H264_MAIN) }, + { PROFILE("high", FF_PROFILE_H264_HIGH) }, +#undef PROFILE + + { "level", "Set level (level_idc)", + OFFSET(level), AV_OPT_TYPE_INT, + { .i64 = 51 }, 0x00, 0xff, FLAGS, "level" }, + +#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = value }, 0, 0, FLAGS, "level" + { LEVEL("1", 10) }, + { LEVEL("1.1", 11) }, + { LEVEL("1.2", 12) }, + { LEVEL("1.3", 13) }, + { LEVEL("2", 20) }, + { LEVEL("2.1", 21) }, + { LEVEL("2.2", 22) }, + { LEVEL("3", 30) }, + { LEVEL("3.1", 31) }, + { LEVEL("3.2", 32) }, + { LEVEL("4", 40) }, + { LEVEL("4.1", 41) }, + { LEVEL("4.2", 42) }, + { LEVEL("5", 50) }, + { LEVEL("5.1", 51) }, + { LEVEL("5.2", 52) }, + { LEVEL("6", 60) }, + { LEVEL("6.1", 61) }, + { LEVEL("6.2", 62) }, +#undef LEVEL + { NULL }, }; static const AVCodecDefault vaapi_encode_h264_defaults[] = { - { "profile", "100" }, - { "level", "51" }, { "b", "0" }, { "bf", "2" }, { "g", "120" }, @@ -1301,12 +1087,13 @@ AVCodec ff_h264_vaapi_encoder = { sizeof(VAAPIEncodeH264Options)), .init = &vaapi_encode_h264_init, .encode2 = &ff_vaapi_encode2, - .close = &ff_vaapi_encode_close, + .close = &vaapi_encode_h264_close, .priv_class = &vaapi_encode_h264_class, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .defaults = vaapi_encode_h264_defaults, .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE, }, + .wrapper_name = "vaapi", }; diff --git a/libavcodec/vaapi_encode_h265.c b/libavcodec/vaapi_encode_h265.c index 971458db8759f..5203c6871dd0e 100644 --- a/libavcodec/vaapi_encode_h265.c +++ b/libavcodec/vaapi_encode_h265.c @@ -16,163 +16,25 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include #include #include "libavutil/avassert.h" -#include "libavutil/internal.h" +#include "libavutil/common.h" #include "libavutil/opt.h" -#include "libavutil/pixfmt.h" #include "avcodec.h" +#include "cbs.h" +#include "cbs_h265.h" #include "hevc.h" #include "internal.h" #include "put_bits.h" #include "vaapi_encode.h" -#include "vaapi_encode_h26x.h" - - -#define MAX_ST_REF_PIC_SETS 32 -#define MAX_DPB_PICS 16 -#define MAX_LAYERS 1 - - -typedef struct VAAPIEncodeH265STRPS { - char inter_ref_pic_set_prediction_flag; - - unsigned int num_negative_pics; - unsigned int num_positive_pics; - - unsigned int delta_poc_s0_minus1[MAX_DPB_PICS]; - char used_by_curr_pic_s0_flag[MAX_DPB_PICS]; - - unsigned int delta_poc_s1_minus1[MAX_DPB_PICS]; - char used_by_curr_pic_s1_flag[MAX_DPB_PICS]; -} VAAPIEncodeH265STRPS; - -// This structure contains all possibly-useful per-sequence syntax elements -// which are not already contained in the various VAAPI structures. -typedef struct VAAPIEncodeH265MiscSequenceParams { - - // Parameter set IDs. - unsigned int video_parameter_set_id; - unsigned int seq_parameter_set_id; - - // Layering. - unsigned int vps_max_layers_minus1; - unsigned int vps_max_sub_layers_minus1; - char vps_temporal_id_nesting_flag; - unsigned int vps_max_layer_id; - unsigned int vps_num_layer_sets_minus1; - unsigned int sps_max_sub_layers_minus1; - char sps_temporal_id_nesting_flag; - char layer_id_included_flag[MAX_LAYERS][64]; - - // Profile/tier/level parameters. - char general_profile_compatibility_flag[32]; - char general_progressive_source_flag; - char general_interlaced_source_flag; - char general_non_packed_constraint_flag; - char general_frame_only_constraint_flag; - char general_inbld_flag; - - // Decode/display ordering parameters. - unsigned int log2_max_pic_order_cnt_lsb_minus4; - char vps_sub_layer_ordering_info_present_flag; - unsigned int vps_max_dec_pic_buffering_minus1[MAX_LAYERS]; - unsigned int vps_max_num_reorder_pics[MAX_LAYERS]; - unsigned int vps_max_latency_increase_plus1[MAX_LAYERS]; - char sps_sub_layer_ordering_info_present_flag; - unsigned int sps_max_dec_pic_buffering_minus1[MAX_LAYERS]; - unsigned int sps_max_num_reorder_pics[MAX_LAYERS]; - unsigned int sps_max_latency_increase_plus1[MAX_LAYERS]; - - // Timing information. - char vps_timing_info_present_flag; - unsigned int vps_num_units_in_tick; - unsigned int vps_time_scale; - char vps_poc_proportional_to_timing_flag; - unsigned int vps_num_ticks_poc_diff_minus1; - - // Cropping information. - char conformance_window_flag; - unsigned int conf_win_left_offset; - unsigned int conf_win_right_offset; - unsigned int conf_win_top_offset; - unsigned int conf_win_bottom_offset; - - // Short-term reference picture sets. - unsigned int num_short_term_ref_pic_sets; - VAAPIEncodeH265STRPS st_ref_pic_set[MAX_ST_REF_PIC_SETS]; - - // Long-term reference pictures. - char long_term_ref_pics_present_flag; - unsigned int num_long_term_ref_pics_sps; - struct { - unsigned int lt_ref_pic_poc_lsb_sps; - char used_by_curr_pic_lt_sps_flag; - } lt_ref_pic; - - // Deblocking filter control. - char deblocking_filter_control_present_flag; - char deblocking_filter_override_enabled_flag; - char pps_deblocking_filter_disabled_flag; - int pps_beta_offset_div2; - int pps_tc_offset_div2; - - // Video Usability Information. - char vui_parameters_present_flag; - char aspect_ratio_info_present_flag; - unsigned int aspect_ratio_idc; - unsigned int sar_width; - unsigned int sar_height; - char video_signal_type_present_flag; - unsigned int video_format; - char video_full_range_flag; - char colour_description_present_flag; - unsigned int colour_primaries; - unsigned int transfer_characteristics; - unsigned int matrix_coeffs; - - // Oddments. - char uniform_spacing_flag; - char output_flag_present_flag; - char cabac_init_present_flag; - unsigned int num_extra_slice_header_bits; - char lists_modification_present_flag; - char pps_slice_chroma_qp_offsets_present_flag; - char pps_slice_chroma_offset_list_enabled_flag; -} VAAPIEncodeH265MiscSequenceParams; - -// This structure contains all possibly-useful per-slice syntax elements -// which are not already contained in the various VAAPI structures. -typedef struct VAAPIEncodeH265MiscSliceParams { - // Slice segments. - char first_slice_segment_in_pic_flag; - - // Short-term reference picture sets. - char short_term_ref_pic_set_sps_flag; - unsigned int short_term_ref_pic_idx; - VAAPIEncodeH265STRPS st_ref_pic_set; - - // Deblocking filter. - char deblocking_filter_override_flag; - - // Oddments. - char slice_reserved_flag[8]; - char no_output_of_prior_pics_flag; - char pic_output_flag; -} VAAPIEncodeH265MiscSliceParams; - -typedef struct VAAPIEncodeH265Slice { - VAAPIEncodeH265MiscSliceParams misc_slice_params; - - int64_t pic_order_cnt; -} VAAPIEncodeH265Slice; -typedef struct VAAPIEncodeH265Context { - VAAPIEncodeH265MiscSequenceParams misc_sequence_params; +typedef struct VAAPIEncodeH265Context { unsigned int ctu_width; unsigned int ctu_height; @@ -180,777 +42,494 @@ typedef struct VAAPIEncodeH265Context { int fixed_qp_p; int fixed_qp_b; + H265RawAUD aud; + H265RawVPS vps; + H265RawSPS sps; + H265RawPPS pps; + H265RawSlice slice; + int64_t last_idr_frame; + int pic_order_cnt; + + int slice_nal_unit; + int slice_type; + int pic_type; - // Rate control configuration. - struct { - VAEncMiscParameterBuffer misc; - VAEncMiscParameterRateControl rc; - } rc_params; - struct { - VAEncMiscParameterBuffer misc; - VAEncMiscParameterHRD hrd; - } hrd_params; + CodedBitstreamContext *cbc; + CodedBitstreamFragment current_access_unit; + int aud_needed; } VAAPIEncodeH265Context; typedef struct VAAPIEncodeH265Options { int qp; + int aud; + int profile; + int level; } VAAPIEncodeH265Options; -#define vseq_var(name) vseq->name, name -#define vseq_field(name) vseq->seq_fields.bits.name, name -#define vpic_var(name) vpic->name, name -#define vpic_field(name) vpic->pic_fields.bits.name, name -#define vslice_var(name) vslice->name, name -#define vslice_field(name) vslice->slice_fields.bits.name, name -#define mseq_var(name) mseq->name, name -#define mslice_var(name) mslice->name, name -#define mstrps_var(name) mstrps->name, name - -static void vaapi_encode_h265_write_nal_unit_header(PutBitContext *pbc, - int nal_unit_type) +static int vaapi_encode_h265_write_access_unit(AVCodecContext *avctx, + char *data, size_t *data_len, + CodedBitstreamFragment *au) { - u(1, 0, forbidden_zero_bit); - u(6, nal_unit_type, nal_unit_type); - u(6, 0, nuh_layer_id); - u(3, 1, nuh_temporal_id_plus1); -} - -static void vaapi_encode_h265_write_rbsp_trailing_bits(PutBitContext *pbc) -{ - u(1, 1, rbsp_stop_one_bit); - while (put_bits_count(pbc) & 7) - u(1, 0, rbsp_alignment_zero_bit); -} - -static void vaapi_encode_h265_write_profile_tier_level(PutBitContext *pbc, - VAAPIEncodeContext *ctx) -{ - VAEncSequenceParameterBufferHEVC *vseq = ctx->codec_sequence_params; - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265MiscSequenceParams *mseq = &priv->misc_sequence_params; - int j; - - if (1) { - u(2, 0, general_profile_space); - u(1, vseq_var(general_tier_flag)); - u(5, vseq_var(general_profile_idc)); - - for (j = 0; j < 32; j++) { - u(1, mseq_var(general_profile_compatibility_flag[j])); - } - - u(1, mseq_var(general_progressive_source_flag)); - u(1, mseq_var(general_interlaced_source_flag)); - u(1, mseq_var(general_non_packed_constraint_flag)); - u(1, mseq_var(general_frame_only_constraint_flag)); + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = ctx->priv_data; + int err; - if (0) { - // Not main profile. - // Lots of extra constraint flags. - } else { - // put_bits only handles up to 31 bits. - u(23, 0, general_reserved_zero_43bits); - u(20, 0, general_reserved_zero_43bits); - } + err = ff_cbs_write_fragment_data(priv->cbc, au); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to write packed header.\n"); + return err; + } - if (vseq->general_profile_idc >= 1 && vseq->general_profile_idc <= 5) { - u(1, mseq_var(general_inbld_flag)); - } else { - u(1, 0, general_reserved_zero_bit); - } + if (*data_len < 8 * au->data_size - au->data_bit_padding) { + av_log(avctx, AV_LOG_ERROR, "Access unit too large: " + "%zu < %zu.\n", *data_len, + 8 * au->data_size - au->data_bit_padding); + return AVERROR(ENOSPC); } - u(8, vseq_var(general_level_idc)); + memcpy(data, au->data, au->data_size); + *data_len = 8 * au->data_size - au->data_bit_padding; - // No sublayers. + return 0; } -static void vaapi_encode_h265_write_vps(PutBitContext *pbc, - VAAPIEncodeContext *ctx) +static int vaapi_encode_h265_add_nal(AVCodecContext *avctx, + CodedBitstreamFragment *au, + void *nal_unit) { - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265MiscSequenceParams *mseq = &priv->misc_sequence_params; - int i, j; - - vaapi_encode_h265_write_nal_unit_header(pbc, HEVC_NAL_VPS); - - u(4, mseq->video_parameter_set_id, vps_video_parameter_set_id); + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = ctx->priv_data; + H265RawNALUnitHeader *header = nal_unit; + int err; - u(1, 1, vps_base_layer_internal_flag); - u(1, 1, vps_base_layer_available_flag); - u(6, mseq_var(vps_max_layers_minus1)); - u(3, mseq_var(vps_max_sub_layers_minus1)); - u(1, mseq_var(vps_temporal_id_nesting_flag)); + err = ff_cbs_insert_unit_content(priv->cbc, au, -1, + header->nal_unit_type, nal_unit, NULL); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to add NAL unit: " + "type = %d.\n", header->nal_unit_type); + return err; + } - u(16, 0xffff, vps_reserved_0xffff_16bits); + return 0; +} - vaapi_encode_h265_write_profile_tier_level(pbc, ctx); +static int vaapi_encode_h265_write_sequence_header(AVCodecContext *avctx, + char *data, size_t *data_len) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = ctx->priv_data; + CodedBitstreamFragment *au = &priv->current_access_unit; + int err; - u(1, mseq_var(vps_sub_layer_ordering_info_present_flag)); - for (i = (mseq->vps_sub_layer_ordering_info_present_flag ? - 0 : mseq->vps_max_sub_layers_minus1); - i <= mseq->vps_max_sub_layers_minus1; i++) { - ue(mseq_var(vps_max_dec_pic_buffering_minus1[i])); - ue(mseq_var(vps_max_num_reorder_pics[i])); - ue(mseq_var(vps_max_latency_increase_plus1[i])); + if (priv->aud_needed) { + err = vaapi_encode_h265_add_nal(avctx, au, &priv->aud); + if (err < 0) + goto fail; + priv->aud_needed = 0; } - u(6, mseq_var(vps_max_layer_id)); - ue(mseq_var(vps_num_layer_sets_minus1)); - for (i = 1; i <= mseq->vps_num_layer_sets_minus1; i++) { - for (j = 0; j < mseq->vps_max_layer_id; j++) - u(1, mseq_var(layer_id_included_flag[i][j])); - } + err = vaapi_encode_h265_add_nal(avctx, au, &priv->vps); + if (err < 0) + goto fail; - u(1, mseq_var(vps_timing_info_present_flag)); - if (mseq->vps_timing_info_present_flag) { - u(1, 0, put_bits_hack_zero_bit); - u(31, mseq_var(vps_num_units_in_tick)); - u(1, 0, put_bits_hack_zero_bit); - u(31, mseq_var(vps_time_scale)); - u(1, mseq_var(vps_poc_proportional_to_timing_flag)); - if (mseq->vps_poc_proportional_to_timing_flag) { - ue(mseq_var(vps_num_ticks_poc_diff_minus1)); - } - ue(0, vps_num_hrd_parameters); - } + err = vaapi_encode_h265_add_nal(avctx, au, &priv->sps); + if (err < 0) + goto fail; - u(1, 0, vps_extension_flag); + err = vaapi_encode_h265_add_nal(avctx, au, &priv->pps); + if (err < 0) + goto fail; - vaapi_encode_h265_write_rbsp_trailing_bits(pbc); + err = vaapi_encode_h265_write_access_unit(avctx, data, data_len, au); +fail: + ff_cbs_fragment_uninit(priv->cbc, au); + return err; } -static void vaapi_encode_h265_write_st_ref_pic_set(PutBitContext *pbc, - int st_rps_idx, - VAAPIEncodeH265STRPS *mstrps) +static int vaapi_encode_h265_write_slice_header(AVCodecContext *avctx, + VAAPIEncodePicture *pic, + VAAPIEncodeSlice *slice, + char *data, size_t *data_len) { - int i; - - if (st_rps_idx != 0) - u(1, mstrps_var(inter_ref_pic_set_prediction_flag)); - - if (mstrps->inter_ref_pic_set_prediction_flag) { - av_assert0(0 && "inter ref pic set prediction not supported"); - } else { - ue(mstrps_var(num_negative_pics)); - ue(mstrps_var(num_positive_pics)); - - for (i = 0; i < mstrps->num_negative_pics; i++) { - ue(mstrps_var(delta_poc_s0_minus1[i])); - u(1, mstrps_var(used_by_curr_pic_s0_flag[i])); - } - for (i = 0; i < mstrps->num_positive_pics; i++) { - ue(mstrps_var(delta_poc_s1_minus1[i])); - u(1, mstrps_var(used_by_curr_pic_s1_flag[i])); - } - } -} + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = ctx->priv_data; + CodedBitstreamFragment *au = &priv->current_access_unit; + int err; -static void vaapi_encode_h265_write_vui_parameters(PutBitContext *pbc, - VAAPIEncodeContext *ctx) -{ - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265MiscSequenceParams *mseq = &priv->misc_sequence_params; - - u(1, mseq_var(aspect_ratio_info_present_flag)); - if (mseq->aspect_ratio_info_present_flag) { - u(8, mseq_var(aspect_ratio_idc)); - if (mseq->aspect_ratio_idc == 255) { - u(16, mseq_var(sar_width)); - u(16, mseq_var(sar_height)); - } + if (priv->aud_needed) { + err = vaapi_encode_h265_add_nal(avctx, au, &priv->aud); + if (err < 0) + goto fail; + priv->aud_needed = 0; } - u(1, 0, overscan_info_present_flag); - - u(1, mseq_var(video_signal_type_present_flag)); - if (mseq->video_signal_type_present_flag) { - u(3, mseq_var(video_format)); - u(1, mseq_var(video_full_range_flag)); - u(1, mseq_var(colour_description_present_flag)); - if (mseq->colour_description_present_flag) { - u(8, mseq_var(colour_primaries)); - u(8, mseq_var(transfer_characteristics)); - u(8, mseq_var(matrix_coeffs)); - } - } + err = vaapi_encode_h265_add_nal(avctx, au, &priv->slice); + if (err < 0) + goto fail; - u(1, 0, chroma_loc_info_present_flag); - u(1, 0, neutral_chroma_indication_flag); - u(1, 0, field_seq_flag); - u(1, 0, frame_field_info_present_flag); - u(1, 0, default_display_window_flag); - u(1, 0, vui_timing_info_present_flag); - u(1, 0, bitstream_restriction_flag_flag); + err = vaapi_encode_h265_write_access_unit(avctx, data, data_len, au); +fail: + ff_cbs_fragment_uninit(priv->cbc, au); + return err; } -static void vaapi_encode_h265_write_sps(PutBitContext *pbc, - VAAPIEncodeContext *ctx) +static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) { - VAEncSequenceParameterBufferHEVC *vseq = ctx->codec_sequence_params; - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265MiscSequenceParams *mseq = &priv->misc_sequence_params; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = ctx->priv_data; + H265RawVPS *vps = &priv->vps; + H265RawSPS *sps = &priv->sps; + H265RawPPS *pps = &priv->pps; + H265RawVUI *vui = &sps->vui; + VAEncSequenceParameterBufferHEVC *vseq = ctx->codec_sequence_params; + VAEncPictureParameterBufferHEVC *vpic = ctx->codec_picture_params; int i; - vaapi_encode_h265_write_nal_unit_header(pbc, HEVC_NAL_SPS); - - u(4, mseq->video_parameter_set_id, sps_video_parameter_set_id); + memset(&priv->current_access_unit, 0, + sizeof(priv->current_access_unit)); - u(3, mseq_var(sps_max_sub_layers_minus1)); - u(1, mseq_var(sps_temporal_id_nesting_flag)); + memset(vps, 0, sizeof(*vps)); + memset(sps, 0, sizeof(*sps)); + memset(pps, 0, sizeof(*pps)); - vaapi_encode_h265_write_profile_tier_level(pbc, ctx); - - ue(mseq->seq_parameter_set_id, sps_seq_parameter_set_id); - ue(vseq_field(chroma_format_idc)); - if (vseq->seq_fields.bits.chroma_format_idc == 3) - u(1, 0, separate_colour_plane_flag); - - ue(vseq_var(pic_width_in_luma_samples)); - ue(vseq_var(pic_height_in_luma_samples)); - - u(1, mseq_var(conformance_window_flag)); - if (mseq->conformance_window_flag) { - ue(mseq_var(conf_win_left_offset)); - ue(mseq_var(conf_win_right_offset)); - ue(mseq_var(conf_win_top_offset)); - ue(mseq_var(conf_win_bottom_offset)); - } - ue(vseq_field(bit_depth_luma_minus8)); - ue(vseq_field(bit_depth_chroma_minus8)); + // VPS - ue(mseq_var(log2_max_pic_order_cnt_lsb_minus4)); + vps->nal_unit_header = (H265RawNALUnitHeader) { + .nal_unit_type = HEVC_NAL_VPS, + .nuh_layer_id = 0, + .nuh_temporal_id_plus1 = 1, + }; - u(1, mseq_var(sps_sub_layer_ordering_info_present_flag)); - for (i = (mseq->sps_sub_layer_ordering_info_present_flag ? - 0 : mseq->sps_max_sub_layers_minus1); - i <= mseq->sps_max_sub_layers_minus1; i++) { - ue(mseq_var(sps_max_dec_pic_buffering_minus1[i])); - ue(mseq_var(sps_max_num_reorder_pics[i])); - ue(mseq_var(sps_max_latency_increase_plus1[i])); - } + vps->vps_video_parameter_set_id = 0; - ue(vseq_var(log2_min_luma_coding_block_size_minus3)); - ue(vseq_var(log2_diff_max_min_luma_coding_block_size)); - ue(vseq_var(log2_min_transform_block_size_minus2)); - ue(vseq_var(log2_diff_max_min_transform_block_size)); - ue(vseq_var(max_transform_hierarchy_depth_inter)); - ue(vseq_var(max_transform_hierarchy_depth_intra)); + vps->vps_base_layer_internal_flag = 1; + vps->vps_base_layer_available_flag = 1; + vps->vps_max_layers_minus1 = 0; + vps->vps_max_sub_layers_minus1 = 0; + vps->vps_temporal_id_nesting_flag = 1; - u(1, vseq_field(scaling_list_enabled_flag)); - if (vseq->seq_fields.bits.scaling_list_enabled_flag) { - u(1, 0, sps_scaling_list_data_present_flag); - } + vps->profile_tier_level = (H265RawProfileTierLevel) { + .general_profile_space = 0, + .general_profile_idc = avctx->profile, + .general_tier_flag = 0, - u(1, vseq_field(amp_enabled_flag)); - u(1, vseq_field(sample_adaptive_offset_enabled_flag)); - - u(1, vseq_field(pcm_enabled_flag)); - if (vseq->seq_fields.bits.pcm_enabled_flag) { - u(4, vseq_var(pcm_sample_bit_depth_luma_minus1)); - u(4, vseq_var(pcm_sample_bit_depth_chroma_minus1)); - ue(vseq_var(log2_min_pcm_luma_coding_block_size_minus3)); - ue(vseq->log2_max_pcm_luma_coding_block_size_minus3 - - vseq->log2_min_pcm_luma_coding_block_size_minus3, - log2_diff_max_min_pcm_luma_coding_block_size); - u(1, vseq_field(pcm_loop_filter_disabled_flag)); - } + .general_progressive_source_flag = 1, + .general_interlaced_source_flag = 0, + .general_non_packed_constraint_flag = 1, + .general_frame_only_constraint_flag = 1, - ue(mseq_var(num_short_term_ref_pic_sets)); - for (i = 0; i < mseq->num_short_term_ref_pic_sets; i++) - vaapi_encode_h265_write_st_ref_pic_set(pbc, i, - &mseq->st_ref_pic_set[i]); + .general_level_idc = avctx->level, + }; + vps->profile_tier_level.general_profile_compatibility_flag[avctx->profile & 31] = 1; - u(1, mseq_var(long_term_ref_pics_present_flag)); - if (mseq->long_term_ref_pics_present_flag) { - ue(0, num_long_term_ref_pics_sps); - } + vps->vps_sub_layer_ordering_info_present_flag = 0; + vps->vps_max_dec_pic_buffering_minus1[0] = (ctx->b_per_p > 0) + 1; + vps->vps_max_num_reorder_pics[0] = (ctx->b_per_p > 0); + vps->vps_max_latency_increase_plus1[0] = 0; - u(1, vseq_field(sps_temporal_mvp_enabled_flag)); - u(1, vseq_field(strong_intra_smoothing_enabled_flag)); + vps->vps_max_layer_id = 0; + vps->vps_num_layer_sets_minus1 = 0; + vps->layer_id_included_flag[0][0] = 1; - u(1, mseq_var(vui_parameters_present_flag)); - if (mseq->vui_parameters_present_flag) { - vaapi_encode_h265_write_vui_parameters(pbc, ctx); + vps->vps_timing_info_present_flag = 1; + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { + vps->vps_num_units_in_tick = avctx->framerate.den; + vps->vps_time_scale = avctx->framerate.num; + vps->vps_poc_proportional_to_timing_flag = 1; + vps->vps_num_ticks_poc_diff_one_minus1 = 0; + } else { + vps->vps_num_units_in_tick = avctx->time_base.num; + vps->vps_time_scale = avctx->time_base.den; + vps->vps_poc_proportional_to_timing_flag = 0; } + vps->vps_num_hrd_parameters = 0; - u(1, 0, sps_extension_present_flag); - - vaapi_encode_h265_write_rbsp_trailing_bits(pbc); -} - -static void vaapi_encode_h265_write_pps(PutBitContext *pbc, - VAAPIEncodeContext *ctx) -{ - VAEncPictureParameterBufferHEVC *vpic = ctx->codec_picture_params; - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265MiscSequenceParams *mseq = &priv->misc_sequence_params; - int i; - vaapi_encode_h265_write_nal_unit_header(pbc, HEVC_NAL_PPS); + // SPS - ue(vpic->slice_pic_parameter_set_id, pps_pic_parameter_set_id); - ue(mseq->seq_parameter_set_id, pps_seq_parameter_set_id); + sps->nal_unit_header = (H265RawNALUnitHeader) { + .nal_unit_type = HEVC_NAL_SPS, + .nuh_layer_id = 0, + .nuh_temporal_id_plus1 = 1, + }; - u(1, vpic_field(dependent_slice_segments_enabled_flag)); - u(1, mseq_var(output_flag_present_flag)); - u(3, mseq_var(num_extra_slice_header_bits)); - u(1, vpic_field(sign_data_hiding_enabled_flag)); - u(1, mseq_var(cabac_init_present_flag)); + sps->sps_video_parameter_set_id = vps->vps_video_parameter_set_id; - ue(vpic_var(num_ref_idx_l0_default_active_minus1)); - ue(vpic_var(num_ref_idx_l1_default_active_minus1)); + sps->sps_max_sub_layers_minus1 = vps->vps_max_sub_layers_minus1; + sps->sps_temporal_id_nesting_flag = vps->vps_temporal_id_nesting_flag; - se(vpic->pic_init_qp - 26, init_qp_minus26); + sps->profile_tier_level = vps->profile_tier_level; - u(1, vpic_field(constrained_intra_pred_flag)); - u(1, vpic_field(transform_skip_enabled_flag)); + sps->sps_seq_parameter_set_id = 0; - u(1, vpic_field(cu_qp_delta_enabled_flag)); - if (vpic->pic_fields.bits.cu_qp_delta_enabled_flag) - ue(vpic_var(diff_cu_qp_delta_depth)); + sps->chroma_format_idc = 1; // YUV 4:2:0. + sps->separate_colour_plane_flag = 0; - se(vpic_var(pps_cb_qp_offset)); - se(vpic_var(pps_cr_qp_offset)); + sps->pic_width_in_luma_samples = ctx->surface_width; + sps->pic_height_in_luma_samples = ctx->surface_height; - u(1, mseq_var(pps_slice_chroma_qp_offsets_present_flag)); - u(1, vpic_field(weighted_pred_flag)); - u(1, vpic_field(weighted_bipred_flag)); - u(1, vpic_field(transquant_bypass_enabled_flag)); - u(1, vpic_field(tiles_enabled_flag)); - u(1, vpic_field(entropy_coding_sync_enabled_flag)); - - if (vpic->pic_fields.bits.tiles_enabled_flag) { - ue(vpic_var(num_tile_columns_minus1)); - ue(vpic_var(num_tile_rows_minus1)); - u(1, mseq_var(uniform_spacing_flag)); - if (!mseq->uniform_spacing_flag) { - for (i = 0; i < vpic->num_tile_columns_minus1; i++) - ue(vpic_var(column_width_minus1[i])); - for (i = 0; i < vpic->num_tile_rows_minus1; i++) - ue(vpic_var(row_height_minus1[i])); - } - u(1, vpic_field(loop_filter_across_tiles_enabled_flag)); + if (avctx->width != ctx->surface_width || + avctx->height != ctx->surface_height) { + sps->conformance_window_flag = 1; + sps->conf_win_left_offset = 0; + sps->conf_win_right_offset = + (ctx->surface_width - avctx->width) / 2; + sps->conf_win_top_offset = 0; + sps->conf_win_bottom_offset = + (ctx->surface_height - avctx->height) / 2; + } else { + sps->conformance_window_flag = 0; } - u(1, vpic_field(pps_loop_filter_across_slices_enabled_flag)); - u(1, mseq_var(deblocking_filter_control_present_flag)); - if (mseq->deblocking_filter_control_present_flag) { - u(1, mseq_var(deblocking_filter_override_enabled_flag)); - u(1, mseq_var(pps_deblocking_filter_disabled_flag)); - if (!mseq->pps_deblocking_filter_disabled_flag) { - se(mseq_var(pps_beta_offset_div2)); - se(mseq_var(pps_tc_offset_div2)); - } + sps->bit_depth_luma_minus8 = + avctx->profile == FF_PROFILE_HEVC_MAIN_10 ? 2 : 0; + sps->bit_depth_chroma_minus8 = sps->bit_depth_luma_minus8; + + sps->log2_max_pic_order_cnt_lsb_minus4 = 8; + + sps->sps_sub_layer_ordering_info_present_flag = + vps->vps_sub_layer_ordering_info_present_flag; + for (i = 0; i <= sps->sps_max_sub_layers_minus1; i++) { + sps->sps_max_dec_pic_buffering_minus1[i] = + vps->vps_max_dec_pic_buffering_minus1[i]; + sps->sps_max_num_reorder_pics[i] = + vps->vps_max_num_reorder_pics[i]; + sps->sps_max_latency_increase_plus1[i] = + vps->vps_max_latency_increase_plus1[i]; } - u(1, 0, pps_scaling_list_data_present_flag); - // No scaling list data. - - u(1, mseq_var(lists_modification_present_flag)); - ue(vpic_var(log2_parallel_merge_level_minus2)); - u(1, 0, slice_segment_header_extension_present_flag); - u(1, 0, pps_extension_present_flag); - - vaapi_encode_h265_write_rbsp_trailing_bits(pbc); -} - -static void vaapi_encode_h265_write_slice_header2(PutBitContext *pbc, - VAAPIEncodeContext *ctx, - VAAPIEncodePicture *pic, - VAAPIEncodeSlice *slice) -{ - VAEncSequenceParameterBufferHEVC *vseq = ctx->codec_sequence_params; - VAEncPictureParameterBufferHEVC *vpic = pic->codec_picture_params; - VAEncSliceParameterBufferHEVC *vslice = slice->codec_slice_params; - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265MiscSequenceParams *mseq = &priv->misc_sequence_params; - VAAPIEncodeH265Slice *pslice = slice->priv_data; - VAAPIEncodeH265MiscSliceParams *mslice = &pslice->misc_slice_params; - int i; - - vaapi_encode_h265_write_nal_unit_header(pbc, vpic->nal_unit_type); - - u(1, mslice_var(first_slice_segment_in_pic_flag)); - if (vpic->nal_unit_type >= HEVC_NAL_BLA_W_LP && - vpic->nal_unit_type <= 23) - u(1, mslice_var(no_output_of_prior_pics_flag)); - - ue(vslice_var(slice_pic_parameter_set_id)); - - if (!mslice->first_slice_segment_in_pic_flag) { - if (vpic->pic_fields.bits.dependent_slice_segments_enabled_flag) - u(1, vslice_field(dependent_slice_segment_flag)); - u(av_log2((priv->ctu_width * priv->ctu_height) - 1) + 1, - vslice_var(slice_segment_address)); - } - if (!vslice->slice_fields.bits.dependent_slice_segment_flag) { - for (i = 0; i < mseq->num_extra_slice_header_bits; i++) - u(1, mslice_var(slice_reserved_flag[i])); - - ue(vslice_var(slice_type)); - if (mseq->output_flag_present_flag) - u(1, 1, pic_output_flag); - if (vseq->seq_fields.bits.separate_colour_plane_flag) - u(2, vslice_field(colour_plane_id)); - if (vpic->nal_unit_type != HEVC_NAL_IDR_W_RADL && - vpic->nal_unit_type != HEVC_NAL_IDR_N_LP) { - u(4 + mseq->log2_max_pic_order_cnt_lsb_minus4, - (pslice->pic_order_cnt & - ((1 << (mseq->log2_max_pic_order_cnt_lsb_minus4 + 4)) - 1)), - slice_pic_order_cnt_lsb); - - u(1, mslice_var(short_term_ref_pic_set_sps_flag)); - if (!mslice->short_term_ref_pic_set_sps_flag) { - vaapi_encode_h265_write_st_ref_pic_set(pbc, mseq->num_short_term_ref_pic_sets, - &mslice->st_ref_pic_set); - } else if (mseq->num_short_term_ref_pic_sets > 1) { - u(av_log2(mseq->num_short_term_ref_pic_sets - 1) + 1, - mslice_var(short_term_ref_pic_idx)); - } - - if (mseq->long_term_ref_pics_present_flag) { - av_assert0(0); - } - } - - if (vseq->seq_fields.bits.sps_temporal_mvp_enabled_flag) { - u(1, vslice_field(slice_temporal_mvp_enabled_flag)); - } - - if (vseq->seq_fields.bits.sample_adaptive_offset_enabled_flag) { - u(1, vslice_field(slice_sao_luma_flag)); - if (!vseq->seq_fields.bits.separate_colour_plane_flag && - vseq->seq_fields.bits.chroma_format_idc != 0) { - u(1, vslice_field(slice_sao_chroma_flag)); - } - } - - if (vslice->slice_type == HEVC_SLICE_P || vslice->slice_type == HEVC_SLICE_B) { - u(1, vslice_field(num_ref_idx_active_override_flag)); - if (vslice->slice_fields.bits.num_ref_idx_active_override_flag) { - ue(vslice_var(num_ref_idx_l0_active_minus1)); - if (vslice->slice_type == HEVC_SLICE_B) { - ue(vslice_var(num_ref_idx_l1_active_minus1)); - } - } - - if (mseq->lists_modification_present_flag) { - av_assert0(0); - // ref_pic_lists_modification() - } - if (vslice->slice_type == HEVC_SLICE_B) { - u(1, vslice_field(mvd_l1_zero_flag)); - } - if (mseq->cabac_init_present_flag) { - u(1, vslice_field(cabac_init_flag)); - } - if (vslice->slice_fields.bits.slice_temporal_mvp_enabled_flag) { - if (vslice->slice_type == HEVC_SLICE_B) - u(1, vslice_field(collocated_from_l0_flag)); - ue(vpic->collocated_ref_pic_index, collocated_ref_idx); - } - if ((vpic->pic_fields.bits.weighted_pred_flag && - vslice->slice_type == HEVC_SLICE_P) || - (vpic->pic_fields.bits.weighted_bipred_flag && - vslice->slice_type == HEVC_SLICE_B)) { - av_assert0(0); - // pred_weight_table() + // These have to come from the capabilities of the encoder. We have no + // way to query them, so just hardcode parameters which work on the Intel + // driver. + // CTB size from 8x8 to 32x32. + sps->log2_min_luma_coding_block_size_minus3 = 0; + sps->log2_diff_max_min_luma_coding_block_size = 2; + // Transform size from 4x4 to 32x32. + sps->log2_min_luma_transform_block_size_minus2 = 0; + sps->log2_diff_max_min_luma_transform_block_size = 3; + // Full transform hierarchy allowed (2-5). + sps->max_transform_hierarchy_depth_inter = 3; + sps->max_transform_hierarchy_depth_intra = 3; + // AMP works. + sps->amp_enabled_flag = 1; + // SAO and temporal MVP do not work. + sps->sample_adaptive_offset_enabled_flag = 0; + sps->sps_temporal_mvp_enabled_flag = 0; + + sps->pcm_enabled_flag = 0; + + // STRPSs should ideally be here rather than defined individually in + // each slice, but the structure isn't completely fixed so for now + // don't bother. + sps->num_short_term_ref_pic_sets = 0; + sps->long_term_ref_pics_present_flag = 0; + + sps->vui_parameters_present_flag = 1; + + if (avctx->sample_aspect_ratio.num != 0 && + avctx->sample_aspect_ratio.den != 0) { + static const AVRational sar_idc[] = { + { 0, 0 }, + { 1, 1 }, { 12, 11 }, { 10, 11 }, { 16, 11 }, + { 40, 33 }, { 24, 11 }, { 20, 11 }, { 32, 11 }, + { 80, 33 }, { 18, 11 }, { 15, 11 }, { 64, 33 }, + { 160, 99 }, { 4, 3 }, { 3, 2 }, { 2, 1 }, + }; + int i; + for (i = 0; i < FF_ARRAY_ELEMS(sar_idc); i++) { + if (avctx->sample_aspect_ratio.num == sar_idc[i].num && + avctx->sample_aspect_ratio.den == sar_idc[i].den) { + vui->aspect_ratio_idc = i; + break; } - ue(5 - vslice->max_num_merge_cand, five_minus_max_num_merge_cand); } - - se(vslice_var(slice_qp_delta)); - if (mseq->pps_slice_chroma_qp_offsets_present_flag) { - se(vslice_var(slice_cb_qp_offset)); - se(vslice_var(slice_cr_qp_offset)); - } - if (mseq->pps_slice_chroma_offset_list_enabled_flag) { - u(1, 0, cu_chroma_qp_offset_enabled_flag); - } - if (mseq->deblocking_filter_override_enabled_flag) { - u(1, mslice_var(deblocking_filter_override_flag)); - } - if (mslice->deblocking_filter_override_flag) { - u(1, vslice_field(slice_deblocking_filter_disabled_flag)); - if (!vslice->slice_fields.bits.slice_deblocking_filter_disabled_flag) { - se(vslice_var(slice_beta_offset_div2)); - se(vslice_var(slice_tc_offset_div2)); - } - } - if (vpic->pic_fields.bits.pps_loop_filter_across_slices_enabled_flag && - (vslice->slice_fields.bits.slice_sao_luma_flag || - vslice->slice_fields.bits.slice_sao_chroma_flag || - vslice->slice_fields.bits.slice_deblocking_filter_disabled_flag)) { - u(1, vslice_field(slice_loop_filter_across_slices_enabled_flag)); - } - - if (vpic->pic_fields.bits.tiles_enabled_flag || - vpic->pic_fields.bits.entropy_coding_sync_enabled_flag) { - // num_entry_point_offsets - } - - if (0) { - // slice_segment_header_extension_length + if (i >= FF_ARRAY_ELEMS(sar_idc)) { + vui->aspect_ratio_idc = 255; + vui->sar_width = avctx->sample_aspect_ratio.num; + vui->sar_height = avctx->sample_aspect_ratio.den; } + vui->aspect_ratio_info_present_flag = 1; } - u(1, 1, alignment_bit_equal_to_one); - while (put_bits_count(pbc) & 7) - u(1, 0, alignment_bit_equal_to_zero); -} - -static int vaapi_encode_h265_write_sequence_header(AVCodecContext *avctx, - char *data, size_t *data_len) -{ - VAAPIEncodeContext *ctx = avctx->priv_data; - PutBitContext pbc; - char tmp[256]; - int err; - size_t nal_len, bit_len, bit_pos, next_len; - - bit_len = *data_len; - bit_pos = 0; - - init_put_bits(&pbc, tmp, sizeof(tmp)); - vaapi_encode_h265_write_vps(&pbc, ctx); - nal_len = put_bits_count(&pbc); - flush_put_bits(&pbc); - - next_len = bit_len - bit_pos; - err = ff_vaapi_encode_h26x_nal_unit_to_byte_stream(data + bit_pos / 8, - &next_len, - tmp, nal_len); - if (err < 0) - return err; - bit_pos += next_len; - - init_put_bits(&pbc, tmp, sizeof(tmp)); - vaapi_encode_h265_write_sps(&pbc, ctx); - nal_len = put_bits_count(&pbc); - flush_put_bits(&pbc); - - next_len = bit_len - bit_pos; - err = ff_vaapi_encode_h26x_nal_unit_to_byte_stream(data + bit_pos / 8, - &next_len, - tmp, nal_len); - if (err < 0) - return err; - bit_pos += next_len; - - init_put_bits(&pbc, tmp, sizeof(tmp)); - vaapi_encode_h265_write_pps(&pbc, ctx); - nal_len = put_bits_count(&pbc); - flush_put_bits(&pbc); - - next_len = bit_len - bit_pos; - err = ff_vaapi_encode_h26x_nal_unit_to_byte_stream(data + bit_pos / 8, - &next_len, - tmp, nal_len); - if (err < 0) - return err; - bit_pos += next_len; - - *data_len = bit_pos; - return 0; -} - -static int vaapi_encode_h265_write_slice_header(AVCodecContext *avctx, - VAAPIEncodePicture *pic, - VAAPIEncodeSlice *slice, - char *data, size_t *data_len) -{ - VAAPIEncodeContext *ctx = avctx->priv_data; - PutBitContext pbc; - char tmp[256]; - size_t header_len; - - init_put_bits(&pbc, tmp, sizeof(tmp)); - vaapi_encode_h265_write_slice_header2(&pbc, ctx, pic, slice); - header_len = put_bits_count(&pbc); - flush_put_bits(&pbc); - - return ff_vaapi_encode_h26x_nal_unit_to_byte_stream(data, data_len, - tmp, header_len); -} - -static int vaapi_encode_h265_init_sequence_params(AVCodecContext *avctx) -{ - VAAPIEncodeContext *ctx = avctx->priv_data; - VAEncSequenceParameterBufferHEVC *vseq = ctx->codec_sequence_params; - VAEncPictureParameterBufferHEVC *vpic = ctx->codec_picture_params; - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265MiscSequenceParams *mseq = &priv->misc_sequence_params; - int i; - - { - // general_profile_space == 0. - vseq->general_profile_idc = 1; // Main profile (ctx->codec_profile?) - vseq->general_tier_flag = 0; - - vseq->general_level_idc = avctx->level * 3; - - vseq->intra_period = 0; - vseq->intra_idr_period = 0; - vseq->ip_period = 0; - - vseq->pic_width_in_luma_samples = ctx->surface_width; - vseq->pic_height_in_luma_samples = ctx->surface_height; - - vseq->seq_fields.bits.chroma_format_idc = 1; // 4:2:0. - vseq->seq_fields.bits.separate_colour_plane_flag = 0; - vseq->seq_fields.bits.bit_depth_luma_minus8 = - avctx->profile == FF_PROFILE_HEVC_MAIN_10 ? 2 : 0; - vseq->seq_fields.bits.bit_depth_chroma_minus8 = - avctx->profile == FF_PROFILE_HEVC_MAIN_10 ? 2 : 0; - // Other misc flags all zero. - - // These have to come from the capabilities of the encoder. We have - // no way to query it, so just hardcode ones which worked for me... - // CTB size from 8x8 to 32x32. - vseq->log2_min_luma_coding_block_size_minus3 = 0; - vseq->log2_diff_max_min_luma_coding_block_size = 2; - // Transform size from 4x4 to 32x32. - vseq->log2_min_transform_block_size_minus2 = 0; - vseq->log2_diff_max_min_transform_block_size = 3; - // Full transform hierarchy allowed (2-5). - vseq->max_transform_hierarchy_depth_inter = 3; - vseq->max_transform_hierarchy_depth_intra = 3; - - vseq->vui_parameters_present_flag = 0; - - vseq->bits_per_second = avctx->bit_rate; - if (avctx->framerate.num > 0 && avctx->framerate.den > 0) { - vseq->vui_num_units_in_tick = avctx->framerate.den; - vseq->vui_time_scale = avctx->framerate.num; - } else { - vseq->vui_num_units_in_tick = avctx->time_base.num; - vseq->vui_time_scale = avctx->time_base.den; + if (avctx->color_range != AVCOL_RANGE_UNSPECIFIED || + avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || + avctx->color_trc != AVCOL_TRC_UNSPECIFIED || + avctx->colorspace != AVCOL_SPC_UNSPECIFIED) { + vui->video_signal_type_present_flag = 1; + vui->video_format = 5; // Unspecified. + vui->video_full_range_flag = + avctx->color_range == AVCOL_RANGE_JPEG; + + if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || + avctx->color_trc != AVCOL_TRC_UNSPECIFIED || + avctx->colorspace != AVCOL_SPC_UNSPECIFIED) { + vui->colour_description_present_flag = 1; + vui->colour_primaries = avctx->color_primaries; + vui->transfer_characteristics = avctx->color_trc; + vui->matrix_coefficients = avctx->colorspace; } - - vseq->intra_period = avctx->gop_size; - vseq->intra_idr_period = avctx->gop_size; - vseq->ip_period = ctx->b_per_p + 1; + } else { + vui->video_format = 5; + vui->video_full_range_flag = 0; + vui->colour_primaries = avctx->color_primaries; + vui->transfer_characteristics = avctx->color_trc; + vui->matrix_coefficients = avctx->colorspace; } - { - vpic->decoded_curr_pic.picture_id = VA_INVALID_ID; - vpic->decoded_curr_pic.flags = VA_PICTURE_HEVC_INVALID; - - for (i = 0; i < FF_ARRAY_ELEMS(vpic->reference_frames); i++) { - vpic->reference_frames[i].picture_id = VA_INVALID_ID; - vpic->reference_frames[i].flags = VA_PICTURE_HEVC_INVALID; - } - - vpic->collocated_ref_pic_index = 0xff; - - vpic->last_picture = 0; - - vpic->pic_init_qp = priv->fixed_qp_idr; - - vpic->diff_cu_qp_delta_depth = 0; - vpic->pps_cb_qp_offset = 0; - vpic->pps_cr_qp_offset = 0; - - // tiles_enabled_flag == 0, so ignore num_tile_(rows|columns)_minus1. - - vpic->log2_parallel_merge_level_minus2 = 0; - - // No limit on size. - vpic->ctu_max_bitsize_allowed = 0; - - vpic->num_ref_idx_l0_default_active_minus1 = 0; - vpic->num_ref_idx_l1_default_active_minus1 = 0; - - vpic->slice_pic_parameter_set_id = 0; - - vpic->pic_fields.bits.screen_content_flag = 0; - vpic->pic_fields.bits.enable_gpu_weighted_prediction = 0; - - // Per-CU QP changes are required for non-constant-QP modes. - vpic->pic_fields.bits.cu_qp_delta_enabled_flag = - ctx->va_rc_mode != VA_RC_CQP; + if (avctx->chroma_sample_location != AVCHROMA_LOC_UNSPECIFIED) { + vui->chroma_loc_info_present_flag = 1; + vui->chroma_sample_loc_type_top_field = + vui->chroma_sample_loc_type_bottom_field = + avctx->chroma_sample_location - 1; } - { - mseq->video_parameter_set_id = 5; - mseq->seq_parameter_set_id = 5; - - mseq->vps_max_layers_minus1 = 0; - mseq->vps_max_sub_layers_minus1 = 0; - mseq->vps_temporal_id_nesting_flag = 1; - mseq->sps_max_sub_layers_minus1 = 0; - mseq->sps_temporal_id_nesting_flag = 1; - - for (i = 0; i < 32; i++) { - mseq->general_profile_compatibility_flag[i] = - (i == vseq->general_profile_idc); - } - - mseq->general_progressive_source_flag = 1; - mseq->general_interlaced_source_flag = 0; - mseq->general_non_packed_constraint_flag = 0; - mseq->general_frame_only_constraint_flag = 1; - mseq->general_inbld_flag = 0; - - mseq->log2_max_pic_order_cnt_lsb_minus4 = 8; - mseq->vps_sub_layer_ordering_info_present_flag = 0; - mseq->vps_max_dec_pic_buffering_minus1[0] = (avctx->max_b_frames > 0) + 1; - mseq->vps_max_num_reorder_pics[0] = (avctx->max_b_frames > 0); - mseq->vps_max_latency_increase_plus1[0] = 0; - mseq->sps_sub_layer_ordering_info_present_flag = 0; - mseq->sps_max_dec_pic_buffering_minus1[0] = (avctx->max_b_frames > 0) + 1; - mseq->sps_max_num_reorder_pics[0] = (avctx->max_b_frames > 0); - mseq->sps_max_latency_increase_plus1[0] = 0; - - mseq->vps_timing_info_present_flag = 1; - mseq->vps_num_units_in_tick = avctx->time_base.num; - mseq->vps_time_scale = avctx->time_base.den; - mseq->vps_poc_proportional_to_timing_flag = 1; - mseq->vps_num_ticks_poc_diff_minus1 = 0; - - if (avctx->width != ctx->surface_width || - avctx->height != ctx->surface_height) { - mseq->conformance_window_flag = 1; - mseq->conf_win_left_offset = 0; - mseq->conf_win_right_offset = - (ctx->surface_width - avctx->width) / 2; - mseq->conf_win_top_offset = 0; - mseq->conf_win_bottom_offset = - (ctx->surface_height - avctx->height) / 2; - } else { - mseq->conformance_window_flag = 0; - } - - mseq->num_short_term_ref_pic_sets = 0; - // STRPSs should ideally be here rather than repeated in each slice. - - mseq->vui_parameters_present_flag = 1; - if (avctx->sample_aspect_ratio.num != 0) { - mseq->aspect_ratio_info_present_flag = 1; - if (avctx->sample_aspect_ratio.num == - avctx->sample_aspect_ratio.den) { - mseq->aspect_ratio_idc = 1; - } else { - mseq->aspect_ratio_idc = 255; // Extended SAR. - mseq->sar_width = avctx->sample_aspect_ratio.num; - mseq->sar_height = avctx->sample_aspect_ratio.den; - } - } - if (1) { - // Should this be conditional on some of these being set? - mseq->video_signal_type_present_flag = 1; - mseq->video_format = 5; // Unspecified. - mseq->video_full_range_flag = 0; - mseq->colour_description_present_flag = 1; - mseq->colour_primaries = avctx->color_primaries; - mseq->transfer_characteristics = avctx->color_trc; - mseq->matrix_coeffs = avctx->colorspace; - } - } + vui->vui_timing_info_present_flag = 1; + vui->vui_num_units_in_tick = vps->vps_num_units_in_tick; + vui->vui_time_scale = vps->vps_time_scale; + vui->vui_poc_proportional_to_timing_flag = vps->vps_poc_proportional_to_timing_flag; + vui->vui_num_ticks_poc_diff_one_minus1 = vps->vps_num_ticks_poc_diff_one_minus1; + vui->vui_hrd_parameters_present_flag = 0; + + vui->bitstream_restriction_flag = 1; + vui->motion_vectors_over_pic_boundaries_flag = 1; + vui->restricted_ref_pic_lists_flag = 1; + vui->max_bytes_per_pic_denom = 0; + vui->max_bits_per_min_cu_denom = 0; + vui->log2_max_mv_length_horizontal = 15; + vui->log2_max_mv_length_vertical = 15; + + + // PPS + + pps->nal_unit_header = (H265RawNALUnitHeader) { + .nal_unit_type = HEVC_NAL_PPS, + .nuh_layer_id = 0, + .nuh_temporal_id_plus1 = 1, + }; + + pps->pps_pic_parameter_set_id = 0; + pps->pps_seq_parameter_set_id = sps->sps_seq_parameter_set_id; + + pps->num_ref_idx_l0_default_active_minus1 = 0; + pps->num_ref_idx_l1_default_active_minus1 = 0; + + pps->init_qp_minus26 = priv->fixed_qp_idr - 26; + + pps->cu_qp_delta_enabled_flag = (ctx->va_rc_mode != VA_RC_CQP); + pps->diff_cu_qp_delta_depth = 0; + + pps->pps_loop_filter_across_slices_enabled_flag = 1; + + + // Fill VAAPI parameter buffers. + + *vseq = (VAEncSequenceParameterBufferHEVC) { + .general_profile_idc = vps->profile_tier_level.general_profile_idc, + .general_level_idc = vps->profile_tier_level.general_level_idc, + .general_tier_flag = vps->profile_tier_level.general_tier_flag, + + .intra_period = avctx->gop_size, + .intra_idr_period = avctx->gop_size, + .ip_period = ctx->b_per_p + 1, + .bits_per_second = avctx->bit_rate, + + .pic_width_in_luma_samples = sps->pic_width_in_luma_samples, + .pic_height_in_luma_samples = sps->pic_height_in_luma_samples, + + .seq_fields.bits = { + .chroma_format_idc = sps->chroma_format_idc, + .separate_colour_plane_flag = sps->separate_colour_plane_flag, + .bit_depth_luma_minus8 = sps->bit_depth_luma_minus8, + .bit_depth_chroma_minus8 = sps->bit_depth_chroma_minus8, + .scaling_list_enabled_flag = sps->scaling_list_enabled_flag, + .strong_intra_smoothing_enabled_flag = + sps->strong_intra_smoothing_enabled_flag, + .amp_enabled_flag = sps->amp_enabled_flag, + .sample_adaptive_offset_enabled_flag = + sps->sample_adaptive_offset_enabled_flag, + .pcm_enabled_flag = sps->pcm_enabled_flag, + .pcm_loop_filter_disabled_flag = sps->pcm_loop_filter_disabled_flag, + .sps_temporal_mvp_enabled_flag = sps->sps_temporal_mvp_enabled_flag, + }, + + .log2_min_luma_coding_block_size_minus3 = + sps->log2_min_luma_coding_block_size_minus3, + .log2_diff_max_min_luma_coding_block_size = + sps->log2_diff_max_min_luma_coding_block_size, + .log2_min_transform_block_size_minus2 = + sps->log2_min_luma_transform_block_size_minus2, + .log2_diff_max_min_transform_block_size = + sps->log2_diff_max_min_luma_transform_block_size, + .max_transform_hierarchy_depth_inter = + sps->max_transform_hierarchy_depth_inter, + .max_transform_hierarchy_depth_intra = + sps->max_transform_hierarchy_depth_intra, + + .pcm_sample_bit_depth_luma_minus1 = + sps->pcm_sample_bit_depth_luma_minus1, + .pcm_sample_bit_depth_chroma_minus1 = + sps->pcm_sample_bit_depth_chroma_minus1, + .log2_min_pcm_luma_coding_block_size_minus3 = + sps->log2_min_pcm_luma_coding_block_size_minus3, + .log2_max_pcm_luma_coding_block_size_minus3 = + sps->log2_min_pcm_luma_coding_block_size_minus3 + + sps->log2_diff_max_min_pcm_luma_coding_block_size, + + .vui_parameters_present_flag = 0, + }; + + *vpic = (VAEncPictureParameterBufferHEVC) { + .decoded_curr_pic = { + .picture_id = VA_INVALID_ID, + .flags = VA_PICTURE_HEVC_INVALID, + }, + + .coded_buf = VA_INVALID_ID, + + .collocated_ref_pic_index = 0xff, + + .last_picture = 0, + + .pic_init_qp = pps->init_qp_minus26 + 26, + .diff_cu_qp_delta_depth = pps->diff_cu_qp_delta_depth, + .pps_cb_qp_offset = pps->pps_cb_qp_offset, + .pps_cr_qp_offset = pps->pps_cr_qp_offset, + + .num_tile_columns_minus1 = pps->num_tile_columns_minus1, + .num_tile_rows_minus1 = pps->num_tile_rows_minus1, + + .log2_parallel_merge_level_minus2 = pps->log2_parallel_merge_level_minus2, + .ctu_max_bitsize_allowed = 0, + + .num_ref_idx_l0_default_active_minus1 = + pps->num_ref_idx_l0_default_active_minus1, + .num_ref_idx_l1_default_active_minus1 = + pps->num_ref_idx_l1_default_active_minus1, + + .slice_pic_parameter_set_id = pps->pps_pic_parameter_set_id, + + .pic_fields.bits = { + .sign_data_hiding_enabled_flag = pps->sign_data_hiding_enabled_flag, + .constrained_intra_pred_flag = pps->constrained_intra_pred_flag, + .transform_skip_enabled_flag = pps->transform_skip_enabled_flag, + .cu_qp_delta_enabled_flag = pps->cu_qp_delta_enabled_flag, + .weighted_pred_flag = pps->weighted_pred_flag, + .weighted_bipred_flag = pps->weighted_bipred_flag, + .transquant_bypass_enabled_flag = pps->transquant_bypass_enabled_flag, + .tiles_enabled_flag = pps->tiles_enabled_flag, + .entropy_coding_sync_enabled_flag = pps->entropy_coding_sync_enabled_flag, + .loop_filter_across_tiles_enabled_flag = + pps->loop_filter_across_tiles_enabled_flag, + .scaling_list_data_present_flag = (sps->sps_scaling_list_data_present_flag | + pps->pps_scaling_list_data_present_flag), + .screen_content_flag = 0, + .enable_gpu_weighted_prediction = 0, + .no_output_of_prior_pics_flag = 0, + }, + }; return 0; } @@ -959,65 +538,104 @@ static int vaapi_encode_h265_init_picture_params(AVCodecContext *avctx, VAAPIEncodePicture *pic) { VAAPIEncodeContext *ctx = avctx->priv_data; - VAEncPictureParameterBufferHEVC *vpic = pic->codec_picture_params; VAAPIEncodeH265Context *priv = ctx->priv_data; + VAAPIEncodeH265Options *opt = ctx->codec_options; + VAEncPictureParameterBufferHEVC *vpic = pic->codec_picture_params; int i; if (pic->type == PICTURE_TYPE_IDR) { av_assert0(pic->display_order == pic->encode_order); + priv->last_idr_frame = pic->display_order; + + priv->slice_nal_unit = HEVC_NAL_IDR_W_RADL; + priv->slice_type = HEVC_SLICE_I; + priv->pic_type = 0; } else { av_assert0(pic->encode_order > priv->last_idr_frame); - // Display order need not be if we have RA[SD]L pictures, though. + + if (pic->type == PICTURE_TYPE_I) { + priv->slice_nal_unit = HEVC_NAL_CRA_NUT; + priv->slice_type = HEVC_SLICE_I; + priv->pic_type = 0; + } else if (pic->type == PICTURE_TYPE_P) { + av_assert0(pic->refs[0]); + priv->slice_nal_unit = HEVC_NAL_TRAIL_R; + priv->slice_type = HEVC_SLICE_P; + priv->pic_type = 1; + } else { + av_assert0(pic->refs[0] && pic->refs[1]); + if (pic->refs[1]->type == PICTURE_TYPE_I) + priv->slice_nal_unit = HEVC_NAL_RASL_N; + else + priv->slice_nal_unit = HEVC_NAL_TRAIL_N; + priv->slice_type = HEVC_SLICE_B; + priv->pic_type = 2; + } + } + priv->pic_order_cnt = pic->display_order - priv->last_idr_frame; + + if (opt->aud) { + priv->aud_needed = 1; + priv->aud.nal_unit_header = (H265RawNALUnitHeader) { + .nal_unit_type = HEVC_NAL_AUD, + .nuh_layer_id = 0, + .nuh_temporal_id_plus1 = 1, + }; + priv->aud.pic_type = priv->pic_type; + } else { + priv->aud_needed = 0; } - vpic->decoded_curr_pic.picture_id = pic->recon_surface; - vpic->decoded_curr_pic.pic_order_cnt = - pic->display_order - priv->last_idr_frame; - vpic->decoded_curr_pic.flags = 0; + vpic->decoded_curr_pic = (VAPictureHEVC) { + .picture_id = pic->recon_surface, + .pic_order_cnt = priv->pic_order_cnt, + .flags = 0, + }; for (i = 0; i < pic->nb_refs; i++) { VAAPIEncodePicture *ref = pic->refs[i]; - av_assert0(ref); - vpic->reference_frames[i].picture_id = ref->recon_surface; - vpic->reference_frames[i].pic_order_cnt = - ref->display_order - priv->last_idr_frame; - vpic->reference_frames[i].flags = - (ref->display_order < pic->display_order ? - VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE : 0) | - (ref->display_order > pic->display_order ? - VA_PICTURE_HEVC_RPS_ST_CURR_AFTER : 0); + av_assert0(ref && ref->encode_order < pic->encode_order); + + vpic->reference_frames[i] = (VAPictureHEVC) { + .picture_id = ref->recon_surface, + .pic_order_cnt = ref->display_order - priv->last_idr_frame, + .flags = (ref->display_order < pic->display_order ? + VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE : 0) | + (ref->display_order > pic->display_order ? + VA_PICTURE_HEVC_RPS_ST_CURR_AFTER : 0), + }; } for (; i < FF_ARRAY_ELEMS(vpic->reference_frames); i++) { - vpic->reference_frames[i].picture_id = VA_INVALID_ID; - vpic->reference_frames[i].flags = VA_PICTURE_HEVC_INVALID; + vpic->reference_frames[i] = (VAPictureHEVC) { + .picture_id = VA_INVALID_ID, + .flags = VA_PICTURE_HEVC_INVALID, + }; } vpic->coded_buf = pic->output_buffer; + vpic->nal_unit_type = priv->slice_nal_unit; + switch (pic->type) { case PICTURE_TYPE_IDR: - vpic->nal_unit_type = HEVC_NAL_IDR_W_RADL; - vpic->pic_fields.bits.idr_pic_flag = 1; - vpic->pic_fields.bits.coding_type = 1; + vpic->pic_fields.bits.idr_pic_flag = 1; + vpic->pic_fields.bits.coding_type = 1; vpic->pic_fields.bits.reference_pic_flag = 1; break; case PICTURE_TYPE_I: - vpic->nal_unit_type = HEVC_NAL_TRAIL_R; - vpic->pic_fields.bits.idr_pic_flag = 0; - vpic->pic_fields.bits.coding_type = 1; + vpic->pic_fields.bits.idr_pic_flag = 0; + vpic->pic_fields.bits.coding_type = 1; vpic->pic_fields.bits.reference_pic_flag = 1; break; case PICTURE_TYPE_P: - vpic->nal_unit_type = HEVC_NAL_TRAIL_R; - vpic->pic_fields.bits.idr_pic_flag = 0; - vpic->pic_fields.bits.coding_type = 2; + vpic->pic_fields.bits.idr_pic_flag = 0; + vpic->pic_fields.bits.coding_type = 2; vpic->pic_fields.bits.reference_pic_flag = 1; break; case PICTURE_TYPE_B: - vpic->nal_unit_type = HEVC_NAL_TRAIL_R; - vpic->pic_fields.bits.idr_pic_flag = 0; - vpic->pic_fields.bits.coding_type = 3; + vpic->pic_fields.bits.idr_pic_flag = 0; + vpic->pic_fields.bits.coding_type = 3; vpic->pic_fields.bits.reference_pic_flag = 0; break; default: @@ -1034,90 +652,40 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, VAAPIEncodeSlice *slice) { VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = ctx->priv_data; + const H265RawSPS *sps = &priv->sps; + const H265RawPPS *pps = &priv->pps; + H265RawSliceHeader *sh = &priv->slice.header; VAEncPictureParameterBufferHEVC *vpic = pic->codec_picture_params; VAEncSliceParameterBufferHEVC *vslice = slice->codec_slice_params; - VAAPIEncodeH265Context *priv = ctx->priv_data; - VAAPIEncodeH265Slice *pslice; - VAAPIEncodeH265MiscSliceParams *mslice; int i; - slice->priv_data = av_mallocz(sizeof(*pslice)); - if (!slice->priv_data) - return AVERROR(ENOMEM); - pslice = slice->priv_data; - mslice = &pslice->misc_slice_params; - - // Currently we only support one slice per frame. - vslice->slice_segment_address = 0; - vslice->num_ctu_in_slice = priv->ctu_width * priv->ctu_height; - - switch (pic->type) { - case PICTURE_TYPE_IDR: - case PICTURE_TYPE_I: - vslice->slice_type = HEVC_SLICE_I; - break; - case PICTURE_TYPE_P: - vslice->slice_type = HEVC_SLICE_P; - break; - case PICTURE_TYPE_B: - vslice->slice_type = HEVC_SLICE_B; - break; - default: - av_assert0(0 && "invalid picture type"); - } - - vslice->slice_pic_parameter_set_id = vpic->slice_pic_parameter_set_id; - - pslice->pic_order_cnt = pic->display_order - priv->last_idr_frame; - - for (i = 0; i < FF_ARRAY_ELEMS(vslice->ref_pic_list0); i++) { - vslice->ref_pic_list0[i].picture_id = VA_INVALID_ID; - vslice->ref_pic_list0[i].flags = VA_PICTURE_HEVC_INVALID; - vslice->ref_pic_list1[i].picture_id = VA_INVALID_ID; - vslice->ref_pic_list1[i].flags = VA_PICTURE_HEVC_INVALID; - } + sh->nal_unit_header = (H265RawNALUnitHeader) { + .nal_unit_type = priv->slice_nal_unit, + .nuh_layer_id = 0, + .nuh_temporal_id_plus1 = 1, + }; - av_assert0(pic->nb_refs <= 2); - if (pic->nb_refs >= 1) { - // Backward reference for P- or B-frame. - av_assert0(pic->type == PICTURE_TYPE_P || - pic->type == PICTURE_TYPE_B); + sh->slice_pic_parameter_set_id = pps->pps_pic_parameter_set_id; - vslice->num_ref_idx_l0_active_minus1 = 0; - vslice->ref_pic_list0[0] = vpic->reference_frames[0]; - } - if (pic->nb_refs >= 2) { - // Forward reference for B-frame. - av_assert0(pic->type == PICTURE_TYPE_B); - - vslice->num_ref_idx_l1_active_minus1 = 0; - vslice->ref_pic_list1[0] = vpic->reference_frames[1]; - } - - vslice->max_num_merge_cand = 5; - - if (pic->type == PICTURE_TYPE_B) - vslice->slice_qp_delta = priv->fixed_qp_b - vpic->pic_init_qp; - else if (pic->type == PICTURE_TYPE_P) - vslice->slice_qp_delta = priv->fixed_qp_p - vpic->pic_init_qp; - else - vslice->slice_qp_delta = priv->fixed_qp_idr - vpic->pic_init_qp; + // Currently we only support one slice per frame. + sh->first_slice_segment_in_pic_flag = 1; + sh->slice_segment_address = 0; - vslice->slice_fields.bits.last_slice_of_pic_flag = 1; + sh->slice_type = priv->slice_type; - mslice->first_slice_segment_in_pic_flag = 1; + sh->slice_pic_order_cnt_lsb = priv->pic_order_cnt & + (1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4)) - 1; - if (pic->type == PICTURE_TYPE_IDR) { - // No reference pictures. - } else if (0) { - mslice->short_term_ref_pic_set_sps_flag = 1; - mslice->short_term_ref_pic_idx = 0; - } else { + if (pic->type != PICTURE_TYPE_IDR) { + H265RawSTRefPicSet *rps; VAAPIEncodePicture *st; int used; - mslice->short_term_ref_pic_set_sps_flag = 0; - mslice->st_ref_pic_set.inter_ref_pic_set_prediction_flag = 0; + sh->short_term_ref_pic_set_sps_flag = 0; + + rps = &sh->short_term_ref_pic_set; + memset(rps, 0, sizeof(*rps)); for (st = ctx->pic_start; st; st = st->next) { if (st->encode_order >= pic->encode_order) { @@ -1130,26 +698,126 @@ static int vaapi_encode_h265_init_slice_params(AVCodecContext *avctx, used = 1; } if (!used) { - // Currently true, but need not be. - continue; + // Usually each picture always uses all of the others in the + // DPB as references. The one case we have to treat here is + // a non-IDR IRAP picture, which may need to hold unused + // references across itself to be used for the decoding of + // following RASL pictures. This looks for such an RASL + // picture, and keeps the reference if there is one. + VAAPIEncodePicture *rp; + for (rp = ctx->pic_start; rp; rp = rp->next) { + if (rp->encode_order < pic->encode_order) + continue; + if (rp->type != PICTURE_TYPE_B) + continue; + if (rp->refs[0] == st && rp->refs[1] == pic) + break; + } + if (!rp) + continue; } // This only works for one instance of each (delta_poc_sN_minus1 // is relative to the previous frame in the list, not relative to // the current frame directly). if (st->display_order < pic->display_order) { - i = mslice->st_ref_pic_set.num_negative_pics; - mslice->st_ref_pic_set.delta_poc_s0_minus1[i] = + rps->delta_poc_s0_minus1[rps->num_negative_pics] = pic->display_order - st->display_order - 1; - mslice->st_ref_pic_set.used_by_curr_pic_s0_flag[i] = used; - ++mslice->st_ref_pic_set.num_negative_pics; + rps->used_by_curr_pic_s0_flag[rps->num_negative_pics] = used; + ++rps->num_negative_pics; } else { - i = mslice->st_ref_pic_set.num_positive_pics; - mslice->st_ref_pic_set.delta_poc_s1_minus1[i] = + rps->delta_poc_s1_minus1[rps->num_positive_pics] = st->display_order - pic->display_order - 1; - mslice->st_ref_pic_set.used_by_curr_pic_s1_flag[i] = used; - ++mslice->st_ref_pic_set.num_positive_pics; + rps->used_by_curr_pic_s1_flag[rps->num_positive_pics] = used; + ++rps->num_positive_pics; } } + + sh->num_long_term_sps = 0; + sh->num_long_term_pics = 0; + + sh->slice_temporal_mvp_enabled_flag = + sps->sps_temporal_mvp_enabled_flag; + if (sh->slice_temporal_mvp_enabled_flag) { + sh->collocated_from_l0_flag = sh->slice_type == HEVC_SLICE_B; + sh->collocated_ref_idx = 0; + } + + sh->num_ref_idx_active_override_flag = 0; + sh->num_ref_idx_l0_active_minus1 = pps->num_ref_idx_l0_default_active_minus1; + sh->num_ref_idx_l1_active_minus1 = pps->num_ref_idx_l1_default_active_minus1; + } + + sh->slice_sao_luma_flag = sh->slice_sao_chroma_flag = + sps->sample_adaptive_offset_enabled_flag; + + if (pic->type == PICTURE_TYPE_B) + sh->slice_qp_delta = priv->fixed_qp_b - (pps->init_qp_minus26 + 26); + else if (pic->type == PICTURE_TYPE_P) + sh->slice_qp_delta = priv->fixed_qp_p - (pps->init_qp_minus26 + 26); + else + sh->slice_qp_delta = priv->fixed_qp_idr - (pps->init_qp_minus26 + 26); + + + *vslice = (VAEncSliceParameterBufferHEVC) { + .slice_segment_address = sh->slice_segment_address, + .num_ctu_in_slice = priv->ctu_width * priv->ctu_height, + + .slice_type = sh->slice_type, + .slice_pic_parameter_set_id = sh->slice_pic_parameter_set_id, + + .num_ref_idx_l0_active_minus1 = sh->num_ref_idx_l0_active_minus1, + .num_ref_idx_l1_active_minus1 = sh->num_ref_idx_l1_active_minus1, + + .luma_log2_weight_denom = sh->luma_log2_weight_denom, + .delta_chroma_log2_weight_denom = sh->delta_chroma_log2_weight_denom, + + .max_num_merge_cand = 5 - sh->five_minus_max_num_merge_cand, + + .slice_qp_delta = sh->slice_qp_delta, + .slice_cb_qp_offset = sh->slice_cb_qp_offset, + .slice_cr_qp_offset = sh->slice_cr_qp_offset, + + .slice_beta_offset_div2 = sh->slice_beta_offset_div2, + .slice_tc_offset_div2 = sh->slice_tc_offset_div2, + + .slice_fields.bits = { + .last_slice_of_pic_flag = 1, + .dependent_slice_segment_flag = sh->dependent_slice_segment_flag, + .colour_plane_id = sh->colour_plane_id, + .slice_temporal_mvp_enabled_flag = + sh->slice_temporal_mvp_enabled_flag, + .slice_sao_luma_flag = sh->slice_sao_luma_flag, + .slice_sao_chroma_flag = sh->slice_sao_chroma_flag, + .num_ref_idx_active_override_flag = + sh->num_ref_idx_active_override_flag, + .mvd_l1_zero_flag = sh->mvd_l1_zero_flag, + .cabac_init_flag = sh->cabac_init_flag, + .slice_deblocking_filter_disabled_flag = + sh->slice_deblocking_filter_disabled_flag, + .slice_loop_filter_across_slices_enabled_flag = + sh->slice_loop_filter_across_slices_enabled_flag, + .collocated_from_l0_flag = sh->collocated_from_l0_flag, + }, + }; + + for (i = 0; i < FF_ARRAY_ELEMS(vslice->ref_pic_list0); i++) { + vslice->ref_pic_list0[i].picture_id = VA_INVALID_ID; + vslice->ref_pic_list0[i].flags = VA_PICTURE_HEVC_INVALID; + vslice->ref_pic_list1[i].picture_id = VA_INVALID_ID; + vslice->ref_pic_list1[i].flags = VA_PICTURE_HEVC_INVALID; + } + + av_assert0(pic->nb_refs <= 2); + if (pic->nb_refs >= 1) { + // Backward reference for P- or B-frame. + av_assert0(pic->type == PICTURE_TYPE_P || + pic->type == PICTURE_TYPE_B); + vslice->ref_pic_list0[0] = vpic->reference_frames[0]; + } + if (pic->nb_refs >= 2) { + // Forward reference for B-frame. + av_assert0(pic->type == PICTURE_TYPE_B); + vslice->ref_pic_list1[0] = vpic->reference_frames[1]; } return 0; @@ -1160,6 +828,11 @@ static av_cold int vaapi_encode_h265_configure(AVCodecContext *avctx) VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeH265Context *priv = ctx->priv_data; VAAPIEncodeH265Options *opt = ctx->codec_options; + int err; + + err = ff_cbs_init(&priv->cbc, AV_CODEC_ID_HEVC, avctx); + if (err < 0) + return err; priv->ctu_width = FFALIGN(ctx->surface_width, 32) / 32; priv->ctu_height = FFALIGN(ctx->surface_height, 32) / 32; @@ -1226,10 +899,17 @@ static const VAAPIEncodeType vaapi_encode_type_h265 = { static av_cold int vaapi_encode_h265_init(AVCodecContext *avctx) { - VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Options *opt = + (VAAPIEncodeH265Options*)ctx->codec_options_data; ctx->codec = &vaapi_encode_type_h265; + if (avctx->profile == FF_PROFILE_UNKNOWN) + avctx->profile = opt->profile; + if (avctx->level == FF_LEVEL_UNKNOWN) + avctx->level = opt->level; + switch (avctx->profile) { case FF_PROFILE_HEVC_MAIN: case FF_PROFILE_UNKNOWN: @@ -1271,18 +951,62 @@ static av_cold int vaapi_encode_h265_init(AVCodecContext *avctx) return ff_vaapi_encode_init(avctx); } +static av_cold int vaapi_encode_h265_close(AVCodecContext *avctx) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeH265Context *priv = ctx->priv_data; + + if (priv) + ff_cbs_close(&priv->cbc); + + return ff_vaapi_encode_close(avctx); +} + #define OFFSET(x) (offsetof(VAAPIEncodeContext, codec_options_data) + \ offsetof(VAAPIEncodeH265Options, x)) #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM) static const AVOption vaapi_encode_h265_options[] = { { "qp", "Constant QP (for P-frames; scaled by qfactor/qoffset for I/B)", OFFSET(qp), AV_OPT_TYPE_INT, { .i64 = 25 }, 0, 52, FLAGS }, + + { "aud", "Include AUD", + OFFSET(aud), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS }, + + { "profile", "Set profile (general_profile_idc)", + OFFSET(profile), AV_OPT_TYPE_INT, + { .i64 = FF_PROFILE_HEVC_MAIN }, 0x00, 0xff, FLAGS, "profile" }, + +#define PROFILE(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = value }, 0, 0, FLAGS, "profile" + { PROFILE("main", FF_PROFILE_HEVC_MAIN) }, + { PROFILE("main10", FF_PROFILE_HEVC_MAIN_10) }, +#undef PROFILE + + { "level", "Set level (general_level_idc)", + OFFSET(level), AV_OPT_TYPE_INT, + { .i64 = 153 }, 0x00, 0xff, FLAGS, "level" }, + +#define LEVEL(name, value) name, NULL, 0, AV_OPT_TYPE_CONST, \ + { .i64 = value }, 0, 0, FLAGS, "level" + { LEVEL("1", 30) }, + { LEVEL("2", 60) }, + { LEVEL("2.1", 63) }, + { LEVEL("3", 90) }, + { LEVEL("3.1", 93) }, + { LEVEL("4", 120) }, + { LEVEL("4.1", 123) }, + { LEVEL("5", 150) }, + { LEVEL("5.1", 153) }, + { LEVEL("5.2", 156) }, + { LEVEL("6", 180) }, + { LEVEL("6.1", 183) }, + { LEVEL("6.2", 186) }, +#undef LEVEL + { NULL }, }; static const AVCodecDefault vaapi_encode_h265_defaults[] = { - { "profile", "1" }, - { "level", "51" }, { "b", "0" }, { "bf", "2" }, { "g", "120" }, @@ -1309,12 +1033,13 @@ AVCodec ff_hevc_vaapi_encoder = { sizeof(VAAPIEncodeH265Options)), .init = &vaapi_encode_h265_init, .encode2 = &ff_vaapi_encode2, - .close = &ff_vaapi_encode_close, + .close = &vaapi_encode_h265_close, .priv_class = &vaapi_encode_h265_class, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .defaults = vaapi_encode_h265_defaults, .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE, }, + .wrapper_name = "vaapi", }; diff --git a/libavcodec/vaapi_encode_h26x.c b/libavcodec/vaapi_encode_h26x.c deleted file mode 100644 index d806f9b52b354..0000000000000 --- a/libavcodec/vaapi_encode_h26x.c +++ /dev/null @@ -1,68 +0,0 @@ -/* - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include - -#include "vaapi_encode_h26x.h" - -int ff_vaapi_encode_h26x_nal_unit_to_byte_stream(uint8_t *dst, size_t *dst_bit_len, - uint8_t *src, size_t src_bit_len) -{ - size_t dp, sp; - int zero_run = 0; - size_t dst_len = *dst_bit_len / 8; - size_t src_len = (src_bit_len + 7) / 8; - int trailing_zeroes = src_len * 8 - src_bit_len; - - if (dst_len < src_len + 4) { - // Definitely doesn't fit. - goto fail; - } - - // Start code. - dst[0] = dst[1] = dst[2] = 0; - dst[3] = 1; - dp = 4; - - for (sp = 0; sp < src_len; sp++) { - if (dp >= dst_len) - goto fail; - if (zero_run < 2) { - if (src[sp] == 0) - ++zero_run; - else - zero_run = 0; - } else { - if ((src[sp] & ~3) == 0) { - // emulation_prevention_three_byte - dst[dp++] = 3; - if (dp >= dst_len) - goto fail; - } - zero_run = src[sp] == 0; - } - dst[dp++] = src[sp]; - } - - *dst_bit_len = 8 * dp - trailing_zeroes; - return 0; - -fail: - *dst_bit_len = 0; - return AVERROR(ENOSPC); -} diff --git a/libavcodec/vaapi_encode_h26x.h b/libavcodec/vaapi_encode_h26x.h deleted file mode 100644 index f8c6e13adb9b4..0000000000000 --- a/libavcodec/vaapi_encode_h26x.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVCODEC_VAAPI_ENCODE_H26X_H -#define AVCODEC_VAAPI_ENCODE_H26X_H - -#include -#include - -#include "golomb.h" -#include "put_bits.h" - - -// Debug code may be interested in the name of the syntax element being -// for tracing purposes. Here, it is just discarded. - -#define write_u(pbc, width, value, name) put_bits(pbc, width, value) -#define write_ue(pbc, value, name) set_ue_golomb(pbc, value) -#define write_se(pbc, value, name) set_se_golomb(pbc, value) - -#define u(width, ...) write_u(pbc, width, __VA_ARGS__) -#define ue(...) write_ue(pbc, __VA_ARGS__) -#define se(...) write_se(pbc, __VA_ARGS__) - - -// Copy from src to dst, applying emulation prevention. -int ff_vaapi_encode_h26x_nal_unit_to_byte_stream(uint8_t *dst, size_t *dst_len, - uint8_t *src, size_t src_len); - -#endif /* AVCODEC_VAAPI_ENCODE_H26X_H */ diff --git a/libavcodec/vaapi_encode_mjpeg.c b/libavcodec/vaapi_encode_mjpeg.c index 2cbf7925f248f..c949e89646110 100644 --- a/libavcodec/vaapi_encode_mjpeg.c +++ b/libavcodec/vaapi_encode_mjpeg.c @@ -422,9 +422,11 @@ AVCodec ff_mjpeg_vaapi_encoder = { .encode2 = &ff_vaapi_encode2, .close = &ff_vaapi_encode_close, .priv_class = &vaapi_encode_mjpeg_class, + .capabilities = AV_CODEC_CAP_HARDWARE, .defaults = vaapi_encode_mjpeg_defaults, .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE, }, + .wrapper_name = "vaapi", }; diff --git a/libavcodec/vaapi_encode_mpeg2.c b/libavcodec/vaapi_encode_mpeg2.c index dc918884e89cc..42df77ea498ad 100644 --- a/libavcodec/vaapi_encode_mpeg2.c +++ b/libavcodec/vaapi_encode_mpeg2.c @@ -20,15 +20,11 @@ #include #include "libavutil/avassert.h" -#include "libavutil/common.h" -#include "libavutil/internal.h" -#include "libavutil/opt.h" -#include "libavutil/pixfmt.h" #include "avcodec.h" -#include "internal.h" -#include "mpegvideo.h" -#include "put_bits.h" +#include "cbs.h" +#include "cbs_mpeg2.h" +#include "mpeg12.h" #include "vaapi_encode.h" typedef struct VAAPIEncodeMPEG2Context { @@ -39,79 +35,104 @@ typedef struct VAAPIEncodeMPEG2Context { int quant_p; int quant_b; + MPEG2RawSequenceHeader sequence_header; + MPEG2RawExtensionData sequence_extension; + MPEG2RawExtensionData sequence_display_extension; + MPEG2RawGroupOfPicturesHeader gop_header; + MPEG2RawPictureHeader picture_header; + MPEG2RawExtensionData picture_coding_extension; + int64_t last_i_frame; unsigned int bit_rate; unsigned int vbv_buffer_size; + + AVRational frame_rate; + + unsigned int f_code_horizontal; + unsigned int f_code_vertical; + + CodedBitstreamContext *cbc; + CodedBitstreamFragment current_fragment; } VAAPIEncodeMPEG2Context; -#define vseq_var(name) vseq->name, name -#define vseqext_field(name) vseq->sequence_extension.bits.name, name -#define vgop_field(name) vseq->gop_header.bits.name, name -#define vpic_var(name) vpic->name, name -#define vpcext_field(name) vpic->picture_coding_extension.bits.name, name -#define vcomp_field(name) vpic->composite_display.bits.name, name +static int vaapi_encode_mpeg2_write_fragment(AVCodecContext *avctx, + char *data, size_t *data_len, + CodedBitstreamFragment *frag) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + int err; + + err = ff_cbs_write_fragment_data(priv->cbc, frag); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to write packed header.\n"); + return err; + } + + if (*data_len < 8 * frag->data_size - frag->data_bit_padding) { + av_log(avctx, AV_LOG_ERROR, "Access unit too large: " + "%zu < %zu.\n", *data_len, + 8 * frag->data_size - frag->data_bit_padding); + return AVERROR(ENOSPC); + } + + memcpy(data, frag->data, frag->data_size); + *data_len = 8 * frag->data_size - frag->data_bit_padding; + + return 0; +} + +static int vaapi_encode_mpeg2_add_header(AVCodecContext *avctx, + CodedBitstreamFragment *frag, + int type, void *header) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + int err; + + err = ff_cbs_insert_unit_content(priv->cbc, frag, -1, type, header, NULL); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to add header: " + "type = %d.\n", type); + return err; + } -#define u2(width, value, name) put_bits(&pbc, width, value) -#define u(width, ...) u2(width, __VA_ARGS__) + return 0; +} static int vaapi_encode_mpeg2_write_sequence_header(AVCodecContext *avctx, char *data, size_t *data_len) { - VAAPIEncodeContext *ctx = avctx->priv_data; - VAEncSequenceParameterBufferMPEG2 *vseq = ctx->codec_sequence_params; - VAAPIEncodeMPEG2Context *priv = ctx->priv_data; - PutBitContext pbc; - - init_put_bits(&pbc, data, 8 * *data_len); - - u(32, SEQ_START_CODE, sequence_header_code); - - u(12, vseq->picture_width, horizontal_size_value); - u(12, vseq->picture_height, vertical_size_value); - u(4, vseq_var(aspect_ratio_information)); - u(4, 8, frame_rate_code); - u(18, priv->bit_rate & 0x3fff, bit_rate_value); - u(1, 1, marker_bit); - u(10, priv->vbv_buffer_size & 0x3ff, vbv_buffer_size_value); - u(1, 0, constrained_parameters_flag); - u(1, 0, load_intra_quantiser_matrix); - // intra_quantiser_matrix[64] - u(1, 0, load_non_intra_quantiser_matrix); - // non_intra_quantiser_matrix[64] - - while (put_bits_count(&pbc) % 8) - u(1, 0, zero_bit); - - u(32, EXT_START_CODE, extension_start_code); - u(4, 1, extension_start_code_identifier); - u(8, vseqext_field(profile_and_level_indication)); - u(1, vseqext_field(progressive_sequence)); - u(2, vseqext_field(chroma_format)); - u(2, 0, horizontal_size_extension); - u(2, 0, vertical_size_extension); - u(12, priv->bit_rate >> 18, bit_rate_extension); - u(1, 1, marker_bit); - u(8, priv->vbv_buffer_size >> 10, vbv_buffer_size_extension); - u(1, vseqext_field(low_delay)); - u(2, vseqext_field(frame_rate_extension_n)); - u(2, vseqext_field(frame_rate_extension_d)); - - while (put_bits_count(&pbc) % 8) - u(1, 0, zero_bit); - - u(32, GOP_START_CODE, group_start_code); - u(25, vgop_field(time_code)); - u(1, vgop_field(closed_gop)); - u(1, vgop_field(broken_link)); - - while (put_bits_count(&pbc) % 8) - u(1, 0, zero_bit); - - *data_len = put_bits_count(&pbc); - flush_put_bits(&pbc); - + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + CodedBitstreamFragment *frag = &priv->current_fragment; + int err; + + err = vaapi_encode_mpeg2_add_header(avctx, frag, MPEG2_START_SEQUENCE_HEADER, + &priv->sequence_header); + if (err < 0) + goto fail; + + err = vaapi_encode_mpeg2_add_header(avctx, frag, MPEG2_START_EXTENSION, + &priv->sequence_extension); + if (err < 0) + goto fail; + + err = vaapi_encode_mpeg2_add_header(avctx, frag, MPEG2_START_EXTENSION, + &priv->sequence_display_extension); + if (err < 0) + goto fail; + + err = vaapi_encode_mpeg2_add_header(avctx, frag, MPEG2_START_GROUP, + &priv->gop_header); + if (err < 0) + goto fail; + + err = vaapi_encode_mpeg2_write_fragment(avctx, data, data_len, frag); +fail: + ff_cbs_fragment_uninit(priv->cbc, frag); return 0; } @@ -119,139 +140,275 @@ static int vaapi_encode_mpeg2_write_picture_header(AVCodecContext *avctx, VAAPIEncodePicture *pic, char *data, size_t *data_len) { - VAEncPictureParameterBufferMPEG2 *vpic = pic->codec_picture_params; - int picture_coding_type; - PutBitContext pbc; + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + CodedBitstreamFragment *frag = &priv->current_fragment; + int err; + + err = vaapi_encode_mpeg2_add_header(avctx, frag, MPEG2_START_PICTURE, + &priv->picture_header); + if (err < 0) + goto fail; + + err = vaapi_encode_mpeg2_add_header(avctx, frag, MPEG2_START_EXTENSION, + &priv->picture_coding_extension); + if (err < 0) + goto fail; + + err = vaapi_encode_mpeg2_write_fragment(avctx, data, data_len, frag); +fail: + ff_cbs_fragment_uninit(priv->cbc, frag); + return 0; +} - init_put_bits(&pbc, data, 8 * *data_len); +static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + MPEG2RawSequenceHeader *sh = &priv->sequence_header; + MPEG2RawSequenceExtension *se = &priv->sequence_extension.data.sequence; + MPEG2RawSequenceDisplayExtension *sde = &priv->sequence_display_extension.data.sequence_display; + MPEG2RawGroupOfPicturesHeader *goph = &priv->gop_header; + MPEG2RawPictureHeader *ph = &priv->picture_header; + MPEG2RawPictureCodingExtension *pce = &priv->picture_coding_extension.data.picture_coding; + VAEncSequenceParameterBufferMPEG2 *vseq = ctx->codec_sequence_params; + VAEncPictureParameterBufferMPEG2 *vpic = ctx->codec_picture_params; + int code, ext_n, ext_d; - u(32, PICTURE_START_CODE, picture_start_code); - u(10, vpic_var(temporal_reference)); + memset(sh, 0, sizeof(*sh)); + memset(se, 0, sizeof(*se)); + memset(sde, 0, sizeof(*sde)); + memset(goph, 0, sizeof(*goph)); + memset(ph, 0, sizeof(*ph)); + memset(pce, 0, sizeof(*pce)); - switch (vpic->picture_type) { - case VAEncPictureTypeIntra: - picture_coding_type = AV_PICTURE_TYPE_I; - break; - case VAEncPictureTypePredictive: - picture_coding_type = AV_PICTURE_TYPE_P; + + if (avctx->bit_rate > 0) { + priv->bit_rate = (avctx->bit_rate + 399) / 400; + } else { + // Unknown (not a bitrate-targetting mode), so just use the + // highest value. + priv->bit_rate = 0x3fffffff; + } + if (avctx->rc_buffer_size > 0) { + priv->vbv_buffer_size = (avctx->rc_buffer_size + (1 << 14) - 1) >> 14; + } else { + // Unknown, so guess a value from the bitrate. + priv->vbv_buffer_size = priv->bit_rate >> 14; + } + + switch (avctx->level) { + case 4: // High. + case 6: // High 1440. + priv->f_code_horizontal = 9; + priv->f_code_vertical = 5; break; - case VAEncPictureTypeBidirectional: - picture_coding_type = AV_PICTURE_TYPE_B; + case 8: // Main. + priv->f_code_horizontal = 8; + priv->f_code_vertical = 5; break; + case 10: // Low. default: - av_assert0(0 && "invalid picture_coding_type"); - } - u(3, picture_coding_type, picture_coding_type); - u(16, 0xffff, vbv_delay); - if (picture_coding_type == 2 || picture_coding_type == 3) { - u(1, 0, full_pel_forward_vector); - u(3, 7, forward_f_code); - } - if (picture_coding_type == 3) { - u(1, 0, full_pel_backward_vector); - u(3, 7, backward_f_code); + priv->f_code_horizontal = 7; + priv->f_code_vertical = 4; + break; } - u(1, 0, extra_bit_picture); - - while (put_bits_count(&pbc) % 8) - u(1, 0, zero_bit); - - u(32, EXT_START_CODE, extension_start_code); - u(4, 8, extension_start_code_identifier); - u(4, vpic_var(f_code[0][0])); - u(4, vpic_var(f_code[0][1])); - u(4, vpic_var(f_code[1][0])); - u(4, vpic_var(f_code[1][1])); - u(2, vpcext_field(intra_dc_precision)); - u(2, vpcext_field(picture_structure)); - u(1, vpcext_field(top_field_first)); - u(1, vpcext_field(frame_pred_frame_dct)); - u(1, vpcext_field(concealment_motion_vectors)); - u(1, vpcext_field(q_scale_type)); - u(1, vpcext_field(intra_vlc_format)); - u(1, vpcext_field(alternate_scan)); - u(1, vpcext_field(repeat_first_field)); - u(1, 1, chroma_420_type); - u(1, vpcext_field(progressive_frame)); - u(1, vpcext_field(composite_display_flag)); - if (vpic->picture_coding_extension.bits.composite_display_flag) { - u(1, vcomp_field(v_axis)); - u(3, vcomp_field(field_sequence)); - u(1, vcomp_field(sub_carrier)); - u(7, vcomp_field(burst_amplitude)); - u(8, vcomp_field(sub_carrier_phase)); + + + // Sequence header + + sh->sequence_header_code = MPEG2_START_SEQUENCE_HEADER; + + sh->horizontal_size_value = avctx->width & 0xfff; + sh->vertical_size_value = avctx->height & 0xfff; + + if (avctx->sample_aspect_ratio.num != 0 && + avctx->sample_aspect_ratio.den != 0) { + AVRational dar = av_div_q(avctx->sample_aspect_ratio, + (AVRational) { avctx->width, avctx->height }); + + if (av_cmp_q(avctx->sample_aspect_ratio, (AVRational) { 1, 1 }) == 0) { + sh->aspect_ratio_information = 1; + } else if (av_cmp_q(dar, (AVRational) { 3, 4 }) == 0) { + sh->aspect_ratio_information = 2; + } else if (av_cmp_q(dar, (AVRational) { 9, 16 }) == 0) { + sh->aspect_ratio_information = 3; + } else if (av_cmp_q(dar, (AVRational) { 100, 221 }) == 0) { + sh->aspect_ratio_information = 4; + } else { + av_log(avctx, AV_LOG_WARNING, "Sample aspect ratio %d:%d is not " + "representable, signalling square pixels instead.\n", + avctx->sample_aspect_ratio.num, + avctx->sample_aspect_ratio.den); + sh->aspect_ratio_information = 1; + } + } else { + // Unknown - assume square pixels. + sh->aspect_ratio_information = 1; } - while (put_bits_count(&pbc) % 8) - u(1, 0, zero_bit); + if (avctx->framerate.num > 0 && avctx->framerate.den > 0) + priv->frame_rate = avctx->framerate; + else + priv->frame_rate = av_inv_q(avctx->time_base); + ff_mpeg12_find_best_frame_rate(priv->frame_rate, + &code, &ext_n, &ext_d, 0); + sh->frame_rate_code = code; - *data_len = put_bits_count(&pbc); - flush_put_bits(&pbc); + sh->bit_rate_value = priv->bit_rate & 0x3ffff; + sh->vbv_buffer_size_value = priv->vbv_buffer_size & 0x3ff; - return 0; -} + sh->constrained_parameters_flag = 0; + sh->load_intra_quantiser_matrix = 0; + sh->load_non_intra_quantiser_matrix = 0; -static int vaapi_encode_mpeg2_init_sequence_params(AVCodecContext *avctx) -{ - VAAPIEncodeContext *ctx = avctx->priv_data; - VAEncSequenceParameterBufferMPEG2 *vseq = ctx->codec_sequence_params; - VAEncPictureParameterBufferMPEG2 *vpic = ctx->codec_picture_params; - VAAPIEncodeMPEG2Context *priv = ctx->priv_data; - vseq->intra_period = avctx->gop_size; - vseq->ip_period = ctx->b_per_p + 1; + // Sequence extension - vseq->picture_width = avctx->width; - vseq->picture_height = avctx->height; + priv->sequence_extension.extension_start_code = MPEG2_START_EXTENSION; + priv->sequence_extension.extension_start_code_identifier = + MPEG2_EXTENSION_SEQUENCE; - vseq->bits_per_second = avctx->bit_rate; - if (avctx->framerate.num > 0 && avctx->framerate.den > 0) - vseq->frame_rate = (float)avctx->framerate.num / avctx->framerate.den; - else - vseq->frame_rate = (float)avctx->time_base.den / avctx->time_base.num; - - vseq->aspect_ratio_information = 1; - vseq->vbv_buffer_size = avctx->rc_buffer_size / (16 * 1024); - - vseq->sequence_extension.bits.profile_and_level_indication = - avctx->profile << 4 | avctx->level; - vseq->sequence_extension.bits.progressive_sequence = 1; - vseq->sequence_extension.bits.chroma_format = 1; - vseq->sequence_extension.bits.low_delay = 0; - vseq->sequence_extension.bits.frame_rate_extension_n = 0; - vseq->sequence_extension.bits.frame_rate_extension_d = 0; - - vseq->new_gop_header = 0; - vseq->gop_header.bits.time_code = 0; - vseq->gop_header.bits.closed_gop = 1; - vseq->gop_header.bits.broken_link = 0; - - vpic->forward_reference_picture = VA_INVALID_ID; - vpic->backward_reference_picture = VA_INVALID_ID; - vpic->reconstructed_picture = VA_INVALID_ID; - - vpic->coded_buf = VA_INVALID_ID; - - vpic->temporal_reference = 0; - vpic->f_code[0][0] = 15; - vpic->f_code[0][1] = 15; - vpic->f_code[1][0] = 15; - vpic->f_code[1][1] = 15; - - vpic->picture_coding_extension.bits.intra_dc_precision = 0; - vpic->picture_coding_extension.bits.picture_structure = 3; - vpic->picture_coding_extension.bits.top_field_first = 0; - vpic->picture_coding_extension.bits.frame_pred_frame_dct = 1; - vpic->picture_coding_extension.bits.concealment_motion_vectors = 0; - vpic->picture_coding_extension.bits.q_scale_type = 0; - vpic->picture_coding_extension.bits.intra_vlc_format = 0; - vpic->picture_coding_extension.bits.alternate_scan = 0; - vpic->picture_coding_extension.bits.repeat_first_field = 0; - vpic->picture_coding_extension.bits.progressive_frame = 1; - vpic->picture_coding_extension.bits.composite_display_flag = 0; - - priv->bit_rate = (avctx->bit_rate + 399) / 400; - priv->vbv_buffer_size = avctx->rc_buffer_size / (16 * 1024); + se->profile_and_level_indication = avctx->profile << 4 | avctx->level; + se->progressive_sequence = 1; + se->chroma_format = 1; + + se->horizontal_size_extension = avctx->width >> 12; + se->vertical_size_extension = avctx->height >> 12; + + se->bit_rate_extension = priv->bit_rate >> 18; + se->vbv_buffer_size_extension = priv->vbv_buffer_size >> 10; + se->low_delay = ctx->b_per_p == 0; + + se->frame_rate_extension_n = ext_n; + se->frame_rate_extension_d = ext_d; + + + // Sequence display extension + + priv->sequence_display_extension.extension_start_code = + MPEG2_START_EXTENSION; + priv->sequence_display_extension.extension_start_code_identifier = + MPEG2_EXTENSION_SEQUENCE_DISPLAY; + + sde->video_format = 5; + if (avctx->color_primaries != AVCOL_PRI_UNSPECIFIED || + avctx->color_trc != AVCOL_TRC_UNSPECIFIED || + avctx->colorspace != AVCOL_SPC_UNSPECIFIED) { + sde->colour_description = 1; + sde->colour_primaries = avctx->color_primaries; + sde->transfer_characteristics = avctx->color_trc; + sde->matrix_coefficients = avctx->colorspace; + } else { + sde->colour_description = 0; + } + + sde->display_horizontal_size = avctx->width; + sde->display_vertical_size = avctx->height; + + + // GOP header + + goph->group_start_code = MPEG2_START_GROUP; + + goph->time_code = 0; + goph->closed_gop = 1; + goph->broken_link = 0; + + + // Defaults for picture header + + ph->picture_start_code = MPEG2_START_PICTURE; + + ph->vbv_delay = 0xffff; // Not currently calculated. + + ph->full_pel_forward_vector = 0; + ph->forward_f_code = 7; + ph->full_pel_backward_vector = 0; + ph->forward_f_code = 7; + + + // Defaults for picture coding extension + + priv->picture_coding_extension.extension_start_code = + MPEG2_START_EXTENSION; + priv->picture_coding_extension.extension_start_code_identifier = + MPEG2_EXTENSION_PICTURE_CODING; + + pce->intra_dc_precision = 0; + pce->picture_structure = 3; + pce->top_field_first = 0; + pce->frame_pred_frame_dct = 1; + pce->concealment_motion_vectors = 0; + pce->q_scale_type = 0; + pce->intra_vlc_format = 0; + pce->alternate_scan = 0; + pce->repeat_first_field = 0; + pce->progressive_frame = 1; + pce->composite_display_flag = 0; + + + + *vseq = (VAEncSequenceParameterBufferMPEG2) { + .intra_period = avctx->gop_size, + .ip_period = ctx->b_per_p + 1, + + .picture_width = avctx->width, + .picture_height = avctx->height, + + .bits_per_second = avctx->bit_rate, + .frame_rate = av_q2d(priv->frame_rate), + .aspect_ratio_information = sh->aspect_ratio_information, + .vbv_buffer_size = priv->vbv_buffer_size, + + .sequence_extension.bits = { + .profile_and_level_indication = se->profile_and_level_indication, + .progressive_sequence = se->progressive_sequence, + .chroma_format = se->chroma_format, + .low_delay = se->low_delay, + .frame_rate_extension_n = se->frame_rate_extension_n, + .frame_rate_extension_d = se->frame_rate_extension_d, + }, + + .new_gop_header = 1, + .gop_header.bits = { + .time_code = goph->time_code, + .closed_gop = goph->closed_gop, + .broken_link = goph->broken_link, + }, + }; + + *vpic = (VAEncPictureParameterBufferMPEG2) { + .forward_reference_picture = VA_INVALID_ID, + .backward_reference_picture = VA_INVALID_ID, + .reconstructed_picture = VA_INVALID_ID, + .coded_buf = VA_INVALID_ID, + + .vbv_delay = 0xffff, + .f_code = { { 15, 15 }, { 15, 15 } }, + + .picture_coding_extension.bits = { + .intra_dc_precision = pce->intra_dc_precision, + .picture_structure = pce->picture_structure, + .top_field_first = pce->top_field_first, + .frame_pred_frame_dct = pce->frame_pred_frame_dct, + .concealment_motion_vectors = pce->concealment_motion_vectors, + .q_scale_type = pce->q_scale_type, + .intra_vlc_format = pce->intra_vlc_format, + .alternate_scan = pce->alternate_scan, + .repeat_first_field = pce->repeat_first_field, + .progressive_frame = pce->progressive_frame, + .composite_display_flag = pce->composite_display_flag, + }, + + .composite_display.bits = { + .v_axis = pce->v_axis, + .field_sequence = pce->field_sequence, + .sub_carrier = pce->sub_carrier, + .burst_amplitude = pce->burst_amplitude, + .sub_carrier_phase = pce->sub_carrier_phase, + }, + }; return 0; } @@ -260,56 +417,61 @@ static int vaapi_encode_mpeg2_init_picture_params(AVCodecContext *avctx, VAAPIEncodePicture *pic) { VAAPIEncodeContext *ctx = avctx->priv_data; - VAEncPictureParameterBufferMPEG2 *vpic = pic->codec_picture_params; VAAPIEncodeMPEG2Context *priv = ctx->priv_data; - int fch, fcv; + MPEG2RawPictureHeader *ph = &priv->picture_header; + MPEG2RawPictureCodingExtension *pce = &priv->picture_coding_extension.data.picture_coding; + VAEncPictureParameterBufferMPEG2 *vpic = pic->codec_picture_params; - switch (avctx->level) { - case 4: // High. - case 6: // High 1440. - fch = 9; - fcv = 5; - break; - case 8: // Main. - fch = 8; - fcv = 5; - break; - case 10: // Low. - default: - fch = 7; - fcv = 4; - break; + if (pic->type == PICTURE_TYPE_IDR || pic->type == PICTURE_TYPE_I) { + ph->temporal_reference = 0; + ph->picture_coding_type = 1; + priv->last_i_frame = pic->display_order; + } else { + ph->temporal_reference = pic->display_order - priv->last_i_frame; + ph->picture_coding_type = pic->type == PICTURE_TYPE_B ? 3 : 2; + } + + if (pic->type == PICTURE_TYPE_P || pic->type == PICTURE_TYPE_B) { + pce->f_code[0][0] = priv->f_code_horizontal; + pce->f_code[0][1] = priv->f_code_vertical; + } else { + pce->f_code[0][0] = 15; + pce->f_code[0][1] = 15; + } + if (pic->type == PICTURE_TYPE_B) { + pce->f_code[1][0] = priv->f_code_horizontal; + pce->f_code[1][1] = priv->f_code_vertical; + } else { + pce->f_code[1][0] = 15; + pce->f_code[1][1] = 15; } + vpic->reconstructed_picture = pic->recon_surface; + vpic->coded_buf = pic->output_buffer; + switch (pic->type) { case PICTURE_TYPE_IDR: case PICTURE_TYPE_I: vpic->picture_type = VAEncPictureTypeIntra; - priv->last_i_frame = pic->display_order; break; case PICTURE_TYPE_P: vpic->picture_type = VAEncPictureTypePredictive; vpic->forward_reference_picture = pic->refs[0]->recon_surface; - vpic->f_code[0][0] = fch; - vpic->f_code[0][1] = fcv; break; case PICTURE_TYPE_B: vpic->picture_type = VAEncPictureTypeBidirectional; vpic->forward_reference_picture = pic->refs[0]->recon_surface; vpic->backward_reference_picture = pic->refs[1]->recon_surface; - vpic->f_code[0][0] = fch; - vpic->f_code[0][1] = fcv; - vpic->f_code[1][0] = fch; - vpic->f_code[1][1] = fcv; break; default: av_assert0(0 && "invalid picture type"); } - vpic->reconstructed_picture = pic->recon_surface; - vpic->coded_buf = pic->output_buffer; - - vpic->temporal_reference = pic->display_order - priv->last_i_frame; + vpic->temporal_reference = ph->temporal_reference; + vpic->f_code[0][0] = pce->f_code[0][0]; + vpic->f_code[0][1] = pce->f_code[0][1]; + vpic->f_code[1][0] = pce->f_code[1][0]; + vpic->f_code[1][1] = pce->f_code[1][1]; pic->nb_slices = priv->mb_height; @@ -354,6 +516,11 @@ static av_cold int vaapi_encode_mpeg2_configure(AVCodecContext *avctx) { VAAPIEncodeContext *ctx = avctx->priv_data; VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + int err; + + err = ff_cbs_init(&priv->cbc, AV_CODEC_ID_MPEG2VIDEO, avctx); + if (err < 0) + return err; priv->mb_width = FFALIGN(avctx->width, 16) / 16; priv->mb_height = FFALIGN(avctx->height, 16) / 16; @@ -420,11 +587,41 @@ static av_cold int vaapi_encode_mpeg2_init(AVCodecContext *avctx) case FF_PROFILE_MPEG2_MAIN: ctx->va_profile = VAProfileMPEG2Main; break; + case FF_PROFILE_MPEG2_422: + av_log(avctx, AV_LOG_ERROR, "MPEG-2 4:2:2 profile " + "is not supported.\n"); + return AVERROR_PATCHWELCOME; + case FF_PROFILE_MPEG2_HIGH: + av_log(avctx, AV_LOG_ERROR, "MPEG-2 high profile " + "is not supported.\n"); + return AVERROR_PATCHWELCOME; + case FF_PROFILE_MPEG2_SS: + case FF_PROFILE_MPEG2_SNR_SCALABLE: + av_log(avctx, AV_LOG_ERROR, "MPEG-2 scalable profiles " + "are not supported.\n"); + return AVERROR_PATCHWELCOME; default: av_log(avctx, AV_LOG_ERROR, "Unknown MPEG-2 profile %d.\n", avctx->profile); return AVERROR(EINVAL); } + switch (avctx->level) { + case 4: // High + case 6: // High 1440 + case 8: // Main + case 10: // Low + break; + default: + av_log(avctx, AV_LOG_ERROR, "Unknown MPEG-2 level %d.\n", + avctx->level); + return AVERROR(EINVAL); + } + + if (avctx->height % 4096 == 0 || avctx->width % 4096 == 0) { + av_log(avctx, AV_LOG_ERROR, "MPEG-2 does not support picture " + "height or width divisible by 4096.\n"); + return AVERROR(EINVAL); + } ctx->va_entrypoint = VAEntrypointEncSlice; ctx->va_rt_format = VA_RT_FORMAT_YUV420; @@ -439,6 +636,17 @@ static av_cold int vaapi_encode_mpeg2_init(AVCodecContext *avctx) return ff_vaapi_encode_init(avctx); } +static av_cold int vaapi_encode_mpeg2_close(AVCodecContext *avctx) +{ + VAAPIEncodeContext *ctx = avctx->priv_data; + VAAPIEncodeMPEG2Context *priv = ctx->priv_data; + + if (priv) + ff_cbs_close(&priv->cbc); + + return ff_vaapi_encode_close(avctx); +} + static const AVCodecDefault vaapi_encode_mpeg2_defaults[] = { { "profile", "4" }, { "level", "4" }, @@ -460,11 +668,12 @@ AVCodec ff_mpeg2_vaapi_encoder = { .priv_data_size = sizeof(VAAPIEncodeContext), .init = &vaapi_encode_mpeg2_init, .encode2 = &ff_vaapi_encode2, - .close = &ff_vaapi_encode_close, - .capabilities = AV_CODEC_CAP_DELAY, + .close = &vaapi_encode_mpeg2_close, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .defaults = vaapi_encode_mpeg2_defaults, .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE, }, + .wrapper_name = "vaapi", }; diff --git a/libavcodec/vaapi_encode_vp8.c b/libavcodec/vaapi_encode_vp8.c index 423f7483e8866..b4c5521d1f7c3 100644 --- a/libavcodec/vaapi_encode_vp8.c +++ b/libavcodec/vaapi_encode_vp8.c @@ -260,10 +260,11 @@ AVCodec ff_vp8_vaapi_encoder = { .encode2 = &ff_vaapi_encode2, .close = &ff_vaapi_encode_close, .priv_class = &vaapi_encode_vp8_class, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .defaults = vaapi_encode_vp8_defaults, .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE, }, + .wrapper_name = "vaapi", }; diff --git a/libavcodec/vaapi_encode_vp9.c b/libavcodec/vaapi_encode_vp9.c index a987d1cd71924..9108699ac383a 100644 --- a/libavcodec/vaapi_encode_vp9.c +++ b/libavcodec/vaapi_encode_vp9.c @@ -304,10 +304,11 @@ AVCodec ff_vp9_vaapi_encoder = { .encode2 = &ff_vaapi_encode2, .close = &ff_vaapi_encode_close, .priv_class = &vaapi_encode_vp9_class, - .capabilities = AV_CODEC_CAP_DELAY, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, .defaults = vaapi_encode_vp9_defaults, .pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE, }, + .wrapper_name = "vaapi", }; diff --git a/libavcodec/vaapi_h264.c b/libavcodec/vaapi_h264.c index 30e7026ccf049..5854587a255a7 100644 --- a/libavcodec/vaapi_h264.c +++ b/libavcodec/vaapi_h264.c @@ -388,7 +388,7 @@ static int vaapi_h264_decode_slice(AVCodecContext *avctx, return 0; } -AVHWAccel ff_h264_vaapi_hwaccel = { +const AVHWAccel ff_h264_vaapi_hwaccel = { .name = "h264_vaapi", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, @@ -399,6 +399,7 @@ AVHWAccel ff_h264_vaapi_hwaccel = { .frame_priv_data_size = sizeof(VAAPIDecodePicture), .init = &ff_vaapi_decode_init, .uninit = &ff_vaapi_decode_uninit, + .frame_params = &ff_vaapi_common_frame_params, .priv_data_size = sizeof(VAAPIDecodeContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vaapi_hevc.c b/libavcodec/vaapi_hevc.c index 69b8e478c613b..19aabcdb5218a 100644 --- a/libavcodec/vaapi_hevc.c +++ b/libavcodec/vaapi_hevc.c @@ -423,7 +423,7 @@ static int vaapi_hevc_decode_slice(AVCodecContext *avctx, return 0; } -AVHWAccel ff_hevc_vaapi_hwaccel = { +const AVHWAccel ff_hevc_vaapi_hwaccel = { .name = "hevc_vaapi", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_HEVC, @@ -434,6 +434,7 @@ AVHWAccel ff_hevc_vaapi_hwaccel = { .frame_priv_data_size = sizeof(VAAPIDecodePictureHEVC), .init = ff_vaapi_decode_init, .uninit = ff_vaapi_decode_uninit, + .frame_params = ff_vaapi_common_frame_params, .priv_data_size = sizeof(VAAPIDecodeContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vaapi_mjpeg.c b/libavcodec/vaapi_mjpeg.c new file mode 100644 index 0000000000000..14e0206ae1fa3 --- /dev/null +++ b/libavcodec/vaapi_mjpeg.c @@ -0,0 +1,159 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "hwaccel.h" +#include "vaapi_decode.h" +#include "mjpegdec.h" + +static int vaapi_mjpeg_start_frame(AVCodecContext *avctx, + av_unused const uint8_t *buffer, + av_unused uint32_t size) +{ + const MJpegDecodeContext *s = avctx->priv_data; + VAAPIDecodePicture *pic = s->hwaccel_picture_private; + VAPictureParameterBufferJPEGBaseline pp; + int err, i; + + pic->output_surface = ff_vaapi_get_surface_id(s->picture_ptr); + + pp = (VAPictureParameterBufferJPEGBaseline) { + .picture_width = avctx->width, + .picture_height = avctx->height, + + .num_components = s->nb_components, + }; + + for (i = 0; i < s->nb_components; i++) { + pp.components[i].component_id = s->component_id[i]; + pp.components[i].h_sampling_factor = s->h_count[i]; + pp.components[i].v_sampling_factor = s->v_count[i]; + pp.components[i].quantiser_table_selector = s->quant_index[i]; + } + + err = ff_vaapi_decode_make_param_buffer(avctx, pic, + VAPictureParameterBufferType, + &pp, sizeof(pp)); + if (err < 0) + goto fail; + + return 0; + +fail: + ff_vaapi_decode_cancel(avctx, pic); + return err; +} + +static int vaapi_mjpeg_end_frame(AVCodecContext *avctx) +{ + const MJpegDecodeContext *s = avctx->priv_data; + VAAPIDecodePicture *pic = s->hwaccel_picture_private; + + return ff_vaapi_decode_issue(avctx, pic); +} + +static int vaapi_mjpeg_decode_slice(AVCodecContext *avctx, + const uint8_t *buffer, + uint32_t size) +{ + const MJpegDecodeContext *s = avctx->priv_data; + VAAPIDecodePicture *pic = s->hwaccel_picture_private; + VAHuffmanTableBufferJPEGBaseline huff; + VAIQMatrixBufferJPEGBaseline quant; + VASliceParameterBufferJPEGBaseline sp; + int err, i, j; + + memset(&huff, 0, sizeof(huff)); + for (i = 0; i < 2; i++) { + huff.load_huffman_table[i] = 1; + for (j = 0; j < 16; j++) + huff.huffman_table[i].num_dc_codes[j] = s->raw_huffman_lengths[0][i][j]; + for (j = 0; j < 12; j++) + huff.huffman_table[i].dc_values[j] = s->raw_huffman_values[0][i][j]; + for (j = 0; j < 16; j++) + huff.huffman_table[i].num_ac_codes[j] = s->raw_huffman_lengths[1][i][j]; + for (j = 0; j < 162; j++) + huff.huffman_table[i].ac_values[j] = s->raw_huffman_values[1][i][j]; + } + + err = ff_vaapi_decode_make_param_buffer(avctx, pic, + VAHuffmanTableBufferType, + &huff, sizeof(huff)); + if (err < 0) + goto fail; + + memset(&quant, 0, sizeof(quant)); + for (i = 0; i < 4; i++) { + quant.load_quantiser_table[i] = 1; + for (j = 0; j < 64; j++) + quant.quantiser_table[i][j] = s->quant_matrixes[i][j]; + } + + err = ff_vaapi_decode_make_param_buffer(avctx, pic, + VAIQMatrixBufferType, + &quant, sizeof(quant)); + if (err < 0) + goto fail; + + sp = (VASliceParameterBufferJPEGBaseline) { + .slice_data_size = size, + .slice_data_offset = 0, + .slice_data_flag = VA_SLICE_DATA_FLAG_ALL, + + .slice_horizontal_position = 0, + .slice_vertical_position = 0, + + .restart_interval = s->restart_interval, + .num_mcus = s->mb_width * s->mb_height, + }; + + sp.num_components = s->nb_components; + for (i = 0; i < s->nb_components; i++) { + sp.components[i].component_selector = s->component_id[s->comp_index[i]]; + sp.components[i].dc_table_selector = s->dc_index[i]; + sp.components[i].ac_table_selector = s->ac_index[i]; + } + + err = ff_vaapi_decode_make_slice_buffer(avctx, pic, &sp, sizeof(sp), buffer, size); + if (err) + goto fail; + + return 0; + +fail: + ff_vaapi_decode_cancel(avctx, pic); + return err; +} + +const AVHWAccel ff_mjpeg_vaapi_hwaccel = { + .name = "mjpeg_vaapi", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_MJPEG, + .pix_fmt = AV_PIX_FMT_VAAPI, + .start_frame = &vaapi_mjpeg_start_frame, + .end_frame = &vaapi_mjpeg_end_frame, + .decode_slice = &vaapi_mjpeg_decode_slice, + .frame_priv_data_size = sizeof(VAAPIDecodePicture), + .init = &ff_vaapi_decode_init, + .uninit = &ff_vaapi_decode_uninit, + .frame_params = &ff_vaapi_common_frame_params, + .priv_data_size = sizeof(VAAPIDecodeContext), + .caps_internal = HWACCEL_CAP_ASYNC_SAFE, +}; diff --git a/libavcodec/vaapi_mpeg2.c b/libavcodec/vaapi_mpeg2.c index 0d197c9692883..aaed434c88372 100644 --- a/libavcodec/vaapi_mpeg2.c +++ b/libavcodec/vaapi_mpeg2.c @@ -172,7 +172,7 @@ static int vaapi_mpeg2_decode_slice(AVCodecContext *avctx, const uint8_t *buffer return 0; } -AVHWAccel ff_mpeg2_vaapi_hwaccel = { +const AVHWAccel ff_mpeg2_vaapi_hwaccel = { .name = "mpeg2_vaapi", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG2VIDEO, @@ -183,6 +183,7 @@ AVHWAccel ff_mpeg2_vaapi_hwaccel = { .frame_priv_data_size = sizeof(VAAPIDecodePicture), .init = &ff_vaapi_decode_init, .uninit = &ff_vaapi_decode_uninit, + .frame_params = &ff_vaapi_common_frame_params, .priv_data_size = sizeof(VAAPIDecodeContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vaapi_mpeg4.c b/libavcodec/vaapi_mpeg4.c index f8c5ddf209537..11860ff747428 100644 --- a/libavcodec/vaapi_mpeg4.c +++ b/libavcodec/vaapi_mpeg4.c @@ -178,7 +178,7 @@ static int vaapi_mpeg4_decode_slice(AVCodecContext *avctx, const uint8_t *buffer } #if CONFIG_MPEG4_VAAPI_HWACCEL -AVHWAccel ff_mpeg4_vaapi_hwaccel = { +const AVHWAccel ff_mpeg4_vaapi_hwaccel = { .name = "mpeg4_vaapi", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG4, @@ -189,13 +189,14 @@ AVHWAccel ff_mpeg4_vaapi_hwaccel = { .frame_priv_data_size = sizeof(VAAPIDecodePicture), .init = &ff_vaapi_decode_init, .uninit = &ff_vaapi_decode_uninit, + .frame_params = &ff_vaapi_common_frame_params, .priv_data_size = sizeof(VAAPIDecodeContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; #endif #if CONFIG_H263_VAAPI_HWACCEL -AVHWAccel ff_h263_vaapi_hwaccel = { +const AVHWAccel ff_h263_vaapi_hwaccel = { .name = "h263_vaapi", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H263, @@ -206,6 +207,7 @@ AVHWAccel ff_h263_vaapi_hwaccel = { .frame_priv_data_size = sizeof(VAAPIDecodePicture), .init = &ff_vaapi_decode_init, .uninit = &ff_vaapi_decode_uninit, + .frame_params = &ff_vaapi_common_frame_params, .priv_data_size = sizeof(VAAPIDecodeContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vaapi_vc1.c b/libavcodec/vaapi_vc1.c index 30c9ed3c8b530..74ba7831416de 100644 --- a/libavcodec/vaapi_vc1.c +++ b/libavcodec/vaapi_vc1.c @@ -44,7 +44,8 @@ static inline int vc1_has_MVTYPEMB_bitplane(const VC1Context *v) { if (v->mv_type_is_raw) return 0; - return v->s.pict_type == AV_PICTURE_TYPE_P && + return v->fcm == PROGRESSIVE && + (v->s.pict_type == AV_PICTURE_TYPE_P && !v->p_frame_skipped) && (v->mv_mode == MV_PMODE_MIXED_MV || (v->mv_mode == MV_PMODE_INTENSITY_COMP && v->mv_mode2 == MV_PMODE_MIXED_MV)); @@ -55,8 +56,9 @@ static inline int vc1_has_SKIPMB_bitplane(const VC1Context *v) { if (v->skip_is_raw) return 0; - return v->s.pict_type == AV_PICTURE_TYPE_P || - (v->s.pict_type == AV_PICTURE_TYPE_B && !v->bi_type); + return (v->fcm == PROGRESSIVE || v->fcm == ILACE_FRAME) && + ((v->s.pict_type == AV_PICTURE_TYPE_P && !v->p_frame_skipped) || + (v->s.pict_type == AV_PICTURE_TYPE_B && !v->bi_type)); } /** Check whether the DIRECTMB bitplane is present */ @@ -64,7 +66,8 @@ static inline int vc1_has_DIRECTMB_bitplane(const VC1Context *v) { if (v->dmb_is_raw) return 0; - return v->s.pict_type == AV_PICTURE_TYPE_B && !v->bi_type; + return (v->fcm == PROGRESSIVE || v->fcm == ILACE_FRAME) && + (v->s.pict_type == AV_PICTURE_TYPE_B && !v->bi_type); } /** Check whether the ACPRED bitplane is present */ @@ -89,6 +92,25 @@ static inline int vc1_has_OVERFLAGS_bitplane(const VC1Context *v) v->condover == CONDOVER_SELECT; } +/** Check whether the FIELDTX bitplane is present */ +static inline int vc1_has_FIELDTX_bitplane(const VC1Context *v) +{ + if (v->fieldtx_is_raw) + return 0; + return v->fcm == ILACE_FRAME && + (v->s.pict_type == AV_PICTURE_TYPE_I || + (v->s.pict_type == AV_PICTURE_TYPE_B && v->bi_type)); +} + +/** Check whether the FORWARDMB bitplane is present */ +static inline int vc1_has_FORWARDMB_bitplane(const VC1Context *v) +{ + if (v->fmb_is_raw) + return 0; + return v->fcm == ILACE_FIELD && + (v->s.pict_type == AV_PICTURE_TYPE_B && !v->bi_type); +} + /** Reconstruct bitstream PTYPE (7.1.1.4, index into Table-35) */ static int vc1_get_PTYPE(const VC1Context *v) { @@ -101,10 +123,22 @@ static int vc1_get_PTYPE(const VC1Context *v) return 0; } +/** Reconstruct bitstream FPTYPE (9.1.1.42, index into Table-105) */ +static int vc1_get_FPTYPE(const VC1Context *v) +{ + const MpegEncContext *s = &v->s; + switch (s->pict_type) { + case AV_PICTURE_TYPE_I: return 0; + case AV_PICTURE_TYPE_P: return 3; + case AV_PICTURE_TYPE_B: return v->bi_type ? 7 : 4; + } + return 0; +} + /** Reconstruct bitstream MVMODE (7.1.1.32) */ static inline VAMvModeVC1 vc1_get_MVMODE(const VC1Context *v) { - if (v->s.pict_type == AV_PICTURE_TYPE_P || + if ((v->s.pict_type == AV_PICTURE_TYPE_P && !v->p_frame_skipped) || (v->s.pict_type == AV_PICTURE_TYPE_B && !v->bi_type)) return get_VAMvModeVC1(v->mv_mode); return 0; @@ -113,11 +147,77 @@ static inline VAMvModeVC1 vc1_get_MVMODE(const VC1Context *v) /** Reconstruct bitstream MVMODE2 (7.1.1.33) */ static inline VAMvModeVC1 vc1_get_MVMODE2(const VC1Context *v) { - if (v->s.pict_type == AV_PICTURE_TYPE_P && v->mv_mode == MV_PMODE_INTENSITY_COMP) + if ((v->s.pict_type == AV_PICTURE_TYPE_P && !v->p_frame_skipped) && + v->mv_mode == MV_PMODE_INTENSITY_COMP) return get_VAMvModeVC1(v->mv_mode2); return 0; } +av_unused static inline int vc1_get_INTCOMPFIELD(const VC1Context *v) +{ + if ((v->s.pict_type == AV_PICTURE_TYPE_P && !v->p_frame_skipped) && + v->fcm == ILACE_FIELD && + v->mv_mode == MV_PMODE_INTENSITY_COMP) + switch (v->intcompfield) { + case 1: return 1; + case 2: return 2; + case 3: return 0; + } + return 0; +} + +static inline int vc1_get_LUMSCALE(const VC1Context *v) +{ + if (v->s.pict_type == AV_PICTURE_TYPE_P && !v->p_frame_skipped) { + if ((v->fcm == PROGRESSIVE && v->mv_mode == MV_PMODE_INTENSITY_COMP) || + (v->fcm == ILACE_FRAME && v->intcomp)) + return v->lumscale; + else if (v->fcm == ILACE_FIELD && v->mv_mode == MV_PMODE_INTENSITY_COMP) + switch (v->intcompfield) { + case 1: return v->lumscale; + case 2: return v->lumscale2; + case 3: return v->lumscale; + } + } + return 0; +} + +static inline int vc1_get_LUMSHIFT(const VC1Context *v) +{ + if (v->s.pict_type == AV_PICTURE_TYPE_P && !v->p_frame_skipped) { + if ((v->fcm == PROGRESSIVE && v->mv_mode == MV_PMODE_INTENSITY_COMP) || + (v->fcm == ILACE_FRAME && v->intcomp)) + return v->lumshift; + else if (v->fcm == ILACE_FIELD && v->mv_mode == MV_PMODE_INTENSITY_COMP) + switch (v->intcompfield) { + case 1: return v->lumshift; + case 2: return v->lumshift2; + case 3: return v->lumshift; + } + } + return 0; +} + +av_unused static inline int vc1_get_LUMSCALE2(const VC1Context *v) +{ + if ((v->s.pict_type == AV_PICTURE_TYPE_P && !v->p_frame_skipped) && + v->fcm == ILACE_FIELD && + v->mv_mode == MV_PMODE_INTENSITY_COMP && + v->intcompfield == 3) + return v->lumscale2; + return 0; +} + +av_unused static inline int vc1_get_LUMSHIFT2(const VC1Context *v) +{ + if ((v->s.pict_type == AV_PICTURE_TYPE_P && !v->p_frame_skipped) && + v->fcm == ILACE_FIELD && + v->mv_mode == MV_PMODE_INTENSITY_COMP && + v->intcompfield == 3) + return v->lumshift2; + return 0; +} + /** Reconstruct bitstream TTFRM (7.1.1.41, Table-53) */ static inline int vc1_get_TTFRM(const VC1Context *v) { @@ -189,27 +289,32 @@ static int vaapi_vc1_start_frame(AVCodecContext *avctx, av_unused const uint8_t .chroma = v->range_mapuv, }, .b_picture_fraction = v->bfraction_lut_index, - .cbp_table = v->cbpcy_vlc ? v->cbpcy_vlc - ff_vc1_cbpcy_p_vlc : 0, - .mb_mode_table = 0, /* XXX: interlaced frame */ + .cbp_table = (v->fcm == PROGRESSIVE ? v->cbptab : v->icbptab), + .mb_mode_table = v->mbmodetab, .range_reduction_frame = v->rangeredfrm, .rounding_control = v->rnd, .post_processing = v->postproc, .picture_resolution_index = v->respic, - .luma_scale = v->lumscale, - .luma_shift = v->lumshift, .picture_fields.bits = { - .picture_type = vc1_get_PTYPE(v), + .picture_type = (v->fcm == ILACE_FIELD ? vc1_get_FPTYPE(v) : vc1_get_PTYPE(v)), .frame_coding_mode = v->fcm, .top_field_first = v->tff, - .is_first_field = v->fcm == 0, /* XXX: interlaced frame */ - .intensity_compensation = v->mv_mode == MV_PMODE_INTENSITY_COMP, + .is_first_field = !v->second_field, + .intensity_compensation = v->intcomp, }, + .luma_scale = vc1_get_LUMSCALE(v), + .luma_shift = vc1_get_LUMSHIFT(v), +#if VA_CHECK_VERSION(1, 1, 0) + .luma_scale2 = vc1_get_LUMSCALE2(v), + .luma_shift2 = vc1_get_LUMSHIFT2(v), + .intensity_compensation_field = vc1_get_INTCOMPFIELD(v), +#endif .raw_coding.flags = { .mv_type_mb = v->mv_type_is_raw, .direct_mb = v->dmb_is_raw, .skip_mb = v->skip_is_raw, - .field_tx = 0, /* XXX: interlaced frame */ - .forward_mb = 0, /* XXX: interlaced frame */ + .field_tx = v->fieldtx_is_raw, + .forward_mb = v->fmb_is_raw, .ac_pred = v->acpred_is_raw, .overflags = v->overflg_is_raw, }, @@ -217,28 +322,28 @@ static int vaapi_vc1_start_frame(AVCodecContext *avctx, av_unused const uint8_t .bp_mv_type_mb = vc1_has_MVTYPEMB_bitplane(v), .bp_direct_mb = vc1_has_DIRECTMB_bitplane(v), .bp_skip_mb = vc1_has_SKIPMB_bitplane(v), - .bp_field_tx = 0, /* XXX: interlaced frame */ - .bp_forward_mb = 0, /* XXX: interlaced frame */ + .bp_field_tx = vc1_has_FIELDTX_bitplane(v), + .bp_forward_mb = vc1_has_FORWARDMB_bitplane(v), .bp_ac_pred = vc1_has_ACPRED_bitplane(v), .bp_overflags = vc1_has_OVERFLAGS_bitplane(v), }, .reference_fields.bits = { .reference_distance_flag = v->refdist_flag, - .reference_distance = 0, /* XXX: interlaced frame */ - .num_reference_pictures = 0, /* XXX: interlaced frame */ - .reference_field_pic_indicator = 0, /* XXX: interlaced frame */ + .reference_distance = v->refdist, + .num_reference_pictures = v->numref, + .reference_field_pic_indicator = v->reffield, }, .mv_fields.bits = { .mv_mode = vc1_get_MVMODE(v), .mv_mode2 = vc1_get_MVMODE2(v), - .mv_table = s->mv_table_index, - .two_mv_block_pattern_table = 0, /* XXX: interlaced frame */ - .four_mv_switch = 0, /* XXX: interlaced frame */ - .four_mv_block_pattern_table = 0, /* XXX: interlaced frame */ + .mv_table = (v->fcm == PROGRESSIVE ? s->mv_table_index : v->imvtab), + .two_mv_block_pattern_table = v->twomvbptab, + .four_mv_switch = v->fourmvswitch, + .four_mv_block_pattern_table = v->fourmvbptab, .extended_mv_flag = v->extended_mv, .extended_mv_range = v->mvrange, .extended_dmv_flag = v->extended_dmv, - .extended_dmv_range = 0, /* XXX: interlaced frame */ + .extended_dmv_range = v->dmvrange, }, .pic_quantizer_fields.bits = { .dquant = v->dquant, @@ -278,7 +383,7 @@ static int vaapi_vc1_start_frame(AVCodecContext *avctx, av_unused const uint8_t if (err) goto fail; - if (pic_param.bitplane_present.value) { + if (pic_param.bitplane_present.value & 0x7f) { uint8_t *bitplane; const uint8_t *ff_bp[3]; int x, y, n; @@ -298,14 +403,14 @@ static int vaapi_vc1_start_frame(AVCodecContext *avctx, av_unused const uint8_t break; case AV_PICTURE_TYPE_B: if (!v->bi_type) { - ff_bp[0] = pic_param.bitplane_present.flags.bp_direct_mb ? v->direct_mb_plane : NULL; - ff_bp[1] = pic_param.bitplane_present.flags.bp_skip_mb ? s->mbskip_table : NULL; - ff_bp[2] = NULL; /* XXX: interlaced frame (FORWARD plane) */ + ff_bp[0] = pic_param.bitplane_present.flags.bp_direct_mb ? v->direct_mb_plane : NULL; + ff_bp[1] = pic_param.bitplane_present.flags.bp_skip_mb ? s->mbskip_table : NULL; + ff_bp[2] = pic_param.bitplane_present.flags.bp_forward_mb ? v->forward_mb_plane : NULL; break; } /* fall-through (BI-type) */ case AV_PICTURE_TYPE_I: - ff_bp[0] = NULL; /* XXX: interlaced frame (FIELDTX plane) */ + ff_bp[0] = pic_param.bitplane_present.flags.bp_field_tx ? v->fieldtx_plane : NULL; ff_bp[1] = pic_param.bitplane_present.flags.bp_ac_pred ? v->acpred_plane : NULL; ff_bp[2] = pic_param.bitplane_present.flags.bp_overflags ? v->over_flags_plane : NULL; break; @@ -388,7 +493,7 @@ static int vaapi_vc1_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, } #if CONFIG_WMV3_VAAPI_HWACCEL -AVHWAccel ff_wmv3_vaapi_hwaccel = { +const AVHWAccel ff_wmv3_vaapi_hwaccel = { .name = "wmv3_vaapi", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_WMV3, @@ -399,12 +504,13 @@ AVHWAccel ff_wmv3_vaapi_hwaccel = { .frame_priv_data_size = sizeof(VAAPIDecodePicture), .init = &ff_vaapi_decode_init, .uninit = &ff_vaapi_decode_uninit, + .frame_params = &ff_vaapi_common_frame_params, .priv_data_size = sizeof(VAAPIDecodeContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; #endif -AVHWAccel ff_vc1_vaapi_hwaccel = { +const AVHWAccel ff_vc1_vaapi_hwaccel = { .name = "vc1_vaapi", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VC1, @@ -415,6 +521,7 @@ AVHWAccel ff_vc1_vaapi_hwaccel = { .frame_priv_data_size = sizeof(VAAPIDecodePicture), .init = &ff_vaapi_decode_init, .uninit = &ff_vaapi_decode_uninit, + .frame_params = &ff_vaapi_common_frame_params, .priv_data_size = sizeof(VAAPIDecodeContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vaapi_vp8.c b/libavcodec/vaapi_vp8.c new file mode 100644 index 0000000000000..2426b30f13ca1 --- /dev/null +++ b/libavcodec/vaapi_vp8.c @@ -0,0 +1,237 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "hwaccel.h" +#include "vaapi_decode.h" +#include "vp8.h" + +static VASurfaceID vaapi_vp8_surface_id(VP8Frame *vf) +{ + if (vf) + return ff_vaapi_get_surface_id(vf->tf.f); + else + return VA_INVALID_SURFACE; +} + +static int vaapi_vp8_start_frame(AVCodecContext *avctx, + av_unused const uint8_t *buffer, + av_unused uint32_t size) +{ + const VP8Context *s = avctx->priv_data; + VAAPIDecodePicture *pic = s->framep[VP56_FRAME_CURRENT]->hwaccel_picture_private; + VAPictureParameterBufferVP8 pp; + VAProbabilityDataBufferVP8 prob; + VAIQMatrixBufferVP8 quant; + int err, i, j, k; + + pic->output_surface = vaapi_vp8_surface_id(s->framep[VP56_FRAME_CURRENT]); + + pp = (VAPictureParameterBufferVP8) { + .frame_width = avctx->width, + .frame_height = avctx->height, + + .last_ref_frame = vaapi_vp8_surface_id(s->framep[VP56_FRAME_PREVIOUS]), + .golden_ref_frame = vaapi_vp8_surface_id(s->framep[VP56_FRAME_GOLDEN]), + .alt_ref_frame = vaapi_vp8_surface_id(s->framep[VP56_FRAME_GOLDEN2]), + .out_of_loop_frame = VA_INVALID_SURFACE, + + .pic_fields.bits = { + .key_frame = !s->keyframe, + .version = s->profile, + + .segmentation_enabled = s->segmentation.enabled, + .update_mb_segmentation_map = s->segmentation.update_map, + .update_segment_feature_data = s->segmentation.update_feature_data, + + .filter_type = s->filter.simple, + .sharpness_level = s->filter.sharpness, + + .loop_filter_adj_enable = s->lf_delta.enabled, + .mode_ref_lf_delta_update = s->lf_delta.update, + + .sign_bias_golden = s->sign_bias[VP56_FRAME_GOLDEN], + .sign_bias_alternate = s->sign_bias[VP56_FRAME_GOLDEN2], + + .mb_no_coeff_skip = s->mbskip_enabled, + .loop_filter_disable = s->filter.level == 0, + }, + + .prob_skip_false = s->prob->mbskip, + .prob_intra = s->prob->intra, + .prob_last = s->prob->last, + .prob_gf = s->prob->golden, + }; + + for (i = 0; i < 3; i++) + pp.mb_segment_tree_probs[i] = s->prob->segmentid[i]; + + for (i = 0; i < 4; i++) { + if (s->segmentation.enabled) { + pp.loop_filter_level[i] = s->segmentation.filter_level[i]; + if (!s->segmentation.absolute_vals) + pp.loop_filter_level[i] += s->filter.level; + } else { + pp.loop_filter_level[i] = s->filter.level; + } + pp.loop_filter_level[i] = av_clip_uintp2(pp.loop_filter_level[i], 6); + } + + for (i = 0; i < 4; i++) { + pp.loop_filter_deltas_ref_frame[i] = s->lf_delta.ref[i]; + pp.loop_filter_deltas_mode[i] = s->lf_delta.mode[i + 4]; + } + + if (s->keyframe) { + static const uint8_t keyframe_y_mode_probs[4] = { + 145, 156, 163, 128 + }; + static const uint8_t keyframe_uv_mode_probs[3] = { + 142, 114, 183 + }; + memcpy(pp.y_mode_probs, keyframe_y_mode_probs, 4); + memcpy(pp.uv_mode_probs, keyframe_uv_mode_probs, 3); + } else { + for (i = 0; i < 4; i++) + pp.y_mode_probs[i] = s->prob->pred16x16[i]; + for (i = 0; i < 3; i++) + pp.uv_mode_probs[i] = s->prob->pred8x8c[i]; + } + for (i = 0; i < 2; i++) + for (j = 0; j < 19; j++) + pp.mv_probs[i][j] = s->prob->mvc[i][j]; + + pp.bool_coder_ctx.range = s->coder_state_at_header_end.range; + pp.bool_coder_ctx.value = s->coder_state_at_header_end.value; + pp.bool_coder_ctx.count = s->coder_state_at_header_end.bit_count; + + err = ff_vaapi_decode_make_param_buffer(avctx, pic, + VAPictureParameterBufferType, + &pp, sizeof(pp)); + if (err < 0) + goto fail; + + for (i = 0; i < 4; i++) { + for (j = 0; j < 8; j++) { + static const int coeff_bands_inverse[8] = { + 0, 1, 2, 3, 5, 6, 4, 15 + }; + int coeff_pos = coeff_bands_inverse[j]; + + for (k = 0; k < 3; k++) { + memcpy(prob.dct_coeff_probs[i][j][k], + s->prob->token[i][coeff_pos][k], 11); + } + } + } + + err = ff_vaapi_decode_make_param_buffer(avctx, pic, + VAProbabilityBufferType, + &prob, sizeof(prob)); + if (err < 0) + goto fail; + + for (i = 0; i < 4; i++) { + int base_qi = s->segmentation.base_quant[i]; + if (!s->segmentation.absolute_vals) + base_qi += s->quant.yac_qi; + + quant.quantization_index[i][0] = av_clip_uintp2(base_qi, 7); + quant.quantization_index[i][1] = av_clip_uintp2(base_qi + s->quant.ydc_delta, 7); + quant.quantization_index[i][2] = av_clip_uintp2(base_qi + s->quant.y2dc_delta, 7); + quant.quantization_index[i][3] = av_clip_uintp2(base_qi + s->quant.y2ac_delta, 7); + quant.quantization_index[i][4] = av_clip_uintp2(base_qi + s->quant.uvdc_delta, 7); + quant.quantization_index[i][5] = av_clip_uintp2(base_qi + s->quant.uvac_delta, 7); + } + + err = ff_vaapi_decode_make_param_buffer(avctx, pic, + VAIQMatrixBufferType, + &quant, sizeof(quant)); + if (err < 0) + goto fail; + + return 0; + +fail: + ff_vaapi_decode_cancel(avctx, pic); + return err; +} + +static int vaapi_vp8_end_frame(AVCodecContext *avctx) +{ + const VP8Context *s = avctx->priv_data; + VAAPIDecodePicture *pic = s->framep[VP56_FRAME_CURRENT]->hwaccel_picture_private; + + return ff_vaapi_decode_issue(avctx, pic); +} + +static int vaapi_vp8_decode_slice(AVCodecContext *avctx, + const uint8_t *buffer, + uint32_t size) +{ + const VP8Context *s = avctx->priv_data; + VAAPIDecodePicture *pic = s->framep[VP56_FRAME_CURRENT]->hwaccel_picture_private; + VASliceParameterBufferVP8 sp; + int err, i; + + unsigned int header_size = 3 + 7 * s->keyframe; + const uint8_t *data = buffer + header_size; + unsigned int data_size = size - header_size; + + sp = (VASliceParameterBufferVP8) { + .slice_data_size = data_size, + .slice_data_offset = 0, + .slice_data_flag = VA_SLICE_DATA_FLAG_ALL, + + .macroblock_offset = (8 * (s->coder_state_at_header_end.input - data) - + s->coder_state_at_header_end.bit_count - 8), + .num_of_partitions = s->num_coeff_partitions + 1, + }; + + sp.partition_size[0] = s->header_partition_size - ((sp.macroblock_offset + 7) / 8); + for (i = 0; i < 8; i++) + sp.partition_size[i+1] = s->coeff_partition_size[i]; + + err = ff_vaapi_decode_make_slice_buffer(avctx, pic, &sp, sizeof(sp), data, data_size); + if (err) + goto fail; + + return 0; + +fail: + ff_vaapi_decode_cancel(avctx, pic); + return err; +} + +const AVHWAccel ff_vp8_vaapi_hwaccel = { + .name = "vp8_vaapi", + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_VP8, + .pix_fmt = AV_PIX_FMT_VAAPI, + .start_frame = &vaapi_vp8_start_frame, + .end_frame = &vaapi_vp8_end_frame, + .decode_slice = &vaapi_vp8_decode_slice, + .frame_priv_data_size = sizeof(VAAPIDecodePicture), + .init = &ff_vaapi_decode_init, + .uninit = &ff_vaapi_decode_uninit, + .frame_params = &ff_vaapi_common_frame_params, + .priv_data_size = sizeof(VAAPIDecodeContext), + .caps_internal = HWACCEL_CAP_ASYNC_SAFE, +}; diff --git a/libavcodec/vaapi_vp9.c b/libavcodec/vaapi_vp9.c index d8ece75df4fe9..f384ba7873ad5 100644 --- a/libavcodec/vaapi_vp9.c +++ b/libavcodec/vaapi_vp9.c @@ -168,7 +168,7 @@ static int vaapi_vp9_decode_slice(AVCodecContext *avctx, return 0; } -AVHWAccel ff_vp9_vaapi_hwaccel = { +const AVHWAccel ff_vp9_vaapi_hwaccel = { .name = "vp9_vaapi", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VP9, @@ -179,6 +179,7 @@ AVHWAccel ff_vp9_vaapi_hwaccel = { .frame_priv_data_size = sizeof(VAAPIDecodePicture), .init = ff_vaapi_decode_init, .uninit = ff_vaapi_decode_uninit, + .frame_params = ff_vaapi_common_frame_params, .priv_data_size = sizeof(VAAPIDecodeContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vc1.c b/libavcodec/vc1.c index 48a2cc1e48949..e7625070f7982 100644 --- a/libavcodec/vc1.c +++ b/libavcodec/vc1.c @@ -314,11 +314,11 @@ int ff_vc1_decode_sequence_header(AVCodecContext *avctx, VC1Context *v, GetBitCo v->multires = get_bits1(gb); v->res_fasttx = get_bits1(gb); if (!v->res_fasttx) { - v->vc1dsp.vc1_inv_trans_8x8 = ff_simple_idct_8; + v->vc1dsp.vc1_inv_trans_8x8 = ff_simple_idct_int16_8bit; v->vc1dsp.vc1_inv_trans_8x4 = ff_simple_idct84_add; v->vc1dsp.vc1_inv_trans_4x8 = ff_simple_idct48_add; v->vc1dsp.vc1_inv_trans_4x4 = ff_simple_idct44_add; - v->vc1dsp.vc1_inv_trans_8x8_dc = ff_simple_idct_add_8; + v->vc1dsp.vc1_inv_trans_8x8_dc = ff_simple_idct_add_int16_8bit; v->vc1dsp.vc1_inv_trans_8x4_dc = ff_simple_idct84_add; v->vc1dsp.vc1_inv_trans_4x8_dc = ff_simple_idct48_add; v->vc1dsp.vc1_inv_trans_4x4_dc = ff_simple_idct44_add; @@ -629,7 +629,7 @@ int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb) int pqindex, lowquant, status; v->field_mode = 0; - v->fcm = 0; + v->fcm = PROGRESSIVE; if (v->finterpflag) v->interpfrm = get_bits1(gb); if (!v->s.avctx->codec) @@ -766,7 +766,8 @@ int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb) /* Hopefully this is correct for P-frames */ v->s.mv_table_index = get_bits(gb, 2); //but using ff_vc1_ tables - v->cbpcy_vlc = &ff_vc1_cbpcy_p_vlc[get_bits(gb, 2)]; + v->cbptab = get_bits(gb, 2); + v->cbpcy_vlc = &ff_vc1_cbpcy_p_vlc[v->cbptab]; if (v->dquant) { av_log(v->s.avctx, AV_LOG_DEBUG, "VOP DQuant info\n"); @@ -804,7 +805,8 @@ int ff_vc1_parse_frame_header(VC1Context *v, GetBitContext* gb) "Imode: %i, Invert: %i\n", status>>1, status&1); v->s.mv_table_index = get_bits(gb, 2); - v->cbpcy_vlc = &ff_vc1_cbpcy_p_vlc[get_bits(gb, 2)]; + v->cbptab = get_bits(gb, 2); + v->cbpcy_vlc = &ff_vc1_cbpcy_p_vlc[v->cbptab]; if (v->dquant) { av_log(v->s.avctx, AV_LOG_DEBUG, "VOP DQuant info\n"); @@ -845,7 +847,6 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) { int pqindex, lowquant; int status; - int mbmodetab, imvtab, icbptab, twomvbptab, fourmvbptab; /* useful only for debugging */ int field_mode, fcm; v->numref = 0; @@ -1056,21 +1057,21 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) status = bitplane_decoding(v->s.mbskip_table, &v->skip_is_raw, v); av_log(v->s.avctx, AV_LOG_DEBUG, "SKIPMB plane encoding: " "Imode: %i, Invert: %i\n", status>>1, status&1); - mbmodetab = get_bits(gb, 2); + v->mbmodetab = get_bits(gb, 2); if (v->fourmvswitch) - v->mbmode_vlc = &ff_vc1_intfr_4mv_mbmode_vlc[mbmodetab]; + v->mbmode_vlc = &ff_vc1_intfr_4mv_mbmode_vlc[v->mbmodetab]; else - v->mbmode_vlc = &ff_vc1_intfr_non4mv_mbmode_vlc[mbmodetab]; - imvtab = get_bits(gb, 2); - v->imv_vlc = &ff_vc1_1ref_mvdata_vlc[imvtab]; + v->mbmode_vlc = &ff_vc1_intfr_non4mv_mbmode_vlc[v->mbmodetab]; + v->imvtab = get_bits(gb, 2); + v->imv_vlc = &ff_vc1_1ref_mvdata_vlc[v->imvtab]; // interlaced p-picture cbpcy range is [1, 63] - icbptab = get_bits(gb, 3); - v->cbpcy_vlc = &ff_vc1_icbpcy_vlc[icbptab]; - twomvbptab = get_bits(gb, 2); - v->twomvbp_vlc = &ff_vc1_2mv_block_pattern_vlc[twomvbptab]; + v->icbptab = get_bits(gb, 3); + v->cbpcy_vlc = &ff_vc1_icbpcy_vlc[v->icbptab]; + v->twomvbptab = get_bits(gb, 2); + v->twomvbp_vlc = &ff_vc1_2mv_block_pattern_vlc[v->twomvbptab]; if (v->fourmvswitch) { - fourmvbptab = get_bits(gb, 2); - v->fourmvbp_vlc = &ff_vc1_4mv_block_pattern_vlc[fourmvbptab]; + v->fourmvbptab = get_bits(gb, 2); + v->fourmvbp_vlc = &ff_vc1_4mv_block_pattern_vlc[v->fourmvbptab]; } } } @@ -1154,27 +1155,28 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) /* Hopefully this is correct for P-frames */ v->s.mv_table_index = get_bits(gb, 2); //but using ff_vc1_ tables - v->cbpcy_vlc = &ff_vc1_cbpcy_p_vlc[get_bits(gb, 2)]; + v->cbptab = get_bits(gb, 2); + v->cbpcy_vlc = &ff_vc1_cbpcy_p_vlc[v->cbptab]; } else if (v->fcm == ILACE_FRAME) { // frame interlaced v->qs_last = v->s.quarter_sample; v->s.quarter_sample = 1; v->s.mspel = 1; } else { // field interlaced - mbmodetab = get_bits(gb, 3); - imvtab = get_bits(gb, 2 + v->numref); + v->mbmodetab = get_bits(gb, 3); + v->imvtab = get_bits(gb, 2 + v->numref); if (!v->numref) - v->imv_vlc = &ff_vc1_1ref_mvdata_vlc[imvtab]; + v->imv_vlc = &ff_vc1_1ref_mvdata_vlc[v->imvtab]; else - v->imv_vlc = &ff_vc1_2ref_mvdata_vlc[imvtab]; - icbptab = get_bits(gb, 3); - v->cbpcy_vlc = &ff_vc1_icbpcy_vlc[icbptab]; + v->imv_vlc = &ff_vc1_2ref_mvdata_vlc[v->imvtab]; + v->icbptab = get_bits(gb, 3); + v->cbpcy_vlc = &ff_vc1_icbpcy_vlc[v->icbptab]; if ((v->mv_mode == MV_PMODE_INTENSITY_COMP && v->mv_mode2 == MV_PMODE_MIXED_MV) || v->mv_mode == MV_PMODE_MIXED_MV) { - fourmvbptab = get_bits(gb, 2); - v->fourmvbp_vlc = &ff_vc1_4mv_block_pattern_vlc[fourmvbptab]; - v->mbmode_vlc = &ff_vc1_if_mmv_mbmode_vlc[mbmodetab]; + v->fourmvbptab = get_bits(gb, 2); + v->fourmvbp_vlc = &ff_vc1_4mv_block_pattern_vlc[v->fourmvbptab]; + v->mbmode_vlc = &ff_vc1_if_mmv_mbmode_vlc[v->mbmodetab]; } else { - v->mbmode_vlc = &ff_vc1_if_1mv_mbmode_vlc[mbmodetab]; + v->mbmode_vlc = &ff_vc1_if_1mv_mbmode_vlc[v->mbmodetab]; } } if (v->dquant) { @@ -1228,18 +1230,18 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) return -1; av_log(v->s.avctx, AV_LOG_DEBUG, "MB Forward Type plane encoding: " "Imode: %i, Invert: %i\n", status>>1, status&1); - mbmodetab = get_bits(gb, 3); + v->mbmodetab = get_bits(gb, 3); if (v->mv_mode == MV_PMODE_MIXED_MV) - v->mbmode_vlc = &ff_vc1_if_mmv_mbmode_vlc[mbmodetab]; + v->mbmode_vlc = &ff_vc1_if_mmv_mbmode_vlc[v->mbmodetab]; else - v->mbmode_vlc = &ff_vc1_if_1mv_mbmode_vlc[mbmodetab]; - imvtab = get_bits(gb, 3); - v->imv_vlc = &ff_vc1_2ref_mvdata_vlc[imvtab]; - icbptab = get_bits(gb, 3); - v->cbpcy_vlc = &ff_vc1_icbpcy_vlc[icbptab]; + v->mbmode_vlc = &ff_vc1_if_1mv_mbmode_vlc[v->mbmodetab]; + v->imvtab = get_bits(gb, 3); + v->imv_vlc = &ff_vc1_2ref_mvdata_vlc[v->imvtab]; + v->icbptab = get_bits(gb, 3); + v->cbpcy_vlc = &ff_vc1_icbpcy_vlc[v->icbptab]; if (v->mv_mode == MV_PMODE_MIXED_MV) { - fourmvbptab = get_bits(gb, 2); - v->fourmvbp_vlc = &ff_vc1_4mv_block_pattern_vlc[fourmvbptab]; + v->fourmvbptab = get_bits(gb, 2); + v->fourmvbp_vlc = &ff_vc1_4mv_block_pattern_vlc[v->fourmvbptab]; } v->numref = 1; // interlaced field B pictures are always 2-ref } else if (v->fcm == ILACE_FRAME) { @@ -1263,17 +1265,17 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) return -1; av_log(v->s.avctx, AV_LOG_DEBUG, "MB Skip plane encoding: " "Imode: %i, Invert: %i\n", status>>1, status&1); - mbmodetab = get_bits(gb, 2); - v->mbmode_vlc = &ff_vc1_intfr_non4mv_mbmode_vlc[mbmodetab]; - imvtab = get_bits(gb, 2); - v->imv_vlc = &ff_vc1_1ref_mvdata_vlc[imvtab]; + v->mbmodetab = get_bits(gb, 2); + v->mbmode_vlc = &ff_vc1_intfr_non4mv_mbmode_vlc[v->mbmodetab]; + v->imvtab = get_bits(gb, 2); + v->imv_vlc = &ff_vc1_1ref_mvdata_vlc[v->imvtab]; // interlaced p/b-picture cbpcy range is [1, 63] - icbptab = get_bits(gb, 3); - v->cbpcy_vlc = &ff_vc1_icbpcy_vlc[icbptab]; - twomvbptab = get_bits(gb, 2); - v->twomvbp_vlc = &ff_vc1_2mv_block_pattern_vlc[twomvbptab]; - fourmvbptab = get_bits(gb, 2); - v->fourmvbp_vlc = &ff_vc1_4mv_block_pattern_vlc[fourmvbptab]; + v->icbptab = get_bits(gb, 3); + v->cbpcy_vlc = &ff_vc1_icbpcy_vlc[v->icbptab]; + v->twomvbptab = get_bits(gb, 2); + v->twomvbp_vlc = &ff_vc1_2mv_block_pattern_vlc[v->twomvbptab]; + v->fourmvbptab = get_bits(gb, 2); + v->fourmvbp_vlc = &ff_vc1_4mv_block_pattern_vlc[v->fourmvbptab]; } else { v->mv_mode = get_bits1(gb) ? MV_PMODE_1MV : MV_PMODE_1MV_HPEL_BILIN; v->qs_last = v->s.quarter_sample; @@ -1290,7 +1292,8 @@ int ff_vc1_parse_frame_header_adv(VC1Context *v, GetBitContext* gb) av_log(v->s.avctx, AV_LOG_DEBUG, "MB Skip plane encoding: " "Imode: %i, Invert: %i\n", status>>1, status&1); v->s.mv_table_index = get_bits(gb, 2); - v->cbpcy_vlc = &ff_vc1_cbpcy_p_vlc[get_bits(gb, 2)]; + v->cbptab = get_bits(gb, 2); + v->cbpcy_vlc = &ff_vc1_cbpcy_p_vlc[v->cbptab]; } if (v->dquant) { diff --git a/libavcodec/vc1.h b/libavcodec/vc1.h index 556906d496189..8fc0729cb8bb9 100644 --- a/libavcodec/vc1.h +++ b/libavcodec/vc1.h @@ -296,6 +296,7 @@ typedef struct VC1Context{ uint8_t (*curr_luty)[256] ,(*curr_lutuv)[256]; int last_use_ic, *curr_use_ic, next_use_ic, aux_use_ic; int rnd; ///< rounding control + int cbptab; /** Frame decoding info for S/M profiles only */ //@{ @@ -367,6 +368,11 @@ typedef struct VC1Context{ int frfd, brfd; ///< reference frame distance (forward or backward) int first_pic_header_flag; int pic_header_flag; + int mbmodetab; + int icbptab; + int imvtab; + int twomvbptab; + int fourmvbptab; /** Frame decoding info for sprite modes */ //@{ diff --git a/libavcodec/vc1dec.c b/libavcodec/vc1dec.c index 16c601e75611c..cbef89f254562 100644 --- a/libavcodec/vc1dec.c +++ b/libavcodec/vc1dec.c @@ -29,6 +29,7 @@ #include "avcodec.h" #include "blockdsp.h" #include "get_bits.h" +#include "hwaccel.h" #include "internal.h" #include "mpeg_er.h" #include "mpegvideo.h" @@ -37,7 +38,6 @@ #include "profiles.h" #include "vc1.h" #include "vc1data.h" -#include "vdpau_compat.h" #include "libavutil/avassert.h" @@ -657,15 +657,6 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data, return buf_size; } -#if FF_API_CAP_VDPAU - if (s->avctx->codec->capabilities&AV_CODEC_CAP_HWACCEL_VDPAU) { - if (v->profile < PROFILE_ADVANCED) - avctx->pix_fmt = AV_PIX_FMT_VDPAU_WMV3; - else - avctx->pix_fmt = AV_PIX_FMT_VDPAU_VC1; - } -#endif - //for advanced profile we may need to parse and unescape data if (avctx->codec_id == AV_CODEC_ID_VC1 || avctx->codec_id == AV_CODEC_ID_VC1IMAGE) { int buf_size2 = 0; @@ -684,21 +675,13 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data, if (size <= 0) continue; switch (AV_RB32(start)) { case VC1_CODE_FRAME: - if (avctx->hwaccel -#if FF_API_CAP_VDPAU - || s->avctx->codec->capabilities&AV_CODEC_CAP_HWACCEL_VDPAU -#endif - ) + if (avctx->hwaccel) buf_start = start; buf_size2 = vc1_unescape_buffer(start + 4, size, buf2); break; case VC1_CODE_FIELD: { int buf_size3; - if (avctx->hwaccel -#if FF_API_CAP_VDPAU - || s->avctx->codec->capabilities&AV_CODEC_CAP_HWACCEL_VDPAU -#endif - ) + if (avctx->hwaccel) buf_start_second_field = start; tmp = av_realloc_array(slices, sizeof(*slices), (n_slices+1)); if (!tmp) { @@ -764,11 +747,7 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data, ret = AVERROR_INVALIDDATA; goto err; } else { // found field marker, unescape second field - if (avctx->hwaccel -#if FF_API_CAP_VDPAU - || s->avctx->codec->capabilities&AV_CODEC_CAP_HWACCEL_VDPAU -#endif - ) + if (avctx->hwaccel) buf_start_second_field = divider; tmp = av_realloc_array(slices, sizeof(*slices), (n_slices+1)); if (!tmp) { @@ -917,17 +896,6 @@ static int vc1_decode_frame(AVCodecContext *avctx, void *data, s->me.qpel_put = s->qdsp.put_qpel_pixels_tab; s->me.qpel_avg = s->qdsp.avg_qpel_pixels_tab; -#if FF_API_CAP_VDPAU - if ((CONFIG_VC1_VDPAU_DECODER) - &&s->avctx->codec->capabilities&AV_CODEC_CAP_HWACCEL_VDPAU) { - if (v->field_mode && buf_start_second_field) { - ff_vdpau_vc1_decode_picture(s, buf_start, buf_start_second_field - buf_start); - ff_vdpau_vc1_decode_picture(s, buf_start_second_field, (buf + buf_size) - buf_start_second_field); - } else { - ff_vdpau_vc1_decode_picture(s, buf_start, (buf + buf_size) - buf_start); - } - } else -#endif if (avctx->hwaccel) { s->mb_y = 0; if (v->field_mode && buf_start_second_field) { @@ -1152,6 +1120,9 @@ static const enum AVPixelFormat vc1_hwaccel_pixfmt_list_420[] = { AV_PIX_FMT_D3D11VA_VLD, AV_PIX_FMT_D3D11, #endif +#if CONFIG_VC1_NVDEC_HWACCEL + AV_PIX_FMT_CUDA, +#endif #if CONFIG_VC1_VAAPI_HWACCEL AV_PIX_FMT_VAAPI, #endif @@ -1174,6 +1145,27 @@ AVCodec ff_vc1_decoder = { .flush = ff_mpeg_flush, .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, .pix_fmts = vc1_hwaccel_pixfmt_list_420, + .hw_configs = (const AVCodecHWConfigInternal*[]) { +#if CONFIG_VC1_DXVA2_HWACCEL + HWACCEL_DXVA2(vc1), +#endif +#if CONFIG_VC1_D3D11VA_HWACCEL + HWACCEL_D3D11VA(vc1), +#endif +#if CONFIG_VC1_D3D11VA2_HWACCEL + HWACCEL_D3D11VA2(vc1), +#endif +#if CONFIG_VC1_NVDEC_HWACCEL + HWACCEL_NVDEC(vc1), +#endif +#if CONFIG_VC1_VAAPI_HWACCEL + HWACCEL_VAAPI(vc1), +#endif +#if CONFIG_VC1_VDPAU_HWACCEL + HWACCEL_VDPAU(vc1), +#endif + NULL + }, .profiles = NULL_IF_CONFIG_SMALL(ff_vc1_profiles) }; @@ -1190,38 +1182,27 @@ AVCodec ff_wmv3_decoder = { .flush = ff_mpeg_flush, .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, .pix_fmts = vc1_hwaccel_pixfmt_list_420, - .profiles = NULL_IF_CONFIG_SMALL(ff_vc1_profiles) -}; + .hw_configs = (const AVCodecHWConfigInternal*[]) { +#if CONFIG_WMV3_DXVA2_HWACCEL + HWACCEL_DXVA2(wmv3), #endif - -#if CONFIG_WMV3_VDPAU_DECODER && FF_API_VDPAU -AVCodec ff_wmv3_vdpau_decoder = { - .name = "wmv3_vdpau", - .long_name = NULL_IF_CONFIG_SMALL("Windows Media Video 9 VDPAU"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_WMV3, - .priv_data_size = sizeof(VC1Context), - .init = vc1_decode_init, - .close = ff_vc1_decode_end, - .decode = vc1_decode_frame, - .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HWACCEL_VDPAU, - .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_VDPAU_WMV3, AV_PIX_FMT_NONE }, - .profiles = NULL_IF_CONFIG_SMALL(ff_vc1_profiles) -}; +#if CONFIG_WMV3_D3D11VA_HWACCEL + HWACCEL_D3D11VA(wmv3), #endif - -#if CONFIG_VC1_VDPAU_DECODER && FF_API_VDPAU -AVCodec ff_vc1_vdpau_decoder = { - .name = "vc1_vdpau", - .long_name = NULL_IF_CONFIG_SMALL("SMPTE VC-1 VDPAU"), - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_VC1, - .priv_data_size = sizeof(VC1Context), - .init = vc1_decode_init, - .close = ff_vc1_decode_end, - .decode = vc1_decode_frame, - .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HWACCEL_VDPAU, - .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_VDPAU_VC1, AV_PIX_FMT_NONE }, +#if CONFIG_WMV3_D3D11VA2_HWACCEL + HWACCEL_D3D11VA2(wmv3), +#endif +#if CONFIG_WMV3_NVDEC_HWACCEL + HWACCEL_NVDEC(wmv3), +#endif +#if CONFIG_WMV3_VAAPI_HWACCEL + HWACCEL_VAAPI(wmv3), +#endif +#if CONFIG_WMV3_VDPAU_HWACCEL + HWACCEL_VDPAU(wmv3), +#endif + NULL + }, .profiles = NULL_IF_CONFIG_SMALL(ff_vc1_profiles) }; #endif diff --git a/libavcodec/vc2enc.c b/libavcodec/vc2enc.c index 96e27d93ede2d..d0101e01e4309 100644 --- a/libavcodec/vc2enc.c +++ b/libavcodec/vc2enc.c @@ -29,10 +29,6 @@ #include "vc2enc_dwt.h" #include "diractab.h" -/* Total range is -COEF_LUT_TAB to +COEFF_LUT_TAB, but total tab size is half - * (COEF_LUT_TAB*DIRAC_MAX_QUANT_INDEX), as the sign is appended during encoding */ -#define COEF_LUT_TAB 2048 - /* The limited size resolution of each slice forces us to do this */ #define SSIZE_ROUND(b) (FFALIGN((b), s->size_scaler) + 4 + s->prefix_bytes) @@ -152,9 +148,8 @@ typedef struct VC2EncContext { uint8_t quant[MAX_DWT_LEVELS][4]; int custom_quant_matrix; - /* Coefficient LUT */ - uint32_t *coef_lut_val; - uint8_t *coef_lut_len; + /* Division LUT */ + uint32_t qmagic_lut[116][2]; int num_x; /* #slices horizontally */ int num_y; /* #slices vertically */ @@ -164,6 +159,7 @@ typedef struct VC2EncContext { int chroma_y_shift; /* Rate control stuff */ + int frame_max_bytes; int slice_max_bytes; int slice_min_bytes; int q_ceil; @@ -228,37 +224,6 @@ static av_always_inline int count_vc2_ue_uint(uint32_t val) return ff_log2(topbit)*2 + 1; } -static av_always_inline void get_vc2_ue_uint(int val, uint8_t *nbits, - uint32_t *eval) -{ - int i; - int pbits = 0, bits = 0, topbit = 1, maxval = 1; - - if (!val++) { - *nbits = 1; - *eval = 1; - return; - } - - while (val > maxval) { - topbit <<= 1; - maxval <<= 1; - maxval |= 1; - } - - bits = ff_log2(topbit); - - for (i = 0; i < bits; i++) { - topbit >>= 1; - pbits <<= 2; - if (val & topbit) - pbits |= 0x1; - } - - *nbits = bits*2 + 1; - *eval = (pbits << 1) | 1; -} - /* VC-2 10.4 - parse_info() */ static void encode_parse_info(VC2EncContext *s, enum DiracParseCodes pcode) { @@ -556,7 +521,7 @@ static void encode_picture_start(VC2EncContext *s) encode_wavelet_transform(s); } -#define QUANT(c, qf) (((c) << 2)/(qf)) +#define QUANT(c, mul, add, shift) (((mul) * (c) + (add)) >> (shift)) /* VC-2 13.5.5.2 - slice_band() */ static void encode_subband(VC2EncContext *s, PutBitContext *pb, int sx, int sy, @@ -569,24 +534,17 @@ static void encode_subband(VC2EncContext *s, PutBitContext *pb, int sx, int sy, const int top = b->height * (sy+0) / s->num_y; const int bottom = b->height * (sy+1) / s->num_y; - const int qfactor = ff_dirac_qscale_tab[quant]; - const uint8_t *len_lut = &s->coef_lut_len[quant*COEF_LUT_TAB]; - const uint32_t *val_lut = &s->coef_lut_val[quant*COEF_LUT_TAB]; - dwtcoef *coeff = b->buf + top * b->stride; + const uint64_t q_m = ((uint64_t)(s->qmagic_lut[quant][0])) << 2; + const uint64_t q_a = s->qmagic_lut[quant][1]; + const int q_s = av_log2(ff_dirac_qscale_tab[quant]) + 32; for (y = top; y < bottom; y++) { for (x = left; x < right; x++) { - const int neg = coeff[x] < 0; - uint32_t c_abs = FFABS(coeff[x]); - if (c_abs < COEF_LUT_TAB) { - put_bits(pb, len_lut[c_abs], val_lut[c_abs] | neg); - } else { - c_abs = QUANT(c_abs, qfactor); - put_vc2_ue_uint(pb, c_abs); - if (c_abs) - put_bits(pb, 1, neg); - } + uint32_t c_abs = QUANT(FFABS(coeff[x]), q_m, q_a, q_s); + put_vc2_ue_uint(pb, c_abs); + if (c_abs) + put_bits(pb, 1, coeff[x] < 0); } coeff += b->stride; } @@ -618,8 +576,9 @@ static int count_hq_slice(SliceArgs *slice, int quant_idx) SubBand *b = &s->plane[p].band[level][orientation]; const int q_idx = quants[level][orientation]; - const uint8_t *len_lut = &s->coef_lut_len[q_idx*COEF_LUT_TAB]; - const int qfactor = ff_dirac_qscale_tab[q_idx]; + const uint64_t q_m = ((uint64_t)s->qmagic_lut[q_idx][0]) << 2; + const uint64_t q_a = s->qmagic_lut[q_idx][1]; + const int q_s = av_log2(ff_dirac_qscale_tab[q_idx]) + 32; const int left = b->width * slice->x / s->num_x; const int right = b->width *(slice->x+1) / s->num_x; @@ -630,14 +589,9 @@ static int count_hq_slice(SliceArgs *slice, int quant_idx) for (y = top; y < bottom; y++) { for (x = left; x < right; x++) { - uint32_t c_abs = FFABS(buf[x]); - if (c_abs < COEF_LUT_TAB) { - bits += len_lut[c_abs]; - } else { - c_abs = QUANT(c_abs, qfactor); - bits += count_vc2_ue_uint(c_abs); - bits += !!c_abs; - } + uint32_t c_abs = QUANT(FFABS(buf[x]), q_m, q_a, q_s); + bits += count_vc2_ue_uint(c_abs); + bits += !!c_abs; } buf += b->stride; } @@ -715,7 +669,7 @@ static int calc_slice_sizes(VC2EncContext *s) for (i = 0; i < s->num_x*s->num_y; i++) { SliceArgs *args = &enc_args[i]; - bytes_left += s->slice_max_bytes - args->bytes; + bytes_left += args->bytes; for (j = 0; j < slice_redist_range; j++) { if (args->bytes > bytes_top[j]) { bytes_top[j] = args->bytes; @@ -725,8 +679,10 @@ static int calc_slice_sizes(VC2EncContext *s) } } + bytes_left = s->frame_max_bytes - bytes_left; + /* Second pass - distribute leftover bytes */ - while (1) { + while (bytes_left > 0) { int distributed = 0; for (i = 0; i < slice_redist_range; i++) { SliceArgs *args; @@ -994,13 +950,13 @@ static av_cold int vc2_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, const AVFrame *frame, int *got_packet) { int ret = 0; - int sig_size = 256; + int slice_ceil, sig_size = 256; VC2EncContext *s = avctx->priv_data; const int bitexact = avctx->flags & AV_CODEC_FLAG_BITEXACT; const char *aux_data = bitexact ? "Lavc" : LIBAVCODEC_IDENT; const int aux_data_size = bitexact ? sizeof("Lavc") : sizeof(LIBAVCODEC_IDENT); const int header_size = 100 + aux_data_size; - int64_t max_frame_bytes, r_bitrate = avctx->bit_rate >> (s->interlaced); + int64_t r_bitrate = avctx->bit_rate >> (s->interlaced); s->avctx = avctx; s->size_scaler = 2; @@ -1009,18 +965,21 @@ static av_cold int vc2_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, s->next_parse_offset = 0; /* Rate control */ - max_frame_bytes = (av_rescale(r_bitrate, s->avctx->time_base.num, - s->avctx->time_base.den) >> 3) - header_size; - s->slice_max_bytes = av_rescale(max_frame_bytes, 1, s->num_x*s->num_y); + s->frame_max_bytes = (av_rescale(r_bitrate, s->avctx->time_base.num, + s->avctx->time_base.den) >> 3) - header_size; + s->slice_max_bytes = slice_ceil = av_rescale(s->frame_max_bytes, 1, s->num_x*s->num_y); /* Find an appropriate size scaler */ while (sig_size > 255) { int r_size = SSIZE_ROUND(s->slice_max_bytes); + if (r_size > slice_ceil) { + s->slice_max_bytes -= r_size - slice_ceil; + r_size = SSIZE_ROUND(s->slice_max_bytes); + } sig_size = r_size/s->size_scaler; /* Signalled slize size */ s->size_scaler <<= 1; } - s->slice_max_bytes = SSIZE_ROUND(s->slice_max_bytes); s->slice_min_bytes = s->slice_max_bytes - s->slice_max_bytes*(s->tolerance/100.0f); ret = encode_frame(s, avpkt, frame, aux_data, header_size, s->interlaced); @@ -1053,8 +1012,6 @@ static av_cold int vc2_encode_end(AVCodecContext *avctx) } av_freep(&s->slice_args); - av_freep(&s->coef_lut_len); - av_freep(&s->coef_lut_val); return 0; } @@ -1063,7 +1020,7 @@ static av_cold int vc2_encode_init(AVCodecContext *avctx) { Plane *p; SubBand *b; - int i, j, level, o, shift; + int i, level, o, shift, ret; const AVPixFmtDescriptor *fmt = av_pix_fmt_desc_get(avctx->pix_fmt); const int depth = fmt->comp[0].depth; VC2EncContext *s = avctx->priv_data; @@ -1138,7 +1095,9 @@ static av_cold int vc2_encode_init(AVCodecContext *avctx) } /* Chroma subsampling */ - avcodec_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_x_shift, &s->chroma_y_shift); + ret = av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_x_shift, &s->chroma_y_shift); + if (ret) + return ret; /* Bit depth and color range index */ if (depth == 8 && avctx->color_range == AVCOL_RANGE_JPEG) { @@ -1171,7 +1130,7 @@ static av_cold int vc2_encode_init(AVCodecContext *avctx) p->dwt_width = w = FFALIGN(p->width, (1 << s->wavelet_depth)); p->dwt_height = h = FFALIGN(p->height, (1 << s->wavelet_depth)); p->coef_stride = FFALIGN(p->dwt_width, 32); - p->coef_buf = av_malloc(p->coef_stride*p->dwt_height*sizeof(dwtcoef)); + p->coef_buf = av_mallocz(p->coef_stride*p->dwt_height*sizeof(dwtcoef)); if (!p->coef_buf) goto alloc_fail; for (level = s->wavelet_depth-1; level >= 0; level--) { @@ -1190,7 +1149,8 @@ static av_cold int vc2_encode_init(AVCodecContext *avctx) /* DWT init */ if (ff_vc2enc_init_transforms(&s->transform_args[i].t, s->plane[i].coef_stride, - s->plane[i].dwt_height)) + s->plane[i].dwt_height, + s->slice_width, s->slice_height)) goto alloc_fail; } @@ -1202,27 +1162,20 @@ static av_cold int vc2_encode_init(AVCodecContext *avctx) if (!s->slice_args) goto alloc_fail; - /* Lookup tables */ - s->coef_lut_len = av_malloc(COEF_LUT_TAB*(s->q_ceil+1)*sizeof(*s->coef_lut_len)); - if (!s->coef_lut_len) - goto alloc_fail; - - s->coef_lut_val = av_malloc(COEF_LUT_TAB*(s->q_ceil+1)*sizeof(*s->coef_lut_val)); - if (!s->coef_lut_val) - goto alloc_fail; - - for (i = 0; i < s->q_ceil; i++) { - uint8_t *len_lut = &s->coef_lut_len[i*COEF_LUT_TAB]; - uint32_t *val_lut = &s->coef_lut_val[i*COEF_LUT_TAB]; - for (j = 0; j < COEF_LUT_TAB; j++) { - get_vc2_ue_uint(QUANT(j, ff_dirac_qscale_tab[i]), - &len_lut[j], &val_lut[j]); - if (len_lut[j] != 1) { - len_lut[j] += 1; - val_lut[j] <<= 1; - } else { - val_lut[j] = 1; - } + for (i = 0; i < 116; i++) { + const uint64_t qf = ff_dirac_qscale_tab[i]; + const uint32_t m = av_log2(qf); + const uint32_t t = (1ULL << (m + 32)) / qf; + const uint32_t r = (t*qf + qf) & UINT32_MAX; + if (!(qf & (qf - 1))) { + s->qmagic_lut[i][0] = 0xFFFFFFFF; + s->qmagic_lut[i][1] = 0xFFFFFFFF; + } else if (r <= 1 << m) { + s->qmagic_lut[i][0] = t + 1; + s->qmagic_lut[i][1] = 0; + } else { + s->qmagic_lut[i][0] = t; + s->qmagic_lut[i][1] = t; } } diff --git a/libavcodec/vc2enc_dwt.c b/libavcodec/vc2enc_dwt.c index c60b003a31303..d22af8a31380b 100644 --- a/libavcodec/vc2enc_dwt.c +++ b/libavcodec/vc2enc_dwt.c @@ -255,21 +255,27 @@ static void vc2_subband_dwt_haar_shift(VC2TransformContext *t, dwtcoef *data, dwt_haar(t, data, stride, width, height, 1); } -av_cold int ff_vc2enc_init_transforms(VC2TransformContext *s, int p_width, int p_height) +av_cold int ff_vc2enc_init_transforms(VC2TransformContext *s, int p_stride, + int p_height, int slice_w, int slice_h) { s->vc2_subband_dwt[VC2_TRANSFORM_9_7] = vc2_subband_dwt_97; s->vc2_subband_dwt[VC2_TRANSFORM_5_3] = vc2_subband_dwt_53; s->vc2_subband_dwt[VC2_TRANSFORM_HAAR] = vc2_subband_dwt_haar; s->vc2_subband_dwt[VC2_TRANSFORM_HAAR_S] = vc2_subband_dwt_haar_shift; - s->buffer = av_malloc(2*p_width*p_height*sizeof(dwtcoef)); + /* Pad by the slice size, only matters for non-Haar wavelets */ + s->buffer = av_calloc((p_stride + slice_w)*(p_height + slice_h), sizeof(dwtcoef)); if (!s->buffer) return 1; + s->padding = (slice_h >> 1)*p_stride + (slice_w >> 1); + s->buffer += s->padding; + return 0; } av_cold void ff_vc2enc_free_transforms(VC2TransformContext *s) { - av_freep(&s->buffer); + av_free(s->buffer - s->padding); + s->buffer = NULL; } diff --git a/libavcodec/vc2enc_dwt.h b/libavcodec/vc2enc_dwt.h index 7fbbfbe0ed9cf..a6932bcdaf096 100644 --- a/libavcodec/vc2enc_dwt.h +++ b/libavcodec/vc2enc_dwt.h @@ -41,12 +41,14 @@ enum VC2TransformType { typedef struct VC2TransformContext { dwtcoef *buffer; + int padding; void (*vc2_subband_dwt[VC2_TRANSFORMS_NB])(struct VC2TransformContext *t, dwtcoef *data, ptrdiff_t stride, int width, int height); } VC2TransformContext; -int ff_vc2enc_init_transforms(VC2TransformContext *t, int p_width, int p_height); +int ff_vc2enc_init_transforms(VC2TransformContext *t, int p_stride, int p_height, + int slice_w, int slice_h); void ff_vc2enc_free_transforms(VC2TransformContext *t); #endif /* AVCODEC_VC2ENC_DWT_H */ diff --git a/libavcodec/vda.c b/libavcodec/vda.c deleted file mode 100644 index 819ae030b03fd..0000000000000 --- a/libavcodec/vda.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" - -#include "libavutil/mem.h" - -#include "vda.h" -#include "vda_vt_internal.h" - -#if CONFIG_H264_VDA_HWACCEL -AVVDAContext *av_vda_alloc_context(void) -{ - AVVDAContext *ret = av_mallocz(sizeof(*ret)); - - if (ret) { - ret->output_callback = ff_vda_output_callback; - ret->cv_pix_fmt_type = kCVPixelFormatType_422YpCbCr8; - } - - return ret; -} - -int av_vda_default_init(AVCodecContext *avctx) -{ - return av_vda_default_init2(avctx, NULL); -} - -int av_vda_default_init2(AVCodecContext *avctx, AVVDAContext *vdactx) -{ - avctx->hwaccel_context = vdactx ?: av_vda_alloc_context(); - if (!avctx->hwaccel_context) - return AVERROR(ENOMEM); - return ff_vda_default_init(avctx); -} - -void av_vda_default_free(AVCodecContext *avctx) -{ - ff_vda_default_free(avctx); - av_freep(&avctx->hwaccel_context); -} - -void ff_vda_default_free(AVCodecContext *avctx) -{ - AVVDAContext *vda = avctx->hwaccel_context; - if (vda && vda->decoder) - VDADecoderDestroy(vda->decoder); -} - -#else -AVVDAContext *av_vda_alloc_context(void) -{ - return NULL; -} - -int av_vda_default_init(AVCodecContext *avctx) -{ - return AVERROR(ENOSYS); -} - -int av_vda_default_init2(AVCodecContext *avctx, AVVDAContext *vdactx) -{ - return AVERROR(ENOSYS); -} - -void av_vda_default_free(AVCodecContext *ctx) -{ -} -#endif diff --git a/libavcodec/vda.h b/libavcodec/vda.h deleted file mode 100644 index bde14e31d7dfd..0000000000000 --- a/libavcodec/vda.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - * VDA HW acceleration - * - * copyright (c) 2011 Sebastien Zwickert - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVCODEC_VDA_H -#define AVCODEC_VDA_H - -/** - * @file - * @ingroup lavc_codec_hwaccel_vda - * Public libavcodec VDA header. - */ - -#include "libavcodec/avcodec.h" - -#include - -// emmintrin.h is unable to compile with -std=c99 -Werror=missing-prototypes -// http://openradar.appspot.com/8026390 -#undef __GNUC_STDC_INLINE__ - -#define Picture QuickdrawPicture -#include -#undef Picture - -#include "libavcodec/version.h" - -// extra flags not defined in VDADecoder.h -enum { - kVDADecodeInfo_Asynchronous = 1UL << 0, - kVDADecodeInfo_FrameDropped = 1UL << 1 -}; - -/** - * @defgroup lavc_codec_hwaccel_vda VDA - * @ingroup lavc_codec_hwaccel - * - * @{ - */ - -/** - * This structure is used to provide the necessary configurations and data - * to the VDA FFmpeg HWAccel implementation. - * - * The application must make it available as AVCodecContext.hwaccel_context. - */ -struct vda_context { - /** - * VDA decoder object. - * - * - encoding: unused - * - decoding: Set/Unset by libavcodec. - */ - VDADecoder decoder; - - /** - * The Core Video pixel buffer that contains the current image data. - * - * encoding: unused - * decoding: Set by libavcodec. Unset by user. - */ - CVPixelBufferRef cv_buffer; - - /** - * Use the hardware decoder in synchronous mode. - * - * encoding: unused - * decoding: Set by user. - */ - int use_sync_decoding; - - /** - * The frame width. - * - * - encoding: unused - * - decoding: Set/Unset by user. - */ - int width; - - /** - * The frame height. - * - * - encoding: unused - * - decoding: Set/Unset by user. - */ - int height; - - /** - * The frame format. - * - * - encoding: unused - * - decoding: Set/Unset by user. - */ - int format; - - /** - * The pixel format for output image buffers. - * - * - encoding: unused - * - decoding: Set/Unset by user. - */ - OSType cv_pix_fmt_type; - - /** - * unused - */ - uint8_t *priv_bitstream; - - /** - * unused - */ - int priv_bitstream_size; - - /** - * unused - */ - int priv_allocated_size; - - /** - * Use av_buffer to manage buffer. - * When the flag is set, the CVPixelBuffers returned by the decoder will - * be released automatically, so you have to retain them if necessary. - * Not setting this flag may cause memory leak. - * - * encoding: unused - * decoding: Set by user. - */ - int use_ref_buffer; -}; - -/** Create the video decoder. */ -int ff_vda_create_decoder(struct vda_context *vda_ctx, - uint8_t *extradata, - int extradata_size); - -/** Destroy the video decoder. */ -int ff_vda_destroy_decoder(struct vda_context *vda_ctx); - -/** - * This struct holds all the information that needs to be passed - * between the caller and libavcodec for initializing VDA decoding. - * Its size is not a part of the public ABI, it must be allocated with - * av_vda_alloc_context() and freed with av_free(). - */ -typedef struct AVVDAContext { - /** - * VDA decoder object. Created and freed by the caller. - */ - VDADecoder decoder; - - /** - * The output callback that must be passed to VDADecoderCreate. - * Set by av_vda_alloc_context(). - */ - VDADecoderOutputCallback output_callback; - - /** - * CVPixelBuffer Format Type that VDA will use for decoded frames; set by - * the caller. - */ - OSType cv_pix_fmt_type; -} AVVDAContext; - -/** - * Allocate and initialize a VDA context. - * - * This function should be called from the get_format() callback when the caller - * selects the AV_PIX_FMT_VDA format. The caller must then create the decoder - * object (using the output callback provided by libavcodec) that will be used - * for VDA-accelerated decoding. - * - * When decoding with VDA is finished, the caller must destroy the decoder - * object and free the VDA context using av_free(). - * - * @return the newly allocated context or NULL on failure - */ -AVVDAContext *av_vda_alloc_context(void); - -/** - * This is a convenience function that creates and sets up the VDA context using - * an internal implementation. - * - * @param avctx the corresponding codec context - * - * @return >= 0 on success, a negative AVERROR code on failure - */ -int av_vda_default_init(AVCodecContext *avctx); - -/** - * This is a convenience function that creates and sets up the VDA context using - * an internal implementation. - * - * @param avctx the corresponding codec context - * @param vdactx the VDA context to use - * - * @return >= 0 on success, a negative AVERROR code on failure - */ -int av_vda_default_init2(AVCodecContext *avctx, AVVDAContext *vdactx); - -/** - * This function must be called to free the VDA context initialized with - * av_vda_default_init(). - * - * @param avctx the corresponding codec context - */ -void av_vda_default_free(AVCodecContext *avctx); - -/** - * @} - */ - -#endif /* AVCODEC_VDA_H */ diff --git a/libavcodec/vda_h264.c b/libavcodec/vda_h264.c deleted file mode 100644 index 7b88ec7015f54..0000000000000 --- a/libavcodec/vda_h264.c +++ /dev/null @@ -1,425 +0,0 @@ -/* - * VDA H264 HW acceleration. - * - * copyright (c) 2011 Sebastien Zwickert - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include - -#include "vda.h" -#include "libavutil/avutil.h" -#include "h264dec.h" - -struct vda_buffer { - CVPixelBufferRef cv_buffer; -}; -#include "internal.h" -#include "vda_vt_internal.h" - -/* Decoder callback that adds the vda frame to the queue in display order. */ -static void vda_decoder_callback(void *vda_hw_ctx, - CFDictionaryRef user_info, - OSStatus status, - uint32_t infoFlags, - CVImageBufferRef image_buffer) -{ - struct vda_context *vda_ctx = vda_hw_ctx; - - if (infoFlags & kVDADecodeInfo_FrameDropped) - vda_ctx->cv_buffer = NULL; - - if (!image_buffer) - return; - - if (vda_ctx->cv_pix_fmt_type != CVPixelBufferGetPixelFormatType(image_buffer)) - return; - - vda_ctx->cv_buffer = CVPixelBufferRetain(image_buffer); -} - -static int vda_sync_decode(VTContext *ctx, struct vda_context *vda_ctx) -{ - OSStatus status; - CFDataRef coded_frame; - uint32_t flush_flags = 1 << 0; ///< kVDADecoderFlush_emitFrames - - coded_frame = CFDataCreate(kCFAllocatorDefault, - ctx->bitstream, - ctx->bitstream_size); - - status = VDADecoderDecode(vda_ctx->decoder, 0, coded_frame, NULL); - - if (kVDADecoderNoErr == status) - status = VDADecoderFlush(vda_ctx->decoder, flush_flags); - - CFRelease(coded_frame); - - return status; -} - - -static int vda_old_h264_start_frame(AVCodecContext *avctx, - av_unused const uint8_t *buffer, - av_unused uint32_t size) -{ - VTContext *vda = avctx->internal->hwaccel_priv_data; - struct vda_context *vda_ctx = avctx->hwaccel_context; - - if (!vda_ctx->decoder) - return -1; - - vda->bitstream_size = 0; - - return 0; -} - -static int vda_old_h264_decode_slice(AVCodecContext *avctx, - const uint8_t *buffer, - uint32_t size) -{ - VTContext *vda = avctx->internal->hwaccel_priv_data; - struct vda_context *vda_ctx = avctx->hwaccel_context; - void *tmp; - - if (!vda_ctx->decoder) - return -1; - - tmp = av_fast_realloc(vda->bitstream, - &vda->allocated_size, - vda->bitstream_size + size + 4); - if (!tmp) - return AVERROR(ENOMEM); - - vda->bitstream = tmp; - - AV_WB32(vda->bitstream + vda->bitstream_size, size); - memcpy(vda->bitstream + vda->bitstream_size + 4, buffer, size); - - vda->bitstream_size += size + 4; - - return 0; -} - -static void vda_h264_release_buffer(void *opaque, uint8_t *data) -{ - struct vda_buffer *context = opaque; - CVPixelBufferRelease(context->cv_buffer); - av_free(context); -} - -static int vda_old_h264_end_frame(AVCodecContext *avctx) -{ - H264Context *h = avctx->priv_data; - VTContext *vda = avctx->internal->hwaccel_priv_data; - struct vda_context *vda_ctx = avctx->hwaccel_context; - AVFrame *frame = h->cur_pic_ptr->f; - struct vda_buffer *context; - AVBufferRef *buffer; - int status; - - if (!vda_ctx->decoder || !vda->bitstream) - return -1; - - status = vda_sync_decode(vda, vda_ctx); - frame->data[3] = (void*)vda_ctx->cv_buffer; - - if (status) - av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status); - - if (!vda_ctx->use_ref_buffer || status) - return status; - - context = av_mallocz(sizeof(*context)); - buffer = av_buffer_create(NULL, 0, vda_h264_release_buffer, context, 0); - if (!context || !buffer) { - CVPixelBufferRelease(vda_ctx->cv_buffer); - av_free(context); - return -1; - } - - context->cv_buffer = vda_ctx->cv_buffer; - frame->buf[3] = buffer; - - return status; -} - -int ff_vda_create_decoder(struct vda_context *vda_ctx, - uint8_t *extradata, - int extradata_size) -{ - OSStatus status; - CFNumberRef height; - CFNumberRef width; - CFNumberRef format; - CFDataRef avc_data; - CFMutableDictionaryRef config_info; - CFMutableDictionaryRef buffer_attributes; - CFMutableDictionaryRef io_surface_properties; - CFNumberRef cv_pix_fmt; - - vda_ctx->priv_bitstream = NULL; - vda_ctx->priv_allocated_size = 0; - - /* Each VCL NAL in the bitstream sent to the decoder - * is preceded by a 4 bytes length header. - * Change the avcC atom header if needed, to signal headers of 4 bytes. */ - if (extradata_size >= 4 && (extradata[4] & 0x03) != 0x03) { - uint8_t *rw_extradata; - - if (!(rw_extradata = av_malloc(extradata_size))) - return AVERROR(ENOMEM); - - memcpy(rw_extradata, extradata, extradata_size); - - rw_extradata[4] |= 0x03; - - avc_data = CFDataCreate(kCFAllocatorDefault, rw_extradata, extradata_size); - - av_freep(&rw_extradata); - } else { - avc_data = CFDataCreate(kCFAllocatorDefault, extradata, extradata_size); - } - - config_info = CFDictionaryCreateMutable(kCFAllocatorDefault, - 4, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - height = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->height); - width = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->width); - format = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vda_ctx->format); - - CFDictionarySetValue(config_info, kVDADecoderConfiguration_Height, height); - CFDictionarySetValue(config_info, kVDADecoderConfiguration_Width, width); - CFDictionarySetValue(config_info, kVDADecoderConfiguration_SourceFormat, format); - CFDictionarySetValue(config_info, kVDADecoderConfiguration_avcCData, avc_data); - - buffer_attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, - 2, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - io_surface_properties = CFDictionaryCreateMutable(kCFAllocatorDefault, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - cv_pix_fmt = CFNumberCreate(kCFAllocatorDefault, - kCFNumberSInt32Type, - &vda_ctx->cv_pix_fmt_type); - CFDictionarySetValue(buffer_attributes, - kCVPixelBufferPixelFormatTypeKey, - cv_pix_fmt); - CFDictionarySetValue(buffer_attributes, - kCVPixelBufferIOSurfacePropertiesKey, - io_surface_properties); - - status = VDADecoderCreate(config_info, - buffer_attributes, - (VDADecoderOutputCallback *)vda_decoder_callback, - vda_ctx, - &vda_ctx->decoder); - - CFRelease(height); - CFRelease(width); - CFRelease(format); - CFRelease(avc_data); - CFRelease(config_info); - CFRelease(io_surface_properties); - CFRelease(cv_pix_fmt); - CFRelease(buffer_attributes); - - return status; -} - -int ff_vda_destroy_decoder(struct vda_context *vda_ctx) -{ - OSStatus status = kVDADecoderNoErr; - - if (vda_ctx->decoder) - status = VDADecoderDestroy(vda_ctx->decoder); - - return status; -} - -AVHWAccel ff_h264_vda_old_hwaccel = { - .name = "h264_vda", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_H264, - .pix_fmt = AV_PIX_FMT_VDA_VLD, - .start_frame = vda_old_h264_start_frame, - .decode_slice = vda_old_h264_decode_slice, - .end_frame = vda_old_h264_end_frame, - .uninit = ff_videotoolbox_uninit, - .priv_data_size = sizeof(VTContext), -}; - -void ff_vda_output_callback(void *opaque, - CFDictionaryRef user_info, - OSStatus status, - uint32_t infoFlags, - CVImageBufferRef image_buffer) -{ - AVCodecContext *ctx = opaque; - VTContext *vda = ctx->internal->hwaccel_priv_data; - - - if (vda->frame) { - CVPixelBufferRelease(vda->frame); - vda->frame = NULL; - } - - if (!image_buffer) - return; - - vda->frame = CVPixelBufferRetain(image_buffer); -} - -static int vda_h264_end_frame(AVCodecContext *avctx) -{ - H264Context *h = avctx->priv_data; - VTContext *vda = avctx->internal->hwaccel_priv_data; - AVVDAContext *vda_ctx = avctx->hwaccel_context; - AVFrame *frame = h->cur_pic_ptr->f; - uint32_t flush_flags = 1 << 0; ///< kVDADecoderFlush_emitFrames - CFDataRef coded_frame; - OSStatus status; - - if (!vda->bitstream_size) - return AVERROR_INVALIDDATA; - - - coded_frame = CFDataCreate(kCFAllocatorDefault, - vda->bitstream, - vda->bitstream_size); - - status = VDADecoderDecode(vda_ctx->decoder, 0, coded_frame, NULL); - - if (status == kVDADecoderNoErr) - status = VDADecoderFlush(vda_ctx->decoder, flush_flags); - - CFRelease(coded_frame); - - if (!vda->frame) - return AVERROR_UNKNOWN; - - if (status != kVDADecoderNoErr) { - av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status); - return AVERROR_UNKNOWN; - } - - return ff_videotoolbox_buffer_create(vda, frame); -} - -int ff_vda_default_init(AVCodecContext *avctx) -{ - AVVDAContext *vda_ctx = avctx->hwaccel_context; - OSStatus status = kVDADecoderNoErr; - CFNumberRef height; - CFNumberRef width; - CFNumberRef format; - CFDataRef avc_data; - CFMutableDictionaryRef config_info; - CFMutableDictionaryRef buffer_attributes; - CFMutableDictionaryRef io_surface_properties; - CFNumberRef cv_pix_fmt; - int32_t fmt = 'avc1', pix_fmt = vda_ctx->cv_pix_fmt_type; - - // kCVPixelFormatType_420YpCbCr8Planar; - - avc_data = ff_videotoolbox_avcc_extradata_create(avctx); - - config_info = CFDictionaryCreateMutable(kCFAllocatorDefault, - 4, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - height = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &avctx->height); - width = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &avctx->width); - format = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &fmt); - CFDictionarySetValue(config_info, kVDADecoderConfiguration_Height, height); - CFDictionarySetValue(config_info, kVDADecoderConfiguration_Width, width); - CFDictionarySetValue(config_info, kVDADecoderConfiguration_avcCData, avc_data); - CFDictionarySetValue(config_info, kVDADecoderConfiguration_SourceFormat, format); - - buffer_attributes = CFDictionaryCreateMutable(kCFAllocatorDefault, - 2, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - io_surface_properties = CFDictionaryCreateMutable(kCFAllocatorDefault, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - cv_pix_fmt = CFNumberCreate(kCFAllocatorDefault, - kCFNumberSInt32Type, - &pix_fmt); - - CFDictionarySetValue(buffer_attributes, - kCVPixelBufferPixelFormatTypeKey, - cv_pix_fmt); - CFDictionarySetValue(buffer_attributes, - kCVPixelBufferIOSurfacePropertiesKey, - io_surface_properties); - - status = VDADecoderCreate(config_info, - buffer_attributes, - (VDADecoderOutputCallback *)ff_vda_output_callback, - avctx, - &vda_ctx->decoder); - - CFRelease(format); - CFRelease(height); - CFRelease(width); - CFRelease(avc_data); - CFRelease(config_info); - CFRelease(cv_pix_fmt); - CFRelease(io_surface_properties); - CFRelease(buffer_attributes); - - if (status != kVDADecoderNoErr) { - av_log(avctx, AV_LOG_ERROR, "Cannot initialize VDA %d\n", status); - } - - switch (status) { - case kVDADecoderHardwareNotSupportedErr: - case kVDADecoderFormatNotSupportedErr: - return AVERROR(ENOSYS); - case kVDADecoderConfigurationError: - return AVERROR(EINVAL); - case kVDADecoderDecoderFailedErr: - return AVERROR_INVALIDDATA; - case kVDADecoderNoErr: - return 0; - default: - return AVERROR_UNKNOWN; - } -} - -AVHWAccel ff_h264_vda_hwaccel = { - .name = "h264_vda", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_H264, - .pix_fmt = AV_PIX_FMT_VDA, - .alloc_frame = ff_videotoolbox_alloc_frame, - .start_frame = ff_videotoolbox_h264_start_frame, - .decode_slice = ff_videotoolbox_h264_decode_slice, - .end_frame = vda_h264_end_frame, - .uninit = ff_videotoolbox_uninit, - .priv_data_size = sizeof(VTContext), -}; diff --git a/libavcodec/vda_h264_dec.c b/libavcodec/vda_h264_dec.c deleted file mode 100644 index 972bd6bbd6441..0000000000000 --- a/libavcodec/vda_h264_dec.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (c) 2012, Xidorn Quan - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file - * H.264 decoder via VDA - * @author Xidorn Quan - */ - -#include -#include - -#include "vda.h" -#include "h264dec.h" -#include "avcodec.h" - -#ifndef kCFCoreFoundationVersionNumber10_7 -#define kCFCoreFoundationVersionNumber10_7 635.00 -#endif - -extern AVCodec ff_h264_decoder, ff_h264_vda_decoder; - -static const enum AVPixelFormat vda_pixfmts_prior_10_7[] = { - AV_PIX_FMT_UYVY422, - AV_PIX_FMT_YUV420P, - AV_PIX_FMT_NONE -}; - -static const enum AVPixelFormat vda_pixfmts[] = { - AV_PIX_FMT_UYVY422, - AV_PIX_FMT_YUYV422, - AV_PIX_FMT_NV12, - AV_PIX_FMT_YUV420P, - AV_PIX_FMT_NONE -}; - -typedef struct { - H264Context h264ctx; - int h264_initialized; - struct vda_context vda_ctx; - enum AVPixelFormat pix_fmt; - - /* for backing-up fields set by user. - * we have to gain full control of such fields here */ - void *hwaccel_context; - enum AVPixelFormat (*get_format)(struct AVCodecContext *s, const enum AVPixelFormat * fmt); - int (*get_buffer2)(struct AVCodecContext *s, AVFrame *frame, int flags); -} VDADecoderContext; - -static enum AVPixelFormat get_format(struct AVCodecContext *avctx, - const enum AVPixelFormat *fmt) -{ - return AV_PIX_FMT_VDA_VLD; -} - -typedef struct { - CVPixelBufferRef cv_buffer; -} VDABufferContext; - -static void release_buffer(void *opaque, uint8_t *data) -{ - VDABufferContext *context = opaque; - CVPixelBufferUnlockBaseAddress(context->cv_buffer, 0); - CVPixelBufferRelease(context->cv_buffer); - av_free(context); -} - -static int get_buffer2(AVCodecContext *avctx, AVFrame *pic, int flag) -{ - VDABufferContext *context = av_mallocz(sizeof(VDABufferContext)); - AVBufferRef *buffer = av_buffer_create(NULL, 0, release_buffer, context, 0); - if (!context || !buffer) { - av_free(context); - return AVERROR(ENOMEM); - } - - pic->buf[0] = buffer; - pic->data[0] = (void *)1; - return 0; -} - -static inline void set_context(AVCodecContext *avctx) -{ - VDADecoderContext *ctx = avctx->priv_data; - ctx->hwaccel_context = avctx->hwaccel_context; - avctx->hwaccel_context = &ctx->vda_ctx; - ctx->get_format = avctx->get_format; - avctx->get_format = get_format; - ctx->get_buffer2 = avctx->get_buffer2; - avctx->get_buffer2 = get_buffer2; -} - -static inline void restore_context(AVCodecContext *avctx) -{ - VDADecoderContext *ctx = avctx->priv_data; - avctx->hwaccel_context = ctx->hwaccel_context; - avctx->get_format = ctx->get_format; - avctx->get_buffer2 = ctx->get_buffer2; -} - -static int vdadec_decode(AVCodecContext *avctx, - void *data, int *got_frame, AVPacket *avpkt) -{ - VDADecoderContext *ctx = avctx->priv_data; - AVFrame *pic = data; - int ret; - - set_context(avctx); - ret = ff_h264_decoder.decode(avctx, data, got_frame, avpkt); - restore_context(avctx); - if (*got_frame) { - AVBufferRef *buffer = pic->buf[0]; - VDABufferContext *context = av_buffer_get_opaque(buffer); - CVPixelBufferRef cv_buffer = (CVPixelBufferRef)pic->data[3]; - - CVPixelBufferRetain(cv_buffer); - CVPixelBufferLockBaseAddress(cv_buffer, 0); - context->cv_buffer = cv_buffer; - pic->format = ctx->pix_fmt; - if (CVPixelBufferIsPlanar(cv_buffer)) { - int i, count = CVPixelBufferGetPlaneCount(cv_buffer); - av_assert0(count < 4); - for (i = 0; i < count; i++) { - pic->data[i] = CVPixelBufferGetBaseAddressOfPlane(cv_buffer, i); - pic->linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(cv_buffer, i); - } - } else { - pic->data[0] = CVPixelBufferGetBaseAddress(cv_buffer); - pic->linesize[0] = CVPixelBufferGetBytesPerRow(cv_buffer); - } - } - avctx->pix_fmt = ctx->pix_fmt; - - return ret; -} - -static av_cold int vdadec_close(AVCodecContext *avctx) -{ - VDADecoderContext *ctx = avctx->priv_data; - /* release buffers and decoder */ - ff_vda_destroy_decoder(&ctx->vda_ctx); - /* close H.264 decoder */ - if (ctx->h264_initialized) { - set_context(avctx); - ff_h264_decoder.close(avctx); - restore_context(avctx); - } - return 0; -} - -static av_cold int vdadec_init(AVCodecContext *avctx) -{ - VDADecoderContext *ctx = avctx->priv_data; - struct vda_context *vda_ctx = &ctx->vda_ctx; - OSStatus status; - int ret, i; - - ctx->h264_initialized = 0; - - /* init pix_fmts of codec */ - if (!ff_h264_vda_decoder.pix_fmts) { - if (kCFCoreFoundationVersionNumber < kCFCoreFoundationVersionNumber10_7) - ff_h264_vda_decoder.pix_fmts = vda_pixfmts_prior_10_7; - else - ff_h264_vda_decoder.pix_fmts = vda_pixfmts; - } - - /* init vda */ - memset(vda_ctx, 0, sizeof(struct vda_context)); - vda_ctx->width = avctx->width; - vda_ctx->height = avctx->height; - vda_ctx->format = 'avc1'; - vda_ctx->use_sync_decoding = 1; - vda_ctx->use_ref_buffer = 1; - ctx->pix_fmt = avctx->get_format(avctx, avctx->codec->pix_fmts); - switch (ctx->pix_fmt) { - case AV_PIX_FMT_UYVY422: - vda_ctx->cv_pix_fmt_type = '2vuy'; - break; - case AV_PIX_FMT_YUYV422: - vda_ctx->cv_pix_fmt_type = 'yuvs'; - break; - case AV_PIX_FMT_NV12: - vda_ctx->cv_pix_fmt_type = '420v'; - break; - case AV_PIX_FMT_YUV420P: - vda_ctx->cv_pix_fmt_type = 'y420'; - break; - default: - av_log(avctx, AV_LOG_ERROR, "Unsupported pixel format: %d\n", avctx->pix_fmt); - goto failed; - } - status = ff_vda_create_decoder(vda_ctx, - avctx->extradata, avctx->extradata_size); - if (status != kVDADecoderNoErr) { - av_log(avctx, AV_LOG_ERROR, - "Failed to init VDA decoder: %d.\n", status); - goto failed; - } - - /* init H.264 decoder */ - set_context(avctx); - ret = ff_h264_decoder.init(avctx); - restore_context(avctx); - if (ret < 0) { - av_log(avctx, AV_LOG_ERROR, "Failed to open H.264 decoder.\n"); - goto failed; - } - ctx->h264_initialized = 1; - - for (i = 0; i < MAX_SPS_COUNT; i++) { - const SPS *sps = ctx->h264ctx.ps.sps_list[i] ? (const SPS*)ctx->h264ctx.ps.sps_list[i]->data : NULL; - if (sps && (sps->bit_depth_luma != 8 || - sps->chroma_format_idc == 2 || - sps->chroma_format_idc == 3)) { - av_log(avctx, AV_LOG_ERROR, "Format is not supported.\n"); - goto failed; - } - } - - return 0; - -failed: - vdadec_close(avctx); - return -1; -} - -static void vdadec_flush(AVCodecContext *avctx) -{ - set_context(avctx); - ff_h264_decoder.flush(avctx); - restore_context(avctx); -} - -AVCodec ff_h264_vda_decoder = { - .name = "h264_vda", - .type = AVMEDIA_TYPE_VIDEO, - .id = AV_CODEC_ID_H264, - .priv_data_size = sizeof(VDADecoderContext), - .init = vdadec_init, - .close = vdadec_close, - .decode = vdadec_decode, - .capabilities = AV_CODEC_CAP_DELAY, - .flush = vdadec_flush, - .long_name = NULL_IF_CONFIG_SMALL("H.264 (VDA acceleration)"), -}; diff --git a/libavcodec/vdpau.c b/libavcodec/vdpau.c index 42ebddbeeee2e..1b2ec989cda47 100644 --- a/libavcodec/vdpau.c +++ b/libavcodec/vdpau.c @@ -24,23 +24,15 @@ #include #include "avcodec.h" +#include "decode.h" #include "internal.h" #include "h264dec.h" #include "vc1.h" #include "vdpau.h" -#include "vdpau_compat.h" #include "vdpau_internal.h" // XXX: at the time of adding this ifdefery, av_assert* wasn't use outside. // When dropping it, make sure other av_assert* were not added since then. -#if FF_API_BUFS_VDPAU -#include "libavutil/avassert.h" -#endif - -#if FF_API_VDPAU -#undef NDEBUG -#include -#endif /** * @addtogroup VDPAU_Decoding @@ -119,6 +111,25 @@ int av_vdpau_get_surface_parameters(AVCodecContext *avctx, return 0; } +int ff_vdpau_common_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx) +{ + AVHWFramesContext *hw_frames = (AVHWFramesContext*)hw_frames_ctx->data; + VdpChromaType type; + uint32_t width; + uint32_t height; + + if (av_vdpau_get_surface_parameters(avctx, &type, &width, &height)) + return AVERROR(EINVAL); + + hw_frames->format = AV_PIX_FMT_VDPAU; + hw_frames->sw_format = avctx->sw_pix_fmt; + hw_frames->width = width; + hw_frames->height = height; + + return 0; +} + int ff_vdpau_common_init(AVCodecContext *avctx, VdpDecoderProfile profile, int level) { @@ -136,6 +147,7 @@ int ff_vdpau_common_init(AVCodecContext *avctx, VdpDecoderProfile profile, VdpChromaType type; uint32_t width; uint32_t height; + int ret; vdctx->width = UINT32_MAX; vdctx->height = UINT32_MAX; @@ -163,41 +175,14 @@ int ff_vdpau_common_init(AVCodecContext *avctx, VdpDecoderProfile profile, type != VDP_CHROMA_TYPE_420) return AVERROR(ENOSYS); } else { - AVHWFramesContext *frames_ctx = NULL; + AVHWFramesContext *frames_ctx; AVVDPAUDeviceContext *dev_ctx; - // We assume the hw_frames_ctx always survives until ff_vdpau_common_uninit - // is called. This holds true as the user is not allowed to touch - // hw_device_ctx, or hw_frames_ctx after get_format (and ff_get_format - // itself also uninits before unreffing hw_frames_ctx). - if (avctx->hw_frames_ctx) { - frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; - } else if (avctx->hw_device_ctx) { - int ret; - - avctx->hw_frames_ctx = av_hwframe_ctx_alloc(avctx->hw_device_ctx); - if (!avctx->hw_frames_ctx) - return AVERROR(ENOMEM); - - frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; - frames_ctx->format = AV_PIX_FMT_VDPAU; - frames_ctx->sw_format = avctx->sw_pix_fmt; - frames_ctx->width = avctx->coded_width; - frames_ctx->height = avctx->coded_height; - - ret = av_hwframe_ctx_init(avctx->hw_frames_ctx); - if (ret < 0) { - av_buffer_unref(&avctx->hw_frames_ctx); - return ret; - } - } - - if (!frames_ctx) { - av_log(avctx, AV_LOG_ERROR, "A hardware frames context is " - "required for VDPAU decoding.\n"); - return AVERROR(EINVAL); - } + ret = ff_decode_get_hw_frames_ctx(avctx, AV_HWDEVICE_TYPE_VDPAU); + if (ret < 0) + return ret; + frames_ctx = (AVHWFramesContext*)avctx->hw_frames_ctx->data; dev_ctx = frames_ctx->device_ctx->hwctx; vdctx->device = dev_ctx->device; @@ -353,18 +338,6 @@ int ff_vdpau_common_end_frame(AVCodecContext *avctx, AVFrame *frame, if (val < 0) return val; -#if FF_API_BUFS_VDPAU -FF_DISABLE_DEPRECATION_WARNINGS - if (hwctx) { - av_assert0(sizeof(hwctx->info) <= sizeof(pic_ctx->info)); - memcpy(&hwctx->info, &pic_ctx->info, sizeof(hwctx->info)); - hwctx->bitstream_buffers = pic_ctx->bitstream_buffers; - hwctx->bitstream_buffers_used = pic_ctx->bitstream_buffers_used; - hwctx->bitstream_buffers_allocated = pic_ctx->bitstream_buffers_allocated; - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif - if (hwctx && !hwctx->render && hwctx->render2) { status = hwctx->render2(avctx, frame, (void *)&pic_ctx->info, pic_ctx->bitstream_buffers_used, pic_ctx->bitstream_buffers); @@ -375,16 +348,6 @@ FF_ENABLE_DEPRECATION_WARNINGS av_freep(&pic_ctx->bitstream_buffers); -#if FF_API_BUFS_VDPAU -FF_DISABLE_DEPRECATION_WARNINGS - if (hwctx) { - hwctx->bitstream_buffers = NULL; - hwctx->bitstream_buffers_used = 0; - hwctx->bitstream_buffers_allocated = 0; - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif - return vdpau_error(status); } @@ -426,345 +389,6 @@ int ff_vdpau_add_buffer(struct vdpau_picture_context *pic_ctx, return 0; } -/* Obsolete non-hwaccel VDPAU support below... */ - -#if FF_API_VDPAU -void ff_vdpau_add_data_chunk(uint8_t *data, const uint8_t *buf, int buf_size) -{ - struct vdpau_render_state *render = (struct vdpau_render_state*)data; - assert(render); - - render->bitstream_buffers= av_fast_realloc( - render->bitstream_buffers, - &render->bitstream_buffers_allocated, - sizeof(*render->bitstream_buffers)*(render->bitstream_buffers_used + 1) - ); - - render->bitstream_buffers[render->bitstream_buffers_used].struct_version = VDP_BITSTREAM_BUFFER_VERSION; - render->bitstream_buffers[render->bitstream_buffers_used].bitstream = buf; - render->bitstream_buffers[render->bitstream_buffers_used].bitstream_bytes = buf_size; - render->bitstream_buffers_used++; -} - -#if CONFIG_H264_VDPAU_DECODER -void ff_vdpau_h264_set_reference_frames(H264Context *h) -{ - struct vdpau_render_state *render, *render_ref; - VdpReferenceFrameH264 *rf, *rf2; - H264Picture *pic; - int i, list, pic_frame_idx; - - render = (struct vdpau_render_state *)h->cur_pic_ptr->f->data[0]; - assert(render); - - rf = &render->info.h264.referenceFrames[0]; -#define H264_RF_COUNT FF_ARRAY_ELEMS(render->info.h264.referenceFrames) - - for (list = 0; list < 2; ++list) { - H264Picture **lp = list ? h->long_ref : h->short_ref; - int ls = list ? 16 : h->short_ref_count; - - for (i = 0; i < ls; ++i) { - pic = lp[i]; - if (!pic || !pic->reference) - continue; - pic_frame_idx = pic->long_ref ? pic->pic_id : pic->frame_num; - - render_ref = (struct vdpau_render_state *)pic->f->data[0]; - assert(render_ref); - - rf2 = &render->info.h264.referenceFrames[0]; - while (rf2 != rf) { - if ( - (rf2->surface == render_ref->surface) - && (rf2->is_long_term == pic->long_ref) - && (rf2->frame_idx == pic_frame_idx) - ) - break; - ++rf2; - } - if (rf2 != rf) { - rf2->top_is_reference |= (pic->reference & PICT_TOP_FIELD) ? VDP_TRUE : VDP_FALSE; - rf2->bottom_is_reference |= (pic->reference & PICT_BOTTOM_FIELD) ? VDP_TRUE : VDP_FALSE; - continue; - } - - if (rf >= &render->info.h264.referenceFrames[H264_RF_COUNT]) - continue; - - rf->surface = render_ref->surface; - rf->is_long_term = pic->long_ref; - rf->top_is_reference = (pic->reference & PICT_TOP_FIELD) ? VDP_TRUE : VDP_FALSE; - rf->bottom_is_reference = (pic->reference & PICT_BOTTOM_FIELD) ? VDP_TRUE : VDP_FALSE; - rf->field_order_cnt[0] = pic->field_poc[0]; - rf->field_order_cnt[1] = pic->field_poc[1]; - rf->frame_idx = pic_frame_idx; - - ++rf; - } - } - - for (; rf < &render->info.h264.referenceFrames[H264_RF_COUNT]; ++rf) { - rf->surface = VDP_INVALID_HANDLE; - rf->is_long_term = 0; - rf->top_is_reference = 0; - rf->bottom_is_reference = 0; - rf->field_order_cnt[0] = 0; - rf->field_order_cnt[1] = 0; - rf->frame_idx = 0; - } -} - -void ff_vdpau_h264_picture_start(H264Context *h) -{ - struct vdpau_render_state *render; - int i; - - render = (struct vdpau_render_state *)h->cur_pic_ptr->f->data[0]; - assert(render); - - for (i = 0; i < 2; ++i) { - int foc = h->cur_pic_ptr->field_poc[i]; - if (foc == INT_MAX) - foc = 0; - render->info.h264.field_order_cnt[i] = foc; - } - - render->info.h264.frame_num = h->poc.frame_num; -} - -void ff_vdpau_h264_picture_complete(H264Context *h) -{ - struct vdpau_render_state *render; - - render = (struct vdpau_render_state *)h->cur_pic_ptr->f->data[0]; - assert(render); - - render->info.h264.slice_count = h->current_slice; - if (render->info.h264.slice_count < 1) - return; - - render->info.h264.is_reference = (h->cur_pic_ptr->reference & 3) ? VDP_TRUE : VDP_FALSE; - render->info.h264.field_pic_flag = h->picture_structure != PICT_FRAME; - render->info.h264.bottom_field_flag = h->picture_structure == PICT_BOTTOM_FIELD; - render->info.h264.num_ref_frames = h->ps.sps->ref_frame_count; - render->info.h264.mb_adaptive_frame_field_flag = h->ps.sps->mb_aff && !render->info.h264.field_pic_flag; - render->info.h264.constrained_intra_pred_flag = h->ps.pps->constrained_intra_pred; - render->info.h264.weighted_pred_flag = h->ps.pps->weighted_pred; - render->info.h264.weighted_bipred_idc = h->ps.pps->weighted_bipred_idc; - render->info.h264.frame_mbs_only_flag = h->ps.sps->frame_mbs_only_flag; - render->info.h264.transform_8x8_mode_flag = h->ps.pps->transform_8x8_mode; - render->info.h264.chroma_qp_index_offset = h->ps.pps->chroma_qp_index_offset[0]; - render->info.h264.second_chroma_qp_index_offset = h->ps.pps->chroma_qp_index_offset[1]; - render->info.h264.pic_init_qp_minus26 = h->ps.pps->init_qp - 26; - render->info.h264.num_ref_idx_l0_active_minus1 = h->ps.pps->ref_count[0] - 1; - render->info.h264.num_ref_idx_l1_active_minus1 = h->ps.pps->ref_count[1] - 1; - render->info.h264.log2_max_frame_num_minus4 = h->ps.sps->log2_max_frame_num - 4; - render->info.h264.pic_order_cnt_type = h->ps.sps->poc_type; - render->info.h264.log2_max_pic_order_cnt_lsb_minus4 = h->ps.sps->poc_type ? 0 : h->ps.sps->log2_max_poc_lsb - 4; - render->info.h264.delta_pic_order_always_zero_flag = h->ps.sps->delta_pic_order_always_zero_flag; - render->info.h264.direct_8x8_inference_flag = h->ps.sps->direct_8x8_inference_flag; - render->info.h264.entropy_coding_mode_flag = h->ps.pps->cabac; - render->info.h264.pic_order_present_flag = h->ps.pps->pic_order_present; - render->info.h264.deblocking_filter_control_present_flag = h->ps.pps->deblocking_filter_parameters_present; - render->info.h264.redundant_pic_cnt_present_flag = h->ps.pps->redundant_pic_cnt_present; - memcpy(render->info.h264.scaling_lists_4x4, h->ps.pps->scaling_matrix4, sizeof(render->info.h264.scaling_lists_4x4)); - memcpy(render->info.h264.scaling_lists_8x8[0], h->ps.pps->scaling_matrix8[0], sizeof(render->info.h264.scaling_lists_8x8[0])); - memcpy(render->info.h264.scaling_lists_8x8[1], h->ps.pps->scaling_matrix8[3], sizeof(render->info.h264.scaling_lists_8x8[0])); - - ff_h264_draw_horiz_band(h, &h->slice_ctx[0], 0, h->avctx->height); - render->bitstream_buffers_used = 0; -} -#endif /* CONFIG_H264_VDPAU_DECODER */ - -#if CONFIG_MPEG_VDPAU_DECODER || CONFIG_MPEG1_VDPAU_DECODER -void ff_vdpau_mpeg_picture_complete(MpegEncContext *s, const uint8_t *buf, - int buf_size, int slice_count) -{ - struct vdpau_render_state *render, *last, *next; - int i; - - if (!s->current_picture_ptr) return; - - render = (struct vdpau_render_state *)s->current_picture_ptr->f->data[0]; - assert(render); - - /* fill VdpPictureInfoMPEG1Or2 struct */ - render->info.mpeg.picture_structure = s->picture_structure; - render->info.mpeg.picture_coding_type = s->pict_type; - render->info.mpeg.intra_dc_precision = s->intra_dc_precision; - render->info.mpeg.frame_pred_frame_dct = s->frame_pred_frame_dct; - render->info.mpeg.concealment_motion_vectors = s->concealment_motion_vectors; - render->info.mpeg.intra_vlc_format = s->intra_vlc_format; - render->info.mpeg.alternate_scan = s->alternate_scan; - render->info.mpeg.q_scale_type = s->q_scale_type; - render->info.mpeg.top_field_first = s->top_field_first; - render->info.mpeg.full_pel_forward_vector = s->full_pel[0]; // MPEG-1 only. Set 0 for MPEG-2 - render->info.mpeg.full_pel_backward_vector = s->full_pel[1]; // MPEG-1 only. Set 0 for MPEG-2 - render->info.mpeg.f_code[0][0] = s->mpeg_f_code[0][0]; // For MPEG-1 fill both horiz. & vert. - render->info.mpeg.f_code[0][1] = s->mpeg_f_code[0][1]; - render->info.mpeg.f_code[1][0] = s->mpeg_f_code[1][0]; - render->info.mpeg.f_code[1][1] = s->mpeg_f_code[1][1]; - for (i = 0; i < 64; ++i) { - render->info.mpeg.intra_quantizer_matrix[i] = s->intra_matrix[i]; - render->info.mpeg.non_intra_quantizer_matrix[i] = s->inter_matrix[i]; - } - - render->info.mpeg.forward_reference = VDP_INVALID_HANDLE; - render->info.mpeg.backward_reference = VDP_INVALID_HANDLE; - - switch(s->pict_type){ - case AV_PICTURE_TYPE_B: - next = (struct vdpau_render_state *)s->next_picture.f->data[0]; - assert(next); - render->info.mpeg.backward_reference = next->surface; - // no return here, going to set forward prediction - case AV_PICTURE_TYPE_P: - last = (struct vdpau_render_state *)s->last_picture.f->data[0]; - if (!last) // FIXME: Does this test make sense? - last = render; // predict second field from the first - render->info.mpeg.forward_reference = last->surface; - } - - ff_vdpau_add_data_chunk(s->current_picture_ptr->f->data[0], buf, buf_size); - - render->info.mpeg.slice_count = slice_count; - - if (slice_count) - ff_mpeg_draw_horiz_band(s, 0, s->avctx->height); - render->bitstream_buffers_used = 0; -} -#endif /* CONFIG_MPEG_VDPAU_DECODER || CONFIG_MPEG1_VDPAU_DECODER */ - -#if CONFIG_VC1_VDPAU_DECODER -void ff_vdpau_vc1_decode_picture(MpegEncContext *s, const uint8_t *buf, - int buf_size) -{ - VC1Context *v = s->avctx->priv_data; - struct vdpau_render_state *render, *last, *next; - - render = (struct vdpau_render_state *)s->current_picture.f->data[0]; - assert(render); - - /* fill LvPictureInfoVC1 struct */ - render->info.vc1.frame_coding_mode = v->fcm ? v->fcm + 1 : 0; - render->info.vc1.postprocflag = v->postprocflag; - render->info.vc1.pulldown = v->broadcast; - render->info.vc1.interlace = v->interlace; - render->info.vc1.tfcntrflag = v->tfcntrflag; - render->info.vc1.finterpflag = v->finterpflag; - render->info.vc1.psf = v->psf; - render->info.vc1.dquant = v->dquant; - render->info.vc1.panscan_flag = v->panscanflag; - render->info.vc1.refdist_flag = v->refdist_flag; - render->info.vc1.quantizer = v->quantizer_mode; - render->info.vc1.extended_mv = v->extended_mv; - render->info.vc1.extended_dmv = v->extended_dmv; - render->info.vc1.overlap = v->overlap; - render->info.vc1.vstransform = v->vstransform; - render->info.vc1.loopfilter = v->s.loop_filter; - render->info.vc1.fastuvmc = v->fastuvmc; - render->info.vc1.range_mapy_flag = v->range_mapy_flag; - render->info.vc1.range_mapy = v->range_mapy; - render->info.vc1.range_mapuv_flag = v->range_mapuv_flag; - render->info.vc1.range_mapuv = v->range_mapuv; - /* Specific to simple/main profile only */ - render->info.vc1.multires = v->multires; - render->info.vc1.syncmarker = v->resync_marker; - render->info.vc1.rangered = v->rangered | (v->rangeredfrm << 1); - render->info.vc1.maxbframes = v->s.max_b_frames; - - render->info.vc1.deblockEnable = v->postprocflag & 1; - render->info.vc1.pquant = v->pq; - - render->info.vc1.forward_reference = VDP_INVALID_HANDLE; - render->info.vc1.backward_reference = VDP_INVALID_HANDLE; - - if (v->bi_type) - render->info.vc1.picture_type = 4; - else - render->info.vc1.picture_type = s->pict_type - 1 + s->pict_type / 3; - - switch(s->pict_type){ - case AV_PICTURE_TYPE_B: - next = (struct vdpau_render_state *)s->next_picture.f->data[0]; - assert(next); - render->info.vc1.backward_reference = next->surface; - // no break here, going to set forward prediction - case AV_PICTURE_TYPE_P: - last = (struct vdpau_render_state *)s->last_picture.f->data[0]; - if (!last) // FIXME: Does this test make sense? - last = render; // predict second field from the first - render->info.vc1.forward_reference = last->surface; - } - - ff_vdpau_add_data_chunk(s->current_picture_ptr->f->data[0], buf, buf_size); - - render->info.vc1.slice_count = 1; - - ff_mpeg_draw_horiz_band(s, 0, s->avctx->height); - render->bitstream_buffers_used = 0; -} -#endif /* (CONFIG_VC1_VDPAU_DECODER */ - -#if CONFIG_MPEG4_VDPAU_DECODER -void ff_vdpau_mpeg4_decode_picture(Mpeg4DecContext *ctx, const uint8_t *buf, - int buf_size) -{ - MpegEncContext *s = &ctx->m; - struct vdpau_render_state *render, *last, *next; - int i; - - if (!s->current_picture_ptr) return; - - render = (struct vdpau_render_state *)s->current_picture_ptr->f->data[0]; - assert(render); - - /* fill VdpPictureInfoMPEG4Part2 struct */ - render->info.mpeg4.trd[0] = s->pp_time; - render->info.mpeg4.trb[0] = s->pb_time; - render->info.mpeg4.trd[1] = s->pp_field_time >> 1; - render->info.mpeg4.trb[1] = s->pb_field_time >> 1; - render->info.mpeg4.vop_time_increment_resolution = s->avctx->time_base.den; - render->info.mpeg4.vop_coding_type = 0; - render->info.mpeg4.vop_fcode_forward = s->f_code; - render->info.mpeg4.vop_fcode_backward = s->b_code; - render->info.mpeg4.resync_marker_disable = !ctx->resync_marker; - render->info.mpeg4.interlaced = !s->progressive_sequence; - render->info.mpeg4.quant_type = s->mpeg_quant; - render->info.mpeg4.quarter_sample = s->quarter_sample; - render->info.mpeg4.short_video_header = s->avctx->codec->id == AV_CODEC_ID_H263; - render->info.mpeg4.rounding_control = s->no_rounding; - render->info.mpeg4.alternate_vertical_scan_flag = s->alternate_scan; - render->info.mpeg4.top_field_first = s->top_field_first; - for (i = 0; i < 64; ++i) { - render->info.mpeg4.intra_quantizer_matrix[i] = s->intra_matrix[i]; - render->info.mpeg4.non_intra_quantizer_matrix[i] = s->inter_matrix[i]; - } - render->info.mpeg4.forward_reference = VDP_INVALID_HANDLE; - render->info.mpeg4.backward_reference = VDP_INVALID_HANDLE; - - switch (s->pict_type) { - case AV_PICTURE_TYPE_B: - next = (struct vdpau_render_state *)s->next_picture.f->data[0]; - assert(next); - render->info.mpeg4.backward_reference = next->surface; - render->info.mpeg4.vop_coding_type = 2; - // no break here, going to set forward prediction - case AV_PICTURE_TYPE_P: - last = (struct vdpau_render_state *)s->last_picture.f->data[0]; - assert(last); - render->info.mpeg4.forward_reference = last->surface; - } - - ff_vdpau_add_data_chunk(s->current_picture_ptr->f->data[0], buf, buf_size); - - ff_mpeg_draw_horiz_band(s, 0, s->avctx->height); - render->bitstream_buffers_used = 0; -} -#endif /* CONFIG_MPEG4_VDPAU_DECODER */ -#endif /* FF_API_VDPAU */ - #if FF_API_VDPAU_PROFILE int av_vdpau_get_profile(AVCodecContext *avctx, VdpDecoderProfile *profile) { @@ -816,7 +440,7 @@ do { \ AVVDPAUContext *av_vdpau_alloc_context(void) { - return av_mallocz(sizeof(AVVDPAUContext)); + return av_mallocz(sizeof(VDPAUHWContext)); } int av_vdpau_bind_context(AVCodecContext *avctx, VdpDevice device, diff --git a/libavcodec/vdpau.h b/libavcodec/vdpau.h index 855d387d9a0d0..4d99943369118 100644 --- a/libavcodec/vdpau.h +++ b/libavcodec/vdpau.h @@ -57,15 +57,6 @@ #include "avcodec.h" #include "version.h" -#if FF_API_BUFS_VDPAU -union AVVDPAUPictureInfo { - VdpPictureInfoH264 h264; - VdpPictureInfoMPEG1Or2 mpeg; - VdpPictureInfoVC1 vc1; - VdpPictureInfoMPEG4Part2 mpeg4; -}; -#endif - struct AVCodecContext; struct AVFrame; @@ -102,40 +93,6 @@ typedef struct AVVDPAUContext { */ VdpDecoderRender *render; -#if FF_API_BUFS_VDPAU - /** - * VDPAU picture information - * - * Set by libavcodec. - */ - attribute_deprecated - union AVVDPAUPictureInfo info; - - /** - * Allocated size of the bitstream_buffers table. - * - * Set by libavcodec. - */ - attribute_deprecated - int bitstream_buffers_allocated; - - /** - * Useful bitstream buffers in the bitstream buffers table. - * - * Set by libavcodec. - */ - attribute_deprecated - int bitstream_buffers_used; - - /** - * Table of bitstream buffers. - * The user is responsible for freeing this buffer using av_freep(). - * - * Set by libavcodec. - */ - attribute_deprecated - VdpBitstreamBuffer *bitstream_buffers; -#endif AVVDPAU_Render2 render2; } AVVDPAUContext; @@ -214,40 +171,6 @@ attribute_deprecated int av_vdpau_get_profile(AVCodecContext *avctx, VdpDecoderProfile *profile); #endif -#if FF_API_CAP_VDPAU -/** @brief The videoSurface is used for rendering. */ -#define FF_VDPAU_STATE_USED_FOR_RENDER 1 - -/** - * @brief The videoSurface is needed for reference/prediction. - * The codec manipulates this. - */ -#define FF_VDPAU_STATE_USED_FOR_REFERENCE 2 - -/** - * @brief This structure is used as a callback between the FFmpeg - * decoder (vd_) and presentation (vo_) module. - * This is used for defining a video frame containing surface, - * picture parameter, bitstream information etc which are passed - * between the FFmpeg decoder and its clients. - */ -struct vdpau_render_state { - VdpVideoSurface surface; ///< Used as rendered surface, never changed. - - int state; ///< Holds FF_VDPAU_STATE_* values. - - /** picture parameter information for all supported codecs */ - union AVVDPAUPictureInfo info; - - /** Describe size/location of the compressed video data. - Set to 0 when freeing bitstream_buffers. */ - int bitstream_buffers_allocated; - int bitstream_buffers_used; - /** The user is responsible for freeing this buffer using av_freep(). */ - VdpBitstreamBuffer *bitstream_buffers; -}; -#endif - /* @}*/ #endif /* AVCODEC_VDPAU_H */ diff --git a/libavcodec/vdpau_compat.h b/libavcodec/vdpau_compat.h deleted file mode 100644 index 768acce78c7e7..0000000000000 --- a/libavcodec/vdpau_compat.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Video Decode and Presentation API for UNIX (VDPAU) is used for - * HW decode acceleration for MPEG-1/2, H.264 and VC-1. - * - * Copyright (C) 2008 NVIDIA - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVCODEC_VDPAU_COMPAT_H -#define AVCODEC_VDPAU_COMPAT_H - -#include - -#include "h264dec.h" -#include "mpeg4video.h" - -void ff_vdpau_add_data_chunk(uint8_t *data, const uint8_t *buf, - int buf_size); - -void ff_vdpau_mpeg_picture_complete(MpegEncContext *s, const uint8_t *buf, - int buf_size, int slice_count); - -void ff_vdpau_h264_picture_start(H264Context *h); -void ff_vdpau_h264_set_reference_frames(H264Context *h); -void ff_vdpau_h264_picture_complete(H264Context *h); - -void ff_vdpau_vc1_decode_picture(MpegEncContext *s, const uint8_t *buf, - int buf_size); - -void ff_vdpau_mpeg4_decode_picture(Mpeg4DecContext *s, const uint8_t *buf, - int buf_size); - -#endif /* AVCODEC_VDPAU_COMPAT_H */ diff --git a/libavcodec/vdpau_h264.c b/libavcodec/vdpau_h264.c index be6ba71433348..2a260f76abae4 100644 --- a/libavcodec/vdpau_h264.c +++ b/libavcodec/vdpau_h264.c @@ -262,7 +262,7 @@ static int vdpau_h264_init(AVCodecContext *avctx) return ff_vdpau_common_init(avctx, profile, level); } -AVHWAccel ff_h264_vdpau_hwaccel = { +const AVHWAccel ff_h264_vdpau_hwaccel = { .name = "h264_vdpau", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, @@ -273,6 +273,7 @@ AVHWAccel ff_h264_vdpau_hwaccel = { .frame_priv_data_size = sizeof(struct vdpau_picture_context), .init = vdpau_h264_init, .uninit = ff_vdpau_common_uninit, + .frame_params = ff_vdpau_common_frame_params, .priv_data_size = sizeof(VDPAUContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vdpau_hevc.c b/libavcodec/vdpau_hevc.c index fcdf4b2747f26..421135bce25bf 100644 --- a/libavcodec/vdpau_hevc.c +++ b/libavcodec/vdpau_hevc.c @@ -413,7 +413,7 @@ static int vdpau_hevc_init(AVCodecContext *avctx) return ff_vdpau_common_init(avctx, profile, level); } -AVHWAccel ff_hevc_vdpau_hwaccel = { +const AVHWAccel ff_hevc_vdpau_hwaccel = { .name = "hevc_vdpau", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_HEVC, @@ -424,6 +424,7 @@ AVHWAccel ff_hevc_vdpau_hwaccel = { .frame_priv_data_size = sizeof(struct vdpau_picture_context), .init = vdpau_hevc_init, .uninit = ff_vdpau_common_uninit, + .frame_params = ff_vdpau_common_frame_params, .priv_data_size = sizeof(VDPAUContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vdpau_internal.h b/libavcodec/vdpau_internal.h index 30d01af65d801..4d63e50b165ed 100644 --- a/libavcodec/vdpau_internal.h +++ b/libavcodec/vdpau_internal.h @@ -119,5 +119,7 @@ int ff_vdpau_common_end_frame(AVCodecContext *avctx, AVFrame *frame, int ff_vdpau_mpeg_end_frame(AVCodecContext *avctx); int ff_vdpau_add_buffer(struct vdpau_picture_context *pic, const uint8_t *buf, uint32_t buf_size); +int ff_vdpau_common_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx); #endif /* AVCODEC_VDPAU_INTERNAL_H */ diff --git a/libavcodec/vdpau_mpeg12.c b/libavcodec/vdpau_mpeg12.c index b657007ee7710..d286e7e57da2d 100644 --- a/libavcodec/vdpau_mpeg12.c +++ b/libavcodec/vdpau_mpeg12.c @@ -103,7 +103,7 @@ static int vdpau_mpeg1_init(AVCodecContext *avctx) VDP_DECODER_LEVEL_MPEG1_NA); } -AVHWAccel ff_mpeg1_vdpau_hwaccel = { +const AVHWAccel ff_mpeg1_vdpau_hwaccel = { .name = "mpeg1_vdpau", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG1VIDEO, @@ -138,7 +138,7 @@ static int vdpau_mpeg2_init(AVCodecContext *avctx) return ff_vdpau_common_init(avctx, profile, VDP_DECODER_LEVEL_MPEG2_HL); } -AVHWAccel ff_mpeg2_vdpau_hwaccel = { +const AVHWAccel ff_mpeg2_vdpau_hwaccel = { .name = "mpeg2_vdpau", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG2VIDEO, @@ -149,6 +149,7 @@ AVHWAccel ff_mpeg2_vdpau_hwaccel = { .frame_priv_data_size = sizeof(struct vdpau_picture_context), .init = vdpau_mpeg2_init, .uninit = ff_vdpau_common_uninit, + .frame_params = ff_vdpau_common_frame_params, .priv_data_size = sizeof(VDPAUContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vdpau_mpeg4.c b/libavcodec/vdpau_mpeg4.c index bbdd843a449c7..96f83026a8e4d 100644 --- a/libavcodec/vdpau_mpeg4.c +++ b/libavcodec/vdpau_mpeg4.c @@ -110,7 +110,7 @@ static int vdpau_mpeg4_init(AVCodecContext *avctx) return ff_vdpau_common_init(avctx, profile, avctx->level); } -AVHWAccel ff_mpeg4_vdpau_hwaccel = { +const AVHWAccel ff_mpeg4_vdpau_hwaccel = { .name = "mpeg4_vdpau", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG4, @@ -121,6 +121,7 @@ AVHWAccel ff_mpeg4_vdpau_hwaccel = { .frame_priv_data_size = sizeof(struct vdpau_picture_context), .init = vdpau_mpeg4_init, .uninit = ff_vdpau_common_uninit, + .frame_params = ff_vdpau_common_frame_params, .priv_data_size = sizeof(VDPAUContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/vdpau_vc1.c b/libavcodec/vdpau_vc1.c index 665a2333f45a3..671baf96b4d7e 100644 --- a/libavcodec/vdpau_vc1.c +++ b/libavcodec/vdpau_vc1.c @@ -136,7 +136,7 @@ static int vdpau_vc1_init(AVCodecContext *avctx) } #if CONFIG_WMV3_VDPAU_HWACCEL -AVHWAccel ff_wmv3_vdpau_hwaccel = { +const AVHWAccel ff_wmv3_vdpau_hwaccel = { .name = "wm3_vdpau", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_WMV3, @@ -147,12 +147,13 @@ AVHWAccel ff_wmv3_vdpau_hwaccel = { .frame_priv_data_size = sizeof(struct vdpau_picture_context), .init = vdpau_vc1_init, .uninit = ff_vdpau_common_uninit, + .frame_params = ff_vdpau_common_frame_params, .priv_data_size = sizeof(VDPAUContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; #endif -AVHWAccel ff_vc1_vdpau_hwaccel = { +const AVHWAccel ff_vc1_vdpau_hwaccel = { .name = "vc1_vdpau", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_VC1, @@ -163,6 +164,7 @@ AVHWAccel ff_vc1_vdpau_hwaccel = { .frame_priv_data_size = sizeof(struct vdpau_picture_context), .init = vdpau_vc1_init, .uninit = ff_vdpau_common_uninit, + .frame_params = ff_vdpau_common_frame_params, .priv_data_size = sizeof(VDPAUContext), .caps_internal = HWACCEL_CAP_ASYNC_SAFE, }; diff --git a/libavcodec/version.h b/libavcodec/version.h index 10d9ac4eb3c04..6895f1a461e31 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -27,8 +27,8 @@ #include "libavutil/version.h" -#define LIBAVCODEC_VERSION_MAJOR 57 -#define LIBAVCODEC_VERSION_MINOR 107 +#define LIBAVCODEC_VERSION_MAJOR 58 +#define LIBAVCODEC_VERSION_MINOR 18 #define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ @@ -51,136 +51,18 @@ * at once through the bump. This improves the git bisect-ability of the change. */ -#ifndef FF_API_VIMA_DECODER -#define FF_API_VIMA_DECODER (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_AUDIO_CONVERT -#define FF_API_AUDIO_CONVERT (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_AVCODEC_RESAMPLE -#define FF_API_AVCODEC_RESAMPLE FF_API_AUDIO_CONVERT -#endif -#ifndef FF_API_MISSING_SAMPLE -#define FF_API_MISSING_SAMPLE (LIBAVCODEC_VERSION_MAJOR < 58) -#endif #ifndef FF_API_LOWRES -#define FF_API_LOWRES (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_CAP_VDPAU -#define FF_API_CAP_VDPAU (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_BUFS_VDPAU -#define FF_API_BUFS_VDPAU (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_VOXWARE -#define FF_API_VOXWARE (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_SET_DIMENSIONS -#define FF_API_SET_DIMENSIONS (LIBAVCODEC_VERSION_MAJOR < 58) +#define FF_API_LOWRES (LIBAVCODEC_VERSION_MAJOR < 59) #endif #ifndef FF_API_DEBUG_MV #define FF_API_DEBUG_MV (LIBAVCODEC_VERSION_MAJOR < 58) #endif -#ifndef FF_API_AC_VLC -#define FF_API_AC_VLC (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_OLD_MSMPEG4 -#define FF_API_OLD_MSMPEG4 (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_ASPECT_EXTENDED -#define FF_API_ASPECT_EXTENDED (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_ARCH_ALPHA -#define FF_API_ARCH_ALPHA (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_XVMC -#define FF_API_XVMC (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_ERROR_RATE -#define FF_API_ERROR_RATE (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_QSCALE_TYPE -#define FF_API_QSCALE_TYPE (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_MB_TYPE -#define FF_API_MB_TYPE (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_MAX_BFRAMES -#define FF_API_MAX_BFRAMES (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_NEG_LINESIZES -#define FF_API_NEG_LINESIZES (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_EMU_EDGE -#define FF_API_EMU_EDGE (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_ARCH_SH4 -#define FF_API_ARCH_SH4 (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_ARCH_SPARC -#define FF_API_ARCH_SPARC (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_UNUSED_MEMBERS -#define FF_API_UNUSED_MEMBERS (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_IDCT_XVIDMMX -#define FF_API_IDCT_XVIDMMX (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_INPUT_PRESERVED -#define FF_API_INPUT_PRESERVED (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_NORMALIZE_AQP -#define FF_API_NORMALIZE_AQP (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_GMC -#define FF_API_GMC (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_MV0 -#define FF_API_MV0 (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_CODEC_NAME -#define FF_API_CODEC_NAME (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_AFD -#define FF_API_AFD (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_VISMV -/* XXX: don't forget to drop the -vismv documentation */ -#define FF_API_VISMV (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_AUDIOENC_DELAY -#define FF_API_AUDIOENC_DELAY (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_VAAPI_CONTEXT -#define FF_API_VAAPI_CONTEXT (LIBAVCODEC_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_MERGE_SD -#define FF_API_MERGE_SD (LIBAVCODEC_VERSION_MAJOR < 58) -#endif #ifndef FF_API_AVCTX_TIMEBASE #define FF_API_AVCTX_TIMEBASE (LIBAVCODEC_VERSION_MAJOR < 59) #endif -#ifndef FF_API_MPV_OPT -#define FF_API_MPV_OPT (LIBAVCODEC_VERSION_MAJOR < 59) -#endif -#ifndef FF_API_STREAM_CODEC_TAG -#define FF_API_STREAM_CODEC_TAG (LIBAVCODEC_VERSION_MAJOR < 59) -#endif -#ifndef FF_API_QUANT_BIAS -#define FF_API_QUANT_BIAS (LIBAVCODEC_VERSION_MAJOR < 59) -#endif -#ifndef FF_API_RC_STRATEGY -#define FF_API_RC_STRATEGY (LIBAVCODEC_VERSION_MAJOR < 59) -#endif #ifndef FF_API_CODED_FRAME #define FF_API_CODED_FRAME (LIBAVCODEC_VERSION_MAJOR < 59) #endif -#ifndef FF_API_MOTION_EST -#define FF_API_MOTION_EST (LIBAVCODEC_VERSION_MAJOR < 59) -#endif -#ifndef FF_API_WITHOUT_PREFIX -#define FF_API_WITHOUT_PREFIX (LIBAVCODEC_VERSION_MAJOR < 59) -#endif #ifndef FF_API_SIDEDATA_ONLY_PKT #define FF_API_SIDEDATA_ONLY_PKT (LIBAVCODEC_VERSION_MAJOR < 59) #endif @@ -238,6 +120,18 @@ #ifndef FF_API_GETCHROMA #define FF_API_GETCHROMA (LIBAVCODEC_VERSION_MAJOR < 59) #endif +#ifndef FF_API_CODEC_GET_SET +#define FF_API_CODEC_GET_SET (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_USER_VISIBLE_AVHWACCEL +#define FF_API_USER_VISIBLE_AVHWACCEL (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_LOCKMGR +#define FF_API_LOCKMGR (LIBAVCODEC_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_NEXT +#define FF_API_NEXT (LIBAVCODEC_VERSION_MAJOR < 59) +#endif #endif /* AVCODEC_VERSION_H */ diff --git a/libavcodec/videotoolbox.c b/libavcodec/videotoolbox.c index ec8b6d885c8e5..57b6698e1b949 100644 --- a/libavcodec/videotoolbox.c +++ b/libavcodec/videotoolbox.c @@ -21,16 +21,13 @@ */ #include "config.h" -#if CONFIG_VIDEOTOOLBOX -# include "videotoolbox.h" -# include "libavutil/hwcontext_videotoolbox.h" -#else -# include "vda.h" -#endif -#include "vda_vt_internal.h" +#include "videotoolbox.h" +#include "libavutil/hwcontext_videotoolbox.h" +#include "vt_internal.h" #include "libavutil/avutil.h" #include "libavutil/hwcontext.h" #include "bytestream.h" +#include "decode.h" #include "h264dec.h" #include "hevcdec.h" #include "mpegvideo.h" @@ -48,8 +45,10 @@ enum { kCMVideoCodecType_HEVC = 'hvc1' }; static void videotoolbox_buffer_release(void *opaque, uint8_t *data) { - CVPixelBufferRef cv_buffer = (CVImageBufferRef)data; + CVPixelBufferRef cv_buffer = *(CVPixelBufferRef *)data; CVPixelBufferRelease(cv_buffer); + + av_free(data); } static int videotoolbox_buffer_copy(VTContext *vtctx, @@ -72,15 +71,47 @@ static int videotoolbox_buffer_copy(VTContext *vtctx, return 0; } +static int videotoolbox_postproc_frame(void *avctx, AVFrame *frame) +{ + CVPixelBufferRef ref = *(CVPixelBufferRef *)frame->buf[0]->data; + + if (!ref) { + av_log(avctx, AV_LOG_ERROR, "No frame decoded?\n"); + av_frame_unref(frame); + return AVERROR_EXTERNAL; + } + + frame->data[3] = (uint8_t*)ref; + + return 0; +} + int ff_videotoolbox_alloc_frame(AVCodecContext *avctx, AVFrame *frame) { + size_t size = sizeof(CVPixelBufferRef); + uint8_t *data = NULL; + AVBufferRef *buf = NULL; + int ret = ff_attach_decode_data(frame); + FrameDecodeData *fdd; + if (ret < 0) + return ret; + + data = av_mallocz(size); + if (!data) + return AVERROR(ENOMEM); + buf = av_buffer_create(data, size, videotoolbox_buffer_release, NULL, 0); + if (!buf) { + av_freep(&data); + return AVERROR(ENOMEM); + } + frame->buf[0] = buf; + + fdd = (FrameDecodeData*)frame->private_ref->data; + fdd->post_process = videotoolbox_postproc_frame; + frame->width = avctx->width; frame->height = avctx->height; frame->format = avctx->pix_fmt; - frame->buf[0] = av_buffer_alloc(1); - - if (!frame->buf[0]) - return AVERROR(ENOMEM); return 0; } @@ -89,7 +120,8 @@ int ff_videotoolbox_alloc_frame(AVCodecContext *avctx, AVFrame *frame) CFDataRef ff_videotoolbox_avcc_extradata_create(AVCodecContext *avctx) { - H264Context *h = avctx->priv_data; + VTContext *vtctx = avctx->internal->hwaccel_priv_data; + H264Context *h = avctx->priv_data; CFDataRef data = NULL; uint8_t *p; int vt_extradata_size = 6 + 2 + h->ps.sps->data_size + 3 + h->ps.pps->data_size; @@ -115,6 +147,11 @@ CFDataRef ff_videotoolbox_avcc_extradata_create(AVCodecContext *avctx) p += 3 + h->ps.pps->data_size; av_assert0(p - vt_extradata == vt_extradata_size); + // save sps header (profile/level) used to create decoder session, + // so we can detect changes and recreate it. + if (vtctx) + memcpy(vtctx->sps, h->ps.sps->data + 1, 3); + data = CFDataCreate(kCFAllocatorDefault, vt_extradata, vt_extradata_size); av_free(vt_extradata); return data; @@ -135,7 +172,7 @@ CFDataRef ff_videotoolbox_hvcc_extradata_create(AVCodecContext *avctx) int vt_extradata_size = 23 + 5 + vps->data_size + 5 + sps->data_size + 3; uint8_t *vt_extradata; - for (i = 0; i < MAX_PPS_COUNT; i++) { + for (i = 0; i < HEVC_MAX_PPS_COUNT; i++) { if (h->ps.pps_list[i]) { const HEVCPPS *pps = (const HEVCPPS *)h->ps.pps_list[i]->data; vt_extradata_size += 2 + pps->data_size; @@ -262,7 +299,7 @@ CFDataRef ff_videotoolbox_hvcc_extradata_create(AVCodecContext *avctx) HEVC_NAL_PPS & 0x3f); AV_WB16(p + 1, num_pps); p += 3; - for (i = 0; i < MAX_PPS_COUNT; i++) { + for (i = 0; i < HEVC_MAX_PPS_COUNT; i++) { if (h->ps.pps_list[i]) { const HEVCPPS *pps = (const HEVCPPS *)h->ps.pps_list[i]->data; AV_WB16(p, pps->data_size); @@ -278,20 +315,21 @@ CFDataRef ff_videotoolbox_hvcc_extradata_create(AVCodecContext *avctx) return data; } -int ff_videotoolbox_buffer_create(VTContext *vtctx, AVFrame *frame) +static int videotoolbox_set_frame(AVCodecContext *avctx, AVFrame *frame) { - av_buffer_unref(&frame->buf[0]); - - frame->buf[0] = av_buffer_create((uint8_t*)vtctx->frame, - sizeof(vtctx->frame), - videotoolbox_buffer_release, - NULL, - AV_BUFFER_FLAG_READONLY); - if (!frame->buf[0]) { - return AVERROR(ENOMEM); + VTContext *vtctx = avctx->internal->hwaccel_priv_data; + if (!frame->buf[0] || frame->data[3]) { + av_log(avctx, AV_LOG_ERROR, "videotoolbox: invalid state\n"); + av_frame_unref(frame); + return AVERROR_EXTERNAL; } - frame->data[3] = (uint8_t*)vtctx->frame; + CVPixelBufferRef *ref = (CVPixelBufferRef *)frame->buf[0]->data; + + if (*ref) + CVPixelBufferRelease(*ref); + + *ref = vtctx->frame; vtctx->frame = NULL; return 0; @@ -304,8 +342,6 @@ int ff_videotoolbox_h264_start_frame(AVCodecContext *avctx, VTContext *vtctx = avctx->internal->hwaccel_priv_data; H264Context *h = avctx->priv_data; - vtctx->bitstream_size = 0; - if (h->is_avc == 1) { return videotoolbox_buffer_copy(vtctx, buffer, size); } @@ -313,6 +349,29 @@ int ff_videotoolbox_h264_start_frame(AVCodecContext *avctx, return 0; } +static int videotoolbox_h264_decode_params(AVCodecContext *avctx, + int type, + const uint8_t *buffer, + uint32_t size) +{ + VTContext *vtctx = avctx->internal->hwaccel_priv_data; + H264Context *h = avctx->priv_data; + + // save sps header (profile/level) used to create decoder session + if (!vtctx->sps[0]) + memcpy(vtctx->sps, h->ps.sps->data + 1, 3); + + if (type == H264_NAL_SPS) { + if (size > 4 && memcmp(vtctx->sps, buffer + 1, 3) != 0) { + vtctx->reconfig_needed = true; + memcpy(vtctx->sps, buffer + 1, 3); + } + } + + // pass-through SPS/PPS changes to the decoder + return ff_videotoolbox_h264_decode_slice(avctx, buffer, size); +} + int ff_videotoolbox_h264_decode_slice(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size) @@ -378,7 +437,7 @@ static int videotoolbox_buffer_create(AVCodecContext *avctx, AVFrame *frame) AVHWFramesContext *cached_frames; int ret; - ret = ff_videotoolbox_buffer_create(vtctx, frame); + ret = videotoolbox_set_frame(avctx, frame); if (ret < 0) return ret; @@ -578,123 +637,25 @@ static OSStatus videotoolbox_session_decode_frame(AVCodecContext *avctx) return status; } -static int videotoolbox_common_end_frame(AVCodecContext *avctx, AVFrame *frame) -{ - int status; - AVVideotoolboxContext *videotoolbox = videotoolbox_get_context(avctx); - VTContext *vtctx = avctx->internal->hwaccel_priv_data; - - if (!videotoolbox->session || !vtctx->bitstream) - return AVERROR_INVALIDDATA; - - status = videotoolbox_session_decode_frame(avctx); - - if (status) { - av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%d)\n", status); - return AVERROR_UNKNOWN; - } - - if (!vtctx->frame) - return AVERROR_UNKNOWN; - - return videotoolbox_buffer_create(avctx, frame); -} - -static int videotoolbox_h264_end_frame(AVCodecContext *avctx) -{ - H264Context *h = avctx->priv_data; - AVFrame *frame = h->cur_pic_ptr->f; - - return videotoolbox_common_end_frame(avctx, frame); -} - -static int videotoolbox_hevc_end_frame(AVCodecContext *avctx) -{ - HEVCContext *h = avctx->priv_data; - AVFrame *frame = h->ref->frame; - VTContext *vtctx = avctx->internal->hwaccel_priv_data; - int ret; - - ret = videotoolbox_common_end_frame(avctx, frame); - vtctx->bitstream_size = 0; - return ret; -} - -static int videotoolbox_mpeg_start_frame(AVCodecContext *avctx, - const uint8_t *buffer, - uint32_t size) -{ - VTContext *vtctx = avctx->internal->hwaccel_priv_data; - - return videotoolbox_buffer_copy(vtctx, buffer, size); -} - -static int videotoolbox_mpeg_decode_slice(AVCodecContext *avctx, - const uint8_t *buffer, - uint32_t size) -{ - return 0; -} - -static int videotoolbox_mpeg_end_frame(AVCodecContext *avctx) -{ - MpegEncContext *s = avctx->priv_data; - AVFrame *frame = s->current_picture_ptr->f; - - return videotoolbox_common_end_frame(avctx, frame); -} - -static CFDictionaryRef videotoolbox_decoder_config_create(CMVideoCodecType codec_type, - AVCodecContext *avctx) +static CMVideoFormatDescriptionRef videotoolbox_format_desc_create(CMVideoCodecType codec_type, + CFDictionaryRef decoder_spec, + int width, + int height) { - CFMutableDictionaryRef config_info = CFDictionaryCreateMutable(kCFAllocatorDefault, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - CFDictionarySetValue(config_info, - kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder, - kCFBooleanTrue); - - if (avctx->extradata_size) { - CFMutableDictionaryRef avc_info; - CFDataRef data = NULL; - - avc_info = CFDictionaryCreateMutable(kCFAllocatorDefault, - 1, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - - switch (codec_type) { - case kCMVideoCodecType_MPEG4Video : - data = videotoolbox_esds_extradata_create(avctx); - if (data) - CFDictionarySetValue(avc_info, CFSTR("esds"), data); - break; - case kCMVideoCodecType_H264 : - data = ff_videotoolbox_avcc_extradata_create(avctx); - if (data) - CFDictionarySetValue(avc_info, CFSTR("avcC"), data); - break; - case kCMVideoCodecType_HEVC : - data = ff_videotoolbox_hvcc_extradata_create(avctx); - if (data) - CFDictionarySetValue(avc_info, CFSTR("hvcC"), data); - break; - default: - break; - } + CMFormatDescriptionRef cm_fmt_desc; + OSStatus status; - CFDictionarySetValue(config_info, - kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms, - avc_info); + status = CMVideoFormatDescriptionCreate(kCFAllocatorDefault, + codec_type, + width, + height, + decoder_spec, // Dictionary of extension + &cm_fmt_desc); - if (data) - CFRelease(data); + if (status) + return NULL; - CFRelease(avc_info); - } - return config_info; + return cm_fmt_desc; } static CFDictionaryRef videotoolbox_buffer_attributes_create(int width, @@ -739,28 +700,59 @@ static CFDictionaryRef videotoolbox_buffer_attributes_create(int width, return buffer_attributes; } -static CMVideoFormatDescriptionRef videotoolbox_format_desc_create(CMVideoCodecType codec_type, - CFDictionaryRef decoder_spec, - int width, - int height) +static CFDictionaryRef videotoolbox_decoder_config_create(CMVideoCodecType codec_type, + AVCodecContext *avctx) { - CMFormatDescriptionRef cm_fmt_desc; - OSStatus status; + CFMutableDictionaryRef config_info = CFDictionaryCreateMutable(kCFAllocatorDefault, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); - status = CMVideoFormatDescriptionCreate(kCFAllocatorDefault, - codec_type, - width, - height, - decoder_spec, // Dictionary of extension - &cm_fmt_desc); + CFDictionarySetValue(config_info, + kVTVideoDecoderSpecification_RequireHardwareAcceleratedVideoDecoder, + kCFBooleanTrue); - if (status) - return NULL; + CFMutableDictionaryRef avc_info; + CFDataRef data = NULL; - return cm_fmt_desc; + avc_info = CFDictionaryCreateMutable(kCFAllocatorDefault, + 1, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + switch (codec_type) { + case kCMVideoCodecType_MPEG4Video : + if (avctx->extradata_size) + data = videotoolbox_esds_extradata_create(avctx); + if (data) + CFDictionarySetValue(avc_info, CFSTR("esds"), data); + break; + case kCMVideoCodecType_H264 : + data = ff_videotoolbox_avcc_extradata_create(avctx); + if (data) + CFDictionarySetValue(avc_info, CFSTR("avcC"), data); + break; + case kCMVideoCodecType_HEVC : + data = ff_videotoolbox_hvcc_extradata_create(avctx); + if (data) + CFDictionarySetValue(avc_info, CFSTR("hvcC"), data); + break; + default: + break; + } + + CFDictionarySetValue(config_info, + kCMFormatDescriptionExtension_SampleDescriptionExtensionAtoms, + avc_info); + + if (data) + CFRelease(data); + + CFRelease(avc_info); + return config_info; } -static int videotoolbox_default_init(AVCodecContext *avctx) +static int videotoolbox_start(AVCodecContext *avctx) { AVVideotoolboxContext *videotoolbox = videotoolbox_get_context(avctx); OSStatus status; @@ -798,6 +790,11 @@ static int videotoolbox_default_init(AVCodecContext *avctx) decoder_spec = videotoolbox_decoder_config_create(videotoolbox->cm_codec_type, avctx); + if (!decoder_spec) { + av_log(avctx, AV_LOG_ERROR, "decoder specification creation failed\n"); + return -1; + } + videotoolbox->cm_fmt_desc = videotoolbox_format_desc_create(videotoolbox->cm_codec_type, decoder_spec, avctx->width, @@ -839,7 +836,7 @@ static int videotoolbox_default_init(AVCodecContext *avctx) case kVTVideoDecoderMalfunctionErr: av_log(avctx, AV_LOG_VERBOSE, "VideoToolbox malfunction.\n"); return AVERROR(EINVAL); - case kVTVideoDecoderBadDataErr : + case kVTVideoDecoderBadDataErr: av_log(avctx, AV_LOG_VERBOSE, "VideoToolbox reported invalid data.\n"); return AVERROR_INVALIDDATA; case 0: @@ -850,19 +847,123 @@ static int videotoolbox_default_init(AVCodecContext *avctx) } } -static void videotoolbox_default_free(AVCodecContext *avctx) +static void videotoolbox_stop(AVCodecContext *avctx) { AVVideotoolboxContext *videotoolbox = videotoolbox_get_context(avctx); + if (!videotoolbox) + return; + + if (videotoolbox->cm_fmt_desc) { + CFRelease(videotoolbox->cm_fmt_desc); + videotoolbox->cm_fmt_desc = NULL; + } + + if (videotoolbox->session) { + VTDecompressionSessionInvalidate(videotoolbox->session); + CFRelease(videotoolbox->session); + videotoolbox->session = NULL; + } +} + +static const char *videotoolbox_error_string(OSStatus status) +{ + switch (status) { + case kVTVideoDecoderBadDataErr: + return "bad data"; + case kVTVideoDecoderMalfunctionErr: + return "decoder malfunction"; + case kVTInvalidSessionErr: + return "invalid session"; + } + return "unknown"; +} - if (videotoolbox) { - if (videotoolbox->cm_fmt_desc) - CFRelease(videotoolbox->cm_fmt_desc); +static int videotoolbox_common_end_frame(AVCodecContext *avctx, AVFrame *frame) +{ + OSStatus status; + AVVideotoolboxContext *videotoolbox = videotoolbox_get_context(avctx); + VTContext *vtctx = avctx->internal->hwaccel_priv_data; - if (videotoolbox->session) { - VTDecompressionSessionInvalidate(videotoolbox->session); - CFRelease(videotoolbox->session); + if (vtctx->reconfig_needed == true) { + vtctx->reconfig_needed = false; + av_log(avctx, AV_LOG_VERBOSE, "VideoToolbox decoder needs reconfig, restarting..\n"); + videotoolbox_stop(avctx); + if (videotoolbox_start(avctx) != 0) { + return AVERROR_EXTERNAL; } } + + if (!videotoolbox->session || !vtctx->bitstream || !vtctx->bitstream_size) + return AVERROR_INVALIDDATA; + + status = videotoolbox_session_decode_frame(avctx); + if (status != noErr) { + if (status == kVTVideoDecoderMalfunctionErr || status == kVTInvalidSessionErr) + vtctx->reconfig_needed = true; + av_log(avctx, AV_LOG_ERROR, "Failed to decode frame (%s, %d)\n", videotoolbox_error_string(status), (int)status); + return AVERROR_UNKNOWN; + } + + if (!vtctx->frame) { + vtctx->reconfig_needed = true; + return AVERROR_UNKNOWN; + } + + return videotoolbox_buffer_create(avctx, frame); +} + +static int videotoolbox_h264_end_frame(AVCodecContext *avctx) +{ + H264Context *h = avctx->priv_data; + AVFrame *frame = h->cur_pic_ptr->f; + VTContext *vtctx = avctx->internal->hwaccel_priv_data; + int ret = videotoolbox_common_end_frame(avctx, frame); + vtctx->bitstream_size = 0; + return ret; +} + +static int videotoolbox_hevc_decode_params(AVCodecContext *avctx, + int type, + const uint8_t *buffer, + uint32_t size) +{ + return ff_videotoolbox_h264_decode_slice(avctx, buffer, size); +} + +static int videotoolbox_hevc_end_frame(AVCodecContext *avctx) +{ + HEVCContext *h = avctx->priv_data; + AVFrame *frame = h->ref->frame; + VTContext *vtctx = avctx->internal->hwaccel_priv_data; + int ret; + + ret = videotoolbox_common_end_frame(avctx, frame); + vtctx->bitstream_size = 0; + return ret; +} + +static int videotoolbox_mpeg_start_frame(AVCodecContext *avctx, + const uint8_t *buffer, + uint32_t size) +{ + VTContext *vtctx = avctx->internal->hwaccel_priv_data; + + return videotoolbox_buffer_copy(vtctx, buffer, size); +} + +static int videotoolbox_mpeg_decode_slice(AVCodecContext *avctx, + const uint8_t *buffer, + uint32_t size) +{ + return 0; +} + +static int videotoolbox_mpeg_end_frame(AVCodecContext *avctx) +{ + MpegEncContext *s = avctx->priv_data; + AVFrame *frame = s->current_picture_ptr->f; + + return videotoolbox_common_end_frame(avctx, frame); } static int videotoolbox_uninit(AVCodecContext *avctx) @@ -874,7 +975,7 @@ static int videotoolbox_uninit(AVCodecContext *avctx) ff_videotoolbox_uninit(avctx); if (vtctx->vt_ctx) - videotoolbox_default_free(avctx); + videotoolbox_stop(avctx); av_buffer_unref(&vtctx->cached_hw_frames_ctx); av_freep(&vtctx->vt_ctx); @@ -940,7 +1041,7 @@ static int videotoolbox_common_init(AVCodecContext *avctx) goto fail; } - err = videotoolbox_default_init(avctx); + err = videotoolbox_start(avctx); if (err < 0) goto fail; @@ -951,7 +1052,20 @@ static int videotoolbox_common_init(AVCodecContext *avctx) return err; } -AVHWAccel ff_h263_videotoolbox_hwaccel = { +static int videotoolbox_frame_params(AVCodecContext *avctx, + AVBufferRef *hw_frames_ctx) +{ + AVHWFramesContext *frames_ctx = (AVHWFramesContext*)hw_frames_ctx->data; + + frames_ctx->format = AV_PIX_FMT_VIDEOTOOLBOX; + frames_ctx->width = avctx->coded_width; + frames_ctx->height = avctx->coded_height; + frames_ctx->sw_format = AV_PIX_FMT_NV12; + + return 0; +} + +const AVHWAccel ff_h263_videotoolbox_hwaccel = { .name = "h263_videotoolbox", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H263, @@ -960,12 +1074,13 @@ AVHWAccel ff_h263_videotoolbox_hwaccel = { .start_frame = videotoolbox_mpeg_start_frame, .decode_slice = videotoolbox_mpeg_decode_slice, .end_frame = videotoolbox_mpeg_end_frame, + .frame_params = videotoolbox_frame_params, .init = videotoolbox_common_init, .uninit = videotoolbox_uninit, .priv_data_size = sizeof(VTContext), }; -AVHWAccel ff_hevc_videotoolbox_hwaccel = { +const AVHWAccel ff_hevc_videotoolbox_hwaccel = { .name = "hevc_videotoolbox", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_HEVC, @@ -973,13 +1088,15 @@ AVHWAccel ff_hevc_videotoolbox_hwaccel = { .alloc_frame = ff_videotoolbox_alloc_frame, .start_frame = ff_videotoolbox_h264_start_frame, .decode_slice = ff_videotoolbox_h264_decode_slice, + .decode_params = videotoolbox_hevc_decode_params, .end_frame = videotoolbox_hevc_end_frame, + .frame_params = videotoolbox_frame_params, .init = videotoolbox_common_init, .uninit = ff_videotoolbox_uninit, .priv_data_size = sizeof(VTContext), }; -AVHWAccel ff_h264_videotoolbox_hwaccel = { +const AVHWAccel ff_h264_videotoolbox_hwaccel = { .name = "h264_videotoolbox", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_H264, @@ -987,13 +1104,15 @@ AVHWAccel ff_h264_videotoolbox_hwaccel = { .alloc_frame = ff_videotoolbox_alloc_frame, .start_frame = ff_videotoolbox_h264_start_frame, .decode_slice = ff_videotoolbox_h264_decode_slice, + .decode_params = videotoolbox_h264_decode_params, .end_frame = videotoolbox_h264_end_frame, + .frame_params = videotoolbox_frame_params, .init = videotoolbox_common_init, .uninit = videotoolbox_uninit, .priv_data_size = sizeof(VTContext), }; -AVHWAccel ff_mpeg1_videotoolbox_hwaccel = { +const AVHWAccel ff_mpeg1_videotoolbox_hwaccel = { .name = "mpeg1_videotoolbox", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG1VIDEO, @@ -1002,12 +1121,13 @@ AVHWAccel ff_mpeg1_videotoolbox_hwaccel = { .start_frame = videotoolbox_mpeg_start_frame, .decode_slice = videotoolbox_mpeg_decode_slice, .end_frame = videotoolbox_mpeg_end_frame, + .frame_params = videotoolbox_frame_params, .init = videotoolbox_common_init, .uninit = videotoolbox_uninit, .priv_data_size = sizeof(VTContext), }; -AVHWAccel ff_mpeg2_videotoolbox_hwaccel = { +const AVHWAccel ff_mpeg2_videotoolbox_hwaccel = { .name = "mpeg2_videotoolbox", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG2VIDEO, @@ -1016,12 +1136,13 @@ AVHWAccel ff_mpeg2_videotoolbox_hwaccel = { .start_frame = videotoolbox_mpeg_start_frame, .decode_slice = videotoolbox_mpeg_decode_slice, .end_frame = videotoolbox_mpeg_end_frame, + .frame_params = videotoolbox_frame_params, .init = videotoolbox_common_init, .uninit = videotoolbox_uninit, .priv_data_size = sizeof(VTContext), }; -AVHWAccel ff_mpeg4_videotoolbox_hwaccel = { +const AVHWAccel ff_mpeg4_videotoolbox_hwaccel = { .name = "mpeg4_videotoolbox", .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_MPEG4, @@ -1030,6 +1151,7 @@ AVHWAccel ff_mpeg4_videotoolbox_hwaccel = { .start_frame = videotoolbox_mpeg_start_frame, .decode_slice = videotoolbox_mpeg_decode_slice, .end_frame = videotoolbox_mpeg_end_frame, + .frame_params = videotoolbox_frame_params, .init = videotoolbox_common_init, .uninit = videotoolbox_uninit, .priv_data_size = sizeof(VTContext), @@ -1057,13 +1179,13 @@ int av_videotoolbox_default_init2(AVCodecContext *avctx, AVVideotoolboxContext * avctx->hwaccel_context = vtctx ?: av_videotoolbox_alloc_context(); if (!avctx->hwaccel_context) return AVERROR(ENOMEM); - return videotoolbox_default_init(avctx); + return videotoolbox_start(avctx); } void av_videotoolbox_default_free(AVCodecContext *avctx) { - videotoolbox_default_free(avctx); + videotoolbox_stop(avctx); av_freep(&avctx->hwaccel_context); } #endif /* CONFIG_VIDEOTOOLBOX */ diff --git a/libavcodec/videotoolboxenc.c b/libavcodec/videotoolboxenc.c index eba6cc672f81d..7796a685c25ee 100644 --- a/libavcodec/videotoolboxenc.c +++ b/libavcodec/videotoolboxenc.c @@ -35,6 +35,17 @@ #include "h264_sei.h" #include +#if !HAVE_KCMVIDEOCODECTYPE_HEVC +enum { kCMVideoCodecType_HEVC = 'hvc1' }; +#endif + +typedef OSStatus (*getParameterSetAtIndex)(CMFormatDescriptionRef videoDesc, + size_t parameterSetIndex, + const uint8_t * _Nullable *parameterSetPointerOut, + size_t *parameterSetSizeOut, + size_t *parameterSetCountOut, + int *NALUnitHeaderLengthOut); + //These symbols may not be present static struct{ CFStringRef kCVImageBufferColorPrimaries_ITU_R_2020; @@ -65,10 +76,15 @@ static struct{ CFStringRef kVTProfileLevel_H264_High_5_2; CFStringRef kVTProfileLevel_H264_High_AutoLevel; + CFStringRef kVTProfileLevel_HEVC_Main_AutoLevel; + CFStringRef kVTProfileLevel_HEVC_Main10_AutoLevel; + CFStringRef kVTCompressionPropertyKey_RealTime; CFStringRef kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder; CFStringRef kVTVideoEncoderSpecification_RequireHardwareAcceleratedVideoEncoder; + + getParameterSetAtIndex CMVideoFormatDescriptionGetHEVCParameterSetAtIndex; } compat_keys; #define GET_SYM(symbol, defaultVal) \ @@ -83,6 +99,12 @@ do{ \ static pthread_once_t once_ctrl = PTHREAD_ONCE_INIT; static void loadVTEncSymbols(){ + compat_keys.CMVideoFormatDescriptionGetHEVCParameterSetAtIndex = + (getParameterSetAtIndex)dlsym( + RTLD_DEFAULT, + "CMVideoFormatDescriptionGetHEVCParameterSetAtIndex" + ); + GET_SYM(kCVImageBufferColorPrimaries_ITU_R_2020, "ITU_R_2020"); GET_SYM(kCVImageBufferTransferFunction_ITU_R_2020, "ITU_R_2020"); GET_SYM(kCVImageBufferYCbCrMatrix_ITU_R_2020, "ITU_R_2020"); @@ -111,6 +133,9 @@ static void loadVTEncSymbols(){ GET_SYM(kVTProfileLevel_H264_High_5_2, "H264_High_5_2"); GET_SYM(kVTProfileLevel_H264_High_AutoLevel, "H264_High_AutoLevel"); + GET_SYM(kVTProfileLevel_HEVC_Main_AutoLevel, "HEVC_Main_AutoLevel"); + GET_SYM(kVTProfileLevel_HEVC_Main10_AutoLevel, "HEVC_Main10_AutoLevel"); + GET_SYM(kVTCompressionPropertyKey_RealTime, "RealTime"); GET_SYM(kVTVideoEncoderSpecification_EnableHardwareAcceleratedVideoEncoder, @@ -133,6 +158,13 @@ typedef enum VTH264Entropy{ VT_CABAC } VTH264Entropy; +typedef enum VT_HEVCProfile { + HEVC_PROF_AUTO, + HEVC_PROF_MAIN, + HEVC_PROF_MAIN10, + HEVC_PROF_COUNT +} VT_HEVCProfile; + static const uint8_t start_code[] = { 0, 0, 0, 1 }; typedef struct ExtraSEI { @@ -149,10 +181,12 @@ typedef struct BufNode { typedef struct VTEncContext { AVClass *class; + enum AVCodecID codec_id; VTCompressionSessionRef session; CFStringRef ycbcr_matrix; CFStringRef color_primaries; CFStringRef transfer_function; + getParameterSetAtIndex get_param_set_func; pthread_mutex_t lock; pthread_cond_t cv_sample_sent; @@ -348,6 +382,7 @@ static CMVideoCodecType get_cm_codec_type(enum AVCodecID id) { switch (id) { case AV_CODEC_ID_H264: return kCMVideoCodecType_H264; + case AV_CODEC_ID_HEVC: return kCMVideoCodecType_HEVC; default: return 0; } } @@ -365,17 +400,18 @@ static int get_params_size( CMVideoFormatDescriptionRef vid_fmt, size_t *size) { + VTEncContext *vtctx = avctx->priv_data; size_t total_size = 0; size_t ps_count; int is_count_bad = 0; size_t i; int status; - status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, - 0, - NULL, - NULL, - &ps_count, - NULL); + status = vtctx->get_param_set_func(vid_fmt, + 0, + NULL, + NULL, + &ps_count, + NULL); if (status) { is_count_bad = 1; ps_count = 0; @@ -385,12 +421,12 @@ static int get_params_size( for (i = 0; i < ps_count || is_count_bad; i++) { const uint8_t *ps; size_t ps_size; - status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, - i, - &ps, - &ps_size, - NULL, - NULL); + status = vtctx->get_param_set_func(vid_fmt, + i, + &ps, + &ps_size, + NULL, + NULL); if (status) { /* * When ps_count is invalid, status != 0 ends the loop normally @@ -419,18 +455,19 @@ static int copy_param_sets( uint8_t *dst, size_t dst_size) { + VTEncContext *vtctx = avctx->priv_data; size_t ps_count; int is_count_bad = 0; int status; size_t offset = 0; size_t i; - status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, - 0, - NULL, - NULL, - &ps_count, - NULL); + status = vtctx->get_param_set_func(vid_fmt, + 0, + NULL, + NULL, + &ps_count, + NULL); if (status) { is_count_bad = 1; ps_count = 0; @@ -443,12 +480,12 @@ static int copy_param_sets( size_t ps_size; size_t next_offset; - status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, - i, - &ps, - &ps_size, - NULL, - NULL); + status = vtctx->get_param_set_func(vid_fmt, + i, + &ps, + &ps_size, + NULL, + NULL); if (status) { if (i > 0 && is_count_bad) status = 0; @@ -548,6 +585,7 @@ static int get_length_code_size( CMSampleBufferRef sample_buffer, size_t *size) { + VTEncContext *vtctx = avctx->priv_data; CMVideoFormatDescriptionRef vid_fmt; int isize; int status; @@ -558,12 +596,12 @@ static int get_length_code_size( return AVERROR_EXTERNAL; } - status = CMVideoFormatDescriptionGetH264ParameterSetAtIndex(vid_fmt, - 0, - NULL, - NULL, - NULL, - &isize); + status = vtctx->get_param_set_func(vid_fmt, + 0, + NULL, + NULL, + NULL, + &isize); if (status) { av_log(avctx, AV_LOG_ERROR, "Error getting length code size: %d\n", status); return AVERROR_EXTERNAL; @@ -579,8 +617,8 @@ static int get_length_code_size( * If profile_level_val is NULL and this method returns true, don't specify the * profile/level to the encoder. */ -static bool get_vt_profile_level(AVCodecContext *avctx, - CFStringRef *profile_level_val) +static bool get_vt_h264_profile_level(AVCodecContext *avctx, + CFStringRef *profile_level_val) { VTEncContext *vtctx = avctx->priv_data; int64_t profile = vtctx->profile; @@ -670,6 +708,41 @@ static bool get_vt_profile_level(AVCodecContext *avctx, return true; } +/* + * Returns true on success. + * + * If profile_level_val is NULL and this method returns true, don't specify the + * profile/level to the encoder. + */ +static bool get_vt_hevc_profile_level(AVCodecContext *avctx, + CFStringRef *profile_level_val) +{ + VTEncContext *vtctx = avctx->priv_data; + int64_t profile = vtctx->profile; + + *profile_level_val = NULL; + + switch (profile) { + case HEVC_PROF_AUTO: + return true; + case HEVC_PROF_MAIN: + *profile_level_val = + compat_keys.kVTProfileLevel_HEVC_Main_AutoLevel; + break; + case HEVC_PROF_MAIN10: + *profile_level_val = + compat_keys.kVTProfileLevel_HEVC_Main10_AutoLevel; + break; + } + + if (!*profile_level_val) { + av_log(avctx, AV_LOG_ERROR, "Invalid Profile/Level.\n"); + return false; + } + + return true; +} + static int get_cv_pixel_format(AVCodecContext* avctx, enum AVPixelFormat fmt, enum AVColorRange range, @@ -944,52 +1017,55 @@ static int vtenc_create_encoder(AVCodecContext *avctx, return AVERROR_EXTERNAL; } - bytes_per_second_value = max_rate >> 3; - bytes_per_second = CFNumberCreate(kCFAllocatorDefault, - kCFNumberSInt64Type, - &bytes_per_second_value); - if (!bytes_per_second) { - return AVERROR(ENOMEM); - } - one_second_value = 1; - one_second = CFNumberCreate(kCFAllocatorDefault, - kCFNumberSInt64Type, - &one_second_value); - if (!one_second) { - CFRelease(bytes_per_second); - return AVERROR(ENOMEM); - } - nums[0] = bytes_per_second; - nums[1] = one_second; - data_rate_limits = CFArrayCreate(kCFAllocatorDefault, - nums, - 2, - &kCFTypeArrayCallBacks); + if (vtctx->codec_id == AV_CODEC_ID_H264) { + // kVTCompressionPropertyKey_DataRateLimits is not available for HEVC + bytes_per_second_value = max_rate >> 3; + bytes_per_second = CFNumberCreate(kCFAllocatorDefault, + kCFNumberSInt64Type, + &bytes_per_second_value); + if (!bytes_per_second) { + return AVERROR(ENOMEM); + } + one_second_value = 1; + one_second = CFNumberCreate(kCFAllocatorDefault, + kCFNumberSInt64Type, + &one_second_value); + if (!one_second) { + CFRelease(bytes_per_second); + return AVERROR(ENOMEM); + } + nums[0] = (void *)bytes_per_second; + nums[1] = (void *)one_second; + data_rate_limits = CFArrayCreate(kCFAllocatorDefault, + (const void **)nums, + 2, + &kCFTypeArrayCallBacks); + + if (!data_rate_limits) { + CFRelease(bytes_per_second); + CFRelease(one_second); + return AVERROR(ENOMEM); + } + status = VTSessionSetProperty(vtctx->session, + kVTCompressionPropertyKey_DataRateLimits, + data_rate_limits); - if (!data_rate_limits) { CFRelease(bytes_per_second); CFRelease(one_second); - return AVERROR(ENOMEM); - } - status = VTSessionSetProperty(vtctx->session, - kVTCompressionPropertyKey_DataRateLimits, - data_rate_limits); - - CFRelease(bytes_per_second); - CFRelease(one_second); - CFRelease(data_rate_limits); - - if (status) { - av_log(avctx, AV_LOG_ERROR, "Error setting max bitrate property: %d\n", status); - return AVERROR_EXTERNAL; - } + CFRelease(data_rate_limits); - if (profile_level) { - status = VTSessionSetProperty(vtctx->session, - kVTCompressionPropertyKey_ProfileLevel, - profile_level); if (status) { - av_log(avctx, AV_LOG_ERROR, "Error setting profile/level property: %d\n", status); + av_log(avctx, AV_LOG_ERROR, "Error setting max bitrate property: %d\n", status); + return AVERROR_EXTERNAL; + } + + if (profile_level) { + status = VTSessionSetProperty(vtctx->session, + kVTCompressionPropertyKey_ProfileLevel, + profile_level); + if (status) { + av_log(avctx, AV_LOG_ERROR, "Error setting profile/level property: %d\n", status); + } } } @@ -1205,18 +1281,28 @@ static av_cold int vtenc_init(AVCodecContext *avctx) return AVERROR(EINVAL); } - vtctx->has_b_frames = avctx->max_b_frames > 0; - if(vtctx->has_b_frames && vtctx->profile == H264_PROF_BASELINE){ - av_log(avctx, AV_LOG_WARNING, "Cannot use B-frames with baseline profile. Output will not contain B-frames.\n"); - vtctx->has_b_frames = false; - } + vtctx->codec_id = avctx->codec_id; - if (vtctx->entropy == VT_CABAC && vtctx->profile == H264_PROF_BASELINE) { - av_log(avctx, AV_LOG_WARNING, "CABAC entropy requires 'main' or 'high' profile, but baseline was requested. Encode will not use CABAC entropy.\n"); - vtctx->entropy = VT_ENTROPY_NOT_SET; - } + if (vtctx->codec_id == AV_CODEC_ID_H264) { + vtctx->get_param_set_func = CMVideoFormatDescriptionGetH264ParameterSetAtIndex; - if (!get_vt_profile_level(avctx, &profile_level)) return AVERROR(EINVAL); + vtctx->has_b_frames = avctx->max_b_frames > 0; + if(vtctx->has_b_frames && vtctx->profile == H264_PROF_BASELINE){ + av_log(avctx, AV_LOG_WARNING, "Cannot use B-frames with baseline profile. Output will not contain B-frames.\n"); + vtctx->has_b_frames = false; + } + + if (vtctx->entropy == VT_CABAC && vtctx->profile == H264_PROF_BASELINE) { + av_log(avctx, AV_LOG_WARNING, "CABAC entropy requires 'main' or 'high' profile, but baseline was requested. Encode will not use CABAC entropy.\n"); + vtctx->entropy = VT_ENTROPY_NOT_SET; + } + + if (!get_vt_h264_profile_level(avctx, &profile_level)) return AVERROR(EINVAL); + } else { + vtctx->get_param_set_func = compat_keys.CMVideoFormatDescriptionGetHEVCParameterSetAtIndex; + if (!vtctx->get_param_set_func) return AVERROR(EINVAL); + if (!get_vt_hevc_profile_level(avctx, &profile_level)) return AVERROR(EINVAL); + } vtctx->session = NULL; @@ -1853,8 +1939,6 @@ static int get_cv_pixel_info( "Color range not set for %s. Using MPEG range.\n", av_get_pix_fmt_name(av_format)); } - - av_log(avctx, AV_LOG_WARNING, ""); } switch (av_format) { @@ -2424,9 +2508,19 @@ static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_NONE }; -#define OFFSET(x) offsetof(VTEncContext, x) #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM -static const AVOption options[] = { +#define COMMON_OPTIONS \ + { "allow_sw", "Allow software encoding", OFFSET(allow_sw), AV_OPT_TYPE_BOOL, \ + { .i64 = 0 }, 0, 1, VE }, \ + { "realtime", "Hint that encoding should happen in real-time if not faster (e.g. capturing from camera).", \ + OFFSET(realtime), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, \ + { "frames_before", "Other frames will come before the frames in this session. This helps smooth concatenation issues.", \ + OFFSET(frames_before), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, \ + { "frames_after", "Other frames will come after the frames in this session. This helps smooth concatenation issues.", \ + OFFSET(frames_after), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, + +#define OFFSET(x) offsetof(VTEncContext, x) +static const AVOption h264_options[] = { { "profile", "Profile", OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = H264_PROF_AUTO }, H264_PROF_AUTO, H264_PROF_COUNT, VE, "profile" }, { "baseline", "Baseline Profile", 0, AV_OPT_TYPE_CONST, { .i64 = H264_PROF_BASELINE }, INT_MIN, INT_MAX, VE, "profile" }, { "main", "Main Profile", 0, AV_OPT_TYPE_CONST, { .i64 = H264_PROF_MAIN }, INT_MIN, INT_MAX, VE, "profile" }, @@ -2444,32 +2538,22 @@ static const AVOption options[] = { { "5.1", "Level 5.1", 0, AV_OPT_TYPE_CONST, { .i64 = 51 }, INT_MIN, INT_MAX, VE, "level" }, { "5.2", "Level 5.2", 0, AV_OPT_TYPE_CONST, { .i64 = 52 }, INT_MIN, INT_MAX, VE, "level" }, - { "allow_sw", "Allow software encoding", OFFSET(allow_sw), AV_OPT_TYPE_BOOL, - { .i64 = 0 }, 0, 1, VE }, - { "coder", "Entropy coding", OFFSET(entropy), AV_OPT_TYPE_INT, { .i64 = VT_ENTROPY_NOT_SET }, VT_ENTROPY_NOT_SET, VT_CABAC, VE, "coder" }, { "cavlc", "CAVLC entropy coding", 0, AV_OPT_TYPE_CONST, { .i64 = VT_CAVLC }, INT_MIN, INT_MAX, VE, "coder" }, { "vlc", "CAVLC entropy coding", 0, AV_OPT_TYPE_CONST, { .i64 = VT_CAVLC }, INT_MIN, INT_MAX, VE, "coder" }, { "cabac", "CABAC entropy coding", 0, AV_OPT_TYPE_CONST, { .i64 = VT_CABAC }, INT_MIN, INT_MAX, VE, "coder" }, { "ac", "CABAC entropy coding", 0, AV_OPT_TYPE_CONST, { .i64 = VT_CABAC }, INT_MIN, INT_MAX, VE, "coder" }, - { "realtime", "Hint that encoding should happen in real-time if not faster (e.g. capturing from camera).", - OFFSET(realtime), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - - { "frames_before", "Other frames will come before the frames in this session. This helps smooth concatenation issues.", - OFFSET(frames_before), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "frames_after", "Other frames will come after the frames in this session. This helps smooth concatenation issues.", - OFFSET(frames_after), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "a53cc", "Use A53 Closed Captions (if available)", OFFSET(a53_cc), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, VE }, + COMMON_OPTIONS { NULL }, }; static const AVClass h264_videotoolbox_class = { .class_name = "h264_videotoolbox", .item_name = av_default_item_name, - .option = options, + .option = h264_options, .version = LIBAVUTIL_VERSION_INT, }; @@ -2488,3 +2572,36 @@ AVCodec ff_h264_videotoolbox_encoder = { .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, }; + +static const AVOption hevc_options[] = { + { "profile", "Profile", OFFSET(profile), AV_OPT_TYPE_INT, { .i64 = HEVC_PROF_AUTO }, HEVC_PROF_AUTO, HEVC_PROF_COUNT, VE, "profile" }, + { "main", "Main Profile", 0, AV_OPT_TYPE_CONST, { .i64 = HEVC_PROF_MAIN }, INT_MIN, INT_MAX, VE, "profile" }, + { "main10", "Main10 Profile", 0, AV_OPT_TYPE_CONST, { .i64 = HEVC_PROF_MAIN10 }, INT_MIN, INT_MAX, VE, "profile" }, + + COMMON_OPTIONS + { NULL }, +}; + +static const AVClass hevc_videotoolbox_class = { + .class_name = "hevc_videotoolbox", + .item_name = av_default_item_name, + .option = hevc_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_hevc_videotoolbox_encoder = { + .name = "hevc_videotoolbox", + .long_name = NULL_IF_CONFIG_SMALL("VideoToolbox H.265 Encoder"), + .type = AVMEDIA_TYPE_VIDEO, + .id = AV_CODEC_ID_HEVC, + .priv_data_size = sizeof(VTEncContext), + .pix_fmts = pix_fmts, + .init = vtenc_init, + .encode2 = vtenc_frame, + .close = vtenc_close, + .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, + .priv_class = &hevc_videotoolbox_class, + .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | + FF_CODEC_CAP_INIT_CLEANUP, + .wrapper_name = "videotoolbox", +}; diff --git a/libavcodec/vorbis.c b/libavcodec/vorbis.c index 399020eec5517..cca2aa7c635bc 100644 --- a/libavcodec/vorbis.c +++ b/libavcodec/vorbis.c @@ -58,7 +58,7 @@ int ff_vorbis_len2vlc(uint8_t *bits, uint32_t *codes, unsigned num) uint32_t exit_at_level[33] = { 404 }; unsigned i, j, p, code; - for (p = 0; (bits[p] == 0) && (p < num); ++p) + for (p = 0; (p < num) && (bits[p] == 0); ++p) ; if (p == num) return 0; @@ -67,11 +67,11 @@ int ff_vorbis_len2vlc(uint8_t *bits, uint32_t *codes, unsigned num) if (bits[p] > 32) return AVERROR_INVALIDDATA; for (i = 0; i < bits[p]; ++i) - exit_at_level[i+1] = 1 << i; + exit_at_level[i+1] = 1u << i; ++p; - for (i = p; (bits[i] == 0) && (i < num); ++i) + for (i = p; (i < num) && (bits[i] == 0); ++i) ; if (i == num) return 0; @@ -91,7 +91,7 @@ int ff_vorbis_len2vlc(uint8_t *bits, uint32_t *codes, unsigned num) exit_at_level[i] = 0; // construct code (append 0s to end) and introduce new exits for (j = i + 1 ;j <= bits[p]; ++j) - exit_at_level[j] = code + (1 << (j - 1)); + exit_at_level[j] = code + (1u << (j - 1)); codes[p] = code; } diff --git a/libavcodec/vorbisdec.c b/libavcodec/vorbisdec.c index 2a4f482031ef3..00e9cd8a1317b 100644 --- a/libavcodec/vorbisdec.c +++ b/libavcodec/vorbisdec.c @@ -1862,6 +1862,7 @@ AVCodec ff_vorbis_decoder = { .decode = vorbis_decode_frame, .flush = vorbis_decode_flush, .capabilities = AV_CODEC_CAP_DR1, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, .channel_layouts = ff_vorbis_channel_layouts, .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }, diff --git a/libavcodec/vorbisenc.c b/libavcodec/vorbisenc.c index a4ecd8f754774..18a679f2dcadd 100644 --- a/libavcodec/vorbisenc.c +++ b/libavcodec/vorbisenc.c @@ -1093,9 +1093,13 @@ static int vorbis_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, PutBitContext pb; if (frame) { + AVFrame *clone; if ((ret = ff_af_queue_add(&venc->afq, frame)) < 0) return ret; - ff_bufqueue_add(avctx, &venc->bufqueue, av_frame_clone(frame)); + clone = av_frame_clone(frame); + if (!clone) + return AVERROR(ENOMEM); + ff_bufqueue_add(avctx, &venc->bufqueue, clone); } else if (!venc->afq.remaining_samples) return 0; diff --git a/libavcodec/vp3.c b/libavcodec/vp3.c index f167acf4eefa7..1d8375331493f 100644 --- a/libavcodec/vp3.c +++ b/libavcodec/vp3.c @@ -951,9 +951,11 @@ static int unpack_vlcs(Vp3DecodeContext *s, GetBitContext *gb, Vp3Fragment *all_fragments = s->all_fragments; VLC_TYPE(*vlc_table)[2] = table->table; - if (num_coeffs < 0) + if (num_coeffs < 0) { av_log(s->avctx, AV_LOG_ERROR, "Invalid number of coefficients at level %d\n", coeff_index); + return AVERROR_INVALIDDATA; + } if (eob_run > num_coeffs) { coeff_i = @@ -978,6 +980,9 @@ static int unpack_vlcs(Vp3DecodeContext *s, GetBitContext *gb, if (eob_run_get_bits[token]) eob_run += get_bits(gb, eob_run_get_bits[token]); + if (!eob_run) + eob_run = INT_MAX; + // record only the number of blocks ended in this plane, // any spill will be recorded in the next plane. if (eob_run > num_coeffs - coeff_i) { @@ -1761,7 +1766,9 @@ static av_cold int vp3_decode_init(AVCodecContext *avctx) for (i = 0; i < 3; i++) s->qps[i] = -1; - avcodec_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_x_shift, &s->chroma_y_shift); + ret = av_pix_fmt_get_chroma_sub_sample(avctx->pix_fmt, &s->chroma_x_shift, &s->chroma_y_shift); + if (ret) + return ret; s->y_superblock_width = (s->width + 31) / 32; s->y_superblock_height = (s->height + 31) / 32; diff --git a/libavcodec/vp8.c b/libavcodec/vp8.c index 7841a9d964e72..62b9f8bc2dae2 100644 --- a/libavcodec/vp8.c +++ b/libavcodec/vp8.c @@ -27,6 +27,7 @@ #include "libavutil/imgutils.h" #include "avcodec.h" +#include "hwaccel.h" #include "internal.h" #include "mathops.h" #include "rectangle.h" @@ -72,16 +73,30 @@ static int vp8_alloc_frame(VP8Context *s, VP8Frame *f, int ref) if ((ret = ff_thread_get_buffer(s->avctx, &f->tf, ref ? AV_GET_BUFFER_FLAG_REF : 0)) < 0) return ret; - if (!(f->seg_map = av_buffer_allocz(s->mb_width * s->mb_height))) { - ff_thread_release_buffer(s->avctx, &f->tf); - return AVERROR(ENOMEM); + if (!(f->seg_map = av_buffer_allocz(s->mb_width * s->mb_height))) + goto fail; + if (s->avctx->hwaccel) { + const AVHWAccel *hwaccel = s->avctx->hwaccel; + if (hwaccel->frame_priv_data_size) { + f->hwaccel_priv_buf = av_buffer_allocz(hwaccel->frame_priv_data_size); + if (!f->hwaccel_priv_buf) + goto fail; + f->hwaccel_picture_private = f->hwaccel_priv_buf->data; + } } return 0; + +fail: + av_buffer_unref(&f->seg_map); + ff_thread_release_buffer(s->avctx, &f->tf); + return AVERROR(ENOMEM); } static void vp8_release_frame(VP8Context *s, VP8Frame *f) { av_buffer_unref(&f->seg_map); + av_buffer_unref(&f->hwaccel_priv_buf); + f->hwaccel_picture_private = NULL; ff_thread_release_buffer(s->avctx, &f->tf); } @@ -99,6 +114,12 @@ static int vp8_ref_frame(VP8Context *s, VP8Frame *dst, VP8Frame *src) vp8_release_frame(s, dst); return AVERROR(ENOMEM); } + if (src->hwaccel_picture_private) { + dst->hwaccel_priv_buf = av_buffer_ref(src->hwaccel_priv_buf); + if (!dst->hwaccel_priv_buf) + return AVERROR(ENOMEM); + dst->hwaccel_picture_private = dst->hwaccel_priv_buf->data; + } return 0; } @@ -140,12 +161,28 @@ static VP8Frame *vp8_find_free_buffer(VP8Context *s) av_log(s->avctx, AV_LOG_FATAL, "Ran out of free frames!\n"); abort(); } - if (frame->tf.f->data[0]) + if (frame->tf.f->buf[0]) vp8_release_frame(s, frame); return frame; } +static enum AVPixelFormat get_pixel_format(VP8Context *s) +{ + enum AVPixelFormat pix_fmts[] = { +#if CONFIG_VP8_VAAPI_HWACCEL + AV_PIX_FMT_VAAPI, +#endif +#if CONFIG_VP8_NVDEC_HWACCEL + AV_PIX_FMT_CUDA, +#endif + AV_PIX_FMT_YUV420P, + AV_PIX_FMT_NONE, + }; + + return ff_get_format(s->avctx, pix_fmts); +} + static av_always_inline int update_dimensions(VP8Context *s, int width, int height, int is_vp7) { @@ -161,6 +198,13 @@ int update_dimensions(VP8Context *s, int width, int height, int is_vp7) return ret; } + if (!s->actually_webp && !is_vp7) { + s->pix_fmt = get_pixel_format(s); + if (s->pix_fmt < 0) + return AVERROR(EINVAL); + avctx->pix_fmt = s->pix_fmt; + } + s->mb_width = (s->avctx->coded_width + 15) / 16; s->mb_height = (s->avctx->coded_height + 15) / 16; @@ -218,8 +262,9 @@ static void parse_segment_info(VP8Context *s) int i; s->segmentation.update_map = vp8_rac_get(c); + s->segmentation.update_feature_data = vp8_rac_get(c); - if (vp8_rac_get(c)) { // update segment feature data + if (s->segmentation.update_feature_data) { s->segmentation.absolute_vals = vp8_rac_get(c); for (i = 0; i < 4; i++) @@ -274,6 +319,7 @@ static int setup_partitions(VP8Context *s, const uint8_t *buf, int buf_size) int size = AV_RL24(sizes + 3 * i); if (buf_size - size < 0) return -1; + s->coeff_partition_size[i] = size; ret = ff_vp56_init_range_decoder(&s->coeff_partition[i], buf, size); if (ret < 0) @@ -281,7 +327,11 @@ static int setup_partitions(VP8Context *s, const uint8_t *buf, int buf_size) buf += size; buf_size -= size; } - return ff_vp56_init_range_decoder(&s->coeff_partition[i], buf, buf_size); + + s->coeff_partition_size[i] = buf_size; + ff_vp56_init_range_decoder(&s->coeff_partition[i], buf, buf_size); + + return 0; } static void vp7_get_quants(VP8Context *s) @@ -308,28 +358,28 @@ static void vp8_get_quants(VP8Context *s) VP56RangeCoder *c = &s->c; int i, base_qi; - int yac_qi = vp8_rac_get_uint(c, 7); - int ydc_delta = vp8_rac_get_sint(c, 4); - int y2dc_delta = vp8_rac_get_sint(c, 4); - int y2ac_delta = vp8_rac_get_sint(c, 4); - int uvdc_delta = vp8_rac_get_sint(c, 4); - int uvac_delta = vp8_rac_get_sint(c, 4); + s->quant.yac_qi = vp8_rac_get_uint(c, 7); + s->quant.ydc_delta = vp8_rac_get_sint(c, 4); + s->quant.y2dc_delta = vp8_rac_get_sint(c, 4); + s->quant.y2ac_delta = vp8_rac_get_sint(c, 4); + s->quant.uvdc_delta = vp8_rac_get_sint(c, 4); + s->quant.uvac_delta = vp8_rac_get_sint(c, 4); for (i = 0; i < 4; i++) { if (s->segmentation.enabled) { base_qi = s->segmentation.base_quant[i]; if (!s->segmentation.absolute_vals) - base_qi += yac_qi; + base_qi += s->quant.yac_qi; } else - base_qi = yac_qi; + base_qi = s->quant.yac_qi; - s->qmat[i].luma_qmul[0] = vp8_dc_qlookup[av_clip_uintp2(base_qi + ydc_delta, 7)]; + s->qmat[i].luma_qmul[0] = vp8_dc_qlookup[av_clip_uintp2(base_qi + s->quant.ydc_delta, 7)]; s->qmat[i].luma_qmul[1] = vp8_ac_qlookup[av_clip_uintp2(base_qi, 7)]; - s->qmat[i].luma_dc_qmul[0] = vp8_dc_qlookup[av_clip_uintp2(base_qi + y2dc_delta, 7)] * 2; + s->qmat[i].luma_dc_qmul[0] = vp8_dc_qlookup[av_clip_uintp2(base_qi + s->quant.y2dc_delta, 7)] * 2; /* 101581>>16 is equivalent to 155/100 */ - s->qmat[i].luma_dc_qmul[1] = vp8_ac_qlookup[av_clip_uintp2(base_qi + y2ac_delta, 7)] * 101581 >> 16; - s->qmat[i].chroma_qmul[0] = vp8_dc_qlookup[av_clip_uintp2(base_qi + uvdc_delta, 7)]; - s->qmat[i].chroma_qmul[1] = vp8_ac_qlookup[av_clip_uintp2(base_qi + uvac_delta, 7)]; + s->qmat[i].luma_dc_qmul[1] = vp8_ac_qlookup[av_clip_uintp2(base_qi + s->quant.y2ac_delta, 7)] * 101581 >> 16; + s->qmat[i].chroma_qmul[0] = vp8_dc_qlookup[av_clip_uintp2(base_qi + s->quant.uvdc_delta, 7)]; + s->qmat[i].chroma_qmul[1] = vp8_ac_qlookup[av_clip_uintp2(base_qi + s->quant.uvac_delta, 7)]; s->qmat[i].luma_dc_qmul[1] = FFMAX(s->qmat[i].luma_dc_qmul[1], 8); s->qmat[i].chroma_qmul[0] = FFMIN(s->qmat[i].chroma_qmul[0], 132); @@ -606,6 +656,8 @@ static int vp7_decode_frame_header(VP8Context *s, const uint8_t *buf, int buf_si s->fade_present = vp8_rac_get(c); } + if (c->end <= c->buffer && c->bits >= 0) + return AVERROR_INVALIDDATA; /* E. Fading information for previous frame */ if (s->fade_present && vp8_rac_get(c)) { if ((ret = vp7_fade_frame(s ,c)) < 0) @@ -661,6 +713,8 @@ static int vp8_decode_frame_header(VP8Context *s, const uint8_t *buf, int buf_si buf += 3; buf_size -= 3; + s->header_partition_size = header_size; + if (s->profile > 3) av_log(s->avctx, AV_LOG_WARNING, "Unknown profile %d\n", s->profile); @@ -726,9 +780,11 @@ static int vp8_decode_frame_header(VP8Context *s, const uint8_t *buf, int buf_si s->filter.level = vp8_rac_get_uint(c, 6); s->filter.sharpness = vp8_rac_get_uint(c, 3); - if ((s->lf_delta.enabled = vp8_rac_get(c))) - if (vp8_rac_get(c)) + if ((s->lf_delta.enabled = vp8_rac_get(c))) { + s->lf_delta.update = vp8_rac_get(c); + if (s->lf_delta.update) update_lf_deltas(s); + } if (setup_partitions(s, buf, buf_size)) { av_log(s->avctx, AV_LOG_ERROR, "Invalid partitions\n"); @@ -768,6 +824,13 @@ static int vp8_decode_frame_header(VP8Context *s, const uint8_t *buf, int buf_si vp78_update_pred16x16_pred8x8_mvc_probabilities(s, VP8_MVC_SIZE); } + // Record the entropy coder state here so that hwaccels can use it. + s->c.code_word = vp56_rac_renorm(&s->c); + s->coder_state_at_header_end.input = s->c.buffer - (-s->c.bits / 8); + s->coder_state_at_header_end.range = s->c.high; + s->coder_state_at_header_end.value = s->c.code_word >> 16; + s->coder_state_at_header_end.bit_count = -s->c.bits % 8; + return 0; } @@ -2540,7 +2603,6 @@ static int vp8_decode_mb_row_sliced(AVCodecContext *avctx, void *tdata, return vp78_decode_mb_row_sliced(avctx, tdata, jobnr, threadnr, IS_VP8); } - static av_always_inline int vp78_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPacket *avpkt, int is_vp7) @@ -2550,8 +2612,6 @@ int vp78_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, enum AVDiscard skip_thresh; VP8Frame *av_uninit(curframe), *prev_frame; - av_assert0(avctx->pix_fmt == AV_PIX_FMT_YUVA420P || avctx->pix_fmt == AV_PIX_FMT_YUV420P); - if (is_vp7) ret = vp7_decode_frame_header(s, avpkt->data, avpkt->size); else @@ -2560,6 +2620,17 @@ int vp78_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, if (ret < 0) goto err; + if (s->actually_webp) { + // avctx->pix_fmt already set in caller. + } else if (!is_vp7 && s->pix_fmt == AV_PIX_FMT_NONE) { + s->pix_fmt = get_pixel_format(s); + if (s->pix_fmt < 0) { + ret = AVERROR(EINVAL); + goto err; + } + avctx->pix_fmt = s->pix_fmt; + } + prev_frame = s->framep[VP56_FRAME_CURRENT]; referenced = s->update_last || s->update_golden == VP56_FRAME_CURRENT || @@ -2578,7 +2649,7 @@ int vp78_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, // release no longer referenced frames for (i = 0; i < 5; i++) - if (s->frames[i].tf.f->data[0] && + if (s->frames[i].tf.f->buf[0] && &s->frames[i] != prev_frame && &s->frames[i] != s->framep[VP56_FRAME_PREVIOUS] && &s->frames[i] != s->framep[VP56_FRAME_GOLDEN] && @@ -2631,56 +2702,70 @@ int vp78_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, s->next_framep[VP56_FRAME_CURRENT] = curframe; - if (avctx->codec->update_thread_context) - ff_thread_finish_setup(avctx); + ff_thread_finish_setup(avctx); - s->linesize = curframe->tf.f->linesize[0]; - s->uvlinesize = curframe->tf.f->linesize[1]; + if (avctx->hwaccel) { + ret = avctx->hwaccel->start_frame(avctx, avpkt->data, avpkt->size); + if (ret < 0) + goto err; - memset(s->top_nnz, 0, s->mb_width * sizeof(*s->top_nnz)); - /* Zero macroblock structures for top/top-left prediction - * from outside the frame. */ - if (!s->mb_layout) - memset(s->macroblocks + s->mb_height * 2 - 1, 0, - (s->mb_width + 1) * sizeof(*s->macroblocks)); - if (!s->mb_layout && s->keyframe) - memset(s->intra4x4_pred_mode_top, DC_PRED, s->mb_width * 4); + ret = avctx->hwaccel->decode_slice(avctx, avpkt->data, avpkt->size); + if (ret < 0) + goto err; - memset(s->ref_count, 0, sizeof(s->ref_count)); + ret = avctx->hwaccel->end_frame(avctx); + if (ret < 0) + goto err; - if (s->mb_layout == 1) { - // Make sure the previous frame has read its segmentation map, - // if we re-use the same map. - if (prev_frame && s->segmentation.enabled && - !s->segmentation.update_map) - ff_thread_await_progress(&prev_frame->tf, 1, 0); + } else { + s->linesize = curframe->tf.f->linesize[0]; + s->uvlinesize = curframe->tf.f->linesize[1]; + + memset(s->top_nnz, 0, s->mb_width * sizeof(*s->top_nnz)); + /* Zero macroblock structures for top/top-left prediction + * from outside the frame. */ + if (!s->mb_layout) + memset(s->macroblocks + s->mb_height * 2 - 1, 0, + (s->mb_width + 1) * sizeof(*s->macroblocks)); + if (!s->mb_layout && s->keyframe) + memset(s->intra4x4_pred_mode_top, DC_PRED, s->mb_width * 4); + + memset(s->ref_count, 0, sizeof(s->ref_count)); + + if (s->mb_layout == 1) { + // Make sure the previous frame has read its segmentation map, + // if we re-use the same map. + if (prev_frame && s->segmentation.enabled && + !s->segmentation.update_map) + ff_thread_await_progress(&prev_frame->tf, 1, 0); + if (is_vp7) + vp7_decode_mv_mb_modes(avctx, curframe, prev_frame); + else + vp8_decode_mv_mb_modes(avctx, curframe, prev_frame); + } + + if (avctx->active_thread_type == FF_THREAD_FRAME) + num_jobs = 1; + else + num_jobs = FFMIN(s->num_coeff_partitions, avctx->thread_count); + s->num_jobs = num_jobs; + s->curframe = curframe; + s->prev_frame = prev_frame; + s->mv_bounds.mv_min.y = -MARGIN; + s->mv_bounds.mv_max.y = ((s->mb_height - 1) << 6) + MARGIN; + for (i = 0; i < MAX_THREADS; i++) { + VP8ThreadData *td = &s->thread_data[i]; + atomic_init(&td->thread_mb_pos, 0); + atomic_init(&td->wait_mb_pos, INT_MAX); + } if (is_vp7) - vp7_decode_mv_mb_modes(avctx, curframe, prev_frame); + avctx->execute2(avctx, vp7_decode_mb_row_sliced, s->thread_data, NULL, + num_jobs); else - vp8_decode_mv_mb_modes(avctx, curframe, prev_frame); + avctx->execute2(avctx, vp8_decode_mb_row_sliced, s->thread_data, NULL, + num_jobs); } - if (avctx->active_thread_type == FF_THREAD_FRAME) - num_jobs = 1; - else - num_jobs = FFMIN(s->num_coeff_partitions, avctx->thread_count); - s->num_jobs = num_jobs; - s->curframe = curframe; - s->prev_frame = prev_frame; - s->mv_bounds.mv_min.y = -MARGIN; - s->mv_bounds.mv_max.y = ((s->mb_height - 1) << 6) + MARGIN; - for (i = 0; i < MAX_THREADS; i++) { - VP8ThreadData *td = &s->thread_data[i]; - atomic_init(&td->thread_mb_pos, 0); - atomic_init(&td->wait_mb_pos, INT_MAX); - } - if (is_vp7) - avctx->execute2(avctx, vp7_decode_mb_row_sliced, s->thread_data, NULL, - num_jobs); - else - avctx->execute2(avctx, vp8_decode_mb_row_sliced, s->thread_data, NULL, - num_jobs); - ff_thread_report_progress(&curframe->tf, INT_MAX, 0); memcpy(&s->framep[0], &s->next_framep[0], sizeof(s->framep[0]) * 4); @@ -2750,6 +2835,7 @@ int vp78_decode_init(AVCodecContext *avctx, int is_vp7) s->avctx = avctx; s->vp7 = avctx->codec->id == AV_CODEC_ID_VP7; + s->pix_fmt = AV_PIX_FMT_NONE; avctx->pix_fmt = AV_PIX_FMT_YUV420P; avctx->internal->allocate_progress = 1; @@ -2823,13 +2909,14 @@ static int vp8_decode_update_thread_context(AVCodecContext *dst, s->mb_height = s_src->mb_height; } + s->pix_fmt = s_src->pix_fmt; s->prob[0] = s_src->prob[!s_src->update_probabilities]; s->segmentation = s_src->segmentation; s->lf_delta = s_src->lf_delta; memcpy(s->sign_bias, s_src->sign_bias, sizeof(s->sign_bias)); for (i = 0; i < FF_ARRAY_ELEMS(s_src->frames); i++) { - if (s_src->frames[i].tf.f->data[0]) { + if (s_src->frames[i].tf.f->buf[0]) { int ret = vp8_ref_frame(s, &s->frames[i], &s_src->frames[i]); if (ret < 0) return ret; @@ -2876,5 +2963,14 @@ AVCodec ff_vp8_decoder = { .flush = vp8_decode_flush, .init_thread_copy = ONLY_IF_THREADS_ENABLED(vp8_decode_init_thread_copy), .update_thread_context = ONLY_IF_THREADS_ENABLED(vp8_decode_update_thread_context), + .hw_configs = (const AVCodecHWConfigInternal*[]) { +#if CONFIG_VP8_VAAPI_HWACCEL + HWACCEL_VAAPI(vp8), +#endif +#if CONFIG_VP8_NVDEC_HWACCEL + HWACCEL_NVDEC(vp8), +#endif + NULL + }, }; #endif /* CONFIG_VP7_DECODER */ diff --git a/libavcodec/vp8.h b/libavcodec/vp8.h index 8263997e3fcd4..70d21e3c60460 100644 --- a/libavcodec/vp8.h +++ b/libavcodec/vp8.h @@ -138,12 +138,18 @@ typedef struct VP8ThreadData { typedef struct VP8Frame { ThreadFrame tf; AVBufferRef *seg_map; + + AVBufferRef *hwaccel_priv_buf; + void *hwaccel_picture_private; } VP8Frame; #define MAX_THREADS 8 typedef struct VP8Context { VP8ThreadData *thread_data; AVCodecContext *avctx; + enum AVPixelFormat pix_fmt; + int actually_webp; + VP8Frame *framep[4]; VP8Frame *next_framep[4]; VP8Frame *curframe; @@ -172,6 +178,7 @@ typedef struct VP8Context { uint8_t enabled; uint8_t absolute_vals; uint8_t update_map; + uint8_t update_feature_data; int8_t base_quant[4]; int8_t filter_level[4]; ///< base loop filter level } segmentation; @@ -199,8 +206,19 @@ typedef struct VP8Context { int16_t chroma_qmul[2]; } qmat[4]; + // Raw quantisation values, which may be needed by hwaccel decode. + struct { + int yac_qi; + int ydc_delta; + int y2dc_delta; + int y2ac_delta; + int uvdc_delta; + int uvac_delta; + } quant; + struct { uint8_t enabled; ///< whether each mb can have a different strength based on mode/ref + uint8_t update; /** * filter strength adjustment for the following macroblock modes: @@ -228,6 +246,20 @@ typedef struct VP8Context { VP56RangeCoder c; ///< header context, includes mb modes and motion vectors + /* This contains the entropy coder state at the end of the header + * block, in the form specified by the standard. For use by + * hwaccels, so that a hardware decoder has the information to + * start decoding at the macroblock layer. + */ + struct { + const uint8_t *input; + uint32_t range; + uint32_t value; + int bit_count; + } coder_state_at_header_end; + + int header_partition_size; + /** * These are all of the updatable probabilities for binary decisions. * They are only implicitly reset on keyframes, making it quite likely @@ -265,6 +297,7 @@ typedef struct VP8Context { */ int num_coeff_partitions; VP56RangeCoder coeff_partition[8]; + int coeff_partition_size[8]; VideoDSPContext vdsp; VP8DSPContext vp8dsp; H264PredContext hpc; diff --git a/libavcodec/vp9.c b/libavcodec/vp9.c index 6b5de19266f33..b1178c9c0cb0c 100644 --- a/libavcodec/vp9.c +++ b/libavcodec/vp9.c @@ -23,6 +23,7 @@ #include "avcodec.h" #include "get_bits.h" +#include "hwaccel.h" #include "internal.h" #include "profiles.h" #include "thread.h" @@ -169,7 +170,10 @@ static int vp9_frame_ref(AVCodecContext *avctx, VP9Frame *dst, VP9Frame *src) static int update_size(AVCodecContext *avctx, int w, int h) { -#define HWACCEL_MAX (CONFIG_VP9_DXVA2_HWACCEL + CONFIG_VP9_D3D11VA_HWACCEL * 2 + CONFIG_VP9_VAAPI_HWACCEL) +#define HWACCEL_MAX (CONFIG_VP9_DXVA2_HWACCEL + \ + CONFIG_VP9_D3D11VA_HWACCEL * 2 + \ + CONFIG_VP9_NVDEC_HWACCEL + \ + CONFIG_VP9_VAAPI_HWACCEL) enum AVPixelFormat pix_fmts[HWACCEL_MAX + 2], *fmtp = pix_fmts; VP9Context *s = avctx->priv_data; uint8_t *p; @@ -184,6 +188,7 @@ static int update_size(AVCodecContext *avctx, int w, int h) switch (s->pix_fmt) { case AV_PIX_FMT_YUV420P: + case AV_PIX_FMT_YUV420P10: #if CONFIG_VP9_DXVA2_HWACCEL *fmtp++ = AV_PIX_FMT_DXVA2_VLD; #endif @@ -191,12 +196,17 @@ static int update_size(AVCodecContext *avctx, int w, int h) *fmtp++ = AV_PIX_FMT_D3D11VA_VLD; *fmtp++ = AV_PIX_FMT_D3D11; #endif +#if CONFIG_VP9_NVDEC_HWACCEL + *fmtp++ = AV_PIX_FMT_CUDA; +#endif #if CONFIG_VP9_VAAPI_HWACCEL *fmtp++ = AV_PIX_FMT_VAAPI; #endif break; - case AV_PIX_FMT_YUV420P10: case AV_PIX_FMT_YUV420P12: +#if CONFIG_VP9_NVDEC_HWACCEL + *fmtp++ = AV_PIX_FMT_CUDA; +#endif #if CONFIG_VP9_VAAPI_HWACCEL *fmtp++ = AV_PIX_FMT_VAAPI; #endif @@ -1634,8 +1644,10 @@ FF_ENABLE_DEPRECATION_WARNINGS #endif { ret = decode_tiles(avctx, data, size); - if (ret < 0) + if (ret < 0) { + ff_thread_report_progress(&s->s.frames[CUR_FRAME].tf, INT_MAX, 0); return ret; + } } // Sum all counts fields into td[0].counts for tile threading @@ -1785,4 +1797,23 @@ AVCodec ff_vp9_decoder = { .init_thread_copy = ONLY_IF_THREADS_ENABLED(vp9_decode_init_thread_copy), .update_thread_context = ONLY_IF_THREADS_ENABLED(vp9_decode_update_thread_context), .profiles = NULL_IF_CONFIG_SMALL(ff_vp9_profiles), + .bsfs = "vp9_superframe_split", + .hw_configs = (const AVCodecHWConfigInternal*[]) { +#if CONFIG_VP9_DXVA2_HWACCEL + HWACCEL_DXVA2(vp9), +#endif +#if CONFIG_VP9_D3D11VA_HWACCEL + HWACCEL_D3D11VA(vp9), +#endif +#if CONFIG_VP9_D3D11VA2_HWACCEL + HWACCEL_D3D11VA2(vp9), +#endif +#if CONFIG_VP9_NVDEC_HWACCEL + HWACCEL_NVDEC(vp9), +#endif +#if CONFIG_VP9_VAAPI_HWACCEL + HWACCEL_VAAPI(vp9), +#endif + NULL + }, }; diff --git a/libavcodec/vp9_parser.c b/libavcodec/vp9_parser.c index 9900e7ab1f796..9531f34a32531 100644 --- a/libavcodec/vp9_parser.c +++ b/libavcodec/vp9_parser.c @@ -25,21 +25,19 @@ #include "libavcodec/get_bits.h" #include "parser.h" -typedef struct VP9ParseContext { - int n_frames; // 1-8 - int size[8]; - int marker_size; - int64_t pts; -} VP9ParseContext; - -static int parse_frame(AVCodecParserContext *ctx, const uint8_t *buf, int size) +static int parse(AVCodecParserContext *ctx, + AVCodecContext *avctx, + const uint8_t **out_data, int *out_size, + const uint8_t *data, int size) { - VP9ParseContext *s = ctx->priv_data; GetBitContext gb; - int res, profile, keyframe, invisible; + int res, profile, keyframe; - if ((res = init_get_bits8(&gb, buf, size)) < 0) - return res; + *out_data = data; + *out_size = size; + + if ((res = init_get_bits8(&gb, data, size)) < 0) + return size; // parsers can't return errors get_bits(&gb, 2); // frame marker profile = get_bits1(&gb); profile |= get_bits1(&gb) << 1; @@ -47,10 +45,8 @@ static int parse_frame(AVCodecParserContext *ctx, const uint8_t *buf, int size) if (get_bits1(&gb)) { keyframe = 0; - invisible = 0; } else { keyframe = !get_bits1(&gb); - invisible = !get_bits1(&gb); } if (!keyframe) { @@ -61,113 +57,10 @@ static int parse_frame(AVCodecParserContext *ctx, const uint8_t *buf, int size) ctx->key_frame = 1; } - if (!invisible) { - if (ctx->pts == AV_NOPTS_VALUE) - ctx->pts = s->pts; - s->pts = AV_NOPTS_VALUE; - } else if (ctx->pts != AV_NOPTS_VALUE) { - s->pts = ctx->pts; - ctx->pts = AV_NOPTS_VALUE; - } - - return 0; -} - -static int parse(AVCodecParserContext *ctx, - AVCodecContext *avctx, - const uint8_t **out_data, int *out_size, - const uint8_t *data, int size) -{ - VP9ParseContext *s = ctx->priv_data; - int full_size = size; - int marker; - - if (size <= 0) { - *out_size = 0; - *out_data = data; - - return 0; - } - - if (s->n_frames > 0) { - int i; - int size_sum = 0; - - for (i = 0; i < s->n_frames ;i++) - size_sum += s->size[i]; - size_sum += s->marker_size; - - if (size_sum != size) { - av_log(avctx, AV_LOG_ERROR, "Inconsistent input frame sizes %d %d\n", - size_sum, size); - s->n_frames = 0; - } - } - - if (s->n_frames > 0) { - *out_data = data; - *out_size = s->size[--s->n_frames]; - parse_frame(ctx, *out_data, *out_size); - - return s->n_frames > 0 ? *out_size : size /* i.e. include idx tail */; - } - - marker = data[size - 1]; - if ((marker & 0xe0) == 0xc0) { - int nbytes = 1 + ((marker >> 3) & 0x3); - int n_frames = 1 + (marker & 0x7), idx_sz = 2 + n_frames * nbytes; - - if (size >= idx_sz && data[size - idx_sz] == marker) { - const uint8_t *idx = data + size + 1 - idx_sz; - int first = 1; - - switch (nbytes) { -#define case_n(a, rd) \ - case a: \ - while (n_frames--) { \ - unsigned sz = rd; \ - idx += a; \ - if (sz == 0 || sz > size) { \ - s->n_frames = 0; \ - *out_size = size; \ - *out_data = data; \ - av_log(avctx, AV_LOG_ERROR, \ - "Invalid superframe packet size: %u frame size: %d\n", \ - sz, size); \ - return full_size; \ - } \ - if (first) { \ - first = 0; \ - *out_data = data; \ - *out_size = sz; \ - s->n_frames = n_frames; \ - } else { \ - s->size[n_frames] = sz; \ - } \ - data += sz; \ - size -= sz; \ - } \ - s->marker_size = size; \ - parse_frame(ctx, *out_data, *out_size); \ - return s->n_frames > 0 ? *out_size : full_size - - case_n(1, *idx); - case_n(2, AV_RL16(idx)); - case_n(3, AV_RL24(idx)); - case_n(4, AV_RL32(idx)); - } - } - } - - *out_data = data; - *out_size = size; - parse_frame(ctx, data, size); - return size; } AVCodecParser ff_vp9_parser = { .codec_ids = { AV_CODEC_ID_VP9 }, - .priv_data_size = sizeof(VP9ParseContext), .parser_parse = parse, }; diff --git a/libavcodec/vp9_superframe_bsf.c b/libavcodec/vp9_superframe_bsf.c index b686adbe1673f..52569ab097afa 100644 --- a/libavcodec/vp9_superframe_bsf.c +++ b/libavcodec/vp9_superframe_bsf.c @@ -27,20 +27,17 @@ #define MAX_CACHE 8 typedef struct VP9BSFContext { int n_cache; - struct CachedBuf { - uint8_t *data; - int size; - } cache[MAX_CACHE]; + AVPacket *cache[MAX_CACHE]; } VP9BSFContext; -static void stats(const struct CachedBuf *in, int n_in, +static void stats(AVPacket * const *in, int n_in, unsigned *_max, unsigned *_sum) { int n; unsigned max = 0, sum = 0; for (n = 0; n < n_in; n++) { - unsigned sz = in[n].size; + unsigned sz = in[n]->size; if (sz > max) max = sz; @@ -51,7 +48,7 @@ static void stats(const struct CachedBuf *in, int n_in, *_sum = sum; } -static int merge_superframe(const struct CachedBuf *in, int n_in, AVPacket *out) +static int merge_superframe(AVPacket * const *in, int n_in, AVPacket *out) { unsigned max, sum, mag, marker, n, sz; uint8_t *ptr; @@ -66,30 +63,32 @@ static int merge_superframe(const struct CachedBuf *in, int n_in, AVPacket *out) return res; ptr = out->data; for (n = 0; n < n_in; n++) { - memcpy(ptr, in[n].data, in[n].size); - ptr += in[n].size; + memcpy(ptr, in[n]->data, in[n]->size); + ptr += in[n]->size; } #define wloop(mag, wr) \ - for (n = 0; n < n_in; n++) { \ - wr; \ - ptr += mag + 1; \ - } + do { \ + for (n = 0; n < n_in; n++) { \ + wr; \ + ptr += mag + 1; \ + } \ + } while (0) // write superframe with marker 110[mag:2][nframes:3] *ptr++ = marker; switch (mag) { case 0: - wloop(mag, *ptr = in[n].size); + wloop(mag, *ptr = in[n]->size); break; case 1: - wloop(mag, AV_WL16(ptr, in[n].size)); + wloop(mag, AV_WL16(ptr, in[n]->size)); break; case 2: - wloop(mag, AV_WL24(ptr, in[n].size)); + wloop(mag, AV_WL24(ptr, in[n]->size)); break; case 3: - wloop(mag, AV_WL32(ptr, in[n].size)); + wloop(mag, AV_WL32(ptr, in[n]->size)); break; } *ptr++ = marker; @@ -135,7 +134,7 @@ static int vp9_superframe_filter(AVBSFContext *ctx, AVPacket *out) if (uses_superframe_syntax && s->n_cache > 0) { av_log(ctx, AV_LOG_ERROR, "Mixing of superframe syntax and naked VP9 frames not supported"); - res = AVERROR_INVALIDDATA; + res = AVERROR(ENOSYS); goto done; } else if ((!invisible || uses_superframe_syntax) && !s->n_cache) { // passthrough @@ -148,33 +147,26 @@ static int vp9_superframe_filter(AVBSFContext *ctx, AVPacket *out) goto done; } - s->cache[s->n_cache].size = in->size; - if (invisible && !uses_superframe_syntax) { - s->cache[s->n_cache].data = av_malloc(in->size); - if (!s->cache[s->n_cache].data) { - res = AVERROR(ENOMEM); - goto done; - } - memcpy(s->cache[s->n_cache++].data, in->data, in->size); + av_packet_move_ref(s->cache[s->n_cache++], in); + + if (invisible) { res = AVERROR(EAGAIN); goto done; } av_assert0(s->n_cache > 0); - s->cache[s->n_cache].data = in->data; - // build superframe - if ((res = merge_superframe(s->cache, s->n_cache + 1, out)) < 0) + if ((res = merge_superframe(s->cache, s->n_cache, out)) < 0) goto done; - for (n = 0; n < s->n_cache; n++) - av_freep(&s->cache[n].data); - s->n_cache = 0; - - res = av_packet_copy_props(out, in); + res = av_packet_copy_props(out, s->cache[s->n_cache - 1]); if (res < 0) goto done; + for (n = 0; n < s->n_cache; n++) + av_packet_unref(s->cache[n]); + s->n_cache = 0; + done: if (res < 0) av_packet_unref(out); @@ -182,14 +174,29 @@ static int vp9_superframe_filter(AVBSFContext *ctx, AVPacket *out) return res; } +static int vp9_superframe_init(AVBSFContext *ctx) +{ + VP9BSFContext *s = ctx->priv_data; + int n; + + // alloc cache packets + for (n = 0; n < MAX_CACHE; n++) { + s->cache[n] = av_packet_alloc(); + if (!s->cache[n]) + return AVERROR(ENOMEM); + } + + return 0; +} + static void vp9_superframe_close(AVBSFContext *ctx) { VP9BSFContext *s = ctx->priv_data; int n; // free cached data - for (n = 0; n < s->n_cache; n++) - av_freep(&s->cache[n].data); + for (n = 0; n < MAX_CACHE; n++) + av_packet_free(&s->cache[n]); } static const enum AVCodecID codec_ids[] = { @@ -200,6 +207,7 @@ const AVBitStreamFilter ff_vp9_superframe_bsf = { .name = "vp9_superframe", .priv_data_size = sizeof(VP9BSFContext), .filter = vp9_superframe_filter, + .init = vp9_superframe_init, .close = vp9_superframe_close, .codec_ids = codec_ids, }; diff --git a/libavcodec/vp9_superframe_split_bsf.c b/libavcodec/vp9_superframe_split_bsf.c index 6d6d8e664d0ac..9c4aa33dc1b42 100644 --- a/libavcodec/vp9_superframe_split_bsf.c +++ b/libavcodec/vp9_superframe_split_bsf.c @@ -30,7 +30,7 @@ #include "get_bits.h" typedef struct VP9SFSplitContext { - AVPacket *buffer_pkt; + AVPacket buffer_pkt; int nb_frames; int next_frame; @@ -43,13 +43,13 @@ static int vp9_superframe_split_filter(AVBSFContext *ctx, AVPacket *out) VP9SFSplitContext *s = ctx->priv_data; AVPacket *in; int i, j, ret, marker; - int is_superframe = !!s->buffer_pkt; + int is_superframe = !!s->buffer_pkt.data; - if (!s->buffer_pkt) { - ret = ff_bsf_get_packet(ctx, &s->buffer_pkt); + if (!s->buffer_pkt.data) { + ret = ff_bsf_get_packet_ref(ctx, &s->buffer_pkt); if (ret < 0) return ret; - in = s->buffer_pkt; + in = &s->buffer_pkt; marker = in->data[in->size - 1]; if ((marker & 0xe0) == 0xc0) { @@ -59,7 +59,7 @@ static int vp9_superframe_split_filter(AVBSFContext *ctx, AVPacket *out) if (in->size >= idx_size && in->data[in->size - idx_size] == marker) { GetByteContext bc; - int total_size = 0; + int64_t total_size = 0; bytestream2_init(&bc, in->data + in->size + 1 - idx_size, nb_frames * length_size); @@ -70,7 +70,7 @@ static int vp9_superframe_split_filter(AVBSFContext *ctx, AVPacket *out) frame_size |= bytestream2_get_byte(&bc) << (j * 8); total_size += frame_size; - if (total_size > in->size - idx_size) { + if (frame_size < 0 || total_size > in->size - idx_size) { av_log(ctx, AV_LOG_ERROR, "Invalid frame size in a superframe: %d\n", frame_size); ret = AVERROR(EINVAL); @@ -90,7 +90,7 @@ static int vp9_superframe_split_filter(AVBSFContext *ctx, AVPacket *out) GetBitContext gb; int profile, invisible = 0; - ret = av_packet_ref(out, s->buffer_pkt); + ret = av_packet_ref(out, &s->buffer_pkt); if (ret < 0) goto fail; @@ -101,7 +101,7 @@ static int vp9_superframe_split_filter(AVBSFContext *ctx, AVPacket *out) s->next_frame++; if (s->next_frame >= s->nb_frames) - av_packet_free(&s->buffer_pkt); + av_packet_unref(&s->buffer_pkt); ret = init_get_bits8(&gb, out->data, out->size); if (ret < 0) @@ -121,20 +121,21 @@ static int vp9_superframe_split_filter(AVBSFContext *ctx, AVPacket *out) out->pts = AV_NOPTS_VALUE; } else { - av_packet_move_ref(out, s->buffer_pkt); - av_packet_free(&s->buffer_pkt); + av_packet_move_ref(out, &s->buffer_pkt); } return 0; fail: - av_packet_free(&s->buffer_pkt); + if (ret < 0) + av_packet_unref(out); + av_packet_unref(&s->buffer_pkt); return ret; } static void vp9_superframe_split_uninit(AVBSFContext *ctx) { VP9SFSplitContext *s = ctx->priv_data; - av_packet_free(&s->buffer_pkt); + av_packet_unref(&s->buffer_pkt); } const AVBitStreamFilter ff_vp9_superframe_split_bsf = { diff --git a/libavcodec/vda_vt_internal.h b/libavcodec/vt_internal.h similarity index 79% rename from libavcodec/vda_vt_internal.h rename to libavcodec/vt_internal.h index 326a60a695647..fb64735b8cd35 100644 --- a/libavcodec/vda_vt_internal.h +++ b/libavcodec/vt_internal.h @@ -16,17 +16,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVCODEC_VDA_VT_INTERNAL_H -#define AVCODEC_VDA_VT_INTERNAL_H - -void ff_vda_output_callback(void *vda_hw_ctx, - CFDictionaryRef user_info, - OSStatus status, - uint32_t infoFlags, - CVImageBufferRef image_buffer); - -int ff_vda_default_init(AVCodecContext *avctx); -void ff_vda_default_free(AVCodecContext *avctx); +#ifndef AVCODEC_VT_INTERNAL_H +#define AVCODEC_VT_INTERNAL_H typedef struct VTContext { // The current bitstream buffer. @@ -47,11 +38,14 @@ typedef struct VTContext { // Non-NULL if the new hwaccel API is used. This is only a separate struct // to ease compatibility with the old API. struct AVVideotoolboxContext *vt_ctx; + + // Current H264 parameters (used to trigger decoder restart on SPS changes). + uint8_t sps[3]; + bool reconfig_needed; } VTContext; int ff_videotoolbox_alloc_frame(AVCodecContext *avctx, AVFrame *frame); int ff_videotoolbox_uninit(AVCodecContext *avctx); -int ff_videotoolbox_buffer_create(VTContext *vtctx, AVFrame *frame); int ff_videotoolbox_h264_start_frame(AVCodecContext *avctx, const uint8_t *buffer, uint32_t size); @@ -60,4 +54,5 @@ int ff_videotoolbox_h264_decode_slice(AVCodecContext *avctx, uint32_t size); CFDataRef ff_videotoolbox_avcc_extradata_create(AVCodecContext *avctx); CFDataRef ff_videotoolbox_hvcc_extradata_create(AVCodecContext *avctx); -#endif /* AVCODEC_VDA_VT_INTERNAL_H */ + +#endif /* AVCODEC_VT_INTERNAL_H */ diff --git a/libavcodec/wavpack.c b/libavcodec/wavpack.c index a117e8aa81ba2..0e40b29879959 100644 --- a/libavcodec/wavpack.c +++ b/libavcodec/wavpack.c @@ -433,8 +433,8 @@ static inline int wv_unpack_stereo(WavpackFrameContext *s, GetBitContext *gb, L2 = L + ((s->decorr[i].weightA * (int64_t)A + 512) >> 10); R2 = R + ((s->decorr[i].weightB * (int64_t)B + 512) >> 10); } else { - L2 = L + ((int)(s->decorr[i].weightA * (unsigned)A + 512) >> 10); - R2 = R + ((int)(s->decorr[i].weightB * (unsigned)B + 512) >> 10); + L2 = L + (unsigned)((int)(s->decorr[i].weightA * (unsigned)A + 512) >> 10); + R2 = R + (unsigned)((int)(s->decorr[i].weightB * (unsigned)B + 512) >> 10); } if (A && L) s->decorr[i].weightA -= ((((L ^ A) >> 30) & 2) - 1) * s->decorr[i].delta; @@ -446,7 +446,7 @@ static inline int wv_unpack_stereo(WavpackFrameContext *s, GetBitContext *gb, if (type != AV_SAMPLE_FMT_S16P) L2 = L + ((s->decorr[i].weightA * (int64_t)s->decorr[i].samplesA[0] + 512) >> 10); else - L2 = L + ((int)(s->decorr[i].weightA * (unsigned)s->decorr[i].samplesA[0] + 512) >> 10); + L2 = L + (unsigned)((int)(s->decorr[i].weightA * (unsigned)s->decorr[i].samplesA[0] + 512) >> 10); UPDATE_WEIGHT_CLIP(s->decorr[i].weightA, s->decorr[i].delta, s->decorr[i].samplesA[0], L); L = L2; if (type != AV_SAMPLE_FMT_S16P) @@ -460,7 +460,7 @@ static inline int wv_unpack_stereo(WavpackFrameContext *s, GetBitContext *gb, if (type != AV_SAMPLE_FMT_S16P) R2 = R + ((s->decorr[i].weightB * (int64_t)s->decorr[i].samplesB[0] + 512) >> 10); else - R2 = R + ((int)(s->decorr[i].weightB * (unsigned)s->decorr[i].samplesB[0] + 512) >> 10); + R2 = R + (unsigned)((int)(s->decorr[i].weightB * (unsigned)s->decorr[i].samplesB[0] + 512) >> 10); UPDATE_WEIGHT_CLIP(s->decorr[i].weightB, s->decorr[i].delta, s->decorr[i].samplesB[0], R); R = R2; @@ -472,7 +472,7 @@ static inline int wv_unpack_stereo(WavpackFrameContext *s, GetBitContext *gb, if (type != AV_SAMPLE_FMT_S16P) L2 = L + ((s->decorr[i].weightA * (int64_t)R2 + 512) >> 10); else - L2 = L + ((int)(s->decorr[i].weightA * (unsigned)R2 + 512) >> 10); + L2 = L + (unsigned)((int)(s->decorr[i].weightA * (unsigned)R2 + 512) >> 10); UPDATE_WEIGHT_CLIP(s->decorr[i].weightA, s->decorr[i].delta, R2, L); L = L2; s->decorr[i].samplesB[0] = L; @@ -480,7 +480,7 @@ static inline int wv_unpack_stereo(WavpackFrameContext *s, GetBitContext *gb, } if (type == AV_SAMPLE_FMT_S16P) { - if (FFABS(L) + (unsigned)FFABS(R) > (1<<19)) { + if (FFABS((int64_t)L) + FFABS((int64_t)R) > (1<<19)) { av_log(s->avctx, AV_LOG_ERROR, "sample %d %d too large\n", L, R); return AVERROR_INVALIDDATA; } @@ -554,7 +554,7 @@ static inline int wv_unpack_mono(WavpackFrameContext *s, GetBitContext *gb, if (type != AV_SAMPLE_FMT_S16P) S = T + ((s->decorr[i].weightA * (int64_t)A + 512) >> 10); else - S = T + ((int)(s->decorr[i].weightA * (unsigned)A + 512) >> 10); + S = T + (unsigned)((int)(s->decorr[i].weightA * (unsigned)A + 512) >> 10); if (A && T) s->decorr[i].weightA -= ((((T ^ A) >> 30) & 2) - 1) * s->decorr[i].delta; s->decorr[i].samplesA[j] = T = S; diff --git a/libavcodec/webp.c b/libavcodec/webp.c index efa864a6f141d..077bb06f85a7c 100644 --- a/libavcodec/webp.c +++ b/libavcodec/webp.c @@ -1335,6 +1335,7 @@ static int vp8_lossy_decode_frame(AVCodecContext *avctx, AVFrame *p, if (!s->initialized) { ff_vp8_decode_init(avctx); s->initialized = 1; + s->v.actually_webp = 1; } avctx->pix_fmt = s->has_alpha ? AV_PIX_FMT_YUVA420P : AV_PIX_FMT_YUV420P; s->lossless = 0; @@ -1504,7 +1505,7 @@ static int webp_decode_frame(AVCodecContext *avctx, void *data, int *got_frame, } bytestream2_seek(&exif_gb, ifd_offset, SEEK_SET); - if (avpriv_exif_decode_ifd(avctx, &exif_gb, le, 0, &exif_metadata) < 0) { + if (ff_exif_decode_ifd(avctx, &exif_gb, le, 0, &exif_metadata) < 0) { av_log(avctx, AV_LOG_ERROR, "error decoding Exif data\n"); goto exif_end; } diff --git a/libavcodec/wmalosslessdec.c b/libavcodec/wmalosslessdec.c index 133a3e92d1ad4..eb1db615ae180 100644 --- a/libavcodec/wmalosslessdec.c +++ b/libavcodec/wmalosslessdec.c @@ -1148,6 +1148,7 @@ static void save_bits(WmallDecodeCtx *s, GetBitContext* gb, int len, if (len <= 0 || buflen > s->max_frame_size) { avpriv_request_sample(s->avctx, "Too small input buffer"); s->packet_loss = 1; + s->num_saved_bits = 0; return; } @@ -1255,7 +1256,9 @@ static int decode_packet(AVCodecContext *avctx, void *data, int *got_frame_ptr, (frame_size = show_bits(gb, s->log2_frame_size)) && frame_size <= remaining_bits(s, gb)) { save_bits(s, gb, frame_size, 0); - s->packet_done = !decode_frame(s); + + if (!s->packet_loss) + s->packet_done = !decode_frame(s); } else if (!s->len_prefix && s->num_saved_bits > get_bits_count(&s->gb)) { /* when the frames do not have a length prefix, we don't know the diff --git a/libavcodec/wmaprodec.c b/libavcodec/wmaprodec.c index 77a49c9db8c99..9439bfa771c0f 100644 --- a/libavcodec/wmaprodec.c +++ b/libavcodec/wmaprodec.c @@ -107,8 +107,8 @@ #define MAX_BANDS 29 ///< max number of scale factor bands #define MAX_FRAMESIZE 32768 ///< maximum compressed frame size #define XMA_MAX_STREAMS 8 -#define XMA_MAX_CHANNELS 8 #define XMA_MAX_CHANNELS_STREAM 2 +#define XMA_MAX_CHANNELS (XMA_MAX_STREAMS * XMA_MAX_CHANNELS_STREAM) #define WMAPRO_BLOCK_MIN_BITS 6 ///< log2 of min block size #define WMAPRO_BLOCK_MAX_BITS 13 ///< log2 of max block size diff --git a/libavcodec/wmavoice.c b/libavcodec/wmavoice.c index 2ec4499981f52..444e303b0df16 100644 --- a/libavcodec/wmavoice.c +++ b/libavcodec/wmavoice.c @@ -30,6 +30,7 @@ #include "libavutil/channel_layout.h" #include "libavutil/float_dsp.h" #include "libavutil/mem.h" +#include "libavutil/thread.h" #include "avcodec.h" #include "internal.h" #include "get_bits.h" @@ -310,7 +311,7 @@ static av_cold int decode_vbmtree(GetBitContext *gb, int8_t vbm_tree[25]) return 0; } -static av_cold void wmavoice_init_static_data(AVCodec *codec) +static av_cold void wmavoice_init_static_data(void) { static const uint8_t bits[] = { 2, 2, 2, 4, 4, 4, @@ -365,9 +366,12 @@ static av_cold void wmavoice_flush(AVCodecContext *ctx) */ static av_cold int wmavoice_decode_init(AVCodecContext *ctx) { + static AVOnce init_static_once = AV_ONCE_INIT; int n, flags, pitch_range, lsp16_flag; WMAVoiceContext *s = ctx->priv_data; + ff_thread_once(&init_static_once, wmavoice_init_static_data); + /** * Extradata layout: * - byte 0-18: WMAPro-in-WMAVoice extradata (see wmaprodec.c), @@ -1756,6 +1760,10 @@ static int synth_superframe(AVCodecContext *ctx, AVFrame *frame, stabilize_lsps(lsps[n], s->lsps); } + /* synth_superframe can run multiple times per packet + * free potential previous frame */ + av_frame_unref(frame); + /* get output buffer */ frame->nb_samples = MAX_SFRAMESIZE; if ((res = ff_get_buffer(ctx, frame, 0)) < 0) @@ -1987,7 +1995,6 @@ AVCodec ff_wmavoice_decoder = { .id = AV_CODEC_ID_WMAVOICE, .priv_data_size = sizeof(WMAVoiceContext), .init = wmavoice_decode_init, - .init_static_data = wmavoice_init_static_data, .close = wmavoice_decode_end, .decode = wmavoice_decode_packet, .capabilities = AV_CODEC_CAP_SUBFRAMES | AV_CODEC_CAP_DR1 | AV_CODEC_CAP_DELAY, diff --git a/libavcodec/wmv2dec.c b/libavcodec/wmv2dec.c index 20dbee5703229..ea0e0594b5063 100644 --- a/libavcodec/wmv2dec.c +++ b/libavcodec/wmv2dec.c @@ -30,7 +30,7 @@ #include "wmv2.h" -static void parse_mb_skip(Wmv2Context *w) +static int parse_mb_skip(Wmv2Context *w) { int mb_x, mb_y; MpegEncContext *const s = &w->s; @@ -45,6 +45,8 @@ static void parse_mb_skip(Wmv2Context *w) MB_TYPE_16x16 | MB_TYPE_L0; break; case SKIP_TYPE_MPEG: + if (get_bits_left(&s->gb) < s->mb_height * s->mb_width) + return AVERROR_INVALIDDATA; for (mb_y = 0; mb_y < s->mb_height; mb_y++) for (mb_x = 0; mb_x < s->mb_width; mb_x++) mb_type[mb_y * s->mb_stride + mb_x] = @@ -52,6 +54,8 @@ static void parse_mb_skip(Wmv2Context *w) break; case SKIP_TYPE_ROW: for (mb_y = 0; mb_y < s->mb_height; mb_y++) { + if (get_bits_left(&s->gb) < 1) + return AVERROR_INVALIDDATA; if (get_bits1(&s->gb)) { for (mb_x = 0; mb_x < s->mb_width; mb_x++) mb_type[mb_y * s->mb_stride + mb_x] = @@ -65,6 +69,8 @@ static void parse_mb_skip(Wmv2Context *w) break; case SKIP_TYPE_COL: for (mb_x = 0; mb_x < s->mb_width; mb_x++) { + if (get_bits_left(&s->gb) < 1) + return AVERROR_INVALIDDATA; if (get_bits1(&s->gb)) { for (mb_y = 0; mb_y < s->mb_height; mb_y++) mb_type[mb_y * s->mb_stride + mb_x] = @@ -77,6 +83,7 @@ static void parse_mb_skip(Wmv2Context *w) } break; } + return 0; } static int decode_ext_header(Wmv2Context *w) @@ -170,9 +177,12 @@ int ff_wmv2_decode_secondary_picture_header(MpegEncContext *s) } } else { int cbp_index; + int ret; w->j_type = 0; - parse_mb_skip(w); + ret = parse_mb_skip(w); + if (ret < 0) + return ret; cbp_index = decode012(&s->gb); w->cbp_table_index = wmv2_get_cbp_table_index(s, cbp_index); @@ -359,6 +369,8 @@ int ff_wmv2_decode_mb(MpegEncContext *s, int16_t block[6][64]) w->hshift = 0; return 0; } + if (get_bits_left(&s->gb) <= 0) + return AVERROR_INVALIDDATA; code = get_vlc2(&s->gb, ff_mb_non_intra_vlc[w->cbp_table_index].table, MB_NON_INTRA_VLC_BITS, 3); @@ -369,6 +381,8 @@ int ff_wmv2_decode_mb(MpegEncContext *s, int16_t block[6][64]) cbp = code & 0x3f; } else { s->mb_intra = 1; + if (get_bits_left(&s->gb) <= 0) + return AVERROR_INVALIDDATA; code = get_vlc2(&s->gb, ff_msmp4_mb_i_vlc.table, MB_INTRA_VLC_BITS, 2); if (code < 0) { av_log(s->avctx, AV_LOG_ERROR, @@ -460,10 +474,6 @@ static av_cold int wmv2_decode_init(AVCodecContext *avctx) Wmv2Context *const w = avctx->priv_data; int ret; -#if FF_API_EMU_EDGE - avctx->flags |= CODEC_FLAG_EMU_EDGE; -#endif - if ((ret = ff_msmpeg4_decode_init(avctx)) < 0) return ret; diff --git a/libavcodec/wrapped_avframe.c b/libavcodec/wrapped_avframe.c index 5f88a668b927d..85ff32d13aef0 100644 --- a/libavcodec/wrapped_avframe.c +++ b/libavcodec/wrapped_avframe.c @@ -25,6 +25,7 @@ */ #include "avcodec.h" +#include "decode.h" #include "internal.h" #include "libavutil/internal.h" @@ -98,6 +99,12 @@ static int wrapped_avframe_decode(AVCodecContext *avctx, void *data, av_frame_move_ref(out, in); + err = ff_attach_decode_data(out); + if (err < 0) { + av_frame_unref(out); + return err; + } + *got_frame = 1; return 0; } diff --git a/libavcodec/x86/Makefile b/libavcodec/x86/Makefile index a805cd37b484f..2350c8bbee688 100644 --- a/libavcodec/x86/Makefile +++ b/libavcodec/x86/Makefile @@ -63,6 +63,7 @@ OBJS-$(CONFIG_PNG_DECODER) += x86/pngdsp_init.o OBJS-$(CONFIG_PRORES_DECODER) += x86/proresdsp_init.o OBJS-$(CONFIG_PRORES_LGPL_DECODER) += x86/proresdsp_init.o OBJS-$(CONFIG_RV40_DECODER) += x86/rv40dsp_init.o +OBJS-$(CONFIG_SBC_ENCODER) += x86/sbcdsp_init.o OBJS-$(CONFIG_SVQ1_ENCODER) += x86/svq1enc_init.o OBJS-$(CONFIG_TAK_DECODER) += x86/takdsp_init.o OBJS-$(CONFIG_TRUEHD_DECODER) += x86/mlpdsp_init.o @@ -172,6 +173,7 @@ X86ASM-OBJS-$(CONFIG_PNG_DECODER) += x86/pngdsp.o X86ASM-OBJS-$(CONFIG_PRORES_DECODER) += x86/proresdsp.o X86ASM-OBJS-$(CONFIG_PRORES_LGPL_DECODER) += x86/proresdsp.o X86ASM-OBJS-$(CONFIG_RV40_DECODER) += x86/rv40dsp.o +X86ASM-OBJS-$(CONFIG_SBC_ENCODER) += x86/sbcdsp.o X86ASM-OBJS-$(CONFIG_SVQ1_ENCODER) += x86/svq1enc.o X86ASM-OBJS-$(CONFIG_TAK_DECODER) += x86/takdsp.o X86ASM-OBJS-$(CONFIG_TRUEHD_DECODER) += x86/mlpdsp.o diff --git a/libavcodec/x86/audiodsp.asm b/libavcodec/x86/audiodsp.asm index 3973808ca5169..de395e5fa875d 100644 --- a/libavcodec/x86/audiodsp.asm +++ b/libavcodec/x86/audiodsp.asm @@ -62,7 +62,7 @@ SCALARPRODUCT ; %1 = number of xmm registers used ; %2 = number of inline load/process/store loops per asm loop ; %3 = process 4*mmsize (%3=0) or 8*mmsize (%3=1) bytes per loop -; %4 = CLIPD function takes min/max as float instead of int (CLIPD_SSE2) +; %4 = CLIPD function takes min/max as float instead of int (SSE2 version) ; %5 = suffix %macro VECTOR_CLIP_INT32 4-5 cglobal vector_clip_int32%5, 5,5,%1, dst, src, min, max, len @@ -118,14 +118,11 @@ cglobal vector_clip_int32%5, 5,5,%1, dst, src, min, max, len %endmacro INIT_MMX mmx -%define CLIPD CLIPD_MMX VECTOR_CLIP_INT32 0, 1, 0, 0 INIT_XMM sse2 VECTOR_CLIP_INT32 6, 1, 0, 0, _int -%define CLIPD CLIPD_SSE2 VECTOR_CLIP_INT32 6, 2, 0, 1 INIT_XMM sse4 -%define CLIPD CLIPD_SSE41 %ifdef m8 VECTOR_CLIP_INT32 11, 1, 1, 0 %else diff --git a/libavcodec/x86/bswapdsp.asm b/libavcodec/x86/bswapdsp.asm index 56d808362278a..31c6c48a21dee 100644 --- a/libavcodec/x86/bswapdsp.asm +++ b/libavcodec/x86/bswapdsp.asm @@ -35,14 +35,18 @@ SECTION .text mov r3d, r2d sar r2d, 3 jz .left4_%1 +%if cpuflag(avx2) + sar r2d, 1 + jz .left8_%1 +%endif .loop8_%1: mov%1 m0, [r1 + 0] - mov%1 m1, [r1 + 16] -%if cpuflag(ssse3) + mov%1 m1, [r1 + mmsize] +%if cpuflag(ssse3)||cpuflag(avx2) pshufb m0, m2 pshufb m1, m2 mov%1 [r0 + 0], m0 - mov%1 [r0 + 16], m1 + mov%1 [r0 + mmsize], m1 %else pshuflw m0, m0, 10110001b pshuflw m1, m1, 10110001b @@ -59,18 +63,29 @@ SECTION .text mov%1 [r0 + 0], m2 mov%1 [r0 + 16], m3 %endif - add r0, 32 - add r1, 32 + add r0, mmsize*2 + add r1, mmsize*2 dec r2d jnz .loop8_%1 +%if cpuflag(avx2) +.left8_%1: + mov r2d, r3d + test r3d, 8 + jz .left4_%1 + mov%1 m0, [r1] + pshufb m0, m2 + mov%1 [r0 + 0], m0 + add r1, mmsize + add r0, mmsize +%endif .left4_%1: mov r2d, r3d test r3d, 4 jz .left - mov%1 m0, [r1] + mov%1 xm0, [r1] %if cpuflag(ssse3) - pshufb m0, m2 - mov%1 [r0], m0 + pshufb xm0, xm2 + mov%1 [r0], xm0 %else pshuflw m0, m0, 10110001b pshufhw m0, m0, 10110001b @@ -86,16 +101,16 @@ SECTION .text ; void ff_bswap_buf(uint32_t *dst, const uint32_t *src, int w); %macro BSWAP32_BUF 0 -%if cpuflag(ssse3) +%if cpuflag(ssse3)||cpuflag(avx2) cglobal bswap32_buf, 3,4,3 mov r3, r1 - mova m2, [pb_bswap32] + VBROADCASTI128 m2, [pb_bswap32] %else cglobal bswap32_buf, 3,4,5 mov r3, r1 %endif or r3, r0 - test r3, 15 + test r3, mmsize - 1 jz .start_align BSWAP_LOOPS u jmp .left @@ -105,9 +120,9 @@ cglobal bswap32_buf, 3,4,5 %if cpuflag(ssse3) test r2d, 2 jz .left1 - movq m0, [r1] - pshufb m0, m2 - movq [r0], m0 + movq xm0, [r1] + pshufb xm0, xm2 + movq [r0], xm0 add r1, 8 add r0, 8 .left1: @@ -137,3 +152,8 @@ BSWAP32_BUF INIT_XMM ssse3 BSWAP32_BUF + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +BSWAP32_BUF +%endif diff --git a/libavcodec/x86/bswapdsp_init.c b/libavcodec/x86/bswapdsp_init.c index c042e56371298..877bab1a2ce41 100644 --- a/libavcodec/x86/bswapdsp_init.c +++ b/libavcodec/x86/bswapdsp_init.c @@ -25,6 +25,7 @@ void ff_bswap32_buf_sse2(uint32_t *dst, const uint32_t *src, int w); void ff_bswap32_buf_ssse3(uint32_t *dst, const uint32_t *src, int w); +void ff_bswap32_buf_avx2(uint32_t *dst, const uint32_t *src, int w); av_cold void ff_bswapdsp_init_x86(BswapDSPContext *c) { @@ -34,4 +35,6 @@ av_cold void ff_bswapdsp_init_x86(BswapDSPContext *c) c->bswap_buf = ff_bswap32_buf_sse2; if (EXTERNAL_SSSE3(cpu_flags)) c->bswap_buf = ff_bswap32_buf_ssse3; + if (EXTERNAL_AVX2_FAST(cpu_flags)) + c->bswap_buf = ff_bswap32_buf_avx2; } diff --git a/libavcodec/x86/constants.c b/libavcodec/x86/constants.c index 11002ee61e62e..4bfb78cc36116 100644 --- a/libavcodec/x86/constants.c +++ b/libavcodec/x86/constants.c @@ -26,23 +26,23 @@ DECLARE_ALIGNED(32, const ymm_reg, ff_pw_1) = { 0x0001000100010001ULL, 0x000 0x0001000100010001ULL, 0x0001000100010001ULL }; DECLARE_ALIGNED(32, const ymm_reg, ff_pw_2) = { 0x0002000200020002ULL, 0x0002000200020002ULL, 0x0002000200020002ULL, 0x0002000200020002ULL }; -DECLARE_ALIGNED(16, const xmm_reg, ff_pw_3) = { 0x0003000300030003ULL, 0x0003000300030003ULL }; -DECLARE_ALIGNED(32, const ymm_reg, ff_pw_4) = { 0x0004000400040004ULL, 0x0004000400040004ULL, +DECLARE_ASM_ALIGNED(16, const xmm_reg, ff_pw_3) = { 0x0003000300030003ULL, 0x0003000300030003ULL }; +DECLARE_ASM_ALIGNED(32, const ymm_reg, ff_pw_4) = { 0x0004000400040004ULL, 0x0004000400040004ULL, 0x0004000400040004ULL, 0x0004000400040004ULL }; -DECLARE_ALIGNED(16, const xmm_reg, ff_pw_5) = { 0x0005000500050005ULL, 0x0005000500050005ULL }; +DECLARE_ASM_ALIGNED(16, const xmm_reg, ff_pw_5) = { 0x0005000500050005ULL, 0x0005000500050005ULL }; DECLARE_ALIGNED(16, const xmm_reg, ff_pw_8) = { 0x0008000800080008ULL, 0x0008000800080008ULL }; -DECLARE_ALIGNED(16, const xmm_reg, ff_pw_9) = { 0x0009000900090009ULL, 0x0009000900090009ULL }; +DECLARE_ASM_ALIGNED(16, const xmm_reg, ff_pw_9) = { 0x0009000900090009ULL, 0x0009000900090009ULL }; DECLARE_ALIGNED(8, const uint64_t, ff_pw_15) = 0x000F000F000F000FULL; DECLARE_ALIGNED(16, const xmm_reg, ff_pw_16) = { 0x0010001000100010ULL, 0x0010001000100010ULL }; DECLARE_ALIGNED(16, const xmm_reg, ff_pw_17) = { 0x0011001100110011ULL, 0x0011001100110011ULL }; -DECLARE_ALIGNED(16, const xmm_reg, ff_pw_18) = { 0x0012001200120012ULL, 0x0012001200120012ULL }; +DECLARE_ASM_ALIGNED(16, const xmm_reg, ff_pw_18) = { 0x0012001200120012ULL, 0x0012001200120012ULL }; DECLARE_ALIGNED(16, const xmm_reg, ff_pw_20) = { 0x0014001400140014ULL, 0x0014001400140014ULL }; DECLARE_ALIGNED(16, const xmm_reg, ff_pw_32) = { 0x0020002000200020ULL, 0x0020002000200020ULL }; -DECLARE_ALIGNED(8, const uint64_t, ff_pw_42) = 0x002A002A002A002AULL; -DECLARE_ALIGNED(8, const uint64_t, ff_pw_53) = 0x0035003500350035ULL; -DECLARE_ALIGNED(16, const xmm_reg, ff_pw_64) = { 0x0040004000400040ULL, 0x0040004000400040ULL }; -DECLARE_ALIGNED(8, const uint64_t, ff_pw_96) = 0x0060006000600060ULL; -DECLARE_ALIGNED(8, const uint64_t, ff_pw_128) = 0x0080008000800080ULL; +DECLARE_ASM_ALIGNED(8, const uint64_t, ff_pw_42) = 0x002A002A002A002AULL; +DECLARE_ASM_ALIGNED(8, const uint64_t, ff_pw_53) = 0x0035003500350035ULL; +DECLARE_ASM_ALIGNED(16, const xmm_reg, ff_pw_64) = { 0x0040004000400040ULL, 0x0040004000400040ULL }; +DECLARE_ASM_ALIGNED(8, const uint64_t, ff_pw_96) = 0x0060006000600060ULL; +DECLARE_ASM_ALIGNED(8, const uint64_t, ff_pw_128) = 0x0080008000800080ULL; DECLARE_ALIGNED(32, const ymm_reg, ff_pw_255) = { 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL, 0x00ff00ff00ff00ffULL }; DECLARE_ALIGNED(32, const ymm_reg, ff_pw_256) = { 0x0100010001000100ULL, 0x0100010001000100ULL, @@ -74,7 +74,8 @@ DECLARE_ALIGNED(32, const ymm_reg, ff_pb_2) = { 0x0202020202020202ULL, 0x020 DECLARE_ALIGNED(32, const ymm_reg, ff_pb_3) = { 0x0303030303030303ULL, 0x0303030303030303ULL, 0x0303030303030303ULL, 0x0303030303030303ULL }; DECLARE_ALIGNED(32, const xmm_reg, ff_pb_15) = { 0x0F0F0F0F0F0F0F0FULL, 0x0F0F0F0F0F0F0F0FULL }; -DECLARE_ALIGNED(16, const xmm_reg, ff_pb_80) = { 0x8080808080808080ULL, 0x8080808080808080ULL }; +DECLARE_ALIGNED(32, const ymm_reg, ff_pb_80) = { 0x8080808080808080ULL, 0x8080808080808080ULL, + 0x8080808080808080ULL, 0x8080808080808080ULL }; DECLARE_ALIGNED(32, const ymm_reg, ff_pb_FE) = { 0xFEFEFEFEFEFEFEFEULL, 0xFEFEFEFEFEFEFEFEULL, 0xFEFEFEFEFEFEFEFEULL, 0xFEFEFEFEFEFEFEFEULL }; DECLARE_ALIGNED(8, const uint64_t, ff_pb_FC) = 0xFCFCFCFCFCFCFCFCULL; diff --git a/libavcodec/x86/constants.h b/libavcodec/x86/constants.h index bbb0ef844aa92..85da38b7b948c 100644 --- a/libavcodec/x86/constants.h +++ b/libavcodec/x86/constants.h @@ -57,7 +57,7 @@ extern const ymm_reg ff_pb_0; extern const ymm_reg ff_pb_1; extern const ymm_reg ff_pb_2; extern const ymm_reg ff_pb_3; -extern const xmm_reg ff_pb_80; +extern const ymm_reg ff_pb_80; extern const ymm_reg ff_pb_FE; extern const uint64_t ff_pb_FC; diff --git a/libavcodec/x86/dct32.asm b/libavcodec/x86/dct32.asm index 4e657b5460548..21e2f21c97b95 100644 --- a/libavcodec/x86/dct32.asm +++ b/libavcodec/x86/dct32.asm @@ -23,7 +23,8 @@ SECTION_RODATA 32 -align 32 +ps_p1p1m1m1: dd 0, 0, 0x80000000, 0x80000000, 0, 0, 0x80000000, 0x80000000 + ps_cos_vec: dd 0.500603, 0.505471, 0.515447, 0.531043 dd 0.553104, 0.582935, 0.622504, 0.674808 dd -10.190008, -3.407609, -2.057781, -1.484165 @@ -38,9 +39,6 @@ ps_cos_vec: dd 0.500603, 0.505471, 0.515447, 0.531043 dd 1.000000, 0.707107, 1.000000, -0.707107 dd 0.707107, 0.707107, 0.707107, 0.707107 -align 32 -ps_p1p1m1m1: dd 0, 0, 0x80000000, 0x80000000, 0, 0, 0x80000000, 0x80000000 - %macro BUTTERFLY 4 subps %4, %1, %2 addps %2, %2, %1 diff --git a/libavcodec/x86/exrdsp.asm b/libavcodec/x86/exrdsp.asm index 23c9397ef8f84..3bf240c8b1332 100644 --- a/libavcodec/x86/exrdsp.asm +++ b/libavcodec/x86/exrdsp.asm @@ -73,11 +73,7 @@ REORDER_PIXELS %macro PREDICTOR 0 cglobal predictor, 2,2,5, src, size -%if mmsize == 32 - vbroadcasti128 m0, [pb_80] -%else - mova xm0, [pb_80] -%endif + mova m0, [pb_80] mova xm1, [pb_15] mova xm2, xm0 add srcq, sizeq diff --git a/libavcodec/x86/fft.asm b/libavcodec/x86/fft.asm index cdbfd66e821fd..a671e8f48e58e 100644 --- a/libavcodec/x86/fft.asm +++ b/libavcodec/x86/fft.asm @@ -191,6 +191,23 @@ SECTION .text addps %2, %2, %5 ; {i0,i1,i2,i3} %endmacro +%macro INTERL 5 +%if cpuflag(avx) + vunpckhps %3, %2, %1 + vunpcklps %2, %2, %1 + vextractf128 %4(%5), %2, 0 + vextractf128 %4 %+ H(%5), %3, 0 + vextractf128 %4(%5 + 1), %2, 1 + vextractf128 %4 %+ H(%5 + 1), %3, 1 +%elif cpuflag(sse) || cpuflag(3dnow) + mova %3, %2 + unpcklps %2, %1 + unpckhps %3, %1 + mova %4(%5), %2 + mova %4(%5+1), %3 +%endif +%endmacro + ; scheduled for cpu-bound sizes %macro PASS_SMALL 3 ; (to load m4-m7), wre, wim IF%1 mova m4, Z(4) @@ -541,17 +558,6 @@ DEFINE_ARGS zc, w, n, o1, o3 INIT_YMM avx %if HAVE_AVX_EXTERNAL -%macro INTERL_AVX 5 - vunpckhps %3, %2, %1 - vunpcklps %2, %2, %1 - vextractf128 %4(%5), %2, 0 - vextractf128 %4 %+ H(%5), %3, 0 - vextractf128 %4(%5 + 1), %2, 1 - vextractf128 %4 %+ H(%5 + 1), %3, 1 -%endmacro - -%define INTERL INTERL_AVX - DECL_PASS pass_avx, PASS_BIG 1 DECL_PASS pass_interleave_avx, PASS_BIG 0 @@ -566,16 +572,6 @@ cglobal fft_calc, 2,5,8 INIT_XMM sse -%macro INTERL_SSE 5 - mova %3, %2 - unpcklps %2, %1 - unpckhps %3, %1 - mova %4(%5), %2 - mova %4(%5+1), %3 -%endmacro - -%define INTERL INTERL_SSE - DECL_PASS pass_sse, PASS_BIG 1 DECL_PASS pass_interleave_sse, PASS_BIG 0 @@ -861,16 +857,30 @@ INIT_XMM sse %endmacro %macro CMUL 6 ;j, xmm0, xmm1, 3, 4, 5 +%if cpuflag(sse) mulps m6, %3, [%5+%1] mulps m7, %2, [%5+%1] mulps %2, %2, [%6+%1] mulps %3, %3, [%6+%1] subps %2, %2, m6 addps %3, %3, m7 +%elif cpuflag(3dnow) + mova m6, [%1+%2*2] + mova %3, [%1+%2*2+8] + mova %4, m6 + mova m7, %3 + pfmul m6, [%5+%2] + pfmul %3, [%6+%2] + pfmul %4, [%6+%2] + pfmul m7, [%5+%2] + pfsub %3, m6 + pfadd %4, m7 +%endif %endmacro -%macro POSROTATESHUF_AVX 5 ;j, k, z+n8, tcos+n8, tsin+n8 +%macro POSROTATESHUF 5 ;j, k, z+n8, tcos+n8, tsin+n8 .post: +%if cpuflag(avx) vmovaps ymm1, [%3+%1*2] vmovaps ymm0, [%3+%1*2+0x20] vmovaps ymm3, [%3+%2*2] @@ -899,10 +909,7 @@ INIT_XMM sse sub %2, 0x20 add %1, 0x20 jl .post -%endmacro - -%macro POSROTATESHUF 5 ;j, k, z+n8, tcos+n8, tsin+n8 -.post: +%elif cpuflag(sse) movaps xmm1, [%3+%1*2] movaps xmm0, [%3+%1*2+0x10] CMUL %1, xmm0, xmm1, %3, %4, %5 @@ -924,25 +931,9 @@ INIT_XMM sse sub %2, 0x10 add %1, 0x10 jl .post -%endmacro - -%macro CMUL_3DNOW 6 - mova m6, [%1+%2*2] - mova %3, [%1+%2*2+8] - mova %4, m6 - mova m7, %3 - pfmul m6, [%5+%2] - pfmul %3, [%6+%2] - pfmul %4, [%6+%2] - pfmul m7, [%5+%2] - pfsub %3, m6 - pfadd %4, m7 -%endmacro - -%macro POSROTATESHUF_3DNOW 5 ;j, k, z+n8, tcos+n8, tsin+n8 -.post: - CMUL_3DNOW %3, %1, m0, m1, %4, %5 - CMUL_3DNOW %3, %2, m2, m3, %4, %5 +%elif cpuflag(3dnow) + CMUL %3, %1, m0, m1, %4, %5 + CMUL %3, %2, m2, m3, %4, %5 movd [%3+%1*2+ 0], m0 movd [%3+%2*2+12], m1 movd [%3+%2*2+ 0], m2 @@ -958,9 +949,10 @@ INIT_XMM sse sub %2, 8 add %1, 8 jl .post +%endif %endmacro -%macro DECL_IMDCT 1 +%macro DECL_IMDCT 0 cglobal imdct_half, 3,12,8; FFTContext *s, FFTSample *output, const FFTSample *input %if ARCH_X86_64 %define rrevtab r7 @@ -1066,7 +1058,7 @@ cglobal imdct_half, 3,12,8; FFTContext *s, FFTSample *output, const FFTSample *i neg r0 mov r1, -mmsize sub r1, r0 - %1 r0, r1, r6, rtcos, rtsin + POSROTATESHUF r0, r1, r6, rtcos, rtsin %if ARCH_X86_64 == 0 add esp, 12 %endif @@ -1076,18 +1068,18 @@ cglobal imdct_half, 3,12,8; FFTContext *s, FFTSample *output, const FFTSample *i RET %endmacro -DECL_IMDCT POSROTATESHUF +DECL_IMDCT %if ARCH_X86_32 INIT_MMX 3dnow -DECL_IMDCT POSROTATESHUF_3DNOW +DECL_IMDCT INIT_MMX 3dnowext -DECL_IMDCT POSROTATESHUF_3DNOW +DECL_IMDCT %endif INIT_YMM avx %if HAVE_AVX_EXTERNAL -DECL_IMDCT POSROTATESHUF_AVX +DECL_IMDCT %endif diff --git a/libavcodec/x86/h264_idct.asm b/libavcodec/x86/h264_idct.asm index ea91e1ac4d961..c54f9f1a6832a 100644 --- a/libavcodec/x86/h264_idct.asm +++ b/libavcodec/x86/h264_idct.asm @@ -995,7 +995,30 @@ REP_RET SWAP %1, %4, %3 %endmacro -%macro DEQUANT_MMX 3 +%macro DEQUANT 1-3 +%if cpuflag(sse2) + movd xmm4, t3d + movq xmm5, [pw_1] + pshufd xmm4, xmm4, 0 + movq2dq xmm0, m0 + movq2dq xmm1, m1 + movq2dq xmm2, m2 + movq2dq xmm3, m3 + punpcklwd xmm0, xmm5 + punpcklwd xmm1, xmm5 + punpcklwd xmm2, xmm5 + punpcklwd xmm3, xmm5 + pmaddwd xmm0, xmm4 + pmaddwd xmm1, xmm4 + pmaddwd xmm2, xmm4 + pmaddwd xmm3, xmm4 + psrad xmm0, %1 + psrad xmm1, %1 + psrad xmm2, %1 + psrad xmm3, %1 + packssdw xmm0, xmm1 + packssdw xmm2, xmm3 +%else mova m7, [pw_1] mova m4, %1 punpcklwd %1, m7 @@ -1015,6 +1038,7 @@ REP_RET psrad m5, %3 packssdw %1, m4 packssdw %2, m5 +%endif %endmacro %macro STORE_WORDS 5-9 @@ -1053,35 +1077,15 @@ REP_RET %macro DEQUANT_STORE 1 %if cpuflag(sse2) - movd xmm4, t3d - movq xmm5, [pw_1] - pshufd xmm4, xmm4, 0 - movq2dq xmm0, m0 - movq2dq xmm1, m1 - movq2dq xmm2, m2 - movq2dq xmm3, m3 - punpcklwd xmm0, xmm5 - punpcklwd xmm1, xmm5 - punpcklwd xmm2, xmm5 - punpcklwd xmm3, xmm5 - pmaddwd xmm0, xmm4 - pmaddwd xmm1, xmm4 - pmaddwd xmm2, xmm4 - pmaddwd xmm3, xmm4 - psrad xmm0, %1 - psrad xmm1, %1 - psrad xmm2, %1 - psrad xmm3, %1 - packssdw xmm0, xmm1 - packssdw xmm2, xmm3 + DEQUANT %1 STORE_WORDS xmm0, 0, 1, 4, 5, 2, 3, 6, 7 STORE_WORDS xmm2, 8, 9, 12, 13, 10, 11, 14, 15 %else - DEQUANT_MMX m0, m1, %1 + DEQUANT m0, m1, %1 STORE_WORDS m0, 0, 1, 4, 5 STORE_WORDS m1, 2, 3, 6, 7 - DEQUANT_MMX m2, m3, %1 + DEQUANT m2, m3, %1 STORE_WORDS m2, 8, 9, 12, 13 STORE_WORDS m3, 10, 11, 14, 15 %endif @@ -1140,7 +1144,11 @@ IDCT_DC_DEQUANT 0 INIT_MMX sse2 IDCT_DC_DEQUANT 7 -; %unmacro STORE_DIFFx2 8 ; remove macro from x86util.asm but yasm doesn't have this yet +%ifdef __NASM_VER__ +%if __NASM_MAJOR__ >= 2 && __NASM_MINOR__ >= 4 +%unmacro STORE_DIFFx2 8 ; remove macro from x86util.asm but yasm doesn't have this yet +%endif +%endif %macro STORE_DIFFx2 8 ; add1, add2, reg1, reg2, zero, shift, source, stride movd %3, [%7] movd %4, [%7+%8] diff --git a/libavcodec/x86/hevc_sao.asm b/libavcodec/x86/hevc_sao.asm index 888a28afa7c48..756adfee5784c 100644 --- a/libavcodec/x86/hevc_sao.asm +++ b/libavcodec/x86/hevc_sao.asm @@ -198,7 +198,7 @@ HEVC_SAO_BAND_FILTER 64, 2 ;****************************************************************************** %define MAX_PB_SIZE 64 -%define PADDING_SIZE 32 ; AV_INPUT_BUFFER_PADDING_SIZE +%define PADDING_SIZE 64 ; AV_INPUT_BUFFER_PADDING_SIZE %define EDGE_SRCSTRIDE 2 * MAX_PB_SIZE + PADDING_SIZE %macro HEVC_SAO_EDGE_FILTER_INIT 0 diff --git a/libavcodec/x86/hevc_sao_10bit.asm b/libavcodec/x86/hevc_sao_10bit.asm index f81e2d503391d..b30583dd2f878 100644 --- a/libavcodec/x86/hevc_sao_10bit.asm +++ b/libavcodec/x86/hevc_sao_10bit.asm @@ -190,7 +190,7 @@ HEVC_SAO_BAND_FILTER 12, 64, 4 ;****************************************************************************** %define MAX_PB_SIZE 64 -%define PADDING_SIZE 32 ; AV_INPUT_BUFFER_PADDING_SIZE +%define PADDING_SIZE 64 ; AV_INPUT_BUFFER_PADDING_SIZE %define EDGE_SRCSTRIDE 2 * MAX_PB_SIZE + PADDING_SIZE %macro PMINUW 4 diff --git a/libavcodec/x86/huffyuvdsp.asm b/libavcodec/x86/huffyuvdsp.asm index 0d8cae354a504..a1231f1b22622 100644 --- a/libavcodec/x86/huffyuvdsp.asm +++ b/libavcodec/x86/huffyuvdsp.asm @@ -24,77 +24,39 @@ SECTION .text +%include "libavcodec/x86/huffyuvdsp_template.asm" -%macro INT16_LOOP 2 ; %1 = a/u (aligned/unaligned), %2 = add/sub - movd m4, maskd - SPLATW m4, m4 - add wd, wd - test wq, 2*mmsize - 1 - jz %%.tomainloop - push tmpq -%%.wordloop: - sub wq, 2 -%ifidn %2, add - mov tmpw, [srcq+wq] - add tmpw, [dstq+wq] -%else - mov tmpw, [src1q+wq] - sub tmpw, [src2q+wq] -%endif - and tmpw, maskw - mov [dstq+wq], tmpw - test wq, 2*mmsize - 1 - jnz %%.wordloop - pop tmpq -%%.tomainloop: -%ifidn %2, add - add srcq, wq -%else - add src1q, wq - add src2q, wq -%endif - add dstq, wq - neg wq - jz %%.end -%%.loop: -%ifidn %2, add - mov%1 m0, [srcq+wq] - mov%1 m1, [dstq+wq] - mov%1 m2, [srcq+wq+mmsize] - mov%1 m3, [dstq+wq+mmsize] -%else - mov%1 m0, [src1q+wq] - mov%1 m1, [src2q+wq] - mov%1 m2, [src1q+wq+mmsize] - mov%1 m3, [src2q+wq+mmsize] -%endif - p%2w m0, m1 - p%2w m2, m3 - pand m0, m4 - pand m2, m4 - mov%1 [dstq+wq] , m0 - mov%1 [dstq+wq+mmsize], m2 - add wq, 2*mmsize - jl %%.loop -%%.end: - RET -%endmacro - -%if ARCH_X86_32 -INIT_MMX mmx -cglobal add_int16, 4,4,5, dst, src, mask, w, tmp - INT16_LOOP a, add -%endif +;------------------------------------------------------------------------------ +; void (*add_int16)(uint16_t *dst, const uint16_t *src, unsigned mask, int w); +;------------------------------------------------------------------------------ -INIT_XMM sse2 +%macro ADD_INT16 0 cglobal add_int16, 4,4,5, dst, src, mask, w, tmp +%if mmsize > 8 test srcq, mmsize-1 jnz .unaligned test dstq, mmsize-1 jnz .unaligned +%endif INT16_LOOP a, add +%if mmsize > 8 .unaligned: INT16_LOOP u, add +%endif +%endmacro + +%if ARCH_X86_32 +INIT_MMX mmx +ADD_INT16 +%endif + +INIT_XMM sse2 +ADD_INT16 + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +ADD_INT16 +%endif ; void add_hfyu_left_pred_bgr32(uint8_t *dst, const uint8_t *src, ; intptr_t w, uint8_t *left) diff --git a/libavcodec/x86/huffyuvdsp_init.c b/libavcodec/x86/huffyuvdsp_init.c index 26cf6214d8fb0..eb10de383d23a 100644 --- a/libavcodec/x86/huffyuvdsp_init.c +++ b/libavcodec/x86/huffyuvdsp_init.c @@ -28,6 +28,8 @@ void ff_add_int16_mmx(uint16_t *dst, const uint16_t *src, unsigned mask, int w); void ff_add_int16_sse2(uint16_t *dst, const uint16_t *src, unsigned mask, int w); +void ff_add_int16_avx2(uint16_t *dst, const uint16_t *src, unsigned mask, int w); + void ff_add_hfyu_left_pred_bgr32_mmx(uint8_t *dst, const uint8_t *src, intptr_t w, uint8_t *left); void ff_add_hfyu_left_pred_bgr32_sse2(uint8_t *dst, const uint8_t *src, @@ -52,4 +54,8 @@ av_cold void ff_huffyuvdsp_init_x86(HuffYUVDSPContext *c, enum AVPixelFormat pix c->add_int16 = ff_add_int16_sse2; c->add_hfyu_left_pred_bgr32 = ff_add_hfyu_left_pred_bgr32_sse2; } + + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + c->add_int16 = ff_add_int16_avx2; + } } diff --git a/libavcodec/x86/huffyuvdsp_template.asm b/libavcodec/x86/huffyuvdsp_template.asm new file mode 100644 index 0000000000000..89721f4ec3af1 --- /dev/null +++ b/libavcodec/x86/huffyuvdsp_template.asm @@ -0,0 +1,76 @@ +;****************************************************************************** +;* SIMD-optimized HuffYUV functions +;* Copyright (c) 2008 Loren Merritt +;* Copyright (c) 2014 Christophe Gisquet +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%macro INT16_LOOP 2 ; %1 = a/u (aligned/unaligned), %2 = add/sub + movd xm4, maskd + SPLATW m4, xm4 + add wd, wd + test wq, 2*mmsize - 1 + jz %%.tomainloop + push tmpq +%%.wordloop: + sub wq, 2 +%ifidn %2, add + mov tmpw, [srcq+wq] + add tmpw, [dstq+wq] +%else + mov tmpw, [src1q+wq] + sub tmpw, [src2q+wq] +%endif + and tmpw, maskw + mov [dstq+wq], tmpw + test wq, 2*mmsize - 1 + jnz %%.wordloop + pop tmpq +%%.tomainloop: +%ifidn %2, add + add srcq, wq +%else + add src1q, wq + add src2q, wq +%endif + add dstq, wq + neg wq + jz %%.end +%%.loop: +%ifidn %2, add + mov%1 m0, [srcq+wq] + mov%1 m1, [dstq+wq] + mov%1 m2, [srcq+wq+mmsize] + mov%1 m3, [dstq+wq+mmsize] +%else + mov%1 m0, [src1q+wq] + mov%1 m1, [src2q+wq] + mov%1 m2, [src1q+wq+mmsize] + mov%1 m3, [src2q+wq+mmsize] +%endif + p%2w m0, m1 + p%2w m2, m3 + pand m0, m4 + pand m2, m4 + mov%1 [dstq+wq] , m0 + mov%1 [dstq+wq+mmsize], m2 + add wq, 2*mmsize + jl %%.loop +%%.end: + RET +%endmacro diff --git a/libavcodec/x86/huffyuvencdsp.asm b/libavcodec/x86/huffyuvencdsp.asm index eeef81ab8e584..d994fd0fd6339 100644 --- a/libavcodec/x86/huffyuvencdsp.asm +++ b/libavcodec/x86/huffyuvencdsp.asm @@ -27,80 +27,42 @@ SECTION .text +%include "libavcodec/x86/huffyuvdsp_template.asm" + +;------------------------------------------------------------------------------ ; void ff_diff_int16(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, ; unsigned mask, int w); -%macro INT16_LOOP 2 ; %1 = a/u (aligned/unaligned), %2 = add/sub - movd m4, maskd - SPLATW m4, m4 - add wd, wd - test wq, 2*mmsize - 1 - jz %%.tomainloop - push tmpq -%%.wordloop: - sub wq, 2 -%ifidn %2, add - mov tmpw, [srcq+wq] - add tmpw, [dstq+wq] -%else - mov tmpw, [src1q+wq] - sub tmpw, [src2q+wq] -%endif - and tmpw, maskw - mov [dstq+wq], tmpw - test wq, 2*mmsize - 1 - jnz %%.wordloop - pop tmpq -%%.tomainloop: -%ifidn %2, add - add srcq, wq -%else - add src1q, wq - add src2q, wq -%endif - add dstq, wq - neg wq - jz %%.end -%%.loop: -%ifidn %2, add - mov%1 m0, [srcq+wq] - mov%1 m1, [dstq+wq] - mov%1 m2, [srcq+wq+mmsize] - mov%1 m3, [dstq+wq+mmsize] -%else - mov%1 m0, [src1q+wq] - mov%1 m1, [src2q+wq] - mov%1 m2, [src1q+wq+mmsize] - mov%1 m3, [src2q+wq+mmsize] -%endif - p%2w m0, m1 - p%2w m2, m3 - pand m0, m4 - pand m2, m4 - mov%1 [dstq+wq] , m0 - mov%1 [dstq+wq+mmsize], m2 - add wq, 2*mmsize - jl %%.loop -%%.end: - RET -%endmacro - -%if ARCH_X86_32 -INIT_MMX mmx -cglobal diff_int16, 5,5,5, dst, src1, src2, mask, w, tmp - INT16_LOOP a, sub -%endif +;------------------------------------------------------------------------------ -INIT_XMM sse2 +%macro DIFF_INT16 0 cglobal diff_int16, 5,5,5, dst, src1, src2, mask, w, tmp +%if mmsize > 8 test src1q, mmsize-1 jnz .unaligned test src2q, mmsize-1 jnz .unaligned test dstq, mmsize-1 jnz .unaligned +%endif INT16_LOOP a, sub +%if mmsize > 8 .unaligned: INT16_LOOP u, sub +%endif +%endmacro + +%if ARCH_X86_32 +INIT_MMX mmx +DIFF_INT16 +%endif + +INIT_XMM sse2 +DIFF_INT16 + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +DIFF_INT16 +%endif INIT_MMX mmxext cglobal sub_hfyu_median_pred_int16, 7,7,0, dst, src1, src2, mask, w, left, left_top diff --git a/libavcodec/x86/huffyuvencdsp_init.c b/libavcodec/x86/huffyuvencdsp_init.c index f66bc8c4f0a79..6c6e068cf8fc3 100644 --- a/libavcodec/x86/huffyuvencdsp_init.c +++ b/libavcodec/x86/huffyuvencdsp_init.c @@ -32,6 +32,8 @@ void ff_diff_int16_mmx (uint16_t *dst, const uint16_t *src1, const uint16_t *src unsigned mask, int w); void ff_diff_int16_sse2(uint16_t *dst, const uint16_t *src1, const uint16_t *src2, unsigned mask, int w); +void ff_diff_int16_avx2(uint16_t *dst, const uint16_t *src1, const uint16_t *src2, + unsigned mask, int w); void ff_sub_hfyu_median_pred_int16_mmxext(uint16_t *dst, const uint16_t *src1, const uint16_t *src2, unsigned mask, int w, int *left, int *left_top); @@ -51,4 +53,8 @@ av_cold void ff_huffyuvencdsp_init_x86(HuffYUVEncDSPContext *c, AVCodecContext * if (EXTERNAL_SSE2(cpu_flags)) { c->diff_int16 = ff_diff_int16_sse2; } + + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + c->diff_int16 = ff_diff_int16_avx2; + } } diff --git a/libavcodec/x86/idctdsp_init.c b/libavcodec/x86/idctdsp_init.c index 162560d4114d7..9103b92ce7aea 100644 --- a/libavcodec/x86/idctdsp_init.c +++ b/libavcodec/x86/idctdsp_init.c @@ -123,6 +123,7 @@ av_cold void ff_idctdsp_init_x86(IDCTDSPContext *c, AVCodecContext *avctx, } if (avctx->bits_per_raw_sample == 10 && + avctx->codec_id != AV_CODEC_ID_MPEG4 && (avctx->idct_algo == FF_IDCT_AUTO || avctx->idct_algo == FF_IDCT_SIMPLEAUTO || avctx->idct_algo == FF_IDCT_SIMPLE)) { diff --git a/libavcodec/x86/imdct36.asm b/libavcodec/x86/imdct36.asm index 960eabdda5e2b..b386ab95fc1ce 100644 --- a/libavcodec/x86/imdct36.asm +++ b/libavcodec/x86/imdct36.asm @@ -23,7 +23,6 @@ SECTION_RODATA -align 16 ps_mask: dd 0, ~0, ~0, ~0 ps_mask2: dd 0, ~0, 0, ~0 ps_mask3: dd 0, 0, 0, ~0 diff --git a/libavcodec/x86/jpeg2000dsp.asm b/libavcodec/x86/jpeg2000dsp.asm index 56b5fbd6064df..61dfdd4f71ba4 100644 --- a/libavcodec/x86/jpeg2000dsp.asm +++ b/libavcodec/x86/jpeg2000dsp.asm @@ -74,6 +74,19 @@ align 16 movaps m1, [src1q+csizeq] movaps m2, [src2q+csizeq] +%if cpuflag(fma4) || cpuflag(fma3) +%if cpuflag(fma4) + fnmaddps m5, m1, ICT1, m0 + fmaddps m4, m2, ICT0, m0 +%else ; fma3 + movaps m5, m1 + movaps m4, m2 + fnmaddps m5, m5, ICT1, m0 + fmaddps m4, m4, ICT0, m0 +%endif + fmaddps m0, m1, ICT3, m0 + fnmaddps m5, m2, ICT2, m5 +%else ; non FMA %if cpuflag(avx) mulps m5, m1, ICT1 mulps m4, m2, ICT0 @@ -93,6 +106,7 @@ align 16 addps m4, m4, m0 addps m0, m0, m1 subps m5, m5, m2 +%endif movaps [src0q+csizeq], m4 movaps [src2q+csizeq], m0 @@ -106,6 +120,12 @@ INIT_XMM sse ICT_FLOAT 10 INIT_YMM avx ICT_FLOAT 9 +%if HAVE_FMA4_EXTERNAL +INIT_XMM fma4 +ICT_FLOAT 9 +%endif +INIT_YMM fma3 +ICT_FLOAT 9 ;*************************************************************************** ; ff_rct_int_(int32_t *src0, int32_t *src1, int32_t *src2, int csize) diff --git a/libavcodec/x86/jpeg2000dsp_init.c b/libavcodec/x86/jpeg2000dsp_init.c index baa81383eac20..7310a1d0e16ff 100644 --- a/libavcodec/x86/jpeg2000dsp_init.c +++ b/libavcodec/x86/jpeg2000dsp_init.c @@ -26,6 +26,8 @@ void ff_ict_float_sse(void *src0, void *src1, void *src2, int csize); void ff_ict_float_avx(void *src0, void *src1, void *src2, int csize); +void ff_ict_float_fma3(void *src0, void *src1, void *src2, int csize); +void ff_ict_float_fma4(void *src0, void *src1, void *src2, int csize); void ff_rct_int_sse2 (void *src0, void *src1, void *src2, int csize); void ff_rct_int_avx2 (void *src0, void *src1, void *src2, int csize); @@ -44,6 +46,14 @@ av_cold void ff_jpeg2000dsp_init_x86(Jpeg2000DSPContext *c) c->mct_decode[FF_DWT97] = ff_ict_float_avx; } + if (EXTERNAL_FMA4(cpu_flags)) { + c->mct_decode[FF_DWT97] = ff_ict_float_fma4; + } + + if (EXTERNAL_FMA3_FAST(cpu_flags)) { + c->mct_decode[FF_DWT97] = ff_ict_float_fma3; + } + if (EXTERNAL_AVX2_FAST(cpu_flags)) { c->mct_decode[FF_DWT53] = ff_rct_int_avx2; } diff --git a/libavcodec/x86/lossless_videodsp.asm b/libavcodec/x86/lossless_videodsp.asm index 443fe02951d7e..0a1b7091c954d 100644 --- a/libavcodec/x86/lossless_videodsp.asm +++ b/libavcodec/x86/lossless_videodsp.asm @@ -2,6 +2,7 @@ ;* SIMD lossless video DSP utils ;* Copyright (c) 2008 Loren Merritt ;* Copyright (c) 2014 Michael Niedermayer +;* Copyright (c) 2017 Jokyo Images ;* ;* This file is part of FFmpeg. ;* @@ -36,9 +37,11 @@ pb_zzzzzzzz67676767: db -1,-1,-1,-1,-1,-1,-1,-1, 6, 7, 6, 7, 6, 7, 6, 7 SECTION .text +;------------------------------------------------------------------------------ ; void ff_add_median_pred_mmxext(uint8_t *dst, const uint8_t *top, ; const uint8_t *diff, int w, ; int *left, int *left_top) +;------------------------------------------------------------------------------ %macro MEDIAN_PRED 0 cglobal add_median_pred, 6,6,8, dst, top, diff, w, left, left_top movu m0, [topq] @@ -112,44 +115,59 @@ MEDIAN_PRED add dstq, wq neg wq %%.loop: + pshufb xm0, xm5 %if %2 mova m1, [srcq+wq] %else movu m1, [srcq+wq] %endif - mova m2, m1 - psllw m1, 8 + psllw m2, m1, 8 paddb m1, m2 - mova m2, m1 - pshufb m1, m3 + pshufb m2, m1, m3 paddb m1, m2 - pshufb m0, m5 - mova m2, m1 - pshufb m1, m4 + pshufb m2, m1, m4 paddb m1, m2 -%if mmsize == 16 - mova m2, m1 - pshufb m1, m6 +%if mmsize >= 16 + pshufb m2, m1, m6 paddb m1, m2 %endif - paddb m0, m1 + paddb xm0, xm1 %if %1 - mova [dstq+wq], m0 + mova [dstq+wq], xm0 %else - movq [dstq+wq], m0 - movhps [dstq+wq+8], m0 + movq [dstq+wq], xm0 + movhps [dstq+wq+8], xm0 +%endif + +%if mmsize == 32 + vextracti128 xm2, m1, 1 ; get second lane of the ymm + pshufb xm0, xm5 ; set alls val to last val of the first lane + paddb xm0, xm2 +;store val +%if %1 + mova [dstq+wq+16], xm0 +%else; + movq [dstq+wq+16], xm0 + movhps [dstq+wq+16+8], xm0 +%endif %endif add wq, mmsize jl %%.loop +%if mmsize == 32 + movzx eax, byte [dstq - 1] +%else; mov eax, mmsize-1 sub eax, wd movd m1, eax pshufb m0, m1 movd eax, m0 +%endif RET %endmacro +;------------------------------------------------------------------------------ ; int ff_add_left_pred(uint8_t *dst, const uint8_t *src, int w, int left) +;------------------------------------------------------------------------------ INIT_MMX ssse3 cglobal add_left_pred, 3,3,7, dst, src, w, left .skip_prologue: @@ -160,24 +178,36 @@ cglobal add_left_pred, 3,3,7, dst, src, w, left psllq m0, 56 ADD_LEFT_LOOP 1, 1 -INIT_XMM ssse3 +%macro ADD_LEFT_PRED_UNALIGNED 0 cglobal add_left_pred_unaligned, 3,3,7, dst, src, w, left - mova m5, [pb_15] - mova m6, [pb_zzzzzzzz77777777] - mova m4, [pb_zzzz3333zzzzbbbb] - mova m3, [pb_zz11zz55zz99zzdd] - movd m0, leftm - pslldq m0, 15 - test srcq, 15 + mova xm5, [pb_15] + VBROADCASTI128 m6, [pb_zzzzzzzz77777777] + VBROADCASTI128 m4, [pb_zzzz3333zzzzbbbb] + VBROADCASTI128 m3, [pb_zz11zz55zz99zzdd] + movd xm0, leftm + pslldq xm0, 15 + test srcq, mmsize - 1 jnz .src_unaligned - test dstq, 15 + test dstq, mmsize - 1 jnz .dst_unaligned ADD_LEFT_LOOP 1, 1 .dst_unaligned: ADD_LEFT_LOOP 0, 1 .src_unaligned: ADD_LEFT_LOOP 0, 0 +%endmacro + +INIT_XMM ssse3 +ADD_LEFT_PRED_UNALIGNED +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +ADD_LEFT_PRED_UNALIGNED +%endif + +;------------------------------------------------------------------------------ +; void ff_add_bytes(uint8_t *dst, uint8_t *src, ptrdiff_t w); +;------------------------------------------------------------------------------ %macro ADD_BYTES 0 cglobal add_bytes, 3,4,2, dst, src, w, size mov sizeq, wq @@ -217,6 +247,11 @@ ADD_BYTES INIT_XMM sse2 ADD_BYTES +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +ADD_BYTES +%endif + %macro ADD_HFYU_LEFT_LOOP_INT16 2 ; %1 = dst alignment (a/u), %2 = src alignment (a/u) add wd, wd add srcq, wq @@ -258,7 +293,9 @@ ADD_BYTES RET %endmacro +;--------------------------------------------------------------------------------------------- ; int add_left_pred_int16(uint16_t *dst, const uint16_t *src, unsigned mask, int w, int left) +;--------------------------------------------------------------------------------------------- INIT_MMX ssse3 cglobal add_left_pred_int16, 4,4,8, dst, src, mask, w, left .skip_prologue: @@ -270,8 +307,8 @@ cglobal add_left_pred_int16, 4,4,8, dst, src, mask, w, left SPLATW m7 ,m7 ADD_HFYU_LEFT_LOOP_INT16 a, a -INIT_XMM sse4 -cglobal add_left_pred_int16, 4,4,8, dst, src, mask, w, left +INIT_XMM ssse3 +cglobal add_left_pred_int16_unaligned, 4,4,8, dst, src, mask, w, left mova m5, [pb_ef] mova m4, [pb_zzzzzzzz67676767] mova m3, [pb_zzzz2323zzzzabab] @@ -288,3 +325,82 @@ cglobal add_left_pred_int16, 4,4,8, dst, src, mask, w, left ADD_HFYU_LEFT_LOOP_INT16 u, a .src_unaligned: ADD_HFYU_LEFT_LOOP_INT16 u, u + + +;--------------------------------------------------------------------------------------------- +; void add_gradient_pred(uint8_t *src, const ptrdiff_t stride, const ptrdiff_t width) +;--------------------------------------------------------------------------------------------- +%macro ADD_GRADIENT_PRED 0 +cglobal add_gradient_pred, 3,4,5, src, stride, width, tmp + mova xm0, [pb_15] + +;load src - 1 in xm1 + movd xm1, [srcq-1] +%if cpuflag(avx2) + vpbroadcastb xm1, xm1 +%else + pxor xm2, xm2 + pshufb xm1, xm2 +%endif + + add srcq, widthq + neg widthq + neg strideq + +.loop: + lea tmpq, [srcq + strideq] + mova m2, [tmpq + widthq] ; A = src[x-stride] + movu m3, [tmpq + widthq - 1] ; B = src[x - (stride + 1)] + mova m4, [srcq + widthq] ; current val (src[x]) + + psubb m2, m3; A - B + +; prefix sum A-B + pslldq m3, m2, 1 + paddb m2, m3 + pslldq m3, m2, 2 + paddb m2, m3 + pslldq m3, m2, 4 + paddb m2, m3 + pslldq m3, m2, 8 + paddb m2, m3 + +; prefix sum current val + pslldq m3, m4, 1 + paddb m4, m3 + pslldq m3, m4, 2 + paddb m4, m3 + pslldq m3, m4, 4 + paddb m4, m3 + pslldq m3, m4, 8 + paddb m4, m3 + +; last sum + paddb m2, m4 ; current + (A - B) + + paddb xm1, xm2 ; += C + mova [srcq + widthq], xm1 ; store + + pshufb xm1, xm0 ; put last val in all val of xm1 + +%if mmsize == 32 + vextracti128 xm2, m2, 1 ; get second lane of the ymm + paddb xm1, xm2; += C + + mova [srcq + widthq + 16], xm1 ; store + pshufb xm1, xm0 ; put last val in all val of m1 +%endif + + add widthq, mmsize + jl .loop + RET + +%endmacro + +INIT_XMM ssse3 +ADD_GRADIENT_PRED + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +ADD_GRADIENT_PRED +%endif diff --git a/libavcodec/x86/lossless_videodsp_init.c b/libavcodec/x86/lossless_videodsp_init.c index 21bbd12bd2d91..6d71f14e7f9cf 100644 --- a/libavcodec/x86/lossless_videodsp_init.c +++ b/libavcodec/x86/lossless_videodsp_init.c @@ -25,6 +25,7 @@ void ff_add_bytes_mmx(uint8_t *dst, uint8_t *src, ptrdiff_t w); void ff_add_bytes_sse2(uint8_t *dst, uint8_t *src, ptrdiff_t w); +void ff_add_bytes_avx2(uint8_t *dst, uint8_t *src, ptrdiff_t w); void ff_add_median_pred_mmxext(uint8_t *dst, const uint8_t *top, const uint8_t *diff, ptrdiff_t w, @@ -37,9 +38,14 @@ int ff_add_left_pred_ssse3(uint8_t *dst, const uint8_t *src, ptrdiff_t w, int left); int ff_add_left_pred_unaligned_ssse3(uint8_t *dst, const uint8_t *src, ptrdiff_t w, int left); +int ff_add_left_pred_unaligned_avx2(uint8_t *dst, const uint8_t *src, + ptrdiff_t w, int left); int ff_add_left_pred_int16_ssse3(uint16_t *dst, const uint16_t *src, unsigned mask, ptrdiff_t w, unsigned acc); -int ff_add_left_pred_int16_sse4(uint16_t *dst, const uint16_t *src, unsigned mask, ptrdiff_t w, unsigned acc); +int ff_add_left_pred_int16_unaligned_ssse3(uint16_t *dst, const uint16_t *src, unsigned mask, ptrdiff_t w, unsigned acc); + +void ff_add_gradient_pred_ssse3(uint8_t *src, const ptrdiff_t stride, const ptrdiff_t width); +void ff_add_gradient_pred_avx2(uint8_t *src, const ptrdiff_t stride, const ptrdiff_t width); #if HAVE_INLINE_ASM && HAVE_7REGS && ARCH_X86_32 static void add_median_pred_cmov(uint8_t *dst, const uint8_t *top, @@ -106,13 +112,17 @@ void ff_llviddsp_init_x86(LLVidDSPContext *c) if (EXTERNAL_SSSE3(cpu_flags)) { c->add_left_pred = ff_add_left_pred_ssse3; c->add_left_pred_int16 = ff_add_left_pred_int16_ssse3; + c->add_gradient_pred = ff_add_gradient_pred_ssse3; } if (EXTERNAL_SSSE3_FAST(cpu_flags)) { c->add_left_pred = ff_add_left_pred_unaligned_ssse3; + c->add_left_pred_int16 = ff_add_left_pred_int16_unaligned_ssse3; } - if (EXTERNAL_SSE4(cpu_flags)) { - c->add_left_pred_int16 = ff_add_left_pred_int16_sse4; + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + c->add_bytes = ff_add_bytes_avx2; + c->add_left_pred = ff_add_left_pred_unaligned_avx2; + c->add_gradient_pred = ff_add_gradient_pred_avx2; } } diff --git a/libavcodec/x86/lossless_videoencdsp.asm b/libavcodec/x86/lossless_videoencdsp.asm index 4d79eee36ba1a..fb1204f0f1f61 100644 --- a/libavcodec/x86/lossless_videoencdsp.asm +++ b/libavcodec/x86/lossless_videoencdsp.asm @@ -25,6 +25,8 @@ %include "libavutil/x86/x86util.asm" +cextern pb_80 + SECTION .text ; void ff_diff_bytes(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, @@ -149,3 +151,44 @@ DIFF_BYTES_PROLOGUE DIFF_BYTES_BODY u, u %undef i %endif + + +;-------------------------------------------------------------------------------------------------- +;void sub_left_predict(uint8_t *dst, uint8_t *src, ptrdiff_t stride, ptrdiff_t width, int height) +;-------------------------------------------------------------------------------------------------- + +INIT_XMM avx +cglobal sub_left_predict, 5,6,5, dst, src, stride, width, height, x + mova m1, [pb_80] ; prev initial + add dstq, widthq + add srcq, widthq + lea xd, [widthq-1] + neg widthq + and xd, 15 + pinsrb m4, m1, xd, 15 + mov xq, widthq + + .loop: + movu m0, [srcq + widthq] + palignr m2, m0, m1, 15 + movu m1, [srcq + widthq + 16] + palignr m3, m1, m0, 15 + psubb m2, m0, m2 + psubb m3, m1, m3 + movu [dstq + widthq], m2 + movu [dstq + widthq + 16], m3 + add widthq, 2 * 16 + jl .loop + + add srcq, strideq + sub dstq, xq ; dst + width + test xd, 16 + jz .mod32 + mova m1, m0 + +.mod32: + pshufb m1, m4 + mov widthq, xq + dec heightd + jg .loop + RET diff --git a/libavcodec/x86/lossless_videoencdsp_init.c b/libavcodec/x86/lossless_videoencdsp_init.c index fc728c9fd1ef7..40407add52526 100644 --- a/libavcodec/x86/lossless_videoencdsp_init.c +++ b/libavcodec/x86/lossless_videoencdsp_init.c @@ -36,6 +36,9 @@ void ff_diff_bytes_sse2(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, void ff_diff_bytes_avx2(uint8_t *dst, const uint8_t *src1, const uint8_t *src2, intptr_t w); +void ff_sub_left_predict_avx(uint8_t *dst, uint8_t *src, + ptrdiff_t stride, ptrdiff_t width, int height); + #if HAVE_INLINE_ASM static void sub_median_pred_mmxext(uint8_t *dst, const uint8_t *src1, @@ -98,6 +101,10 @@ av_cold void ff_llvidencdsp_init_x86(LLVidEncDSPContext *c) c->diff_bytes = ff_diff_bytes_sse2; } + if (EXTERNAL_AVX(cpu_flags)) { + c->sub_left_predict = ff_sub_left_predict_avx; + } + if (EXTERNAL_AVX2_FAST(cpu_flags)) { c->diff_bytes = ff_diff_bytes_avx2; } diff --git a/libavcodec/x86/mpegvideodsp.c b/libavcodec/x86/mpegvideodsp.c index e0498f3849620..6009b64e0769d 100644 --- a/libavcodec/x86/mpegvideodsp.c +++ b/libavcodec/x86/mpegvideodsp.c @@ -52,8 +52,9 @@ static void gmc_mmx(uint8_t *dst, uint8_t *src, const int dyh = (dyy - (1 << (16 + shift))) * (h - 1); const int dxh = dxy * (h - 1); const int dyw = dyx * (w - 1); - int need_emu = (unsigned) ix >= width - w || - (unsigned) iy >= height - h; + int need_emu = (unsigned) ix >= width - w || width < w || + (unsigned) iy >= height - h || height< h + ; if ( // non-constant fullpel offset (3% of blocks) ((ox ^ (ox + dxw)) | (ox ^ (ox + dxh)) | (ox ^ (ox + dxw + dxh)) | diff --git a/libavcodec/x86/rv40dsp.asm b/libavcodec/x86/rv40dsp.asm index d0c3af0f8d470..bcad1aee80d04 100644 --- a/libavcodec/x86/rv40dsp.asm +++ b/libavcodec/x86/rv40dsp.asm @@ -25,7 +25,6 @@ SECTION_RODATA -align 16 pw_1024: times 8 dw 1 << (16 - 6) ; pw_1024 sixtap_filter_hb_m: times 8 db 1, -5 diff --git a/libavcodec/x86/sbcdsp.asm b/libavcodec/x86/sbcdsp.asm new file mode 100644 index 0000000000000..d68d3a9ae8c02 --- /dev/null +++ b/libavcodec/x86/sbcdsp.asm @@ -0,0 +1,168 @@ +;****************************************************************************** +;* SIMD optimized SBC encoder DSP functions +;* +;* Copyright (C) 2017 Aurelien Jacobs +;* Copyright (C) 2008-2010 Nokia Corporation +;* Copyright (C) 2004-2010 Marcel Holtmann +;* Copyright (C) 2004-2005 Henryk Ploetz +;* Copyright (C) 2005-2006 Brad Midgley +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +SECTION_RODATA + +scale_mask: times 2 dd 0x8000 ; 1 << (SBC_PROTO_FIXED_SCALE - 1) + +SECTION .text + +%macro NIDN 3 +%ifnidn %2, %3 + %1 %2, %3 +%endif +%endmacro + +%macro ANALYZE_MAC 9 ; out1, out2, in1, in2, tmp1, tmp2, add1, add2, offset + NIDN movq, %5, %3 + NIDN movq, %6, %4 + pmaddwd %5, [constsq+%9] + pmaddwd %6, [constsq+%9+8] + NIDN paddd, %1, %7 + NIDN paddd, %2, %8 +%endmacro + +%macro ANALYZE_MAC_IN 7 ; out1, out2, tmp1, tmp2, add1, add2, offset + ANALYZE_MAC %1, %2, [inq+%7], [inq+%7+8], %3, %4, %5, %6, %7 +%endmacro + +%macro ANALYZE_MAC_REG 7 ; out1, out2, in, tmp1, tmp2, offset, pack +%ifidn %7, pack + psrad %3, 16 ; SBC_PROTO_FIXED_SCALE + packssdw %3, %3 +%endif + ANALYZE_MAC %1, %2, %3, %3, %4, %5, %4, %5, %6 +%endmacro + +;******************************************************************* +;void ff_sbc_analyze_4(const int16_t *in, int32_t *out, const int16_t *consts); +;******************************************************************* +INIT_MMX mmx +cglobal sbc_analyze_4, 3, 3, 4, in, out, consts + ANALYZE_MAC_IN m0, m1, m0, m1, [scale_mask], [scale_mask], 0 + ANALYZE_MAC_IN m0, m1, m2, m3, m2, m3, 16 + ANALYZE_MAC_IN m0, m1, m2, m3, m2, m3, 32 + ANALYZE_MAC_IN m0, m1, m2, m3, m2, m3, 48 + ANALYZE_MAC_IN m0, m1, m2, m3, m2, m3, 64 + + ANALYZE_MAC_REG m0, m2, m0, m0, m2, 80, pack + ANALYZE_MAC_REG m0, m2, m1, m1, m3, 96, pack + + movq [outq ], m0 + movq [outq+8], m2 + + RET + + +;******************************************************************* +;void ff_sbc_analyze_8(const int16_t *in, int32_t *out, const int16_t *consts); +;******************************************************************* +INIT_MMX mmx +cglobal sbc_analyze_8, 3, 3, 4, in, out, consts + ANALYZE_MAC_IN m0, m1, m0, m1, [scale_mask], [scale_mask], 0 + ANALYZE_MAC_IN m2, m3, m2, m3, [scale_mask], [scale_mask], 16 + ANALYZE_MAC_IN m0, m1, m4, m5, m4, m5, 32 + ANALYZE_MAC_IN m2, m3, m6, m7, m6, m7, 48 + ANALYZE_MAC_IN m0, m1, m4, m5, m4, m5, 64 + ANALYZE_MAC_IN m2, m3, m6, m7, m6, m7, 80 + ANALYZE_MAC_IN m0, m1, m4, m5, m4, m5, 96 + ANALYZE_MAC_IN m2, m3, m6, m7, m6, m7, 112 + ANALYZE_MAC_IN m0, m1, m4, m5, m4, m5, 128 + ANALYZE_MAC_IN m2, m3, m6, m7, m6, m7, 144 + + ANALYZE_MAC_REG m4, m5, m0, m4, m5, 160, pack + ANALYZE_MAC_REG m4, m5, m1, m6, m7, 192, pack + ANALYZE_MAC_REG m4, m5, m2, m6, m7, 224, pack + ANALYZE_MAC_REG m4, m5, m3, m6, m7, 256, pack + + movq [outq ], m4 + movq [outq+8], m5 + + ANALYZE_MAC_REG m0, m5, m0, m0, m5, 176, no + ANALYZE_MAC_REG m0, m5, m1, m1, m7, 208, no + ANALYZE_MAC_REG m0, m5, m2, m2, m7, 240, no + ANALYZE_MAC_REG m0, m5, m3, m3, m7, 272, no + + movq [outq+16], m0 + movq [outq+24], m5 + + RET + + +;******************************************************************* +;void ff_sbc_calc_scalefactors(int32_t sb_sample_f[16][2][8], +; uint32_t scale_factor[2][8], +; int blocks, int channels, int subbands) +;******************************************************************* +INIT_MMX mmx +cglobal sbc_calc_scalefactors, 5, 7, 4, sb_sample_f, scale_factor, blocks, channels, subbands, ptr, blk + ; subbands = 4 * subbands * channels + movq m3, [scale_mask] + shl subbandsd, 2 + cmp channelsd, 2 + jl .loop_1 + shl subbandsd, 1 + +.loop_1: + sub subbandsq, 8 + lea ptrq, [sb_sample_fq + subbandsq] + + ; blk = (blocks - 1) * 64; + lea blkq, [blocksq - 1] + shl blkd, 6 + + movq m0, m3 +.loop_2: + movq m1, [ptrq+blkq] + pxor m2, m2 + pcmpgtd m1, m2 + paddd m1, [ptrq+blkq] + pcmpgtd m2, m1 + pxor m1, m2 + + por m0, m1 + + sub blkq, 64 + jns .loop_2 + + movd blkd, m0 + psrlq m0, 32 + bsr blkd, blkd + sub blkd, 15 ; SCALE_OUT_BITS + mov [scale_factorq + subbandsq], blkd + + movd blkd, m0 + bsr blkd, blkd + sub blkd, 15 ; SCALE_OUT_BITS + mov [scale_factorq + subbandsq + 4], blkd + + cmp subbandsq, 0 + jg .loop_1 + + emms + RET diff --git a/libavcodec/x86/sbcdsp_init.c b/libavcodec/x86/sbcdsp_init.c new file mode 100644 index 0000000000000..86effecfdf565 --- /dev/null +++ b/libavcodec/x86/sbcdsp_init.c @@ -0,0 +1,51 @@ +/* + * Bluetooth low-complexity, subband codec (SBC) + * + * Copyright (C) 2017 Aurelien Jacobs + * Copyright (C) 2008-2010 Nokia Corporation + * Copyright (C) 2004-2010 Marcel Holtmann + * Copyright (C) 2004-2005 Henryk Ploetz + * Copyright (C) 2005-2006 Brad Midgley + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * SBC MMX optimization for some basic "building bricks" + */ + +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavcodec/sbcdsp.h" + +void ff_sbc_analyze_4_mmx(const int16_t *in, int32_t *out, const int16_t *consts); +void ff_sbc_analyze_8_mmx(const int16_t *in, int32_t *out, const int16_t *consts); +void ff_sbc_calc_scalefactors_mmx(int32_t sb_sample_f[16][2][8], + uint32_t scale_factor[2][8], + int blocks, int channels, int subbands); + +av_cold void ff_sbcdsp_init_x86(SBCDSPContext *s) +{ + int cpu_flags = av_get_cpu_flags(); + + if (EXTERNAL_MMX(cpu_flags)) { + s->sbc_analyze_4 = ff_sbc_analyze_4_mmx; + s->sbc_analyze_8 = ff_sbc_analyze_8_mmx; + s->sbc_calc_scalefactors = ff_sbc_calc_scalefactors_mmx; + } +} diff --git a/libavcodec/x86/utvideodsp.asm b/libavcodec/x86/utvideodsp.asm index e44c1ea4719de..b799c44b64007 100644 --- a/libavcodec/x86/utvideodsp.asm +++ b/libavcodec/x86/utvideodsp.asm @@ -1,6 +1,7 @@ ;****************************************************************************** ;* SIMD-optimized UTVideo functions ;* Copyright (c) 2017 Paul B Mahol +;* Copyright (c) 2017 Jokyo Images ;* ;* This file is part of FFmpeg. ;* @@ -23,17 +24,18 @@ SECTION_RODATA -pb_128: times 16 db 128 -pw_512: times 8 dw 512 -pw_1023: times 8 dw 1023 +cextern pb_80 +cextern pw_512 +cextern pw_1023 SECTION .text -INIT_XMM sse2 - +;------------------------------------------------------------------------------------------- ; void restore_rgb_planes(uint8_t *src_r, uint8_t *src_g, uint8_t *src_b, ; ptrdiff_t linesize_r, ptrdiff_t linesize_g, ptrdiff_t linesize_b, ; int width, int height) +;------------------------------------------------------------------------------------------- +%macro RESTORE_RGB_PLANES 0 cglobal restore_rgb_planes, 7 + ARCH_X86_64, 7 + ARCH_X86_64 * 2, 4, src_r, src_g, src_b, linesize_r, linesize_g, linesize_b, w, h, x movsxdifnidn wq, wd add src_rq, wq @@ -46,7 +48,7 @@ DEFINE_ARGS src_r, src_g, src_b, linesize_r, linesize_g, linesize_b, x %define wq r6m %define hd r7mp %endif - mova m3, [pb_128] + mova m3, [pb_80] .nextrow: mov xq, wq @@ -68,7 +70,22 @@ DEFINE_ARGS src_r, src_g, src_b, linesize_r, linesize_g, linesize_b, x sub hd, 1 jg .nextrow REP_RET +%endmacro + +INIT_XMM sse2 +RESTORE_RGB_PLANES + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +RESTORE_RGB_PLANES +%endif +;------------------------------------------------------------------------------------------- +; void restore_rgb_planes10(uint16_t *src_r, uint16_t *src_g, uint16_t *src_b, +; ptrdiff_t linesize_r, ptrdiff_t linesize_g, ptrdiff_t linesize_b, +; int width, int height) +;------------------------------------------------------------------------------------------- +%macro RESTORE_RGB_PLANES10 0 cglobal restore_rgb_planes10, 7 + ARCH_X86_64, 7 + ARCH_X86_64 * 2, 5, src_r, src_g, src_b, linesize_r, linesize_g, linesize_b, w, h, x shl wd, 1 shl linesize_rq, 1 @@ -109,3 +126,12 @@ DEFINE_ARGS src_r, src_g, src_b, linesize_r, linesize_g, linesize_b, x sub hd, 1 jg .nextrow REP_RET +%endmacro + +INIT_XMM sse2 +RESTORE_RGB_PLANES10 + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +RESTORE_RGB_PLANES10 +%endif diff --git a/libavcodec/x86/utvideodsp_init.c b/libavcodec/x86/utvideodsp_init.c index f8b2a9b0749bb..2b436c6c5c079 100644 --- a/libavcodec/x86/utvideodsp_init.c +++ b/libavcodec/x86/utvideodsp_init.c @@ -28,9 +28,16 @@ void ff_restore_rgb_planes_sse2(uint8_t *src_r, uint8_t *src_g, uint8_t *src_b, ptrdiff_t linesize_r, ptrdiff_t linesize_g, ptrdiff_t linesize_b, int width, int height); +void ff_restore_rgb_planes_avx2(uint8_t *src_r, uint8_t *src_g, uint8_t *src_b, + ptrdiff_t linesize_r, ptrdiff_t linesize_g, + ptrdiff_t linesize_b, int width, int height); + void ff_restore_rgb_planes10_sse2(uint16_t *src_r, uint16_t *src_g, uint16_t *src_b, ptrdiff_t linesize_r, ptrdiff_t linesize_g, ptrdiff_t linesize_b, int width, int height); +void ff_restore_rgb_planes10_avx2(uint16_t *src_r, uint16_t *src_g, uint16_t *src_b, + ptrdiff_t linesize_r, ptrdiff_t linesize_g, + ptrdiff_t linesize_b, int width, int height); av_cold void ff_utvideodsp_init_x86(UTVideoDSPContext *c) { @@ -40,4 +47,8 @@ av_cold void ff_utvideodsp_init_x86(UTVideoDSPContext *c) c->restore_rgb_planes = ff_restore_rgb_planes_sse2; c->restore_rgb_planes10 = ff_restore_rgb_planes10_sse2; } + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + c->restore_rgb_planes = ff_restore_rgb_planes_avx2; + c->restore_rgb_planes10 = ff_restore_rgb_planes10_avx2; + } } diff --git a/libavcodec/x86/vp8dsp.asm b/libavcodec/x86/vp8dsp.asm index e303b802938e4..75de5690a1a0a 100644 --- a/libavcodec/x86/vp8dsp.asm +++ b/libavcodec/x86/vp8dsp.asm @@ -664,6 +664,37 @@ INIT_XMM sse2 FILTER_V 8 %macro FILTER_BILINEAR 1 +%if cpuflag(ssse3) +cglobal put_vp8_bilinear%1_v, 7, 7, 5, dst, dststride, src, srcstride, height, picreg, my + shl myd, 4 +%ifdef PIC + lea picregq, [bilinear_filter_vb_m] +%endif + pxor m4, m4 + mova m3, [bilinear_filter_vb+myq-16] +.nextrow: + movh m0, [srcq+srcstrideq*0] + movh m1, [srcq+srcstrideq*1] + movh m2, [srcq+srcstrideq*2] + punpcklbw m0, m1 + punpcklbw m1, m2 + pmaddubsw m0, m3 + pmaddubsw m1, m3 + psraw m0, 2 + psraw m1, 2 + pavgw m0, m4 + pavgw m1, m4 +%if mmsize==8 + packuswb m0, m0 + packuswb m1, m1 + movh [dstq+dststrideq*0], m0 + movh [dstq+dststrideq*1], m1 +%else + packuswb m0, m1 + movh [dstq+dststrideq*0], m0 + movhps [dstq+dststrideq*1], m0 +%endif +%else ; cpuflag(ssse3) cglobal put_vp8_bilinear%1_v, 7, 7, 7, dst, dststride, src, srcstride, height, picreg, my shl myd, 4 %ifdef PIC @@ -701,6 +732,7 @@ cglobal put_vp8_bilinear%1_v, 7, 7, 7, dst, dststride, src, srcstride, height, p movh [dstq+dststrideq*0], m0 movhps [dstq+dststrideq*1], m0 %endif +%endif ; cpuflag(ssse3) lea dstq, [dstq+dststrideq*2] lea srcq, [srcq+srcstrideq*2] @@ -708,6 +740,37 @@ cglobal put_vp8_bilinear%1_v, 7, 7, 7, dst, dststride, src, srcstride, height, p jg .nextrow REP_RET +%if cpuflag(ssse3) +cglobal put_vp8_bilinear%1_h, 6, 6 + npicregs, 5, dst, dststride, src, srcstride, height, mx, picreg + shl mxd, 4 +%ifdef PIC + lea picregq, [bilinear_filter_vb_m] +%endif + pxor m4, m4 + mova m2, [filter_h2_shuf] + mova m3, [bilinear_filter_vb+mxq-16] +.nextrow: + movu m0, [srcq+srcstrideq*0] + movu m1, [srcq+srcstrideq*1] + pshufb m0, m2 + pshufb m1, m2 + pmaddubsw m0, m3 + pmaddubsw m1, m3 + psraw m0, 2 + psraw m1, 2 + pavgw m0, m4 + pavgw m1, m4 +%if mmsize==8 + packuswb m0, m0 + packuswb m1, m1 + movh [dstq+dststrideq*0], m0 + movh [dstq+dststrideq*1], m1 +%else + packuswb m0, m1 + movh [dstq+dststrideq*0], m0 + movhps [dstq+dststrideq*1], m0 +%endif +%else ; cpuflag(ssse3) cglobal put_vp8_bilinear%1_h, 6, 6 + npicregs, 7, dst, dststride, src, srcstride, height, mx, picreg shl mxd, 4 %ifdef PIC @@ -746,6 +809,7 @@ cglobal put_vp8_bilinear%1_h, 6, 6 + npicregs, 7, dst, dststride, src, srcstride movh [dstq+dststrideq*0], m0 movhps [dstq+dststrideq*1], m0 %endif +%endif ; cpuflag(ssse3) lea dstq, [dstq+dststrideq*2] lea srcq, [srcq+srcstrideq*2] @@ -758,85 +822,10 @@ INIT_MMX mmxext FILTER_BILINEAR 4 INIT_XMM sse2 FILTER_BILINEAR 8 - -%macro FILTER_BILINEAR_SSSE3 1 -cglobal put_vp8_bilinear%1_v, 7, 7, 5, dst, dststride, src, srcstride, height, picreg, my - shl myd, 4 -%ifdef PIC - lea picregq, [bilinear_filter_vb_m] -%endif - pxor m4, m4 - mova m3, [bilinear_filter_vb+myq-16] -.nextrow: - movh m0, [srcq+srcstrideq*0] - movh m1, [srcq+srcstrideq*1] - movh m2, [srcq+srcstrideq*2] - punpcklbw m0, m1 - punpcklbw m1, m2 - pmaddubsw m0, m3 - pmaddubsw m1, m3 - psraw m0, 2 - psraw m1, 2 - pavgw m0, m4 - pavgw m1, m4 -%if mmsize==8 - packuswb m0, m0 - packuswb m1, m1 - movh [dstq+dststrideq*0], m0 - movh [dstq+dststrideq*1], m1 -%else - packuswb m0, m1 - movh [dstq+dststrideq*0], m0 - movhps [dstq+dststrideq*1], m0 -%endif - - lea dstq, [dstq+dststrideq*2] - lea srcq, [srcq+srcstrideq*2] - sub heightd, 2 - jg .nextrow - REP_RET - -cglobal put_vp8_bilinear%1_h, 6, 6 + npicregs, 5, dst, dststride, src, srcstride, height, mx, picreg - shl mxd, 4 -%ifdef PIC - lea picregq, [bilinear_filter_vb_m] -%endif - pxor m4, m4 - mova m2, [filter_h2_shuf] - mova m3, [bilinear_filter_vb+mxq-16] -.nextrow: - movu m0, [srcq+srcstrideq*0] - movu m1, [srcq+srcstrideq*1] - pshufb m0, m2 - pshufb m1, m2 - pmaddubsw m0, m3 - pmaddubsw m1, m3 - psraw m0, 2 - psraw m1, 2 - pavgw m0, m4 - pavgw m1, m4 -%if mmsize==8 - packuswb m0, m0 - packuswb m1, m1 - movh [dstq+dststrideq*0], m0 - movh [dstq+dststrideq*1], m1 -%else - packuswb m0, m1 - movh [dstq+dststrideq*0], m0 - movhps [dstq+dststrideq*1], m0 -%endif - - lea dstq, [dstq+dststrideq*2] - lea srcq, [srcq+srcstrideq*2] - sub heightd, 2 - jg .nextrow - REP_RET -%endmacro - INIT_MMX ssse3 -FILTER_BILINEAR_SSSE3 4 +FILTER_BILINEAR 4 INIT_XMM ssse3 -FILTER_BILINEAR_SSSE3 8 +FILTER_BILINEAR 8 INIT_MMX mmx cglobal put_vp8_pixels8, 5, 5, 0, dst, dststride, src, srcstride, height diff --git a/libavcodec/xan.c b/libavcodec/xan.c index 4c01c0013fd8d..1ccf164847bb7 100644 --- a/libavcodec/xan.c +++ b/libavcodec/xan.c @@ -131,7 +131,10 @@ static int xan_huffman_decode(uint8_t *dest, int dest_len, return ret; while (val != 0x16) { - unsigned idx = val - 0x17 + get_bits1(&gb) * byte; + unsigned idx; + if (get_bits_left(&gb) < 1) + return AVERROR_INVALIDDATA; + idx = val - 0x17 + get_bits1(&gb) * byte; if (idx >= 2 * byte) return AVERROR_INVALIDDATA; val = src[idx]; @@ -263,7 +266,7 @@ static inline void xan_wc3_copy_pixel_run(XanContext *s, AVFrame *frame, prevframe_index = (y + motion_y) * stride + x + motion_x; prevframe_x = x + motion_x; - if (prev_palette_plane == palette_plane && FFABS(curframe_index - prevframe_index) < pixel_count) { + if (prev_palette_plane == palette_plane && FFABS(motion_x + width*motion_y) < pixel_count) { avpriv_request_sample(s->avctx, "Overlapping copy"); return ; } diff --git a/libavcodec/xwdenc.c b/libavcodec/xwdenc.c index 43bca8903322b..81cca6c9636ec 100644 --- a/libavcodec/xwdenc.c +++ b/libavcodec/xwdenc.c @@ -41,6 +41,7 @@ static int xwd_encode_frame(AVCodecContext *avctx, AVPacket *pkt, int i, out_size, ret; uint8_t *ptr, *buf; AVFrame * const p = (AVFrame *)pict; + uint32_t pal[256]; pixdepth = av_get_bits_per_pixel(desc); if (desc->flags & AV_PIX_FMT_FLAG_BE) @@ -180,11 +181,17 @@ static int xwd_encode_frame(AVCodecContext *avctx, AVPacket *pkt, bytestream_put_be32(&buf, 0); // window border width bytestream_put_buffer(&buf, WINDOW_NAME, WINDOW_NAME_SIZE); + if (pix_fmt == AV_PIX_FMT_PAL8) { + memcpy(pal, p->data[1], sizeof(pal)); + } else { + avpriv_set_systematic_pal2(pal, pix_fmt); + } + for (i = 0; i < ncolors; i++) { uint32_t val; uint8_t red, green, blue; - val = AV_RN32A(p->data[1] + i * 4); + val = pal[i]; red = (val >> 16) & 0xFF; green = (val >> 8) & 0xFF; blue = val & 0xFF; diff --git a/libavcodec/zmbv.c b/libavcodec/zmbv.c index b09dc41ebd2ae..f91d2e393179d 100644 --- a/libavcodec/zmbv.c +++ b/libavcodec/zmbv.c @@ -539,6 +539,8 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame, AVPac } else { frame->key_frame = 0; frame->pict_type = AV_PICTURE_TYPE_P; + if (c->decomp_len < 2LL * ((c->width + c->bw - 1) / c->bw) * ((c->height + c->bh - 1) / c->bh)) + return AVERROR_INVALIDDATA; if (c->decomp_len) c->decode_xor(c); } diff --git a/libavdevice/.gitignore b/libavdevice/.gitignore new file mode 100644 index 0000000000000..08ac3eb86a81f --- /dev/null +++ b/libavdevice/.gitignore @@ -0,0 +1,2 @@ +/indev_list.c +/outdev_list.c diff --git a/libavdevice/Makefile b/libavdevice/Makefile index 8228d6214793f..f11a6f2a860b1 100644 --- a/libavdevice/Makefile +++ b/libavdevice/Makefile @@ -14,6 +14,7 @@ OBJS-$(CONFIG_SHARED) += reverse.o # input/output devices OBJS-$(CONFIG_ALSA_INDEV) += alsa_dec.o alsa.o timefilter.o OBJS-$(CONFIG_ALSA_OUTDEV) += alsa_enc.o alsa.o +OBJS-$(CONFIG_ANDROID_CAMERA_INDEV) += android_camera.o OBJS-$(CONFIG_AVFOUNDATION_INDEV) += avfoundation.o OBJS-$(CONFIG_BKTR_INDEV) += bktr.o OBJS-$(CONFIG_CACA_OUTDEV) += caca.o diff --git a/libavdevice/alldevices.c b/libavdevice/alldevices.c index b767b6a718821..adde749ce1302 100644 --- a/libavdevice/alldevices.c +++ b/libavdevice/alldevices.c @@ -20,59 +20,51 @@ #include "config.h" #include "libavutil/thread.h" +#include "libavformat/internal.h" #include "avdevice.h" -#define REGISTER_OUTDEV(X, x) \ - { \ - extern AVOutputFormat ff_##x##_muxer; \ - if (CONFIG_##X##_OUTDEV) \ - av_register_output_format(&ff_##x##_muxer); \ - } +/* devices */ +extern AVInputFormat ff_alsa_demuxer; +extern AVOutputFormat ff_alsa_muxer; +extern AVInputFormat ff_android_camera_demuxer; +extern AVInputFormat ff_avfoundation_demuxer; +extern AVInputFormat ff_bktr_demuxer; +extern AVOutputFormat ff_caca_muxer; +extern AVInputFormat ff_decklink_demuxer; +extern AVOutputFormat ff_decklink_muxer; +extern AVInputFormat ff_libndi_newtek_demuxer; +extern AVOutputFormat ff_libndi_newtek_muxer; +extern AVInputFormat ff_dshow_demuxer; +extern AVInputFormat ff_fbdev_demuxer; +extern AVOutputFormat ff_fbdev_muxer; +extern AVInputFormat ff_gdigrab_demuxer; +extern AVInputFormat ff_iec61883_demuxer; +extern AVInputFormat ff_jack_demuxer; +extern AVInputFormat ff_kmsgrab_demuxer; +extern AVInputFormat ff_lavfi_demuxer; +extern AVInputFormat ff_openal_demuxer; +extern AVOutputFormat ff_opengl_muxer; +extern AVInputFormat ff_oss_demuxer; +extern AVOutputFormat ff_oss_muxer; +extern AVInputFormat ff_pulse_demuxer; +extern AVOutputFormat ff_pulse_muxer; +extern AVOutputFormat ff_sdl2_muxer; +extern AVInputFormat ff_sndio_demuxer; +extern AVOutputFormat ff_sndio_muxer; +extern AVInputFormat ff_v4l2_demuxer; +extern AVOutputFormat ff_v4l2_muxer; +extern AVInputFormat ff_vfwcap_demuxer; +extern AVInputFormat ff_xcbgrab_demuxer; +extern AVOutputFormat ff_xv_muxer; -#define REGISTER_INDEV(X, x) \ - { \ - extern AVInputFormat ff_##x##_demuxer; \ - if (CONFIG_##X##_INDEV) \ - av_register_input_format(&ff_##x##_demuxer); \ - } +/* external libraries */ +extern AVInputFormat ff_libcdio_demuxer; +extern AVInputFormat ff_libdc1394_demuxer; -#define REGISTER_INOUTDEV(X, x) REGISTER_OUTDEV(X, x); REGISTER_INDEV(X, x) - -static void register_all(void) -{ - /* devices */ - REGISTER_INOUTDEV(ALSA, alsa); - REGISTER_INDEV (AVFOUNDATION, avfoundation); - REGISTER_INDEV (BKTR, bktr); - REGISTER_OUTDEV (CACA, caca); - REGISTER_INOUTDEV(DECKLINK, decklink); - REGISTER_INOUTDEV(LIBNDI_NEWTEK, libndi_newtek); - REGISTER_INDEV (DSHOW, dshow); - REGISTER_INOUTDEV(FBDEV, fbdev); - REGISTER_INDEV (GDIGRAB, gdigrab); - REGISTER_INDEV (IEC61883, iec61883); - REGISTER_INDEV (JACK, jack); - REGISTER_INDEV (KMSGRAB, kmsgrab); - REGISTER_INDEV (LAVFI, lavfi); - REGISTER_INDEV (OPENAL, openal); - REGISTER_OUTDEV (OPENGL, opengl); - REGISTER_INOUTDEV(OSS, oss); - REGISTER_INOUTDEV(PULSE, pulse); - REGISTER_OUTDEV (SDL2, sdl2); - REGISTER_INOUTDEV(SNDIO, sndio); - REGISTER_INOUTDEV(V4L2, v4l2); - REGISTER_INDEV (VFWCAP, vfwcap); - REGISTER_INDEV (XCBGRAB, xcbgrab); - REGISTER_OUTDEV (XV, xv); - - /* external libraries */ - REGISTER_INDEV (LIBCDIO, libcdio); - REGISTER_INDEV (LIBDC1394, libdc1394); -} +#include "libavdevice/outdev_list.c" +#include "libavdevice/indev_list.c" void avdevice_register_all(void) { - static AVOnce control = AV_ONCE_INIT; - - ff_thread_once(&control, register_all); + avpriv_register_devices(outdev_list, indev_list); } diff --git a/libavdevice/alsa.c b/libavdevice/alsa.c index 1bbff30d5cc43..1b21beb6d51e7 100644 --- a/libavdevice/alsa.c +++ b/libavdevice/alsa.c @@ -177,8 +177,8 @@ av_cold int ff_alsa_open(AVFormatContext *ctx, snd_pcm_stream_t mode, snd_pcm_uframes_t buffer_size, period_size; uint64_t layout = ctx->streams[0]->codecpar->channel_layout; - if (ctx->filename[0] == 0) audio_device = "default"; - else audio_device = ctx->filename; + if (ctx->url[0] == 0) audio_device = "default"; + else audio_device = ctx->url; if (*codec_id == AV_CODEC_ID_NONE) *codec_id = DEFAULT_CODEC_ID; diff --git a/libavdevice/alsa.h b/libavdevice/alsa.h index cd41d965f700b..1ed8c82199267 100644 --- a/libavdevice/alsa.h +++ b/libavdevice/alsa.h @@ -43,7 +43,7 @@ typedef void (*ff_reorder_func)(const void *, void *, int); -#define ALSA_BUFFER_SIZE_MAX 65536 +#define ALSA_BUFFER_SIZE_MAX 131072 typedef struct AlsaData { AVClass *class; diff --git a/libavdevice/android_camera.c b/libavdevice/android_camera.c new file mode 100644 index 0000000000000..4a956a7f526a2 --- /dev/null +++ b/libavdevice/android_camera.c @@ -0,0 +1,871 @@ +/* + * Android camera input device + * + * Copyright (C) 2017 Felix Matouschek + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "libavformat/avformat.h" +#include "libavformat/internal.h" +#include "libavutil/avstring.h" +#include "libavutil/display.h" +#include "libavutil/imgutils.h" +#include "libavutil/log.h" +#include "libavutil/opt.h" +#include "libavutil/parseutils.h" +#include "libavutil/pixfmt.h" +#include "libavutil/threadmessage.h" +#include "libavutil/time.h" + +#include "version.h" + +/* This image format is available on all Android devices + * supporting the Camera2 API */ +#define IMAGE_FORMAT_ANDROID AIMAGE_FORMAT_YUV_420_888 + +#define MAX_BUF_COUNT 2 +#define VIDEO_STREAM_INDEX 0 +#define VIDEO_TIMEBASE_ANDROID 1000000000 + +#define RETURN_CASE(x) case x: return AV_STRINGIFY(x); +#define RETURN_DEFAULT(x) default: return AV_STRINGIFY(x); + +typedef struct AndroidCameraCtx { + const AVClass *class; + + int requested_width; + int requested_height; + AVRational framerate; + int camera_index; + int input_queue_size; + + uint8_t lens_facing; + int32_t sensor_orientation; + int width; + int height; + int32_t framerate_range[2]; + int image_format; + + ACameraManager *camera_mgr; + char *camera_id; + ACameraMetadata *camera_metadata; + ACameraDevice *camera_dev; + ACameraDevice_StateCallbacks camera_state_callbacks; + AImageReader *image_reader; + AImageReader_ImageListener image_listener; + ANativeWindow *image_reader_window; + ACaptureSessionOutputContainer *capture_session_output_container; + ACaptureSessionOutput *capture_session_output; + ACameraOutputTarget *camera_output_target; + ACaptureRequest *capture_request; + ACameraCaptureSession_stateCallbacks capture_session_state_callbacks; + ACameraCaptureSession *capture_session; + + AVThreadMessageQueue *input_queue; + atomic_int exit; + atomic_int got_image_format; +} AndroidCameraCtx; + +static const char *camera_status_string(camera_status_t val) +{ + switch(val) { + RETURN_CASE(ACAMERA_OK) + RETURN_CASE(ACAMERA_ERROR_UNKNOWN) + RETURN_CASE(ACAMERA_ERROR_INVALID_PARAMETER) + RETURN_CASE(ACAMERA_ERROR_CAMERA_DISCONNECTED) + RETURN_CASE(ACAMERA_ERROR_NOT_ENOUGH_MEMORY) + RETURN_CASE(ACAMERA_ERROR_METADATA_NOT_FOUND) + RETURN_CASE(ACAMERA_ERROR_CAMERA_DEVICE) + RETURN_CASE(ACAMERA_ERROR_CAMERA_SERVICE) + RETURN_CASE(ACAMERA_ERROR_SESSION_CLOSED) + RETURN_CASE(ACAMERA_ERROR_INVALID_OPERATION) + RETURN_CASE(ACAMERA_ERROR_STREAM_CONFIGURE_FAIL) + RETURN_CASE(ACAMERA_ERROR_CAMERA_IN_USE) + RETURN_CASE(ACAMERA_ERROR_MAX_CAMERA_IN_USE) + RETURN_CASE(ACAMERA_ERROR_CAMERA_DISABLED) + RETURN_CASE(ACAMERA_ERROR_PERMISSION_DENIED) + RETURN_DEFAULT(ACAMERA_ERROR_UNKNOWN) + } +} + +static const char *media_status_string(media_status_t val) +{ + switch(val) { + RETURN_CASE(AMEDIA_OK) + RETURN_CASE(AMEDIA_ERROR_UNKNOWN) + RETURN_CASE(AMEDIA_ERROR_MALFORMED) + RETURN_CASE(AMEDIA_ERROR_UNSUPPORTED) + RETURN_CASE(AMEDIA_ERROR_INVALID_OBJECT) + RETURN_CASE(AMEDIA_ERROR_INVALID_PARAMETER) + RETURN_CASE(AMEDIA_ERROR_INVALID_OPERATION) + RETURN_CASE(AMEDIA_DRM_NOT_PROVISIONED) + RETURN_CASE(AMEDIA_DRM_RESOURCE_BUSY) + RETURN_CASE(AMEDIA_DRM_DEVICE_REVOKED) + RETURN_CASE(AMEDIA_DRM_SHORT_BUFFER) + RETURN_CASE(AMEDIA_DRM_SESSION_NOT_OPENED) + RETURN_CASE(AMEDIA_DRM_TAMPER_DETECTED) + RETURN_CASE(AMEDIA_DRM_VERIFY_FAILED) + RETURN_CASE(AMEDIA_DRM_NEED_KEY) + RETURN_CASE(AMEDIA_DRM_LICENSE_EXPIRED) + RETURN_CASE(AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE) + RETURN_CASE(AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED) + RETURN_CASE(AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE) + RETURN_CASE(AMEDIA_IMGREADER_CANNOT_UNLOCK_IMAGE) + RETURN_CASE(AMEDIA_IMGREADER_IMAGE_NOT_LOCKED) + RETURN_DEFAULT(AMEDIA_ERROR_UNKNOWN) + } +} + +static const char *error_state_callback_string(int val) +{ + switch(val) { + RETURN_CASE(ERROR_CAMERA_IN_USE) + RETURN_CASE(ERROR_MAX_CAMERAS_IN_USE) + RETURN_CASE(ERROR_CAMERA_DISABLED) + RETURN_CASE(ERROR_CAMERA_DEVICE) + RETURN_CASE(ERROR_CAMERA_SERVICE) + default: + return "ERROR_CAMERA_UNKNOWN"; + } +} + +static void camera_dev_disconnected(void *context, ACameraDevice *device) +{ + AVFormatContext *avctx = context; + AndroidCameraCtx *ctx = avctx->priv_data; + atomic_store(&ctx->exit, 1); + av_log(avctx, AV_LOG_ERROR, "Camera with id %s disconnected.\n", + ACameraDevice_getId(device)); +} + +static void camera_dev_error(void *context, ACameraDevice *device, int error) +{ + AVFormatContext *avctx = context; + AndroidCameraCtx *ctx = avctx->priv_data; + atomic_store(&ctx->exit, 1); + av_log(avctx, AV_LOG_ERROR, "Error %s on camera with id %s.\n", + error_state_callback_string(error), ACameraDevice_getId(device)); +} + +static int open_camera(AVFormatContext *avctx) +{ + AndroidCameraCtx *ctx = avctx->priv_data; + camera_status_t ret; + ACameraIdList *camera_ids; + + ret = ACameraManager_getCameraIdList(ctx->camera_mgr, &camera_ids); + if (ret != ACAMERA_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to get camera id list, error: %s.\n", + camera_status_string(ret)); + return AVERROR_EXTERNAL; + } + + if (ctx->camera_index < camera_ids->numCameras) { + ctx->camera_id = av_strdup(camera_ids->cameraIds[ctx->camera_index]); + if (!ctx->camera_id) { + av_log(avctx, AV_LOG_ERROR, "Failed to allocate memory for camera_id.\n"); + return AVERROR(ENOMEM); + } + } else { + av_log(avctx, AV_LOG_ERROR, "No camera with index %d available.\n", + ctx->camera_index); + return AVERROR(ENXIO); + } + + ACameraManager_deleteCameraIdList(camera_ids); + + ret = ACameraManager_getCameraCharacteristics(ctx->camera_mgr, + ctx->camera_id, &ctx->camera_metadata); + if (ret != ACAMERA_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to get metadata for camera with id %s, error: %s.\n", + ctx->camera_id, camera_status_string(ret)); + return AVERROR_EXTERNAL; + } + + ctx->camera_state_callbacks.context = avctx; + ctx->camera_state_callbacks.onDisconnected = camera_dev_disconnected; + ctx->camera_state_callbacks.onError = camera_dev_error; + + ret = ACameraManager_openCamera(ctx->camera_mgr, ctx->camera_id, + &ctx->camera_state_callbacks, &ctx->camera_dev); + if (ret != ACAMERA_OK) { + av_log(avctx, AV_LOG_ERROR, "Failed to open camera with id %s, error: %s.\n", + ctx->camera_id, camera_status_string(ret)); + return AVERROR_EXTERNAL; + } + + return 0; +} + +static void get_sensor_orientation(AVFormatContext *avctx) +{ + AndroidCameraCtx *ctx = avctx->priv_data; + ACameraMetadata_const_entry lens_facing; + ACameraMetadata_const_entry sensor_orientation; + + ACameraMetadata_getConstEntry(ctx->camera_metadata, + ACAMERA_LENS_FACING, &lens_facing); + ACameraMetadata_getConstEntry(ctx->camera_metadata, + ACAMERA_SENSOR_ORIENTATION, &sensor_orientation); + + ctx->lens_facing = lens_facing.data.u8[0]; + ctx->sensor_orientation = sensor_orientation.data.i32[0]; +} + +static void match_video_size(AVFormatContext *avctx) +{ + AndroidCameraCtx *ctx = avctx->priv_data; + ACameraMetadata_const_entry available_configs; + int found = 0; + + ACameraMetadata_getConstEntry(ctx->camera_metadata, + ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, + &available_configs); + + for (int i = 0; i < available_configs.count; i++) { + int32_t input = available_configs.data.i32[i * 4 + 3]; + int32_t format = available_configs.data.i32[i * 4 + 0]; + + if (input) { + continue; + } + + if (format == IMAGE_FORMAT_ANDROID) { + int32_t width = available_configs.data.i32[i * 4 + 1]; + int32_t height = available_configs.data.i32[i * 4 + 2]; + + //Same ratio + if ((ctx->requested_width == width && ctx->requested_height == height) || + (ctx->requested_width == height && ctx->requested_height == width)) { + ctx->width = width; + ctx->height = height; + found = 1; + break; + } + } + } + + if (!found || ctx->width == 0 || ctx->height == 0) { + ctx->width = available_configs.data.i32[1]; + ctx->height = available_configs.data.i32[2]; + + av_log(avctx, AV_LOG_WARNING, + "Requested video_size %dx%d not available, falling back to %dx%d\n", + ctx->requested_width, ctx->requested_height, ctx->width, ctx->height); + } + + return; +} + +static void match_framerate(AVFormatContext *avctx) +{ + AndroidCameraCtx *ctx = avctx->priv_data; + ACameraMetadata_const_entry available_framerates; + int found = 0; + int current_best_match = -1; + int requested_framerate = av_q2d(ctx->framerate); + + ACameraMetadata_getConstEntry(ctx->camera_metadata, + ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, + &available_framerates); + + for (int i = 0; i < available_framerates.count; i++) { + int32_t min = available_framerates.data.i32[i * 2 + 0]; + int32_t max = available_framerates.data.i32[i * 2 + 1]; + + if (requested_framerate == max) { + if (min == max) { + ctx->framerate_range[0] = min; + ctx->framerate_range[1] = max; + found = 1; + break; + } else if (current_best_match >= 0) { + int32_t current_best_match_min = available_framerates.data.i32[current_best_match * 2 + 0]; + if (min > current_best_match_min) { + current_best_match = i; + } + } else { + current_best_match = i; + } + } + } + + if (!found) { + if (current_best_match >= 0) { + ctx->framerate_range[0] = available_framerates.data.i32[current_best_match * 2 + 0]; + ctx->framerate_range[1] = available_framerates.data.i32[current_best_match * 2 + 1]; + + } else { + ctx->framerate_range[0] = available_framerates.data.i32[0]; + ctx->framerate_range[1] = available_framerates.data.i32[1]; + } + + av_log(avctx, AV_LOG_WARNING, + "Requested framerate %d not available, falling back to min: %d and max: %d fps\n", + requested_framerate, ctx->framerate_range[0], ctx->framerate_range[1]); + } + + return; +} + +static int get_image_format(AVFormatContext *avctx, AImage *image) +{ + AndroidCameraCtx *ctx = avctx->priv_data; + int32_t image_pixelstrides[2]; + uint8_t *image_plane_data[2]; + int plane_data_length[2]; + + for (int i = 0; i < 2; i++) { + AImage_getPlanePixelStride(image, i + 1, &image_pixelstrides[i]); + AImage_getPlaneData(image, i + 1, &image_plane_data[i], &plane_data_length[i]); + } + + if (image_pixelstrides[0] != image_pixelstrides[1]) { + av_log(avctx, AV_LOG_ERROR, + "Pixel strides of U and V plane should have been the same.\n"); + return AVERROR_EXTERNAL; + } + + switch (image_pixelstrides[0]) { + case 1: + ctx->image_format = AV_PIX_FMT_YUV420P; + break; + case 2: + if (image_plane_data[0] < image_plane_data[1]) { + ctx->image_format = AV_PIX_FMT_NV12; + } else { + ctx->image_format = AV_PIX_FMT_NV21; + } + break; + default: + av_log(avctx, AV_LOG_ERROR, + "Unknown pixel stride %d of U and V plane, cannot determine camera image format.\n", + image_pixelstrides[0]); + return AVERROR(ENOSYS); + } + + return 0; +} + +static void image_available(void *context, AImageReader *reader) +{ + AVFormatContext *avctx = context; + AndroidCameraCtx *ctx = avctx->priv_data; + media_status_t media_status; + int ret = 0; + + AImage *image; + int64_t image_timestamp; + int32_t image_linestrides[4]; + uint8_t *image_plane_data[4]; + int plane_data_length[4]; + + AVPacket pkt; + int pkt_buffer_size = 0; + + media_status = AImageReader_acquireLatestImage(reader, &image); + if (media_status != AMEDIA_OK) { + if (media_status == AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE) { + av_log(avctx, AV_LOG_WARNING, + "An image reader frame was discarded"); + } else { + av_log(avctx, AV_LOG_ERROR, + "Failed to acquire latest image from image reader, error: %s.\n", + media_status_string(media_status)); + ret = AVERROR_EXTERNAL; + } + goto error; + } + + // Silently drop frames when exit is set + if (atomic_load(&ctx->exit)) { + goto error; + } + + // Determine actual image format + if (!atomic_load(&ctx->got_image_format)) { + ret = get_image_format(avctx, image); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, + "Could not get image format of camera.\n"); + goto error; + } else { + atomic_store(&ctx->got_image_format, 1); + } + } + + pkt_buffer_size = av_image_get_buffer_size(ctx->image_format, ctx->width, ctx->height, 32); + AImage_getTimestamp(image, &image_timestamp); + + AImage_getPlaneRowStride(image, 0, &image_linestrides[0]); + AImage_getPlaneData(image, 0, &image_plane_data[0], &plane_data_length[0]); + + switch (ctx->image_format) { + case AV_PIX_FMT_YUV420P: + AImage_getPlaneRowStride(image, 1, &image_linestrides[1]); + AImage_getPlaneData(image, 1, &image_plane_data[1], &plane_data_length[1]); + AImage_getPlaneRowStride(image, 2, &image_linestrides[2]); + AImage_getPlaneData(image, 2, &image_plane_data[2], &plane_data_length[2]); + break; + case AV_PIX_FMT_NV12: + AImage_getPlaneRowStride(image, 1, &image_linestrides[1]); + AImage_getPlaneData(image, 1, &image_plane_data[1], &plane_data_length[1]); + break; + case AV_PIX_FMT_NV21: + AImage_getPlaneRowStride(image, 2, &image_linestrides[1]); + AImage_getPlaneData(image, 2, &image_plane_data[1], &plane_data_length[1]); + break; + default: + av_log(avctx, AV_LOG_ERROR, "Unsupported camera image format.\n"); + ret = AVERROR(ENOSYS); + goto error; + } + + ret = av_new_packet(&pkt, pkt_buffer_size); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, + "Failed to create new av packet, error: %s.\n", av_err2str(ret)); + goto error; + } + + pkt.stream_index = VIDEO_STREAM_INDEX; + pkt.pts = image_timestamp; + av_image_copy_to_buffer(pkt.data, pkt_buffer_size, + (const uint8_t * const *) image_plane_data, + image_linestrides, ctx->image_format, + ctx->width, ctx->height, 32); + + ret = av_thread_message_queue_send(ctx->input_queue, &pkt, AV_THREAD_MESSAGE_NONBLOCK); + +error: + if (ret < 0) { + if (ret != AVERROR(EAGAIN)) { + av_log(avctx, AV_LOG_ERROR, + "Error while processing new image, error: %s.\n", av_err2str(ret)); + av_thread_message_queue_set_err_recv(ctx->input_queue, ret); + atomic_store(&ctx->exit, 1); + } else { + av_log(avctx, AV_LOG_WARNING, + "Input queue was full, dropping frame, consider raising the input_queue_size option (current value: %d)\n", + ctx->input_queue_size); + } + if (pkt_buffer_size) { + av_packet_unref(&pkt); + } + } + + AImage_delete(image); + + return; +} + +static int create_image_reader(AVFormatContext *avctx) +{ + AndroidCameraCtx *ctx = avctx->priv_data; + media_status_t ret; + + ret = AImageReader_new(ctx->width, ctx->height, IMAGE_FORMAT_ANDROID, + MAX_BUF_COUNT, &ctx->image_reader); + if (ret != AMEDIA_OK) { + av_log(avctx, AV_LOG_ERROR, + "Failed to create image reader, error: %s.\n", media_status_string(ret)); + return AVERROR_EXTERNAL; + } + + ctx->image_listener.context = avctx; + ctx->image_listener.onImageAvailable = image_available; + + ret = AImageReader_setImageListener(ctx->image_reader, &ctx->image_listener); + if (ret != AMEDIA_OK) { + av_log(avctx, AV_LOG_ERROR, + "Failed to set image listener on image reader, error: %s.\n", + media_status_string(ret)); + return AVERROR_EXTERNAL; + } + + ret = AImageReader_getWindow(ctx->image_reader, &ctx->image_reader_window); + if (ret != AMEDIA_OK) { + av_log(avctx, AV_LOG_ERROR, + "Could not get image reader window, error: %s.\n", + media_status_string(ret)); + return AVERROR_EXTERNAL; + } + + return 0; +} + +static void capture_session_closed(void *context, ACameraCaptureSession *session) +{ + av_log(context, AV_LOG_INFO, "Android camera capture session was closed.\n"); +} + +static void capture_session_ready(void *context, ACameraCaptureSession *session) +{ + av_log(context, AV_LOG_INFO, "Android camera capture session is ready.\n"); +} + +static void capture_session_active(void *context, ACameraCaptureSession *session) +{ + av_log(context, AV_LOG_INFO, "Android camera capture session is active.\n"); +} + +static int create_capture_session(AVFormatContext *avctx) +{ + AndroidCameraCtx *ctx = avctx->priv_data; + camera_status_t ret; + + ret = ACaptureSessionOutputContainer_create(&ctx->capture_session_output_container); + if (ret != ACAMERA_OK) { + av_log(avctx, AV_LOG_ERROR, + "Failed to create capture session output container, error: %s.\n", + camera_status_string(ret)); + return AVERROR_EXTERNAL; + } + + ANativeWindow_acquire(ctx->image_reader_window); + + ret = ACaptureSessionOutput_create(ctx->image_reader_window, &ctx->capture_session_output); + if (ret != ACAMERA_OK) { + av_log(avctx, AV_LOG_ERROR, + "Failed to create capture session container, error: %s.\n", + camera_status_string(ret)); + return AVERROR_EXTERNAL; + } + + ret = ACaptureSessionOutputContainer_add(ctx->capture_session_output_container, + ctx->capture_session_output); + if (ret != ACAMERA_OK) { + av_log(avctx, AV_LOG_ERROR, + "Failed to add output to output container, error: %s.\n", + camera_status_string(ret)); + return AVERROR_EXTERNAL; + } + + ret = ACameraOutputTarget_create(ctx->image_reader_window, &ctx->camera_output_target); + if (ret != ACAMERA_OK) { + av_log(avctx, AV_LOG_ERROR, + "Failed to create camera output target, error: %s.\n", + camera_status_string(ret)); + return AVERROR_EXTERNAL; + } + + ret = ACameraDevice_createCaptureRequest(ctx->camera_dev, TEMPLATE_RECORD, &ctx->capture_request); + if (ret != ACAMERA_OK) { + av_log(avctx, AV_LOG_ERROR, + "Failed to create capture request, error: %s.\n", + camera_status_string(ret)); + return AVERROR_EXTERNAL; + } + + ret = ACaptureRequest_setEntry_i32(ctx->capture_request, ACAMERA_CONTROL_AE_TARGET_FPS_RANGE, + 2, ctx->framerate_range); + if (ret != ACAMERA_OK) { + av_log(avctx, AV_LOG_ERROR, + "Failed to set target fps range in capture request, error: %s.\n", + camera_status_string(ret)); + return AVERROR_EXTERNAL; + } + + ret = ACaptureRequest_addTarget(ctx->capture_request, ctx->camera_output_target); + if (ret != ACAMERA_OK) { + av_log(avctx, AV_LOG_ERROR, + "Failed to add capture request capture request, error: %s.\n", + camera_status_string(ret)); + return AVERROR_EXTERNAL; + } + + ctx->capture_session_state_callbacks.context = avctx; + ctx->capture_session_state_callbacks.onClosed = capture_session_closed; + ctx->capture_session_state_callbacks.onReady = capture_session_ready; + ctx->capture_session_state_callbacks.onActive = capture_session_active; + + ret = ACameraDevice_createCaptureSession(ctx->camera_dev, ctx->capture_session_output_container, + &ctx->capture_session_state_callbacks, &ctx->capture_session); + if (ret != ACAMERA_OK) { + av_log(avctx, AV_LOG_ERROR, + "Failed to create capture session, error: %s.\n", + camera_status_string(ret)); + return AVERROR_EXTERNAL; + } + + ret = ACameraCaptureSession_setRepeatingRequest(ctx->capture_session, NULL, 1, &ctx->capture_request, NULL); + if (ret != ACAMERA_OK) { + av_log(avctx, AV_LOG_ERROR, + "Failed to set repeating request on capture session, error: %s.\n", + camera_status_string(ret)); + return AVERROR_EXTERNAL; + } + + return 0; +} + +static int wait_for_image_format(AVFormatContext *avctx) +{ + AndroidCameraCtx *ctx = avctx->priv_data; + + while (!atomic_load(&ctx->got_image_format) && !atomic_load(&ctx->exit)) { + //Wait until first frame arrived and actual image format was determined + usleep(1000); + } + + return atomic_load(&ctx->got_image_format); +} + +static int add_display_matrix(AVFormatContext *avctx, AVStream *st) +{ + AndroidCameraCtx *ctx = avctx->priv_data; + uint8_t *side_data; + int32_t display_matrix[9]; + + av_display_rotation_set(display_matrix, ctx->sensor_orientation); + + if (ctx->lens_facing == ACAMERA_LENS_FACING_FRONT) { + av_display_matrix_flip(display_matrix, 1, 0); + } + + side_data = av_stream_new_side_data(st, + AV_PKT_DATA_DISPLAYMATRIX, sizeof(display_matrix)); + + if (!side_data) { + return AVERROR(ENOMEM); + } + + memcpy(side_data, display_matrix, sizeof(display_matrix)); + + return 0; +} + +static int add_video_stream(AVFormatContext *avctx) +{ + AndroidCameraCtx *ctx = avctx->priv_data; + AVStream *st; + AVCodecParameters *codecpar; + + st = avformat_new_stream(avctx, NULL); + if (!st) { + return AVERROR(ENOMEM); + } + + st->id = VIDEO_STREAM_INDEX; + st->avg_frame_rate = (AVRational) { ctx->framerate_range[1], 1 }; + st->r_frame_rate = (AVRational) { ctx->framerate_range[1], 1 }; + + if (!wait_for_image_format(avctx)) { + return AVERROR_EXTERNAL; + } + + codecpar = st->codecpar; + codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + codecpar->codec_id = AV_CODEC_ID_RAWVIDEO; + codecpar->format = ctx->image_format; + codecpar->width = ctx->width; + codecpar->height = ctx->height; + + avpriv_set_pts_info(st, 64, 1, VIDEO_TIMEBASE_ANDROID); + + return add_display_matrix(avctx, st); +} + +static int android_camera_read_close(AVFormatContext *avctx) +{ + AndroidCameraCtx *ctx = avctx->priv_data; + + atomic_store(&ctx->exit, 1); + + if (ctx->capture_session) { + ACameraCaptureSession_stopRepeating(ctx->capture_session); + // Following warning is emitted, after capture session closed callback is received: + // ACameraCaptureSession: Device is closed but session 0 is not notified + // Seems to be a bug in Android, we can ignore this + ACameraCaptureSession_close(ctx->capture_session); + ctx->capture_session = NULL; + } + + if (ctx->capture_request) { + ACaptureRequest_removeTarget(ctx->capture_request, ctx->camera_output_target); + ACaptureRequest_free(ctx->capture_request); + ctx->capture_request = NULL; + } + + if (ctx->camera_output_target) { + ACameraOutputTarget_free(ctx->camera_output_target); + ctx->camera_output_target = NULL; + } + + if (ctx->capture_session_output) { + ACaptureSessionOutputContainer_remove(ctx->capture_session_output_container, + ctx->capture_session_output); + ACaptureSessionOutput_free(ctx->capture_session_output); + ctx->capture_session_output = NULL; + } + + if (ctx->image_reader_window) { + ANativeWindow_release(ctx->image_reader_window); + ctx->image_reader_window = NULL; + } + + if (ctx->capture_session_output_container) { + ACaptureSessionOutputContainer_free(ctx->capture_session_output_container); + ctx->capture_session_output_container = NULL; + } + + if (ctx->camera_dev) { + ACameraDevice_close(ctx->camera_dev); + ctx->camera_dev = NULL; + } + + if (ctx->image_reader) { + AImageReader_delete(ctx->image_reader); + ctx->image_reader = NULL; + } + + if (ctx->camera_metadata) { + ACameraMetadata_free(ctx->camera_metadata); + ctx->camera_metadata = NULL; + } + + av_freep(&ctx->camera_id); + + if (ctx->camera_mgr) { + ACameraManager_delete(ctx->camera_mgr); + ctx->camera_mgr = NULL; + } + + if (ctx->input_queue) { + AVPacket pkt; + av_thread_message_queue_set_err_send(ctx->input_queue, AVERROR_EOF); + while (av_thread_message_queue_recv(ctx->input_queue, &pkt, AV_THREAD_MESSAGE_NONBLOCK) >= 0) { + av_packet_unref(&pkt); + } + av_thread_message_queue_free(&ctx->input_queue); + } + + return 0; +} + +static int android_camera_read_header(AVFormatContext *avctx) +{ + AndroidCameraCtx *ctx = avctx->priv_data; + int ret; + + atomic_init(&ctx->got_image_format, 0); + atomic_init(&ctx->exit, 0); + + ret = av_thread_message_queue_alloc(&ctx->input_queue, ctx->input_queue_size, sizeof(AVPacket)); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, + "Failed to allocate input queue, error: %s.\n", av_err2str(ret)); + goto error; + } + + ctx->camera_mgr = ACameraManager_create(); + if (!ctx->camera_mgr) { + av_log(avctx, AV_LOG_ERROR, "Failed to create Android camera manager.\n"); + ret = AVERROR_EXTERNAL; + goto error; + } + + ret = open_camera(avctx); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to open camera.\n"); + goto error; + } + + get_sensor_orientation(avctx); + match_video_size(avctx); + match_framerate(avctx); + + ret = create_image_reader(avctx); + if (ret < 0) { + goto error; + } + + ret = create_capture_session(avctx); + if (ret < 0) { + goto error; + } + + ret = add_video_stream(avctx); + +error: + if (ret < 0) { + android_camera_read_close(avctx); + av_log(avctx, AV_LOG_ERROR, "Failed to open android_camera.\n"); + } + + return ret; +} + +static int android_camera_read_packet(AVFormatContext *avctx, AVPacket *pkt) +{ + AndroidCameraCtx *ctx = avctx->priv_data; + int ret; + + if (!atomic_load(&ctx->exit)) { + ret = av_thread_message_queue_recv(ctx->input_queue, pkt, + avctx->flags & AVFMT_FLAG_NONBLOCK ? AV_THREAD_MESSAGE_NONBLOCK : 0); + } else { + ret = AVERROR_EOF; + } + + if (ret < 0) { + return ret; + } else { + return pkt->size; + } +} + +#define OFFSET(x) offsetof(AndroidCameraCtx, x) +#define DEC AV_OPT_FLAG_DECODING_PARAM +static const AVOption options[] = { + { "video_size", "set video size given as a string such as 640x480 or hd720", OFFSET(requested_width), AV_OPT_TYPE_IMAGE_SIZE, {.str = NULL}, 0, 0, DEC }, + { "framerate", "set video frame rate", OFFSET(framerate), AV_OPT_TYPE_VIDEO_RATE, {.str = "30"}, 0, INT_MAX, DEC }, + { "camera_index", "set index of camera to use", OFFSET(camera_index), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC }, + { "input_queue_size", "set maximum number of frames to buffer", OFFSET(input_queue_size), AV_OPT_TYPE_INT, {.i64 = 5}, 0, INT_MAX, DEC }, + { NULL }, +}; + +static const AVClass android_camera_class = { + .class_name = "android_camera indev", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, + .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT, +}; + +AVInputFormat ff_android_camera_demuxer = { + .name = "android_camera", + .long_name = NULL_IF_CONFIG_SMALL("Android camera input device"), + .priv_data_size = sizeof(AndroidCameraCtx), + .read_header = android_camera_read_header, + .read_packet = android_camera_read_packet, + .read_close = android_camera_read_close, + .flags = AVFMT_NOFILE, + .priv_class = &android_camera_class, +}; diff --git a/libavdevice/avdevice.c b/libavdevice/avdevice.c index 01c46924d10a0..72e1b67887f9b 100644 --- a/libavdevice/avdevice.c +++ b/libavdevice/avdevice.c @@ -135,9 +135,9 @@ int avdevice_app_to_dev_control_message(struct AVFormatContext *s, enum AVAppToD int avdevice_dev_to_app_control_message(struct AVFormatContext *s, enum AVDevToAppMessageType type, void *data, size_t data_size) { - if (!av_format_get_control_message_cb(s)) + if (!s->control_message_cb) return AVERROR(ENOSYS); - return av_format_get_control_message_cb(s)(s, type, data, data_size); + return s->control_message_cb(s, type, data, data_size); } int avdevice_capabilities_create(AVDeviceCapabilitiesQuery **caps, AVFormatContext *s, diff --git a/libavdevice/avfoundation.m b/libavdevice/avfoundation.m index e2ddf47dbe8dc..a540f6a079246 100644 --- a/libavdevice/avfoundation.m +++ b/libavdevice/avfoundation.m @@ -259,7 +259,7 @@ static void destroy_context(AVFContext* ctx) static void parse_device_name(AVFormatContext *s) { AVFContext *ctx = (AVFContext*)s->priv_data; - char *tmp = av_strdup(s->filename); + char *tmp = av_strdup(s->url); char *save; if (tmp[0] != ':') { diff --git a/libavdevice/bktr.c b/libavdevice/bktr.c index 418247dc4eb5e..993cc19ac7c79 100644 --- a/libavdevice/bktr.c +++ b/libavdevice/bktr.c @@ -294,7 +294,7 @@ static int grab_read_header(AVFormatContext *s1) st->codecpar->height = s->height; st->avg_frame_rate = framerate; - if (bktr_init(s1->filename, s->width, s->height, s->standard, + if (bktr_init(s1->url, s->width, s->height, s->standard, &s->video_fd, &s->tuner_fd, -1, 0.0) < 0) { ret = AVERROR(EIO); goto out; diff --git a/libavdevice/caca.c b/libavdevice/caca.c index 93cc0ffd252e9..47de8247dcf11 100644 --- a/libavdevice/caca.c +++ b/libavdevice/caca.c @@ -178,7 +178,7 @@ static int caca_write_header(AVFormatContext *s) } if (!c->window_title) - c->window_title = av_strdup(s->filename); + c->window_title = av_strdup(s->url); caca_set_display_title(c->display, c->window_title); caca_set_display_time(c->display, av_rescale_q(1, st->codec->time_base, AV_TIME_BASE_Q)); diff --git a/libavdevice/decklink_common.cpp b/libavdevice/decklink_common.cpp index 2bd63ac820c75..b889033cf8ea7 100644 --- a/libavdevice/decklink_common.cpp +++ b/libavdevice/decklink_common.cpp @@ -29,7 +29,18 @@ extern "C" { #ifdef _WIN32 #include #else +/* The file provided by the SDK is known to be missing prototypes, which doesn't + cause issues with GCC since the warning doesn't apply to C++ files. However + Clang does complain (and warnings are treated as errors), so suppress the + warning just for this one file */ +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmissing-prototypes" +#endif #include +#ifdef __clang__ +#pragma clang diagnostic pop +#endif #endif extern "C" { @@ -75,7 +86,6 @@ static char *dup_wchar_to_utf8(wchar_t *w) #define DECKLINK_STR OLECHAR * #define DECKLINK_STRDUP dup_wchar_to_utf8 #define DECKLINK_FREE(s) SysFreeString(s) -#define DECKLINK_BOOL BOOL #elif defined(__APPLE__) static char *dup_cfstring_to_utf8(CFStringRef w) { @@ -86,13 +96,11 @@ static char *dup_cfstring_to_utf8(CFStringRef w) #define DECKLINK_STR const __CFString * #define DECKLINK_STRDUP dup_cfstring_to_utf8 #define DECKLINK_FREE(s) CFRelease(s) -#define DECKLINK_BOOL bool #else #define DECKLINK_STR const char * #define DECKLINK_STRDUP av_strdup /* free() is needed for a string returned by the DeckLink SDL. */ #define DECKLINK_FREE(s) free((void *) s) -#define DECKLINK_BOOL bool #endif HRESULT ff_decklink_get_display_name(IDeckLink *This, const char **displayName) @@ -148,23 +156,12 @@ static DECKLINK_BOOL field_order_eq(enum AVFieldOrder field_order, BMDFieldDomin return false; } -int ff_decklink_set_format(AVFormatContext *avctx, - int width, int height, - int tb_num, int tb_den, - enum AVFieldOrder field_order, - decklink_direction_t direction, int num) -{ +int ff_decklink_set_configs(AVFormatContext *avctx, + decklink_direction_t direction) { struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data; struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx; - BMDDisplayModeSupport support; - IDeckLinkDisplayModeIterator *itermode; - IDeckLinkDisplayMode *mode; - int i = 1; HRESULT res; - av_log(avctx, AV_LOG_DEBUG, "Trying to find mode for frame size %dx%d, frame timing %d/%d, field order %d, direction %d, mode number %d, format code %s\n", - width, height, tb_num, tb_den, field_order, direction, num, (cctx->format_code) ? cctx->format_code : "(unset)"); - if (ctx->duplex_mode) { DECKLINK_BOOL duplex_supported = false; @@ -181,7 +178,6 @@ int ff_decklink_set_format(AVFormatContext *avctx, av_log(avctx, AV_LOG_WARNING, "Unable to set duplex mode, because it is not supported.\n"); } } - if (direction == DIRECTION_IN) { int ret; ret = decklink_select_input(avctx, bmdDeckLinkConfigAudioInputConnection); @@ -190,6 +186,28 @@ int ff_decklink_set_format(AVFormatContext *avctx, ret = decklink_select_input(avctx, bmdDeckLinkConfigVideoInputConnection); if (ret < 0) return ret; + } + return 0; +} + +int ff_decklink_set_format(AVFormatContext *avctx, + int width, int height, + int tb_num, int tb_den, + enum AVFieldOrder field_order, + decklink_direction_t direction, int num) +{ + struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data; + struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx; + BMDDisplayModeSupport support; + IDeckLinkDisplayModeIterator *itermode; + IDeckLinkDisplayMode *mode; + int i = 1; + HRESULT res; + + av_log(avctx, AV_LOG_DEBUG, "Trying to find mode for frame size %dx%d, frame timing %d/%d, field order %d, direction %d, mode number %d, format code %s\n", + width, height, tb_num, tb_den, field_order, direction, num, (cctx->format_code) ? cctx->format_code : "(unset)"); + + if (direction == DIRECTION_IN) { res = ctx->dli->GetDisplayModeIterator (&itermode); } else { res = ctx->dlo->GetDisplayModeIterator (&itermode); @@ -304,21 +322,14 @@ int ff_decklink_list_devices(AVFormatContext *avctx, ret = AVERROR(ENOMEM); goto next; } - new_device->device_name = av_strdup(displayName); - if (!new_device->device_name) { - ret = AVERROR(ENOMEM); - goto next; - } + new_device->device_name = av_strdup(displayName); new_device->device_description = av_strdup(displayName); - if (!new_device->device_description) { - av_freep(&new_device->device_name); - ret = AVERROR(ENOMEM); - goto next; - } - if ((ret = av_dynarray_add_nofree(&device_list->devices, - &device_list->nb_devices, new_device)) < 0) { + if (!new_device->device_name || + !new_device->device_description || + av_dynarray_add_nofree(&device_list->devices, &device_list->nb_devices, new_device) < 0) { + ret = AVERROR(ENOMEM); av_freep(&new_device->device_name); av_freep(&new_device->device_description); av_freep(&new_device); @@ -386,7 +397,7 @@ int ff_decklink_list_formats(AVFormatContext *avctx, decklink_direction_t direct } av_log(avctx, AV_LOG_INFO, "Supported formats for '%s':\n\tformat_code\tdescription", - avctx->filename); + avctx->url); while (itermode->Next(&mode) == S_OK) { BMDTimeValue tb_num, tb_den; mode->GetFrameRate(&tb_num, &tb_den); diff --git a/libavdevice/decklink_common.h b/libavdevice/decklink_common.h index 6b2525fb53691..57ee7d1d689f6 100644 --- a/libavdevice/decklink_common.h +++ b/libavdevice/decklink_common.h @@ -28,6 +28,12 @@ #include "libavutil/thread.h" #include "decklink_common_c.h" +#ifdef _WIN32 +#define DECKLINK_BOOL BOOL +#else +#define DECKLINK_BOOL bool +#endif + class decklink_output_callback; class decklink_input_callback; @@ -95,8 +101,10 @@ struct decklink_ctx { pthread_mutex_t mutex; pthread_cond_t cond; int frames_buffer_available_spots; + int autodetect; int channels; + int audio_depth; }; typedef enum { DIRECTION_IN, DIRECTION_OUT} decklink_direction_t; @@ -133,6 +141,7 @@ static const BMDVideoConnection decklink_video_connection_map[] = { }; HRESULT ff_decklink_get_display_name(IDeckLink *This, const char **displayName); +int ff_decklink_set_configs(AVFormatContext *avctx, decklink_direction_t direction); int ff_decklink_set_format(AVFormatContext *avctx, int width, int height, int tb_num, int tb_den, enum AVFieldOrder field_order, decklink_direction_t direction = DIRECTION_OUT, int num = 0); int ff_decklink_set_format(AVFormatContext *avctx, decklink_direction_t direction, int num); int ff_decklink_list_devices(AVFormatContext *avctx, struct AVDeviceInfoList *device_list, int show_inputs, int show_outputs); diff --git a/libavdevice/decklink_common_c.h b/libavdevice/decklink_common_c.h index 5616ab32f9cc6..08e9f9bbd5e12 100644 --- a/libavdevice/decklink_common_c.h +++ b/libavdevice/decklink_common_c.h @@ -28,6 +28,8 @@ typedef enum DecklinkPtsSource { PTS_SRC_VIDEO = 2, PTS_SRC_REFERENCE = 3, PTS_SRC_WALLCLOCK = 4, + PTS_SRC_ABS_WALLCLOCK = 5, + PTS_SRC_NB } DecklinkPtsSource; struct decklink_cctx { @@ -42,6 +44,7 @@ struct decklink_cctx { double preroll; int v210; int audio_channels; + int audio_depth; int duplex_mode; DecklinkPtsSource audio_pts_source; DecklinkPtsSource video_pts_source; @@ -51,6 +54,7 @@ struct decklink_cctx { char *format_code; int raw_format; int64_t queue_size; + int copyts; }; #endif /* AVDEVICE_DECKLINK_COMMON_C_H */ diff --git a/libavdevice/decklink_dec.cpp b/libavdevice/decklink_dec.cpp index d9ac01ac91bd1..e97a4402ea319 100644 --- a/libavdevice/decklink_dec.cpp +++ b/libavdevice/decklink_dec.cpp @@ -36,6 +36,7 @@ extern "C" { #include "libavutil/avutil.h" #include "libavutil/common.h" #include "libavutil/imgutils.h" +#include "libavutil/intreadwrite.h" #include "libavutil/time.h" #include "libavutil/mathematics.h" #include "libavutil/reverse.h" @@ -49,6 +50,7 @@ extern "C" { #include "decklink_dec.h" #define MAX_WIDTH_VANC 1920 +const BMDDisplayMode AUTODETECT_DEFAULT_MODE = bmdModeNTSC; typedef struct VANCLineNumber { BMDDisplayMode mode; @@ -147,6 +149,17 @@ static void extract_luma_from_v210(uint16_t *dst, const uint8_t *src, int width) } } +static void unpack_v210(uint16_t *dst, const uint8_t *src, int width) +{ + int i; + for (i = 0; i < width * 2 / 3; i++) { + *dst++ = src[0] + ((src[1] & 3) << 8); + *dst++ = (src[1] >> 2) + ((src[2] & 15) << 6); + *dst++ = (src[2] >> 4) + ((src[3] & 63) << 4); + src += 4; + } +} + static uint8_t calc_parity_and_line_offset(int line) { uint8_t ret = (line < 313) << 5; @@ -262,8 +275,8 @@ static uint8_t* teletext_data_unit_from_ancillary_packet(uint16_t *py, uint16_t return tgt; } -uint8_t *vanc_to_cc(AVFormatContext *avctx, uint16_t *buf, size_t words, - unsigned &cc_count) +static uint8_t *vanc_to_cc(AVFormatContext *avctx, uint16_t *buf, size_t words, + unsigned &cc_count) { size_t i, len = (buf[5] & 0xff) + 6 + 1; uint8_t cdp_sum, rate; @@ -352,8 +365,8 @@ uint8_t *vanc_to_cc(AVFormatContext *avctx, uint16_t *buf, size_t words, return cc; } -uint8_t *get_metadata(AVFormatContext *avctx, uint16_t *buf, size_t width, - uint8_t *tgt, size_t tgt_size, AVPacket *pkt) +static uint8_t *get_metadata(AVFormatContext *avctx, uint16_t *buf, size_t width, + uint8_t *tgt, size_t tgt_size, AVPacket *pkt) { decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data; uint16_t *max_buf = buf + width; @@ -451,24 +464,22 @@ static unsigned long long avpacket_queue_size(AVPacketQueue *q) static int avpacket_queue_put(AVPacketQueue *q, AVPacket *pkt) { AVPacketList *pkt1; - int ret; // Drop Packet if queue size is > maximum queue size if (avpacket_queue_size(q) > (uint64_t)q->max_q_size) { av_log(q->avctx, AV_LOG_WARNING, "Decklink input buffer overrun!\n"); return -1; } - - pkt1 = (AVPacketList *)av_mallocz(sizeof(AVPacketList)); - if (!pkt1) { + /* ensure the packet is reference counted */ + if (av_packet_make_refcounted(pkt) < 0) { return -1; } - ret = av_packet_ref(&pkt1->pkt, pkt); - av_packet_unref(pkt); - if (ret < 0) { - av_free(pkt1); + + pkt1 = (AVPacketList *)av_malloc(sizeof(AVPacketList)); + if (!pkt1) { return -1; } + av_packet_move_ref(&pkt1->pkt, pkt); pkt1->next = NULL; pthread_mutex_lock(&q->mutex); @@ -583,8 +594,10 @@ ULONG decklink_input_callback::Release(void) static int64_t get_pkt_pts(IDeckLinkVideoInputFrame *videoFrame, IDeckLinkAudioInputPacket *audioFrame, int64_t wallclock, + int64_t abs_wallclock, DecklinkPtsSource pts_src, - AVRational time_base, int64_t *initial_pts) + AVRational time_base, int64_t *initial_pts, + int copyts) { int64_t pts = AV_NOPTS_VALUE; BMDTimeValue bmd_pts; @@ -604,23 +617,30 @@ static int64_t get_pkt_pts(IDeckLinkVideoInputFrame *videoFrame, res = videoFrame->GetHardwareReferenceTimestamp(time_base.den, &bmd_pts, &bmd_duration); break; case PTS_SRC_WALLCLOCK: + /* fall through */ + case PTS_SRC_ABS_WALLCLOCK: { /* MSVC does not support compound literals like AV_TIME_BASE_Q * in C++ code (compiler error C4576) */ AVRational timebase; timebase.num = 1; timebase.den = AV_TIME_BASE; - pts = av_rescale_q(wallclock, timebase, time_base); + if (pts_src == PTS_SRC_WALLCLOCK) + pts = av_rescale_q(wallclock, timebase, time_base); + else + pts = av_rescale_q(abs_wallclock, timebase, time_base); break; } } if (res == S_OK) pts = bmd_pts / time_base.num; - if (pts != AV_NOPTS_VALUE && *initial_pts == AV_NOPTS_VALUE) - *initial_pts = pts; - if (*initial_pts != AV_NOPTS_VALUE) - pts -= *initial_pts; + if (!copyts) { + if (pts != AV_NOPTS_VALUE && *initial_pts == AV_NOPTS_VALUE) + *initial_pts = pts; + if (*initial_pts != AV_NOPTS_VALUE) + pts -= *initial_pts; + } return pts; } @@ -632,11 +652,23 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( void *audioFrameBytes; BMDTimeValue frameTime; BMDTimeValue frameDuration; - int64_t wallclock = 0; + int64_t wallclock = 0, abs_wallclock = 0; + struct decklink_cctx *cctx = (struct decklink_cctx *) avctx->priv_data; + + if (ctx->autodetect) { + if (videoFrame && !(videoFrame->GetFlags() & bmdFrameHasNoInputSource) && + ctx->bmd_mode == bmdModeUnknown) + { + ctx->bmd_mode = AUTODETECT_DEFAULT_MODE; + } + return S_OK; + } ctx->frameCount++; if (ctx->audio_pts_source == PTS_SRC_WALLCLOCK || ctx->video_pts_source == PTS_SRC_WALLCLOCK) wallclock = av_gettime_relative(); + if (ctx->audio_pts_source == PTS_SRC_ABS_WALLCLOCK || ctx->video_pts_source == PTS_SRC_ABS_WALLCLOCK) + abs_wallclock = av_gettime(); // Handle Video Frame if (videoFrame) { @@ -683,7 +715,7 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( no_video = 0; } - pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, ctx->video_pts_source, ctx->video_st->time_base, &initial_video_pts); + pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, abs_wallclock, ctx->video_pts_source, ctx->video_st->time_base, &initial_video_pts, cctx->copyts); pkt.dts = pkt.pts; pkt.duration = frameDuration; @@ -729,9 +761,15 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( for (i = vanc_line_numbers[idx].vanc_start; i <= vanc_line_numbers[idx].vanc_end; i++) { uint8_t *buf; if (vanc->GetBufferForVerticalBlankingLine(i, (void**)&buf) == S_OK) { - uint16_t luma_vanc[MAX_WIDTH_VANC]; - extract_luma_from_v210(luma_vanc, buf, videoFrame->GetWidth()); - txt_buf = get_metadata(avctx, luma_vanc, videoFrame->GetWidth(), + uint16_t vanc[MAX_WIDTH_VANC]; + size_t vanc_size = videoFrame->GetWidth(); + if (ctx->bmd_mode == bmdModeNTSC && videoFrame->GetWidth() * 2 <= MAX_WIDTH_VANC) { + vanc_size = vanc_size * 2; + unpack_v210(vanc, buf, videoFrame->GetWidth()); + } else { + extract_luma_from_v210(vanc, buf, videoFrame->GetWidth()); + } + txt_buf = get_metadata(avctx, vanc, vanc_size, txt_buf, sizeof(txt_buf0) - (txt_buf - txt_buf0), &pkt); } if (i == vanc_line_numbers[idx].field0_vanc_end) @@ -771,10 +809,10 @@ HRESULT decklink_input_callback::VideoInputFrameArrived( av_init_packet(&pkt); //hack among hacks - pkt.size = audioFrame->GetSampleFrameCount() * ctx->audio_st->codecpar->channels * (16 / 8); + pkt.size = audioFrame->GetSampleFrameCount() * ctx->audio_st->codecpar->channels * (ctx->audio_depth / 8); audioFrame->GetBytes(&audioFrameBytes); audioFrame->GetPacketTime(&audio_pts, ctx->audio_st->time_base.den); - pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, ctx->audio_pts_source, ctx->audio_st->time_base, &initial_audio_pts); + pkt.pts = get_pkt_pts(videoFrame, audioFrame, wallclock, abs_wallclock, ctx->audio_pts_source, ctx->audio_st->time_base, &initial_audio_pts, cctx->copyts); pkt.dts = pkt.pts; //fprintf(stderr,"Audio Frame size %d ts %d\n", pkt.size, pkt.pts); @@ -794,17 +832,56 @@ HRESULT decklink_input_callback::VideoInputFormatChanged( BMDVideoInputFormatChangedEvents events, IDeckLinkDisplayMode *mode, BMDDetectedVideoInputFormatFlags) { + ctx->bmd_mode = mode->GetDisplayMode(); return S_OK; } -static HRESULT decklink_start_input(AVFormatContext *avctx) -{ - struct decklink_cctx *cctx = (struct decklink_cctx *)avctx->priv_data; +static int decklink_autodetect(struct decklink_cctx *cctx) { struct decklink_ctx *ctx = (struct decklink_ctx *)cctx->ctx; + DECKLINK_BOOL autodetect_supported = false; + int i; + + if (ctx->attr->GetFlag(BMDDeckLinkSupportsInputFormatDetection, &autodetect_supported) != S_OK) + return -1; + if (autodetect_supported == false) + return -1; + + ctx->autodetect = 1; + ctx->bmd_mode = bmdModeUnknown; + if (ctx->dli->EnableVideoInput(AUTODETECT_DEFAULT_MODE, + bmdFormat8BitYUV, + bmdVideoInputEnableFormatDetection) != S_OK) { + return -1; + } + + if (ctx->dli->StartStreams() != S_OK) { + return -1; + } + + // 1 second timeout + for (i = 0; i < 10; i++) { + av_usleep(100000); + /* Sometimes VideoInputFrameArrived is called without the + * bmdFrameHasNoInputSource flag before VideoInputFormatChanged. + * So don't break for bmd_mode == AUTODETECT_DEFAULT_MODE. */ + if (ctx->bmd_mode != bmdModeUnknown && + ctx->bmd_mode != AUTODETECT_DEFAULT_MODE) + break; + } + + ctx->dli->PauseStreams(); + ctx->dli->FlushStreams(); + ctx->autodetect = 0; + if (ctx->bmd_mode != bmdModeUnknown) { + cctx->format_code = (char *)av_mallocz(5); + if (!cctx->format_code) + return -1; + AV_WB32(cctx->format_code, ctx->bmd_mode); + return 0; + } else { + return -1; + } - ctx->input_callback = new decklink_input_callback(avctx); - ctx->dli->SetCallback(ctx->input_callback); - return ctx->dli->StartStreams(); } extern "C" { @@ -854,6 +931,7 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) ctx->audio_pts_source = cctx->audio_pts_source; ctx->video_pts_source = cctx->video_pts_source; ctx->draw_bars = cctx->draw_bars; + ctx->audio_depth = cctx->audio_depth; cctx->ctx = ctx; /* Check audio channel option for valid values: 2, 8 or 16 */ @@ -867,6 +945,16 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) return AVERROR(EINVAL); } + /* Check audio bit depth option for valid values: 16 or 32 */ + switch (cctx->audio_depth) { + case 16: + case 32: + break; + default: + av_log(avctx, AV_LOG_ERROR, "Value for audio bit depth option must be either 16 or 32\n"); + return AVERROR(EINVAL); + } + /* List available devices. */ if (ctx->list_devices) { ff_decklink_list_devices_legacy(avctx, 1, 0); @@ -878,7 +966,7 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) cctx->raw_format = MKBETAG('v','2','1','0'); } - strcpy (fname, avctx->filename); + av_strlcpy(fname, avctx->url, sizeof(fname)); tmp=strchr (fname, '@'); if (tmp != NULL) { av_log(avctx, AV_LOG_WARNING, "The @mode syntax is deprecated and will be removed. Please use the -format_code option.\n"); @@ -893,7 +981,7 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) /* Get input device. */ if (ctx->dl->QueryInterface(IID_IDeckLinkInput, (void **) &ctx->dli) != S_OK) { av_log(avctx, AV_LOG_ERROR, "Could not open input device from '%s'\n", - avctx->filename); + avctx->url); ret = AVERROR(EIO); goto error; } @@ -905,13 +993,28 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) goto error; } - if (mode_num > 0 || cctx->format_code) { - if (ff_decklink_set_format(avctx, DIRECTION_IN, mode_num) < 0) { - av_log(avctx, AV_LOG_ERROR, "Could not set mode number %d or format code %s for %s\n", - mode_num, (cctx->format_code) ? cctx->format_code : "(unset)", fname); + if (ff_decklink_set_configs(avctx, DIRECTION_IN) < 0) { + av_log(avctx, AV_LOG_ERROR, "Could not set input configuration\n"); + ret = AVERROR(EIO); + goto error; + } + + ctx->input_callback = new decklink_input_callback(avctx); + ctx->dli->SetCallback(ctx->input_callback); + + if (mode_num == 0 && !cctx->format_code) { + if (decklink_autodetect(cctx) < 0) { + av_log(avctx, AV_LOG_ERROR, "Cannot Autodetect input stream or No signal\n"); ret = AVERROR(EIO); goto error; } + av_log(avctx, AV_LOG_INFO, "Autodetected the input mode\n"); + } + if (ff_decklink_set_format(avctx, DIRECTION_IN, mode_num) < 0) { + av_log(avctx, AV_LOG_ERROR, "Could not set mode number %d or format code %s for %s\n", + mode_num, (cctx->format_code) ? cctx->format_code : "(unset)", fname); + ret = AVERROR(EIO); + goto error; } #if !CONFIG_LIBZVBI @@ -930,7 +1033,7 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) goto error; } st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; - st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE; + st->codecpar->codec_id = cctx->audio_depth == 32 ? AV_CODEC_ID_PCM_S32LE : AV_CODEC_ID_PCM_S16LE; st->codecpar->sample_rate = bmdAudioSampleRate48kHz; st->codecpar->channels = cctx->audio_channels; avpriv_set_pts_info(st, 64, 1, 1000000); /* 64 bits pts in us */ @@ -948,7 +1051,7 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) st->time_base.den = ctx->bmd_tb_den; st->time_base.num = ctx->bmd_tb_num; - av_stream_set_r_frame_rate(st, av_make_q(st->time_base.den, st->time_base.num)); + st->r_frame_rate = av_make_q(st->time_base.den, st->time_base.num); switch((BMDPixelFormat)cctx->raw_format) { case bmdFormat8BitYUV: @@ -965,7 +1068,7 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) break; case bmdFormat8BitARGB: st->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO; - st->codecpar->codec_tag = avcodec_pix_fmt_to_codec_tag((enum AVPixelFormat)st->codecpar->format);; + st->codecpar->codec_tag = avcodec_pix_fmt_to_codec_tag((enum AVPixelFormat)st->codecpar->format); st->codecpar->format = AV_PIX_FMT_0RGB; st->codecpar->bit_rate = av_rescale(ctx->bmd_width * ctx->bmd_height * 32, st->time_base.den, st->time_base.num); break; @@ -1021,7 +1124,7 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) } av_log(avctx, AV_LOG_VERBOSE, "Using %d input audio channels\n", ctx->audio_st->codecpar->channels); - result = ctx->dli->EnableAudioInput(bmdAudioSampleRate48kHz, bmdAudioSampleType16bitInteger, ctx->audio_st->codecpar->channels); + result = ctx->dli->EnableAudioInput(bmdAudioSampleRate48kHz, cctx->audio_depth == 32 ? bmdAudioSampleType32bitInteger : bmdAudioSampleType16bitInteger, ctx->audio_st->codecpar->channels); if (result != S_OK) { av_log(avctx, AV_LOG_ERROR, "Cannot enable audio input\n"); @@ -1041,7 +1144,7 @@ av_cold int ff_decklink_read_header(AVFormatContext *avctx) avpacket_queue_init (avctx, &ctx->queue); - if (decklink_start_input (avctx) != S_OK) { + if (ctx->dli->StartStreams() != S_OK) { av_log(avctx, AV_LOG_ERROR, "Cannot start input stream\n"); ret = AVERROR(EIO); goto error; diff --git a/libavdevice/decklink_dec_c.c b/libavdevice/decklink_dec_c.c index 1127d23adaafd..47018dc681a96 100644 --- a/libavdevice/decklink_dec_c.c +++ b/libavdevice/decklink_dec_c.c @@ -64,14 +64,17 @@ static const AVOption options[] = { { "analog_xlr", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 4}, 0, 0, DEC, "audio_input"}, { "analog_rca", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 5}, 0, 0, DEC, "audio_input"}, { "microphone", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = 6}, 0, 0, DEC, "audio_input"}, - { "audio_pts", "audio pts source", OFFSET(audio_pts_source), AV_OPT_TYPE_INT, { .i64 = PTS_SRC_AUDIO }, 1, 4, DEC, "pts_source"}, - { "video_pts", "video pts source", OFFSET(video_pts_source), AV_OPT_TYPE_INT, { .i64 = PTS_SRC_VIDEO }, 1, 4, DEC, "pts_source"}, + { "audio_pts", "audio pts source", OFFSET(audio_pts_source), AV_OPT_TYPE_INT, { .i64 = PTS_SRC_AUDIO }, 1, PTS_SRC_NB-1, DEC, "pts_source"}, + { "video_pts", "video pts source", OFFSET(video_pts_source), AV_OPT_TYPE_INT, { .i64 = PTS_SRC_VIDEO }, 1, PTS_SRC_NB-1, DEC, "pts_source"}, { "audio", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_AUDIO }, 0, 0, DEC, "pts_source"}, { "video", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_VIDEO }, 0, 0, DEC, "pts_source"}, { "reference", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_REFERENCE}, 0, 0, DEC, "pts_source"}, { "wallclock", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_WALLCLOCK}, 0, 0, DEC, "pts_source"}, + { "abs_wallclock", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PTS_SRC_ABS_WALLCLOCK}, 0, 0, DEC, "pts_source"}, { "draw_bars", "draw bars on signal loss" , OFFSET(draw_bars), AV_OPT_TYPE_BOOL, { .i64 = 1}, 0, 1, DEC }, { "queue_size", "input queue buffer size", OFFSET(queue_size), AV_OPT_TYPE_INT64, { .i64 = (1024 * 1024 * 1024)}, 0, INT64_MAX, DEC }, + { "audio_depth", "audio bitdepth (16 or 32)", OFFSET(audio_depth), AV_OPT_TYPE_INT, { .i64 = 16}, 16, 32, DEC }, + { "decklink_copyts", "copy timestamps, do not remove the initial offset", OFFSET(copyts), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, DEC }, { NULL }, }; diff --git a/libavdevice/decklink_enc.cpp b/libavdevice/decklink_enc.cpp index 81df563b3bf66..28ab928cd50cd 100644 --- a/libavdevice/decklink_enc.cpp +++ b/libavdevice/decklink_enc.cpp @@ -162,6 +162,10 @@ static int decklink_setup_video(AVFormatContext *avctx, AVStream *st) return -1; } + if (ff_decklink_set_configs(avctx, DIRECTION_OUT) < 0) { + av_log(avctx, AV_LOG_ERROR, "Could not set output configuration\n"); + return -1; + } if (ff_decklink_set_format(avctx, c->width, c->height, st->time_base.num, st->time_base.den, c->field_order)) { av_log(avctx, AV_LOG_ERROR, "Unsupported video size, framerate or field order!" @@ -317,7 +321,7 @@ static int decklink_write_video_packet(AVFormatContext *avctx, AVPacket *pkt) pthread_mutex_unlock(&ctx->mutex); /* Schedule frame for playback. */ - hr = ctx->dlo->ScheduleVideoFrame((struct IDeckLinkVideoFrame *) frame, + hr = ctx->dlo->ScheduleVideoFrame((class IDeckLinkVideoFrame *) frame, pkt->pts * ctx->bmd_tb_num, ctx->bmd_tb_num, ctx->bmd_tb_den); /* Pass ownership to DeckLink, or release on failure */ @@ -396,14 +400,14 @@ av_cold int ff_decklink_write_header(AVFormatContext *avctx) return AVERROR_EXIT; } - ret = ff_decklink_init_device(avctx, avctx->filename); + ret = ff_decklink_init_device(avctx, avctx->url); if (ret < 0) return ret; /* Get output device. */ if (ctx->dl->QueryInterface(IID_IDeckLinkOutput, (void **) &ctx->dlo) != S_OK) { av_log(avctx, AV_LOG_ERROR, "Could not open output device from '%s'\n", - avctx->filename); + avctx->url); ret = AVERROR(EIO); goto error; } diff --git a/libavdevice/dshow.c b/libavdevice/dshow.c index f2453e6114477..de910c0994344 100644 --- a/libavdevice/dshow.c +++ b/libavdevice/dshow.c @@ -1033,7 +1033,7 @@ static int parse_device_name(AVFormatContext *avctx) { struct dshow_ctx *ctx = avctx->priv_data; char **device_name = ctx->device_name; - char *name = av_strdup(avctx->filename); + char *name = av_strdup(avctx->url); char *tmp = name; int ret = 1; char *type; diff --git a/libavdevice/fbdev_dec.c b/libavdevice/fbdev_dec.c index d9c75df2029b6..6a5181686812c 100644 --- a/libavdevice/fbdev_dec.c +++ b/libavdevice/fbdev_dec.c @@ -78,8 +78,8 @@ static av_cold int fbdev_read_header(AVFormatContext *avctx) if (avctx->flags & AVFMT_FLAG_NONBLOCK) flags |= O_NONBLOCK; - if (avctx->filename[0]) - device = avctx->filename; + if (avctx->url[0]) + device = avctx->url; else device = ff_fbdev_default_device(); diff --git a/libavdevice/fbdev_enc.c b/libavdevice/fbdev_enc.c index b4e5f849759ff..4191596825069 100644 --- a/libavdevice/fbdev_enc.c +++ b/libavdevice/fbdev_enc.c @@ -53,8 +53,8 @@ static av_cold int fbdev_write_header(AVFormatContext *h) return AVERROR(EINVAL); } - if (h->filename[0]) - device = h->filename; + if (h->url[0]) + device = h->url; else device = ff_fbdev_default_device(); diff --git a/libavdevice/gdigrab.c b/libavdevice/gdigrab.c index 87f5012034ce9..ab08c11788481 100644 --- a/libavdevice/gdigrab.c +++ b/libavdevice/gdigrab.c @@ -230,12 +230,14 @@ gdigrab_read_header(AVFormatContext *s1) HBITMAP hbmp = NULL; void *buffer = NULL; - const char *filename = s1->filename; + const char *filename = s1->url; const char *name = NULL; AVStream *st = NULL; int bpp; + int horzres; int vertres; + int desktophorzres; int desktopvertres; RECT virtual_rect; RECT clip_rect; @@ -279,11 +281,13 @@ gdigrab_read_header(AVFormatContext *s1) GetClientRect(hwnd, &virtual_rect); } else { /* desktop -- get the right height and width for scaling DPI */ + horzres = GetDeviceCaps(source_hdc, HORZRES); vertres = GetDeviceCaps(source_hdc, VERTRES); + desktophorzres = GetDeviceCaps(source_hdc, DESKTOPHORZRES); desktopvertres = GetDeviceCaps(source_hdc, DESKTOPVERTRES); virtual_rect.left = GetSystemMetrics(SM_XVIRTUALSCREEN); virtual_rect.top = GetSystemMetrics(SM_YVIRTUALSCREEN); - virtual_rect.right = (virtual_rect.left + GetSystemMetrics(SM_CXVIRTUALSCREEN)) * desktopvertres / vertres; + virtual_rect.right = (virtual_rect.left + GetSystemMetrics(SM_CXVIRTUALSCREEN)) * desktophorzres / horzres; virtual_rect.bottom = (virtual_rect.top + GetSystemMetrics(SM_CYVIRTUALSCREEN)) * desktopvertres / vertres; } @@ -447,7 +451,9 @@ static void paint_mouse_pointer(AVFormatContext *s1, struct gdigrab *gdigrab) POINT pos; RECT clip_rect = gdigrab->clip_rect; HWND hwnd = gdigrab->hwnd; + int horzres = GetDeviceCaps(gdigrab->source_hdc, HORZRES); int vertres = GetDeviceCaps(gdigrab->source_hdc, VERTRES); + int desktophorzres = GetDeviceCaps(gdigrab->source_hdc, DESKTOPHORZRES); int desktopvertres = GetDeviceCaps(gdigrab->source_hdc, DESKTOPVERTRES); info.hbmMask = NULL; info.hbmColor = NULL; @@ -483,7 +489,7 @@ static void paint_mouse_pointer(AVFormatContext *s1, struct gdigrab *gdigrab) } //that would keep the correct location of mouse with hidpi screens - pos.x = pos.x * desktopvertres / vertres; + pos.x = pos.x * desktophorzres / horzres; pos.y = pos.y * desktopvertres / vertres; av_log(s1, AV_LOG_DEBUG, "Cursor pos (%li,%li) -> (%li,%li)\n", diff --git a/libavdevice/iec61883.c b/libavdevice/iec61883.c index 721dca38eef99..dcf755392675a 100644 --- a/libavdevice/iec61883.c +++ b/libavdevice/iec61883.c @@ -118,7 +118,7 @@ static int iec61883_callback(unsigned char *data, int length, goto exit; } - packet->buf = av_malloc(length); + packet->buf = av_malloc(length + AV_INPUT_BUFFER_PADDING_SIZE); if (!packet->buf) { av_free(packet); ret = -1; @@ -127,6 +127,7 @@ static int iec61883_callback(unsigned char *data, int length, packet->len = length; memcpy(packet->buf, data, length); + memset(packet->buf + length, 0, AV_INPUT_BUFFER_PADDING_SIZE); if (dv->queue_first) { dv->queue_last->next = packet; @@ -200,13 +201,21 @@ static int iec61883_parse_queue_dv(struct iec61883_data *dv, AVPacket *pkt) size = avpriv_dv_produce_packet(dv->dv_demux, pkt, packet->buf, packet->len, -1); dv->queue_first = packet->next; + if (size < 0) + av_free(packet->buf); av_free(packet); dv->packets--; - if (size > 0) - return size; + if (size < 0) + return -1; - return -1; + if (av_packet_from_data(pkt, pkt->data, pkt->size) < 0) { + av_freep(&pkt->data); + av_packet_unref(pkt); + return -1; + } + + return size; } static int iec61883_parse_queue_hdv(struct iec61883_data *dv, AVPacket *pkt) @@ -259,14 +268,14 @@ static int iec61883_read_header(AVFormatContext *context) goto fail; } - inport = strtol(context->filename, &endptr, 10); - if (endptr != context->filename && *endptr == '\0') { + inport = strtol(context->url, &endptr, 10); + if (endptr != context->url && *endptr == '\0') { av_log(context, AV_LOG_INFO, "Selecting IEEE1394 port: %d\n", inport); j = inport; nb_ports = inport + 1; - } else if (strcmp(context->filename, "auto")) { + } else if (strcmp(context->url, "auto")) { av_log(context, AV_LOG_ERROR, "Invalid input \"%s\", you should specify " - "\"auto\" for auto-detection, or the port number.\n", context->filename); + "\"auto\" for auto-detection, or the port number.\n", context->url); goto fail; } @@ -454,6 +463,7 @@ static int iec61883_close(AVFormatContext *context) } else { iec61883_dv_fb_stop(dv->iec61883_dv); iec61883_dv_fb_close(dv->iec61883_dv); + av_freep(&dv->dv_demux); } while (dv->queue_first) { DVPacket *packet = dv->queue_first; diff --git a/libavdevice/jack.c b/libavdevice/jack.c index 076078ce6de7c..34f1c6de97350 100644 --- a/libavdevice/jack.c +++ b/libavdevice/jack.c @@ -94,13 +94,9 @@ static int process_callback(jack_nframes_t nframes, void *arg) /* Copy and interleave audio data from the JACK buffer into the packet */ for (i = 0; i < self->nports; i++) { - #if HAVE_JACK_PORT_GET_LATENCY_RANGE jack_latency_range_t range; jack_port_get_latency_range(self->ports[i], JackCaptureLatency, &range); latency += range.max; - #else - latency += jack_port_get_total_latency(self->client, self->ports[i]); - #endif buffer = jack_port_get_buffer(self->ports[i], self->buffer_size); for (j = 0; j < self->buffer_size; j++) pkt_data[j * self->nports + i] = buffer[j]; @@ -154,8 +150,8 @@ static int start_jack(AVFormatContext *context) jack_status_t status; int i, test; - /* Register as a JACK client, using the context filename as client name. */ - self->client = jack_client_open(context->filename, JackNullOption, &status); + /* Register as a JACK client, using the context url as client name. */ + self->client = jack_client_open(context->url, JackNullOption, &status); if (!self->client) { av_log(context, AV_LOG_ERROR, "Unable to register as a JACK client\n"); return AVERROR(EIO); @@ -178,7 +174,7 @@ static int start_jack(AVFormatContext *context) JackPortIsInput, 0); if (!self->ports[i]) { av_log(context, AV_LOG_ERROR, "Unable to register port %s:%s\n", - context->filename, str); + context->url, str); jack_client_close(self->client); return AVERROR(EIO); } diff --git a/libavdevice/kmsgrab.c b/libavdevice/kmsgrab.c index 6a6de09c3763b..d0de774871cb4 100644 --- a/libavdevice/kmsgrab.c +++ b/libavdevice/kmsgrab.c @@ -451,6 +451,7 @@ static const AVClass kmsgrab_class = { .item_name = av_default_item_name, .option = options, .version = LIBAVUTIL_VERSION_INT, + .category = AV_CLASS_CATEGORY_DEVICE_VIDEO_INPUT, }; AVInputFormat ff_kmsgrab_demuxer = { diff --git a/libavdevice/lavfi.c b/libavdevice/lavfi.c index ede391f4d6bb4..ca8f05f3f7236 100644 --- a/libavdevice/lavfi.c +++ b/libavdevice/lavfi.c @@ -38,7 +38,6 @@ #include "libavutil/parseutils.h" #include "libavutil/pixdesc.h" #include "libavfilter/avfilter.h" -#include "libavfilter/avfiltergraph.h" #include "libavfilter/buffersink.h" #include "libavformat/avio_internal.h" #include "libavformat/internal.h" @@ -121,7 +120,7 @@ av_cold static int lavfi_read_header(AVFormatContext *avctx) { LavfiContext *lavfi = avctx->priv_data; AVFilterInOut *input_links = NULL, *output_links = NULL, *inout; - AVFilter *buffersink, *abuffersink; + const AVFilter *buffersink, *abuffersink; int *pix_fmts = create_all_formats(AV_PIX_FMT_NB); enum AVMediaType type; int ret = 0, i, n; @@ -131,8 +130,6 @@ av_cold static int lavfi_read_header(AVFormatContext *avctx) if (!pix_fmts) FAIL(AVERROR(ENOMEM)); - avfilter_register_all(); - buffersink = avfilter_get_by_name("buffersink"); abuffersink = avfilter_get_by_name("abuffersink"); @@ -167,7 +164,7 @@ av_cold static int lavfi_read_header(AVFormatContext *avctx) } if (!lavfi->graph_str) - lavfi->graph_str = av_strdup(avctx->filename); + lavfi->graph_str = av_strdup(avctx->url); /* parse the graph, create a stream for each open output */ if (!(lavfi->graph = avfilter_graph_alloc())) diff --git a/libavdevice/libcdio.c b/libavdevice/libcdio.c index f6d4fce25629f..a4c9f52337373 100644 --- a/libavdevice/libcdio.c +++ b/libavdevice/libcdio.c @@ -60,9 +60,9 @@ static av_cold int read_header(AVFormatContext *ctx) if (!(st = avformat_new_stream(ctx, NULL))) return AVERROR(ENOMEM); - s->drive = cdio_cddap_identify(ctx->filename, CDDA_MESSAGE_LOGIT, &err); + s->drive = cdio_cddap_identify(ctx->url, CDDA_MESSAGE_LOGIT, &err); if (!s->drive) { - av_log(ctx, AV_LOG_ERROR, "Could not open drive %s.\n", ctx->filename); + av_log(ctx, AV_LOG_ERROR, "Could not open drive %s.\n", ctx->url); return AVERROR(EINVAL); } if (err) { @@ -70,7 +70,7 @@ static av_cold int read_header(AVFormatContext *ctx) free(err); } if ((ret = cdio_cddap_open(s->drive)) < 0 || !s->drive->opened) { - av_log(ctx, AV_LOG_ERROR, "Could not open disk in drive %s.\n", ctx->filename); + av_log(ctx, AV_LOG_ERROR, "Could not open disk in drive %s.\n", ctx->url); return AVERROR(EINVAL); } diff --git a/libavdevice/libndi_newtek_dec.c b/libavdevice/libndi_newtek_dec.c index 8cbcd9a1d2058..4fb719770e57c 100644 --- a/libavdevice/libndi_newtek_dec.c +++ b/libavdevice/libndi_newtek_dec.c @@ -149,7 +149,7 @@ static int ndi_read_header(AVFormatContext *avctx) } /* Find available sources. */ - ret = ndi_find_sources(avctx, avctx->filename, &recv_create_desc.source_to_connect_to); + ret = ndi_find_sources(avctx, avctx->url, &recv_create_desc.source_to_connect_to); if (ctx->find_sources) { return AVERROR_EXIT; } @@ -189,7 +189,7 @@ static int ndi_create_video_stream(AVFormatContext *avctx, NDIlib_video_frame_t } st->time_base = NDI_TIME_BASE_Q; - av_stream_set_r_frame_rate(st, av_make_q(v->frame_rate_N, v->frame_rate_D)); + st->r_frame_rate = av_make_q(v->frame_rate_N, v->frame_rate_D); tmp = av_mul_q(av_d2q(v->picture_aspect_ratio, INT_MAX), (AVRational){v->yres, v->xres}); av_reduce(&st->sample_aspect_ratio.num, &st->sample_aspect_ratio.den, tmp.num, tmp.den, 1000); diff --git a/libavdevice/libndi_newtek_enc.c b/libavdevice/libndi_newtek_enc.c index 6ca6f41b734ed..f3603f5a3ad6e 100644 --- a/libavdevice/libndi_newtek_enc.c +++ b/libavdevice/libndi_newtek_enc.c @@ -233,7 +233,7 @@ static int ndi_write_header(AVFormatContext *avctx) int ret = 0; unsigned int n; struct NDIContext *ctx = avctx->priv_data; - const NDIlib_send_create_t ndi_send_desc = { .p_ndi_name = avctx->filename, + const NDIlib_send_create_t ndi_send_desc = { .p_ndi_name = avctx->url, .p_groups = NULL, .clock_video = ctx->clock_video, .clock_audio = ctx->clock_audio }; if (!NDIlib_initialize()) { @@ -260,7 +260,7 @@ static int ndi_write_header(AVFormatContext *avctx) ctx->ndi_send = NDIlib_send_create(&ndi_send_desc); if (!ctx->ndi_send) { - av_log(avctx, AV_LOG_ERROR, "Failed to create NDI output %s\n", avctx->filename); + av_log(avctx, AV_LOG_ERROR, "Failed to create NDI output %s\n", avctx->url); ret = AVERROR_EXTERNAL; } diff --git a/libavdevice/openal-dec.c b/libavdevice/openal-dec.c index 6eb0efe38f1e3..c19048e15d34a 100644 --- a/libavdevice/openal-dec.c +++ b/libavdevice/openal-dec.c @@ -139,7 +139,7 @@ static int read_header(AVFormatContext *ctx) /* Open device for capture */ ad->device = - alcCaptureOpenDevice(ctx->filename[0] ? ctx->filename : NULL, + alcCaptureOpenDevice(ctx->url[0] ? ctx->url : NULL, ad->sample_rate, ad->sample_format, ad->sample_rate); /* Maximum 1 second of sample data to be read at once */ diff --git a/libavdevice/opengl_enc.c b/libavdevice/opengl_enc.c index bb6787c6f13ba..54c7e610bd52b 100644 --- a/libavdevice/opengl_enc.c +++ b/libavdevice/opengl_enc.c @@ -1070,7 +1070,7 @@ static av_cold int opengl_write_header(AVFormatContext *h) opengl->window_height = opengl->height; if (!opengl->window_title && !opengl->no_window) - opengl->window_title = av_strdup(h->filename); + opengl->window_title = av_strdup(h->url); if ((ret = opengl_create_window(h))) goto fail; diff --git a/libavdevice/oss.c b/libavdevice/oss.c index d74112825bf30..d92cde3313153 100644 --- a/libavdevice/oss.c +++ b/libavdevice/oss.c @@ -23,17 +23,12 @@ #include -#if HAVE_SOUNDCARD_H -#include -#else -#include -#endif - #if HAVE_UNISTD_H #include #endif #include #include +#include #include "libavutil/log.h" diff --git a/libavdevice/oss_dec.c b/libavdevice/oss_dec.c index 9f748f2bc3b17..d0dc327dc6273 100644 --- a/libavdevice/oss_dec.c +++ b/libavdevice/oss_dec.c @@ -23,17 +23,12 @@ #include -#if HAVE_SOUNDCARD_H -#include -#else -#include -#endif - #if HAVE_UNISTD_H #include #endif #include #include +#include #include "libavutil/internal.h" #include "libavutil/opt.h" @@ -57,7 +52,7 @@ static int audio_read_header(AVFormatContext *s1) return AVERROR(ENOMEM); } - ret = ff_oss_audio_open(s1, 0, s1->filename); + ret = ff_oss_audio_open(s1, 0, s1->url); if (ret < 0) { return AVERROR(EIO); } diff --git a/libavdevice/oss_enc.c b/libavdevice/oss_enc.c index 2268b4cfe4254..e3172afaa47b9 100644 --- a/libavdevice/oss_enc.c +++ b/libavdevice/oss_enc.c @@ -21,17 +21,12 @@ #include "config.h" -#if HAVE_SOUNDCARD_H -#include -#else -#include -#endif - #if HAVE_UNISTD_H #include #endif #include #include +#include #include "libavutil/internal.h" @@ -51,7 +46,7 @@ static int audio_write_header(AVFormatContext *s1) st = s1->streams[0]; s->sample_rate = st->codecpar->sample_rate; s->channels = st->codecpar->channels; - ret = ff_oss_audio_open(s1, 1, s1->filename); + ret = ff_oss_audio_open(s1, 1, s1->url); if (ret < 0) { return AVERROR(EIO); } else { diff --git a/libavdevice/pulse_audio_dec.c b/libavdevice/pulse_audio_dec.c index 95a1d6ecfa620..5977fb7e9e5f6 100644 --- a/libavdevice/pulse_audio_dec.c +++ b/libavdevice/pulse_audio_dec.c @@ -158,8 +158,8 @@ static av_cold int pulse_read_header(AVFormatContext *s) attr.fragsize = pd->fragment_size; - if (s->filename[0] != '\0' && strcmp(s->filename, "default")) - device = s->filename; + if (s->url[0] != '\0' && strcmp(s->url, "default")) + device = s->url; if (!(pd->mainloop = pa_threaded_mainloop_new())) { pulse_close(s); diff --git a/libavdevice/pulse_audio_enc.c b/libavdevice/pulse_audio_enc.c index 0efcf0fe7e5c6..d430b77272647 100644 --- a/libavdevice/pulse_audio_enc.c +++ b/libavdevice/pulse_audio_enc.c @@ -459,8 +459,8 @@ static av_cold int pulse_write_header(AVFormatContext *h) st = h->streams[0]; if (!stream_name) { - if (h->filename[0]) - stream_name = h->filename; + if (h->url[0]) + stream_name = h->url; else stream_name = "Playback"; } diff --git a/libavdevice/sdl2.c b/libavdevice/sdl2.c index 5d9e91ec2139a..48ed977bebd35 100644 --- a/libavdevice/sdl2.c +++ b/libavdevice/sdl2.c @@ -165,7 +165,7 @@ static int sdl2_write_header(AVFormatContext *s) int flags = 0; if (!sdl->window_title) - sdl->window_title = av_strdup(s->filename); + sdl->window_title = av_strdup(s->url); if (SDL_WasInit(SDL_INIT_VIDEO)) { av_log(s, AV_LOG_WARNING, diff --git a/libavdevice/sndio_dec.c b/libavdevice/sndio_dec.c index 2d13232bf17a6..ebb485a2c7b78 100644 --- a/libavdevice/sndio_dec.c +++ b/libavdevice/sndio_dec.c @@ -41,7 +41,7 @@ static av_cold int audio_read_header(AVFormatContext *s1) if (!st) return AVERROR(ENOMEM); - ret = ff_sndio_open(s1, 0, s1->filename); + ret = ff_sndio_open(s1, 0, s1->url); if (ret < 0) return ret; diff --git a/libavdevice/sndio_enc.c b/libavdevice/sndio_enc.c index 47f500d71e515..f6dd2901089c2 100644 --- a/libavdevice/sndio_enc.c +++ b/libavdevice/sndio_enc.c @@ -38,7 +38,7 @@ static av_cold int audio_write_header(AVFormatContext *s1) s->sample_rate = st->codecpar->sample_rate; s->channels = st->codecpar->channels; - ret = ff_sndio_open(s1, 1, s1->filename); + ret = ff_sndio_open(s1, 1, s1->url); return ret; } diff --git a/libavdevice/v4l2.c b/libavdevice/v4l2.c index f087badf5ca74..10a0ff0dd611c 100644 --- a/libavdevice/v4l2.c +++ b/libavdevice/v4l2.c @@ -106,7 +106,7 @@ struct buff_data { int index; }; -static int device_open(AVFormatContext *ctx) +static int device_open(AVFormatContext *ctx, const char* device_path) { struct video_data *s = ctx->priv_data; struct v4l2_capability cap; @@ -147,11 +147,11 @@ static int device_open(AVFormatContext *ctx) flags |= O_NONBLOCK; } - fd = v4l2_open(ctx->filename, flags, 0); + fd = v4l2_open(device_path, flags, 0); if (fd < 0) { err = AVERROR(errno); av_log(ctx, AV_LOG_ERROR, "Cannot open video device %s: %s\n", - ctx->filename, av_err2str(err)); + device_path, av_err2str(err)); return err; } @@ -840,7 +840,7 @@ static int v4l2_read_header(AVFormatContext *ctx) v4l2_log_file = fopen("/dev/null", "w"); #endif - s->fd = device_open(ctx); + s->fd = device_open(ctx, ctx->url); if (s->fd < 0) return s->fd; @@ -1042,11 +1042,13 @@ static int v4l2_get_device_list(AVFormatContext *ctx, AVDeviceInfoList *device_l return ret; } while ((entry = readdir(dir))) { + char device_name[256]; + if (!v4l2_is_v4l_dev(entry->d_name)) continue; - snprintf(ctx->filename, sizeof(ctx->filename), "/dev/%s", entry->d_name); - if ((s->fd = device_open(ctx)) < 0) + snprintf(device_name, sizeof(device_name), "/dev/%s", entry->d_name); + if ((s->fd = device_open(ctx, device_name)) < 0) continue; if (v4l2_ioctl(s->fd, VIDIOC_QUERYCAP, &cap) < 0) { @@ -1060,7 +1062,7 @@ static int v4l2_get_device_list(AVFormatContext *ctx, AVDeviceInfoList *device_l ret = AVERROR(ENOMEM); goto fail; } - device->device_name = av_strdup(ctx->filename); + device->device_name = av_strdup(device_name); device->device_description = av_strdup(cap.card); if (!device->device_name || !device->device_description) { ret = AVERROR(ENOMEM); diff --git a/libavdevice/v4l2enc.c b/libavdevice/v4l2enc.c index faf6e07f86796..85200d0a36314 100644 --- a/libavdevice/v4l2enc.c +++ b/libavdevice/v4l2enc.c @@ -39,10 +39,10 @@ static av_cold int write_header(AVFormatContext *s1) if (s1->flags & AVFMT_FLAG_NONBLOCK) flags |= O_NONBLOCK; - s->fd = open(s1->filename, flags); + s->fd = open(s1->url, flags); if (s->fd < 0) { res = AVERROR(errno); - av_log(s1, AV_LOG_ERROR, "Unable to open V4L2 device '%s'\n", s1->filename); + av_log(s1, AV_LOG_ERROR, "Unable to open V4L2 device '%s'\n", s1->url); return res; } diff --git a/libavdevice/version.h b/libavdevice/version.h index 9d900877af962..dbfbfd069a53c 100644 --- a/libavdevice/version.h +++ b/libavdevice/version.h @@ -27,8 +27,8 @@ #include "libavutil/version.h" -#define LIBAVDEVICE_VERSION_MAJOR 57 -#define LIBAVDEVICE_VERSION_MINOR 10 +#define LIBAVDEVICE_VERSION_MAJOR 58 +#define LIBAVDEVICE_VERSION_MINOR 3 #define LIBAVDEVICE_VERSION_MICRO 100 #define LIBAVDEVICE_VERSION_INT AV_VERSION_INT(LIBAVDEVICE_VERSION_MAJOR, \ diff --git a/libavdevice/vfwcap.c b/libavdevice/vfwcap.c index f03d38ac2629c..6a923d9957802 100644 --- a/libavdevice/vfwcap.c +++ b/libavdevice/vfwcap.c @@ -256,7 +256,7 @@ static int vfw_read_header(AVFormatContext *s) int ret; AVRational framerate_q; - if (!strcmp(s->filename, "list")) { + if (!strcmp(s->url, "list")) { for (devnum = 0; devnum <= 9; devnum++) { char driver_name[256]; char driver_ver[256]; @@ -279,7 +279,7 @@ static int vfw_read_header(AVFormatContext *s) } /* If atoi fails, devnum==0 and the default device is used */ - devnum = atoi(s->filename); + devnum = atoi(s->url); ret = SendMessage(ctx->hwnd, WM_CAP_DRIVER_CONNECT, devnum, 0); if(!ret) { diff --git a/libavdevice/xcbgrab.c b/libavdevice/xcbgrab.c index 1968fe02d4f45..6d142abd4fd3a 100644 --- a/libavdevice/xcbgrab.c +++ b/libavdevice/xcbgrab.c @@ -629,14 +629,14 @@ static av_cold int xcbgrab_read_header(AVFormatContext *s) XCBGrabContext *c = s->priv_data; int screen_num, ret; const xcb_setup_t *setup; - char *display_name = av_strdup(s->filename); + char *display_name = av_strdup(s->url); if (!display_name) return AVERROR(ENOMEM); - if (!sscanf(s->filename, "%[^+]+%d,%d", display_name, &c->x, &c->y)) { + if (!sscanf(s->url, "%[^+]+%d,%d", display_name, &c->x, &c->y)) { *display_name = 0; - sscanf(s->filename, "+%d,%d", &c->x, &c->y); + sscanf(s->url, "+%d,%d", &c->x, &c->y); } c->conn = xcb_connect(display_name[0] ? display_name : NULL, &screen_num); @@ -644,7 +644,7 @@ static av_cold int xcbgrab_read_header(AVFormatContext *s) if ((ret = xcb_connection_has_error(c->conn))) { av_log(s, AV_LOG_ERROR, "Cannot open display %s, error %d.\n", - s->filename[0] ? s->filename : "default", ret); + s->url[0] ? s->url : "default", ret); return AVERROR(EIO); } diff --git a/libavdevice/xv.c b/libavdevice/xv.c index 185de7569e10a..c3ed2e48bd25c 100644 --- a/libavdevice/xv.c +++ b/libavdevice/xv.c @@ -151,7 +151,7 @@ static int xv_write_header(AVFormatContext *s) xv->window_width, xv->window_height, 0, 0, 0); if (!xv->window_title) { - if (!(xv->window_title = av_strdup(s->filename))) { + if (!(xv->window_title = av_strdup(s->url))) { ret = AVERROR(ENOMEM); goto fail; } diff --git a/libavfilter/.gitignore b/libavfilter/.gitignore new file mode 100644 index 0000000000000..26bddebc933d8 --- /dev/null +++ b/libavfilter/.gitignore @@ -0,0 +1 @@ +/filter_list.c diff --git a/libavfilter/Makefile b/libavfilter/Makefile index d2f0495f37114..3a9fb02556440 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -2,7 +2,6 @@ NAME = avfilter DESC = FFmpeg audio/video filtering library HEADERS = avfilter.h \ - avfiltergraph.h \ buffersink.h \ buffersrc.h \ version.h \ @@ -20,15 +19,18 @@ OBJS = allfilters.o \ framequeue.o \ graphdump.o \ graphparser.o \ - opencl_allkernels.o \ transform.o \ video.o \ OBJS-$(HAVE_THREADS) += pthread.o +# subsystems +OBJS-$(CONFIG_QSVVPP) += qsvvpp.o + # audio filters OBJS-$(CONFIG_ABENCH_FILTER) += f_bench.o OBJS-$(CONFIG_ACOMPRESSOR_FILTER) += af_sidechaincompress.o +OBJS-$(CONFIG_ACONTRAST_FILTER) += af_acontrast.o OBJS-$(CONFIG_ACOPY_FILTER) += af_acopy.o OBJS-$(CONFIG_ACROSSFADE_FILTER) += af_afade.o OBJS-$(CONFIG_ACRUSHER_FILTER) += af_acrusher.o @@ -41,6 +43,7 @@ OBJS-$(CONFIG_AFFTFILT_FILTER) += af_afftfilt.o OBJS-$(CONFIG_AFIR_FILTER) += af_afir.o OBJS-$(CONFIG_AFORMAT_FILTER) += af_aformat.o OBJS-$(CONFIG_AGATE_FILTER) += af_agate.o +OBJS-$(CONFIG_AIIR_FILTER) += af_aiir.o OBJS-$(CONFIG_AINTERLEAVE_FILTER) += f_interleave.o OBJS-$(CONFIG_ALIMITER_FILTER) += af_alimiter.o OBJS-$(CONFIG_ALLPASS_FILTER) += af_biquads.o @@ -84,6 +87,7 @@ OBJS-$(CONFIG_COMPENSATIONDELAY_FILTER) += af_compensationdelay.o OBJS-$(CONFIG_CROSSFEED_FILTER) += af_crossfeed.o OBJS-$(CONFIG_CRYSTALIZER_FILTER) += af_crystalizer.o OBJS-$(CONFIG_DCSHIFT_FILTER) += af_dcshift.o +OBJS-$(CONFIG_DRMETER_FILTER) += af_drmeter.o OBJS-$(CONFIG_DYNAUDNORM_FILTER) += af_dynaudnorm.o OBJS-$(CONFIG_EARWAX_FILTER) += af_earwax.o OBJS-$(CONFIG_EBUR128_FILTER) += f_ebur128.o @@ -99,6 +103,8 @@ OBJS-$(CONFIG_JOIN_FILTER) += af_join.o OBJS-$(CONFIG_LADSPA_FILTER) += af_ladspa.o OBJS-$(CONFIG_LOUDNORM_FILTER) += af_loudnorm.o ebur128.o OBJS-$(CONFIG_LOWPASS_FILTER) += af_biquads.o +OBJS-$(CONFIG_LV2_FILTER) += af_lv2.o +OBJS-$(CONFIG_MCOMPAND_FILTER) += af_mcompand.o OBJS-$(CONFIG_PAN_FILTER) += af_pan.o OBJS-$(CONFIG_REPLAYGAIN_FILTER) += af_replaygain.o OBJS-$(CONFIG_RESAMPLE_FILTER) += af_resample.o @@ -122,6 +128,7 @@ OBJS-$(CONFIG_AEVALSRC_FILTER) += aeval.o OBJS-$(CONFIG_ANOISESRC_FILTER) += asrc_anoisesrc.o OBJS-$(CONFIG_ANULLSRC_FILTER) += asrc_anullsrc.o OBJS-$(CONFIG_FLITE_FILTER) += asrc_flite.o +OBJS-$(CONFIG_HILBERT_FILTER) += asrc_hilbert.o OBJS-$(CONFIG_SINE_FILTER) += asrc_sine.o OBJS-$(CONFIG_ANULLSINK_FILTER) += asink_anullsink.o @@ -132,6 +139,8 @@ OBJS-$(CONFIG_ALPHAMERGE_FILTER) += vf_alphamerge.o OBJS-$(CONFIG_ASS_FILTER) += vf_subtitles.o OBJS-$(CONFIG_ATADENOISE_FILTER) += vf_atadenoise.o OBJS-$(CONFIG_AVGBLUR_FILTER) += vf_avgblur.o +OBJS-$(CONFIG_AVGBLUR_OPENCL_FILTER) += vf_avgblur_opencl.o opencl.o \ + opencl/avgblur.o OBJS-$(CONFIG_BBOX_FILTER) += bbox.o vf_bbox.o OBJS-$(CONFIG_BENCH_FILTER) += f_bench.o OBJS-$(CONFIG_BITPLANENOISE_FILTER) += vf_bitplanenoise.o @@ -150,6 +159,8 @@ OBJS-$(CONFIG_COLORLEVELS_FILTER) += vf_colorlevels.o OBJS-$(CONFIG_COLORMATRIX_FILTER) += vf_colormatrix.o OBJS-$(CONFIG_COLORSPACE_FILTER) += vf_colorspace.o colorspacedsp.o OBJS-$(CONFIG_CONVOLUTION_FILTER) += vf_convolution.o +OBJS-$(CONFIG_CONVOLUTION_OPENCL_FILTER) += vf_convolution_opencl.o opencl.o \ + opencl/convolution.o OBJS-$(CONFIG_CONVOLVE_FILTER) += vf_convolve.o framesync.o OBJS-$(CONFIG_COPY_FILTER) += vf_copy.o OBJS-$(CONFIG_COREIMAGE_FILTER) += vf_coreimage.o @@ -161,12 +172,14 @@ OBJS-$(CONFIG_DATASCOPE_FILTER) += vf_datascope.o OBJS-$(CONFIG_DCTDNOIZ_FILTER) += vf_dctdnoiz.o OBJS-$(CONFIG_DEBAND_FILTER) += vf_deband.o OBJS-$(CONFIG_DECIMATE_FILTER) += vf_decimate.o +OBJS-$(CONFIG_DECONVOLVE_FILTER) += vf_convolve.o framesync.o OBJS-$(CONFIG_DEFLATE_FILTER) += vf_neighbor.o OBJS-$(CONFIG_DEFLICKER_FILTER) += vf_deflicker.o OBJS-$(CONFIG_DEINTERLACE_QSV_FILTER) += vf_deinterlace_qsv.o -OBJS-$(CONFIG_DEINTERLACE_VAAPI_FILTER) += vf_deinterlace_vaapi.o +OBJS-$(CONFIG_DEINTERLACE_VAAPI_FILTER) += vf_deinterlace_vaapi.o vaapi_vpp.o OBJS-$(CONFIG_DEJUDDER_FILTER) += vf_dejudder.o OBJS-$(CONFIG_DELOGO_FILTER) += vf_delogo.o +OBJS-$(CONFIG_DENOISE_VAAPI_FILTER) += vf_misc_vaapi.o vaapi_vpp.o OBJS-$(CONFIG_DESHAKE_FILTER) += vf_deshake.o OBJS-$(CONFIG_DESPILL_FILTER) += vf_despill.o OBJS-$(CONFIG_DETELECINE_FILTER) += vf_detelecine.o @@ -179,6 +192,7 @@ OBJS-$(CONFIG_DRAWGRID_FILTER) += vf_drawbox.o OBJS-$(CONFIG_DRAWTEXT_FILTER) += vf_drawtext.o OBJS-$(CONFIG_EDGEDETECT_FILTER) += vf_edgedetect.o OBJS-$(CONFIG_ELBG_FILTER) += vf_elbg.o +OBJS-$(CONFIG_ENTROPY_FILTER) += vf_entropy.o OBJS-$(CONFIG_EQ_FILTER) += vf_eq.o OBJS-$(CONFIG_EROSION_FILTER) += vf_neighbor.o OBJS-$(CONFIG_EXTRACTPLANES_FILTER) += vf_extractplanes.o @@ -188,6 +202,7 @@ OBJS-$(CONFIG_FIELD_FILTER) += vf_field.o OBJS-$(CONFIG_FIELDHINT_FILTER) += vf_fieldhint.o OBJS-$(CONFIG_FIELDMATCH_FILTER) += vf_fieldmatch.o OBJS-$(CONFIG_FIELDORDER_FILTER) += vf_fieldorder.o +OBJS-$(CONFIG_FILLBORDERS_FILTER) += vf_fillborders.o OBJS-$(CONFIG_FIND_RECT_FILTER) += vf_find_rect.o lavfutils.o OBJS-$(CONFIG_FLOODFILL_FILTER) += vf_floodfill.o OBJS-$(CONFIG_FORMAT_FILTER) += vf_format.o @@ -237,18 +252,22 @@ OBJS-$(CONFIG_MESTIMATE_FILTER) += vf_mestimate.o motion_estimation OBJS-$(CONFIG_METADATA_FILTER) += f_metadata.o OBJS-$(CONFIG_MIDEQUALIZER_FILTER) += vf_midequalizer.o framesync.o OBJS-$(CONFIG_MINTERPOLATE_FILTER) += vf_minterpolate.o motion_estimation.o +OBJS-$(CONFIG_MIX_FILTER) += vf_mix.o OBJS-$(CONFIG_MPDECIMATE_FILTER) += vf_mpdecimate.o OBJS-$(CONFIG_NEGATE_FILTER) += vf_lut.o OBJS-$(CONFIG_NLMEANS_FILTER) += vf_nlmeans.o OBJS-$(CONFIG_NNEDI_FILTER) += vf_nnedi.o OBJS-$(CONFIG_NOFORMAT_FILTER) += vf_format.o OBJS-$(CONFIG_NOISE_FILTER) += vf_noise.o +OBJS-$(CONFIG_NORMALIZE_FILTER) += vf_normalize.o OBJS-$(CONFIG_NULL_FILTER) += vf_null.o OBJS-$(CONFIG_OCR_FILTER) += vf_ocr.o OBJS-$(CONFIG_OCV_FILTER) += vf_libopencv.o -OBJS-$(CONFIG_OPENCL) += deshake_opencl.o unsharp_opencl.o OBJS-$(CONFIG_OSCILLOSCOPE_FILTER) += vf_datascope.o OBJS-$(CONFIG_OVERLAY_FILTER) += vf_overlay.o framesync.o +OBJS-$(CONFIG_OVERLAY_OPENCL_FILTER) += vf_overlay_opencl.o opencl.o \ + opencl/overlay.o framesync.o +OBJS-$(CONFIG_OVERLAY_QSV_FILTER) += vf_overlay_qsv.o OBJS-$(CONFIG_OWDENOISE_FILTER) += vf_owdenoise.o OBJS-$(CONFIG_PAD_FILTER) += vf_pad.o OBJS-$(CONFIG_PALETTEGEN_FILTER) += vf_palettegen.o @@ -262,6 +281,8 @@ OBJS-$(CONFIG_PP_FILTER) += vf_pp.o OBJS-$(CONFIG_PP7_FILTER) += vf_pp7.o OBJS-$(CONFIG_PREMULTIPLY_FILTER) += vf_premultiply.o framesync.o OBJS-$(CONFIG_PREWITT_FILTER) += vf_convolution.o +OBJS-$(CONFIG_PROCAMP_VAAPI_FILTER) += vf_procamp_vaapi.o vaapi_vpp.o +OBJS-$(CONFIG_PROGRAM_OPENCL_FILTER) += vf_program_opencl.o opencl.o framesync.o OBJS-$(CONFIG_PSEUDOCOLOR_FILTER) += vf_pseudocolor.o OBJS-$(CONFIG_PSNR_FILTER) += vf_psnr.o framesync.o OBJS-$(CONFIG_PULLUP_FILTER) += vf_pullup.o @@ -282,7 +303,7 @@ OBJS-$(CONFIG_SCALE_FILTER) += vf_scale.o scale.o OBJS-$(CONFIG_SCALE_CUDA_FILTER) += vf_scale_cuda.o vf_scale_cuda.ptx.o OBJS-$(CONFIG_SCALE_NPP_FILTER) += vf_scale_npp.o scale.o OBJS-$(CONFIG_SCALE_QSV_FILTER) += vf_scale_qsv.o -OBJS-$(CONFIG_SCALE_VAAPI_FILTER) += vf_scale_vaapi.o scale.o +OBJS-$(CONFIG_SCALE_VAAPI_FILTER) += vf_scale_vaapi.o scale.o vaapi_vpp.o OBJS-$(CONFIG_SCALE2REF_FILTER) += vf_scale.o scale.o OBJS-$(CONFIG_SELECT_FILTER) += f_select.o OBJS-$(CONFIG_SELECTIVECOLOR_FILTER) += vf_selectivecolor.o @@ -291,8 +312,10 @@ OBJS-$(CONFIG_SEPARATEFIELDS_FILTER) += vf_separatefields.o OBJS-$(CONFIG_SETDAR_FILTER) += vf_aspect.o OBJS-$(CONFIG_SETFIELD_FILTER) += vf_setfield.o OBJS-$(CONFIG_SETPTS_FILTER) += setpts.o +OBJS-$(CONFIG_SETRANGE_FILTER) += vf_setparams.o OBJS-$(CONFIG_SETSAR_FILTER) += vf_aspect.o OBJS-$(CONFIG_SETTB_FILTER) += settb.o +OBJS-$(CONFIG_SHARPNESS_VAAPI_FILTER) += vf_misc_vaapi.o vaapi_vpp.o OBJS-$(CONFIG_SHOWINFO_FILTER) += vf_showinfo.o OBJS-$(CONFIG_SHOWPALETTE_FILTER) += vf_showpalette.o OBJS-$(CONFIG_SHUFFLEFRAMES_FILTER) += vf_shuffleframes.o @@ -324,14 +347,18 @@ OBJS-$(CONFIG_TRANSPOSE_FILTER) += vf_transpose.o OBJS-$(CONFIG_TRIM_FILTER) += trim.o OBJS-$(CONFIG_UNPREMULTIPLY_FILTER) += vf_premultiply.o framesync.o OBJS-$(CONFIG_UNSHARP_FILTER) += vf_unsharp.o +OBJS-$(CONFIG_UNSHARP_OPENCL_FILTER) += vf_unsharp_opencl.o opencl.o \ + opencl/unsharp.o OBJS-$(CONFIG_USPP_FILTER) += vf_uspp.o OBJS-$(CONFIG_VAGUEDENOISER_FILTER) += vf_vaguedenoiser.o OBJS-$(CONFIG_VECTORSCOPE_FILTER) += vf_vectorscope.o OBJS-$(CONFIG_VFLIP_FILTER) += vf_vflip.o +OBJS-$(CONFIG_VFRDET_FILTER) += vf_vfrdet.o OBJS-$(CONFIG_VIDSTABDETECT_FILTER) += vidstabutils.o vf_vidstabdetect.o OBJS-$(CONFIG_VIDSTABTRANSFORM_FILTER) += vidstabutils.o vf_vidstabtransform.o OBJS-$(CONFIG_VIGNETTE_FILTER) += vf_vignette.o OBJS-$(CONFIG_VMAFMOTION_FILTER) += vf_vmafmotion.o framesync.o +OBJS-$(CONFIG_VPP_QSV_FILTER) += vf_vpp_qsv.o OBJS-$(CONFIG_VSTACK_FILTER) += vf_stack.o framesync.o OBJS-$(CONFIG_W3FDIF_FILTER) += vf_w3fdif.o OBJS-$(CONFIG_WAVEFORM_FILTER) += vf_waveform.o @@ -353,6 +380,7 @@ OBJS-$(CONFIG_LIFE_FILTER) += vsrc_life.o OBJS-$(CONFIG_MANDELBROT_FILTER) += vsrc_mandelbrot.o OBJS-$(CONFIG_MPTESTSRC_FILTER) += vsrc_mptestsrc.o OBJS-$(CONFIG_NULLSRC_FILTER) += vsrc_testsrc.o +OBJS-$(CONFIG_OPENCLSRC_FILTER) += vf_program_opencl.o opencl.o OBJS-$(CONFIG_RGBTESTSRC_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_SMPTEBARS_FILTER) += vsrc_testsrc.o OBJS-$(CONFIG_SMPTEHDBARS_FILTER) += vsrc_testsrc.o @@ -386,10 +414,13 @@ OBJS-$(CONFIG_MOVIE_FILTER) += src_movie.o SLIBOBJS-$(HAVE_GNU_WINDRES) += avfilterres.o SKIPHEADERS-$(CONFIG_LIBVIDSTAB) += vidstabutils.h -SKIPHEADERS-$(CONFIG_OPENCL) += opencl_internal.h deshake_opencl_kernel.h unsharp_opencl_kernel.h OBJS-$(CONFIG_SHARED) += log2_tab.o +SKIPHEADERS-$(CONFIG_QSVVPP) += qsvvpp.h +SKIPHEADERS-$(CONFIG_OPENCL) += opencl.h +SKIPHEADERS-$(CONFIG_VAAPI) += vaapi_vpp.h + TOOLS = graph2dot TESTPROGS = drawutils filtfmts formats integral @@ -397,3 +428,9 @@ TOOLS-$(CONFIG_LIBZMQ) += zmqsend clean:: $(RM) $(CLEANSUFFIXES:%=libavfilter/libmpcodecs/%) + +OPENCL = $(subst $(SRC_PATH)/,,$(wildcard $(SRC_PATH)/libavfilter/opencl/*.cl)) +.SECONDARY: $(OPENCL:.cl=.c) +libavfilter/opencl/%.c: TAG = OPENCL +libavfilter/opencl/%.c: $(SRC_PATH)/libavfilter/opencl/%.cl + $(M)$(SRC_PATH)/tools/cl2c $< $@ diff --git a/libavfilter/af_acontrast.c b/libavfilter/af_acontrast.c new file mode 100644 index 0000000000000..e08053146e345 --- /dev/null +++ b/libavfilter/af_acontrast.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2008 Rob Sykes + * Copyright (c) 2017 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/channel_layout.h" +#include "libavutil/opt.h" +#include "avfilter.h" +#include "audio.h" +#include "formats.h" + +typedef struct AudioContrastContext { + const AVClass *class; + float contrast; + void (*filter)(void **dst, const void **src, + int nb_samples, int channels, float contrast); +} AudioContrastContext; + +#define OFFSET(x) offsetof(AudioContrastContext, x) +#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption acontrast_options[] = { + { "contrast", "set contrast", OFFSET(contrast), AV_OPT_TYPE_FLOAT, {.dbl=33}, 0, 100, A }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(acontrast); + +static int query_formats(AVFilterContext *ctx) +{ + AVFilterFormats *formats = NULL; + AVFilterChannelLayouts *layouts = NULL; + static const enum AVSampleFormat sample_fmts[] = { + AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_DBLP, + AV_SAMPLE_FMT_NONE + }; + int ret; + + formats = ff_make_format_list(sample_fmts); + if (!formats) + return AVERROR(ENOMEM); + ret = ff_set_common_formats(ctx, formats); + if (ret < 0) + return ret; + + layouts = ff_all_channel_counts(); + if (!layouts) + return AVERROR(ENOMEM); + + ret = ff_set_common_channel_layouts(ctx, layouts); + if (ret < 0) + return ret; + + formats = ff_all_samplerates(); + return ff_set_common_samplerates(ctx, formats); +} + +static void filter_flt(void **d, const void **s, + int nb_samples, int channels, + float contrast) +{ + const float *src = s[0]; + float *dst = d[0]; + int n, c; + + for (n = 0; n < nb_samples; n++) { + for (c = 0; c < channels; c++) { + float d = src[c] * M_PI_2; + + dst[c] = sinf(d + contrast * sinf(d * 4)); + } + + dst += c; + src += c; + } +} + +static void filter_dbl(void **d, const void **s, + int nb_samples, int channels, + float contrast) +{ + const double *src = s[0]; + double *dst = d[0]; + int n, c; + + for (n = 0; n < nb_samples; n++) { + for (c = 0; c < channels; c++) { + double d = src[c] * M_PI_2; + + dst[c] = sin(d + contrast * sin(d * 4)); + } + + dst += c; + src += c; + } +} + +static void filter_fltp(void **d, const void **s, + int nb_samples, int channels, + float contrast) +{ + int n, c; + + for (c = 0; c < channels; c++) { + const float *src = s[c]; + float *dst = d[c]; + + for (n = 0; n < nb_samples; n++) { + float d = src[n] * M_PI_2; + + dst[n] = sinf(d + contrast * sinf(d * 4)); + } + } +} + +static void filter_dblp(void **d, const void **s, + int nb_samples, int channels, + float contrast) +{ + int n, c; + + for (c = 0; c < channels; c++) { + const double *src = s[c]; + double *dst = d[c]; + + for (n = 0; n < nb_samples; n++) { + double d = src[n] * M_PI_2; + + dst[n] = sin(d + contrast * sin(d * 4)); + } + } +} + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + AudioContrastContext *s = ctx->priv; + + switch (inlink->format) { + case AV_SAMPLE_FMT_FLT: s->filter = filter_flt; break; + case AV_SAMPLE_FMT_DBL: s->filter = filter_dbl; break; + case AV_SAMPLE_FMT_FLTP: s->filter = filter_fltp; break; + case AV_SAMPLE_FMT_DBLP: s->filter = filter_dblp; break; + } + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + AudioContrastContext *s = ctx->priv; + AVFrame *out; + + if (av_frame_is_writable(in)) { + out = in; + } else { + out = ff_get_audio_buffer(outlink, in->nb_samples); + if (!out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + av_frame_copy_props(out, in); + } + + s->filter((void **)out->extended_data, (const void **)in->extended_data, + in->nb_samples, in->channels, s->contrast / 750); + + if (out != in) + av_frame_free(&in); + + return ff_filter_frame(outlink, out); +} + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .filter_frame = filter_frame, + .config_props = config_input, + }, + { NULL } +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + }, + { NULL } +}; + +AVFilter ff_af_acontrast = { + .name = "acontrast", + .description = NULL_IF_CONFIG_SMALL("Simple audio dynamic range compression/expansion filter."), + .query_formats = query_formats, + .priv_size = sizeof(AudioContrastContext), + .priv_class = &acontrast_class, + .inputs = inputs, + .outputs = outputs, +}; diff --git a/libavfilter/af_adelay.c b/libavfilter/af_adelay.c index 983f089c21bcf..d6d81ba7d803f 100644 --- a/libavfilter/af_adelay.c +++ b/libavfilter/af_adelay.c @@ -192,7 +192,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) if (ctx->is_disabled || !s->delays) return ff_filter_frame(ctx->outputs[0], frame); - out_frame = ff_get_audio_buffer(inlink, frame->nb_samples); + out_frame = ff_get_audio_buffer(ctx->outputs[0], frame->nb_samples); if (!out_frame) { av_frame_free(&frame); return AVERROR(ENOMEM); diff --git a/libavfilter/af_aecho.c b/libavfilter/af_aecho.c index cfaea3de43057..b9ac18d3a462b 100644 --- a/libavfilter/af_aecho.c +++ b/libavfilter/af_aecho.c @@ -279,7 +279,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) if (av_frame_is_writable(frame)) { out_frame = frame; } else { - out_frame = ff_get_audio_buffer(inlink, frame->nb_samples); + out_frame = ff_get_audio_buffer(ctx->outputs[0], frame->nb_samples); if (!out_frame) { av_frame_free(&frame); return AVERROR(ENOMEM); diff --git a/libavfilter/af_aemphasis.c b/libavfilter/af_aemphasis.c index a5b8e3058a2e4..e1fa93affcaf4 100644 --- a/libavfilter/af_aemphasis.c +++ b/libavfilter/af_aemphasis.c @@ -96,7 +96,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_afade.c b/libavfilter/af_afade.c index 7ad124e887bd5..285b5b6557ec0 100644 --- a/libavfilter/af_afade.c +++ b/libavfilter/af_afade.c @@ -23,10 +23,14 @@ * fade audio filter */ +#define FF_INTERNAL_FIELDS 1 +#include "framequeue.h" + #include "libavutil/audio_fifo.h" #include "libavutil/opt.h" #include "audio.h" #include "avfilter.h" +#include "filters.h" #include "internal.h" typedef struct AudioFadeContext { @@ -39,6 +43,7 @@ typedef struct AudioFadeContext { int64_t start_time; int overlap; int cf0_eof; + int prev_size; int crossfade_is_over; AVAudioFifo *fifo[2]; int64_t pts; @@ -282,7 +287,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf) if (av_frame_is_writable(buf)) { out_buf = buf; } else { - out_buf = ff_get_audio_buffer(inlink, nb_samples); + out_buf = ff_get_audio_buffer(outlink, nb_samples); if (!out_buf) return AVERROR(ENOMEM); av_frame_copy_props(out_buf, buf); @@ -428,157 +433,127 @@ CROSSFADE(flt, float) CROSSFADE(s16, int16_t) CROSSFADE(s32, int32_t) -static int acrossfade_filter_frame(AVFilterLink *inlink, AVFrame *in) +static int activate(AVFilterContext *ctx) { - AVFilterContext *ctx = inlink->dst; AudioFadeContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; - AVFrame *out, *cf[2] = { NULL }; - int ret = 0, nb_samples; + AVFrame *in = NULL, *out, *cf[2] = { NULL }; + int ret = 0, nb_samples, status; + int64_t pts; if (s->crossfade_is_over) { + ret = ff_inlink_consume_frame(ctx->inputs[1], &in); + if (ret < 0) { + return ret; + } else if (ff_inlink_acknowledge_status(ctx->inputs[1], &status, &pts)) { + ff_outlink_set_status(ctx->outputs[0], status, pts); + return 0; + } else { + if (ff_outlink_frame_wanted(ctx->outputs[0]) && !in) { + ff_inlink_request_frame(ctx->inputs[1]); + return 0; + } + } in->pts = s->pts; s->pts += av_rescale_q(in->nb_samples, (AVRational){ 1, outlink->sample_rate }, outlink->time_base); return ff_filter_frame(outlink, in); - } else if (inlink == ctx->inputs[0]) { - av_audio_fifo_write(s->fifo[0], (void **)in->extended_data, in->nb_samples); + } - nb_samples = av_audio_fifo_size(s->fifo[0]) - s->nb_samples; + if (ff_framequeue_queued_samples(&ctx->inputs[0]->fifo) > s->nb_samples) { + nb_samples = ff_framequeue_queued_samples(&ctx->inputs[0]->fifo) - s->nb_samples; if (nb_samples > 0) { - out = ff_get_audio_buffer(outlink, nb_samples); - if (!out) { - ret = AVERROR(ENOMEM); - goto fail; - } - av_audio_fifo_read(s->fifo[0], (void **)out->extended_data, nb_samples); - out->pts = s->pts; - s->pts += av_rescale_q(nb_samples, - (AVRational){ 1, outlink->sample_rate }, outlink->time_base); - ret = ff_filter_frame(outlink, out); - } - } else if (av_audio_fifo_size(s->fifo[1]) < s->nb_samples) { - if (!s->overlap && av_audio_fifo_size(s->fifo[0]) > 0) { - nb_samples = av_audio_fifo_size(s->fifo[0]); - - cf[0] = ff_get_audio_buffer(outlink, nb_samples); - out = ff_get_audio_buffer(outlink, nb_samples); - if (!out || !cf[0]) { - ret = AVERROR(ENOMEM); - goto fail; + ret = ff_inlink_consume_samples(ctx->inputs[0], nb_samples, nb_samples, &in); + if (ret < 0) { + return ret; } - av_audio_fifo_read(s->fifo[0], (void **)cf[0]->extended_data, nb_samples); - - s->fade_samples(out->extended_data, cf[0]->extended_data, nb_samples, - outlink->channels, -1, nb_samples - 1, nb_samples, s->curve); - out->pts = s->pts; - s->pts += av_rescale_q(nb_samples, - (AVRational){ 1, outlink->sample_rate }, outlink->time_base); - ret = ff_filter_frame(outlink, out); - if (ret < 0) - goto fail; } - - av_audio_fifo_write(s->fifo[1], (void **)in->extended_data, in->nb_samples); - } else if (av_audio_fifo_size(s->fifo[1]) >= s->nb_samples) { - av_audio_fifo_write(s->fifo[1], (void **)in->extended_data, in->nb_samples); - + in->pts = s->pts; + s->pts += av_rescale_q(in->nb_samples, + (AVRational){ 1, outlink->sample_rate }, outlink->time_base); + return ff_filter_frame(outlink, in); + } else if (ff_framequeue_queued_samples(&ctx->inputs[1]->fifo) >= s->nb_samples) { if (s->overlap) { - cf[0] = ff_get_audio_buffer(outlink, s->nb_samples); - cf[1] = ff_get_audio_buffer(outlink, s->nb_samples); out = ff_get_audio_buffer(outlink, s->nb_samples); - if (!out || !cf[0] || !cf[1]) { + if (!out) + return AVERROR(ENOMEM); + + ret = ff_inlink_consume_samples(ctx->inputs[0], s->nb_samples, s->nb_samples, &cf[0]); + if (ret < 0) { av_frame_free(&out); - ret = AVERROR(ENOMEM); - goto fail; + return ret; } - av_audio_fifo_read(s->fifo[0], (void **)cf[0]->extended_data, s->nb_samples); - av_audio_fifo_read(s->fifo[1], (void **)cf[1]->extended_data, s->nb_samples); + ret = ff_inlink_consume_samples(ctx->inputs[1], s->nb_samples, s->nb_samples, &cf[1]); + if (ret < 0) { + av_frame_free(&out); + return ret; + } s->crossfade_samples(out->extended_data, cf[0]->extended_data, cf[1]->extended_data, - s->nb_samples, in->channels, + s->nb_samples, out->channels, s->curve, s->curve2); out->pts = s->pts; s->pts += av_rescale_q(s->nb_samples, (AVRational){ 1, outlink->sample_rate }, outlink->time_base); - ret = ff_filter_frame(outlink, out); - if (ret < 0) - goto fail; + s->crossfade_is_over = 1; + av_frame_free(&cf[0]); + av_frame_free(&cf[1]); + return ff_filter_frame(outlink, out); } else { out = ff_get_audio_buffer(outlink, s->nb_samples); - cf[1] = ff_get_audio_buffer(outlink, s->nb_samples); - if (!out || !cf[1]) { - ret = AVERROR(ENOMEM); + if (!out) + return AVERROR(ENOMEM); + + ret = ff_inlink_consume_samples(ctx->inputs[0], s->nb_samples, s->nb_samples, &cf[0]); + if (ret < 0) { av_frame_free(&out); - goto fail; + return ret; } - av_audio_fifo_read(s->fifo[1], (void **)cf[1]->extended_data, s->nb_samples); - - s->fade_samples(out->extended_data, cf[1]->extended_data, s->nb_samples, - outlink->channels, 1, 0, s->nb_samples, s->curve2); + s->fade_samples(out->extended_data, cf[0]->extended_data, s->nb_samples, + outlink->channels, -1, s->nb_samples - 1, s->nb_samples, s->curve); out->pts = s->pts; s->pts += av_rescale_q(s->nb_samples, (AVRational){ 1, outlink->sample_rate }, outlink->time_base); + av_frame_free(&cf[0]); ret = ff_filter_frame(outlink, out); if (ret < 0) - goto fail; - } + return ret; - nb_samples = av_audio_fifo_size(s->fifo[1]); - if (nb_samples > 0) { - out = ff_get_audio_buffer(outlink, nb_samples); - if (!out) { - ret = AVERROR(ENOMEM); - goto fail; + out = ff_get_audio_buffer(outlink, s->nb_samples); + if (!out) + return AVERROR(ENOMEM); + + ret = ff_inlink_consume_samples(ctx->inputs[1], s->nb_samples, s->nb_samples, &cf[1]); + if (ret < 0) { + av_frame_free(&out); + return ret; } - av_audio_fifo_read(s->fifo[1], (void **)out->extended_data, nb_samples); + s->fade_samples(out->extended_data, cf[1]->extended_data, s->nb_samples, + outlink->channels, 1, 0, s->nb_samples, s->curve2); out->pts = s->pts; - s->pts += av_rescale_q(nb_samples, + s->pts += av_rescale_q(s->nb_samples, (AVRational){ 1, outlink->sample_rate }, outlink->time_base); - ret = ff_filter_frame(outlink, out); + s->crossfade_is_over = 1; + av_frame_free(&cf[1]); + return ff_filter_frame(outlink, out); } - s->crossfade_is_over = 1; - } - -fail: - av_frame_free(&in); - av_frame_free(&cf[0]); - av_frame_free(&cf[1]); - return ret; -} - -static int acrossfade_request_frame(AVFilterLink *outlink) -{ - AVFilterContext *ctx = outlink->src; - AudioFadeContext *s = ctx->priv; - int ret = 0; - - if (!s->cf0_eof) { - AVFilterLink *cf0 = ctx->inputs[0]; - ret = ff_request_frame(cf0); - if (ret < 0 && ret != AVERROR_EOF) - return ret; - if (ret == AVERROR_EOF) { + } else if (ff_outlink_frame_wanted(ctx->outputs[0])) { + if (!s->cf0_eof && ctx->inputs[0]->status_in) { s->cf0_eof = 1; - ret = 0; } - } else { - AVFilterLink *cf1 = ctx->inputs[1]; - int nb_samples = av_audio_fifo_size(s->fifo[1]); - - ret = ff_request_frame(cf1); - if (ret == AVERROR_EOF && nb_samples > 0) { - AVFrame *out = ff_get_audio_buffer(outlink, nb_samples); - if (!out) - return AVERROR(ENOMEM); - - av_audio_fifo_read(s->fifo[1], (void **)out->extended_data, nb_samples); - ret = ff_filter_frame(outlink, out); + if (ctx->inputs[1]->status_in) { + ff_outlink_set_status(ctx->outputs[0], AVERROR_EOF, AV_NOPTS_VALUE); + return 0; } + if (!s->cf0_eof) + ff_inlink_request_frame(ctx->inputs[0]); + else + ff_inlink_request_frame(ctx->inputs[1]); + return 0; } return ret; @@ -615,32 +590,17 @@ static int acrossfade_config_output(AVFilterLink *outlink) config_output(outlink); - s->fifo[0] = av_audio_fifo_alloc(outlink->format, outlink->channels, s->nb_samples); - s->fifo[1] = av_audio_fifo_alloc(outlink->format, outlink->channels, s->nb_samples); - if (!s->fifo[0] || !s->fifo[1]) - return AVERROR(ENOMEM); - return 0; } -static av_cold void uninit(AVFilterContext *ctx) -{ - AudioFadeContext *s = ctx->priv; - - av_audio_fifo_free(s->fifo[0]); - av_audio_fifo_free(s->fifo[1]); -} - static const AVFilterPad avfilter_af_acrossfade_inputs[] = { { .name = "crossfade0", .type = AVMEDIA_TYPE_AUDIO, - .filter_frame = acrossfade_filter_frame, }, { .name = "crossfade1", .type = AVMEDIA_TYPE_AUDIO, - .filter_frame = acrossfade_filter_frame, }, { NULL } }; @@ -649,7 +609,6 @@ static const AVFilterPad avfilter_af_acrossfade_outputs[] = { { .name = "default", .type = AVMEDIA_TYPE_AUDIO, - .request_frame = acrossfade_request_frame, .config_props = acrossfade_config_output, }, { NULL } @@ -660,7 +619,7 @@ AVFilter ff_af_acrossfade = { .description = NULL_IF_CONFIG_SMALL("Cross fade two input audio streams."), .query_formats = query_formats, .priv_size = sizeof(AudioFadeContext), - .uninit = uninit, + .activate = activate, .priv_class = &acrossfade_class, .inputs = avfilter_af_acrossfade_inputs, .outputs = avfilter_af_acrossfade_outputs, diff --git a/libavfilter/af_afftfilt.c b/libavfilter/af_afftfilt.c index 52755a1fb42d3..7f28e1f77bcdf 100644 --- a/libavfilter/af_afftfilt.c +++ b/libavfilter/af_afftfilt.c @@ -197,8 +197,10 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) int ch, n, ret, i, j, k; int start = s->start, end = s->end; - av_audio_fifo_write(s->fifo, (void **)frame->extended_data, frame->nb_samples); + ret = av_audio_fifo_write(s->fifo, (void **)frame->extended_data, frame->nb_samples); av_frame_free(&frame); + if (ret < 0) + return ret; while (av_audio_fifo_size(s->fifo) >= window_size) { if (!in) { @@ -316,7 +318,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) } av_frame_free(&in); - return ret; + return ret < 0 ? ret : 0; } static int query_formats(AVFilterContext *ctx) diff --git a/libavfilter/af_afir.c b/libavfilter/af_afir.c index c4443fdffdd4d..6687242631673 100644 --- a/libavfilter/af_afir.c +++ b/libavfilter/af_afir.c @@ -105,7 +105,7 @@ static int fir_channel(AVFilterContext *ctx, void *arg, int ch, int nb_jobs) if (out) { float *ptr = (float *)out->extended_data[ch]; - s->fdsp->vector_fmul_scalar(ptr, dst, s->gain * s->wet_gain, FFALIGN(out->nb_samples, 4)); + s->fdsp->vector_fmul_scalar(ptr, dst, s->wet_gain, FFALIGN(out->nb_samples, 4)); emms_c(); } @@ -166,7 +166,6 @@ static int convert_coeffs(AVFilterContext *ctx) { AudioFIRContext *s = ctx->priv; int i, ch, n, N; - float power = 0; s->nb_taps = av_audio_fifo_size(s->fifo[1]); if (s->nb_taps <= 0) @@ -217,13 +216,29 @@ static int convert_coeffs(AVFilterContext *ctx) av_audio_fifo_read(s->fifo[1], (void **)s->in[1]->extended_data, s->nb_taps); + if (s->again) { + float power = 0; + + for (ch = 0; ch < ctx->inputs[1]->channels; ch++) { + float *time = (float *)s->in[1]->extended_data[!s->one2many * ch]; + + for (i = 0; i < s->nb_taps; i++) + power += FFABS(time[i]); + } + + s->gain = sqrtf(1.f / (ctx->inputs[1]->channels * power)) / (sqrtf(ctx->inputs[1]->channels)); + for (ch = 0; ch < ctx->inputs[1]->channels; ch++) { + float *time = (float *)s->in[1]->extended_data[!s->one2many * ch]; + + s->fdsp->vector_fmul_scalar(time, time, s->gain, FFALIGN(s->nb_taps, 4)); + } + } + for (ch = 0; ch < ctx->inputs[1]->channels; ch++) { float *time = (float *)s->in[1]->extended_data[!s->one2many * ch]; float *block = s->block[ch]; FFTComplex *coeff = s->coeff[ch]; - power += s->fdsp->scalarproduct_float(time, time, s->nb_taps); - for (i = FFMAX(1, s->length * s->nb_taps); i < s->nb_taps; i++) time[i] = 0; @@ -252,7 +267,6 @@ static int convert_coeffs(AVFilterContext *ctx) } av_frame_free(&s->in[1]); - s->gain = s->again ? 1.f / sqrtf(power / ctx->inputs[1]->channels) : 1.f; av_log(ctx, AV_LOG_DEBUG, "nb_taps: %d\n", s->nb_taps); av_log(ctx, AV_LOG_DEBUG, "nb_partitions: %d\n", s->nb_partitions); av_log(ctx, AV_LOG_DEBUG, "partition size: %d\n", s->part_size); @@ -267,11 +281,13 @@ static int read_ir(AVFilterLink *link, AVFrame *frame) { AVFilterContext *ctx = link->dst; AudioFIRContext *s = ctx->priv; - int nb_taps, max_nb_taps; + int nb_taps, max_nb_taps, ret; - av_audio_fifo_write(s->fifo[1], (void **)frame->extended_data, - frame->nb_samples); + ret = av_audio_fifo_write(s->fifo[1], (void **)frame->extended_data, + frame->nb_samples); av_frame_free(&frame); + if (ret < 0) + return ret; nb_taps = av_audio_fifo_size(s->fifo[1]); max_nb_taps = MAX_IR_DURATION * ctx->outputs[0]->sample_rate; @@ -288,15 +304,18 @@ static int filter_frame(AVFilterLink *link, AVFrame *frame) AVFilterContext *ctx = link->dst; AudioFIRContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; - int ret = 0; + int ret; - av_audio_fifo_write(s->fifo[0], (void **)frame->extended_data, - frame->nb_samples); - if (s->pts == AV_NOPTS_VALUE) + ret = av_audio_fifo_write(s->fifo[0], (void **)frame->extended_data, + frame->nb_samples); + if (ret > 0 && s->pts == AV_NOPTS_VALUE) s->pts = frame->pts; av_frame_free(&frame); + if (ret < 0) + return ret; + if (!s->have_coeffs && s->eof_coeffs) { ret = convert_coeffs(ctx); if (ret < 0) @@ -307,10 +326,10 @@ static int filter_frame(AVFilterLink *link, AVFrame *frame) while (av_audio_fifo_size(s->fifo[0]) >= s->part_size) { ret = fir_frame(s, outlink); if (ret < 0) - break; + return ret; } } - return ret; + return 0; } static int request_frame(AVFilterLink *outlink) @@ -334,9 +353,11 @@ static int request_frame(AVFilterLink *outlink) if (!silence) return AVERROR(ENOMEM); - av_audio_fifo_write(s->fifo[0], (void **)silence->extended_data, - silence->nb_samples); + ret = av_audio_fifo_write(s->fifo[0], (void **)silence->extended_data, + silence->nb_samples); av_frame_free(&silence); + if (ret < 0) + return ret; s->need_padding = 0; } diff --git a/libavfilter/af_agate.c b/libavfilter/af_agate.c index 20905ccb19025..ba96863a688a5 100644 --- a/libavfilter/af_agate.c +++ b/libavfilter/af_agate.c @@ -214,7 +214,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); @@ -323,14 +323,13 @@ static int activate(AVFilterContext *ctx) } FF_FILTER_FORWARD_STATUS(ctx->inputs[0], ctx->outputs[0]); FF_FILTER_FORWARD_STATUS(ctx->inputs[1], ctx->outputs[0]); - /* TODO reindent */ - if (ff_outlink_frame_wanted(ctx->outputs[0])) { - if (!av_audio_fifo_size(s->fifo[0])) - ff_inlink_request_frame(ctx->inputs[0]); - if (!av_audio_fifo_size(s->fifo[1])) - ff_inlink_request_frame(ctx->inputs[1]); - } - return 0; + if (ff_outlink_frame_wanted(ctx->outputs[0])) { + if (!av_audio_fifo_size(s->fifo[0])) + ff_inlink_request_frame(ctx->inputs[0]); + if (!av_audio_fifo_size(s->fifo[1])) + ff_inlink_request_frame(ctx->inputs[1]); + } + return 0; } static int scquery_formats(AVFilterContext *ctx) diff --git a/libavfilter/af_aiir.c b/libavfilter/af_aiir.c new file mode 100644 index 0000000000000..1f2a568c1d906 --- /dev/null +++ b/libavfilter/af_aiir.c @@ -0,0 +1,849 @@ +/* + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/opt.h" +#include "audio.h" +#include "avfilter.h" +#include "internal.h" + +typedef struct ThreadData { + AVFrame *in, *out; +} ThreadData; + +typedef struct Pair { + int a, b; +} Pair; + +typedef struct BiquadContext { + double a0, a1, a2; + double b0, b1, b2; + double i1, i2; + double o1, o2; +} BiquadContext; + +typedef struct IIRChannel { + int nb_ab[2]; + double *ab[2]; + double g; + double *cache[2]; + BiquadContext *biquads; + int clippings; +} IIRChannel; + +typedef struct AudioIIRContext { + const AVClass *class; + char *a_str, *b_str, *g_str; + double dry_gain, wet_gain; + int format; + int process; + int precision; + + IIRChannel *iir; + int channels; + enum AVSampleFormat sample_format; + + int (*iir_channel)(AVFilterContext *ctx, void *arg, int ch, int nb_jobs); +} AudioIIRContext; + +static int query_formats(AVFilterContext *ctx) +{ + AudioIIRContext *s = ctx->priv; + AVFilterFormats *formats; + AVFilterChannelLayouts *layouts; + enum AVSampleFormat sample_fmts[] = { + AV_SAMPLE_FMT_DBLP, + AV_SAMPLE_FMT_NONE + }; + int ret; + + layouts = ff_all_channel_counts(); + if (!layouts) + return AVERROR(ENOMEM); + ret = ff_set_common_channel_layouts(ctx, layouts); + if (ret < 0) + return ret; + + sample_fmts[0] = s->sample_format; + formats = ff_make_format_list(sample_fmts); + if (!formats) + return AVERROR(ENOMEM); + ret = ff_set_common_formats(ctx, formats); + if (ret < 0) + return ret; + + formats = ff_all_samplerates(); + if (!formats) + return AVERROR(ENOMEM); + return ff_set_common_samplerates(ctx, formats); +} + +#define IIR_CH(name, type, min, max, need_clipping) \ +static int iir_ch_## name(AVFilterContext *ctx, void *arg, int ch, int nb_jobs) \ +{ \ + AudioIIRContext *s = ctx->priv; \ + const double ig = s->dry_gain; \ + const double og = s->wet_gain; \ + ThreadData *td = arg; \ + AVFrame *in = td->in, *out = td->out; \ + const type *src = (const type *)in->extended_data[ch]; \ + double *ic = (double *)s->iir[ch].cache[0]; \ + double *oc = (double *)s->iir[ch].cache[1]; \ + const int nb_a = s->iir[ch].nb_ab[0]; \ + const int nb_b = s->iir[ch].nb_ab[1]; \ + const double *a = s->iir[ch].ab[0]; \ + const double *b = s->iir[ch].ab[1]; \ + int *clippings = &s->iir[ch].clippings; \ + type *dst = (type *)out->extended_data[ch]; \ + int n; \ + \ + for (n = 0; n < in->nb_samples; n++) { \ + double sample = 0.; \ + int x; \ + \ + memmove(&ic[1], &ic[0], (nb_b - 1) * sizeof(*ic)); \ + memmove(&oc[1], &oc[0], (nb_a - 1) * sizeof(*oc)); \ + ic[0] = src[n] * ig; \ + for (x = 0; x < nb_b; x++) \ + sample += b[x] * ic[x]; \ + \ + for (x = 1; x < nb_a; x++) \ + sample -= a[x] * oc[x]; \ + \ + oc[0] = sample; \ + sample *= og; \ + if (need_clipping && sample < min) { \ + (*clippings)++; \ + dst[n] = min; \ + } else if (need_clipping && sample > max) { \ + (*clippings)++; \ + dst[n] = max; \ + } else { \ + dst[n] = sample; \ + } \ + } \ + \ + return 0; \ +} + +IIR_CH(s16p, int16_t, INT16_MIN, INT16_MAX, 1) +IIR_CH(s32p, int32_t, INT32_MIN, INT32_MAX, 1) +IIR_CH(fltp, float, -1., 1., 0) +IIR_CH(dblp, double, -1., 1., 0) + +#define SERIAL_IIR_CH(name, type, min, max, need_clipping) \ +static int iir_ch_serial_## name(AVFilterContext *ctx, void *arg, int ch, int nb_jobs) \ +{ \ + AudioIIRContext *s = ctx->priv; \ + const double ig = s->dry_gain; \ + const double og = s->wet_gain; \ + ThreadData *td = arg; \ + AVFrame *in = td->in, *out = td->out; \ + const type *src = (const type *)in->extended_data[ch]; \ + type *dst = (type *)out->extended_data[ch]; \ + IIRChannel *iir = &s->iir[ch]; \ + int *clippings = &iir->clippings; \ + int nb_biquads = (FFMAX(iir->nb_ab[0], iir->nb_ab[1]) + 1) / 2; \ + int n, i; \ + \ + for (i = 0; i < nb_biquads; i++) { \ + const double a1 = -iir->biquads[i].a1; \ + const double a2 = -iir->biquads[i].a2; \ + const double b0 = iir->biquads[i].b0; \ + const double b1 = iir->biquads[i].b1; \ + const double b2 = iir->biquads[i].b2; \ + double i1 = iir->biquads[i].i1; \ + double i2 = iir->biquads[i].i2; \ + double o1 = iir->biquads[i].o1; \ + double o2 = iir->biquads[i].o2; \ + \ + for (n = 0; n < in->nb_samples; n++) { \ + double sample = ig * (i ? dst[n] : src[n]); \ + double o0 = sample * b0 + i1 * b1 + i2 * b2 + o1 * a1 + o2 * a2; \ + \ + i2 = i1; \ + i1 = src[n]; \ + o2 = o1; \ + o1 = o0; \ + o0 *= og; \ + \ + if (need_clipping && o0 < min) { \ + (*clippings)++; \ + dst[n] = min; \ + } else if (need_clipping && o0 > max) { \ + (*clippings)++; \ + dst[n] = max; \ + } else { \ + dst[n] = o0; \ + } \ + } \ + iir->biquads[i].i1 = i1; \ + iir->biquads[i].i2 = i2; \ + iir->biquads[i].o1 = o1; \ + iir->biquads[i].o2 = o2; \ + } \ + \ + return 0; \ +} + +SERIAL_IIR_CH(s16p, int16_t, INT16_MIN, INT16_MAX, 1) +SERIAL_IIR_CH(s32p, int32_t, INT32_MIN, INT32_MAX, 1) +SERIAL_IIR_CH(fltp, float, -1., 1., 0) +SERIAL_IIR_CH(dblp, double, -1., 1., 0) + +static void count_coefficients(char *item_str, int *nb_items) +{ + char *p; + + if (!item_str) + return; + + *nb_items = 1; + for (p = item_str; *p && *p != '|'; p++) { + if (*p == ' ') + (*nb_items)++; + } +} + +static int read_gains(AVFilterContext *ctx, char *item_str, int nb_items) +{ + AudioIIRContext *s = ctx->priv; + char *p, *arg, *old_str, *prev_arg = NULL, *saveptr = NULL; + int i; + + p = old_str = av_strdup(item_str); + if (!p) + return AVERROR(ENOMEM); + for (i = 0; i < nb_items; i++) { + if (!(arg = av_strtok(p, "|", &saveptr))) + arg = prev_arg; + + if (!arg) { + av_freep(&old_str); + return AVERROR(EINVAL); + } + + p = NULL; + if (sscanf(arg, "%lf", &s->iir[i].g) != 1) { + av_log(ctx, AV_LOG_ERROR, "Invalid gains supplied: %s\n", arg); + av_freep(&old_str); + return AVERROR(EINVAL); + } + + prev_arg = arg; + } + + av_freep(&old_str); + + return 0; +} + +static int read_tf_coefficients(AVFilterContext *ctx, char *item_str, int nb_items, double *dst) +{ + char *p, *arg, *old_str, *saveptr = NULL; + int i; + + p = old_str = av_strdup(item_str); + if (!p) + return AVERROR(ENOMEM); + for (i = 0; i < nb_items; i++) { + if (!(arg = av_strtok(p, " ", &saveptr))) + break; + + p = NULL; + if (sscanf(arg, "%lf", &dst[i]) != 1) { + av_log(ctx, AV_LOG_ERROR, "Invalid coefficients supplied: %s\n", arg); + av_freep(&old_str); + return AVERROR(EINVAL); + } + } + + av_freep(&old_str); + + return 0; +} + +static int read_zp_coefficients(AVFilterContext *ctx, char *item_str, int nb_items, double *dst, const char *format) +{ + char *p, *arg, *old_str, *saveptr = NULL; + int i; + + p = old_str = av_strdup(item_str); + if (!p) + return AVERROR(ENOMEM); + for (i = 0; i < nb_items; i++) { + if (!(arg = av_strtok(p, " ", &saveptr))) + break; + + p = NULL; + if (sscanf(arg, format, &dst[i*2], &dst[i*2+1]) != 2) { + av_log(ctx, AV_LOG_ERROR, "Invalid coefficients supplied: %s\n", arg); + av_freep(&old_str); + return AVERROR(EINVAL); + } + } + + av_freep(&old_str); + + return 0; +} + +static const char *format[] = { "%lf", "%lf %lfi", "%lf %lfr", "%lf %lfd" }; + +static int read_channels(AVFilterContext *ctx, int channels, uint8_t *item_str, int ab) +{ + AudioIIRContext *s = ctx->priv; + char *p, *arg, *old_str, *prev_arg = NULL, *saveptr = NULL; + int i, ret; + + p = old_str = av_strdup(item_str); + if (!p) + return AVERROR(ENOMEM); + for (i = 0; i < channels; i++) { + IIRChannel *iir = &s->iir[i]; + + if (!(arg = av_strtok(p, "|", &saveptr))) + arg = prev_arg; + + if (!arg) { + av_freep(&old_str); + return AVERROR(EINVAL); + } + + count_coefficients(arg, &iir->nb_ab[ab]); + + p = NULL; + iir->cache[ab] = av_calloc(iir->nb_ab[ab] + 1, sizeof(double)); + iir->ab[ab] = av_calloc(iir->nb_ab[ab] * (!!s->format + 1), sizeof(double)); + if (!iir->ab[ab] || !iir->cache[ab]) { + av_freep(&old_str); + return AVERROR(ENOMEM); + } + + if (s->format) { + ret = read_zp_coefficients(ctx, arg, iir->nb_ab[ab], iir->ab[ab], format[s->format]); + } else { + ret = read_tf_coefficients(ctx, arg, iir->nb_ab[ab], iir->ab[ab]); + } + if (ret < 0) { + av_freep(&old_str); + return ret; + } + prev_arg = arg; + } + + av_freep(&old_str); + + return 0; +} + +static void multiply(double wre, double wim, int npz, double *coeffs) +{ + double nwre = -wre, nwim = -wim; + double cre, cim; + int i; + + for (i = npz; i >= 1; i--) { + cre = coeffs[2 * i + 0]; + cim = coeffs[2 * i + 1]; + + coeffs[2 * i + 0] = (nwre * cre - nwim * cim) + coeffs[2 * (i - 1) + 0]; + coeffs[2 * i + 1] = (nwre * cim + nwim * cre) + coeffs[2 * (i - 1) + 1]; + } + + cre = coeffs[0]; + cim = coeffs[1]; + coeffs[0] = nwre * cre - nwim * cim; + coeffs[1] = nwre * cim + nwim * cre; +} + +static int expand(AVFilterContext *ctx, double *pz, int nb, double *coeffs) +{ + int i; + + coeffs[0] = 1.0; + coeffs[1] = 0.0; + + for (i = 0; i < nb; i++) { + coeffs[2 * (i + 1) ] = 0.0; + coeffs[2 * (i + 1) + 1] = 0.0; + } + + for (i = 0; i < nb; i++) + multiply(pz[2 * i], pz[2 * i + 1], nb, coeffs); + + for (i = 0; i < nb + 1; i++) { + if (fabs(coeffs[2 * i + 1]) > FLT_EPSILON) { + av_log(ctx, AV_LOG_ERROR, "coeff: %lf of z^%d is not real; poles/zeros are not complex conjugates.\n", + coeffs[2 * i + 1], i); + return AVERROR(EINVAL); + } + } + + return 0; +} + +static int convert_zp2tf(AVFilterContext *ctx, int channels) +{ + AudioIIRContext *s = ctx->priv; + int ch, i, j, ret = 0; + + for (ch = 0; ch < channels; ch++) { + IIRChannel *iir = &s->iir[ch]; + double *topc, *botc; + + topc = av_calloc((iir->nb_ab[0] + 1) * 2, sizeof(*topc)); + botc = av_calloc((iir->nb_ab[1] + 1) * 2, sizeof(*botc)); + if (!topc || !botc) { + ret = AVERROR(ENOMEM); + goto fail; + } + + ret = expand(ctx, iir->ab[0], iir->nb_ab[0], botc); + if (ret < 0) { + goto fail; + } + + ret = expand(ctx, iir->ab[1], iir->nb_ab[1], topc); + if (ret < 0) { + goto fail; + } + + for (j = 0, i = iir->nb_ab[1]; i >= 0; j++, i--) { + iir->ab[1][j] = topc[2 * i]; + } + iir->nb_ab[1]++; + + for (j = 0, i = iir->nb_ab[0]; i >= 0; j++, i--) { + iir->ab[0][j] = botc[2 * i]; + } + iir->nb_ab[0]++; + +fail: + av_free(topc); + av_free(botc); + if (ret < 0) + break; + } + + return ret; +} + +static int decompose_zp2biquads(AVFilterContext *ctx, int channels) +{ + AudioIIRContext *s = ctx->priv; + int ch, ret; + + for (ch = 0; ch < channels; ch++) { + IIRChannel *iir = &s->iir[ch]; + int nb_biquads = (FFMAX(iir->nb_ab[0], iir->nb_ab[1]) + 1) / 2; + int current_biquad = 0; + + iir->biquads = av_calloc(nb_biquads, sizeof(BiquadContext)); + if (!iir->biquads) + return AVERROR(ENOMEM); + + while (nb_biquads--) { + Pair outmost_pole = { -1, -1 }; + Pair nearest_zero = { -1, -1 }; + double zeros[4] = { 0 }; + double poles[4] = { 0 }; + double b[6] = { 0 }; + double a[6] = { 0 }; + double min_distance = DBL_MAX; + double max_mag = 0; + int i; + + for (i = 0; i < iir->nb_ab[0]; i++) { + double mag; + + if (isnan(iir->ab[0][2 * i]) || isnan(iir->ab[0][2 * i + 1])) + continue; + mag = hypot(iir->ab[0][2 * i], iir->ab[0][2 * i + 1]); + + if (mag > max_mag) { + max_mag = mag; + outmost_pole.a = i; + } + } + + for (i = 0; i < iir->nb_ab[1]; i++) { + if (isnan(iir->ab[0][2 * i]) || isnan(iir->ab[0][2 * i + 1])) + continue; + + if (iir->ab[0][2 * i ] == iir->ab[0][2 * outmost_pole.a ] && + iir->ab[0][2 * i + 1] == -iir->ab[0][2 * outmost_pole.a + 1]) { + outmost_pole.b = i; + break; + } + } + + av_log(ctx, AV_LOG_VERBOSE, "outmost_pole is %d.%d\n", outmost_pole.a, outmost_pole.b); + + if (outmost_pole.a < 0 || outmost_pole.b < 0) + return AVERROR(EINVAL); + + for (i = 0; i < iir->nb_ab[1]; i++) { + double distance; + + if (isnan(iir->ab[1][2 * i]) || isnan(iir->ab[1][2 * i + 1])) + continue; + distance = hypot(iir->ab[0][2 * outmost_pole.a ] - iir->ab[1][2 * i ], + iir->ab[0][2 * outmost_pole.a + 1] - iir->ab[1][2 * i + 1]); + + if (distance < min_distance) { + min_distance = distance; + nearest_zero.a = i; + } + } + + for (i = 0; i < iir->nb_ab[1]; i++) { + if (isnan(iir->ab[1][2 * i]) || isnan(iir->ab[1][2 * i + 1])) + continue; + + if (iir->ab[1][2 * i ] == iir->ab[1][2 * nearest_zero.a ] && + iir->ab[1][2 * i + 1] == -iir->ab[1][2 * nearest_zero.a + 1]) { + nearest_zero.b = i; + break; + } + } + + av_log(ctx, AV_LOG_VERBOSE, "nearest_zero is %d.%d\n", nearest_zero.a, nearest_zero.b); + + if (nearest_zero.a < 0 || nearest_zero.b < 0) + return AVERROR(EINVAL); + + poles[0] = iir->ab[0][2 * outmost_pole.a ]; + poles[1] = iir->ab[0][2 * outmost_pole.a + 1]; + + zeros[0] = iir->ab[1][2 * nearest_zero.a ]; + zeros[1] = iir->ab[1][2 * nearest_zero.a + 1]; + + if (nearest_zero.a == nearest_zero.b && outmost_pole.a == outmost_pole.b) { + zeros[2] = 0; + zeros[3] = 0; + + poles[2] = 0; + poles[3] = 0; + } else { + poles[2] = iir->ab[0][2 * outmost_pole.b ]; + poles[3] = iir->ab[0][2 * outmost_pole.b + 1]; + + zeros[2] = iir->ab[1][2 * nearest_zero.b ]; + zeros[3] = iir->ab[1][2 * nearest_zero.b + 1]; + } + + ret = expand(ctx, zeros, 2, b); + if (ret < 0) + return ret; + + ret = expand(ctx, poles, 2, a); + if (ret < 0) + return ret; + + iir->ab[0][2 * outmost_pole.a] = iir->ab[0][2 * outmost_pole.a + 1] = NAN; + iir->ab[0][2 * outmost_pole.b] = iir->ab[0][2 * outmost_pole.b + 1] = NAN; + iir->ab[1][2 * nearest_zero.a] = iir->ab[1][2 * nearest_zero.a + 1] = NAN; + iir->ab[1][2 * nearest_zero.b] = iir->ab[1][2 * nearest_zero.b + 1] = NAN; + + iir->biquads[current_biquad].a0 = 1.0; + iir->biquads[current_biquad].a1 = a[2] / a[4]; + iir->biquads[current_biquad].a2 = a[0] / a[4]; + iir->biquads[current_biquad].b0 = b[4] / a[4] * (current_biquad ? 1.0 : iir->g); + iir->biquads[current_biquad].b1 = b[2] / a[4] * (current_biquad ? 1.0 : iir->g); + iir->biquads[current_biquad].b2 = b[0] / a[4] * (current_biquad ? 1.0 : iir->g); + + av_log(ctx, AV_LOG_VERBOSE, "a=%lf %lf %lf:b=%lf %lf %lf\n", + iir->biquads[current_biquad].a0, + iir->biquads[current_biquad].a1, + iir->biquads[current_biquad].a2, + iir->biquads[current_biquad].b0, + iir->biquads[current_biquad].b1, + iir->biquads[current_biquad].b2); + + current_biquad++; + } + } + + return 0; +} + +static void convert_pr2zp(AVFilterContext *ctx, int channels) +{ + AudioIIRContext *s = ctx->priv; + int ch; + + for (ch = 0; ch < channels; ch++) { + IIRChannel *iir = &s->iir[ch]; + int n; + + for (n = 0; n < iir->nb_ab[0]; n++) { + double r = iir->ab[0][2*n]; + double angle = iir->ab[0][2*n+1]; + + iir->ab[0][2*n] = r * cos(angle); + iir->ab[0][2*n+1] = r * sin(angle); + } + + for (n = 0; n < iir->nb_ab[1]; n++) { + double r = iir->ab[1][2*n]; + double angle = iir->ab[1][2*n+1]; + + iir->ab[1][2*n] = r * cos(angle); + iir->ab[1][2*n+1] = r * sin(angle); + } + } +} + +static void convert_pd2zp(AVFilterContext *ctx, int channels) +{ + AudioIIRContext *s = ctx->priv; + int ch; + + for (ch = 0; ch < channels; ch++) { + IIRChannel *iir = &s->iir[ch]; + int n; + + for (n = 0; n < iir->nb_ab[0]; n++) { + double r = iir->ab[0][2*n]; + double angle = M_PI*iir->ab[0][2*n+1]/180.; + + iir->ab[0][2*n] = r * cos(angle); + iir->ab[0][2*n+1] = r * sin(angle); + } + + for (n = 0; n < iir->nb_ab[1]; n++) { + double r = iir->ab[1][2*n]; + double angle = M_PI*iir->ab[1][2*n+1]/180.; + + iir->ab[1][2*n] = r * cos(angle); + iir->ab[1][2*n+1] = r * sin(angle); + } + } +} + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + AudioIIRContext *s = ctx->priv; + AVFilterLink *inlink = ctx->inputs[0]; + int ch, ret, i; + + s->channels = inlink->channels; + s->iir = av_calloc(s->channels, sizeof(*s->iir)); + if (!s->iir) + return AVERROR(ENOMEM); + + ret = read_gains(ctx, s->g_str, inlink->channels); + if (ret < 0) + return ret; + + ret = read_channels(ctx, inlink->channels, s->a_str, 0); + if (ret < 0) + return ret; + + ret = read_channels(ctx, inlink->channels, s->b_str, 1); + if (ret < 0) + return ret; + + if (s->format == 2) { + convert_pr2zp(ctx, inlink->channels); + } else if (s->format == 3) { + convert_pd2zp(ctx, inlink->channels); + } + + if (s->format == 0) + av_log(ctx, AV_LOG_WARNING, "tf coefficients format is not recommended for too high number of zeros/poles.\n"); + + if (s->format > 0 && s->process == 0) { + av_log(ctx, AV_LOG_WARNING, "Direct processsing is not recommended for zp coefficients format.\n"); + + ret = convert_zp2tf(ctx, inlink->channels); + if (ret < 0) + return ret; + } else if (s->format == 0 && s->process == 1) { + av_log(ctx, AV_LOG_ERROR, "Serial cascading is not implemented for transfer function.\n"); + return AVERROR_PATCHWELCOME; + } else if (s->format > 0 && s->process == 1) { + if (inlink->format == AV_SAMPLE_FMT_S16P) + av_log(ctx, AV_LOG_WARNING, "Serial cascading is not recommended for i16 precision.\n"); + + ret = decompose_zp2biquads(ctx, inlink->channels); + if (ret < 0) + return ret; + } + + for (ch = 0; ch < inlink->channels; ch++) { + IIRChannel *iir = &s->iir[ch]; + + for (i = 1; i < iir->nb_ab[0]; i++) { + iir->ab[0][i] /= iir->ab[0][0]; + } + + for (i = 0; i < iir->nb_ab[1]; i++) { + iir->ab[1][i] *= iir->g / iir->ab[0][0]; + } + } + + switch (inlink->format) { + case AV_SAMPLE_FMT_DBLP: s->iir_channel = s->process == 1 ? iir_ch_serial_dblp : iir_ch_dblp; break; + case AV_SAMPLE_FMT_FLTP: s->iir_channel = s->process == 1 ? iir_ch_serial_fltp : iir_ch_fltp; break; + case AV_SAMPLE_FMT_S32P: s->iir_channel = s->process == 1 ? iir_ch_serial_s32p : iir_ch_s32p; break; + case AV_SAMPLE_FMT_S16P: s->iir_channel = s->process == 1 ? iir_ch_serial_s16p : iir_ch_s16p; break; + } + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AudioIIRContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + ThreadData td; + AVFrame *out; + int ch; + + if (av_frame_is_writable(in)) { + out = in; + } else { + out = ff_get_audio_buffer(outlink, in->nb_samples); + if (!out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + av_frame_copy_props(out, in); + } + + td.in = in; + td.out = out; + ctx->internal->execute(ctx, s->iir_channel, &td, NULL, outlink->channels); + + for (ch = 0; ch < outlink->channels; ch++) { + if (s->iir[ch].clippings > 0) + av_log(ctx, AV_LOG_WARNING, "Channel %d clipping %d times. Please reduce gain.\n", + ch, s->iir[ch].clippings); + s->iir[ch].clippings = 0; + } + + if (in != out) + av_frame_free(&in); + + return ff_filter_frame(outlink, out); +} + +static av_cold int init(AVFilterContext *ctx) +{ + AudioIIRContext *s = ctx->priv; + + if (!s->a_str || !s->b_str || !s->g_str) { + av_log(ctx, AV_LOG_ERROR, "Valid coefficients are mandatory.\n"); + return AVERROR(EINVAL); + } + + switch (s->precision) { + case 0: s->sample_format = AV_SAMPLE_FMT_DBLP; break; + case 1: s->sample_format = AV_SAMPLE_FMT_FLTP; break; + case 2: s->sample_format = AV_SAMPLE_FMT_S32P; break; + case 3: s->sample_format = AV_SAMPLE_FMT_S16P; break; + default: return AVERROR_BUG; + } + + return 0; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + AudioIIRContext *s = ctx->priv; + int ch; + + if (s->iir) { + for (ch = 0; ch < s->channels; ch++) { + IIRChannel *iir = &s->iir[ch]; + av_freep(&iir->ab[0]); + av_freep(&iir->ab[1]); + av_freep(&iir->cache[0]); + av_freep(&iir->cache[1]); + av_freep(&iir->biquads); + } + } + av_freep(&s->iir); +} + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .config_props = config_output, + }, + { NULL } +}; + +#define OFFSET(x) offsetof(AudioIIRContext, x) +#define AF AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption aiir_options[] = { + { "z", "set B/numerator/zeros coefficients", OFFSET(b_str), AV_OPT_TYPE_STRING, {.str="1+0i 1-0i"}, 0, 0, AF }, + { "p", "set A/denominator/poles coefficients", OFFSET(a_str), AV_OPT_TYPE_STRING, {.str="1+0i 1-0i"}, 0, 0, AF }, + { "k", "set channels gains", OFFSET(g_str), AV_OPT_TYPE_STRING, {.str="1|1"}, 0, 0, AF }, + { "dry", "set dry gain", OFFSET(dry_gain), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, AF }, + { "wet", "set wet gain", OFFSET(wet_gain), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 1, AF }, + { "f", "set coefficients format", OFFSET(format), AV_OPT_TYPE_INT, {.i64=1}, 0, 3, AF, "format" }, + { "tf", "transfer function", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "format" }, + { "zp", "Z-plane zeros/poles", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "format" }, + { "pr", "Z-plane zeros/poles (polar radians)", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF, "format" }, + { "pd", "Z-plane zeros/poles (polar degrees)", 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, AF, "format" }, + { "r", "set kind of processing", OFFSET(process), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, AF, "process" }, + { "d", "direct", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "process" }, + { "s", "serial cascading", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "process" }, + { "e", "set precision", OFFSET(precision),AV_OPT_TYPE_INT, {.i64=0}, 0, 3, AF, "precision" }, + { "dbl", "double-precision floating-point", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, AF, "precision" }, + { "flt", "single-precision floating-point", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, AF, "precision" }, + { "i32", "32-bit integers", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, AF, "precision" }, + { "i16", "16-bit integers", 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, AF, "precision" }, + { NULL }, +}; + +AVFILTER_DEFINE_CLASS(aiir); + +AVFilter ff_af_aiir = { + .name = "aiir", + .description = NULL_IF_CONFIG_SMALL("Apply Infinite Impulse Response filter with supplied coefficients."), + .priv_size = sizeof(AudioIIRContext), + .priv_class = &aiir_class, + .init = init, + .uninit = uninit, + .query_formats = query_formats, + .inputs = inputs, + .outputs = outputs, + .flags = AVFILTER_FLAG_SLICE_THREADS, +}; diff --git a/libavfilter/af_alimiter.c b/libavfilter/af_alimiter.c index 46211a710ada8..c41e95576f760 100644 --- a/libavfilter/af_alimiter.c +++ b/libavfilter/af_alimiter.c @@ -135,7 +135,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); @@ -327,6 +327,11 @@ static int config_input(AVFilterLink *inlink) s->buffer_size = inlink->sample_rate * s->attack * inlink->channels; s->buffer_size -= s->buffer_size % inlink->channels; + if (s->buffer_size <= 0) { + av_log(ctx, AV_LOG_ERROR, "Attack is too small.\n"); + return AVERROR(EINVAL); + } + return 0; } diff --git a/libavfilter/af_amix.c b/libavfilter/af_amix.c index 09848e5d91a92..46f1bf63d790d 100644 --- a/libavfilter/af_amix.c +++ b/libavfilter/af_amix.c @@ -162,6 +162,7 @@ typedef struct MixContext { int active_inputs; /**< number of input currently active */ int duration_mode; /**< mode for determining duration */ float dropout_transition; /**< transition time when an input drops out */ + char *weights_str; /**< string for custom weights for every input */ int nb_channels; /**< number of channels */ int sample_rate; /**< sample rate */ @@ -169,7 +170,9 @@ typedef struct MixContext { AVAudioFifo **fifos; /**< audio fifo for each input */ uint8_t *input_state; /**< current state of each input */ float *input_scale; /**< mixing scale factor for each input */ - float scale_norm; /**< normalization factor for all inputs */ + float *weights; /**< custom weights for every input */ + float weight_sum; /**< sum of custom weights for every input */ + float *scale_norm; /**< normalization factor for every input */ int64_t next_pts; /**< calculated pts for next output frame */ FrameList *frame_list; /**< list of frame info for the first input */ } MixContext; @@ -188,6 +191,8 @@ static const AVOption amix_options[] = { { "dropout_transition", "Transition time, in seconds, for volume " "renormalization when an input stream ends.", OFFSET(dropout_transition), AV_OPT_TYPE_FLOAT, { .dbl = 2.0 }, 0, INT_MAX, A|F }, + { "weights", "Set weight for each input.", + OFFSET(weights_str), AV_OPT_TYPE_STRING, {.str="1 1"}, 0, 0, A|F }, { NULL } }; @@ -202,16 +207,26 @@ AVFILTER_DEFINE_CLASS(amix); */ static void calculate_scales(MixContext *s, int nb_samples) { + float weight_sum = 0.f; int i; - if (s->scale_norm > s->active_inputs) { - s->scale_norm -= nb_samples / (s->dropout_transition * s->sample_rate); - s->scale_norm = FFMAX(s->scale_norm, s->active_inputs); + for (i = 0; i < s->nb_inputs; i++) + if (s->input_state[i] & INPUT_ON) + weight_sum += s->weights[i]; + + for (i = 0; i < s->nb_inputs; i++) { + if (s->input_state[i] & INPUT_ON) { + if (s->scale_norm[i] > weight_sum / s->weights[i]) { + s->scale_norm[i] -= ((s->weight_sum / s->weights[i]) / s->nb_inputs) * + nb_samples / (s->dropout_transition * s->sample_rate); + s->scale_norm[i] = FFMAX(s->scale_norm[i], weight_sum / s->weights[i]); + } + } } for (i = 0; i < s->nb_inputs; i++) { if (s->input_state[i] & INPUT_ON) - s->input_scale[i] = 1.0f / s->scale_norm; + s->input_scale[i] = 1.0f / s->scale_norm[i]; else s->input_scale[i] = 0.0f; } @@ -251,9 +266,11 @@ static int config_output(AVFilterLink *outlink) s->active_inputs = s->nb_inputs; s->input_scale = av_mallocz_array(s->nb_inputs, sizeof(*s->input_scale)); - if (!s->input_scale) + s->scale_norm = av_mallocz_array(s->nb_inputs, sizeof(*s->scale_norm)); + if (!s->input_scale || !s->scale_norm) return AVERROR(ENOMEM); - s->scale_norm = s->active_inputs; + for (i = 0; i < s->nb_inputs; i++) + s->scale_norm[i] = s->weight_sum / s->weights[i]; calculate_scales(s, 0); av_get_channel_layout_string(buf, sizeof(buf), -1, outlink->channel_layout); @@ -487,15 +504,15 @@ static int activate(AVFilterContext *ctx) static av_cold int init(AVFilterContext *ctx) { MixContext *s = ctx->priv; + char *p, *arg, *saveptr = NULL; + float last_weight = 1.f; int i, ret; for (i = 0; i < s->nb_inputs; i++) { - char name[32]; AVFilterPad pad = { 0 }; - snprintf(name, sizeof(name), "input%d", i); pad.type = AVMEDIA_TYPE_AUDIO; - pad.name = av_strdup(name); + pad.name = av_asprintf("input%d", i); if (!pad.name) return AVERROR(ENOMEM); @@ -509,6 +526,26 @@ static av_cold int init(AVFilterContext *ctx) if (!s->fdsp) return AVERROR(ENOMEM); + s->weights = av_mallocz_array(s->nb_inputs, sizeof(*s->weights)); + if (!s->weights) + return AVERROR(ENOMEM); + + p = s->weights_str; + for (i = 0; i < s->nb_inputs; i++) { + if (!(arg = av_strtok(p, " ", &saveptr))) + break; + + p = NULL; + sscanf(arg, "%f", &last_weight); + s->weights[i] = last_weight; + s->weight_sum += last_weight; + } + + for (; i < s->nb_inputs; i++) { + s->weights[i] = last_weight; + s->weight_sum += last_weight; + } + return 0; } @@ -526,6 +563,8 @@ static av_cold void uninit(AVFilterContext *ctx) av_freep(&s->frame_list); av_freep(&s->input_state); av_freep(&s->input_scale); + av_freep(&s->scale_norm); + av_freep(&s->weights); av_freep(&s->fdsp); for (i = 0; i < ctx->nb_inputs; i++) diff --git a/libavfilter/af_aphaser.c b/libavfilter/af_aphaser.c index dcffc216dd3dc..bf46cc8fab775 100644 --- a/libavfilter/af_aphaser.c +++ b/libavfilter/af_aphaser.c @@ -247,7 +247,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inbuf) if (av_frame_is_writable(inbuf)) { outbuf = inbuf; } else { - outbuf = ff_get_audio_buffer(inlink, inbuf->nb_samples); + outbuf = ff_get_audio_buffer(outlink, inbuf->nb_samples); if (!outbuf) { av_frame_free(&inbuf); return AVERROR(ENOMEM); diff --git a/libavfilter/af_asetnsamples.c b/libavfilter/af_asetnsamples.c index 3c2f66b30aa48..ecb76e64db4a4 100644 --- a/libavfilter/af_asetnsamples.c +++ b/libavfilter/af_asetnsamples.c @@ -140,11 +140,14 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) return -1; } } - av_audio_fifo_write(asns->fifo, (void **)insamples->extended_data, nb_samples); - if (asns->next_out_pts == AV_NOPTS_VALUE) + ret = av_audio_fifo_write(asns->fifo, (void **)insamples->extended_data, nb_samples); + if (ret > 0 && asns->next_out_pts == AV_NOPTS_VALUE) asns->next_out_pts = insamples->pts; av_frame_free(&insamples); + if (ret < 0) + return ret; + while (av_audio_fifo_size(asns->fifo) >= asns->nb_out_samples) push_samples(outlink); return 0; diff --git a/libavfilter/af_biquads.c b/libavfilter/af_biquads.c index c4f619a423930..d5c3823e6446c 100644 --- a/libavfilter/af_biquads.c +++ b/libavfilter/af_biquads.c @@ -73,7 +73,6 @@ enum FilterType { equalizer, bass, treble, - band, bandpass, bandreject, allpass, @@ -87,6 +86,8 @@ enum WidthType { OCTAVE, QFACTOR, SLOPE, + KHERTZ, + NB_WTYPE, }; typedef struct ChanCache { @@ -237,7 +238,7 @@ BIQUAD_FILTER(s32, int32_t, INT32_MIN, INT32_MAX, 1) BIQUAD_FILTER(flt, float, -1., 1., 0) BIQUAD_FILTER(dbl, double, -1., 1., 0) -static int config_output(AVFilterLink *outlink) +static int config_filter(AVFilterLink *outlink, int reset) { AVFilterContext *ctx = outlink->src; BiquadsContext *s = ctx->priv; @@ -260,6 +261,9 @@ static int config_output(AVFilterLink *outlink) case HERTZ: alpha = sin(w0) / (2 * s->frequency / s->width); break; + case KHERTZ: + alpha = sin(w0) / (2 * s->frequency / (s->width * 1000)); + break; case OCTAVE: alpha = sin(w0) * sinh(log(2.) / 2 * s->width * w0 / sin(w0)); break; @@ -371,16 +375,20 @@ static int config_output(AVFilterLink *outlink) av_assert0(0); } + av_log(ctx, AV_LOG_VERBOSE, "a=%lf %lf %lf:b=%lf %lf %lf\n", s->a0, s->a1, s->a2, s->b0, s->b1, s->b2); + s->a1 /= s->a0; s->a2 /= s->a0; s->b0 /= s->a0; s->b1 /= s->a0; s->b2 /= s->a0; + s->a0 /= s->a0; s->cache = av_realloc_f(s->cache, sizeof(ChanCache), inlink->channels); if (!s->cache) return AVERROR(ENOMEM); - memset(s->cache, 0, sizeof(ChanCache) * inlink->channels); + if (reset) + memset(s->cache, 0, sizeof(ChanCache) * inlink->channels); switch (inlink->format) { case AV_SAMPLE_FMT_S16P: s->filter = biquad_s16; break; @@ -395,6 +403,11 @@ static int config_output(AVFilterLink *outlink) return 0; } +static int config_output(AVFilterLink *outlink) +{ + return config_filter(outlink, 1); +} + static int filter_frame(AVFilterLink *inlink, AVFrame *buf) { AVFilterContext *ctx = inlink->dst; @@ -407,7 +420,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf) if (av_frame_is_writable(buf)) { out_buf = buf; } else { - out_buf = ff_get_audio_buffer(inlink, nb_samples); + out_buf = ff_get_audio_buffer(outlink, nb_samples); if (!out_buf) { av_frame_free(&buf); return AVERROR(ENOMEM); @@ -438,6 +451,117 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf) return ff_filter_frame(outlink, out_buf); } +static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, + char *res, int res_len, int flags) +{ + BiquadsContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; + + if ((!strcmp(cmd, "frequency") || !strcmp(cmd, "f")) && + (s->filter_type == equalizer || + s->filter_type == bass || + s->filter_type == treble || + s->filter_type == bandpass || + s->filter_type == bandreject|| + s->filter_type == lowpass || + s->filter_type == highpass || + s->filter_type == allpass)) { + double freq; + + if (sscanf(args, "%lf", &freq) != 1) { + av_log(ctx, AV_LOG_ERROR, "Invalid frequency value.\n"); + return AVERROR(EINVAL); + } + + s->frequency = freq; + } else if ((!strcmp(cmd, "gain") || !strcmp(cmd, "g")) && + (s->filter_type == equalizer || + s->filter_type == bass || + s->filter_type == treble)) { + double gain; + + if (sscanf(args, "%lf", &gain) != 1) { + av_log(ctx, AV_LOG_ERROR, "Invalid gain value.\n"); + return AVERROR(EINVAL); + } + + s->gain = gain; + } else if ((!strcmp(cmd, "width") || !strcmp(cmd, "w")) && + (s->filter_type == equalizer || + s->filter_type == bass || + s->filter_type == treble || + s->filter_type == bandpass || + s->filter_type == bandreject|| + s->filter_type == lowpass || + s->filter_type == highpass || + s->filter_type == allpass)) { + double width; + + if (sscanf(args, "%lf", &width) != 1) { + av_log(ctx, AV_LOG_ERROR, "Invalid width value.\n"); + return AVERROR(EINVAL); + } + + s->width = width; + } else if ((!strcmp(cmd, "width_type") || !strcmp(cmd, "t")) && + (s->filter_type == equalizer || + s->filter_type == bass || + s->filter_type == treble || + s->filter_type == bandpass || + s->filter_type == bandreject|| + s->filter_type == lowpass || + s->filter_type == highpass || + s->filter_type == allpass)) { + char width_type; + + if (sscanf(args, "%c", &width_type) != 1) { + av_log(ctx, AV_LOG_ERROR, "Invalid width_type value.\n"); + return AVERROR(EINVAL); + } + + switch (width_type) { + case 'h': width_type = HERTZ; break; + case 'q': width_type = QFACTOR; break; + case 'o': width_type = OCTAVE; break; + case 's': width_type = SLOPE; break; + case 'k': width_type = KHERTZ; break; + default: + av_log(ctx, AV_LOG_ERROR, "Invalid width_type value: %c\n", width_type); + return AVERROR(EINVAL); + } + + s->width_type = width_type; + } else if ((!strcmp(cmd, "a0") || + !strcmp(cmd, "a1") || + !strcmp(cmd, "a2") || + !strcmp(cmd, "b0") || + !strcmp(cmd, "b1") || + !strcmp(cmd, "b2")) && + s->filter_type == biquad) { + double value; + + if (sscanf(args, "%lf", &value) != 1) { + av_log(ctx, AV_LOG_ERROR, "Invalid biquad value.\n"); + return AVERROR(EINVAL); + } + + if (!strcmp(cmd, "a0")) + s->a0 = value; + else if (!strcmp(cmd, "a1")) + s->a1 = value; + else if (!strcmp(cmd, "a2")) + s->a2 = value; + else if (!strcmp(cmd, "b0")) + s->b0 = value; + else if (!strcmp(cmd, "b1")) + s->b1 = value; + else if (!strcmp(cmd, "b2")) + s->b2 = value; + } + + return config_filter(outlink, 0); +} + static av_cold void uninit(AVFilterContext *ctx) { BiquadsContext *s = ctx->priv; @@ -486,20 +610,22 @@ AVFilter ff_af_##name_ = { \ .inputs = inputs, \ .outputs = outputs, \ .priv_class = &name_##_class, \ + .process_command = process_command, \ } #if CONFIG_EQUALIZER_FILTER static const AVOption equalizer_options[] = { {"frequency", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 999999, FLAGS}, {"f", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=0}, 0, 999999, FLAGS}, - {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, - {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, + {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, + {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"}, {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"}, {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"}, {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"}, - {"width", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 999, FLAGS}, - {"w", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 999, FLAGS}, + {"k", "kHz", 0, AV_OPT_TYPE_CONST, {.i64=KHERTZ}, 0, 0, FLAGS, "width_type"}, + {"width", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 99999, FLAGS}, + {"w", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0, 99999, FLAGS}, {"gain", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS}, {"g", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS}, {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, @@ -513,12 +639,13 @@ DEFINE_BIQUAD_FILTER(equalizer, "Apply two-pole peaking equalization (EQ) filter static const AVOption bass_options[] = { {"frequency", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=100}, 0, 999999, FLAGS}, {"f", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=100}, 0, 999999, FLAGS}, - {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, - {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, + {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, + {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"}, {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"}, {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"}, {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"}, + {"k", "kHz", 0, AV_OPT_TYPE_CONST, {.i64=KHERTZ}, 0, 0, FLAGS, "width_type"}, {"width", "set shelf transition steep", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, {"w", "set shelf transition steep", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, {"gain", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS}, @@ -534,12 +661,13 @@ DEFINE_BIQUAD_FILTER(bass, "Boost or cut lower frequencies."); static const AVOption treble_options[] = { {"frequency", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS}, {"f", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS}, - {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, - {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, + {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, + {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"}, {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"}, {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"}, {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"}, + {"k", "kHz", 0, AV_OPT_TYPE_CONST, {.i64=KHERTZ}, 0, 0, FLAGS, "width_type"}, {"width", "set shelf transition steep", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, {"w", "set shelf transition steep", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, {"gain", "set gain", OFFSET(gain), AV_OPT_TYPE_DOUBLE, {.dbl=0}, -900, 900, FLAGS}, @@ -555,14 +683,15 @@ DEFINE_BIQUAD_FILTER(treble, "Boost or cut upper frequencies."); static const AVOption bandpass_options[] = { {"frequency", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS}, {"f", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS}, - {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, - {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, + {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, + {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"}, {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"}, {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"}, {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"}, - {"width", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 999, FLAGS}, - {"w", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 999, FLAGS}, + {"k", "kHz", 0, AV_OPT_TYPE_CONST, {.i64=KHERTZ}, 0, 0, FLAGS, "width_type"}, + {"width", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, + {"w", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, {"csg", "use constant skirt gain", OFFSET(csg), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS}, {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {"c", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, @@ -575,14 +704,15 @@ DEFINE_BIQUAD_FILTER(bandpass, "Apply a two-pole Butterworth band-pass filter.") static const AVOption bandreject_options[] = { {"frequency", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS}, {"f", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS}, - {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, - {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, + {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, + {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"}, {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"}, {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"}, {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"}, - {"width", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 999, FLAGS}, - {"w", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 999, FLAGS}, + {"k", "kHz", 0, AV_OPT_TYPE_CONST, {.i64=KHERTZ}, 0, 0, FLAGS, "width_type"}, + {"width", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, + {"w", "set band-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.5}, 0, 99999, FLAGS}, {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {"c", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {NULL} @@ -594,12 +724,13 @@ DEFINE_BIQUAD_FILTER(bandreject, "Apply a two-pole Butterworth band-reject filte static const AVOption lowpass_options[] = { {"frequency", "set frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=500}, 0, 999999, FLAGS}, {"f", "set frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=500}, 0, 999999, FLAGS}, - {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, - {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, + {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, + {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"}, {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"}, {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"}, {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"}, + {"k", "kHz", 0, AV_OPT_TYPE_CONST, {.i64=KHERTZ}, 0, 0, FLAGS, "width_type"}, {"width", "set width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.707}, 0, 99999, FLAGS}, {"w", "set width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.707}, 0, 99999, FLAGS}, {"poles", "set number of poles", OFFSET(poles), AV_OPT_TYPE_INT, {.i64=2}, 1, 2, FLAGS}, @@ -615,12 +746,13 @@ DEFINE_BIQUAD_FILTER(lowpass, "Apply a low-pass filter with 3dB point frequency. static const AVOption highpass_options[] = { {"frequency", "set frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS}, {"f", "set frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS}, - {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, - {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, SLOPE, FLAGS, "width_type"}, + {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, + {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=QFACTOR}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"}, {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"}, {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"}, {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"}, + {"k", "kHz", 0, AV_OPT_TYPE_CONST, {.i64=KHERTZ}, 0, 0, FLAGS, "width_type"}, {"width", "set width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.707}, 0, 99999, FLAGS}, {"w", "set width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=0.707}, 0, 99999, FLAGS}, {"poles", "set number of poles", OFFSET(poles), AV_OPT_TYPE_INT, {.i64=2}, 1, 2, FLAGS}, @@ -636,12 +768,13 @@ DEFINE_BIQUAD_FILTER(highpass, "Apply a high-pass filter with 3dB point frequenc static const AVOption allpass_options[] = { {"frequency", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS}, {"f", "set central frequency", OFFSET(frequency), AV_OPT_TYPE_DOUBLE, {.dbl=3000}, 0, 999999, FLAGS}, - {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=HERTZ}, HERTZ, SLOPE, FLAGS, "width_type"}, - {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=HERTZ}, HERTZ, SLOPE, FLAGS, "width_type"}, + {"width_type", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=HERTZ}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, + {"t", "set filter-width type", OFFSET(width_type), AV_OPT_TYPE_INT, {.i64=HERTZ}, HERTZ, NB_WTYPE-1, FLAGS, "width_type"}, {"h", "Hz", 0, AV_OPT_TYPE_CONST, {.i64=HERTZ}, 0, 0, FLAGS, "width_type"}, {"q", "Q-Factor", 0, AV_OPT_TYPE_CONST, {.i64=QFACTOR}, 0, 0, FLAGS, "width_type"}, {"o", "octave", 0, AV_OPT_TYPE_CONST, {.i64=OCTAVE}, 0, 0, FLAGS, "width_type"}, {"s", "slope", 0, AV_OPT_TYPE_CONST, {.i64=SLOPE}, 0, 0, FLAGS, "width_type"}, + {"k", "kHz", 0, AV_OPT_TYPE_CONST, {.i64=KHERTZ}, 0, 0, FLAGS, "width_type"}, {"width", "set filter-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=707.1}, 0, 99999, FLAGS}, {"w", "set filter-width", OFFSET(width), AV_OPT_TYPE_DOUBLE, {.dbl=707.1}, 0, 99999, FLAGS}, {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, @@ -653,12 +786,12 @@ DEFINE_BIQUAD_FILTER(allpass, "Apply a two-pole all-pass filter."); #endif /* CONFIG_ALLPASS_FILTER */ #if CONFIG_BIQUAD_FILTER static const AVOption biquad_options[] = { - {"a0", NULL, OFFSET(a0), AV_OPT_TYPE_DOUBLE, {.dbl=1}, INT16_MIN, INT16_MAX, FLAGS}, - {"a1", NULL, OFFSET(a1), AV_OPT_TYPE_DOUBLE, {.dbl=1}, INT16_MIN, INT16_MAX, FLAGS}, - {"a2", NULL, OFFSET(a2), AV_OPT_TYPE_DOUBLE, {.dbl=1}, INT16_MIN, INT16_MAX, FLAGS}, - {"b0", NULL, OFFSET(b0), AV_OPT_TYPE_DOUBLE, {.dbl=1}, INT16_MIN, INT16_MAX, FLAGS}, - {"b1", NULL, OFFSET(b1), AV_OPT_TYPE_DOUBLE, {.dbl=1}, INT16_MIN, INT16_MAX, FLAGS}, - {"b2", NULL, OFFSET(b2), AV_OPT_TYPE_DOUBLE, {.dbl=1}, INT16_MIN, INT16_MAX, FLAGS}, + {"a0", NULL, OFFSET(a0), AV_OPT_TYPE_DOUBLE, {.dbl=1}, INT32_MIN, INT32_MAX, FLAGS}, + {"a1", NULL, OFFSET(a1), AV_OPT_TYPE_DOUBLE, {.dbl=0}, INT32_MIN, INT32_MAX, FLAGS}, + {"a2", NULL, OFFSET(a2), AV_OPT_TYPE_DOUBLE, {.dbl=0}, INT32_MIN, INT32_MAX, FLAGS}, + {"b0", NULL, OFFSET(b0), AV_OPT_TYPE_DOUBLE, {.dbl=0}, INT32_MIN, INT32_MAX, FLAGS}, + {"b1", NULL, OFFSET(b1), AV_OPT_TYPE_DOUBLE, {.dbl=0}, INT32_MIN, INT32_MAX, FLAGS}, + {"b2", NULL, OFFSET(b2), AV_OPT_TYPE_DOUBLE, {.dbl=0}, INT32_MIN, INT32_MAX, FLAGS}, {"channels", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {"c", "set channels to filter", OFFSET(channels), AV_OPT_TYPE_CHANNEL_LAYOUT, {.i64=-1}, INT64_MIN, INT64_MAX, FLAGS}, {NULL} diff --git a/libavfilter/af_bs2b.c b/libavfilter/af_bs2b.c index b7cfd3815b0b2..c01b983cd3668 100644 --- a/libavfilter/af_bs2b.c +++ b/libavfilter/af_bs2b.c @@ -32,6 +32,8 @@ #include "formats.h" #include "internal.h" +typedef void (*filter_func)(t_bs2bdp bs2bdp, uint8_t *sample, int n); + typedef struct Bs2bContext { const AVClass *class; @@ -41,7 +43,7 @@ typedef struct Bs2bContext { t_bs2bdp bs2bp; - void (*filter)(t_bs2bdp bs2bdp, uint8_t *sample, int n); + filter_func filter; } Bs2bContext; #define OFFSET(x) offsetof(Bs2bContext, x) @@ -133,7 +135,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) if (av_frame_is_writable(frame)) { out_frame = frame; } else { - out_frame = ff_get_audio_buffer(inlink, frame->nb_samples); + out_frame = ff_get_audio_buffer(outlink, frame->nb_samples); if (!out_frame) { av_frame_free(&frame); return AVERROR(ENOMEM); @@ -165,19 +167,19 @@ static int config_output(AVFilterLink *outlink) switch (inlink->format) { case AV_SAMPLE_FMT_U8: - bs2b->filter = bs2b_cross_feed_u8; + bs2b->filter = (filter_func) bs2b_cross_feed_u8; break; case AV_SAMPLE_FMT_S16: - bs2b->filter = (void*)bs2b_cross_feed_s16; + bs2b->filter = (filter_func) bs2b_cross_feed_s16; break; case AV_SAMPLE_FMT_S32: - bs2b->filter = (void*)bs2b_cross_feed_s32; + bs2b->filter = (filter_func) bs2b_cross_feed_s32; break; case AV_SAMPLE_FMT_FLT: - bs2b->filter = (void*)bs2b_cross_feed_f; + bs2b->filter = (filter_func) bs2b_cross_feed_f; break; case AV_SAMPLE_FMT_DBL: - bs2b->filter = (void*)bs2b_cross_feed_d; + bs2b->filter = (filter_func) bs2b_cross_feed_d; break; default: return AVERROR_BUG; diff --git a/libavfilter/af_channelmap.c b/libavfilter/af_channelmap.c index 7c2be95bfd43c..285d76a3ef3ef 100644 --- a/libavfilter/af_channelmap.c +++ b/libavfilter/af_channelmap.c @@ -149,13 +149,6 @@ static av_cold int channelmap_init(AVFilterContext *ctx) else mode = MAP_PAIR_STR_STR; } -#if FF_API_OLD_FILTER_OPTS - if (strchr(mapping, ',')) { - av_log(ctx, AV_LOG_WARNING, "This syntax is deprecated, use " - "'|' to separate the mappings.\n"); - separator = ','; - } -#endif } if (mode != MAP_NONE) { diff --git a/libavfilter/af_channelsplit.c b/libavfilter/af_channelsplit.c index 8c6b00fe4f507..821bb73801414 100644 --- a/libavfilter/af_channelsplit.c +++ b/libavfilter/af_channelsplit.c @@ -38,6 +38,9 @@ typedef struct ChannelSplitContext { uint64_t channel_layout; char *channel_layout_str; + char *channels_str; + + int map[64]; } ChannelSplitContext; #define OFFSET(x) offsetof(ChannelSplitContext, x) @@ -45,6 +48,7 @@ typedef struct ChannelSplitContext { #define F AV_OPT_FLAG_FILTERING_PARAM static const AVOption channelsplit_options[] = { { "channel_layout", "Input channel layout.", OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, { .str = "stereo" }, .flags = A|F }, + { "channels", "Channels to extract.", OFFSET(channels_str), AV_OPT_TYPE_STRING, { .str = "all" }, .flags = A|F }, { NULL } }; @@ -53,8 +57,9 @@ AVFILTER_DEFINE_CLASS(channelsplit); static av_cold int init(AVFilterContext *ctx) { ChannelSplitContext *s = ctx->priv; + uint64_t channel_layout; int nb_channels; - int ret = 0, i; + int all = 0, ret = 0, i; if (!(s->channel_layout = av_get_channel_layout(s->channel_layout_str))) { av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout '%s'.\n", @@ -63,14 +68,35 @@ static av_cold int init(AVFilterContext *ctx) goto fail; } - nb_channels = av_get_channel_layout_nb_channels(s->channel_layout); + + if (!strcmp(s->channels_str, "all")) { + nb_channels = av_get_channel_layout_nb_channels(s->channel_layout); + channel_layout = s->channel_layout; + all = 1; + } else { + if ((ret = av_get_extended_channel_layout(s->channels_str, &channel_layout, &nb_channels)) < 0) + return ret; + } + for (i = 0; i < nb_channels; i++) { - uint64_t channel = av_channel_layout_extract_channel(s->channel_layout, i); + uint64_t channel = av_channel_layout_extract_channel(channel_layout, i); AVFilterPad pad = { 0 }; pad.type = AVMEDIA_TYPE_AUDIO; pad.name = av_get_channel_name(channel); + if (all) { + s->map[i] = i; + } else { + if ((ret = av_get_channel_layout_channel_index(s->channel_layout, channel)) < 0) { + av_log(ctx, AV_LOG_ERROR, "Channel name '%s' not present in channel layout '%s'.\n", + av_get_channel_name(channel), s->channel_layout_str); + return ret; + } + + s->map[i] = ret; + } + if ((ret = ff_insert_outpad(ctx, i, &pad)) < 0) { return ret; } @@ -96,7 +122,7 @@ static int query_formats(AVFilterContext *ctx) for (i = 0; i < ctx->nb_outputs; i++) { AVFilterChannelLayouts *out_layouts = NULL; - uint64_t channel = av_channel_layout_extract_channel(s->channel_layout, i); + uint64_t channel = av_channel_layout_extract_channel(s->channel_layout, s->map[i]); if ((ret = ff_add_channel_layout(&out_layouts, channel)) < 0 || (ret = ff_channel_layouts_ref(out_layouts, &ctx->outputs[i]->in_channel_layouts)) < 0) @@ -109,6 +135,7 @@ static int query_formats(AVFilterContext *ctx) static int filter_frame(AVFilterLink *inlink, AVFrame *buf) { AVFilterContext *ctx = inlink->dst; + ChannelSplitContext *s = ctx->priv; int i, ret = 0; for (i = 0; i < ctx->nb_outputs; i++) { @@ -119,9 +146,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf) break; } - buf_out->data[0] = buf_out->extended_data[0] = buf_out->extended_data[i]; + buf_out->data[0] = buf_out->extended_data[0] = buf_out->extended_data[s->map[i]]; buf_out->channel_layout = - av_channel_layout_extract_channel(buf->channel_layout, i); + av_channel_layout_extract_channel(buf->channel_layout, s->map[i]); buf_out->channels = 1; ret = ff_filter_frame(ctx->outputs[i], buf_out); diff --git a/libavfilter/af_chorus.c b/libavfilter/af_chorus.c index 87c82900970ba..29c47ab14a6c8 100644 --- a/libavfilter/af_chorus.c +++ b/libavfilter/af_chorus.c @@ -247,7 +247,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) if (av_frame_is_writable(frame)) { out_frame = frame; } else { - out_frame = ff_get_audio_buffer(inlink, frame->nb_samples); + out_frame = ff_get_audio_buffer(ctx->outputs[0], frame->nb_samples); if (!out_frame) { av_frame_free(&frame); return AVERROR(ENOMEM); diff --git a/libavfilter/af_compand.c b/libavfilter/af_compand.c index 8589b1ef094b5..c138f0b1d8f97 100644 --- a/libavfilter/af_compand.c +++ b/libavfilter/af_compand.c @@ -185,7 +185,7 @@ static int compand_nodelay(AVFilterContext *ctx, AVFrame *frame) if (av_frame_is_writable(frame)) { out_frame = frame; } else { - out_frame = ff_get_audio_buffer(inlink, nb_samples); + out_frame = ff_get_audio_buffer(ctx->outputs[0], nb_samples); if (!out_frame) { av_frame_free(&frame); return AVERROR(ENOMEM); @@ -249,7 +249,7 @@ static int compand_delay(AVFilterContext *ctx, AVFrame *frame) if (count >= s->delay_samples) { if (!out_frame) { - out_frame = ff_get_audio_buffer(inlink, nb_samples - i); + out_frame = ff_get_audio_buffer(ctx->outputs[0], nb_samples - i); if (!out_frame) { av_frame_free(&frame); return AVERROR(ENOMEM); diff --git a/libavfilter/af_compensationdelay.c b/libavfilter/af_compensationdelay.c index d5a3484317163..05285cd29757b 100644 --- a/libavfilter/af_compensationdelay.c +++ b/libavfilter/af_compensationdelay.c @@ -131,7 +131,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) AVFrame *out; int n, ch; - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(ctx->outputs[0], in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_crossfeed.c b/libavfilter/af_crossfeed.c index d3def92fb39a9..a0af280432600 100644 --- a/libavfilter/af_crossfeed.c +++ b/libavfilter/af_crossfeed.c @@ -99,7 +99,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_crystalizer.c b/libavfilter/af_crystalizer.c index dec30aa5f48a3..5b27e1fb797db 100644 --- a/libavfilter/af_crystalizer.c +++ b/libavfilter/af_crystalizer.c @@ -173,7 +173,7 @@ static void filter_dblp(void **d, void **p, const void **s, static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; - CrystalizerContext *s = ctx->priv; + CrystalizerContext *s = ctx->priv; switch (inlink->format) { case AV_SAMPLE_FMT_FLT: s->filter = filter_flt; break; @@ -203,7 +203,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_dcshift.c b/libavfilter/af_dcshift.c index 6d33daee0b62b..e007efe05e446 100644 --- a/libavfilter/af_dcshift.c +++ b/libavfilter/af_dcshift.c @@ -28,7 +28,7 @@ typedef struct DCShiftContext { const AVClass *class; double dcshift; - double limiterthreshhold; + double limiterthreshold; double limitergain; } DCShiftContext; @@ -47,7 +47,7 @@ static av_cold int init(AVFilterContext *ctx) { DCShiftContext *s = ctx->priv; - s->limiterthreshhold = INT32_MAX * (1.0 - (fabs(s->dcshift) - s->limitergain)); + s->limiterthreshold = INT32_MAX * (1.0 - (fabs(s->dcshift) - s->limitergain)); return 0; } @@ -111,14 +111,14 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) d = src[j]; - if (d > s->limiterthreshhold && dcshift > 0) { - d = (d - s->limiterthreshhold) * s->limitergain / - (INT32_MAX - s->limiterthreshhold) + - s->limiterthreshhold + dcshift; - } else if (d < -s->limiterthreshhold && dcshift < 0) { - d = (d + s->limiterthreshhold) * s->limitergain / - (INT32_MAX - s->limiterthreshhold) - - s->limiterthreshhold + dcshift; + if (d > s->limiterthreshold && dcshift > 0) { + d = (d - s->limiterthreshold) * s->limitergain / + (INT32_MAX - s->limiterthreshold) + + s->limiterthreshold + dcshift; + } else if (d < -s->limiterthreshold && dcshift < 0) { + d = (d + s->limiterthreshold) * s->limitergain / + (INT32_MAX - s->limiterthreshold) - + s->limiterthreshold + dcshift; } else { d = dcshift * INT32_MAX + d; } diff --git a/libavfilter/af_drmeter.c b/libavfilter/af_drmeter.c new file mode 100644 index 0000000000000..ecccb6518639d --- /dev/null +++ b/libavfilter/af_drmeter.c @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/ffmath.h" +#include "libavutil/opt.h" +#include "audio.h" +#include "avfilter.h" +#include "internal.h" + +typedef struct ChannelStats { + uint64_t nb_samples; + uint64_t blknum; + float peak; + float sum; + uint32_t peaks[10001]; + uint32_t rms[10001]; +} ChannelStats; + +typedef struct DRMeterContext { + const AVClass *class; + ChannelStats *chstats; + int nb_channels; + uint64_t tc_samples; + double time_constant; +} DRMeterContext; + +#define OFFSET(x) offsetof(DRMeterContext, x) +#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption drmeter_options[] = { + { "length", "set the window length", OFFSET(time_constant), AV_OPT_TYPE_DOUBLE, {.dbl=3}, .01, 10, FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(drmeter); + +static int query_formats(AVFilterContext *ctx) +{ + AVFilterFormats *formats; + AVFilterChannelLayouts *layouts; + static const enum AVSampleFormat sample_fmts[] = { + AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_FLT, + AV_SAMPLE_FMT_NONE + }; + int ret; + + layouts = ff_all_channel_counts(); + if (!layouts) + return AVERROR(ENOMEM); + ret = ff_set_common_channel_layouts(ctx, layouts); + if (ret < 0) + return ret; + + formats = ff_make_format_list(sample_fmts); + if (!formats) + return AVERROR(ENOMEM); + ret = ff_set_common_formats(ctx, formats); + if (ret < 0) + return ret; + + formats = ff_all_samplerates(); + if (!formats) + return AVERROR(ENOMEM); + return ff_set_common_samplerates(ctx, formats); +} + +static int config_output(AVFilterLink *outlink) +{ + DRMeterContext *s = outlink->src->priv; + + s->chstats = av_calloc(sizeof(*s->chstats), outlink->channels); + if (!s->chstats) + return AVERROR(ENOMEM); + s->nb_channels = outlink->channels; + s->tc_samples = s->time_constant * outlink->sample_rate + .5; + + return 0; +} + +static void finish_block(ChannelStats *p) +{ + int peak_bin, rms_bin; + float peak, rms; + + rms = sqrt(2 * p->sum / p->nb_samples); + peak = p->peak; + rms_bin = av_clip(rms * 10000, 0, 10000); + peak_bin = av_clip(peak * 10000, 0, 10000); + p->rms[rms_bin]++; + p->peaks[peak_bin]++; + + p->peak = 0; + p->sum = 0; + p->nb_samples = 0; + p->blknum++; +} + +static void update_stat(DRMeterContext *s, ChannelStats *p, float sample) +{ + if (p->nb_samples >= s->tc_samples) { + finish_block(p); + } + + p->peak = FFMAX(FFABS(sample), p->peak); + p->sum += sample * sample; + p->nb_samples++; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *buf) +{ + DRMeterContext *s = inlink->dst->priv; + const int channels = s->nb_channels; + int i, c; + + switch (inlink->format) { + case AV_SAMPLE_FMT_FLTP: + for (c = 0; c < channels; c++) { + ChannelStats *p = &s->chstats[c]; + const float *src = (const float *)buf->extended_data[c]; + + for (i = 0; i < buf->nb_samples; i++, src++) + update_stat(s, p, *src); + } + break; + case AV_SAMPLE_FMT_FLT: { + const float *src = (const float *)buf->extended_data[0]; + + for (i = 0; i < buf->nb_samples; i++) { + for (c = 0; c < channels; c++, src++) + update_stat(s, &s->chstats[c], *src); + }} + break; + } + + return ff_filter_frame(inlink->dst->outputs[0], buf); +} + +#define SQR(a) ((a)*(a)) + +static void print_stats(AVFilterContext *ctx) +{ + DRMeterContext *s = ctx->priv; + float dr = 0; + int ch; + + for (ch = 0; ch < s->nb_channels; ch++) { + ChannelStats *p = &s->chstats[ch]; + float chdr, secondpeak, rmssum = 0; + int i, j, first = 0; + + finish_block(p); + + for (i = 0; i <= 10000; i++) { + if (p->peaks[10000 - i]) { + if (first) + break; + first = 1; + } + } + + secondpeak = (10000 - i) / 10000.; + + for (i = 10000, j = 0; i >= 0 && j < 0.2 * p->blknum; i--) { + if (p->rms[i]) { + rmssum += SQR(i / 10000.) * p->rms[i]; + j += p->rms[i]; + } + } + + chdr = 20 * log10(secondpeak / sqrt(rmssum / (0.2 * p->blknum))); + dr += chdr; + av_log(ctx, AV_LOG_INFO, "Channel %d: DR: %.1f\n", ch + 1, chdr); + } + + av_log(ctx, AV_LOG_INFO, "Overall DR: %.1f\n", dr / s->nb_channels); +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + DRMeterContext *s = ctx->priv; + + if (s->nb_channels) + print_stats(ctx); + av_freep(&s->chstats); +} + +static const AVFilterPad drmeter_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad drmeter_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .config_props = config_output, + }, + { NULL } +}; + +AVFilter ff_af_drmeter = { + .name = "drmeter", + .description = NULL_IF_CONFIG_SMALL("Measure audio dynamic range."), + .query_formats = query_formats, + .priv_size = sizeof(DRMeterContext), + .priv_class = &drmeter_class, + .uninit = uninit, + .inputs = drmeter_inputs, + .outputs = drmeter_outputs, +}; diff --git a/libavfilter/af_earwax.c b/libavfilter/af_earwax.c index 7b880c86c6e20..cdd2b4fc49c50 100644 --- a/libavfilter/af_earwax.c +++ b/libavfilter/af_earwax.c @@ -115,7 +115,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) { AVFilterLink *outlink = inlink->dst->outputs[0]; int16_t *taps, *endin, *in, *out; - AVFrame *outsamples = ff_get_audio_buffer(inlink, insamples->nb_samples); + AVFrame *outsamples = ff_get_audio_buffer(outlink, insamples->nb_samples); int len; if (!outsamples) { diff --git a/libavfilter/af_extrastereo.c b/libavfilter/af_extrastereo.c index a746006f7107f..13c6f4777679e 100644 --- a/libavfilter/af_extrastereo.c +++ b/libavfilter/af_extrastereo.c @@ -71,7 +71,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); @@ -90,9 +90,12 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) right = average + mult * (right - average); if (s->clip) { - dst[n * 2 ] = av_clipf(left, -1, 1); - dst[n * 2 + 1] = av_clipf(right, -1, 1); + left = av_clipf(left, -1, 1); + right = av_clipf(right, -1, 1); } + + dst[n * 2 ] = left; + dst[n * 2 + 1] = right; } if (out != in) diff --git a/libavfilter/af_flanger.c b/libavfilter/af_flanger.c index a92367c97a391..b7497a12eda7e 100644 --- a/libavfilter/af_flanger.c +++ b/libavfilter/af_flanger.c @@ -148,7 +148,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) if (av_frame_is_writable(frame)) { out_frame = frame; } else { - out_frame = ff_get_audio_buffer(inlink, frame->nb_samples); + out_frame = ff_get_audio_buffer(ctx->outputs[0], frame->nb_samples); if (!out_frame) { av_frame_free(&frame); return AVERROR(ENOMEM); diff --git a/libavfilter/af_haas.c b/libavfilter/af_haas.c index 691c251f54e08..0cfc93a7d1f24 100644 --- a/libavfilter/af_haas.c +++ b/libavfilter/af_haas.c @@ -144,7 +144,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_headphone.c b/libavfilter/af_headphone.c index 3b76d1d737054..79101322189c4 100644 --- a/libavfilter/af_headphone.c +++ b/libavfilter/af_headphone.c @@ -35,6 +35,9 @@ #define TIME_DOMAIN 0 #define FREQUENCY_DOMAIN 1 +#define HRIR_STEREO 0 +#define HRIR_MULTI 1 + typedef struct HeadphoneContext { const AVClass *class; @@ -64,6 +67,7 @@ typedef struct HeadphoneContext { int buffer_length; int n_fft; int size; + int hrir_fmt; int *delay[2]; float *data_ir[2]; @@ -130,14 +134,18 @@ static void parse_map(AVFilterContext *ctx) char buf[8]; p = NULL; - if (parse_channel_name(s, s->nb_inputs - 1, &arg, &out_ch_id, buf)) { + if (parse_channel_name(s, s->nb_irs, &arg, &out_ch_id, buf)) { av_log(ctx, AV_LOG_WARNING, "Failed to parse \'%s\' as channel name.\n", buf); continue; } - s->mapping[s->nb_inputs - 1] = out_ch_id; - s->nb_inputs++; + s->mapping[s->nb_irs] = out_ch_id; + s->nb_irs++; } - s->nb_irs = s->nb_inputs - 1; + + if (s->hrir_fmt == HRIR_MULTI) + s->nb_inputs = 2; + else + s->nb_inputs = s->nb_irs + 1; av_free(args); } @@ -324,16 +332,19 @@ static int read_ir(AVFilterLink *inlink, AVFrame *frame) { AVFilterContext *ctx = inlink->dst; HeadphoneContext *s = ctx->priv; - int ir_len, max_ir_len, input_number; + int ir_len, max_ir_len, input_number, ret; for (input_number = 0; input_number < s->nb_inputs; input_number++) if (inlink == ctx->inputs[input_number]) break; - av_audio_fifo_write(s->in[input_number].fifo, (void **)frame->extended_data, - frame->nb_samples); + ret = av_audio_fifo_write(s->in[input_number].fifo, (void **)frame->extended_data, + frame->nb_samples); av_frame_free(&frame); + if (ret < 0) + return ret; + ir_len = av_audio_fifo_size(s->in[input_number].fifo); max_ir_len = 65536; if (ir_len > max_ir_len) { @@ -346,7 +357,7 @@ static int read_ir(AVFilterLink *inlink, AVFrame *frame) return 0; } -static int headphone_frame(HeadphoneContext *s, AVFilterLink *outlink) +static int headphone_frame(HeadphoneContext *s, AVFilterLink *outlink, int max_nb_samples) { AVFilterContext *ctx = outlink->src; AVFrame *in = s->in[0].frame; @@ -380,6 +391,7 @@ static int headphone_frame(HeadphoneContext *s, AVFilterLink *outlink) n_clippings[0] + n_clippings[1], out->nb_samples * 2); } + out->nb_samples = max_nb_samples; return ff_filter_frame(outlink, out); } @@ -398,10 +410,10 @@ static int convert_coeffs(AVFilterContext *ctx, AVFilterLink *inlink) float *data_ir_r = NULL; int offset = 0, ret = 0; int n_fft; - int i, j; + int i, j, k; s->buffer_length = 1 << (32 - ff_clz(s->ir_len)); - s->n_fft = n_fft = 1 << (32 - ff_clz(s->ir_len + inlink->sample_rate)); + s->n_fft = n_fft = 1 << (32 - ff_clz(s->ir_len + s->size)); if (s->type == FREQUENCY_DOMAIN) { fft_in_l = av_calloc(n_fft, sizeof(*fft_in_l)); @@ -429,8 +441,8 @@ static int convert_coeffs(AVFilterContext *ctx, AVFilterLink *inlink) s->data_ir[0] = av_calloc(FFALIGN(s->ir_len, 16), sizeof(float) * s->nb_irs); s->data_ir[1] = av_calloc(FFALIGN(s->ir_len, 16), sizeof(float) * s->nb_irs); - s->delay[0] = av_malloc_array(s->nb_irs, sizeof(float)); - s->delay[1] = av_malloc_array(s->nb_irs, sizeof(float)); + s->delay[0] = av_calloc(s->nb_irs, sizeof(float)); + s->delay[1] = av_calloc(s->nb_irs, sizeof(float)); if (s->type == TIME_DOMAIN) { s->ringbuffer[0] = av_calloc(s->buffer_length, sizeof(float) * nb_input_channels); @@ -438,8 +450,8 @@ static int convert_coeffs(AVFilterContext *ctx, AVFilterLink *inlink) } else { s->ringbuffer[0] = av_calloc(s->buffer_length, sizeof(float)); s->ringbuffer[1] = av_calloc(s->buffer_length, sizeof(float)); - s->temp_fft[0] = av_malloc_array(s->n_fft, sizeof(FFTComplex)); - s->temp_fft[1] = av_malloc_array(s->n_fft, sizeof(FFTComplex)); + s->temp_fft[0] = av_calloc(s->n_fft, sizeof(FFTComplex)); + s->temp_fft[1] = av_calloc(s->n_fft, sizeof(FFTComplex)); if (!s->temp_fft[0] || !s->temp_fft[1]) { ret = AVERROR(ENOMEM); goto fail; @@ -457,7 +469,7 @@ static int convert_coeffs(AVFilterContext *ctx, AVFilterLink *inlink) ret = AVERROR(ENOMEM); goto fail; } - for (i = 0; i < s->nb_irs; i++) { + for (i = 0; i < s->nb_inputs - 1; i++) { s->in[i + 1].frame = ff_get_audio_buffer(ctx->inputs[i + 1], s->ir_len); if (!s->in[i + 1].frame) { ret = AVERROR(ENOMEM); @@ -476,59 +488,106 @@ static int convert_coeffs(AVFilterContext *ctx, AVFilterLink *inlink) goto fail; } } else { - data_hrtf_l = av_malloc_array(n_fft, sizeof(*data_hrtf_l) * nb_irs); - data_hrtf_r = av_malloc_array(n_fft, sizeof(*data_hrtf_r) * nb_irs); + data_hrtf_l = av_calloc(n_fft, sizeof(*data_hrtf_l) * nb_irs); + data_hrtf_r = av_calloc(n_fft, sizeof(*data_hrtf_r) * nb_irs); if (!data_hrtf_r || !data_hrtf_l) { ret = AVERROR(ENOMEM); goto fail; } } - for (i = 0; i < s->nb_irs; i++) { + for (i = 0; i < s->nb_inputs - 1; i++) { int len = s->in[i + 1].ir_len; int delay_l = s->in[i + 1].delay_l; int delay_r = s->in[i + 1].delay_r; - int idx = -1; float *ptr; - for (j = 0; j < inlink->channels; j++) { - if (s->mapping[i] < 0) { - continue; - } - - if ((av_channel_layout_extract_channel(inlink->channel_layout, j)) == (1LL << s->mapping[i])) { - idx = j; - break; - } - } - if (idx == -1) - continue; - av_audio_fifo_read(s->in[i + 1].fifo, (void **)s->in[i + 1].frame->extended_data, len); ptr = (float *)s->in[i + 1].frame->extended_data[0]; - if (s->type == TIME_DOMAIN) { - offset = idx * FFALIGN(len, 16); - for (j = 0; j < len; j++) { - data_ir_l[offset + j] = ptr[len * 2 - j * 2 - 2] * gain_lin; - data_ir_r[offset + j] = ptr[len * 2 - j * 2 - 1] * gain_lin; - } - } else { - memset(fft_in_l, 0, n_fft * sizeof(*fft_in_l)); - memset(fft_in_r, 0, n_fft * sizeof(*fft_in_r)); + if (s->hrir_fmt == HRIR_STEREO) { + int idx = -1; + + for (j = 0; j < inlink->channels; j++) { + if (s->mapping[i] < 0) { + continue; + } - offset = idx * n_fft; - for (j = 0; j < len; j++) { - fft_in_l[delay_l + j].re = ptr[j * 2 ] * gain_lin; - fft_in_r[delay_r + j].re = ptr[j * 2 + 1] * gain_lin; + if ((av_channel_layout_extract_channel(inlink->channel_layout, j)) == (1LL << s->mapping[i])) { + idx = i; + break; + } } - av_fft_permute(s->fft[0], fft_in_l); - av_fft_calc(s->fft[0], fft_in_l); - memcpy(data_hrtf_l + offset, fft_in_l, n_fft * sizeof(*fft_in_l)); - av_fft_permute(s->fft[0], fft_in_r); - av_fft_calc(s->fft[0], fft_in_r); - memcpy(data_hrtf_r + offset, fft_in_r, n_fft * sizeof(*fft_in_r)); + if (idx == -1) + continue; + if (s->type == TIME_DOMAIN) { + offset = idx * FFALIGN(len, 16); + for (j = 0; j < len; j++) { + data_ir_l[offset + j] = ptr[len * 2 - j * 2 - 2] * gain_lin; + data_ir_r[offset + j] = ptr[len * 2 - j * 2 - 1] * gain_lin; + } + } else { + memset(fft_in_l, 0, n_fft * sizeof(*fft_in_l)); + memset(fft_in_r, 0, n_fft * sizeof(*fft_in_r)); + + offset = idx * n_fft; + for (j = 0; j < len; j++) { + fft_in_l[delay_l + j].re = ptr[j * 2 ] * gain_lin; + fft_in_r[delay_r + j].re = ptr[j * 2 + 1] * gain_lin; + } + + av_fft_permute(s->fft[0], fft_in_l); + av_fft_calc(s->fft[0], fft_in_l); + memcpy(data_hrtf_l + offset, fft_in_l, n_fft * sizeof(*fft_in_l)); + av_fft_permute(s->fft[0], fft_in_r); + av_fft_calc(s->fft[0], fft_in_r); + memcpy(data_hrtf_r + offset, fft_in_r, n_fft * sizeof(*fft_in_r)); + } + } else { + int I, N = ctx->inputs[1]->channels; + + for (k = 0; k < N / 2; k++) { + int idx = -1; + + for (j = 0; j < inlink->channels; j++) { + if (s->mapping[k] < 0) { + continue; + } + + if ((av_channel_layout_extract_channel(inlink->channel_layout, j)) == (1LL << s->mapping[k])) { + idx = k; + break; + } + } + if (idx == -1) + continue; + + I = idx * 2; + if (s->type == TIME_DOMAIN) { + offset = idx * FFALIGN(len, 16); + for (j = 0; j < len; j++) { + data_ir_l[offset + j] = ptr[len * N - j * N - N + I ] * gain_lin; + data_ir_r[offset + j] = ptr[len * N - j * N - N + I + 1] * gain_lin; + } + } else { + memset(fft_in_l, 0, n_fft * sizeof(*fft_in_l)); + memset(fft_in_r, 0, n_fft * sizeof(*fft_in_r)); + + offset = idx * n_fft; + for (j = 0; j < len; j++) { + fft_in_l[delay_l + j].re = ptr[j * N + I ] * gain_lin; + fft_in_r[delay_r + j].re = ptr[j * N + I + 1] * gain_lin; + } + + av_fft_permute(s->fft[0], fft_in_l); + av_fft_calc(s->fft[0], fft_in_l); + memcpy(data_hrtf_l + offset, fft_in_l, n_fft * sizeof(*fft_in_l)); + av_fft_permute(s->fft[0], fft_in_r); + av_fft_calc(s->fft[0], fft_in_r); + memcpy(data_hrtf_r + offset, fft_in_r, n_fft * sizeof(*fft_in_r)); + } + } } } @@ -536,8 +595,8 @@ static int convert_coeffs(AVFilterContext *ctx, AVFilterLink *inlink) memcpy(s->data_ir[0], data_ir_l, sizeof(float) * nb_irs * FFALIGN(ir_len, 16)); memcpy(s->data_ir[1], data_ir_r, sizeof(float) * nb_irs * FFALIGN(ir_len, 16)); } else { - s->data_hrtf[0] = av_malloc_array(n_fft * s->nb_irs, sizeof(FFTComplex)); - s->data_hrtf[1] = av_malloc_array(n_fft * s->nb_irs, sizeof(FFTComplex)); + s->data_hrtf[0] = av_calloc(n_fft * s->nb_irs, sizeof(FFTComplex)); + s->data_hrtf[1] = av_calloc(n_fft * s->nb_irs, sizeof(FFTComplex)); if (!s->data_hrtf[0] || !s->data_hrtf[1]) { ret = AVERROR(ENOMEM); goto fail; @@ -572,13 +631,16 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) AVFilterLink *outlink = ctx->outputs[0]; int ret = 0; - av_audio_fifo_write(s->in[0].fifo, (void **)in->extended_data, - in->nb_samples); + ret = av_audio_fifo_write(s->in[0].fifo, (void **)in->extended_data, + in->nb_samples); if (s->pts == AV_NOPTS_VALUE) s->pts = in->pts; av_frame_free(&in); + if (ret < 0) + return ret; + if (!s->have_hrirs && s->eof_hrirs) { ret = convert_coeffs(ctx, inlink); if (ret < 0) @@ -587,12 +649,13 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (s->have_hrirs) { while (av_audio_fifo_size(s->in[0].fifo) >= s->size) { - ret = headphone_frame(s, outlink); + ret = headphone_frame(s, outlink, s->size); if (ret < 0) - break; + return ret; } } - return ret; + + return 0; } static int query_formats(AVFilterContext *ctx) @@ -600,6 +663,8 @@ static int query_formats(AVFilterContext *ctx) struct HeadphoneContext *s = ctx->priv; AVFilterFormats *formats = NULL; AVFilterChannelLayouts *layouts = NULL; + AVFilterChannelLayouts *stereo_layout = NULL; + AVFilterChannelLayouts *hrir_layouts = NULL; int ret, i; ret = ff_add_format(&formats, AV_SAMPLE_FMT_FLT); @@ -617,18 +682,26 @@ static int query_formats(AVFilterContext *ctx) if (ret) return ret; - layouts = NULL; - ret = ff_add_channel_layout(&layouts, AV_CH_LAYOUT_STEREO); + ret = ff_add_channel_layout(&stereo_layout, AV_CH_LAYOUT_STEREO); if (ret) return ret; - for (i = 1; i < s->nb_inputs; i++) { - ret = ff_channel_layouts_ref(layouts, &ctx->inputs[i]->out_channel_layouts); + if (s->hrir_fmt == HRIR_MULTI) { + hrir_layouts = ff_all_channel_counts(); + if (!hrir_layouts) + ret = AVERROR(ENOMEM); + ret = ff_channel_layouts_ref(hrir_layouts, &ctx->inputs[1]->out_channel_layouts); if (ret) return ret; + } else { + for (i = 1; i < s->nb_inputs; i++) { + ret = ff_channel_layouts_ref(stereo_layout, &ctx->inputs[i]->out_channel_layouts); + if (ret) + return ret; + } } - ret = ff_channel_layouts_ref(layouts, &ctx->outputs[0]->in_channel_layouts); + ret = ff_channel_layouts_ref(stereo_layout, &ctx->outputs[0]->in_channel_layouts); if (ret) return ret; @@ -643,14 +716,8 @@ static int config_input(AVFilterLink *inlink) AVFilterContext *ctx = inlink->dst; HeadphoneContext *s = ctx->priv; - if (s->type == FREQUENCY_DOMAIN) { - inlink->partial_buf_size = - inlink->min_samples = - inlink->max_samples = inlink->sample_rate; - } - if (s->nb_irs < inlink->channels) { - av_log(ctx, AV_LOG_ERROR, "Number of inputs must be >= %d.\n", inlink->channels + 1); + av_log(ctx, AV_LOG_ERROR, "Number of HRIRs must be >= %d.\n", inlink->channels); return AVERROR(EINVAL); } @@ -712,10 +779,14 @@ static int config_output(AVFilterLink *outlink) AVFilterLink *inlink = ctx->inputs[0]; int i; - if (s->type == TIME_DOMAIN) - s->size = 1024; - else - s->size = inlink->sample_rate; + if (s->hrir_fmt == HRIR_MULTI) { + AVFilterLink *hrir_link = ctx->inputs[1]; + + if (hrir_link->channels < inlink->channels * 2) { + av_log(ctx, AV_LOG_ERROR, "Number of channels in HRIR stream must be >= %d.\n", inlink->channels * 2); + return AVERROR(EINVAL); + } + } for (i = 0; i < s->nb_inputs; i++) { s->in[i].fifo = av_audio_fifo_alloc(ctx->inputs[i]->format, ctx->inputs[i]->channels, 1024); @@ -746,7 +817,31 @@ static int request_frame(AVFilterLink *outlink) s->eof_hrirs = 1; } } - return ff_request_frame(ctx->inputs[0]); + + ret = ff_request_frame(ctx->inputs[0]); + if (ret == AVERROR_EOF && av_audio_fifo_size(s->in[0].fifo) > 0 && s->have_hrirs) { + int nb_samples = av_audio_fifo_size(s->in[0].fifo); + AVFrame *in = ff_get_audio_buffer(ctx->inputs[0], s->size - nb_samples); + + if (!in) + return AVERROR(ENOMEM); + + av_samples_set_silence(in->extended_data, 0, + in->nb_samples, + in->channels, + in->format); + + ret = av_audio_fifo_write(s->in[0].fifo, (void **)in->extended_data, + in->nb_samples); + av_frame_free(&in); + if (ret < 0) + return ret; + ret = headphone_frame(s, outlink, nb_samples); + + av_audio_fifo_drain(s->in[0].fifo, av_audio_fifo_size(s->in[0].fifo)); + } + + return ret; } static av_cold void uninit(AVFilterContext *ctx) @@ -791,6 +886,10 @@ static const AVOption headphone_options[] = { { "type", "set processing", OFFSET(type), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, .flags = FLAGS, "type" }, { "time", "time domain", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, .flags = FLAGS, "type" }, { "freq", "frequency domain", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, .flags = FLAGS, "type" }, + { "size", "set frame size", OFFSET(size), AV_OPT_TYPE_INT, {.i64=1024},1024,96000, .flags = FLAGS }, + { "hrir", "set hrir format", OFFSET(hrir_fmt), AV_OPT_TYPE_INT, {.i64=HRIR_STEREO}, 0, 1, .flags = FLAGS, "hrir" }, + { "stereo", "hrir files have exactly 2 channels", 0, AV_OPT_TYPE_CONST, {.i64=HRIR_STEREO}, 0, 0, .flags = FLAGS, "hrir" }, + { "multich", "single multichannel hrir file", 0, AV_OPT_TYPE_CONST, {.i64=HRIR_MULTI}, 0, 0, .flags = FLAGS, "hrir" }, { NULL } }; diff --git a/libavfilter/af_join.c b/libavfilter/af_join.c index f8af0a180402b..4f86e13558417 100644 --- a/libavfilter/af_join.c +++ b/libavfilter/af_join.c @@ -32,6 +32,7 @@ #include "audio.h" #include "avfilter.h" #include "formats.h" +#include "filters.h" #include "internal.h" typedef struct ChannelMap { @@ -78,48 +79,12 @@ static const AVOption join_options[] = { AVFILTER_DEFINE_CLASS(join); -static int try_push_frame(AVFilterContext *ctx); - -static int filter_frame(AVFilterLink *link, AVFrame *frame) -{ - AVFilterContext *ctx = link->dst; - JoinContext *s = ctx->priv; - int i, j; - - for (i = 0; i < ctx->nb_inputs; i++) - if (link == ctx->inputs[i]) - break; - av_assert0(i < ctx->nb_inputs); - av_assert0(!s->input_frames[i]); - s->input_frames[i] = frame; - - /* request the same number of samples on all inputs */ - /* FIXME that means a frame arriving asynchronously on a different input - will not have the requested number of samples */ - if (i == 0) { - int nb_samples = s->input_frames[0]->nb_samples; - - for (j = 1; !i && j < ctx->nb_inputs; j++) - ctx->inputs[j]->request_samples = nb_samples; - } - - return try_push_frame(ctx); -} - static int parse_maps(AVFilterContext *ctx) { JoinContext *s = ctx->priv; char separator = '|'; char *cur = s->map; -#if FF_API_OLD_FILTER_OPTS - if (cur && strchr(cur, ',')) { - av_log(ctx, AV_LOG_WARNING, "This syntax is deprecated, use '|' to " - "separate the mappings.\n"); - separator = ','; - } -#endif - while (cur && *cur) { char *sep, *next, *p; uint64_t in_channel = 0, out_channel = 0; @@ -228,9 +193,6 @@ static av_cold int join_init(AVFilterContext *ctx) pad.name = av_strdup(name); if (!pad.name) return AVERROR(ENOMEM); - pad.filter_frame = filter_frame; - - pad.needs_fifo = 1; if ((ret = ff_insert_inpad(ctx, i, &pad)) < 0) { av_freep(&pad.name); @@ -398,21 +360,6 @@ static int join_config_output(AVFilterLink *outlink) return ret; } -static int join_request_frame(AVFilterLink *outlink) -{ - AVFilterContext *ctx = outlink->src; - JoinContext *s = ctx->priv; - int i; - - /* get a frame on each input */ - for (i = 0; i < ctx->nb_inputs; i++) { - AVFilterLink *inlink = ctx->inputs[i]; - if (!s->input_frames[i]) - return ff_request_frame(inlink); - } - return 0; -} - static int try_push_frame(AVFilterContext *ctx) { AVFilterLink *outlink = ctx->outputs[0]; @@ -428,6 +375,8 @@ static int try_push_frame(AVFilterContext *ctx) return 0; nb_samples = FFMIN(nb_samples, s->input_frames[i]->nb_samples); } + if (!nb_samples) + return 0; /* setup the output frame */ frame = av_frame_alloc(); @@ -516,12 +465,61 @@ static int try_push_frame(AVFilterContext *ctx) return ret; } +static int activate(AVFilterContext *ctx) +{ + JoinContext *s = ctx->priv; + int i, ret, status; + int nb_samples = 0; + int64_t pts; + + if (!s->input_frames[0]) { + ret = ff_inlink_consume_frame(ctx->inputs[0], &s->input_frames[0]); + if (ret < 0) { + return ret; + } else if (ff_inlink_acknowledge_status(ctx->inputs[0], &status, &pts)) { + ff_outlink_set_status(ctx->outputs[0], status, pts); + return 0; + } else { + if (ff_outlink_frame_wanted(ctx->outputs[0]) && !s->input_frames[0]) { + ff_inlink_request_frame(ctx->inputs[0]); + return 0; + } + } + if (!s->input_frames[0]) { + return 0; + } + } + + nb_samples = s->input_frames[0]->nb_samples; + + for (i = 1; i < ctx->nb_inputs && nb_samples > 0; i++) { + if (s->input_frames[i]) + continue; + + if (ff_inlink_check_available_samples(ctx->inputs[i], nb_samples) > 0) { + ret = ff_inlink_consume_samples(ctx->inputs[i], nb_samples, nb_samples, &s->input_frames[i]); + if (ret < 0) { + return ret; + } else if (ff_inlink_acknowledge_status(ctx->inputs[i], &status, &pts)) { + ff_outlink_set_status(ctx->outputs[0], status, pts); + return 0; + } + } else { + if (ff_outlink_frame_wanted(ctx->outputs[0])) { + ff_inlink_request_frame(ctx->inputs[i]); + return 0; + } + } + } + + return try_push_frame(ctx); +} + static const AVFilterPad avfilter_af_join_outputs[] = { { .name = "default", .type = AVMEDIA_TYPE_AUDIO, .config_props = join_config_output, - .request_frame = join_request_frame, }, { NULL } }; @@ -534,6 +532,7 @@ AVFilter ff_af_join = { .priv_class = &join_class, .init = join_init, .uninit = join_uninit, + .activate = activate, .query_formats = join_query_formats, .inputs = NULL, .outputs = avfilter_af_join_outputs, diff --git a/libavfilter/af_ladspa.c b/libavfilter/af_ladspa.c index 5532dacd73a71..3be26bc849db6 100644 --- a/libavfilter/af_ladspa.c +++ b/libavfilter/af_ladspa.c @@ -318,8 +318,6 @@ static int config_output(AVFilterLink *outlink) ret = 0; } else { - LADSPAContext *s = ctx->priv; - outlink->sample_rate = s->sample_rate; outlink->time_base = (AVRational){1, s->sample_rate}; diff --git a/libavfilter/af_loudnorm.c b/libavfilter/af_loudnorm.c index e3e815e2723fc..314b25fa39f5f 100644 --- a/libavfilter/af_loudnorm.c +++ b/libavfilter/af_loudnorm.c @@ -423,7 +423,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); @@ -431,6 +431,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) av_frame_copy_props(out, in); } + if (s->pts == AV_NOPTS_VALUE) + s->pts = in->pts; + out->pts = s->pts; src = (const double *)in->data[0]; dst = (double *)out->data[0]; @@ -763,7 +766,7 @@ static int config_input(AVFilterLink *inlink) inlink->partial_buf_size = frame_size(inlink->sample_rate, 3000); } - s->pts = + s->pts = AV_NOPTS_VALUE; s->buf_index = s->prev_buf_index = s->limiter_buf_index = 0; diff --git a/libavfilter/af_lv2.c b/libavfilter/af_lv2.c new file mode 100644 index 0000000000000..8a0a6fd8883af --- /dev/null +++ b/libavfilter/af_lv2.c @@ -0,0 +1,602 @@ +/* + * Copyright (c) 2017 Paul B Mahol + * Copyright (c) 2007-2016 David Robillard + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * LV2 wrapper + */ + +#include +#include +#include + +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/channel_layout.h" +#include "libavutil/opt.h" +#include "audio.h" +#include "avfilter.h" +#include "internal.h" + +typedef struct URITable { + char **uris; + size_t n_uris; +} URITable; + +typedef struct LV2Context { + const AVClass *class; + char *plugin_uri; + char *options; + + unsigned nb_inputs; + unsigned nb_inputcontrols; + unsigned nb_outputs; + + int sample_rate; + int nb_samples; + int64_t pts; + int64_t duration; + + LilvWorld *world; + const LilvPlugin *plugin; + uint32_t nb_ports; + float *values; + URITable uri_table; + LV2_URID_Map map; + LV2_Feature map_feature; + LV2_URID_Unmap unmap; + LV2_Feature unmap_feature; + LV2_Atom_Sequence seq_in[2]; + LV2_Atom_Sequence *seq_out; + const LV2_Feature *features[5]; + + float *mins; + float *maxes; + float *controls; + + LilvInstance *instance; + + LilvNode *atom_AtomPort; + LilvNode *atom_Sequence; + LilvNode *lv2_AudioPort; + LilvNode *lv2_CVPort; + LilvNode *lv2_ControlPort; + LilvNode *lv2_Optional; + LilvNode *lv2_InputPort; + LilvNode *lv2_OutputPort; + LilvNode *urid_map; + LilvNode *powerOf2BlockLength; + LilvNode *fixedBlockLength; + LilvNode *boundedBlockLength; +} LV2Context; + +#define OFFSET(x) offsetof(LV2Context, x) +#define FLAGS AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption lv2_options[] = { + { "plugin", "set plugin uri", OFFSET(plugin_uri), AV_OPT_TYPE_STRING, .flags = FLAGS }, + { "p", "set plugin uri", OFFSET(plugin_uri), AV_OPT_TYPE_STRING, .flags = FLAGS }, + { "controls", "set plugin options", OFFSET(options), AV_OPT_TYPE_STRING, .flags = FLAGS }, + { "c", "set plugin options", OFFSET(options), AV_OPT_TYPE_STRING, .flags = FLAGS }, + { "sample_rate", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64=44100}, 1, INT32_MAX, FLAGS }, + { "s", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64=44100}, 1, INT32_MAX, FLAGS }, + { "nb_samples", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, INT_MAX, FLAGS }, + { "n", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64=1024}, 1, INT_MAX, FLAGS }, + { "duration", "set audio duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64=-1}, -1, INT64_MAX, FLAGS }, + { "d", "set audio duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64=-1}, -1, INT64_MAX, FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(lv2); + +static void uri_table_init(URITable *table) +{ + table->uris = NULL; + table->n_uris = 0; +} + +static void uri_table_destroy(URITable *table) +{ + int i; + + for (i = 0; i < table->n_uris; i++) { + av_freep(&table->uris[i]); + } + + av_freep(&table->uris); +} + +static LV2_URID uri_table_map(LV2_URID_Map_Handle handle, const char *uri) +{ + URITable *table = (URITable*)handle; + const size_t len = strlen(uri); + size_t i; + char **tmp; + + for (i = 0; i < table->n_uris; i++) { + if (!strcmp(table->uris[i], uri)) { + return i + 1; + } + } + + tmp = av_calloc(table->n_uris + 1, sizeof(char*)); + if (!tmp) + return table->n_uris; + memcpy(tmp, table->uris, table->n_uris * sizeof(char**)); + + av_free(table->uris); + table->uris = tmp; + table->uris[table->n_uris] = av_malloc(len + 1); + if (!table->uris[table->n_uris]) + return table->n_uris; + + memcpy(table->uris[table->n_uris], uri, len + 1); + table->n_uris++; + + return table->n_uris; +} + +static const char *uri_table_unmap(LV2_URID_Map_Handle handle, LV2_URID urid) +{ + URITable *table = (URITable*)handle; + + if (urid > 0 && urid <= table->n_uris) { + return table->uris[urid - 1]; + } + + return NULL; +} + +static void connect_ports(LV2Context *s, AVFrame *in, AVFrame *out) +{ + int ich = 0, och = 0, i; + + for (i = 0; i < s->nb_ports; i++) { + const LilvPort *port = lilv_plugin_get_port_by_index(s->plugin, i); + + if (lilv_port_is_a(s->plugin, port, s->lv2_AudioPort) || + lilv_port_is_a(s->plugin, port, s->lv2_CVPort)) { + if (lilv_port_is_a(s->plugin, port, s->lv2_InputPort)) { + lilv_instance_connect_port(s->instance, i, in->extended_data[ich++]); + } else if (lilv_port_is_a(s->plugin, port, s->lv2_OutputPort)) { + lilv_instance_connect_port(s->instance, i, out->extended_data[och++]); + } else { + av_log(s, AV_LOG_WARNING, "port %d neither input nor output, skipping\n", i); + } + } else if (lilv_port_is_a(s->plugin, port, s->atom_AtomPort)) { + if (lilv_port_is_a(s->plugin, port, s->lv2_InputPort)) { + lilv_instance_connect_port(s->instance, i, &s->seq_in); + } else { + lilv_instance_connect_port(s->instance, i, s->seq_out); + } + } else if (lilv_port_is_a(s->plugin, port, s->lv2_ControlPort)) { + lilv_instance_connect_port(s->instance, i, &s->controls[i]); + } + } + + s->seq_in[0].atom.size = sizeof(LV2_Atom_Sequence_Body); + s->seq_in[0].atom.type = uri_table_map(&s->uri_table, LV2_ATOM__Sequence); + s->seq_out->atom.size = 9624; + s->seq_out->atom.type = uri_table_map(&s->uri_table, LV2_ATOM__Chunk); +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + LV2Context *s = ctx->priv; + AVFrame *out; + + if (!s->nb_outputs || + (av_frame_is_writable(in) && s->nb_inputs == s->nb_outputs)) { + out = in; + } else { + out = ff_get_audio_buffer(ctx->outputs[0], in->nb_samples); + if (!out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + av_frame_copy_props(out, in); + } + + connect_ports(s, in, out); + + lilv_instance_run(s->instance, in->nb_samples); + + if (out != in) + av_frame_free(&in); + + return ff_filter_frame(ctx->outputs[0], out); +} + +static int request_frame(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + LV2Context *s = ctx->priv; + AVFrame *out; + int64_t t; + + if (ctx->nb_inputs) + return ff_request_frame(ctx->inputs[0]); + + t = av_rescale(s->pts, AV_TIME_BASE, s->sample_rate); + if (s->duration >= 0 && t >= s->duration) + return AVERROR_EOF; + + out = ff_get_audio_buffer(outlink, s->nb_samples); + if (!out) + return AVERROR(ENOMEM); + + connect_ports(s, out, out); + + lilv_instance_run(s->instance, out->nb_samples); + + out->sample_rate = s->sample_rate; + out->pts = s->pts; + s->pts += s->nb_samples; + + return ff_filter_frame(outlink, out); +} + +static const LV2_Feature buf_size_features[3] = { + { LV2_BUF_SIZE__powerOf2BlockLength, NULL }, + { LV2_BUF_SIZE__fixedBlockLength, NULL }, + { LV2_BUF_SIZE__boundedBlockLength, NULL }, +}; + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + LV2Context *s = ctx->priv; + char *p, *arg, *saveptr = NULL; + int i, sample_rate; + + uri_table_init(&s->uri_table); + s->map.handle = &s->uri_table; + s->map.map = uri_table_map; + s->map_feature.URI = LV2_URID_MAP_URI; + s->map_feature.data = &s->map; + s->unmap.handle = &s->uri_table; + s->unmap.unmap = uri_table_unmap; + s->unmap_feature.URI = LV2_URID_UNMAP_URI; + s->unmap_feature.data = &s->unmap; + s->features[0] = &s->map_feature; + s->features[1] = &s->unmap_feature; + s->features[2] = &buf_size_features[0]; + s->features[3] = &buf_size_features[1]; + s->features[4] = &buf_size_features[2]; + + if (ctx->nb_inputs) { + AVFilterLink *inlink = ctx->inputs[0]; + + outlink->format = inlink->format; + outlink->sample_rate = sample_rate = inlink->sample_rate; + if (s->nb_inputs == s->nb_outputs) { + outlink->channel_layout = inlink->channel_layout; + outlink->channels = inlink->channels; + } + + } else { + outlink->sample_rate = sample_rate = s->sample_rate; + outlink->time_base = (AVRational){1, s->sample_rate}; + } + + s->instance = lilv_plugin_instantiate(s->plugin, sample_rate, s->features); + if (!s->instance) { + av_log(s, AV_LOG_ERROR, "Failed to instantiate <%s>\n", lilv_node_as_uri(lilv_plugin_get_uri(s->plugin))); + return AVERROR(EINVAL); + } + + s->mins = av_calloc(s->nb_ports, sizeof(float)); + s->maxes = av_calloc(s->nb_ports, sizeof(float)); + s->controls = av_calloc(s->nb_ports, sizeof(float)); + + if (!s->mins || !s->maxes || !s->controls) + return AVERROR(ENOMEM); + + lilv_plugin_get_port_ranges_float(s->plugin, s->mins, s->maxes, s->controls); + s->seq_out = av_malloc(sizeof(LV2_Atom_Sequence) + 9624); + if (!s->seq_out) + return AVERROR(ENOMEM); + + if (s->options && !strcmp(s->options, "help")) { + if (!s->nb_inputcontrols) { + av_log(ctx, AV_LOG_INFO, + "The '%s' plugin does not have any input controls.\n", + s->plugin_uri); + } else { + av_log(ctx, AV_LOG_INFO, + "The '%s' plugin has the following input controls:\n", + s->plugin_uri); + for (i = 0; i < s->nb_ports; i++) { + const LilvPort *port = lilv_plugin_get_port_by_index(s->plugin, i); + const LilvNode *symbol = lilv_port_get_symbol(s->plugin, port); + LilvNode *name = lilv_port_get_name(s->plugin, port); + + if (lilv_port_is_a(s->plugin, port, s->lv2_InputPort) && + lilv_port_is_a(s->plugin, port, s->lv2_ControlPort)) { + av_log(ctx, AV_LOG_INFO, "%s\t\t (from %f to %f) (default %f)\t\t%s\n", + lilv_node_as_string(symbol), s->mins[i], s->maxes[i], s->controls[i], + lilv_node_as_string(name)); + } + + lilv_node_free(name); + } + } + return AVERROR_EXIT; + } + + p = s->options; + while (s->options) { + const LilvPort *port; + LilvNode *sym; + float val; + char *str, *vstr; + int index; + + if (!(arg = av_strtok(p, " |", &saveptr))) + break; + p = NULL; + + vstr = strstr(arg, "="); + if (vstr == NULL) { + av_log(ctx, AV_LOG_ERROR, "Invalid syntax.\n"); + return AVERROR(EINVAL); + } + + vstr[0] = 0; + str = arg; + val = atof(vstr+1); + sym = lilv_new_string(s->world, str); + port = lilv_plugin_get_port_by_symbol(s->plugin, sym); + lilv_node_free(sym); + if (!port) { + av_log(s, AV_LOG_WARNING, "Unknown option: <%s>\n", str); + } else { + index = lilv_port_get_index(s->plugin, port); + s->controls[index] = val; + } + } + + if (s->nb_inputs && + (lilv_plugin_has_feature(s->plugin, s->powerOf2BlockLength) || + lilv_plugin_has_feature(s->plugin, s->fixedBlockLength) || + lilv_plugin_has_feature(s->plugin, s->boundedBlockLength))) { + AVFilterLink *inlink = ctx->inputs[0]; + + inlink->partial_buf_size = inlink->min_samples = inlink->max_samples = 4096; + } + + return 0; +} + +static av_cold int init(AVFilterContext *ctx) +{ + LV2Context *s = ctx->priv; + const LilvPlugins *plugins; + const LilvPlugin *plugin; + AVFilterPad pad = { NULL }; + LilvNode *uri; + int i; + + s->world = lilv_world_new(); + if (!s->world) + return AVERROR(ENOMEM); + + uri = lilv_new_uri(s->world, s->plugin_uri); + if (!uri) { + av_log(s, AV_LOG_ERROR, "Invalid plugin URI <%s>\n", s->plugin_uri); + return AVERROR(EINVAL); + } + + lilv_world_load_all(s->world); + plugins = lilv_world_get_all_plugins(s->world); + plugin = lilv_plugins_get_by_uri(plugins, uri); + lilv_node_free(uri); + + if (!plugin) { + av_log(s, AV_LOG_ERROR, "Plugin <%s> not found\n", s->plugin_uri); + return AVERROR(EINVAL); + } + + s->plugin = plugin; + s->nb_ports = lilv_plugin_get_num_ports(s->plugin); + + s->lv2_InputPort = lilv_new_uri(s->world, LV2_CORE__InputPort); + s->lv2_OutputPort = lilv_new_uri(s->world, LV2_CORE__OutputPort); + s->lv2_AudioPort = lilv_new_uri(s->world, LV2_CORE__AudioPort); + s->lv2_ControlPort = lilv_new_uri(s->world, LV2_CORE__ControlPort); + s->lv2_Optional = lilv_new_uri(s->world, LV2_CORE__connectionOptional); + s->atom_AtomPort = lilv_new_uri(s->world, LV2_ATOM__AtomPort); + s->atom_Sequence = lilv_new_uri(s->world, LV2_ATOM__Sequence); + s->urid_map = lilv_new_uri(s->world, LV2_URID__map); + s->powerOf2BlockLength = lilv_new_uri(s->world, LV2_BUF_SIZE__powerOf2BlockLength); + s->fixedBlockLength = lilv_new_uri(s->world, LV2_BUF_SIZE__fixedBlockLength); + s->boundedBlockLength = lilv_new_uri(s->world, LV2_BUF_SIZE__boundedBlockLength); + + for (i = 0; i < s->nb_ports; i++) { + const LilvPort *lport = lilv_plugin_get_port_by_index(s->plugin, i); + int is_input = 0; + int is_optional = 0; + + is_optional = lilv_port_has_property(s->plugin, lport, s->lv2_Optional); + + if (lilv_port_is_a(s->plugin, lport, s->lv2_InputPort)) { + is_input = 1; + } else if (!lilv_port_is_a(s->plugin, lport, s->lv2_OutputPort) && !is_optional) { + return AVERROR(EINVAL); + } + + if (lilv_port_is_a(s->plugin, lport, s->lv2_ControlPort)) { + if (is_input) { + s->nb_inputcontrols++; + } + } else if (lilv_port_is_a(s->plugin, lport, s->lv2_AudioPort)) { + if (is_input) { + s->nb_inputs++; + } else { + s->nb_outputs++; + } + } + } + + pad.type = AVMEDIA_TYPE_AUDIO; + + if (s->nb_inputs) { + pad.name = av_asprintf("in0:%s:%u", s->plugin_uri, s->nb_inputs); + if (!pad.name) + return AVERROR(ENOMEM); + + pad.filter_frame = filter_frame; + if (ff_insert_inpad(ctx, ctx->nb_inputs, &pad) < 0) { + av_freep(&pad.name); + return AVERROR(ENOMEM); + } + } + + return 0; +} + +static int query_formats(AVFilterContext *ctx) +{ + LV2Context *s = ctx->priv; + AVFilterFormats *formats; + AVFilterChannelLayouts *layouts; + AVFilterLink *outlink = ctx->outputs[0]; + static const enum AVSampleFormat sample_fmts[] = { + AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; + int ret; + + formats = ff_make_format_list(sample_fmts); + if (!formats) + return AVERROR(ENOMEM); + ret = ff_set_common_formats(ctx, formats); + if (ret < 0) + return ret; + + if (s->nb_inputs) { + formats = ff_all_samplerates(); + if (!formats) + return AVERROR(ENOMEM); + + ret = ff_set_common_samplerates(ctx, formats); + if (ret < 0) + return ret; + } else { + int sample_rates[] = { s->sample_rate, -1 }; + + ret = ff_set_common_samplerates(ctx, ff_make_format_list(sample_rates)); + if (ret < 0) + return ret; + } + + if (s->nb_inputs == 2 && s->nb_outputs == 2) { + layouts = NULL; + ret = ff_add_channel_layout(&layouts, AV_CH_LAYOUT_STEREO); + if (ret < 0) + return ret; + ret = ff_set_common_channel_layouts(ctx, layouts); + if (ret < 0) + return ret; + } else { + if (s->nb_inputs >= 1) { + AVFilterLink *inlink = ctx->inputs[0]; + uint64_t inlayout = FF_COUNT2LAYOUT(s->nb_inputs); + + layouts = NULL; + ret = ff_add_channel_layout(&layouts, inlayout); + if (ret < 0) + return ret; + ret = ff_channel_layouts_ref(layouts, &inlink->out_channel_layouts); + if (ret < 0) + return ret; + + if (!s->nb_outputs) { + ret = ff_channel_layouts_ref(layouts, &outlink->in_channel_layouts); + if (ret < 0) + return ret; + } + } + + if (s->nb_outputs >= 1) { + uint64_t outlayout = FF_COUNT2LAYOUT(s->nb_outputs); + + layouts = NULL; + ret = ff_add_channel_layout(&layouts, outlayout); + if (ret < 0) + return ret; + ret = ff_channel_layouts_ref(layouts, &outlink->in_channel_layouts); + if (ret < 0) + return ret; + } + } + + return 0; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + LV2Context *s = ctx->priv; + + lilv_node_free(s->powerOf2BlockLength); + lilv_node_free(s->fixedBlockLength); + lilv_node_free(s->boundedBlockLength); + lilv_node_free(s->urid_map); + lilv_node_free(s->atom_Sequence); + lilv_node_free(s->atom_AtomPort); + lilv_node_free(s->lv2_Optional); + lilv_node_free(s->lv2_ControlPort); + lilv_node_free(s->lv2_AudioPort); + lilv_node_free(s->lv2_OutputPort); + lilv_node_free(s->lv2_InputPort); + uri_table_destroy(&s->uri_table); + lilv_instance_free(s->instance); + lilv_world_free(s->world); + av_freep(&s->mins); + av_freep(&s->maxes); + av_freep(&s->controls); + av_freep(&s->seq_out); + + if (ctx->nb_inputs) + av_freep(&ctx->input_pads[0].name); +} + +static const AVFilterPad lv2_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .config_props = config_output, + .request_frame = request_frame, + }, + { NULL } +}; + +AVFilter ff_af_lv2 = { + .name = "lv2", + .description = NULL_IF_CONFIG_SMALL("Apply LV2 effect."), + .priv_size = sizeof(LV2Context), + .priv_class = &lv2_class, + .init = init, + .uninit = uninit, + .query_formats = query_formats, + .inputs = 0, + .outputs = lv2_outputs, + .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, +}; diff --git a/libavfilter/af_mcompand.c b/libavfilter/af_mcompand.c new file mode 100644 index 0000000000000..f142573beabdd --- /dev/null +++ b/libavfilter/af_mcompand.c @@ -0,0 +1,689 @@ +/* + * COpyright (c) 2002 Daniel Pouzzner + * Copyright (c) 1999 Chris Bagwell + * Copyright (c) 1999 Nick Bailey + * Copyright (c) 2007 Rob Sykes + * Copyright (c) 2013 Paul B Mahol + * Copyright (c) 2014 Andrew Kelley + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * audio multiband compand filter + */ + +#include "libavutil/avassert.h" +#include "libavutil/avstring.h" +#include "libavutil/ffmath.h" +#include "libavutil/opt.h" +#include "libavutil/samplefmt.h" +#include "audio.h" +#include "avfilter.h" +#include "internal.h" + +typedef struct CompandSegment { + double x, y; + double a, b; +} CompandSegment; + +typedef struct CompandT { + CompandSegment *segments; + int nb_segments; + double in_min_lin; + double out_min_lin; + double curve_dB; + double gain_dB; +} CompandT; + +#define N 4 + +typedef struct PrevCrossover { + double in; + double out_low; + double out_high; +} PrevCrossover[N * 2]; + +typedef struct Crossover { + PrevCrossover *previous; + size_t pos; + double coefs[3 *(N+1)]; +} Crossover; + +typedef struct CompBand { + CompandT transfer_fn; + double *attack_rate; + double *decay_rate; + double *volume; + double delay; + double topfreq; + Crossover filter; + AVFrame *delay_buf; + size_t delay_size; + ptrdiff_t delay_buf_ptr; + size_t delay_buf_cnt; +} CompBand; + +typedef struct MCompandContext { + const AVClass *class; + + char *args; + + int nb_bands; + CompBand *bands; + AVFrame *band_buf1, *band_buf2, *band_buf3; + int band_samples; + size_t delay_buf_size; +} MCompandContext; + +#define OFFSET(x) offsetof(MCompandContext, x) +#define A AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption mcompand_options[] = { + { "args", "set parameters for each band", OFFSET(args), AV_OPT_TYPE_STRING, { .str = "0.005,0.1 6 -47/-40,-34/-34,-17/-33 100 | 0.003,0.05 6 -47/-40,-34/-34,-17/-33 400 | 0.000625,0.0125 6 -47/-40,-34/-34,-15/-33 1600 | 0.0001,0.025 6 -47/-40,-34/-34,-31/-31,-0/-30 6400 | 0,0.025 6 -38/-31,-28/-28,-0/-25 22000" }, 0, 0, A }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(mcompand); + +static av_cold void uninit(AVFilterContext *ctx) +{ + MCompandContext *s = ctx->priv; + int i; + + av_frame_free(&s->band_buf1); + av_frame_free(&s->band_buf2); + av_frame_free(&s->band_buf3); + + if (s->bands) { + for (i = 0; i < s->nb_bands; i++) { + av_freep(&s->bands[i].attack_rate); + av_freep(&s->bands[i].decay_rate); + av_freep(&s->bands[i].volume); + av_freep(&s->bands[i].transfer_fn.segments); + av_freep(&s->bands[i].filter.previous); + av_frame_free(&s->bands[i].delay_buf); + } + } + av_freep(&s->bands); +} + +static int query_formats(AVFilterContext *ctx) +{ + AVFilterChannelLayouts *layouts; + AVFilterFormats *formats; + static const enum AVSampleFormat sample_fmts[] = { + AV_SAMPLE_FMT_DBLP, + AV_SAMPLE_FMT_NONE + }; + int ret; + + layouts = ff_all_channel_counts(); + if (!layouts) + return AVERROR(ENOMEM); + ret = ff_set_common_channel_layouts(ctx, layouts); + if (ret < 0) + return ret; + + formats = ff_make_format_list(sample_fmts); + if (!formats) + return AVERROR(ENOMEM); + ret = ff_set_common_formats(ctx, formats); + if (ret < 0) + return ret; + + formats = ff_all_samplerates(); + if (!formats) + return AVERROR(ENOMEM); + return ff_set_common_samplerates(ctx, formats); +} + +static void count_items(char *item_str, int *nb_items, char delimiter) +{ + char *p; + + *nb_items = 1; + for (p = item_str; *p; p++) { + if (*p == delimiter) + (*nb_items)++; + } +} + +static void update_volume(CompBand *cb, double in, int ch) +{ + double delta = in - cb->volume[ch]; + + if (delta > 0.0) + cb->volume[ch] += delta * cb->attack_rate[ch]; + else + cb->volume[ch] += delta * cb->decay_rate[ch]; +} + +static double get_volume(CompandT *s, double in_lin) +{ + CompandSegment *cs; + double in_log, out_log; + int i; + + if (in_lin <= s->in_min_lin) + return s->out_min_lin; + + in_log = log(in_lin); + + for (i = 1; i < s->nb_segments; i++) + if (in_log <= s->segments[i].x) + break; + cs = &s->segments[i - 1]; + in_log -= cs->x; + out_log = cs->y + in_log * (cs->a * in_log + cs->b); + + return exp(out_log); +} + +static int parse_points(char *points, int nb_points, double radius, + CompandT *s, AVFilterContext *ctx) +{ + int new_nb_items, num; + char *saveptr = NULL; + char *p = points; + int i; + +#define S(x) s->segments[2 * ((x) + 1)] + for (i = 0, new_nb_items = 0; i < nb_points; i++) { + char *tstr = av_strtok(p, ",", &saveptr); + p = NULL; + if (!tstr || sscanf(tstr, "%lf/%lf", &S(i).x, &S(i).y) != 2) { + av_log(ctx, AV_LOG_ERROR, + "Invalid and/or missing input/output value.\n"); + return AVERROR(EINVAL); + } + if (i && S(i - 1).x > S(i).x) { + av_log(ctx, AV_LOG_ERROR, + "Transfer function input values must be increasing.\n"); + return AVERROR(EINVAL); + } + S(i).y -= S(i).x; + av_log(ctx, AV_LOG_DEBUG, "%d: x=%f y=%f\n", i, S(i).x, S(i).y); + new_nb_items++; + } + num = new_nb_items; + + /* Add 0,0 if necessary */ + if (num == 0 || S(num - 1).x) + num++; + +#undef S +#define S(x) s->segments[2 * (x)] + /* Add a tail off segment at the start */ + S(0).x = S(1).x - 2 * s->curve_dB; + S(0).y = S(1).y; + num++; + + /* Join adjacent colinear segments */ + for (i = 2; i < num; i++) { + double g1 = (S(i - 1).y - S(i - 2).y) * (S(i - 0).x - S(i - 1).x); + double g2 = (S(i - 0).y - S(i - 1).y) * (S(i - 1).x - S(i - 2).x); + int j; + + if (fabs(g1 - g2)) + continue; + num--; + for (j = --i; j < num; j++) + S(j) = S(j + 1); + } + + for (i = 0; i < s->nb_segments; i += 2) { + s->segments[i].y += s->gain_dB; + s->segments[i].x *= M_LN10 / 20; + s->segments[i].y *= M_LN10 / 20; + } + +#define L(x) s->segments[i - (x)] + for (i = 4; i < s->nb_segments; i += 2) { + double x, y, cx, cy, in1, in2, out1, out2, theta, len, r; + + L(4).a = 0; + L(4).b = (L(2).y - L(4).y) / (L(2).x - L(4).x); + + L(2).a = 0; + L(2).b = (L(0).y - L(2).y) / (L(0).x - L(2).x); + + theta = atan2(L(2).y - L(4).y, L(2).x - L(4).x); + len = hypot(L(2).x - L(4).x, L(2).y - L(4).y); + r = FFMIN(radius, len); + L(3).x = L(2).x - r * cos(theta); + L(3).y = L(2).y - r * sin(theta); + + theta = atan2(L(0).y - L(2).y, L(0).x - L(2).x); + len = hypot(L(0).x - L(2).x, L(0).y - L(2).y); + r = FFMIN(radius, len / 2); + x = L(2).x + r * cos(theta); + y = L(2).y + r * sin(theta); + + cx = (L(3).x + L(2).x + x) / 3; + cy = (L(3).y + L(2).y + y) / 3; + + L(2).x = x; + L(2).y = y; + + in1 = cx - L(3).x; + out1 = cy - L(3).y; + in2 = L(2).x - L(3).x; + out2 = L(2).y - L(3).y; + L(3).a = (out2 / in2 - out1 / in1) / (in2 - in1); + L(3).b = out1 / in1 - L(3).a * in1; + } + L(3).x = 0; + L(3).y = L(2).y; + + s->in_min_lin = exp(s->segments[1].x); + s->out_min_lin = exp(s->segments[1].y); + + return 0; +} + +static void square_quadratic(double const *x, double *y) +{ + y[0] = x[0] * x[0]; + y[1] = 2 * x[0] * x[1]; + y[2] = 2 * x[0] * x[2] + x[1] * x[1]; + y[3] = 2 * x[1] * x[2]; + y[4] = x[2] * x[2]; +} + +static int crossover_setup(AVFilterLink *outlink, Crossover *p, double frequency) +{ + double w0 = 2 * M_PI * frequency / outlink->sample_rate; + double Q = sqrt(.5), alpha = sin(w0) / (2*Q); + double x[9], norm; + int i; + + if (w0 > M_PI) + return AVERROR(EINVAL); + + x[0] = (1 - cos(w0))/2; /* Cf. filter_LPF in biquads.c */ + x[1] = 1 - cos(w0); + x[2] = (1 - cos(w0))/2; + x[3] = (1 + cos(w0))/2; /* Cf. filter_HPF in biquads.c */ + x[4] = -(1 + cos(w0)); + x[5] = (1 + cos(w0))/2; + x[6] = 1 + alpha; + x[7] = -2*cos(w0); + x[8] = 1 - alpha; + + for (norm = x[6], i = 0; i < 9; ++i) + x[i] /= norm; + + square_quadratic(x , p->coefs); + square_quadratic(x + 3, p->coefs + 5); + square_quadratic(x + 6, p->coefs + 10); + + p->previous = av_calloc(outlink->channels, sizeof(*p->previous)); + if (!p->previous) + return AVERROR(ENOMEM); + + return 0; +} + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + MCompandContext *s = ctx->priv; + int ret, ch, i, k, new_nb_items, nb_bands; + char *p = s->args, *saveptr = NULL; + int max_delay_size = 0; + + count_items(s->args, &nb_bands, '|'); + s->nb_bands = FFMAX(1, nb_bands); + + s->bands = av_calloc(nb_bands, sizeof(*s->bands)); + if (!s->bands) + return AVERROR(ENOMEM); + + for (i = 0, new_nb_items = 0; i < nb_bands; i++) { + int nb_points, nb_attacks, nb_items = 0; + char *tstr2, *tstr = av_strtok(p, "|", &saveptr); + char *p2, *p3, *saveptr2 = NULL, *saveptr3 = NULL; + double radius; + + if (!tstr) { + uninit(ctx); + return AVERROR(EINVAL); + } + p = NULL; + + p2 = tstr; + count_items(tstr, &nb_items, ' '); + tstr2 = av_strtok(p2, " ", &saveptr2); + if (!tstr2) { + av_log(ctx, AV_LOG_ERROR, "at least one attacks/decays rate is mandatory\n"); + uninit(ctx); + return AVERROR(EINVAL); + } + p2 = NULL; + p3 = tstr2; + + count_items(tstr2, &nb_attacks, ','); + if (!nb_attacks || nb_attacks & 1) { + av_log(ctx, AV_LOG_ERROR, "number of attacks rate plus decays rate must be even\n"); + uninit(ctx); + return AVERROR(EINVAL); + } + + s->bands[i].attack_rate = av_calloc(outlink->channels, sizeof(double)); + s->bands[i].decay_rate = av_calloc(outlink->channels, sizeof(double)); + s->bands[i].volume = av_calloc(outlink->channels, sizeof(double)); + for (k = 0; k < FFMIN(nb_attacks / 2, outlink->channels); k++) { + char *tstr3 = av_strtok(p3, ",", &saveptr3); + + p3 = NULL; + sscanf(tstr3, "%lf", &s->bands[i].attack_rate[k]); + tstr3 = av_strtok(p3, ",", &saveptr3); + sscanf(tstr3, "%lf", &s->bands[i].decay_rate[k]); + + if (s->bands[i].attack_rate[k] > 1.0 / outlink->sample_rate) { + s->bands[i].attack_rate[k] = 1.0 - exp(-1.0 / (outlink->sample_rate * s->bands[i].attack_rate[k])); + } else { + s->bands[i].attack_rate[k] = 1.0; + } + + if (s->bands[i].decay_rate[k] > 1.0 / outlink->sample_rate) { + s->bands[i].decay_rate[k] = 1.0 - exp(-1.0 / (outlink->sample_rate * s->bands[i].decay_rate[k])); + } else { + s->bands[i].decay_rate[k] = 1.0; + } + } + + for (ch = k; ch < outlink->channels; ch++) { + s->bands[i].attack_rate[ch] = s->bands[i].attack_rate[k - 1]; + s->bands[i].decay_rate[ch] = s->bands[i].decay_rate[k - 1]; + } + + tstr2 = av_strtok(p2, " ", &saveptr2); + if (!tstr2) { + av_log(ctx, AV_LOG_ERROR, "transfer function curve in dB must be set\n"); + uninit(ctx); + return AVERROR(EINVAL); + } + sscanf(tstr2, "%lf", &s->bands[i].transfer_fn.curve_dB); + + radius = s->bands[i].transfer_fn.curve_dB * M_LN10 / 20.0; + + tstr2 = av_strtok(p2, " ", &saveptr2); + if (!tstr2) { + av_log(ctx, AV_LOG_ERROR, "transfer points missing\n"); + uninit(ctx); + return AVERROR(EINVAL); + } + + count_items(tstr2, &nb_points, ','); + s->bands[i].transfer_fn.nb_segments = (nb_points + 4) * 2; + s->bands[i].transfer_fn.segments = av_calloc(s->bands[i].transfer_fn.nb_segments, + sizeof(CompandSegment)); + if (!s->bands[i].transfer_fn.segments) { + uninit(ctx); + return AVERROR(ENOMEM); + } + + ret = parse_points(tstr2, nb_points, radius, &s->bands[i].transfer_fn, ctx); + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "transfer points parsing failed\n"); + uninit(ctx); + return ret; + } + + tstr2 = av_strtok(p2, " ", &saveptr2); + if (!tstr2) { + av_log(ctx, AV_LOG_ERROR, "crossover_frequency is missing\n"); + uninit(ctx); + return AVERROR(EINVAL); + } + + new_nb_items += sscanf(tstr2, "%lf", &s->bands[i].topfreq) == 1; + if (s->bands[i].topfreq < 0 || s->bands[i].topfreq >= outlink->sample_rate / 2) { + av_log(ctx, AV_LOG_ERROR, "crossover_frequency: %f, should be >=0 and lower than half of sample rate: %d.\n", s->bands[i].topfreq, outlink->sample_rate / 2); + uninit(ctx); + return AVERROR(EINVAL); + } + + if (s->bands[i].topfreq != 0) { + ret = crossover_setup(outlink, &s->bands[i].filter, s->bands[i].topfreq); + if (ret < 0) { + uninit(ctx); + return ret; + } + } + + tstr2 = av_strtok(p2, " ", &saveptr2); + if (tstr2) { + sscanf(tstr2, "%lf", &s->bands[i].delay); + max_delay_size = FFMAX(max_delay_size, s->bands[i].delay * outlink->sample_rate); + + tstr2 = av_strtok(p2, " ", &saveptr2); + if (tstr2) { + double initial_volume; + + sscanf(tstr2, "%lf", &initial_volume); + initial_volume = pow(10.0, initial_volume / 20); + + for (k = 0; k < outlink->channels; k++) { + s->bands[i].volume[k] = initial_volume; + } + + tstr2 = av_strtok(p2, " ", &saveptr2); + if (tstr2) { + sscanf(tstr2, "%lf", &s->bands[i].transfer_fn.gain_dB); + } + } + } + } + s->nb_bands = new_nb_items; + + for (i = 0; max_delay_size > 0 && i < s->nb_bands; i++) { + s->bands[i].delay_buf = ff_get_audio_buffer(outlink, max_delay_size); + if (!s->bands[i].delay_buf) + return AVERROR(ENOMEM); + } + s->delay_buf_size = max_delay_size; + + return 0; +} + +#define CONVOLVE _ _ _ _ + +static void crossover(int ch, Crossover *p, + double *ibuf, double *obuf_low, + double *obuf_high, size_t len) +{ + double out_low, out_high; + + while (len--) { + p->pos = p->pos ? p->pos - 1 : N - 1; +#define _ out_low += p->coefs[j] * p->previous[ch][p->pos + j].in \ + - p->coefs[2*N+2 + j] * p->previous[ch][p->pos + j].out_low, j++; + { + int j = 1; + out_low = p->coefs[0] * *ibuf; + CONVOLVE + *obuf_low++ = out_low; + } +#undef _ +#define _ out_high += p->coefs[j+N+1] * p->previous[ch][p->pos + j].in \ + - p->coefs[2*N+2 + j] * p->previous[ch][p->pos + j].out_high, j++; + { + int j = 1; + out_high = p->coefs[N+1] * *ibuf; + CONVOLVE + *obuf_high++ = out_high; + } + p->previous[ch][p->pos + N].in = p->previous[ch][p->pos].in = *ibuf++; + p->previous[ch][p->pos + N].out_low = p->previous[ch][p->pos].out_low = out_low; + p->previous[ch][p->pos + N].out_high = p->previous[ch][p->pos].out_high = out_high; + } +} + +static int mcompand_channel(MCompandContext *c, CompBand *l, double *ibuf, double *obuf, int len, int ch) +{ + int i; + + for (i = 0; i < len; i++) { + double level_in_lin, level_out_lin, checkbuf; + /* Maintain the volume fields by simulating a leaky pump circuit */ + update_volume(l, fabs(ibuf[i]), ch); + + /* Volume memory is updated: perform compand */ + level_in_lin = l->volume[ch]; + level_out_lin = get_volume(&l->transfer_fn, level_in_lin); + + if (c->delay_buf_size <= 0) { + checkbuf = ibuf[i] * level_out_lin; + obuf[i] = checkbuf; + } else { + double *delay_buf = (double *)l->delay_buf->extended_data[ch]; + + /* FIXME: note that this lookahead algorithm is really lame: + the response to a peak is released before the peak + arrives. */ + + /* because volume application delays differ band to band, but + total delay doesn't, the volume is applied in an iteration + preceding that in which the sample goes to obuf, except in + the band(s) with the longest vol app delay. + + the offset between delay_buf_ptr and the sample to apply + vol to, is a constant equal to the difference between this + band's delay and the longest delay of all the bands. */ + + if (l->delay_buf_cnt >= l->delay_size) { + checkbuf = + delay_buf[(l->delay_buf_ptr + + c->delay_buf_size - + l->delay_size) % c->delay_buf_size] * level_out_lin; + delay_buf[(l->delay_buf_ptr + c->delay_buf_size - + l->delay_size) % c->delay_buf_size] = checkbuf; + } + if (l->delay_buf_cnt >= c->delay_buf_size) { + obuf[i] = delay_buf[l->delay_buf_ptr]; + } else { + l->delay_buf_cnt++; + } + delay_buf[l->delay_buf_ptr++] = ibuf[i]; + l->delay_buf_ptr %= c->delay_buf_size; + } + } + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + MCompandContext *s = ctx->priv; + AVFrame *out, *abuf, *bbuf, *cbuf; + int ch, band, i; + + out = ff_get_audio_buffer(outlink, in->nb_samples); + if (!out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + + if (s->band_samples < in->nb_samples) { + av_frame_free(&s->band_buf1); + av_frame_free(&s->band_buf2); + av_frame_free(&s->band_buf3); + + s->band_buf1 = ff_get_audio_buffer(outlink, in->nb_samples); + s->band_buf2 = ff_get_audio_buffer(outlink, in->nb_samples); + s->band_buf3 = ff_get_audio_buffer(outlink, in->nb_samples); + s->band_samples = in->nb_samples; + } + + for (ch = 0; ch < outlink->channels; ch++) { + double *a, *dst = (double *)out->extended_data[ch]; + + for (band = 0, abuf = in, bbuf = s->band_buf2, cbuf = s->band_buf1; band < s->nb_bands; band++) { + CompBand *b = &s->bands[band]; + + if (b->topfreq) { + crossover(ch, &b->filter, (double *)abuf->extended_data[ch], + (double *)bbuf->extended_data[ch], (double *)cbuf->extended_data[ch], in->nb_samples); + } else { + bbuf = abuf; + abuf = cbuf; + } + + if (abuf == in) + abuf = s->band_buf3; + mcompand_channel(s, b, (double *)bbuf->extended_data[ch], (double *)abuf->extended_data[ch], out->nb_samples, ch); + a = (double *)abuf->extended_data[ch]; + for (i = 0; i < out->nb_samples; i++) { + dst[i] += a[i]; + } + + FFSWAP(AVFrame *, abuf, cbuf); + } + } + + out->pts = in->pts; + av_frame_free(&in); + return ff_filter_frame(outlink, out); +} + +static int request_frame(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + int ret; + + ret = ff_request_frame(ctx->inputs[0]); + + return ret; +} + +static const AVFilterPad mcompand_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad mcompand_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .request_frame = request_frame, + .config_props = config_output, + }, + { NULL } +}; + + +AVFilter ff_af_mcompand = { + .name = "mcompand", + .description = NULL_IF_CONFIG_SMALL( + "Multiband Compress or expand audio dynamic range."), + .query_formats = query_formats, + .priv_size = sizeof(MCompandContext), + .priv_class = &mcompand_class, + .uninit = uninit, + .inputs = mcompand_inputs, + .outputs = mcompand_outputs, +}; diff --git a/libavfilter/af_pan.c b/libavfilter/af_pan.c index 23b29419b6350..34e522c9d4eb2 100644 --- a/libavfilter/af_pan.c +++ b/libavfilter/af_pan.c @@ -104,6 +104,7 @@ static av_cold int init(AVFilterContext *ctx) char *arg, *arg0, *tokenizer, *args = av_strdup(pan->args); int out_ch_id, in_ch_id, len, named, ret, sign = 1; int nb_in_channels[2] = { 0, 0 }; // number of unnamed and named input channels + int used_out_ch[MAX_CHANNELS] = {0}; double gain; if (!pan->args) { @@ -127,6 +128,7 @@ static av_cold int init(AVFilterContext *ctx) /* parse channel specifications */ while ((arg = arg0 = av_strtok(NULL, "|", &tokenizer))) { + int used_in_ch[MAX_CHANNELS] = {0}; /* channel name */ if (parse_channel_name(&arg, &out_ch_id, &named)) { av_log(ctx, AV_LOG_ERROR, @@ -153,6 +155,13 @@ static av_cold int init(AVFilterContext *ctx) ret = AVERROR(EINVAL); goto fail; } + if (used_out_ch[out_ch_id]) { + av_log(ctx, AV_LOG_ERROR, + "Can not reference out channel %d twice\n", out_ch_id); + ret = AVERROR(EINVAL); + goto fail; + } + used_out_ch[out_ch_id] = 1; skip_spaces(&arg); if (*arg == '=') { arg++; @@ -166,6 +175,7 @@ static av_cold int init(AVFilterContext *ctx) goto fail; } /* gains */ + sign = 1; while (1) { gain = 1; if (sscanf(arg, "%lf%n *%n", &gain, &len, &len)) @@ -183,6 +193,13 @@ static av_cold int init(AVFilterContext *ctx) ret = AVERROR(EINVAL); goto fail; } + if (used_in_ch[in_ch_id]) { + av_log(ctx, AV_LOG_ERROR, + "Can not reference in channel %d twice\n", in_ch_id); + ret = AVERROR(EINVAL); + goto fail; + } + used_in_ch[in_ch_id] = 1; pan->gain[out_ch_id][in_ch_id] = sign * gain; skip_spaces(&arg); if (!*arg) diff --git a/libavfilter/af_replaygain.c b/libavfilter/af_replaygain.c index c8f6f9666d6ce..97617346edfed 100644 --- a/libavfilter/af_replaygain.c +++ b/libavfilter/af_replaygain.c @@ -554,7 +554,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) uint32_t level; AVFrame *out; - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_rubberband.c b/libavfilter/af_rubberband.c index ded25449ddfe7..ea6f4ff2c9c85 100644 --- a/libavfilter/af_rubberband.c +++ b/libavfilter/af_rubberband.c @@ -128,7 +128,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) nb_samples = rubberband_available(s->rbs); if (nb_samples > 0) { - out = ff_get_audio_buffer(inlink, nb_samples); + out = ff_get_audio_buffer(outlink, nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); @@ -187,7 +187,7 @@ static int request_frame(AVFilterLink *outlink) nb_samples = rubberband_available(s->rbs); if (nb_samples > 0) { - out = ff_get_audio_buffer(inlink, nb_samples); + out = ff_get_audio_buffer(outlink, nb_samples); if (!out) return AVERROR(ENOMEM); out->pts = av_rescale_q(s->nb_samples_out, diff --git a/libavfilter/af_sidechaincompress.c b/libavfilter/af_sidechaincompress.c index 55bed438446c2..888049eaf0e0f 100644 --- a/libavfilter/af_sidechaincompress.c +++ b/libavfilter/af_sidechaincompress.c @@ -241,14 +241,13 @@ static int activate(AVFilterContext *ctx) } FF_FILTER_FORWARD_STATUS(ctx->inputs[0], ctx->outputs[0]); FF_FILTER_FORWARD_STATUS(ctx->inputs[1], ctx->outputs[0]); - /* TODO reindent */ - if (ff_outlink_frame_wanted(ctx->outputs[0])) { - if (!av_audio_fifo_size(s->fifo[0])) - ff_inlink_request_frame(ctx->inputs[0]); - if (!av_audio_fifo_size(s->fifo[1])) - ff_inlink_request_frame(ctx->inputs[1]); - } - return 0; + if (ff_outlink_frame_wanted(ctx->outputs[0])) { + if (!av_audio_fifo_size(s->fifo[0])) + ff_inlink_request_frame(ctx->inputs[0]); + if (!av_audio_fifo_size(s->fifo[1])) + ff_inlink_request_frame(ctx->inputs[1]); + } + return 0; } static int query_formats(AVFilterContext *ctx) @@ -368,7 +367,7 @@ static int acompressor_filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_silencedetect.c b/libavfilter/af_silencedetect.c index b048d63738643..6e321a5d9717f 100644 --- a/libavfilter/af_silencedetect.c +++ b/libavfilter/af_silencedetect.c @@ -36,9 +36,14 @@ typedef struct SilenceDetectContext { const AVClass *class; double noise; ///< noise amplitude ratio double duration; ///< minimum duration of silence until notification - int64_t nb_null_samples; ///< current number of continuous zero samples - int64_t start; ///< if silence is detected, this value contains the time of the first zero sample + int mono; ///< mono mode : check each channel separately (default = check when ALL channels are silent) + int channels; ///< number of channels + int independant_channels; ///< number of entries in following arrays (always 1 in mono mode) + int64_t *nb_null_samples; ///< (array) current number of continuous zero samples + int64_t *start; ///< (array) if silence is detected, this value contains the time of the first zero sample (default/unset = INT64_MIN) + int64_t frame_end; ///< pts of the end of the current frame (used to compute duration of silence at EOS) int last_sample_rate; ///< last sample rate to check for sample rate changes + AVRational time_base; ///< time_base void (*silencedetect)(struct SilenceDetectContext *s, AVFrame *insamples, int nb_samples, int64_t nb_samples_notify, @@ -52,44 +57,61 @@ static const AVOption silencedetect_options[] = { { "noise", "set noise tolerance", OFFSET(noise), AV_OPT_TYPE_DOUBLE, {.dbl=0.001}, 0, DBL_MAX, FLAGS }, { "d", "set minimum duration in seconds", OFFSET(duration), AV_OPT_TYPE_DOUBLE, {.dbl=2.}, 0, 24*60*60, FLAGS }, { "duration", "set minimum duration in seconds", OFFSET(duration), AV_OPT_TYPE_DOUBLE, {.dbl=2.}, 0, 24*60*60, FLAGS }, + { "mono", "check each channel separately", OFFSET(mono), AV_OPT_TYPE_BOOL, {.i64=0.}, 0, 1, FLAGS }, { NULL } }; AVFILTER_DEFINE_CLASS(silencedetect); -static char *get_metadata_val(AVFrame *insamples, const char *key) +static void set_meta(AVFrame *insamples, int channel, const char *key, char *value) { - AVDictionaryEntry *e = av_dict_get(insamples->metadata, key, NULL, 0); - return e && e->value ? e->value : NULL; -} + char key2[128]; + if (channel) + snprintf(key2, sizeof(key2), "lavfi.%s.%d", key, channel); + else + snprintf(key2, sizeof(key2), "lavfi.%s", key); + av_dict_set(&insamples->metadata, key2, value, 0); +} static av_always_inline void update(SilenceDetectContext *s, AVFrame *insamples, - int is_silence, int64_t nb_samples_notify, + int is_silence, int current_sample, int64_t nb_samples_notify, AVRational time_base) { + int channel = current_sample % s->independant_channels; if (is_silence) { - if (!s->start) { - s->nb_null_samples++; - if (s->nb_null_samples >= nb_samples_notify) { - s->start = insamples->pts - (int64_t)(s->duration / av_q2d(time_base) + .5); - av_dict_set(&insamples->metadata, "lavfi.silence_start", - av_ts2timestr(s->start, &time_base), 0); + if (s->start[channel] == INT64_MIN) { + s->nb_null_samples[channel]++; + if (s->nb_null_samples[channel] >= nb_samples_notify) { + s->start[channel] = insamples->pts + av_rescale_q(current_sample / s->channels + 1 - nb_samples_notify * s->independant_channels / s->channels, + (AVRational){ 1, s->last_sample_rate }, time_base); + set_meta(insamples, s->mono ? channel + 1 : 0, "silence_start", + av_ts2timestr(s->start[channel], &time_base)); + if (s->mono) + av_log(s, AV_LOG_INFO, "channel: %d | ", channel); av_log(s, AV_LOG_INFO, "silence_start: %s\n", - get_metadata_val(insamples, "lavfi.silence_start")); + av_ts2timestr(s->start[channel], &time_base)); } } } else { - if (s->start) { - av_dict_set(&insamples->metadata, "lavfi.silence_end", - av_ts2timestr(insamples->pts, &time_base), 0); - av_dict_set(&insamples->metadata, "lavfi.silence_duration", - av_ts2timestr(insamples->pts - s->start, &time_base), 0); - av_log(s, AV_LOG_INFO, - "silence_end: %s | silence_duration: %s\n", - get_metadata_val(insamples, "lavfi.silence_end"), - get_metadata_val(insamples, "lavfi.silence_duration")); + if (s->start[channel] > INT64_MIN) { + int64_t end_pts = insamples ? insamples->pts + av_rescale_q(current_sample / s->channels, + (AVRational){ 1, s->last_sample_rate }, time_base) + : s->frame_end; + int64_t duration_ts = end_pts - s->start[channel]; + if (insamples) { + set_meta(insamples, s->mono ? channel + 1 : 0, "silence_end", + av_ts2timestr(end_pts, &time_base)); + set_meta(insamples, s->mono ? channel + 1 : 0, "silence_duration", + av_ts2timestr(duration_ts, &time_base)); + } + if (s->mono) + av_log(s, AV_LOG_INFO, "channel: %d | ", channel); + av_log(s, AV_LOG_INFO, "silence_end: %s | silence_duration: %s\n", + av_ts2timestr(end_pts, &time_base), + av_ts2timestr(duration_ts, &time_base)); } - s->nb_null_samples = s->start = 0; + s->nb_null_samples[channel] = 0; + s->start[channel] = INT64_MIN; } } @@ -103,7 +125,7 @@ static void silencedetect_##name(SilenceDetectContext *s, AVFrame *insamples, int i; \ \ for (i = 0; i < nb_samples; i++, p++) \ - update(s, insamples, *p < noise && *p > -noise, \ + update(s, insamples, *p < noise && *p > -noise, i, \ nb_samples_notify, time_base); \ } @@ -116,6 +138,18 @@ static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; SilenceDetectContext *s = ctx->priv; + int c; + + s->channels = inlink->channels; + s->independant_channels = s->mono ? s->channels : 1; + s->nb_null_samples = av_mallocz_array(sizeof(*s->nb_null_samples), s->independant_channels); + if (!s->nb_null_samples) + return AVERROR(ENOMEM); + s->start = av_malloc_array(sizeof(*s->start), s->independant_channels); + if (!s->start) + return AVERROR(ENOMEM); + for (c = 0; c < s->independant_channels; c++) + s->start[c] = INT64_MIN; switch (inlink->format) { case AV_SAMPLE_FMT_DBL: s->silencedetect = silencedetect_dbl; break; @@ -139,12 +173,18 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) const int nb_channels = inlink->channels; const int srate = inlink->sample_rate; const int nb_samples = insamples->nb_samples * nb_channels; - const int64_t nb_samples_notify = srate * s->duration * nb_channels; + const int64_t nb_samples_notify = srate * s->duration * (s->mono ? 1 : nb_channels); + int c; // scale number of null samples to the new sample rate if (s->last_sample_rate && s->last_sample_rate != srate) - s->nb_null_samples = srate * s->nb_null_samples / s->last_sample_rate; + for (c = 0; c < s->independant_channels; c++) { + s->nb_null_samples[c] = srate * s->nb_null_samples[c] / s->last_sample_rate; + } s->last_sample_rate = srate; + s->time_base = inlink->time_base; + s->frame_end = insamples->pts + av_rescale_q(insamples->nb_samples, + (AVRational){ 1, s->last_sample_rate }, inlink->time_base); // TODO: document metadata s->silencedetect(s, insamples, nb_samples, nb_samples_notify, @@ -186,6 +226,18 @@ static int query_formats(AVFilterContext *ctx) return ff_set_common_samplerates(ctx, formats); } +static av_cold void uninit(AVFilterContext *ctx) +{ + SilenceDetectContext *s = ctx->priv; + int c; + + for (c = 0; c < s->independant_channels; c++) + if (s->start[c] > INT64_MIN) + update(s, NULL, 0, c, 0, s->time_base); + av_freep(&s->nb_null_samples); + av_freep(&s->start); +} + static const AVFilterPad silencedetect_inputs[] = { { .name = "default", @@ -209,6 +261,7 @@ AVFilter ff_af_silencedetect = { .description = NULL_IF_CONFIG_SMALL("Detect silence."), .priv_size = sizeof(SilenceDetectContext), .query_formats = query_formats, + .uninit = uninit, .inputs = silencedetect_inputs, .outputs = silencedetect_outputs, .priv_class = &silencedetect_class, diff --git a/libavfilter/af_silenceremove.c b/libavfilter/af_silenceremove.c index af504630598e4..d826a22e9dea6 100644 --- a/libavfilter/af_silenceremove.c +++ b/libavfilter/af_silenceremove.c @@ -186,8 +186,17 @@ static int config_input(AVFilterLink *inlink) s->start_duration = av_rescale(s->start_duration, inlink->sample_rate, AV_TIME_BASE); + if (s->start_duration < 0) { + av_log(ctx, AV_LOG_WARNING, "start duration must be non-negative\n"); + s->start_duration = -s->start_duration; + } + s->stop_duration = av_rescale(s->stop_duration, inlink->sample_rate, AV_TIME_BASE); + if (s->stop_duration < 0) { + av_log(ctx, AV_LOG_WARNING, "stop duration must be non-negative\n"); + s->stop_duration = -s->stop_duration; + } s->start_holdoff = av_malloc_array(FFMAX(s->start_duration, 1), sizeof(*s->start_holdoff) * @@ -469,7 +478,7 @@ static int request_frame(AVFilterLink *outlink) (AVRational){1, outlink->sample_rate}, outlink->time_base); - ret = ff_filter_frame(ctx->inputs[0], frame); + ret = ff_filter_frame(outlink, frame); } s->mode = SILENCE_STOP; } diff --git a/libavfilter/af_stereotools.c b/libavfilter/af_stereotools.c index a5e0b427f1e32..7e529783d5950 100644 --- a/libavfilter/af_stereotools.c +++ b/libavfilter/af_stereotools.c @@ -166,7 +166,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_stereowiden.c b/libavfilter/af_stereowiden.c index 24146ff1df006..ef16fcec73b8d 100644 --- a/libavfilter/af_stereowiden.c +++ b/libavfilter/af_stereowiden.c @@ -98,7 +98,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_surround.c b/libavfilter/af_surround.c index c7122379d6049..f29afecbfb640 100644 --- a/libavfilter/af_surround.c +++ b/libavfilter/af_surround.c @@ -90,6 +90,15 @@ typedef struct AudioSurroundContext { float mag_total, float x, float y, int n); + void (*upmix_5_0)(AVFilterContext *ctx, + float c_re, float c_im, + float mag_totall, float mag_totalr, + float fl_phase, float fr_phase, + float bl_phase, float br_phase, + float sl_phase, float sr_phase, + float xl, float yl, + float xr, float yr, + int n); void (*upmix_5_1)(AVFilterContext *ctx, float c_re, float c_im, float lfe_re, float lfe_im, @@ -764,6 +773,66 @@ static void upmix_7_1(AVFilterContext *ctx, dstrs[2 * n + 1] = rs_mag * sinf(r_phase); } +static void upmix_7_1_5_0_side(AVFilterContext *ctx, + float c_re, float c_im, + float mag_totall, float mag_totalr, + float fl_phase, float fr_phase, + float bl_phase, float br_phase, + float sl_phase, float sr_phase, + float xl, float yl, + float xr, float yr, + int n) +{ + float fl_mag, fr_mag, ls_mag, rs_mag, lb_mag, rb_mag; + float *dstc, *dstl, *dstr, *dstls, *dstrs, *dstlb, *dstrb, *dstlfe; + float lfe_mag, c_phase, mag_total = (mag_totall + mag_totalr) * 0.5; + AudioSurroundContext *s = ctx->priv; + + dstl = (float *)s->output->extended_data[0]; + dstr = (float *)s->output->extended_data[1]; + dstc = (float *)s->output->extended_data[2]; + dstlfe = (float *)s->output->extended_data[3]; + dstlb = (float *)s->output->extended_data[4]; + dstrb = (float *)s->output->extended_data[5]; + dstls = (float *)s->output->extended_data[6]; + dstrs = (float *)s->output->extended_data[7]; + + c_phase = atan2f(c_im, c_re); + + get_lfe(s->output_lfe, n, s->lowcut, s->highcut, &lfe_mag, &mag_total); + + fl_mag = sqrtf(.5f * (xl + 1.f)) * ((yl + 1.f) * .5f) * mag_totall; + fr_mag = sqrtf(.5f * (xr + 1.f)) * ((yr + 1.f) * .5f) * mag_totalr; + lb_mag = sqrtf(.5f * (-xl + 1.f)) * ((yl + 1.f) * .5f) * mag_totall; + rb_mag = sqrtf(.5f * (-xr + 1.f)) * ((yr + 1.f) * .5f) * mag_totalr; + ls_mag = sqrtf(1.f - fabsf(xl)) * ((yl + 1.f) * .5f) * mag_totall; + rs_mag = sqrtf(1.f - fabsf(xr)) * ((yr + 1.f) * .5f) * mag_totalr; + + dstl[2 * n ] = fl_mag * cosf(fl_phase); + dstl[2 * n + 1] = fl_mag * sinf(fl_phase); + + dstr[2 * n ] = fr_mag * cosf(fr_phase); + dstr[2 * n + 1] = fr_mag * sinf(fr_phase); + + dstc[2 * n ] = c_re; + dstc[2 * n + 1] = c_im; + + dstlfe[2 * n ] = lfe_mag * cosf(c_phase); + dstlfe[2 * n + 1] = lfe_mag * sinf(c_phase); + + dstlb[2 * n ] = lb_mag * cosf(bl_phase); + dstlb[2 * n + 1] = lb_mag * sinf(bl_phase); + + dstrb[2 * n ] = rb_mag * cosf(br_phase); + dstrb[2 * n + 1] = rb_mag * sinf(br_phase); + + dstls[2 * n ] = ls_mag * cosf(sl_phase); + dstls[2 * n + 1] = ls_mag * sinf(sl_phase); + + dstrs[2 * n ] = rs_mag * cosf(sr_phase); + dstrs[2 * n + 1] = rs_mag * sinf(sr_phase); +} + static void upmix_7_1_5_1(AVFilterContext *ctx, float c_re, float c_im, float lfe_re, float lfe_im, @@ -918,6 +987,118 @@ static void filter_2_1(AVFilterContext *ctx) } } +static void filter_5_0_side(AVFilterContext *ctx) +{ + AudioSurroundContext *s = ctx->priv; + float *srcl, *srcr, *srcc, *srcsl, *srcsr; + int n; + + srcl = (float *)s->input->extended_data[0]; + srcr = (float *)s->input->extended_data[1]; + srcc = (float *)s->input->extended_data[2]; + srcsl = (float *)s->input->extended_data[3]; + srcsr = (float *)s->input->extended_data[4]; + + for (n = 0; n < s->buf_size; n++) { + float fl_re = srcl[2 * n], fr_re = srcr[2 * n]; + float fl_im = srcl[2 * n + 1], fr_im = srcr[2 * n + 1]; + float c_re = srcc[2 * n], c_im = srcc[2 * n + 1]; + float sl_re = srcsl[2 * n], sl_im = srcsl[2 * n + 1]; + float sr_re = srcsr[2 * n], sr_im = srcsr[2 * n + 1]; + float fl_mag = hypotf(fl_re, fl_im); + float fr_mag = hypotf(fr_re, fr_im); + float fl_phase = atan2f(fl_im, fl_re); + float fr_phase = atan2f(fr_im, fr_re); + float sl_mag = hypotf(sl_re, sl_im); + float sr_mag = hypotf(sr_re, sr_im); + float sl_phase = atan2f(sl_im, sl_re); + float sr_phase = atan2f(sr_im, sr_re); + float phase_difl = fabsf(fl_phase - sl_phase); + float phase_difr = fabsf(fr_phase - sr_phase); + float mag_difl = (fl_mag - sl_mag) / (fl_mag + sl_mag); + float mag_difr = (fr_mag - sr_mag) / (fr_mag + sr_mag); + float mag_totall = hypotf(fl_mag, sl_mag); + float mag_totalr = hypotf(fr_mag, sr_mag); + float bl_phase = atan2f(fl_im + sl_im, fl_re + sl_re); + float br_phase = atan2f(fr_im + sr_im, fr_re + sr_re); + float xl, yl; + float xr, yr; + + if (phase_difl > M_PI) + phase_difl = 2 * M_PI - phase_difl; + + if (phase_difr > M_PI) + phase_difr = 2 * M_PI - phase_difr; + + stereo_position(mag_difl, phase_difl, &xl, &yl); + stereo_position(mag_difr, phase_difr, &xr, &yr); + + s->upmix_5_0(ctx, c_re, c_im, + mag_totall, mag_totalr, + fl_phase, fr_phase, + bl_phase, br_phase, + sl_phase, sr_phase, + xl, yl, xr, yr, n); + } +} + +static void filter_5_1_side(AVFilterContext *ctx) +{ + AudioSurroundContext *s = ctx->priv; + float *srcl, *srcr, *srcc, *srclfe, *srcsl, *srcsr; + int n; + + srcl = (float *)s->input->extended_data[0]; + srcr = (float *)s->input->extended_data[1]; + srcc = (float *)s->input->extended_data[2]; + srclfe = (float *)s->input->extended_data[3]; + srcsl = (float *)s->input->extended_data[4]; + srcsr = (float *)s->input->extended_data[5]; + + for (n = 0; n < s->buf_size; n++) { + float fl_re = srcl[2 * n], fr_re = srcr[2 * n]; + float fl_im = srcl[2 * n + 1], fr_im = srcr[2 * n + 1]; + float c_re = srcc[2 * n], c_im = srcc[2 * n + 1]; + float lfe_re = srclfe[2 * n], lfe_im = srclfe[2 * n + 1]; + float sl_re = srcsl[2 * n], sl_im = srcsl[2 * n + 1]; + float sr_re = srcsr[2 * n], sr_im = srcsr[2 * n + 1]; + float fl_mag = hypotf(fl_re, fl_im); + float fr_mag = hypotf(fr_re, fr_im); + float fl_phase = atan2f(fl_im, fl_re); + float fr_phase = atan2f(fr_im, fr_re); + float sl_mag = hypotf(sl_re, sl_im); + float sr_mag = hypotf(sr_re, sr_im); + float sl_phase = atan2f(sl_im, sl_re); + float sr_phase = atan2f(sr_im, sr_re); + float phase_difl = fabsf(fl_phase - sl_phase); + float phase_difr = fabsf(fr_phase - sr_phase); + float mag_difl = (fl_mag - sl_mag) / (fl_mag + sl_mag); + float mag_difr = (fr_mag - sr_mag) / (fr_mag + sr_mag); + float mag_totall = hypotf(fl_mag, sl_mag); + float mag_totalr = hypotf(fr_mag, sr_mag); + float bl_phase = atan2f(fl_im + sl_im, fl_re + sl_re); + float br_phase = atan2f(fr_im + sr_im, fr_re + sr_re); + float xl, yl; + float xr, yr; + + if (phase_difl > M_PI) + phase_difl = 2 * M_PI - phase_difl; + + if (phase_difr > M_PI) + phase_difr = 2 * M_PI - phase_difr; + + stereo_position(mag_difl, phase_difl, &xl, &yl); + stereo_position(mag_difr, phase_difr, &xr, &yr); + + s->upmix_5_1(ctx, c_re, c_im, lfe_re, lfe_im, + mag_totall, mag_totalr, + fl_phase, fr_phase, + bl_phase, br_phase, + sl_phase, sr_phase, + xl, yl, xr, yr, n); + } +} + static void filter_5_1_back(AVFilterContext *ctx) { AudioSurroundContext *s = ctx->priv; @@ -1063,6 +1244,26 @@ static int init(AVFilterContext *ctx) goto fail; } break; + case AV_CH_LAYOUT_5POINT0: + s->filter = filter_5_0_side; + switch (s->out_channel_layout) { + case AV_CH_LAYOUT_7POINT1: + s->upmix_5_0 = upmix_7_1_5_0_side; + break; + default: + goto fail; + } + break; + case AV_CH_LAYOUT_5POINT1: + s->filter = filter_5_1_side; + switch (s->out_channel_layout) { + case AV_CH_LAYOUT_7POINT1: + s->upmix_5_1 = upmix_7_1_5_1; + break; + default: + goto fail; + } + break; case AV_CH_LAYOUT_5POINT1_BACK: s->filter = filter_5_1_back; switch (s->out_channel_layout) { @@ -1149,18 +1350,19 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; AudioSurroundContext *s = ctx->priv; + int ret; - av_audio_fifo_write(s->fifo, (void **)in->extended_data, - in->nb_samples); - - if (s->pts == AV_NOPTS_VALUE) + ret = av_audio_fifo_write(s->fifo, (void **)in->extended_data, + in->nb_samples); + if (ret >= 0 && s->pts == AV_NOPTS_VALUE) s->pts = in->pts; av_frame_free(&in); + if (ret < 0) + return ret; while (av_audio_fifo_size(s->fifo) >= s->buf_size) { AVFrame *out; - int ret; ret = av_audio_fifo_peek(s->fifo, (void **)s->input->extended_data, s->buf_size); if (ret < 0) @@ -1188,6 +1390,27 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) return 0; } +static int request_frame(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + AudioSurroundContext *s = ctx->priv; + int ret = 0; + + ret = ff_request_frame(ctx->inputs[0]); + + if (ret == AVERROR_EOF && av_audio_fifo_size(s->fifo) > 0 && av_audio_fifo_size(s->fifo) < s->buf_size) { + AVFrame *in; + + in = ff_get_audio_buffer(outlink, s->buf_size - av_audio_fifo_size(s->fifo)); + if (!in) + return AVERROR(ENOMEM); + ret = filter_frame(ctx->inputs[0], in); + av_audio_fifo_drain(s->fifo, s->buf_size); + } + + return ret; +} + static av_cold void uninit(AVFilterContext *ctx) { AudioSurroundContext *s = ctx->priv; @@ -1243,9 +1466,10 @@ static const AVFilterPad inputs[] = { static const AVFilterPad outputs[] = { { - .name = "default", - .type = AVMEDIA_TYPE_AUDIO, - .config_props = config_output, + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .request_frame = request_frame, + .config_props = config_output, }, { NULL } }; diff --git a/libavfilter/af_tremolo.c b/libavfilter/af_tremolo.c index 572e9e3b56082..8cbc79892d123 100644 --- a/libavfilter/af_tremolo.c +++ b/libavfilter/af_tremolo.c @@ -57,7 +57,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_vibrato.c b/libavfilter/af_vibrato.c index c7691f2f2a8ee..22bbab6239b95 100644 --- a/libavfilter/af_vibrato.c +++ b/libavfilter/af_vibrato.c @@ -63,7 +63,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (av_frame_is_writable(in)) { out = in; } else { - out = ff_get_audio_buffer(inlink, in->nb_samples); + out = ff_get_audio_buffer(outlink, in->nb_samples); if (!out) { av_frame_free(&in); return AVERROR(ENOMEM); diff --git a/libavfilter/af_volume.c b/libavfilter/af_volume.c index 3d76f12f2cc66..b106ed8cf4aa8 100644 --- a/libavfilter/af_volume.c +++ b/libavfilter/af_volume.c @@ -410,7 +410,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *buf) && (vol->precision != PRECISION_FIXED || vol->volume_i > 0)) { out_buf = buf; } else { - out_buf = ff_get_audio_buffer(inlink, nb_samples); + out_buf = ff_get_audio_buffer(outlink, nb_samples); if (!out_buf) { av_frame_free(&buf); return AVERROR(ENOMEM); diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index 9b672a7a7e73f..68b299202719a 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -22,391 +22,458 @@ #include "libavutil/thread.h" #include "avfilter.h" #include "config.h" -#include "opencl_allkernels.h" +extern AVFilter ff_af_abench; +extern AVFilter ff_af_acompressor; +extern AVFilter ff_af_acontrast; +extern AVFilter ff_af_acopy; +extern AVFilter ff_af_acrossfade; +extern AVFilter ff_af_acrusher; +extern AVFilter ff_af_adelay; +extern AVFilter ff_af_aecho; +extern AVFilter ff_af_aemphasis; +extern AVFilter ff_af_aeval; +extern AVFilter ff_af_afade; +extern AVFilter ff_af_afftfilt; +extern AVFilter ff_af_afir; +extern AVFilter ff_af_aformat; +extern AVFilter ff_af_agate; +extern AVFilter ff_af_aiir; +extern AVFilter ff_af_ainterleave; +extern AVFilter ff_af_alimiter; +extern AVFilter ff_af_allpass; +extern AVFilter ff_af_aloop; +extern AVFilter ff_af_amerge; +extern AVFilter ff_af_ametadata; +extern AVFilter ff_af_amix; +extern AVFilter ff_af_anequalizer; +extern AVFilter ff_af_anull; +extern AVFilter ff_af_apad; +extern AVFilter ff_af_aperms; +extern AVFilter ff_af_aphaser; +extern AVFilter ff_af_apulsator; +extern AVFilter ff_af_arealtime; +extern AVFilter ff_af_aresample; +extern AVFilter ff_af_areverse; +extern AVFilter ff_af_aselect; +extern AVFilter ff_af_asendcmd; +extern AVFilter ff_af_asetnsamples; +extern AVFilter ff_af_asetpts; +extern AVFilter ff_af_asetrate; +extern AVFilter ff_af_asettb; +extern AVFilter ff_af_ashowinfo; +extern AVFilter ff_af_asidedata; +extern AVFilter ff_af_asplit; +extern AVFilter ff_af_astats; +extern AVFilter ff_af_astreamselect; +extern AVFilter ff_af_atempo; +extern AVFilter ff_af_atrim; +extern AVFilter ff_af_azmq; +extern AVFilter ff_af_bandpass; +extern AVFilter ff_af_bandreject; +extern AVFilter ff_af_bass; +extern AVFilter ff_af_biquad; +extern AVFilter ff_af_bs2b; +extern AVFilter ff_af_channelmap; +extern AVFilter ff_af_channelsplit; +extern AVFilter ff_af_chorus; +extern AVFilter ff_af_compand; +extern AVFilter ff_af_compensationdelay; +extern AVFilter ff_af_crossfeed; +extern AVFilter ff_af_crystalizer; +extern AVFilter ff_af_dcshift; +extern AVFilter ff_af_drmeter; +extern AVFilter ff_af_dynaudnorm; +extern AVFilter ff_af_earwax; +extern AVFilter ff_af_ebur128; +extern AVFilter ff_af_equalizer; +extern AVFilter ff_af_extrastereo; +extern AVFilter ff_af_firequalizer; +extern AVFilter ff_af_flanger; +extern AVFilter ff_af_haas; +extern AVFilter ff_af_hdcd; +extern AVFilter ff_af_headphone; +extern AVFilter ff_af_highpass; +extern AVFilter ff_af_join; +extern AVFilter ff_af_ladspa; +extern AVFilter ff_af_loudnorm; +extern AVFilter ff_af_lowpass; +extern AVFilter ff_af_lv2; +extern AVFilter ff_af_mcompand; +extern AVFilter ff_af_pan; +extern AVFilter ff_af_replaygain; +extern AVFilter ff_af_resample; +extern AVFilter ff_af_rubberband; +extern AVFilter ff_af_sidechaincompress; +extern AVFilter ff_af_sidechaingate; +extern AVFilter ff_af_silencedetect; +extern AVFilter ff_af_silenceremove; +extern AVFilter ff_af_sofalizer; +extern AVFilter ff_af_stereotools; +extern AVFilter ff_af_stereowiden; +extern AVFilter ff_af_superequalizer; +extern AVFilter ff_af_surround; +extern AVFilter ff_af_treble; +extern AVFilter ff_af_tremolo; +extern AVFilter ff_af_vibrato; +extern AVFilter ff_af_volume; +extern AVFilter ff_af_volumedetect; -#define REGISTER_FILTER(X, x, y) \ - { \ - extern AVFilter ff_##y##_##x; \ - if (CONFIG_##X##_FILTER) \ - avfilter_register(&ff_##y##_##x); \ - } +extern AVFilter ff_asrc_aevalsrc; +extern AVFilter ff_asrc_anoisesrc; +extern AVFilter ff_asrc_anullsrc; +extern AVFilter ff_asrc_flite; +extern AVFilter ff_asrc_hilbert; +extern AVFilter ff_asrc_sine; -#define REGISTER_FILTER_UNCONDITIONAL(x) \ - { \ - extern AVFilter ff_##x; \ - avfilter_register(&ff_##x); \ - } +extern AVFilter ff_asink_anullsink; + +extern AVFilter ff_vf_alphaextract; +extern AVFilter ff_vf_alphamerge; +extern AVFilter ff_vf_ass; +extern AVFilter ff_vf_atadenoise; +extern AVFilter ff_vf_avgblur; +extern AVFilter ff_vf_avgblur_opencl; +extern AVFilter ff_vf_bbox; +extern AVFilter ff_vf_bench; +extern AVFilter ff_vf_bitplanenoise; +extern AVFilter ff_vf_blackdetect; +extern AVFilter ff_vf_blackframe; +extern AVFilter ff_vf_blend; +extern AVFilter ff_vf_boxblur; +extern AVFilter ff_vf_bwdif; +extern AVFilter ff_vf_chromakey; +extern AVFilter ff_vf_ciescope; +extern AVFilter ff_vf_codecview; +extern AVFilter ff_vf_colorbalance; +extern AVFilter ff_vf_colorchannelmixer; +extern AVFilter ff_vf_colorkey; +extern AVFilter ff_vf_colorlevels; +extern AVFilter ff_vf_colormatrix; +extern AVFilter ff_vf_colorspace; +extern AVFilter ff_vf_convolution; +extern AVFilter ff_vf_convolution_opencl; +extern AVFilter ff_vf_convolve; +extern AVFilter ff_vf_copy; +extern AVFilter ff_vf_coreimage; +extern AVFilter ff_vf_cover_rect; +extern AVFilter ff_vf_crop; +extern AVFilter ff_vf_cropdetect; +extern AVFilter ff_vf_curves; +extern AVFilter ff_vf_datascope; +extern AVFilter ff_vf_dctdnoiz; +extern AVFilter ff_vf_deband; +extern AVFilter ff_vf_decimate; +extern AVFilter ff_vf_deconvolve; +extern AVFilter ff_vf_deflate; +extern AVFilter ff_vf_deflicker; +extern AVFilter ff_vf_deinterlace_qsv; +extern AVFilter ff_vf_deinterlace_vaapi; +extern AVFilter ff_vf_dejudder; +extern AVFilter ff_vf_delogo; +extern AVFilter ff_vf_denoise_vaapi; +extern AVFilter ff_vf_deshake; +extern AVFilter ff_vf_despill; +extern AVFilter ff_vf_detelecine; +extern AVFilter ff_vf_dilation; +extern AVFilter ff_vf_displace; +extern AVFilter ff_vf_doubleweave; +extern AVFilter ff_vf_drawbox; +extern AVFilter ff_vf_drawgraph; +extern AVFilter ff_vf_drawgrid; +extern AVFilter ff_vf_drawtext; +extern AVFilter ff_vf_edgedetect; +extern AVFilter ff_vf_elbg; +extern AVFilter ff_vf_entropy; +extern AVFilter ff_vf_eq; +extern AVFilter ff_vf_erosion; +extern AVFilter ff_vf_extractplanes; +extern AVFilter ff_vf_fade; +extern AVFilter ff_vf_fftfilt; +extern AVFilter ff_vf_field; +extern AVFilter ff_vf_fieldhint; +extern AVFilter ff_vf_fieldmatch; +extern AVFilter ff_vf_fieldorder; +extern AVFilter ff_vf_fillborders; +extern AVFilter ff_vf_find_rect; +extern AVFilter ff_vf_floodfill; +extern AVFilter ff_vf_format; +extern AVFilter ff_vf_fps; +extern AVFilter ff_vf_framepack; +extern AVFilter ff_vf_framerate; +extern AVFilter ff_vf_framestep; +extern AVFilter ff_vf_frei0r; +extern AVFilter ff_vf_fspp; +extern AVFilter ff_vf_gblur; +extern AVFilter ff_vf_geq; +extern AVFilter ff_vf_gradfun; +extern AVFilter ff_vf_haldclut; +extern AVFilter ff_vf_hflip; +extern AVFilter ff_vf_histeq; +extern AVFilter ff_vf_histogram; +extern AVFilter ff_vf_hqdn3d; +extern AVFilter ff_vf_hqx; +extern AVFilter ff_vf_hstack; +extern AVFilter ff_vf_hue; +extern AVFilter ff_vf_hwdownload; +extern AVFilter ff_vf_hwmap; +extern AVFilter ff_vf_hwupload; +extern AVFilter ff_vf_hwupload_cuda; +extern AVFilter ff_vf_hysteresis; +extern AVFilter ff_vf_idet; +extern AVFilter ff_vf_il; +extern AVFilter ff_vf_inflate; +extern AVFilter ff_vf_interlace; +extern AVFilter ff_vf_interleave; +extern AVFilter ff_vf_kerndeint; +extern AVFilter ff_vf_lenscorrection; +extern AVFilter ff_vf_libvmaf; +extern AVFilter ff_vf_limiter; +extern AVFilter ff_vf_loop; +extern AVFilter ff_vf_lumakey; +extern AVFilter ff_vf_lut; +extern AVFilter ff_vf_lut2; +extern AVFilter ff_vf_lut3d; +extern AVFilter ff_vf_lutrgb; +extern AVFilter ff_vf_lutyuv; +extern AVFilter ff_vf_maskedclamp; +extern AVFilter ff_vf_maskedmerge; +extern AVFilter ff_vf_mcdeint; +extern AVFilter ff_vf_mergeplanes; +extern AVFilter ff_vf_mestimate; +extern AVFilter ff_vf_metadata; +extern AVFilter ff_vf_midequalizer; +extern AVFilter ff_vf_minterpolate; +extern AVFilter ff_vf_mix; +extern AVFilter ff_vf_mpdecimate; +extern AVFilter ff_vf_negate; +extern AVFilter ff_vf_nlmeans; +extern AVFilter ff_vf_nnedi; +extern AVFilter ff_vf_noformat; +extern AVFilter ff_vf_noise; +extern AVFilter ff_vf_normalize; +extern AVFilter ff_vf_null; +extern AVFilter ff_vf_ocr; +extern AVFilter ff_vf_ocv; +extern AVFilter ff_vf_oscilloscope; +extern AVFilter ff_vf_overlay; +extern AVFilter ff_vf_overlay_opencl; +extern AVFilter ff_vf_overlay_qsv; +extern AVFilter ff_vf_owdenoise; +extern AVFilter ff_vf_pad; +extern AVFilter ff_vf_palettegen; +extern AVFilter ff_vf_paletteuse; +extern AVFilter ff_vf_perms; +extern AVFilter ff_vf_perspective; +extern AVFilter ff_vf_phase; +extern AVFilter ff_vf_pixdesctest; +extern AVFilter ff_vf_pixscope; +extern AVFilter ff_vf_pp; +extern AVFilter ff_vf_pp7; +extern AVFilter ff_vf_premultiply; +extern AVFilter ff_vf_prewitt; +extern AVFilter ff_vf_procamp_vaapi; +extern AVFilter ff_vf_program_opencl; +extern AVFilter ff_vf_pseudocolor; +extern AVFilter ff_vf_psnr; +extern AVFilter ff_vf_pullup; +extern AVFilter ff_vf_qp; +extern AVFilter ff_vf_random; +extern AVFilter ff_vf_readeia608; +extern AVFilter ff_vf_readvitc; +extern AVFilter ff_vf_realtime; +extern AVFilter ff_vf_remap; +extern AVFilter ff_vf_removegrain; +extern AVFilter ff_vf_removelogo; +extern AVFilter ff_vf_repeatfields; +extern AVFilter ff_vf_reverse; +extern AVFilter ff_vf_roberts; +extern AVFilter ff_vf_rotate; +extern AVFilter ff_vf_sab; +extern AVFilter ff_vf_scale; +extern AVFilter ff_vf_scale_cuda; +extern AVFilter ff_vf_scale_npp; +extern AVFilter ff_vf_scale_qsv; +extern AVFilter ff_vf_scale_vaapi; +extern AVFilter ff_vf_scale2ref; +extern AVFilter ff_vf_select; +extern AVFilter ff_vf_selectivecolor; +extern AVFilter ff_vf_sendcmd; +extern AVFilter ff_vf_separatefields; +extern AVFilter ff_vf_setdar; +extern AVFilter ff_vf_setfield; +extern AVFilter ff_vf_setpts; +extern AVFilter ff_vf_setrange; +extern AVFilter ff_vf_setsar; +extern AVFilter ff_vf_settb; +extern AVFilter ff_vf_sharpness_vaapi; +extern AVFilter ff_vf_showinfo; +extern AVFilter ff_vf_showpalette; +extern AVFilter ff_vf_shuffleframes; +extern AVFilter ff_vf_shuffleplanes; +extern AVFilter ff_vf_sidedata; +extern AVFilter ff_vf_signalstats; +extern AVFilter ff_vf_signature; +extern AVFilter ff_vf_smartblur; +extern AVFilter ff_vf_sobel; +extern AVFilter ff_vf_split; +extern AVFilter ff_vf_spp; +extern AVFilter ff_vf_ssim; +extern AVFilter ff_vf_stereo3d; +extern AVFilter ff_vf_streamselect; +extern AVFilter ff_vf_subtitles; +extern AVFilter ff_vf_super2xsai; +extern AVFilter ff_vf_swaprect; +extern AVFilter ff_vf_swapuv; +extern AVFilter ff_vf_tblend; +extern AVFilter ff_vf_telecine; +extern AVFilter ff_vf_threshold; +extern AVFilter ff_vf_thumbnail; +extern AVFilter ff_vf_thumbnail_cuda; +extern AVFilter ff_vf_tile; +extern AVFilter ff_vf_tinterlace; +extern AVFilter ff_vf_tlut2; +extern AVFilter ff_vf_tonemap; +extern AVFilter ff_vf_transpose; +extern AVFilter ff_vf_trim; +extern AVFilter ff_vf_unpremultiply; +extern AVFilter ff_vf_unsharp; +extern AVFilter ff_vf_unsharp_opencl; +extern AVFilter ff_vf_uspp; +extern AVFilter ff_vf_vaguedenoiser; +extern AVFilter ff_vf_vectorscope; +extern AVFilter ff_vf_vflip; +extern AVFilter ff_vf_vfrdet; +extern AVFilter ff_vf_vidstabdetect; +extern AVFilter ff_vf_vidstabtransform; +extern AVFilter ff_vf_vignette; +extern AVFilter ff_vf_vmafmotion; +extern AVFilter ff_vf_vpp_qsv; +extern AVFilter ff_vf_vstack; +extern AVFilter ff_vf_w3fdif; +extern AVFilter ff_vf_waveform; +extern AVFilter ff_vf_weave; +extern AVFilter ff_vf_xbr; +extern AVFilter ff_vf_yadif; +extern AVFilter ff_vf_zmq; +extern AVFilter ff_vf_zoompan; +extern AVFilter ff_vf_zscale; + +extern AVFilter ff_vsrc_allrgb; +extern AVFilter ff_vsrc_allyuv; +extern AVFilter ff_vsrc_cellauto; +extern AVFilter ff_vsrc_color; +extern AVFilter ff_vsrc_coreimagesrc; +extern AVFilter ff_vsrc_frei0r_src; +extern AVFilter ff_vsrc_haldclutsrc; +extern AVFilter ff_vsrc_life; +extern AVFilter ff_vsrc_mandelbrot; +extern AVFilter ff_vsrc_mptestsrc; +extern AVFilter ff_vsrc_nullsrc; +extern AVFilter ff_vsrc_openclsrc; +extern AVFilter ff_vsrc_rgbtestsrc; +extern AVFilter ff_vsrc_smptebars; +extern AVFilter ff_vsrc_smptehdbars; +extern AVFilter ff_vsrc_testsrc; +extern AVFilter ff_vsrc_testsrc2; +extern AVFilter ff_vsrc_yuvtestsrc; + +extern AVFilter ff_vsink_nullsink; + +/* multimedia filters */ +extern AVFilter ff_avf_abitscope; +extern AVFilter ff_avf_adrawgraph; +extern AVFilter ff_avf_ahistogram; +extern AVFilter ff_avf_aphasemeter; +extern AVFilter ff_avf_avectorscope; +extern AVFilter ff_avf_concat; +extern AVFilter ff_avf_showcqt; +extern AVFilter ff_avf_showfreqs; +extern AVFilter ff_avf_showspectrum; +extern AVFilter ff_avf_showspectrumpic; +extern AVFilter ff_avf_showvolume; +extern AVFilter ff_avf_showwaves; +extern AVFilter ff_avf_showwavespic; +extern AVFilter ff_vaf_spectrumsynth; -static void register_all(void) +/* multimedia sources */ +extern AVFilter ff_avsrc_amovie; +extern AVFilter ff_avsrc_movie; + +/* those filters are part of public or internal API, + * they are formatted to not be found by the grep + * as they are manually added again (due to their 'names' + * being the same while having different 'types'). */ +extern AVFilter ff_asrc_abuffer; +extern AVFilter ff_vsrc_buffer; +extern AVFilter ff_asink_abuffer; +extern AVFilter ff_vsink_buffer; +extern AVFilter ff_af_afifo; +extern AVFilter ff_vf_fifo; + +#include "libavfilter/filter_list.c" + + +const AVFilter *av_filter_iterate(void **opaque) { - REGISTER_FILTER(ABENCH, abench, af); - REGISTER_FILTER(ACOMPRESSOR, acompressor, af); - REGISTER_FILTER(ACOPY, acopy, af); - REGISTER_FILTER(ACROSSFADE, acrossfade, af); - REGISTER_FILTER(ACRUSHER, acrusher, af); - REGISTER_FILTER(ADELAY, adelay, af); - REGISTER_FILTER(AECHO, aecho, af); - REGISTER_FILTER(AEMPHASIS, aemphasis, af); - REGISTER_FILTER(AEVAL, aeval, af); - REGISTER_FILTER(AFADE, afade, af); - REGISTER_FILTER(AFFTFILT, afftfilt, af); - REGISTER_FILTER(AFIR, afir, af); - REGISTER_FILTER(AFORMAT, aformat, af); - REGISTER_FILTER(AGATE, agate, af); - REGISTER_FILTER(AINTERLEAVE, ainterleave, af); - REGISTER_FILTER(ALIMITER, alimiter, af); - REGISTER_FILTER(ALLPASS, allpass, af); - REGISTER_FILTER(ALOOP, aloop, af); - REGISTER_FILTER(AMERGE, amerge, af); - REGISTER_FILTER(AMETADATA, ametadata, af); - REGISTER_FILTER(AMIX, amix, af); - REGISTER_FILTER(ANEQUALIZER, anequalizer, af); - REGISTER_FILTER(ANULL, anull, af); - REGISTER_FILTER(APAD, apad, af); - REGISTER_FILTER(APERMS, aperms, af); - REGISTER_FILTER(APHASER, aphaser, af); - REGISTER_FILTER(APULSATOR, apulsator, af); - REGISTER_FILTER(AREALTIME, arealtime, af); - REGISTER_FILTER(ARESAMPLE, aresample, af); - REGISTER_FILTER(AREVERSE, areverse, af); - REGISTER_FILTER(ASELECT, aselect, af); - REGISTER_FILTER(ASENDCMD, asendcmd, af); - REGISTER_FILTER(ASETNSAMPLES, asetnsamples, af); - REGISTER_FILTER(ASETPTS, asetpts, af); - REGISTER_FILTER(ASETRATE, asetrate, af); - REGISTER_FILTER(ASETTB, asettb, af); - REGISTER_FILTER(ASHOWINFO, ashowinfo, af); - REGISTER_FILTER(ASIDEDATA, asidedata, af); - REGISTER_FILTER(ASPLIT, asplit, af); - REGISTER_FILTER(ASTATS, astats, af); - REGISTER_FILTER(ASTREAMSELECT, astreamselect, af); - REGISTER_FILTER(ATEMPO, atempo, af); - REGISTER_FILTER(ATRIM, atrim, af); - REGISTER_FILTER(AZMQ, azmq, af); - REGISTER_FILTER(BANDPASS, bandpass, af); - REGISTER_FILTER(BANDREJECT, bandreject, af); - REGISTER_FILTER(BASS, bass, af); - REGISTER_FILTER(BIQUAD, biquad, af); - REGISTER_FILTER(BS2B, bs2b, af); - REGISTER_FILTER(CHANNELMAP, channelmap, af); - REGISTER_FILTER(CHANNELSPLIT, channelsplit, af); - REGISTER_FILTER(CHORUS, chorus, af); - REGISTER_FILTER(COMPAND, compand, af); - REGISTER_FILTER(COMPENSATIONDELAY, compensationdelay, af); - REGISTER_FILTER(CROSSFEED, crossfeed, af); - REGISTER_FILTER(CRYSTALIZER, crystalizer, af); - REGISTER_FILTER(DCSHIFT, dcshift, af); - REGISTER_FILTER(DYNAUDNORM, dynaudnorm, af); - REGISTER_FILTER(EARWAX, earwax, af); - REGISTER_FILTER(EBUR128, ebur128, af); - REGISTER_FILTER(EQUALIZER, equalizer, af); - REGISTER_FILTER(EXTRASTEREO, extrastereo, af); - REGISTER_FILTER(FIREQUALIZER, firequalizer, af); - REGISTER_FILTER(FLANGER, flanger, af); - REGISTER_FILTER(HAAS, haas, af); - REGISTER_FILTER(HDCD, hdcd, af); - REGISTER_FILTER(HEADPHONE, headphone, af); - REGISTER_FILTER(HIGHPASS, highpass, af); - REGISTER_FILTER(JOIN, join, af); - REGISTER_FILTER(LADSPA, ladspa, af); - REGISTER_FILTER(LOUDNORM, loudnorm, af); - REGISTER_FILTER(LOWPASS, lowpass, af); - REGISTER_FILTER(PAN, pan, af); - REGISTER_FILTER(REPLAYGAIN, replaygain, af); - REGISTER_FILTER(RESAMPLE, resample, af); - REGISTER_FILTER(RUBBERBAND, rubberband, af); - REGISTER_FILTER(SIDECHAINCOMPRESS, sidechaincompress, af); - REGISTER_FILTER(SIDECHAINGATE, sidechaingate, af); - REGISTER_FILTER(SILENCEDETECT, silencedetect, af); - REGISTER_FILTER(SILENCEREMOVE, silenceremove, af); - REGISTER_FILTER(SOFALIZER, sofalizer, af); - REGISTER_FILTER(STEREOTOOLS, stereotools, af); - REGISTER_FILTER(STEREOWIDEN, stereowiden, af); - REGISTER_FILTER(SUPEREQUALIZER, superequalizer, af); - REGISTER_FILTER(SURROUND, surround, af); - REGISTER_FILTER(TREBLE, treble, af); - REGISTER_FILTER(TREMOLO, tremolo, af); - REGISTER_FILTER(VIBRATO, vibrato, af); - REGISTER_FILTER(VOLUME, volume, af); - REGISTER_FILTER(VOLUMEDETECT, volumedetect, af); + uintptr_t i = (uintptr_t)*opaque; + const AVFilter *f = filter_list[i]; + + if (f) + *opaque = (void*)(i + 1); - REGISTER_FILTER(AEVALSRC, aevalsrc, asrc); - REGISTER_FILTER(ANOISESRC, anoisesrc, asrc); - REGISTER_FILTER(ANULLSRC, anullsrc, asrc); - REGISTER_FILTER(FLITE, flite, asrc); - REGISTER_FILTER(SINE, sine, asrc); + return f; +} - REGISTER_FILTER(ANULLSINK, anullsink, asink); +const AVFilter *avfilter_get_by_name(const char *name) +{ + const AVFilter *f = NULL; + void *opaque = 0; - REGISTER_FILTER(ALPHAEXTRACT, alphaextract, vf); - REGISTER_FILTER(ALPHAMERGE, alphamerge, vf); - REGISTER_FILTER(ASS, ass, vf); - REGISTER_FILTER(ATADENOISE, atadenoise, vf); - REGISTER_FILTER(AVGBLUR, avgblur, vf); - REGISTER_FILTER(BBOX, bbox, vf); - REGISTER_FILTER(BENCH, bench, vf); - REGISTER_FILTER(BITPLANENOISE, bitplanenoise, vf); - REGISTER_FILTER(BLACKDETECT, blackdetect, vf); - REGISTER_FILTER(BLACKFRAME, blackframe, vf); - REGISTER_FILTER(BLEND, blend, vf); - REGISTER_FILTER(BOXBLUR, boxblur, vf); - REGISTER_FILTER(BWDIF, bwdif, vf); - REGISTER_FILTER(CHROMAKEY, chromakey, vf); - REGISTER_FILTER(CIESCOPE, ciescope, vf); - REGISTER_FILTER(CODECVIEW, codecview, vf); - REGISTER_FILTER(COLORBALANCE, colorbalance, vf); - REGISTER_FILTER(COLORCHANNELMIXER, colorchannelmixer, vf); - REGISTER_FILTER(COLORKEY, colorkey, vf); - REGISTER_FILTER(COLORLEVELS, colorlevels, vf); - REGISTER_FILTER(COLORMATRIX, colormatrix, vf); - REGISTER_FILTER(COLORSPACE, colorspace, vf); - REGISTER_FILTER(CONVOLUTION, convolution, vf); - REGISTER_FILTER(CONVOLVE, convolve, vf); - REGISTER_FILTER(COPY, copy, vf); - REGISTER_FILTER(COREIMAGE, coreimage, vf); - REGISTER_FILTER(COVER_RECT, cover_rect, vf); - REGISTER_FILTER(CROP, crop, vf); - REGISTER_FILTER(CROPDETECT, cropdetect, vf); - REGISTER_FILTER(CURVES, curves, vf); - REGISTER_FILTER(DATASCOPE, datascope, vf); - REGISTER_FILTER(DCTDNOIZ, dctdnoiz, vf); - REGISTER_FILTER(DEBAND, deband, vf); - REGISTER_FILTER(DECIMATE, decimate, vf); - REGISTER_FILTER(DEFLATE, deflate, vf); - REGISTER_FILTER(DEFLICKER, deflicker, vf); - REGISTER_FILTER(DEINTERLACE_QSV,deinterlace_qsv,vf); - REGISTER_FILTER(DEINTERLACE_VAAPI, deinterlace_vaapi, vf); - REGISTER_FILTER(DEJUDDER, dejudder, vf); - REGISTER_FILTER(DELOGO, delogo, vf); - REGISTER_FILTER(DESHAKE, deshake, vf); - REGISTER_FILTER(DESPILL, despill, vf); - REGISTER_FILTER(DETELECINE, detelecine, vf); - REGISTER_FILTER(DILATION, dilation, vf); - REGISTER_FILTER(DISPLACE, displace, vf); - REGISTER_FILTER(DOUBLEWEAVE, doubleweave, vf); - REGISTER_FILTER(DRAWBOX, drawbox, vf); - REGISTER_FILTER(DRAWGRAPH, drawgraph, vf); - REGISTER_FILTER(DRAWGRID, drawgrid, vf); - REGISTER_FILTER(DRAWTEXT, drawtext, vf); - REGISTER_FILTER(EDGEDETECT, edgedetect, vf); - REGISTER_FILTER(ELBG, elbg, vf); - REGISTER_FILTER(EQ, eq, vf); - REGISTER_FILTER(EROSION, erosion, vf); - REGISTER_FILTER(EXTRACTPLANES, extractplanes, vf); - REGISTER_FILTER(FADE, fade, vf); - REGISTER_FILTER(FFTFILT, fftfilt, vf); - REGISTER_FILTER(FIELD, field, vf); - REGISTER_FILTER(FIELDHINT, fieldhint, vf); - REGISTER_FILTER(FIELDMATCH, fieldmatch, vf); - REGISTER_FILTER(FIELDORDER, fieldorder, vf); - REGISTER_FILTER(FIND_RECT, find_rect, vf); - REGISTER_FILTER(FLOODFILL, floodfill, vf); - REGISTER_FILTER(FORMAT, format, vf); - REGISTER_FILTER(FPS, fps, vf); - REGISTER_FILTER(FRAMEPACK, framepack, vf); - REGISTER_FILTER(FRAMERATE, framerate, vf); - REGISTER_FILTER(FRAMESTEP, framestep, vf); - REGISTER_FILTER(FREI0R, frei0r, vf); - REGISTER_FILTER(FSPP, fspp, vf); - REGISTER_FILTER(GBLUR, gblur, vf); - REGISTER_FILTER(GEQ, geq, vf); - REGISTER_FILTER(GRADFUN, gradfun, vf); - REGISTER_FILTER(HALDCLUT, haldclut, vf); - REGISTER_FILTER(HFLIP, hflip, vf); - REGISTER_FILTER(HISTEQ, histeq, vf); - REGISTER_FILTER(HISTOGRAM, histogram, vf); - REGISTER_FILTER(HQDN3D, hqdn3d, vf); - REGISTER_FILTER(HQX, hqx, vf); - REGISTER_FILTER(HSTACK, hstack, vf); - REGISTER_FILTER(HUE, hue, vf); - REGISTER_FILTER(HWDOWNLOAD, hwdownload, vf); - REGISTER_FILTER(HWMAP, hwmap, vf); - REGISTER_FILTER(HWUPLOAD, hwupload, vf); - REGISTER_FILTER(HWUPLOAD_CUDA, hwupload_cuda, vf); - REGISTER_FILTER(HYSTERESIS, hysteresis, vf); - REGISTER_FILTER(IDET, idet, vf); - REGISTER_FILTER(IL, il, vf); - REGISTER_FILTER(INFLATE, inflate, vf); - REGISTER_FILTER(INTERLACE, interlace, vf); - REGISTER_FILTER(INTERLEAVE, interleave, vf); - REGISTER_FILTER(KERNDEINT, kerndeint, vf); - REGISTER_FILTER(LENSCORRECTION, lenscorrection, vf); - REGISTER_FILTER(LIBVMAF, libvmaf, vf); - REGISTER_FILTER(LIMITER, limiter, vf); - REGISTER_FILTER(LOOP, loop, vf); - REGISTER_FILTER(LUMAKEY, lumakey, vf); - REGISTER_FILTER(LUT, lut, vf); - REGISTER_FILTER(LUT2, lut2, vf); - REGISTER_FILTER(LUT3D, lut3d, vf); - REGISTER_FILTER(LUTRGB, lutrgb, vf); - REGISTER_FILTER(LUTYUV, lutyuv, vf); - REGISTER_FILTER(MASKEDCLAMP, maskedclamp, vf); - REGISTER_FILTER(MASKEDMERGE, maskedmerge, vf); - REGISTER_FILTER(MCDEINT, mcdeint, vf); - REGISTER_FILTER(MERGEPLANES, mergeplanes, vf); - REGISTER_FILTER(MESTIMATE, mestimate, vf); - REGISTER_FILTER(METADATA, metadata, vf); - REGISTER_FILTER(MIDEQUALIZER, midequalizer, vf); - REGISTER_FILTER(MINTERPOLATE, minterpolate, vf); - REGISTER_FILTER(MPDECIMATE, mpdecimate, vf); - REGISTER_FILTER(NEGATE, negate, vf); - REGISTER_FILTER(NLMEANS, nlmeans, vf); - REGISTER_FILTER(NNEDI, nnedi, vf); - REGISTER_FILTER(NOFORMAT, noformat, vf); - REGISTER_FILTER(NOISE, noise, vf); - REGISTER_FILTER(NULL, null, vf); - REGISTER_FILTER(OCR, ocr, vf); - REGISTER_FILTER(OCV, ocv, vf); - REGISTER_FILTER(OSCILLOSCOPE, oscilloscope, vf); - REGISTER_FILTER(OVERLAY, overlay, vf); - REGISTER_FILTER(OWDENOISE, owdenoise, vf); - REGISTER_FILTER(PAD, pad, vf); - REGISTER_FILTER(PALETTEGEN, palettegen, vf); - REGISTER_FILTER(PALETTEUSE, paletteuse, vf); - REGISTER_FILTER(PERMS, perms, vf); - REGISTER_FILTER(PERSPECTIVE, perspective, vf); - REGISTER_FILTER(PHASE, phase, vf); - REGISTER_FILTER(PIXDESCTEST, pixdesctest, vf); - REGISTER_FILTER(PIXSCOPE, pixscope, vf); - REGISTER_FILTER(PP, pp, vf); - REGISTER_FILTER(PP7, pp7, vf); - REGISTER_FILTER(PREMULTIPLY, premultiply, vf); - REGISTER_FILTER(PREWITT, prewitt, vf); - REGISTER_FILTER(PSEUDOCOLOR, pseudocolor, vf); - REGISTER_FILTER(PSNR, psnr, vf); - REGISTER_FILTER(PULLUP, pullup, vf); - REGISTER_FILTER(QP, qp, vf); - REGISTER_FILTER(RANDOM, random, vf); - REGISTER_FILTER(READEIA608, readeia608, vf); - REGISTER_FILTER(READVITC, readvitc, vf); - REGISTER_FILTER(REALTIME, realtime, vf); - REGISTER_FILTER(REMAP, remap, vf); - REGISTER_FILTER(REMOVEGRAIN, removegrain, vf); - REGISTER_FILTER(REMOVELOGO, removelogo, vf); - REGISTER_FILTER(REPEATFIELDS, repeatfields, vf); - REGISTER_FILTER(REVERSE, reverse, vf); - REGISTER_FILTER(ROBERTS, roberts, vf); - REGISTER_FILTER(ROTATE, rotate, vf); - REGISTER_FILTER(SAB, sab, vf); - REGISTER_FILTER(SCALE, scale, vf); - REGISTER_FILTER(SCALE_CUDA, scale_cuda, vf); - REGISTER_FILTER(SCALE_NPP, scale_npp, vf); - REGISTER_FILTER(SCALE_QSV, scale_qsv, vf); - REGISTER_FILTER(SCALE_VAAPI, scale_vaapi, vf); - REGISTER_FILTER(SCALE2REF, scale2ref, vf); - REGISTER_FILTER(SELECT, select, vf); - REGISTER_FILTER(SELECTIVECOLOR, selectivecolor, vf); - REGISTER_FILTER(SENDCMD, sendcmd, vf); - REGISTER_FILTER(SEPARATEFIELDS, separatefields, vf); - REGISTER_FILTER(SETDAR, setdar, vf); - REGISTER_FILTER(SETFIELD, setfield, vf); - REGISTER_FILTER(SETPTS, setpts, vf); - REGISTER_FILTER(SETSAR, setsar, vf); - REGISTER_FILTER(SETTB, settb, vf); - REGISTER_FILTER(SHOWINFO, showinfo, vf); - REGISTER_FILTER(SHOWPALETTE, showpalette, vf); - REGISTER_FILTER(SHUFFLEFRAMES, shuffleframes, vf); - REGISTER_FILTER(SHUFFLEPLANES, shuffleplanes, vf); - REGISTER_FILTER(SIDEDATA, sidedata, vf); - REGISTER_FILTER(SIGNALSTATS, signalstats, vf); - REGISTER_FILTER(SIGNATURE, signature, vf); - REGISTER_FILTER(SMARTBLUR, smartblur, vf); - REGISTER_FILTER(SOBEL, sobel, vf); - REGISTER_FILTER(SPLIT, split, vf); - REGISTER_FILTER(SPP, spp, vf); - REGISTER_FILTER(SSIM, ssim, vf); - REGISTER_FILTER(STEREO3D, stereo3d, vf); - REGISTER_FILTER(STREAMSELECT, streamselect, vf); - REGISTER_FILTER(SUBTITLES, subtitles, vf); - REGISTER_FILTER(SUPER2XSAI, super2xsai, vf); - REGISTER_FILTER(SWAPRECT, swaprect, vf); - REGISTER_FILTER(SWAPUV, swapuv, vf); - REGISTER_FILTER(TBLEND, tblend, vf); - REGISTER_FILTER(TELECINE, telecine, vf); - REGISTER_FILTER(THRESHOLD, threshold, vf); - REGISTER_FILTER(THUMBNAIL, thumbnail, vf); - REGISTER_FILTER(THUMBNAIL_CUDA, thumbnail_cuda, vf); - REGISTER_FILTER(TILE, tile, vf); - REGISTER_FILTER(TINTERLACE, tinterlace, vf); - REGISTER_FILTER(TLUT2, tlut2, vf); - REGISTER_FILTER(TONEMAP, tonemap, vf); - REGISTER_FILTER(TRANSPOSE, transpose, vf); - REGISTER_FILTER(TRIM, trim, vf); - REGISTER_FILTER(UNPREMULTIPLY, unpremultiply, vf); - REGISTER_FILTER(UNSHARP, unsharp, vf); - REGISTER_FILTER(USPP, uspp, vf); - REGISTER_FILTER(VAGUEDENOISER, vaguedenoiser, vf); - REGISTER_FILTER(VECTORSCOPE, vectorscope, vf); - REGISTER_FILTER(VFLIP, vflip, vf); - REGISTER_FILTER(VIDSTABDETECT, vidstabdetect, vf); - REGISTER_FILTER(VIDSTABTRANSFORM, vidstabtransform, vf); - REGISTER_FILTER(VIGNETTE, vignette, vf); - REGISTER_FILTER(VMAFMOTION, vmafmotion, vf); - REGISTER_FILTER(VSTACK, vstack, vf); - REGISTER_FILTER(W3FDIF, w3fdif, vf); - REGISTER_FILTER(WAVEFORM, waveform, vf); - REGISTER_FILTER(WEAVE, weave, vf); - REGISTER_FILTER(XBR, xbr, vf); - REGISTER_FILTER(YADIF, yadif, vf); - REGISTER_FILTER(ZMQ, zmq, vf); - REGISTER_FILTER(ZOOMPAN, zoompan, vf); - REGISTER_FILTER(ZSCALE, zscale, vf); + if (!name) + return NULL; - REGISTER_FILTER(ALLRGB, allrgb, vsrc); - REGISTER_FILTER(ALLYUV, allyuv, vsrc); - REGISTER_FILTER(CELLAUTO, cellauto, vsrc); - REGISTER_FILTER(COLOR, color, vsrc); - REGISTER_FILTER(COREIMAGESRC, coreimagesrc, vsrc); - REGISTER_FILTER(FREI0R, frei0r_src, vsrc); - REGISTER_FILTER(HALDCLUTSRC, haldclutsrc, vsrc); - REGISTER_FILTER(LIFE, life, vsrc); - REGISTER_FILTER(MANDELBROT, mandelbrot, vsrc); - REGISTER_FILTER(MPTESTSRC, mptestsrc, vsrc); - REGISTER_FILTER(NULLSRC, nullsrc, vsrc); - REGISTER_FILTER(RGBTESTSRC, rgbtestsrc, vsrc); - REGISTER_FILTER(SMPTEBARS, smptebars, vsrc); - REGISTER_FILTER(SMPTEHDBARS, smptehdbars, vsrc); - REGISTER_FILTER(TESTSRC, testsrc, vsrc); - REGISTER_FILTER(TESTSRC2, testsrc2, vsrc); - REGISTER_FILTER(YUVTESTSRC, yuvtestsrc, vsrc); + while ((f = av_filter_iterate(&opaque))) + if (!strcmp(f->name, name)) + return (AVFilter *)f; - REGISTER_FILTER(NULLSINK, nullsink, vsink); + return NULL; +} - /* multimedia filters */ - REGISTER_FILTER(ABITSCOPE, abitscope, avf); - REGISTER_FILTER(ADRAWGRAPH, adrawgraph, avf); - REGISTER_FILTER(AHISTOGRAM, ahistogram, avf); - REGISTER_FILTER(APHASEMETER, aphasemeter, avf); - REGISTER_FILTER(AVECTORSCOPE, avectorscope, avf); - REGISTER_FILTER(CONCAT, concat, avf); - REGISTER_FILTER(SHOWCQT, showcqt, avf); - REGISTER_FILTER(SHOWFREQS, showfreqs, avf); - REGISTER_FILTER(SHOWSPECTRUM, showspectrum, avf); - REGISTER_FILTER(SHOWSPECTRUMPIC, showspectrumpic, avf); - REGISTER_FILTER(SHOWVOLUME, showvolume, avf); - REGISTER_FILTER(SHOWWAVES, showwaves, avf); - REGISTER_FILTER(SHOWWAVESPIC, showwavespic, avf); - REGISTER_FILTER(SPECTRUMSYNTH, spectrumsynth, vaf); - /* multimedia sources */ - REGISTER_FILTER(AMOVIE, amovie, avsrc); - REGISTER_FILTER(MOVIE, movie, avsrc); +#if FF_API_NEXT +FF_DISABLE_DEPRECATION_WARNINGS +static AVOnce av_filter_next_init = AV_ONCE_INIT; - /* those filters are part of public or internal API => registered - * unconditionally */ - REGISTER_FILTER_UNCONDITIONAL(asrc_abuffer); - REGISTER_FILTER_UNCONDITIONAL(vsrc_buffer); - REGISTER_FILTER_UNCONDITIONAL(asink_abuffer); - REGISTER_FILTER_UNCONDITIONAL(vsink_buffer); - REGISTER_FILTER_UNCONDITIONAL(af_afifo); - REGISTER_FILTER_UNCONDITIONAL(vf_fifo); - ff_opencl_register_filter_kernel_code_all(); +static void av_filter_init_next(void) +{ + AVFilter *prev = NULL, *p; + void *i = 0; + while ((p = (AVFilter*)av_filter_iterate(&i))) { + if (prev) + prev->next = p; + prev = p; + } } void avfilter_register_all(void) { - static AVOnce control = AV_ONCE_INIT; + ff_thread_once(&av_filter_next_init, av_filter_init_next); +} + +int avfilter_register(AVFilter *filter) +{ + ff_thread_once(&av_filter_next_init, av_filter_init_next); + + return 0; +} + +const AVFilter *avfilter_next(const AVFilter *prev) +{ + ff_thread_once(&av_filter_next_init, av_filter_init_next); - ff_thread_once(&control, register_all); + return prev ? prev->next : filter_list[0]; } + +FF_ENABLE_DEPRECATION_WARNINGS +#endif diff --git a/libavfilter/asrc_hilbert.c b/libavfilter/asrc_hilbert.c new file mode 100644 index 0000000000000..a3a395254fef3 --- /dev/null +++ b/libavfilter/asrc_hilbert.c @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2018 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/opt.h" +#include "audio.h" +#include "avfilter.h" +#include "internal.h" +#include "window_func.h" + +typedef struct HilbertContext { + const AVClass *class; + + int sample_rate; + int nb_taps; + int nb_samples; + int win_func; + + float *taps; + int64_t pts; +} HilbertContext; + +#define OFFSET(x) offsetof(HilbertContext, x) +#define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption hilbert_options[] = { + { "sample_rate", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64=44100}, 1, INT_MAX, FLAGS }, + { "r", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64=44100}, 1, INT_MAX, FLAGS }, + { "taps", "set number of taps", OFFSET(nb_taps), AV_OPT_TYPE_INT, {.i64=22051}, 11, UINT16_MAX, FLAGS }, + { "t", "set number of taps", OFFSET(nb_taps), AV_OPT_TYPE_INT, {.i64=22051}, 11, UINT16_MAX, FLAGS }, + { "nb_samples", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64 = 1024}, 1, INT_MAX, FLAGS }, + { "n", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64 = 1024}, 1, INT_MAX, FLAGS }, + { "win_func", "set window function", OFFSET(win_func), AV_OPT_TYPE_INT, {.i64=WFUNC_BLACKMAN}, 0, NB_WFUNC-1, FLAGS, "win_func" }, + { "w", "set window function", OFFSET(win_func), AV_OPT_TYPE_INT, {.i64=WFUNC_BLACKMAN}, 0, NB_WFUNC-1, FLAGS, "win_func" }, + { "rect", "Rectangular", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_RECT}, 0, 0, FLAGS, "win_func" }, + { "bartlett", "Bartlett", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BARTLETT}, 0, 0, FLAGS, "win_func" }, + { "hanning", "Hanning", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HANNING}, 0, 0, FLAGS, "win_func" }, + { "hamming", "Hamming", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_HAMMING}, 0, 0, FLAGS, "win_func" }, + { "blackman", "Blackman", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BLACKMAN}, 0, 0, FLAGS, "win_func" }, + { "welch", "Welch", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_WELCH}, 0, 0, FLAGS, "win_func" }, + { "flattop", "Flat-top", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_FLATTOP}, 0, 0, FLAGS, "win_func" }, + { "bharris", "Blackman-Harris", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BHARRIS}, 0, 0, FLAGS, "win_func" }, + { "bnuttall", "Blackman-Nuttall", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BNUTTALL}, 0, 0, FLAGS, "win_func" }, + { "bhann", "Bartlett-Hann", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_BHANN}, 0, 0, FLAGS, "win_func" }, + { "sine", "Sine", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_SINE}, 0, 0, FLAGS, "win_func" }, + { "nuttall", "Nuttall", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_NUTTALL}, 0, 0, FLAGS, "win_func" }, + { "lanczos", "Lanczos", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_LANCZOS}, 0, 0, FLAGS, "win_func" }, + { "gauss", "Gauss", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_GAUSS}, 0, 0, FLAGS, "win_func" }, + { "tukey", "Tukey", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_TUKEY}, 0, 0, FLAGS, "win_func" }, + { "dolph", "Dolph-Chebyshev", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_DOLPH}, 0, 0, FLAGS, "win_func" }, + { "cauchy", "Cauchy", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_CAUCHY}, 0, 0, FLAGS, "win_func" }, + { "parzen", "Parzen", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_PARZEN}, 0, 0, FLAGS, "win_func" }, + { "poisson", "Poisson", 0, AV_OPT_TYPE_CONST, {.i64=WFUNC_POISSON}, 0, 0, FLAGS, "win_func" }, + {NULL} +}; + +AVFILTER_DEFINE_CLASS(hilbert); + +static av_cold int init(AVFilterContext *ctx) +{ + HilbertContext *s = ctx->priv; + + if (!(s->nb_taps & 1)) { + av_log(s, AV_LOG_ERROR, "Number of taps %d must be odd length.\n", s->nb_taps); + return AVERROR(EINVAL); + } + + return 0; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + HilbertContext *s = ctx->priv; + + av_freep(&s->taps); +} + +static av_cold int query_formats(AVFilterContext *ctx) +{ + HilbertContext *s = ctx->priv; + static const int64_t chlayouts[] = { AV_CH_LAYOUT_MONO, -1 }; + int sample_rates[] = { s->sample_rate, -1 }; + static const enum AVSampleFormat sample_fmts[] = { + AV_SAMPLE_FMT_FLT, + AV_SAMPLE_FMT_NONE + }; + + AVFilterFormats *formats; + AVFilterChannelLayouts *layouts; + int ret; + + formats = ff_make_format_list(sample_fmts); + if (!formats) + return AVERROR(ENOMEM); + ret = ff_set_common_formats (ctx, formats); + if (ret < 0) + return ret; + + layouts = avfilter_make_format64_list(chlayouts); + if (!layouts) + return AVERROR(ENOMEM); + ret = ff_set_common_channel_layouts(ctx, layouts); + if (ret < 0) + return ret; + + formats = ff_make_format_list(sample_rates); + if (!formats) + return AVERROR(ENOMEM); + return ff_set_common_samplerates(ctx, formats); +} + +static av_cold int config_props(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + HilbertContext *s = ctx->priv; + float overlap; + int i; + + s->taps = av_malloc_array(s->nb_taps, sizeof(*s->taps)); + if (!s->taps) + return AVERROR(ENOMEM); + + generate_window_func(s->taps, s->nb_taps, s->win_func, &overlap); + + for (i = 0; i < s->nb_taps; i++) { + int k = -(s->nb_taps / 2) + i; + + if (k & 1) { + float pk = M_PI * k; + + s->taps[i] *= (1.f - cosf(pk)) / pk; + } else { + s->taps[i] = 0.f; + } + } + + s->pts = 0; + + return 0; +} + +static int request_frame(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + HilbertContext *s = ctx->priv; + AVFrame *frame; + int nb_samples; + + nb_samples = FFMIN(s->nb_samples, s->nb_taps - s->pts); + if (!nb_samples) + return AVERROR_EOF; + + if (!(frame = ff_get_audio_buffer(outlink, nb_samples))) + return AVERROR(ENOMEM); + + memcpy(frame->data[0], s->taps + s->pts, nb_samples * sizeof(float)); + + frame->pts = s->pts; + s->pts += nb_samples; + return ff_filter_frame(outlink, frame); +} + +static const AVFilterPad hilbert_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .request_frame = request_frame, + .config_props = config_props, + }, + { NULL } +}; + +AVFilter ff_asrc_hilbert = { + .name = "hilbert", + .description = NULL_IF_CONFIG_SMALL("Generate a Hilbert transform FIR coefficients."), + .query_formats = query_formats, + .init = init, + .uninit = uninit, + .priv_size = sizeof(HilbertContext), + .inputs = NULL, + .outputs = hilbert_outputs, + .priv_class = &hilbert_class, +}; diff --git a/libavfilter/avf_avectorscope.c b/libavfilter/avf_avectorscope.c index c8ff0698e3c4c..75e0ee5e2a41f 100644 --- a/libavfilter/avf_avectorscope.c +++ b/libavfilter/avf_avectorscope.c @@ -65,6 +65,8 @@ typedef struct AudioVectorScopeContext { int contrast[4]; int fade[4]; double zoom; + int swap; + int mirror; unsigned prev_x, prev_y; AVRational frame_rate; } AudioVectorScopeContext; @@ -99,6 +101,12 @@ static const AVOption avectorscope_options[] = { { "sqrt", "square root", 0, AV_OPT_TYPE_CONST, {.i64=SQRT}, 0, 0, FLAGS, "scale" }, { "cbrt", "cube root", 0, AV_OPT_TYPE_CONST, {.i64=CBRT}, 0, 0, FLAGS, "scale" }, { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=LOG}, 0, 0, FLAGS, "scale" }, + { "swap", "swap x axis with y axis", OFFSET(swap), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS }, + { "mirror", "mirror axis", OFFSET(mirror), AV_OPT_TYPE_INT, {.i64=2}, 0, 3, FLAGS, "mirror" }, + { "none", "no mirror", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "mirror" }, + { "x", "mirror x", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "mirror" }, + { "y", "mirror y", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "mirror" }, + { "xy", "mirror both", 0, AV_OPT_TYPE_CONST, {.i64=3}, 0, 0, FLAGS, "mirror" }, { NULL } }; @@ -316,6 +324,15 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) break; } + if (s->mirror & 1) + src[0] = -src[0]; + + if (s->mirror & 2) + src[1] = -src[1]; + + if (s->swap) + FFSWAP(float, src[0], src[1]); + if (s->mode == LISSAJOUS) { x = ((src[1] - src[0]) * zoom / 2 + 1) * hw; y = (1.0 - (src[0] + src[1]) * zoom / 2) * hh; diff --git a/libavfilter/avf_concat.c b/libavfilter/avf_concat.c index 6198a33d53560..46bd42359b301 100644 --- a/libavfilter/avf_concat.c +++ b/libavfilter/avf_concat.c @@ -418,6 +418,19 @@ static av_cold void uninit(AVFilterContext *ctx) av_freep(&cat->in); } +static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, + char *res, int res_len, int flags) +{ + int ret = AVERROR(ENOSYS); + + if (!strcmp(cmd, "next")) { + av_log(ctx, AV_LOG_VERBOSE, "Command received: next\n"); + return flush_segment(ctx); + } + + return ret; +} + AVFilter ff_avf_concat = { .name = "concat", .description = NULL_IF_CONFIG_SMALL("Concatenate audio and video streams."), @@ -429,4 +442,5 @@ AVFilter ff_avf_concat = { .outputs = NULL, .priv_class = &concat_class, .flags = AVFILTER_FLAG_DYNAMIC_INPUTS | AVFILTER_FLAG_DYNAMIC_OUTPUTS, + .process_command = process_command, }; diff --git a/libavfilter/avf_showvolume.c b/libavfilter/avf_showvolume.c index 897e5709b8566..6b553c4eba774 100644 --- a/libavfilter/avf_showvolume.c +++ b/libavfilter/avf_showvolume.c @@ -33,6 +33,7 @@ static const char *const var_names[] = { "VOLUME", "CHANNEL", "PEAK", NULL }; enum { VAR_VOLUME, VAR_CHANNEL, VAR_PEAK, VAR_VARS_NB }; +enum DisplayScale { LINEAR, LOG, NB_DISPLAY_SCALE }; typedef struct ShowVolumeContext { const AVClass *class; @@ -43,6 +44,8 @@ typedef struct ShowVolumeContext { char *color; int orientation; int step; + float bgopacity; + int mode; AVFrame *out; AVExpr *c_expr; @@ -50,6 +53,17 @@ typedef struct ShowVolumeContext { int draw_volume; double *values; uint32_t *color_lut; + float *max; + float rms_factor; + int display_scale; + + double draw_persistent_duration; /* in second */ + uint8_t persistant_max_rgba[4]; + int persistent_max_frames; /* number of frames to check max value */ + float *max_persistent; /* max value for draw_persistent_max for each channel */ + int *nb_frames_max_display; /* number of frame for each channel, for displaying the max value */ + + void (*meter)(float *src, int nb_samples, float *max, float factor); } ShowVolumeContext; #define OFFSET(x) offsetof(ShowVolumeContext, x) @@ -61,14 +75,23 @@ static const AVOption showvolume_options[] = { { "b", "set border width", OFFSET(b), AV_OPT_TYPE_INT, {.i64=1}, 0, 5, FLAGS }, { "w", "set channel width", OFFSET(w), AV_OPT_TYPE_INT, {.i64=400}, 80, 8192, FLAGS }, { "h", "set channel height", OFFSET(h), AV_OPT_TYPE_INT, {.i64=20}, 1, 900, FLAGS }, - { "f", "set fade", OFFSET(f), AV_OPT_TYPE_DOUBLE, {.dbl=0.95}, 0.001, 1, FLAGS }, + { "f", "set fade", OFFSET(f), AV_OPT_TYPE_DOUBLE, {.dbl=0.95}, 0, 1, FLAGS }, { "c", "set volume color expression", OFFSET(color), AV_OPT_TYPE_STRING, {.str="PEAK*255+floor((1-PEAK)*255)*256+0xff000000"}, 0, 0, FLAGS }, { "t", "display channel names", OFFSET(draw_text), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS }, { "v", "display volume value", OFFSET(draw_volume), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS }, + { "dm", "duration for max value display", OFFSET(draw_persistent_duration), AV_OPT_TYPE_DOUBLE, {.dbl=0.}, 0, 9000, FLAGS}, + { "dmc","set color of the max value line", OFFSET(persistant_max_rgba), AV_OPT_TYPE_COLOR, {.str = "orange"}, CHAR_MIN, CHAR_MAX, FLAGS }, { "o", "set orientation", OFFSET(orientation), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "orientation" }, { "h", "horizontal", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "orientation" }, { "v", "vertical", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "orientation" }, { "s", "set step size", OFFSET(step), AV_OPT_TYPE_INT, {.i64=0}, 0, 5, FLAGS }, + { "p", "set background opacity", OFFSET(bgopacity), AV_OPT_TYPE_FLOAT, {.dbl=0}, 0, 1, FLAGS }, + { "m", "set mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "mode" }, + { "p", "peak", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "mode" }, + { "r", "rms", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "mode" }, + { "ds", "set display scale", OFFSET(display_scale), AV_OPT_TYPE_INT, {.i64=LINEAR}, LINEAR, NB_DISPLAY_SCALE - 1, FLAGS, "display_scale" }, + { "lin", "linear", 0, AV_OPT_TYPE_CONST, {.i64=LINEAR}, 0, 0, FLAGS, "display_scale" }, + { "log", "log", 0, AV_OPT_TYPE_CONST, {.i64=LOG}, 0, 0, FLAGS, "display_scale" }, { NULL } }; @@ -118,6 +141,23 @@ static int query_formats(AVFilterContext *ctx) return 0; } +static void find_peak(float *src, int nb_samples, float *peak, float factor) +{ + int i; + + *peak = 0; + for (i = 0; i < nb_samples; i++) + *peak = FFMAX(*peak, FFABS(src[i])); +} + +static void find_rms(float *src, int nb_samples, float *rms, float factor) +{ + int i; + + for (i = 0; i < nb_samples; i++) + *rms += factor * (src[i] * src[i] - *rms); +} + static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; @@ -136,6 +176,23 @@ static int config_input(AVFilterLink *inlink) if (!s->color_lut) return AVERROR(ENOMEM); + s->max = av_calloc(inlink->channels, sizeof(*s->max)); + if (!s->max) + return AVERROR(ENOMEM); + + s->rms_factor = 10000. / inlink->sample_rate; + + switch (s->mode) { + case 0: s->meter = find_peak; break; + case 1: s->meter = find_rms; break; + default: return AVERROR_BUG; + } + + if (s->draw_persistent_duration > 0.) { + s->persistent_max_frames = (int) FFMAX(av_q2d(s->frame_rate) * s->draw_persistent_duration, 1.); + s->max_persistent = av_calloc(inlink->channels * s->persistent_max_frames, sizeof(*s->max_persistent)); + s->nb_frames_max_display = av_calloc(inlink->channels * s->persistent_max_frames, sizeof(*s->nb_frames_max_display)); + } return 0; } @@ -183,7 +240,7 @@ static void drawtext(AVFrame *pic, int x, int y, const char *txt, int o) for (i = 0; txt[i]; i++) { int char_y, mask; - if (o) { + if (o) { /* vertical orientation */ for (char_y = font_height - 1; char_y >= 0; char_y--) { uint8_t *p = pic->data[0] + (y + i * 10) * pic->linesize[0] + x * 4; for (mask = 0x80; mask; mask >>= 1) { @@ -192,7 +249,7 @@ static void drawtext(AVFrame *pic, int x, int y, const char *txt, int o) p += pic->linesize[0]; } } - } else { + } else { /* horizontal orientation */ uint8_t *p = pic->data[0] + y * pic->linesize[0] + (x + i * 8) * 4; for (char_y = 0; char_y < font_height; char_y++) { for (mask = 0x80; mask; mask >>= 1) { @@ -206,13 +263,67 @@ static void drawtext(AVFrame *pic, int x, int y, const char *txt, int o) } } +static void clear_picture(ShowVolumeContext *s, AVFilterLink *outlink) +{ + int i, j; + const uint32_t bg = (uint32_t)(s->bgopacity * 255) << 24; + + for (i = 0; i < outlink->h; i++) { + uint32_t *dst = (uint32_t *)(s->out->data[0] + i * s->out->linesize[0]); + for (j = 0; j < outlink->w; j++) + AV_WN32A(dst + j, bg); + } +} + +static inline int calc_max_draw(ShowVolumeContext *s, AVFilterLink *outlink, float max) +{ + float max_val; + if (s->display_scale == LINEAR) { + max_val = max; + } else { /* log */ + max_val = av_clipf(0.21 * log10(max) + 1, 0, 1); + } + if (s->orientation) { /* vertical */ + return outlink->h - outlink->h * max_val; + } else { /* horizontal */ + return s->w * max_val; + } +} + +static inline void calc_persistent_max(ShowVolumeContext *s, float max, int channel) +{ + /* update max value for persistent max display */ + if ((max >= s->max_persistent[channel]) || (s->nb_frames_max_display[channel] >= s->persistent_max_frames)) { /* update max value for display */ + s->max_persistent[channel] = max; + s->nb_frames_max_display[channel] = 0; + } else { + s->nb_frames_max_display[channel] += 1; /* incremente display frame count */ + } +} + +static inline void draw_max_line(ShowVolumeContext *s, int max_draw, int channel) +{ + int k; + if (s->orientation) { /* vertical */ + uint8_t *dst = s->out->data[0] + max_draw * s->out->linesize[0] + channel * (s->b + s->h) * 4; + for (k = 0; k < s->h; k++) { + memcpy(dst + k * 4, s->persistant_max_rgba, sizeof(s->persistant_max_rgba)); + } + } else { /* horizontal */ + for (k = 0; k < s->h; k++) { + uint8_t *dst = s->out->data[0] + (channel * s->h + channel * s->b + k) * s->out->linesize[0]; + memcpy(dst + max_draw * 4, s->persistant_max_rgba, sizeof(s->persistant_max_rgba)); + } + } +} + static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) { AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; ShowVolumeContext *s = ctx->priv; const int step = s->step; - int c, i, j, k; + int c, j, k, max_draw; AVFrame *out; if (!s->out || s->out->width != outlink->w || @@ -223,35 +334,40 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) av_frame_free(&insamples); return AVERROR(ENOMEM); } - - for (i = 0; i < outlink->h; i++) - memset(s->out->data[0] + i * s->out->linesize[0], 0, outlink->w * 4); + clear_picture(s, outlink); } s->out->pts = insamples->pts; - for (j = 0; j < outlink->h; j++) { - uint8_t *dst = s->out->data[0] + j * s->out->linesize[0]; - for (k = 0; k < outlink->w; k++) { - dst[k * 4 + 0] = FFMAX(dst[k * 4 + 0] * s->f, 0); - dst[k * 4 + 1] = FFMAX(dst[k * 4 + 1] * s->f, 0); - dst[k * 4 + 2] = FFMAX(dst[k * 4 + 2] * s->f, 0); - dst[k * 4 + 3] = FFMAX(dst[k * 4 + 3] * s->f, 0); + if ((s->f < 1.) && (s->f > 0.)) { + for (j = 0; j < outlink->h; j++) { + uint8_t *dst = s->out->data[0] + j * s->out->linesize[0]; + const uint32_t alpha = s->bgopacity * 255; + + for (k = 0; k < outlink->w; k++) { + dst[k * 4 + 0] = FFMAX(dst[k * 4 + 0] * s->f, 0); + dst[k * 4 + 1] = FFMAX(dst[k * 4 + 1] * s->f, 0); + dst[k * 4 + 2] = FFMAX(dst[k * 4 + 2] * s->f, 0); + dst[k * 4 + 3] = FFMAX(dst[k * 4 + 3] * s->f, alpha); + } } + } else if (s->f == 0.) { + clear_picture(s, outlink); } - if (s->orientation) { + if (s->orientation) { /* vertical */ for (c = 0; c < inlink->channels; c++) { float *src = (float *)insamples->extended_data[c]; uint32_t *lut = s->color_lut + s->w * c; - float max = 0; + float max; - for (i = 0; i < insamples->nb_samples; i++) - max = FFMAX(max, src[i]); + s->meter(src, insamples->nb_samples, &s->max[c], s->rms_factor); + max = s->max[c]; s->values[c * VAR_VARS_NB + VAR_VOLUME] = 20.0 * log10(max); max = av_clipf(max, 0, 1); + max_draw = calc_max_draw(s, outlink, max); - for (j = outlink->h - outlink->h * max; j < s->w; j++) { + for (j = max_draw; j < s->w; j++) { uint8_t *dst = s->out->data[0] + j * s->out->linesize[0] + c * (s->b + s->h) * 4; for (k = 0; k < s->h; k++) { AV_WN32A(&dst[k * 4], lut[s->w - j - 1]); @@ -266,23 +382,30 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) continue; drawtext(s->out, c * (s->h + s->b) + (s->h - 10) / 2, outlink->h - 35, channel_name, 1); } + + if (s->draw_persistent_duration > 0.) { + calc_persistent_max(s, max, c); + max_draw = FFMAX(0, calc_max_draw(s, outlink, s->max_persistent[c]) - 1); + draw_max_line(s, max_draw, c); + } } - } else { + } else { /* horizontal */ for (c = 0; c < inlink->channels; c++) { float *src = (float *)insamples->extended_data[c]; uint32_t *lut = s->color_lut + s->w * c; - float max = 0; + float max; - for (i = 0; i < insamples->nb_samples; i++) - max = FFMAX(max, src[i]); + s->meter(src, insamples->nb_samples, &s->max[c], s->rms_factor); + max = s->max[c]; s->values[c * VAR_VARS_NB + VAR_VOLUME] = 20.0 * log10(max); max = av_clipf(max, 0, 1); + max_draw = calc_max_draw(s, outlink, max); for (j = 0; j < s->h; j++) { uint8_t *dst = s->out->data[0] + (c * s->h + c * s->b + j) * s->out->linesize[0]; - for (k = 0; k < s->w * max; k++) { + for (k = 0; k < max_draw; k++) { AV_WN32A(dst + k * 4, lut[k]); if (k & step) k += step; @@ -295,6 +418,12 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) continue; drawtext(s->out, 2, c * (s->h + s->b) + (s->h - 8) / 2, channel_name, 0); } + + if (s->draw_persistent_duration > 0.) { + calc_persistent_max(s, max, c); + max_draw = FFMAX(0, calc_max_draw(s, outlink, s->max_persistent[c]) - 1); + draw_max_line(s, max_draw, c); + } } } @@ -304,18 +433,16 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) return AVERROR(ENOMEM); av_frame_make_writable(out); - for (c = 0; c < inlink->channels && s->draw_volume; c++) { + /* draw volume level */ + for (c = 0; c < inlink->channels && s->h >= 8 && s->draw_volume; c++) { char buf[16]; - if (s->orientation) { - if (s->h >= 8) { - snprintf(buf, sizeof(buf), "%.2f", s->values[c * VAR_VARS_NB + VAR_VOLUME]); - drawtext(out, c * (s->h + s->b) + (s->h - 8) / 2, 2, buf, 1); - } - } else { - if (s->h >= 8) { - snprintf(buf, sizeof(buf), "%.2f", s->values[c * VAR_VARS_NB + VAR_VOLUME]); - drawtext(out, FFMAX(0, s->w - 8 * (int)strlen(buf)), c * (s->h + s->b) + (s->h - 8) / 2, buf, 0); - } + + if (s->orientation) { /* vertical */ + snprintf(buf, sizeof(buf), "%.2f", s->values[c * VAR_VARS_NB + VAR_VOLUME]); + drawtext(out, c * (s->h + s->b) + (s->h - 8) / 2, 2, buf, 1); + } else { /* horizontal */ + snprintf(buf, sizeof(buf), "%.2f", s->values[c * VAR_VARS_NB + VAR_VOLUME]); + drawtext(out, FFMAX(0, s->w - 8 * (int)strlen(buf)), c * (s->h + s->b) + (s->h - 8) / 2, buf, 0); } } @@ -330,6 +457,7 @@ static av_cold void uninit(AVFilterContext *ctx) av_expr_free(s->c_expr); av_freep(&s->values); av_freep(&s->color_lut); + av_freep(&s->max); } static const AVFilterPad showvolume_inputs[] = { diff --git a/libavfilter/avf_showwaves.c b/libavfilter/avf_showwaves.c index 0866967984673..bb7f4ea87e046 100644 --- a/libavfilter/avf_showwaves.c +++ b/libavfilter/avf_showwaves.c @@ -50,6 +50,12 @@ enum ShowWavesScale { SCALE_NB, }; +enum ShowWavesDrawMode { + DRAW_SCALE, + DRAW_FULL, + DRAW_NB, +}; + struct frame_node { AVFrame *frame; struct frame_node *next; @@ -68,6 +74,7 @@ typedef struct ShowWavesContext { int sample_count_mod; int mode; ///< ShowWavesMode int scale; ///< ShowWavesScale + int draw_mode; ///< ShowWavesDrawMode int split_channels; uint8_t *fg; @@ -104,6 +111,9 @@ static const AVOption showwaves_options[] = { { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=SCALE_LOG}, .flags=FLAGS, .unit="scale"}, { "sqrt", "square root", 0, AV_OPT_TYPE_CONST, {.i64=SCALE_SQRT}, .flags=FLAGS, .unit="scale"}, { "cbrt", "cubic root", 0, AV_OPT_TYPE_CONST, {.i64=SCALE_CBRT}, .flags=FLAGS, .unit="scale"}, + { "draw", "set draw mode", OFFSET(draw_mode), AV_OPT_TYPE_INT, {.i64 = DRAW_SCALE}, 0, DRAW_NB-1, FLAGS, .unit="draw" }, + { "scale", "scale pixel values for each drawn sample", 0, AV_OPT_TYPE_CONST, {.i64=DRAW_SCALE}, .flags=FLAGS, .unit="draw"}, + { "full", "draw every pixel for sample directly", 0, AV_OPT_TYPE_CONST, {.i64=DRAW_FULL}, .flags=FLAGS, .unit="draw"}, { NULL } }; @@ -202,9 +212,9 @@ static int get_cbrt_h2(int16_t sample, int height) return cbrt(FFABS(sample)) * height / cbrt(INT16_MAX); } -static void draw_sample_point_rgba(uint8_t *buf, int height, int linesize, - int16_t *prev_y, - const uint8_t color[4], int h) +static void draw_sample_point_rgba_scale(uint8_t *buf, int height, int linesize, + int16_t *prev_y, + const uint8_t color[4], int h) { if (h >= 0 && h < height) { buf[h * linesize + 0] += color[0]; @@ -214,9 +224,21 @@ static void draw_sample_point_rgba(uint8_t *buf, int height, int linesize, } } -static void draw_sample_line_rgba(uint8_t *buf, int height, int linesize, - int16_t *prev_y, - const uint8_t color[4], int h) +static void draw_sample_point_rgba_full(uint8_t *buf, int height, int linesize, + int16_t *prev_y, + const uint8_t color[4], int h) +{ + if (h >= 0 && h < height) { + buf[h * linesize + 0] = color[0]; + buf[h * linesize + 1] = color[1]; + buf[h * linesize + 2] = color[2]; + buf[h * linesize + 3] = color[3]; + } +} + +static void draw_sample_line_rgba_scale(uint8_t *buf, int height, int linesize, + int16_t *prev_y, + const uint8_t color[4], int h) { int k; int start = height/2; @@ -231,9 +253,26 @@ static void draw_sample_line_rgba(uint8_t *buf, int height, int linesize, } } -static void draw_sample_p2p_rgba(uint8_t *buf, int height, int linesize, - int16_t *prev_y, - const uint8_t color[4], int h) +static void draw_sample_line_rgba_full(uint8_t *buf, int height, int linesize, + int16_t *prev_y, + const uint8_t color[4], int h) +{ + int k; + int start = height/2; + int end = av_clip(h, 0, height-1); + if (start > end) + FFSWAP(int16_t, start, end); + for (k = start; k < end; k++) { + buf[k * linesize + 0] = color[0]; + buf[k * linesize + 1] = color[1]; + buf[k * linesize + 2] = color[2]; + buf[k * linesize + 3] = color[3]; + } +} + +static void draw_sample_p2p_rgba_scale(uint8_t *buf, int height, int linesize, + int16_t *prev_y, + const uint8_t color[4], int h) { int k; if (h >= 0 && h < height) { @@ -257,9 +296,35 @@ static void draw_sample_p2p_rgba(uint8_t *buf, int height, int linesize, *prev_y = h; } -static void draw_sample_cline_rgba(uint8_t *buf, int height, int linesize, - int16_t *prev_y, - const uint8_t color[4], int h) +static void draw_sample_p2p_rgba_full(uint8_t *buf, int height, int linesize, + int16_t *prev_y, + const uint8_t color[4], int h) +{ + int k; + if (h >= 0 && h < height) { + buf[h * linesize + 0] = color[0]; + buf[h * linesize + 1] = color[1]; + buf[h * linesize + 2] = color[2]; + buf[h * linesize + 3] = color[3]; + if (*prev_y && h != *prev_y) { + int start = *prev_y; + int end = av_clip(h, 0, height-1); + if (start > end) + FFSWAP(int16_t, start, end); + for (k = start + 1; k < end; k++) { + buf[k * linesize + 0] = color[0]; + buf[k * linesize + 1] = color[1]; + buf[k * linesize + 2] = color[2]; + buf[k * linesize + 3] = color[3]; + } + } + } + *prev_y = h; +} + +static void draw_sample_cline_rgba_scale(uint8_t *buf, int height, int linesize, + int16_t *prev_y, + const uint8_t color[4], int h) { int k; const int start = (height - h) / 2; @@ -271,6 +336,20 @@ static void draw_sample_cline_rgba(uint8_t *buf, int height, int linesize, buf[k * linesize + 3] += color[3]; } } + static void draw_sample_cline_rgba_full(uint8_t *buf, int height, int linesize, + int16_t *prev_y, + const uint8_t color[4], int h) +{ + int k; + const int start = (height - h) / 2; + const int end = start + h; + for (k = start; k < end; k++) { + buf[k * linesize + 0] = color[0]; + buf[k * linesize + 1] = color[1]; + buf[k * linesize + 2] = color[2]; + buf[k * linesize + 3] = color[3]; + } +} static void draw_sample_point_gray(uint8_t *buf, int height, int linesize, int16_t *prev_y, @@ -368,10 +447,10 @@ static int config_output(AVFilterLink *outlink) break; case AV_PIX_FMT_RGBA: switch (showwaves->mode) { - case MODE_POINT: showwaves->draw_sample = draw_sample_point_rgba; break; - case MODE_LINE: showwaves->draw_sample = draw_sample_line_rgba; break; - case MODE_P2P: showwaves->draw_sample = draw_sample_p2p_rgba; break; - case MODE_CENTERED_LINE: showwaves->draw_sample = draw_sample_cline_rgba; break; + case MODE_POINT: showwaves->draw_sample = showwaves->draw_mode == DRAW_SCALE ? draw_sample_point_rgba_scale : draw_sample_point_rgba_full; break; + case MODE_LINE: showwaves->draw_sample = showwaves->draw_mode == DRAW_SCALE ? draw_sample_line_rgba_scale : draw_sample_line_rgba_full; break; + case MODE_P2P: showwaves->draw_sample = showwaves->draw_mode == DRAW_SCALE ? draw_sample_p2p_rgba_scale : draw_sample_p2p_rgba_full; break; + case MODE_CENTERED_LINE: showwaves->draw_sample = showwaves->draw_mode == DRAW_SCALE ? draw_sample_cline_rgba_scale : draw_sample_cline_rgba_full; break; default: return AVERROR_BUG; } @@ -430,8 +509,12 @@ static int config_output(AVFilterLink *outlink) if (!colors) return AVERROR(ENOMEM); - /* multiplication factor, pre-computed to avoid in-loop divisions */ - x = 255 / ((showwaves->split_channels ? 1 : nb_channels) * showwaves->n); + if (showwaves->draw_mode == DRAW_SCALE) { + /* multiplication factor, pre-computed to avoid in-loop divisions */ + x = 255 / ((showwaves->split_channels ? 1 : nb_channels) * showwaves->n); + } else { + x = 255; + } if (outlink->format == AV_PIX_FMT_RGBA) { uint8_t fg[4] = { 0xff, 0xff, 0xff, 0xff }; diff --git a/libavfilter/avfilter.c b/libavfilter/avfilter.c index f0f849b326164..ed8161136c272 100644 --- a/libavfilter/avfilter.c +++ b/libavfilter/avfilter.c @@ -19,7 +19,6 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/atomic.h" #include "libavutil/avassert.h" #include "libavutil/avstring.h" #include "libavutil/buffer.h" @@ -33,6 +32,7 @@ #include "libavutil/pixdesc.h" #include "libavutil/rational.h" #include "libavutil/samplefmt.h" +#include "libavutil/thread.h" #define FF_INTERNAL_FIELDS 1 #include "framequeue.h" @@ -183,10 +183,12 @@ void avfilter_link_free(AVFilterLink **link) av_freep(link); } +#if FF_API_FILTER_GET_SET int avfilter_link_get_channels(AVFilterLink *link) { return link->channels; } +#endif void ff_filter_set_ready(AVFilterContext *filter, unsigned priority) { @@ -573,58 +575,6 @@ int avfilter_process_command(AVFilterContext *filter, const char *cmd, const cha return AVERROR(ENOSYS); } -static AVFilter *first_filter; -static AVFilter **last_filter = &first_filter; - -#if !FF_API_NOCONST_GET_NAME -const -#endif -AVFilter *avfilter_get_by_name(const char *name) -{ - const AVFilter *f = NULL; - - if (!name) - return NULL; - - while ((f = avfilter_next(f))) - if (!strcmp(f->name, name)) - return (AVFilter *)f; - - return NULL; -} - -int avfilter_register(AVFilter *filter) -{ - AVFilter **f = last_filter; - - /* the filter must select generic or internal exclusively */ - av_assert0((filter->flags & AVFILTER_FLAG_SUPPORT_TIMELINE) != AVFILTER_FLAG_SUPPORT_TIMELINE); - - filter->next = NULL; - - while(*f || avpriv_atomic_ptr_cas((void * volatile *)f, NULL, filter)) - f = &(*f)->next; - last_filter = &filter->next; - - return 0; -} - -const AVFilter *avfilter_next(const AVFilter *prev) -{ - return prev ? prev->next : first_filter; -} - -#if FF_API_OLD_FILTER_REGISTER -AVFilter **av_filter_next(AVFilter **filter) -{ - return filter ? &(*filter)->next : &first_filter; -} - -void avfilter_uninit(void) -{ -} -#endif - int avfilter_pad_count(const AVFilterPad *pads) { int count; @@ -653,10 +603,11 @@ static void *filter_child_next(void *obj, void *prev) static const AVClass *filter_child_class_next(const AVClass *prev) { + void *opaque = NULL; const AVFilter *f = NULL; /* find the filter that corresponds to prev */ - while (prev && (f = avfilter_next(f))) + while (prev && (f = av_filter_iterate(&opaque))) if (f->priv_class == prev) break; @@ -665,7 +616,7 @@ static const AVClass *filter_child_class_next(const AVClass *prev) return NULL; /* find next filter with specific options */ - while ((f = avfilter_next(f))) + while ((f = av_filter_iterate(&opaque))) if (f->priv_class) return f->priv_class; @@ -681,6 +632,8 @@ static const AVOption avfilter_options[] = { { "enable", "set enable expression", OFFSET(enable_str), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, { "threads", "Allowed number of threads", OFFSET(nb_threads), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, + { "extra_hw_frames", "Number of extra hardware frames to allocate for the user", + OFFSET(extra_hw_frames), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, FLAGS }, { NULL }, }; @@ -783,14 +736,6 @@ AVFilterContext *ff_filter_alloc(const AVFilter *filter, const char *inst_name) return NULL; } -#if FF_API_AVFILTER_OPEN -int avfilter_open(AVFilterContext **filter_ctx, AVFilter *filter, const char *inst_name) -{ - *filter_ctx = ff_filter_alloc(filter, inst_name); - return *filter_ctx ? 0 : AVERROR(ENOMEM); -} -#endif - static void free_link(AVFilterLink *link) { if (!link) @@ -939,13 +884,6 @@ static int process_options(AVFilterContext *ctx, AVDictionary **options, return count; } -#if FF_API_AVFILTER_INIT_FILTER -int avfilter_init_filter(AVFilterContext *filter, const char *args, void *opaque) -{ - return avfilter_init_str(filter, args); -} -#endif - int avfilter_init_dict(AVFilterContext *ctx, AVDictionary **options) { int ret = 0; @@ -996,7 +934,7 @@ int avfilter_init_str(AVFilterContext *filter, const char *args) return AVERROR(EINVAL); } -#if FF_API_OLD_FILTER_OPTS || FF_API_OLD_FILTER_OPTS_ERROR +#if FF_API_OLD_FILTER_OPTS_ERROR if ( !strcmp(filter->filter->name, "format") || !strcmp(filter->filter->name, "noformat") || !strcmp(filter->filter->name, "frei0r") || @@ -1056,14 +994,6 @@ int avfilter_init_str(AVFilterContext *filter, const char *args) while ((p = strchr(p, ':'))) *p++ = '|'; -#if FF_API_OLD_FILTER_OPTS - if (deprecated) - av_log(filter, AV_LOG_WARNING, "This syntax is deprecated. Use " - "'|' to separate the list items.\n"); - - av_log(filter, AV_LOG_DEBUG, "compat: called with args=[%s]\n", copy); - ret = process_options(filter, &options, copy); -#else if (deprecated) { av_log(filter, AV_LOG_ERROR, "This syntax is deprecated. Use " "'|' to separate the list items ('%s' instead of '%s')\n", @@ -1072,7 +1002,6 @@ int avfilter_init_str(AVFilterContext *filter, const char *args) } else { ret = process_options(filter, &options, copy); } -#endif av_freep(©); if (ret < 0) @@ -1570,7 +1499,7 @@ int ff_inlink_consume_samples(AVFilterLink *link, unsigned min, unsigned max, return 0; if (link->status_in) min = FFMIN(min, ff_framequeue_queued_samples(&link->fifo)); - ret = take_samples(link, min, link->max_samples, &frame); + ret = take_samples(link, min, max, &frame); if (ret < 0) return ret; consume_update(link, frame); @@ -1692,3 +1621,24 @@ const AVClass *avfilter_get_class(void) { return &avfilter_class; } + +int ff_filter_init_hw_frames(AVFilterContext *avctx, AVFilterLink *link, + int default_pool_size) +{ + AVHWFramesContext *frames; + + // Must already be set by caller. + av_assert0(link->hw_frames_ctx); + + frames = (AVHWFramesContext*)link->hw_frames_ctx->data; + + if (frames->initial_pool_size == 0) { + // Dynamic allocation is necessarily supported. + } else if (avctx->extra_hw_frames >= 0) { + frames->initial_pool_size += avctx->extra_hw_frames; + } else { + frames->initial_pool_size = default_pool_size; + } + + return 0; +} diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h index 73a723d583311..9d70e7118beea 100644 --- a/libavfilter/avfilter.h +++ b/libavfilter/avfilter.h @@ -406,6 +406,22 @@ struct AVFilterContext { * a higher value suggests a more urgent activation. */ unsigned ready; + + /** + * Sets the number of extra hardware frames which the filter will + * allocate on its output links for use in following filters or by + * the caller. + * + * Some hardware filters require all frames that they will use for + * output to be defined in advance before filtering starts. For such + * filters, any hardware frame pools used for output must therefore be + * of fixed size. The extra frames set here are on top of any number + * that the filter needs internally in order to operate normally. + * + * This field must be set before the graph containing this filter is + * configured. + */ + int extra_hw_frames; }; /** @@ -647,10 +663,14 @@ int avfilter_link(AVFilterContext *src, unsigned srcpad, */ void avfilter_link_free(AVFilterLink **link); +#if FF_API_FILTER_GET_SET /** * Get the number of channels of a link. + * @deprecated Use av_buffersink_get_channels() */ +attribute_deprecated int avfilter_link_get_channels(AVFilterLink *link); +#endif /** * Set the closed field of a link. @@ -677,14 +697,21 @@ int avfilter_config_links(AVFilterContext *filter); */ int avfilter_process_command(AVFilterContext *filter, const char *cmd, const char *arg, char *res, int res_len, int flags); -/** Initialize the filter system. Register all builtin filters. */ -void avfilter_register_all(void); +/** + * Iterate over all registered filters. + * + * @param opaque a pointer where libavfilter will store the iteration state. Must + * point to NULL to start the iteration. + * + * @return the next registered filter or NULL when the iteration is + * finished + */ +const AVFilter *av_filter_iterate(void **opaque); -#if FF_API_OLD_FILTER_REGISTER -/** Uninitialize the filter system. Unregister all filters. */ +#if FF_API_NEXT +/** Initialize the filter system. Register all builtin filters. */ attribute_deprecated -void avfilter_uninit(void); -#endif +void avfilter_register_all(void); /** * Register a filter. This is only needed if you plan to use @@ -696,69 +723,27 @@ void avfilter_uninit(void); * @return 0 if the registration was successful, a negative value * otherwise */ +attribute_deprecated int avfilter_register(AVFilter *filter); -/** - * Get a filter definition matching the given name. - * - * @param name the filter name to find - * @return the filter definition, if any matching one is registered. - * NULL if none found. - */ -#if !FF_API_NOCONST_GET_NAME -const -#endif -AVFilter *avfilter_get_by_name(const char *name); - /** * Iterate over all registered filters. * @return If prev is non-NULL, next registered filter after prev or NULL if * prev is the last filter. If prev is NULL, return the first registered filter. */ -const AVFilter *avfilter_next(const AVFilter *prev); - -#if FF_API_OLD_FILTER_REGISTER -/** - * If filter is NULL, returns a pointer to the first registered filter pointer, - * if filter is non-NULL, returns the next pointer after filter. - * If the returned pointer points to NULL, the last registered filter - * was already reached. - * @deprecated use avfilter_next() - */ attribute_deprecated -AVFilter **av_filter_next(AVFilter **filter); +const AVFilter *avfilter_next(const AVFilter *prev); #endif -#if FF_API_AVFILTER_OPEN /** - * Create a filter instance. + * Get a filter definition matching the given name. * - * @param filter_ctx put here a pointer to the created filter context - * on success, NULL on failure - * @param filter the filter to create an instance of - * @param inst_name Name to give to the new instance. Can be NULL for none. - * @return >= 0 in case of success, a negative error code otherwise - * @deprecated use avfilter_graph_alloc_filter() instead + * @param name the filter name to find + * @return the filter definition, if any matching one is registered. + * NULL if none found. */ -attribute_deprecated -int avfilter_open(AVFilterContext **filter_ctx, AVFilter *filter, const char *inst_name); -#endif - +const AVFilter *avfilter_get_by_name(const char *name); -#if FF_API_AVFILTER_INIT_FILTER -/** - * Initialize a filter. - * - * @param filter the filter to initialize - * @param args A string of parameters to use when initializing the filter. - * The format and meaning of this string varies by filter. - * @param opaque Any extra non-string data needed by the filter. The meaning - * of this parameter varies by filter. - * @return zero on success - */ -attribute_deprecated -int avfilter_init_filter(AVFilterContext *filter, const char *args, void *opaque); -#endif /** * Initialize a filter with the supplied parameters. @@ -959,20 +944,6 @@ AVFilterContext *avfilter_graph_alloc_filter(AVFilterGraph *graph, */ AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, const char *name); -#if FF_API_AVFILTER_OPEN -/** - * Add an existing filter instance to a filter graph. - * - * @param graphctx the filter graph - * @param filter the filter to be added - * - * @deprecated use avfilter_graph_alloc_filter() to allocate a filter in a - * filter graph - */ -attribute_deprecated -int avfilter_graph_add_filter(AVFilterGraph *graphctx, AVFilterContext *filter); -#endif - /** * Create and add a filter instance into an existing graph. * The filter instance is created from the filter filt and inited diff --git a/libavfilter/avfiltergraph.c b/libavfilter/avfiltergraph.c index 4304c06847919..4cc6892404317 100644 --- a/libavfilter/avfiltergraph.c +++ b/libavfilter/avfiltergraph.c @@ -28,6 +28,7 @@ #include "libavutil/avstring.h" #include "libavutil/bprint.h" #include "libavutil/channel_layout.h" +#include "libavutil/imgutils.h" #include "libavutil/internal.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" @@ -42,17 +43,19 @@ #include "thread.h" #define OFFSET(x) offsetof(AVFilterGraph, x) -#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM +#define F AV_OPT_FLAG_FILTERING_PARAM +#define V AV_OPT_FLAG_VIDEO_PARAM +#define A AV_OPT_FLAG_AUDIO_PARAM static const AVOption filtergraph_options[] = { { "thread_type", "Allowed thread types", OFFSET(thread_type), AV_OPT_TYPE_FLAGS, - { .i64 = AVFILTER_THREAD_SLICE }, 0, INT_MAX, FLAGS, "thread_type" }, - { "slice", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVFILTER_THREAD_SLICE }, .flags = FLAGS, .unit = "thread_type" }, + { .i64 = AVFILTER_THREAD_SLICE }, 0, INT_MAX, F|V|A, "thread_type" }, + { "slice", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AVFILTER_THREAD_SLICE }, .flags = F|V|A, .unit = "thread_type" }, { "threads", "Maximum number of threads", OFFSET(nb_threads), - AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, FLAGS }, + AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, F|V|A }, {"scale_sws_opts" , "default scale filter options" , OFFSET(scale_sws_opts) , - AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS }, + AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, F|V }, {"aresample_swr_opts" , "default aresample filter options" , OFFSET(aresample_swr_opts) , - AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS }, + AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, F|A }, { NULL }, }; @@ -136,23 +139,6 @@ void avfilter_graph_free(AVFilterGraph **graph) av_freep(graph); } -#if FF_API_AVFILTER_OPEN -int avfilter_graph_add_filter(AVFilterGraph *graph, AVFilterContext *filter) -{ - AVFilterContext **filters = av_realloc(graph->filters, - sizeof(*filters) * (graph->nb_filters + 1)); - if (!filters) - return AVERROR(ENOMEM); - - graph->filters = filters; - graph->filters[graph->nb_filters++] = filter; - - filter->graph = graph; - - return 0; -} -#endif - int avfilter_graph_create_filter(AVFilterContext **filt_ctx, const AVFilter *filt, const char *name, const char *args, void *opaque, AVFilterGraph *graph_ctx) @@ -280,6 +266,27 @@ static int graph_config_links(AVFilterGraph *graph, AVClass *log_ctx) return 0; } +static int graph_check_links(AVFilterGraph *graph, AVClass *log_ctx) +{ + AVFilterContext *f; + AVFilterLink *l; + unsigned i, j; + int ret; + + for (i = 0; i < graph->nb_filters; i++) { + f = graph->filters[i]; + for (j = 0; j < f->nb_outputs; j++) { + l = f->outputs[j]; + if (l->type == AVMEDIA_TYPE_VIDEO) { + ret = av_image_check_size2(l->w, l->h, INT64_MAX, l->format, 0, f); + if (ret < 0) + return ret; + } + } + } + return 0; +} + AVFilterContext *avfilter_graph_get_filter(AVFilterGraph *graph, const char *name) { int i; @@ -509,9 +516,8 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) if (convert_needed) { AVFilterContext *convert; - AVFilter *filter; + const AVFilter *filter; AVFilterLink *inlink, *outlink; - char scale_args[256]; char inst_name[30]; if (graph->disable_auto_convert) { @@ -548,10 +554,6 @@ static int query_formats(AVFilterGraph *graph, AVClass *log_ctx) snprintf(inst_name, sizeof(inst_name), "auto_resampler_%d", resampler_count++); - scale_args[0] = '\0'; - if (graph->aresample_swr_opts) - snprintf(scale_args, sizeof(scale_args), "%s", - graph->aresample_swr_opts); if ((ret = avfilter_graph_create_filter(&convert, filter, inst_name, graph->aresample_swr_opts, NULL, graph)) < 0) @@ -1235,7 +1237,7 @@ static int graph_insert_fifos(AVFilterGraph *graph, AVClass *log_ctx) for (j = 0; j < f->nb_inputs; j++) { AVFilterLink *link = f->inputs[j]; AVFilterContext *fifo_ctx; - AVFilter *fifo; + const AVFilter *fifo; char name[32]; if (!link->dstpad->needs_fifo) @@ -1273,6 +1275,8 @@ int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx) return ret; if ((ret = graph_config_links(graphctx, log_ctx))) return ret; + if ((ret = graph_check_links(graphctx, log_ctx))) + return ret; if ((ret = graph_config_pointers(graphctx, log_ctx))) return ret; diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c index ad5aedd5f7de9..cd56f8ca457e4 100644 --- a/libavfilter/buffersrc.c +++ b/libavfilter/buffersrc.c @@ -304,14 +304,6 @@ static const AVOption buffer_options[] = { { "video_size", NULL, OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, .flags = V }, { "height", NULL, OFFSET(h), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, V }, { "pix_fmt", NULL, OFFSET(pix_fmt), AV_OPT_TYPE_PIXEL_FMT, { .i64 = AV_PIX_FMT_NONE }, .min = AV_PIX_FMT_NONE, .max = INT_MAX, .flags = V }, -#if FF_API_OLD_FILTER_OPTS - /* those 4 are for compatibility with the old option passing system where each filter - * did its own parsing */ - { "time_base_num", "deprecated, do not use", OFFSET(time_base.num), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, V }, - { "time_base_den", "deprecated, do not use", OFFSET(time_base.den), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, V }, - { "sar_num", "deprecated, do not use", OFFSET(pixel_aspect.num), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, V }, - { "sar_den", "deprecated, do not use", OFFSET(pixel_aspect.den), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, V }, -#endif { "sar", "sample aspect ratio", OFFSET(pixel_aspect), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, DBL_MAX, V }, { "pixel_aspect", "sample aspect ratio", OFFSET(pixel_aspect), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, DBL_MAX, V }, { "time_base", NULL, OFFSET(time_base), AV_OPT_TYPE_RATIONAL, { .dbl = 0 }, 0, DBL_MAX, V }, diff --git a/libavfilter/deshake.h b/libavfilter/deshake.h index 5e25bb3a7af12..406cbab2f65f2 100644 --- a/libavfilter/deshake.h +++ b/libavfilter/deshake.h @@ -26,9 +26,6 @@ #include "avfilter.h" #include "transform.h" #include "libavutil/pixelutils.h" -#if CONFIG_OPENCL -#include "libavutil/opencl.h" -#endif enum SearchMethod { @@ -53,24 +50,6 @@ typedef struct Transform { double zoom; ///< Zoom percentage } Transform; -#if CONFIG_OPENCL - -typedef struct DeshakeOpenclContext { - cl_command_queue command_queue; - cl_program program; - cl_kernel kernel_luma; - cl_kernel kernel_chroma; - int in_plane_size[8]; - int out_plane_size[8]; - int plane_num; - cl_mem cl_inbuf; - size_t cl_inbuf_size; - cl_mem cl_outbuf; - size_t cl_outbuf_size; -} DeshakeOpenclContext; - -#endif - #define MAX_R 64 typedef struct DeshakeContext { @@ -96,9 +75,6 @@ typedef struct DeshakeContext { int cy; char *filename; ///< Motion search detailed log filename int opencl; -#if CONFIG_OPENCL - DeshakeOpenclContext opencl_ctx; -#endif int (* transform)(AVFilterContext *ctx, int width, int height, int cw, int ch, const float *matrix_y, const float *matrix_uv, enum InterpolateMethod interpolate, enum FillMethod fill, AVFrame *in, AVFrame *out); diff --git a/libavfilter/deshake_opencl.c b/libavfilter/deshake_opencl.c deleted file mode 100644 index 877ec1dc03fba..0000000000000 --- a/libavfilter/deshake_opencl.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (C) 2013 Wei Gao - * Copyright (C) 2013 Lenny Wang - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file - * transform input video - */ - -#include "libavutil/common.h" -#include "libavutil/dict.h" -#include "libavutil/pixdesc.h" -#include "deshake_opencl.h" -#include "libavutil/opencl_internal.h" - -#define PLANE_NUM 3 -#define ROUND_TO_16(a) (((((a) - 1)/16)+1)*16) - -int ff_opencl_transform(AVFilterContext *ctx, - int width, int height, int cw, int ch, - const float *matrix_y, const float *matrix_uv, - enum InterpolateMethod interpolate, - enum FillMethod fill, AVFrame *in, AVFrame *out) -{ - int ret = 0; - cl_int status; - DeshakeContext *deshake = ctx->priv; - float4 packed_matrix_lu = {matrix_y[0], matrix_y[1], matrix_y[2], matrix_y[5]}; - float4 packed_matrix_ch = {matrix_uv[0], matrix_uv[1], matrix_uv[2], matrix_uv[5]}; - size_t global_worksize_lu[2] = {(size_t)ROUND_TO_16(width), (size_t)ROUND_TO_16(height)}; - size_t global_worksize_ch[2] = {(size_t)ROUND_TO_16(cw), (size_t)(2*ROUND_TO_16(ch))}; - size_t local_worksize[2] = {16, 16}; - FFOpenclParam param_lu = {0}; - FFOpenclParam param_ch = {0}; - param_lu.ctx = param_ch.ctx = ctx; - param_lu.kernel = deshake->opencl_ctx.kernel_luma; - param_ch.kernel = deshake->opencl_ctx.kernel_chroma; - - if ((unsigned int)interpolate > INTERPOLATE_BIQUADRATIC) { - av_log(ctx, AV_LOG_ERROR, "Selected interpolate method is invalid\n"); - return AVERROR(EINVAL); - } - ret = avpriv_opencl_set_parameter(¶m_lu, - FF_OPENCL_PARAM_INFO(deshake->opencl_ctx.cl_inbuf), - FF_OPENCL_PARAM_INFO(deshake->opencl_ctx.cl_outbuf), - FF_OPENCL_PARAM_INFO(packed_matrix_lu), - FF_OPENCL_PARAM_INFO(interpolate), - FF_OPENCL_PARAM_INFO(fill), - FF_OPENCL_PARAM_INFO(in->linesize[0]), - FF_OPENCL_PARAM_INFO(out->linesize[0]), - FF_OPENCL_PARAM_INFO(height), - FF_OPENCL_PARAM_INFO(width), - NULL); - if (ret < 0) - return ret; - ret = avpriv_opencl_set_parameter(¶m_ch, - FF_OPENCL_PARAM_INFO(deshake->opencl_ctx.cl_inbuf), - FF_OPENCL_PARAM_INFO(deshake->opencl_ctx.cl_outbuf), - FF_OPENCL_PARAM_INFO(packed_matrix_ch), - FF_OPENCL_PARAM_INFO(interpolate), - FF_OPENCL_PARAM_INFO(fill), - FF_OPENCL_PARAM_INFO(in->linesize[0]), - FF_OPENCL_PARAM_INFO(out->linesize[0]), - FF_OPENCL_PARAM_INFO(in->linesize[1]), - FF_OPENCL_PARAM_INFO(out->linesize[1]), - FF_OPENCL_PARAM_INFO(height), - FF_OPENCL_PARAM_INFO(width), - FF_OPENCL_PARAM_INFO(ch), - FF_OPENCL_PARAM_INFO(cw), - NULL); - if (ret < 0) - return ret; - status = clEnqueueNDRangeKernel(deshake->opencl_ctx.command_queue, - deshake->opencl_ctx.kernel_luma, 2, NULL, - global_worksize_lu, local_worksize, 0, NULL, NULL); - status |= clEnqueueNDRangeKernel(deshake->opencl_ctx.command_queue, - deshake->opencl_ctx.kernel_chroma, 2, NULL, - global_worksize_ch, local_worksize, 0, NULL, NULL); - if (status != CL_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "OpenCL run kernel error occurred: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - ret = av_opencl_buffer_read_image(out->data, deshake->opencl_ctx.out_plane_size, - deshake->opencl_ctx.plane_num, deshake->opencl_ctx.cl_outbuf, - deshake->opencl_ctx.cl_outbuf_size); - if (ret < 0) - return ret; - return ret; -} - -int ff_opencl_deshake_init(AVFilterContext *ctx) -{ - int ret = 0; - DeshakeContext *deshake = ctx->priv; - ret = av_opencl_init(NULL); - if (ret < 0) - return ret; - deshake->opencl_ctx.plane_num = PLANE_NUM; - deshake->opencl_ctx.command_queue = av_opencl_get_command_queue(); - if (!deshake->opencl_ctx.command_queue) { - av_log(ctx, AV_LOG_ERROR, "Unable to get OpenCL command queue in filter 'deshake'\n"); - return AVERROR(EINVAL); - } - deshake->opencl_ctx.program = av_opencl_compile("avfilter_transform", NULL); - if (!deshake->opencl_ctx.program) { - av_log(ctx, AV_LOG_ERROR, "OpenCL failed to compile program 'avfilter_transform'\n"); - return AVERROR(EINVAL); - } - if (!deshake->opencl_ctx.kernel_luma) { - deshake->opencl_ctx.kernel_luma = clCreateKernel(deshake->opencl_ctx.program, - "avfilter_transform_luma", &ret); - if (ret != CL_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "OpenCL failed to create kernel 'avfilter_transform_luma'\n"); - return AVERROR(EINVAL); - } - } - if (!deshake->opencl_ctx.kernel_chroma) { - deshake->opencl_ctx.kernel_chroma = clCreateKernel(deshake->opencl_ctx.program, - "avfilter_transform_chroma", &ret); - if (ret != CL_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "OpenCL failed to create kernel 'avfilter_transform_chroma'\n"); - return AVERROR(EINVAL); - } - } - return ret; -} - -void ff_opencl_deshake_uninit(AVFilterContext *ctx) -{ - DeshakeContext *deshake = ctx->priv; - av_opencl_buffer_release(&deshake->opencl_ctx.cl_inbuf); - av_opencl_buffer_release(&deshake->opencl_ctx.cl_outbuf); - clReleaseKernel(deshake->opencl_ctx.kernel_luma); - clReleaseKernel(deshake->opencl_ctx.kernel_chroma); - clReleaseProgram(deshake->opencl_ctx.program); - deshake->opencl_ctx.command_queue = NULL; - av_opencl_uninit(); -} - -int ff_opencl_deshake_process_inout_buf(AVFilterContext *ctx, AVFrame *in, AVFrame *out) -{ - int ret = 0; - AVFilterLink *link = ctx->inputs[0]; - DeshakeContext *deshake = ctx->priv; - const int hshift = av_pix_fmt_desc_get(link->format)->log2_chroma_h; - int chroma_height = AV_CEIL_RSHIFT(link->h, hshift); - - if ((!deshake->opencl_ctx.cl_inbuf) || (!deshake->opencl_ctx.cl_outbuf)) { - deshake->opencl_ctx.in_plane_size[0] = (in->linesize[0] * in->height); - deshake->opencl_ctx.in_plane_size[1] = (in->linesize[1] * chroma_height); - deshake->opencl_ctx.in_plane_size[2] = (in->linesize[2] * chroma_height); - deshake->opencl_ctx.out_plane_size[0] = (out->linesize[0] * out->height); - deshake->opencl_ctx.out_plane_size[1] = (out->linesize[1] * chroma_height); - deshake->opencl_ctx.out_plane_size[2] = (out->linesize[2] * chroma_height); - deshake->opencl_ctx.cl_inbuf_size = deshake->opencl_ctx.in_plane_size[0] + - deshake->opencl_ctx.in_plane_size[1] + - deshake->opencl_ctx.in_plane_size[2]; - deshake->opencl_ctx.cl_outbuf_size = deshake->opencl_ctx.out_plane_size[0] + - deshake->opencl_ctx.out_plane_size[1] + - deshake->opencl_ctx.out_plane_size[2]; - if (!deshake->opencl_ctx.cl_inbuf) { - ret = av_opencl_buffer_create(&deshake->opencl_ctx.cl_inbuf, - deshake->opencl_ctx.cl_inbuf_size, - CL_MEM_READ_ONLY, NULL); - if (ret < 0) - return ret; - } - if (!deshake->opencl_ctx.cl_outbuf) { - ret = av_opencl_buffer_create(&deshake->opencl_ctx.cl_outbuf, - deshake->opencl_ctx.cl_outbuf_size, - CL_MEM_READ_WRITE, NULL); - if (ret < 0) - return ret; - } - } - ret = av_opencl_buffer_write_image(deshake->opencl_ctx.cl_inbuf, - deshake->opencl_ctx.cl_inbuf_size, - 0, in->data,deshake->opencl_ctx.in_plane_size, - deshake->opencl_ctx.plane_num); - return ret; -} diff --git a/libavfilter/deshake_opencl.h b/libavfilter/deshake_opencl.h deleted file mode 100644 index f3d96dc4e90f3..0000000000000 --- a/libavfilter/deshake_opencl.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2013 Wei Gao - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVFILTER_DESHAKE_OPENCL_H -#define AVFILTER_DESHAKE_OPENCL_H - -#include "deshake.h" - -typedef struct float4 { - float x; - float y; - float z; - float w; -} float4; - -int ff_opencl_deshake_init(AVFilterContext *ctx); - -void ff_opencl_deshake_uninit(AVFilterContext *ctx); - -int ff_opencl_deshake_process_inout_buf(AVFilterContext *ctx, AVFrame *in, AVFrame *out); - -int ff_opencl_transform(AVFilterContext *ctx, - int width, int height, int cw, int ch, - const float *matrix_y, const float *matrix_uv, - enum InterpolateMethod interpolate, - enum FillMethod fill, AVFrame *in, AVFrame *out); - -#endif /* AVFILTER_DESHAKE_OPENCL_H */ diff --git a/libavfilter/deshake_opencl_kernel.h b/libavfilter/deshake_opencl_kernel.h deleted file mode 100644 index dd45d6f60bab2..0000000000000 --- a/libavfilter/deshake_opencl_kernel.h +++ /dev/null @@ -1,225 +0,0 @@ -/* - * Copyright (C) 2013 Wei Gao - * Copyright (C) 2013 Lenny Wang - * - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVFILTER_DESHAKE_OPENCL_KERNEL_H -#define AVFILTER_DESHAKE_OPENCL_KERNEL_H - -#include "libavutil/opencl.h" - -const char *ff_kernel_deshake_opencl = AV_OPENCL_KERNEL( -inline unsigned char pixel(global const unsigned char *src, int x, int y, - int w, int h,int stride, unsigned char def) -{ - return (x < 0 || y < 0 || x >= w || y >= h) ? def : src[x + y * stride]; -} - -unsigned char interpolate_nearest(float x, float y, global const unsigned char *src, - int width, int height, int stride, unsigned char def) -{ - return pixel(src, (int)(x + 0.5f), (int)(y + 0.5f), width, height, stride, def); -} - -unsigned char interpolate_bilinear(float x, float y, global const unsigned char *src, - int width, int height, int stride, unsigned char def) -{ - int x_c, x_f, y_c, y_f; - int v1, v2, v3, v4; - x_f = (int)x; - y_f = (int)y; - x_c = x_f + 1; - y_c = y_f + 1; - - if (x_f < -1 || x_f > width || y_f < -1 || y_f > height) { - return def; - } else { - v4 = pixel(src, x_f, y_f, width, height, stride, def); - v2 = pixel(src, x_c, y_f, width, height, stride, def); - v3 = pixel(src, x_f, y_c, width, height, stride, def); - v1 = pixel(src, x_c, y_c, width, height, stride, def); - return (v1*(x - x_f)*(y - y_f) + v2*((x - x_f)*(y_c - y)) + - v3*(x_c - x)*(y - y_f) + v4*((x_c - x)*(y_c - y))); - } -} - -unsigned char interpolate_biquadratic(float x, float y, global const unsigned char *src, - int width, int height, int stride, unsigned char def) -{ - int x_c, x_f, y_c, y_f; - unsigned char v1, v2, v3, v4; - float f1, f2, f3, f4; - x_f = (int)x; - y_f = (int)y; - x_c = x_f + 1; - y_c = y_f + 1; - - if (x_f < - 1 || x_f > width || y_f < -1 || y_f > height) - return def; - else { - v4 = pixel(src, x_f, y_f, width, height, stride, def); - v2 = pixel(src, x_c, y_f, width, height, stride, def); - v3 = pixel(src, x_f, y_c, width, height, stride, def); - v1 = pixel(src, x_c, y_c, width, height, stride, def); - - f1 = 1 - sqrt((x_c - x) * (y_c - y)); - f2 = 1 - sqrt((x_c - x) * (y - y_f)); - f3 = 1 - sqrt((x - x_f) * (y_c - y)); - f4 = 1 - sqrt((x - x_f) * (y - y_f)); - return (v1 * f1 + v2 * f2 + v3 * f3 + v4 * f4) / (f1 + f2 + f3 + f4); - } -} - -inline const float clipf(float a, float amin, float amax) -{ - if (a < amin) return amin; - else if (a > amax) return amax; - else return a; -} - -inline int mirror(int v, int m) -{ - while ((unsigned)v > (unsigned)m) { - v = -v; - if (v < 0) - v += 2 * m; - } - return v; -} - -kernel void avfilter_transform_luma(global unsigned char *src, - global unsigned char *dst, - float4 matrix, - int interpolate, - int fill, - int src_stride_lu, - int dst_stride_lu, - int height, - int width) -{ - int x = get_global_id(0); - int y = get_global_id(1); - int idx_dst = y * dst_stride_lu + x; - unsigned char def = 0; - float x_s = x * matrix.x + y * matrix.y + matrix.z; - float y_s = x * (-matrix.y) + y * matrix.x + matrix.w; - - if (x < width && y < height) { - switch (fill) { - case 0: //FILL_BLANK - def = 0; - break; - case 1: //FILL_ORIGINAL - def = src[y*src_stride_lu + x]; - break; - case 2: //FILL_CLAMP - y_s = clipf(y_s, 0, height - 1); - x_s = clipf(x_s, 0, width - 1); - def = src[(int)y_s * src_stride_lu + (int)x_s]; - break; - case 3: //FILL_MIRROR - y_s = mirror(y_s, height - 1); - x_s = mirror(x_s, width - 1); - def = src[(int)y_s * src_stride_lu + (int)x_s]; - break; - } - switch (interpolate) { - case 0: //INTERPOLATE_NEAREST - dst[idx_dst] = interpolate_nearest(x_s, y_s, src, width, height, src_stride_lu, def); - break; - case 1: //INTERPOLATE_BILINEAR - dst[idx_dst] = interpolate_bilinear(x_s, y_s, src, width, height, src_stride_lu, def); - break; - case 2: //INTERPOLATE_BIQUADRATIC - dst[idx_dst] = interpolate_biquadratic(x_s, y_s, src, width, height, src_stride_lu, def); - break; - default: - return; - } - } -} - -kernel void avfilter_transform_chroma(global unsigned char *src, - global unsigned char *dst, - float4 matrix, - int interpolate, - int fill, - int src_stride_lu, - int dst_stride_lu, - int src_stride_ch, - int dst_stride_ch, - int height, - int width, - int ch, - int cw) -{ - - int x = get_global_id(0); - int y = get_global_id(1); - int pad_ch = get_global_size(1)>>1; - global unsigned char *dst_u = dst + height * dst_stride_lu; - global unsigned char *src_u = src + height * src_stride_lu; - global unsigned char *dst_v = dst_u + ch * dst_stride_ch; - global unsigned char *src_v = src_u + ch * src_stride_ch; - src = y < pad_ch ? src_u : src_v; - dst = y < pad_ch ? dst_u : dst_v; - y = select(y - pad_ch, y, y < pad_ch); - float x_s = x * matrix.x + y * matrix.y + matrix.z; - float y_s = x * (-matrix.y) + y * matrix.x + matrix.w; - int idx_dst = y * dst_stride_ch + x; - unsigned char def; - - if (x < cw && y < ch) { - switch (fill) { - case 0: //FILL_BLANK - def = 0; - break; - case 1: //FILL_ORIGINAL - def = src[y*src_stride_ch + x]; - break; - case 2: //FILL_CLAMP - y_s = clipf(y_s, 0, ch - 1); - x_s = clipf(x_s, 0, cw - 1); - def = src[(int)y_s * src_stride_ch + (int)x_s]; - break; - case 3: //FILL_MIRROR - y_s = mirror(y_s, ch - 1); - x_s = mirror(x_s, cw - 1); - def = src[(int)y_s * src_stride_ch + (int)x_s]; - break; - } - switch (interpolate) { - case 0: //INTERPOLATE_NEAREST - dst[idx_dst] = interpolate_nearest(x_s, y_s, src, cw, ch, src_stride_ch, def); - break; - case 1: //INTERPOLATE_BILINEAR - dst[idx_dst] = interpolate_bilinear(x_s, y_s, src, cw, ch, src_stride_ch, def); - break; - case 2: //INTERPOLATE_BIQUADRATIC - dst[idx_dst] = interpolate_biquadratic(x_s, y_s, src, cw, ch, src_stride_ch, def); - break; - default: - return; - } - } -} -); - -#endif /* AVFILTER_DESHAKE_OPENCL_KERNEL_H */ diff --git a/libavfilter/drawutils.c b/libavfilter/drawutils.c index 77ab86b775454..db8c7a6226178 100644 --- a/libavfilter/drawutils.c +++ b/libavfilter/drawutils.c @@ -184,9 +184,9 @@ int ff_draw_init(FFDrawContext *draw, enum AVPixelFormat format, unsigned flags) if (!desc || !desc->name) return AVERROR(EINVAL); - if (desc->flags & ~(AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_PSEUDOPAL | AV_PIX_FMT_FLAG_ALPHA)) + if (desc->flags & ~(AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_RGB | FF_PSEUDOPAL | AV_PIX_FMT_FLAG_ALPHA)) return AVERROR(ENOSYS); - if (format == AV_PIX_FMT_P010LE || format == AV_PIX_FMT_P010BE) + if (format == AV_PIX_FMT_P010LE || format == AV_PIX_FMT_P010BE || format == AV_PIX_FMT_P016LE || format == AV_PIX_FMT_P016BE) return AVERROR(ENOSYS); for (i = 0; i < desc->nb_components; i++) { c = &desc->comp[i]; diff --git a/libavfilter/formats.c b/libavfilter/formats.c index d4de862237503..31ee445c494ee 100644 --- a/libavfilter/formats.c +++ b/libavfilter/formats.c @@ -72,7 +72,7 @@ do { for (j = 0; j < b->nb; j++) \ if (a->fmts[i] == b->fmts[j]) { \ if(k >= FFMIN(a->nb, b->nb)){ \ - av_log(NULL, AV_LOG_ERROR, "Duplicate formats in avfilter_merge_formats() detected\n"); \ + av_log(NULL, AV_LOG_ERROR, "Duplicate formats in %s detected\n", __FUNCTION__); \ av_free(ret->fmts); \ av_free(ret); \ return NULL; \ @@ -662,20 +662,12 @@ int ff_parse_sample_rate(int *ret, const char *arg, void *log_ctx) int ff_parse_channel_layout(int64_t *ret, int *nret, const char *arg, void *log_ctx) { - char *tail; int64_t chlayout; int nb_channels; if (av_get_extended_channel_layout(arg, &chlayout, &nb_channels) < 0) { - /* [TEMPORARY 2016-12 -> 2017-12]*/ - nb_channels = strtol(arg, &tail, 10); - if (!errno && *tail == 'c' && *(tail + 1) == '\0' && nb_channels > 0 && nb_channels < 64) { - chlayout = 0; - av_log(log_ctx, AV_LOG_WARNING, "Deprecated channel count specification '%s'. This will stop working in releases made in 2018 and after.\n", arg); - } else { - av_log(log_ctx, AV_LOG_ERROR, "Invalid channel layout '%s'\n", arg); - return AVERROR(EINVAL); - } + av_log(log_ctx, AV_LOG_ERROR, "Invalid channel layout '%s'\n", arg); + return AVERROR(EINVAL); } if (!chlayout && !nret) { av_log(log_ctx, AV_LOG_ERROR, "Unknown channel layout '%s' is not supported.\n", arg); diff --git a/libavfilter/framepool.c b/libavfilter/framepool.c index 42c0e58498b57..3b178cebb8173 100644 --- a/libavfilter/framepool.c +++ b/libavfilter/framepool.c @@ -71,7 +71,7 @@ FFFramePool *ff_frame_pool_video_init(AVBufferRef* (*alloc)(int size), pool->format = format; pool->align = align; - if ((ret = av_image_check_size(width, height, 0, NULL)) < 0) { + if ((ret = av_image_check_size2(width, height, INT64_MAX, format, 0, NULL)) < 0) { goto fail; } @@ -103,7 +103,7 @@ FFFramePool *ff_frame_pool_video_init(AVBufferRef* (*alloc)(int size), } if (desc->flags & AV_PIX_FMT_FLAG_PAL || - desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) { + desc->flags & FF_PSEUDOPAL) { pool->pools[1] = av_buffer_pool_init(AVPALETTE_SIZE, alloc); if (!pool->pools[1]) goto fail; @@ -227,7 +227,7 @@ AVFrame *ff_frame_pool_get(FFFramePool *pool) } if (desc->flags & AV_PIX_FMT_FLAG_PAL || - desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) { + desc->flags & FF_PSEUDOPAL) { enum AVPixelFormat format = pool->format == AV_PIX_FMT_PAL8 ? AV_PIX_FMT_BGR8 : pool->format; diff --git a/libavfilter/framerate.h b/libavfilter/framerate.h new file mode 100644 index 0000000000000..a42d5af68a293 --- /dev/null +++ b/libavfilter/framerate.h @@ -0,0 +1,74 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFILTER_FRAMERATE_H +#define AVFILTER_FRAMERATE_H + +#include "libavutil/pixelutils.h" +#include "avfilter.h" + +#define BLEND_FUNC_PARAMS const uint8_t *src1, ptrdiff_t src1_linesize, \ + const uint8_t *src2, ptrdiff_t src2_linesize, \ + uint8_t *dst, ptrdiff_t dst_linesize, \ + ptrdiff_t width, ptrdiff_t height, \ + int factor1, int factor2, int half + +#define BLEND_FACTOR_DEPTH8 7 +#define BLEND_FACTOR_DEPTH16 15 + +typedef void (*blend_func)(BLEND_FUNC_PARAMS); + +typedef struct FrameRateContext { + const AVClass *class; + // parameters + AVRational dest_frame_rate; ///< output frames per second + int flags; ///< flags affecting frame rate conversion algorithm + double scene_score; ///< score that denotes a scene change has happened + int interp_start; ///< start of range to apply linear interpolation + int interp_end; ///< end of range to apply linear interpolation + + int line_size[4]; ///< bytes of pixel data per line for each plane + int vsub; + + AVRational srce_time_base; ///< timebase of source + AVRational dest_time_base; ///< timebase of destination + + av_pixelutils_sad_fn sad; ///< Sum of the absolute difference function (scene detect only) + double prev_mafd; ///< previous MAFD (scene detect only) + + int blend_factor_max; + int bitdepth; + AVFrame *work; + + AVFrame *f0; ///< last frame + AVFrame *f1; ///< current frame + int64_t pts0; ///< last frame pts in dest_time_base + int64_t pts1; ///< current frame pts in dest_time_base + int64_t delta; ///< pts1 to pts0 delta + double score; ///< scene change score (f0 to f1) + int flush; ///< 1 if the filter is being flushed + int64_t start_pts; ///< pts of the first output frame + int64_t n; ///< output frame counter + + blend_func blend; +} FrameRateContext; + +void ff_framerate_init(FrameRateContext *s); +void ff_framerate_init_x86(FrameRateContext *s); + +#endif /* AVFILTER_FRAMERATE_H */ diff --git a/libavfilter/framesync.c b/libavfilter/framesync.c index 82d715750c4bc..da12c58a618aa 100644 --- a/libavfilter/framesync.c +++ b/libavfilter/framesync.c @@ -406,7 +406,7 @@ int ff_framesync_dualinput_get_writable(FFFrameSync *fs, AVFrame **f0, AVFrame * ret = ff_inlink_make_frame_writable(fs->parent->inputs[0], f0); if (ret < 0) { av_frame_free(f0); - av_frame_free(f1); + *f1 = NULL; return ret; } return 0; diff --git a/libavfilter/framesync.h b/libavfilter/framesync.h index 9fdc4d1ae2db0..abf3bf552b99c 100644 --- a/libavfilter/framesync.h +++ b/libavfilter/framesync.h @@ -286,6 +286,9 @@ int ff_framesync_init_dualinput(FFFrameSync *fs, AVFilterContext *parent); * @param f0 used to return the main frame * @param f1 used to return the second frame, or NULL if disabled * @return >=0 for success or AVERROR code + * @note The frame returned in f0 belongs to the caller (get = 1 in + * ff_framesync_get_frame()) while the frame returned in f1 is still owned + * by the framesync structure. */ int ff_framesync_dualinput_get(FFFrameSync *fs, AVFrame **f0, AVFrame **f1); diff --git a/libavfilter/graphparser.c b/libavfilter/graphparser.c index 1405926bfd570..d92b5360a6afd 100644 --- a/libavfilter/graphparser.c +++ b/libavfilter/graphparser.c @@ -96,7 +96,7 @@ static char *parse_link_name(const char **buf, void *log_ctx) static int create_filter(AVFilterContext **filt_ctx, AVFilterGraph *ctx, int index, const char *name, const char *args, void *log_ctx) { - AVFilter *filt; + const AVFilter *filt; char name2[30]; const char *inst_name = NULL, *filt_name = NULL; char *tmp_args = NULL; diff --git a/libavfilter/hflip.h b/libavfilter/hflip.h new file mode 100644 index 0000000000000..204090dbb4e2c --- /dev/null +++ b/libavfilter/hflip.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2007 Benoit Fouet + * Copyright (c) 2010 Stefano Sabatini + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFILTER_HFLIP_H +#define AVFILTER_HFLIP_H + +#include "avfilter.h" + +typedef struct FlipContext { + const AVClass *class; + int max_step[4]; ///< max pixel step for each plane, expressed as a number of bytes + int planewidth[4]; ///< width of each plane + int planeheight[4]; ///< height of each plane + + void (*flip_line[4])(const uint8_t *src, uint8_t *dst, int w); +} FlipContext; + +int ff_hflip_init(FlipContext *s, int step[4], int nb_planes); +void ff_hflip_init_x86(FlipContext *s, int step[4], int nb_planes); + +#endif /* AVFILTER_HFLIP_H */ diff --git a/libavfilter/interlace.h b/libavfilter/interlace.h index 90a0198bdc4aa..b41f0d5706fab 100644 --- a/libavfilter/interlace.h +++ b/libavfilter/interlace.h @@ -62,6 +62,7 @@ typedef struct InterlaceContext { ptrdiff_t mref, ptrdiff_t pref, int clip_max); } InterlaceContext; -void ff_interlace_init_x86(InterlaceContext *interlace); +void ff_interlace_init(InterlaceContext *interlace, int depth); +void ff_interlace_init_x86(InterlaceContext *interlace, int depth); #endif /* AVFILTER_INTERLACE_H */ diff --git a/libavfilter/internal.h b/libavfilter/internal.h index f9679ed1d77f9..498bd3328d093 100644 --- a/libavfilter/internal.h +++ b/libavfilter/internal.h @@ -411,4 +411,20 @@ static inline int ff_norm_qscale(int qscale, int type) */ int ff_filter_get_nb_threads(AVFilterContext *ctx); +/** + * Perform any additional setup required for hardware frames. + * + * link->hw_frames_ctx must be set before calling this function. + * Inside link->hw_frames_ctx, the fields format, sw_format, width and + * height must be set. If dynamically allocated pools are not supported, + * then initial_pool_size must also be set, to the minimum hardware frame + * pool size necessary for the filter to work (taking into account any + * frames which need to stored for use in operations as appropriate). If + * default_pool_size is nonzero, then it will be used as the pool size if + * no other modification takes place (this can be used to preserve + * compatibility). + */ +int ff_filter_init_hw_frames(AVFilterContext *avctx, AVFilterLink *link, + int default_pool_size); + #endif /* AVFILTER_INTERNAL_H */ diff --git a/libavfilter/lavfutils.c b/libavfilter/lavfutils.c index b6319cf02758a..db4b69b9f36d0 100644 --- a/libavfilter/lavfutils.c +++ b/libavfilter/lavfutils.c @@ -37,8 +37,6 @@ int ff_load_image(uint8_t *data[4], int linesize[4], av_init_packet(&pkt); - av_register_all(); - iformat = av_find_input_format("image2pipe"); if ((ret = avformat_open_input(&format_ctx, filename, iformat, NULL)) < 0) { av_log(log_ctx, AV_LOG_ERROR, diff --git a/libavfilter/opencl.c b/libavfilter/opencl.c new file mode 100644 index 0000000000000..ae61667380a64 --- /dev/null +++ b/libavfilter/opencl.c @@ -0,0 +1,342 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include + +#include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_opencl.h" +#include "libavutil/mem.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "formats.h" +#include "opencl.h" + +int ff_opencl_filter_query_formats(AVFilterContext *avctx) +{ + const static enum AVPixelFormat pix_fmts[] = { + AV_PIX_FMT_OPENCL, + AV_PIX_FMT_NONE, + }; + AVFilterFormats *formats; + + formats = ff_make_format_list(pix_fmts); + if (!formats) + return AVERROR(ENOMEM); + + return ff_set_common_formats(avctx, formats); +} + +static int opencl_filter_set_device(AVFilterContext *avctx, + AVBufferRef *device) +{ + OpenCLFilterContext *ctx = avctx->priv; + + av_buffer_unref(&ctx->device_ref); + + ctx->device_ref = av_buffer_ref(device); + if (!ctx->device_ref) + return AVERROR(ENOMEM); + + ctx->device = (AVHWDeviceContext*)ctx->device_ref->data; + ctx->hwctx = ctx->device->hwctx; + + return 0; +} + +int ff_opencl_filter_config_input(AVFilterLink *inlink) +{ + AVFilterContext *avctx = inlink->dst; + OpenCLFilterContext *ctx = avctx->priv; + AVHWFramesContext *input_frames; + int err; + + if (!inlink->hw_frames_ctx) { + av_log(avctx, AV_LOG_ERROR, "OpenCL filtering requires a " + "hardware frames context on the input.\n"); + return AVERROR(EINVAL); + } + + // Extract the device and default output format from the first input. + if (avctx->inputs[0] != inlink) + return 0; + + input_frames = (AVHWFramesContext*)inlink->hw_frames_ctx->data; + if (input_frames->format != AV_PIX_FMT_OPENCL) + return AVERROR(EINVAL); + + err = opencl_filter_set_device(avctx, input_frames->device_ref); + if (err < 0) + return err; + + // Default output parameters match input parameters. + if (ctx->output_format == AV_PIX_FMT_NONE) + ctx->output_format = input_frames->sw_format; + if (!ctx->output_width) + ctx->output_width = inlink->w; + if (!ctx->output_height) + ctx->output_height = inlink->h; + + return 0; +} + +int ff_opencl_filter_config_output(AVFilterLink *outlink) +{ + AVFilterContext *avctx = outlink->src; + OpenCLFilterContext *ctx = avctx->priv; + AVBufferRef *output_frames_ref = NULL; + AVHWFramesContext *output_frames; + int err; + + av_buffer_unref(&outlink->hw_frames_ctx); + + if (!ctx->device_ref) { + if (!avctx->hw_device_ctx) { + av_log(avctx, AV_LOG_ERROR, "OpenCL filtering requires an " + "OpenCL device.\n"); + return AVERROR(EINVAL); + } + + err = opencl_filter_set_device(avctx, avctx->hw_device_ctx); + if (err < 0) + return err; + } + + output_frames_ref = av_hwframe_ctx_alloc(ctx->device_ref); + if (!output_frames_ref) { + err = AVERROR(ENOMEM); + goto fail; + } + output_frames = (AVHWFramesContext*)output_frames_ref->data; + + output_frames->format = AV_PIX_FMT_OPENCL; + output_frames->sw_format = ctx->output_format; + output_frames->width = ctx->output_width; + output_frames->height = ctx->output_height; + + err = av_hwframe_ctx_init(output_frames_ref); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to initialise output " + "frames: %d.\n", err); + goto fail; + } + + outlink->hw_frames_ctx = output_frames_ref; + outlink->w = ctx->output_width; + outlink->h = ctx->output_height; + + return 0; +fail: + av_buffer_unref(&output_frames_ref); + return err; +} + +int ff_opencl_filter_init(AVFilterContext *avctx) +{ + OpenCLFilterContext *ctx = avctx->priv; + + ctx->output_format = AV_PIX_FMT_NONE; + + return 0; +} + +void ff_opencl_filter_uninit(AVFilterContext *avctx) +{ + OpenCLFilterContext *ctx = avctx->priv; + cl_int cle; + + if (ctx->program) { + cle = clReleaseProgram(ctx->program); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "program: %d.\n", cle); + } + + av_buffer_unref(&ctx->device_ref); +} + +int ff_opencl_filter_load_program(AVFilterContext *avctx, + const char **program_source_array, + int nb_strings) +{ + OpenCLFilterContext *ctx = avctx->priv; + cl_int cle; + + ctx->program = clCreateProgramWithSource(ctx->hwctx->context, nb_strings, + program_source_array, + NULL, &cle); + if (!ctx->program) { + av_log(avctx, AV_LOG_ERROR, "Failed to create program: %d.\n", cle); + return AVERROR(EIO); + } + + cle = clBuildProgram(ctx->program, 1, &ctx->hwctx->device_id, + NULL, NULL, NULL); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to build program: %d.\n", cle); + + if (cle == CL_BUILD_PROGRAM_FAILURE) { + char *log; + size_t log_length; + + clGetProgramBuildInfo(ctx->program, ctx->hwctx->device_id, + CL_PROGRAM_BUILD_LOG, 0, NULL, &log_length); + + log = av_malloc(log_length); + if (log) { + cle = clGetProgramBuildInfo(ctx->program, + ctx->hwctx->device_id, + CL_PROGRAM_BUILD_LOG, + log_length, log, NULL); + if (cle == CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Build log:\n%s\n", log); + } + + av_free(log); + } + + clReleaseProgram(ctx->program); + ctx->program = NULL; + return AVERROR(EIO); + } + + return 0; +} + +int ff_opencl_filter_load_program_from_file(AVFilterContext *avctx, + const char *filename) +{ + FILE *file; + char *src = NULL; + size_t pos, len, rb; + const char *src_const; + int err; + + file = fopen(filename, "r"); + if (!file) { + av_log(avctx, AV_LOG_ERROR, "Unable to open program " + "source file \"%s\".\n", filename); + return AVERROR(ENOENT); + } + + len = 1 << 16; + pos = 0; + + err = av_reallocp(&src, len); + if (err < 0) + goto fail; + + err = snprintf(src, len, "#line 1 \"%s\"\n", filename); + if (err < 0) { + err = AVERROR(errno); + goto fail; + } + if (err > len / 2) { + err = AVERROR(EINVAL); + goto fail; + } + pos = err; + + while (1) { + rb = fread(src + pos, 1, len - pos - 1, file); + if (rb == 0 && ferror(file)) { + err = AVERROR(EIO); + goto fail; + } + pos += rb; + if (pos < len) + break; + len <<= 1; + err = av_reallocp(&src, len); + if (err < 0) + goto fail; + } + src[pos] = 0; + + src_const = src; + + err = ff_opencl_filter_load_program(avctx, &src_const, 1); +fail: + fclose(file); + av_freep(&src); + return err; +} + +int ff_opencl_filter_work_size_from_image(AVFilterContext *avctx, + size_t *work_size, + AVFrame *frame, int plane, + int block_alignment) +{ + cl_mem image; + cl_mem_object_type type; + size_t width, height; + cl_int cle; + + if (frame->format != AV_PIX_FMT_OPENCL) { + av_log(avctx, AV_LOG_ERROR, "Invalid frame format %s, " + "opencl required.\n", av_get_pix_fmt_name(frame->format)); + return AVERROR(EINVAL); + } + + image = (cl_mem)frame->data[plane]; + if (!image) { + av_log(avctx, AV_LOG_ERROR, "Plane %d required but not set.\n", + plane); + return AVERROR(EINVAL); + } + + cle = clGetMemObjectInfo(image, CL_MEM_TYPE, sizeof(type), + &type, NULL); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to query object type of " + "plane %d: %d.\n", plane, cle); + return AVERROR_UNKNOWN; + } + if (type != CL_MEM_OBJECT_IMAGE2D) { + av_log(avctx, AV_LOG_ERROR, "Plane %d is not a 2D image.\n", + plane); + return AVERROR(EINVAL); + } + + cle = clGetImageInfo(image, CL_IMAGE_WIDTH, sizeof(size_t), + &width, NULL); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to query plane %d width: %d.\n", + plane, cle); + return AVERROR_UNKNOWN; + } + + cle = clGetImageInfo(image, CL_IMAGE_HEIGHT, sizeof(size_t), + &height, NULL); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to query plane %d height: %d.\n", + plane, cle); + return AVERROR_UNKNOWN; + } + + if (block_alignment) { + width = FFALIGN(width, block_alignment); + height = FFALIGN(height, block_alignment); + } + + work_size[0] = width; + work_size[1] = height; + + return 0; +} diff --git a/libavfilter/opencl.h b/libavfilter/opencl.h new file mode 100644 index 0000000000000..c0a45197853bc --- /dev/null +++ b/libavfilter/opencl.h @@ -0,0 +1,101 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFILTER_OPENCL_H +#define AVFILTER_OPENCL_H + +// The intended target is OpenCL 1.2, so disable warnings for APIs +// deprecated after that. This primarily applies to clCreateCommandQueue(), +// we can't use the replacement clCreateCommandQueueWithProperties() because +// it was introduced in OpenCL 2.0. +#define CL_USE_DEPRECATED_OPENCL_1_2_APIS + +#include "libavutil/buffer.h" +#include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_opencl.h" +#include "libavutil/pixfmt.h" + +#include "avfilter.h" + +typedef struct OpenCLFilterContext { + const AVClass *class; + + AVBufferRef *device_ref; + AVHWDeviceContext *device; + AVOpenCLDeviceContext *hwctx; + + cl_program program; + + enum AVPixelFormat output_format; + int output_width; + int output_height; +} OpenCLFilterContext; + +/** + * Return that all inputs and outputs support only AV_PIX_FMT_OPENCL. + */ +int ff_opencl_filter_query_formats(AVFilterContext *avctx); + +/** + * Check that the input link contains a suitable hardware frames + * context and extract the device from it. + */ +int ff_opencl_filter_config_input(AVFilterLink *inlink); + +/** + * Create a suitable hardware frames context for the output. + */ +int ff_opencl_filter_config_output(AVFilterLink *outlink); + +/** + * Initialise an OpenCL filter context. + */ +int ff_opencl_filter_init(AVFilterContext *avctx); + +/** + * Uninitialise an OpenCL filter context. + */ +void ff_opencl_filter_uninit(AVFilterContext *avctx); + +/** + * Load a new OpenCL program from strings in memory. + * + * Creates a new program and compiles it for the current device. + * Will log any build errors if compilation fails. + */ +int ff_opencl_filter_load_program(AVFilterContext *avctx, + const char **program_source_array, + int nb_strings); + +/** + * Load a new OpenCL program from a file. + * + * Same as ff_opencl_filter_load_program(), but from a file. + */ +int ff_opencl_filter_load_program_from_file(AVFilterContext *avctx, + const char *filename); + +/** + * Find the work size needed needed for a given plane of an image. + */ +int ff_opencl_filter_work_size_from_image(AVFilterContext *avctx, + size_t *work_size, + AVFrame *frame, int plane, + int block_alignment); + +#endif /* AVFILTER_OPENCL_H */ diff --git a/libavfilter/opencl/.gitignore b/libavfilter/opencl/.gitignore new file mode 100644 index 0000000000000..064a8d8ef55dc --- /dev/null +++ b/libavfilter/opencl/.gitignore @@ -0,0 +1 @@ +*.c diff --git a/libavfilter/opencl/avgblur.cl b/libavfilter/opencl/avgblur.cl new file mode 100644 index 0000000000000..6a8d70df93017 --- /dev/null +++ b/libavfilter/opencl/avgblur.cl @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2018 Dylan Fernando + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +__kernel void avgblur_horiz(__write_only image2d_t dst, + __read_only image2d_t src, + int rad) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_FILTER_NEAREST); + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + int2 size = (int2)(get_global_size(0), get_global_size(1)); + + int count = 0; + float4 acc = (float4)(0,0,0,0); + + for (int xx = max(0, loc.x - rad); xx < min(loc.x + rad + 1, size.x); xx++) { + count++; + acc += read_imagef(src, sampler, (int2)(xx, loc.y)); + } + + write_imagef(dst, loc, acc / count); +} + +__kernel void avgblur_vert(__write_only image2d_t dst, + __read_only image2d_t src, + int radv) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_FILTER_NEAREST); + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + int2 size = (int2)(get_global_size(0), get_global_size(1)); + + int count = 0; + float4 acc = (float4)(0,0,0,0); + + for (int yy = max(0, loc.y - radv); yy < min(loc.y + radv + 1, size.y); yy++) { + count++; + acc += read_imagef(src, sampler, (int2)(loc.x, yy)); + } + + write_imagef(dst, loc, acc / count); +} diff --git a/libavfilter/opencl/convolution.cl b/libavfilter/opencl/convolution.cl new file mode 100644 index 0000000000000..03ef4eff1bc72 --- /dev/null +++ b/libavfilter/opencl/convolution.cl @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2018 Danil Iashchenko + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +__kernel void convolution_global(__write_only image2d_t dst, + __read_only image2d_t src, + int coef_matrix_dim, + __constant float *coef_matrix, + float div, + float bias) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_ADDRESS_CLAMP_TO_EDGE | + CLK_FILTER_NEAREST); + + const int half_matrix_dim = (coef_matrix_dim / 2); + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + float4 convPix = (float4)(0.0f, 0.0f, 0.0f, 0.0f); + + for (int conv_i = -half_matrix_dim; conv_i <= half_matrix_dim; conv_i++) { + for (int conv_j = -half_matrix_dim; conv_j <= half_matrix_dim; conv_j++) { + float4 px = read_imagef(src, sampler, loc + (int2)(conv_j, conv_i)); + convPix += px * coef_matrix[(conv_i + half_matrix_dim) * coef_matrix_dim + + (conv_j + half_matrix_dim)]; + } + } + float4 dstPix = convPix * div + bias; + write_imagef(dst, loc, dstPix); +} diff --git a/libavfilter/opencl/overlay.cl b/libavfilter/opencl/overlay.cl new file mode 100644 index 0000000000000..8c783d0edceef --- /dev/null +++ b/libavfilter/opencl/overlay.cl @@ -0,0 +1,104 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +__kernel void overlay_no_alpha(__write_only image2d_t dst, + __read_only image2d_t main, + __read_only image2d_t overlay, + int x_position, + int y_position) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_FILTER_NEAREST); + + int2 overlay_size = get_image_dim(overlay); + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + + if (loc.x < x_position || + loc.y < y_position || + loc.x >= overlay_size.x + x_position || + loc.y >= overlay_size.y + y_position) { + float4 val = read_imagef(main, sampler, loc); + write_imagef(dst, loc, val); + } else { + int2 loc_overlay = (int2)(x_position, y_position); + float4 val = read_imagef(overlay, sampler, loc - loc_overlay); + write_imagef(dst, loc, val); + } +} + +__kernel void overlay_internal_alpha(__write_only image2d_t dst, + __read_only image2d_t main, + __read_only image2d_t overlay, + int x_position, + int y_position) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_FILTER_NEAREST); + + int2 overlay_size = get_image_dim(overlay); + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + + if (loc.x < x_position || + loc.y < y_position || + loc.x >= overlay_size.x + x_position || + loc.y >= overlay_size.y + y_position) { + float4 val = read_imagef(main, sampler, loc); + write_imagef(dst, loc, val); + } else { + int2 loc_overlay = (int2)(x_position, y_position); + float4 in_main = read_imagef(main, sampler, loc); + float4 in_overlay = read_imagef(overlay, sampler, loc - loc_overlay); + float4 val = in_overlay * in_overlay.w + in_main * (1.0f - in_overlay.w); + write_imagef(dst, loc, val); + } +} + +__kernel void overlay_external_alpha(__write_only image2d_t dst, + __read_only image2d_t main, + __read_only image2d_t overlay, + __read_only image2d_t alpha, + int x_position, + int y_position, + int alpha_adj_x, + int alpha_adj_y) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_FILTER_NEAREST); + + int2 overlay_size = get_image_dim(overlay); + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + + if (loc.x < x_position || + loc.y < y_position || + loc.x >= overlay_size.x + x_position || + loc.y >= overlay_size.y + y_position) { + float4 val = read_imagef(main, sampler, loc); + write_imagef(dst, loc, val); + } else { + int2 loc_overlay = (int2)(x_position, y_position); + float4 in_main = read_imagef(main, sampler, loc); + float4 in_overlay = read_imagef(overlay, sampler, loc - loc_overlay); + + int2 loc_alpha = (int2)(loc.x * alpha_adj_x, + loc.y * alpha_adj_y) - loc_overlay; + float4 in_alpha = read_imagef(alpha, sampler, loc_alpha); + + float4 val = in_overlay * in_alpha.x + in_main * (1.0f - in_alpha.x); + write_imagef(dst, loc, val); + } +} diff --git a/libavfilter/opencl/unsharp.cl b/libavfilter/opencl/unsharp.cl new file mode 100644 index 0000000000000..e629834e50635 --- /dev/null +++ b/libavfilter/opencl/unsharp.cl @@ -0,0 +1,99 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +__kernel void unsharp_global(__write_only image2d_t dst, + __read_only image2d_t src, + int size_x, + int size_y, + float amount, + __constant float *coef_matrix) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_FILTER_NEAREST); + int2 loc = (int2)(get_global_id(0), get_global_id(1)); + int2 centre = (int2)(size_x / 2, size_y / 2); + + float4 val = read_imagef(src, sampler, loc); + float4 sum = 0.0f; + int x, y; + + for (y = 0; y < size_y; y++) { + for (x = 0; x < size_x; x++) { + int2 pos = loc + (int2)(x, y) - centre; + sum += coef_matrix[y * size_x + x] * + read_imagef(src, sampler, pos); + } + } + + write_imagef(dst, loc, val + (val - sum) * amount); +} + +__kernel void unsharp_local(__write_only image2d_t dst, + __read_only image2d_t src, + int size_x, + int size_y, + float amount, + __constant float *coef_x, + __constant float *coef_y) +{ + const sampler_t sampler = (CLK_NORMALIZED_COORDS_FALSE | + CLK_ADDRESS_CLAMP_TO_EDGE | + CLK_FILTER_NEAREST); + int2 block = (int2)(get_group_id(0), get_group_id(1)) * 16; + int2 pos = (int2)(get_local_id(0), get_local_id(1)); + + __local float4 tmp[32][32]; + + int rad_x = size_x / 2; + int rad_y = size_y / 2; + int x, y; + + for (y = 0; y <= 1; y++) { + for (x = 0; x <= 1; x++) { + tmp[pos.y + 16 * y][pos.x + 16 * x] = + read_imagef(src, sampler, block + pos + (int2)(16 * x - 8, 16 * y - 8)); + } + } + + barrier(CLK_LOCAL_MEM_FENCE); + + float4 val = tmp[pos.y + 8][pos.x + 8]; + + float4 horiz[2]; + for (y = 0; y <= 1; y++) { + horiz[y] = 0.0f; + for (x = 0; x < size_x; x++) + horiz[y] += coef_x[x] * tmp[pos.y + y * 16][pos.x + 8 + x - rad_x]; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + for (y = 0; y <= 1; y++) { + tmp[pos.y + y * 16][pos.x + 8] = horiz[y]; + } + + barrier(CLK_LOCAL_MEM_FENCE); + + float4 sum = 0.0f; + for (y = 0; y < size_y; y++) + sum += coef_y[y] * tmp[pos.y + 8 + y - rad_y][pos.x + 8]; + + if (block.x + pos.x < get_image_width(dst) && + block.y + pos.y < get_image_height(dst)) + write_imagef(dst, block + pos, val + (val - sum) * amount); +} diff --git a/libavfilter/opencl_allkernels.c b/libavfilter/opencl_allkernels.c deleted file mode 100644 index 6d80fa859838b..0000000000000 --- a/libavfilter/opencl_allkernels.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2013 Wei Gao - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "opencl_allkernels.h" -#if CONFIG_OPENCL -#include "libavutil/opencl.h" -#include "deshake_opencl_kernel.h" -#include "unsharp_opencl_kernel.h" -#endif - -#define OPENCL_REGISTER_KERNEL_CODE(X, x) \ - { \ - if (CONFIG_##X##_FILTER) { \ - av_opencl_register_kernel_code(ff_kernel_##x##_opencl); \ - } \ - } - -void ff_opencl_register_filter_kernel_code_all(void) -{ - #if CONFIG_OPENCL - OPENCL_REGISTER_KERNEL_CODE(DESHAKE, deshake); - OPENCL_REGISTER_KERNEL_CODE(UNSHARP, unsharp); - #endif -} diff --git a/compat/tms470/math.h b/libavfilter/opencl_source.h similarity index 72% rename from compat/tms470/math.h rename to libavfilter/opencl_source.h index 0a42743a0b406..4bb996924e4ac 100644 --- a/compat/tms470/math.h +++ b/libavfilter/opencl_source.h @@ -16,15 +16,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef COMPAT_TMS470_MATH_H -#define COMPAT_TMS470_MATH_H +#ifndef AVFILTER_OPENCL_SOURCE_H +#define AVFILTER_OPENCL_SOURCE_H -#include_next +extern const char *ff_opencl_source_avgblur; +extern const char *ff_opencl_source_convolution; +extern const char *ff_opencl_source_overlay; +extern const char *ff_opencl_source_unsharp; -#undef INFINITY -#undef NAN - -#define INFINITY (*(const float*)((const unsigned []){ 0x7f800000 })) -#define NAN (*(const float*)((const unsigned []){ 0x7fc00000 })) - -#endif /* COMPAT_TMS470_MATH_H */ +#endif /* AVFILTER_OPENCL_SOURCE_H */ diff --git a/libavfilter/pthread.c b/libavfilter/pthread.c index 567dd4c178c93..7e37c73ca34a6 100644 --- a/libavfilter/pthread.c +++ b/libavfilter/pthread.c @@ -85,10 +85,6 @@ int ff_graph_thread_init(AVFilterGraph *graph) { int ret; -#if HAVE_W32THREADS - w32thread_init(); -#endif - if (graph->nb_threads == 1) { graph->thread_type = 0; return 0; diff --git a/libavfilter/qsvvpp.c b/libavfilter/qsvvpp.c new file mode 100644 index 0000000000000..732cf56a6acc6 --- /dev/null +++ b/libavfilter/qsvvpp.c @@ -0,0 +1,733 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Intel Quick Sync Video VPP base function + */ + +#include "libavutil/common.h" +#include "libavutil/mathematics.h" +#include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_qsv.h" +#include "libavutil/time.h" +#include "libavutil/pixdesc.h" + +#include "internal.h" +#include "qsvvpp.h" +#include "video.h" + +#define IS_VIDEO_MEMORY(mode) (mode & (MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET | \ + MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET)) +#define IS_OPAQUE_MEMORY(mode) (mode & MFX_MEMTYPE_OPAQUE_FRAME) +#define IS_SYSTEM_MEMORY(mode) (mode & MFX_MEMTYPE_SYSTEM_MEMORY) + +typedef struct QSVFrame { + AVFrame *frame; + mfxFrameSurface1 *surface; + mfxFrameSurface1 surface_internal; /* for system memory */ + struct QSVFrame *next; +} QSVFrame; + +/* abstract struct for all QSV filters */ +struct QSVVPPContext { + mfxSession session; + int (*filter_frame) (AVFilterLink *outlink, AVFrame *frame);/* callback */ + enum AVPixelFormat out_sw_format; /* Real output format */ + mfxVideoParam vpp_param; + mfxFrameInfo *frame_infos; /* frame info for each input */ + + /* members related to the input/output surface */ + int in_mem_mode; + int out_mem_mode; + QSVFrame *in_frame_list; + QSVFrame *out_frame_list; + int nb_surface_ptrs_in; + int nb_surface_ptrs_out; + mfxFrameSurface1 **surface_ptrs_in; + mfxFrameSurface1 **surface_ptrs_out; + + /* MFXVPP extern parameters */ + mfxExtOpaqueSurfaceAlloc opaque_alloc; + mfxExtBuffer **ext_buffers; + int nb_ext_buffers; +}; + +static const mfxHandleType handle_types[] = { + MFX_HANDLE_VA_DISPLAY, + MFX_HANDLE_D3D9_DEVICE_MANAGER, + MFX_HANDLE_D3D11_DEVICE, +}; + +static const AVRational default_tb = { 1, 90000 }; + +/* functions for frameAlloc */ +static mfxStatus frame_alloc(mfxHDL pthis, mfxFrameAllocRequest *req, + mfxFrameAllocResponse *resp) +{ + QSVVPPContext *s = pthis; + int i; + + if (!(req->Type & MFX_MEMTYPE_VIDEO_MEMORY_PROCESSOR_TARGET) || + !(req->Type & (MFX_MEMTYPE_FROM_VPPIN | MFX_MEMTYPE_FROM_VPPOUT)) || + !(req->Type & MFX_MEMTYPE_EXTERNAL_FRAME)) + return MFX_ERR_UNSUPPORTED; + + if (req->Type & MFX_MEMTYPE_FROM_VPPIN) { + resp->mids = av_mallocz(s->nb_surface_ptrs_in * sizeof(*resp->mids)); + if (!resp->mids) + return AVERROR(ENOMEM); + + for (i = 0; i < s->nb_surface_ptrs_in; i++) + resp->mids[i] = s->surface_ptrs_in[i]->Data.MemId; + + resp->NumFrameActual = s->nb_surface_ptrs_in; + } else { + resp->mids = av_mallocz(s->nb_surface_ptrs_out * sizeof(*resp->mids)); + if (!resp->mids) + return AVERROR(ENOMEM); + + for (i = 0; i < s->nb_surface_ptrs_out; i++) + resp->mids[i] = s->surface_ptrs_out[i]->Data.MemId; + + resp->NumFrameActual = s->nb_surface_ptrs_out; + } + + return MFX_ERR_NONE; +} + +static mfxStatus frame_free(mfxHDL pthis, mfxFrameAllocResponse *resp) +{ + av_freep(&resp->mids); + return MFX_ERR_NONE; +} + +static mfxStatus frame_lock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr) +{ + return MFX_ERR_UNSUPPORTED; +} + +static mfxStatus frame_unlock(mfxHDL pthis, mfxMemId mid, mfxFrameData *ptr) +{ + return MFX_ERR_UNSUPPORTED; +} + +static mfxStatus frame_get_hdl(mfxHDL pthis, mfxMemId mid, mfxHDL *hdl) +{ + *hdl = mid; + return MFX_ERR_NONE; +} + +static int pix_fmt_to_mfx_fourcc(int format) +{ + switch (format) { + case AV_PIX_FMT_YUV420P: + return MFX_FOURCC_YV12; + case AV_PIX_FMT_NV12: + return MFX_FOURCC_NV12; + case AV_PIX_FMT_YUYV422: + return MFX_FOURCC_YUY2; + case AV_PIX_FMT_RGB32: + return MFX_FOURCC_RGB4; + } + + return MFX_FOURCC_NV12; +} + +static int map_frame_to_surface(AVFrame *frame, mfxFrameSurface1 *surface) +{ + switch (frame->format) { + case AV_PIX_FMT_NV12: + surface->Data.Y = frame->data[0]; + surface->Data.UV = frame->data[1]; + break; + case AV_PIX_FMT_YUV420P: + surface->Data.Y = frame->data[0]; + surface->Data.U = frame->data[1]; + surface->Data.V = frame->data[2]; + break; + case AV_PIX_FMT_YUYV422: + surface->Data.Y = frame->data[0]; + surface->Data.U = frame->data[0] + 1; + surface->Data.V = frame->data[0] + 3; + break; + case AV_PIX_FMT_RGB32: + surface->Data.B = frame->data[0]; + surface->Data.G = frame->data[0] + 1; + surface->Data.R = frame->data[0] + 2; + surface->Data.A = frame->data[0] + 3; + break; + default: + return MFX_ERR_UNSUPPORTED; + } + surface->Data.Pitch = frame->linesize[0]; + + return 0; +} + +/* fill the surface info */ +static int fill_frameinfo_by_link(mfxFrameInfo *frameinfo, AVFilterLink *link) +{ + enum AVPixelFormat pix_fmt; + AVHWFramesContext *frames_ctx; + AVQSVFramesContext *frames_hwctx; + const AVPixFmtDescriptor *desc; + + if (link->format == AV_PIX_FMT_QSV) { + if (!link->hw_frames_ctx) + return AVERROR(EINVAL); + + frames_ctx = (AVHWFramesContext *)link->hw_frames_ctx->data; + frames_hwctx = frames_ctx->hwctx; + *frameinfo = frames_hwctx->surfaces[0].Info; + } else { + pix_fmt = link->format; + desc = av_pix_fmt_desc_get(pix_fmt); + if (!desc) + return AVERROR_BUG; + + frameinfo->CropX = 0; + frameinfo->CropY = 0; + frameinfo->Width = FFALIGN(link->w, 32); + frameinfo->Height = FFALIGN(link->h, 32); + frameinfo->PicStruct = MFX_PICSTRUCT_PROGRESSIVE; + frameinfo->FourCC = pix_fmt_to_mfx_fourcc(pix_fmt); + frameinfo->BitDepthLuma = desc->comp[0].depth; + frameinfo->BitDepthChroma = desc->comp[0].depth; + frameinfo->Shift = desc->comp[0].depth > 8; + if (desc->log2_chroma_w && desc->log2_chroma_h) + frameinfo->ChromaFormat = MFX_CHROMAFORMAT_YUV420; + else if (desc->log2_chroma_w) + frameinfo->ChromaFormat = MFX_CHROMAFORMAT_YUV422; + else + frameinfo->ChromaFormat = MFX_CHROMAFORMAT_YUV444; + } + + frameinfo->CropW = link->w; + frameinfo->CropH = link->h; + frameinfo->FrameRateExtN = link->frame_rate.num; + frameinfo->FrameRateExtD = link->frame_rate.den; + frameinfo->AspectRatioW = link->sample_aspect_ratio.num ? link->sample_aspect_ratio.num : 1; + frameinfo->AspectRatioH = link->sample_aspect_ratio.den ? link->sample_aspect_ratio.den : 1; + + return 0; +} + +static void clear_unused_frames(QSVFrame *list) +{ + while (list) { + if (list->surface && !list->surface->Data.Locked) { + list->surface = NULL; + av_frame_free(&list->frame); + } + list = list->next; + } +} + +static void clear_frame_list(QSVFrame **list) +{ + while (*list) { + QSVFrame *frame; + + frame = *list; + *list = (*list)->next; + av_frame_free(&frame->frame); + av_freep(&frame); + } +} + +static QSVFrame *get_free_frame(QSVFrame **list) +{ + QSVFrame *out = *list; + + for (; out; out = out->next) { + if (!out->surface) + break; + } + + if (!out) { + out = av_mallocz(sizeof(*out)); + if (!out) { + av_log(NULL, AV_LOG_ERROR, "Can't alloc new output frame.\n"); + return NULL; + } + out->next = *list; + *list = out; + } + + return out; +} + +/* get the input surface */ +static QSVFrame *submit_frame(QSVVPPContext *s, AVFilterLink *inlink, AVFrame *picref) +{ + QSVFrame *qsv_frame; + AVFilterContext *ctx = inlink->dst; + + clear_unused_frames(s->in_frame_list); + + qsv_frame = get_free_frame(&s->in_frame_list); + if (!qsv_frame) + return NULL; + + /* Turn AVFrame into mfxFrameSurface1. + * For video/opaque memory mode, pix_fmt is AV_PIX_FMT_QSV, and + * mfxFrameSurface1 is stored in AVFrame->data[3]; + * for system memory mode, raw video data is stored in + * AVFrame, we should map it into mfxFrameSurface1. + */ + if (!IS_SYSTEM_MEMORY(s->in_mem_mode)) { + if (picref->format != AV_PIX_FMT_QSV) { + av_log(ctx, AV_LOG_ERROR, "QSVVPP gets a wrong frame.\n"); + return NULL; + } + qsv_frame->frame = picref; + qsv_frame->surface = (mfxFrameSurface1 *)qsv_frame->frame->data[3]; + } else { + /* make a copy if the input is not padded as libmfx requires */ + if (picref->height & 31 || picref->linesize[0] & 31) { + qsv_frame->frame = ff_get_video_buffer(inlink, + FFALIGN(inlink->w, 32), + FFALIGN(inlink->h, 32)); + if (!qsv_frame->frame) + return NULL; + + qsv_frame->frame->width = picref->width; + qsv_frame->frame->height = picref->height; + + if (av_frame_copy(qsv_frame->frame, picref) < 0) { + av_frame_free(&qsv_frame->frame); + return NULL; + } + + av_frame_copy_props(qsv_frame->frame, picref); + av_frame_free(&picref); + } else + qsv_frame->frame = picref; + + if (map_frame_to_surface(qsv_frame->frame, + &qsv_frame->surface_internal) < 0) { + av_log(ctx, AV_LOG_ERROR, "Unsupported frame.\n"); + return NULL; + } + qsv_frame->surface = &qsv_frame->surface_internal; + } + + qsv_frame->surface->Info = s->frame_infos[FF_INLINK_IDX(inlink)]; + qsv_frame->surface->Data.TimeStamp = av_rescale_q(qsv_frame->frame->pts, + inlink->time_base, default_tb); + + qsv_frame->surface->Info.PicStruct = + !qsv_frame->frame->interlaced_frame ? MFX_PICSTRUCT_PROGRESSIVE : + (qsv_frame->frame->top_field_first ? MFX_PICSTRUCT_FIELD_TFF : + MFX_PICSTRUCT_FIELD_BFF); + if (qsv_frame->frame->repeat_pict == 1) + qsv_frame->surface->Info.PicStruct |= MFX_PICSTRUCT_FIELD_REPEATED; + else if (qsv_frame->frame->repeat_pict == 2) + qsv_frame->surface->Info.PicStruct |= MFX_PICSTRUCT_FRAME_DOUBLING; + else if (qsv_frame->frame->repeat_pict == 4) + qsv_frame->surface->Info.PicStruct |= MFX_PICSTRUCT_FRAME_TRIPLING; + + return qsv_frame; +} + +/* get the output surface */ +static QSVFrame *query_frame(QSVVPPContext *s, AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + QSVFrame *out_frame; + int ret; + + clear_unused_frames(s->out_frame_list); + + out_frame = get_free_frame(&s->out_frame_list); + if (!out_frame) + return NULL; + + /* For video memory, get a hw frame; + * For system memory, get a sw frame and map it into a mfx_surface. */ + if (!IS_SYSTEM_MEMORY(s->out_mem_mode)) { + out_frame->frame = av_frame_alloc(); + if (!out_frame->frame) + return NULL; + + ret = av_hwframe_get_buffer(outlink->hw_frames_ctx, out_frame->frame, 0); + if (ret < 0) { + av_log(ctx, AV_LOG_ERROR, "Can't allocate a surface.\n"); + return NULL; + } + + out_frame->surface = (mfxFrameSurface1 *)out_frame->frame->data[3]; + } else { + /* Get a frame with aligned dimensions. + * Libmfx need system memory being 128x64 aligned */ + out_frame->frame = ff_get_video_buffer(outlink, + FFALIGN(outlink->w, 128), + FFALIGN(outlink->h, 64)); + if (!out_frame->frame) + return NULL; + + out_frame->frame->width = outlink->w; + out_frame->frame->height = outlink->h; + + ret = map_frame_to_surface(out_frame->frame, + &out_frame->surface_internal); + if (ret < 0) + return NULL; + + out_frame->surface = &out_frame->surface_internal; + } + + out_frame->surface->Info = s->vpp_param.vpp.Out; + + return out_frame; +} + +/* create the QSV session */ +static int init_vpp_session(AVFilterContext *avctx, QSVVPPContext *s) +{ + AVFilterLink *inlink = avctx->inputs[0]; + AVFilterLink *outlink = avctx->outputs[0]; + AVQSVFramesContext *in_frames_hwctx = NULL; + AVQSVFramesContext *out_frames_hwctx = NULL; + + AVBufferRef *device_ref; + AVHWDeviceContext *device_ctx; + AVQSVDeviceContext *device_hwctx; + mfxHDL handle; + mfxHandleType handle_type; + mfxVersion ver; + mfxIMPL impl; + int ret, i; + + if (inlink->hw_frames_ctx) { + AVHWFramesContext *frames_ctx = (AVHWFramesContext *)inlink->hw_frames_ctx->data; + + device_ref = frames_ctx->device_ref; + in_frames_hwctx = frames_ctx->hwctx; + + s->in_mem_mode = in_frames_hwctx->frame_type; + + s->surface_ptrs_in = av_mallocz_array(in_frames_hwctx->nb_surfaces, + sizeof(*s->surface_ptrs_in)); + if (!s->surface_ptrs_in) + return AVERROR(ENOMEM); + + for (i = 0; i < in_frames_hwctx->nb_surfaces; i++) + s->surface_ptrs_in[i] = in_frames_hwctx->surfaces + i; + + s->nb_surface_ptrs_in = in_frames_hwctx->nb_surfaces; + } else if (avctx->hw_device_ctx) { + device_ref = avctx->hw_device_ctx; + s->in_mem_mode = MFX_MEMTYPE_SYSTEM_MEMORY; + } else { + av_log(avctx, AV_LOG_ERROR, "No hw context provided.\n"); + return AVERROR(EINVAL); + } + + device_ctx = (AVHWDeviceContext *)device_ref->data; + device_hwctx = device_ctx->hwctx; + + if (outlink->format == AV_PIX_FMT_QSV) { + AVHWFramesContext *out_frames_ctx; + AVBufferRef *out_frames_ref = av_hwframe_ctx_alloc(device_ref); + if (!out_frames_ref) + return AVERROR(ENOMEM); + + s->out_mem_mode = IS_OPAQUE_MEMORY(s->in_mem_mode) ? + MFX_MEMTYPE_OPAQUE_FRAME : + MFX_MEMTYPE_VIDEO_MEMORY_DECODER_TARGET; + + out_frames_ctx = (AVHWFramesContext *)out_frames_ref->data; + out_frames_hwctx = out_frames_ctx->hwctx; + + out_frames_ctx->format = AV_PIX_FMT_QSV; + out_frames_ctx->width = FFALIGN(outlink->w, 32); + out_frames_ctx->height = FFALIGN(outlink->h, 32); + out_frames_ctx->sw_format = s->out_sw_format; + out_frames_ctx->initial_pool_size = 64; + out_frames_hwctx->frame_type = s->out_mem_mode; + + ret = av_hwframe_ctx_init(out_frames_ref); + if (ret < 0) { + av_buffer_unref(&out_frames_ref); + av_log(avctx, AV_LOG_ERROR, "Error creating frames_ctx for output pad.\n"); + return ret; + } + + s->surface_ptrs_out = av_mallocz_array(out_frames_hwctx->nb_surfaces, + sizeof(*s->surface_ptrs_out)); + if (!s->surface_ptrs_out) { + av_buffer_unref(&out_frames_ref); + return AVERROR(ENOMEM); + } + + for (i = 0; i < out_frames_hwctx->nb_surfaces; i++) + s->surface_ptrs_out[i] = out_frames_hwctx->surfaces + i; + s->nb_surface_ptrs_out = out_frames_hwctx->nb_surfaces; + + av_buffer_unref(&outlink->hw_frames_ctx); + outlink->hw_frames_ctx = out_frames_ref; + } else + s->out_mem_mode = MFX_MEMTYPE_SYSTEM_MEMORY; + + /* extract the properties of the "master" session given to us */ + ret = MFXQueryIMPL(device_hwctx->session, &impl); + if (ret == MFX_ERR_NONE) + ret = MFXQueryVersion(device_hwctx->session, &ver); + if (ret != MFX_ERR_NONE) { + av_log(avctx, AV_LOG_ERROR, "Error querying the session attributes\n"); + return AVERROR_UNKNOWN; + } + + for (i = 0; i < FF_ARRAY_ELEMS(handle_types); i++) { + ret = MFXVideoCORE_GetHandle(device_hwctx->session, handle_types[i], &handle); + if (ret == MFX_ERR_NONE) { + handle_type = handle_types[i]; + break; + } + } + + /* create a "slave" session with those same properties, to be used for vpp */ + ret = MFXInit(impl, &ver, &s->session); + if (ret != MFX_ERR_NONE) { + av_log(avctx, AV_LOG_ERROR, "Error initializing a session for scaling\n"); + return AVERROR_UNKNOWN; + } + + if (handle) { + ret = MFXVideoCORE_SetHandle(s->session, handle_type, handle); + if (ret != MFX_ERR_NONE) + return AVERROR_UNKNOWN; + } + + if (QSV_RUNTIME_VERSION_ATLEAST(ver, 1, 25)) { + ret = MFXJoinSession(device_hwctx->session, s->session); + if (ret != MFX_ERR_NONE) + return AVERROR_UNKNOWN; + } + + if (IS_OPAQUE_MEMORY(s->in_mem_mode) || IS_OPAQUE_MEMORY(s->out_mem_mode)) { + s->opaque_alloc.In.Surfaces = s->surface_ptrs_in; + s->opaque_alloc.In.NumSurface = s->nb_surface_ptrs_in; + s->opaque_alloc.In.Type = s->in_mem_mode; + + s->opaque_alloc.Out.Surfaces = s->surface_ptrs_out; + s->opaque_alloc.Out.NumSurface = s->nb_surface_ptrs_out; + s->opaque_alloc.Out.Type = s->out_mem_mode; + + s->opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION; + s->opaque_alloc.Header.BufferSz = sizeof(s->opaque_alloc); + } else if (IS_VIDEO_MEMORY(s->in_mem_mode) || IS_VIDEO_MEMORY(s->out_mem_mode)) { + mfxFrameAllocator frame_allocator = { + .pthis = s, + .Alloc = frame_alloc, + .Lock = frame_lock, + .Unlock = frame_unlock, + .GetHDL = frame_get_hdl, + .Free = frame_free, + }; + + ret = MFXVideoCORE_SetFrameAllocator(s->session, &frame_allocator); + if (ret != MFX_ERR_NONE) + return AVERROR_UNKNOWN; + } + + return 0; +} + +int ff_qsvvpp_create(AVFilterContext *avctx, QSVVPPContext **vpp, QSVVPPParam *param) +{ + int i; + int ret; + QSVVPPContext *s; + + s = av_mallocz(sizeof(*s)); + if (!s) + return AVERROR(ENOMEM); + + s->filter_frame = param->filter_frame; + if (!s->filter_frame) + s->filter_frame = ff_filter_frame; + s->out_sw_format = param->out_sw_format; + + /* create the vpp session */ + ret = init_vpp_session(avctx, s); + if (ret < 0) + goto failed; + + s->frame_infos = av_mallocz_array(avctx->nb_inputs, sizeof(*s->frame_infos)); + if (!s->frame_infos) { + ret = AVERROR(ENOMEM); + goto failed; + } + + /* Init each input's information */ + for (i = 0; i < avctx->nb_inputs; i++) { + ret = fill_frameinfo_by_link(&s->frame_infos[i], avctx->inputs[i]); + if (ret < 0) + goto failed; + } + + /* Update input's frame info according to crop */ + for (i = 0; i < param->num_crop; i++) { + QSVVPPCrop *crop = param->crop + i; + if (crop->in_idx > avctx->nb_inputs) { + ret = AVERROR(EINVAL); + goto failed; + } + s->frame_infos[crop->in_idx].CropX = crop->x; + s->frame_infos[crop->in_idx].CropY = crop->y; + s->frame_infos[crop->in_idx].CropW = crop->w; + s->frame_infos[crop->in_idx].CropH = crop->h; + } + + s->vpp_param.vpp.In = s->frame_infos[0]; + + ret = fill_frameinfo_by_link(&s->vpp_param.vpp.Out, avctx->outputs[0]); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Fail to get frame info from link.\n"); + goto failed; + } + + if (IS_OPAQUE_MEMORY(s->in_mem_mode) || IS_OPAQUE_MEMORY(s->out_mem_mode)) { + s->nb_ext_buffers = param->num_ext_buf + 1; + s->ext_buffers = av_mallocz_array(s->nb_ext_buffers, sizeof(*s->ext_buffers)); + if (!s->ext_buffers) { + ret = AVERROR(ENOMEM); + goto failed; + } + + s->ext_buffers[0] = (mfxExtBuffer *)&s->opaque_alloc; + for (i = 1; i < param->num_ext_buf; i++) + s->ext_buffers[i] = param->ext_buf[i - 1]; + s->vpp_param.ExtParam = s->ext_buffers; + s->vpp_param.NumExtParam = s->nb_ext_buffers; + } else { + s->vpp_param.NumExtParam = param->num_ext_buf; + s->vpp_param.ExtParam = param->ext_buf; + } + + s->vpp_param.AsyncDepth = 1; + + if (IS_SYSTEM_MEMORY(s->in_mem_mode)) + s->vpp_param.IOPattern |= MFX_IOPATTERN_IN_SYSTEM_MEMORY; + else if (IS_VIDEO_MEMORY(s->in_mem_mode)) + s->vpp_param.IOPattern |= MFX_IOPATTERN_IN_VIDEO_MEMORY; + else if (IS_OPAQUE_MEMORY(s->in_mem_mode)) + s->vpp_param.IOPattern |= MFX_IOPATTERN_IN_OPAQUE_MEMORY; + + if (IS_SYSTEM_MEMORY(s->out_mem_mode)) + s->vpp_param.IOPattern |= MFX_IOPATTERN_OUT_SYSTEM_MEMORY; + else if (IS_VIDEO_MEMORY(s->out_mem_mode)) + s->vpp_param.IOPattern |= MFX_IOPATTERN_OUT_VIDEO_MEMORY; + else if (IS_OPAQUE_MEMORY(s->out_mem_mode)) + s->vpp_param.IOPattern |= MFX_IOPATTERN_OUT_OPAQUE_MEMORY; + + ret = MFXVideoVPP_Init(s->session, &s->vpp_param); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to create a qsvvpp, ret = %d.\n", ret); + goto failed; + } + + *vpp = s; + return 0; + +failed: + ff_qsvvpp_free(&s); + + return ret; +} + +int ff_qsvvpp_free(QSVVPPContext **vpp) +{ + QSVVPPContext *s = *vpp; + + if (!s) + return 0; + + if (s->session) { + MFXVideoVPP_Close(s->session); + MFXClose(s->session); + } + + /* release all the resources */ + clear_frame_list(&s->in_frame_list); + clear_frame_list(&s->out_frame_list); + av_freep(&s->surface_ptrs_in); + av_freep(&s->surface_ptrs_out); + av_freep(&s->ext_buffers); + av_freep(&s->frame_infos); + av_freep(vpp); + + return 0; +} + +int ff_qsvvpp_filter_frame(QSVVPPContext *s, AVFilterLink *inlink, AVFrame *picref) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + mfxSyncPoint sync; + QSVFrame *in_frame, *out_frame; + int ret, filter_ret; + + in_frame = submit_frame(s, inlink, picref); + if (!in_frame) { + av_log(ctx, AV_LOG_ERROR, "Failed to submit frame on input[%d]\n", + FF_INLINK_IDX(inlink)); + return AVERROR(ENOMEM); + } + + do { + out_frame = query_frame(s, outlink); + if (!out_frame) { + av_log(ctx, AV_LOG_ERROR, "Failed to query an output frame.\n"); + return AVERROR(ENOMEM); + } + + do { + ret = MFXVideoVPP_RunFrameVPPAsync(s->session, in_frame->surface, + out_frame->surface, NULL, &sync); + if (ret == MFX_WRN_DEVICE_BUSY) + av_usleep(500); + } while (ret == MFX_WRN_DEVICE_BUSY); + + if (ret < 0 && ret != MFX_ERR_MORE_SURFACE) { + /* Ignore more_data error */ + if (ret == MFX_ERR_MORE_DATA) + ret = AVERROR(EAGAIN); + break; + } + + if (MFXVideoCORE_SyncOperation(s->session, sync, 1000) < 0) + av_log(ctx, AV_LOG_WARNING, "Sync failed.\n"); + + out_frame->frame->pts = av_rescale_q(out_frame->surface->Data.TimeStamp, + default_tb, outlink->time_base); + + filter_ret = s->filter_frame(outlink, out_frame->frame); + if (filter_ret < 0) { + av_frame_free(&out_frame->frame); + ret = filter_ret; + break; + } + out_frame->frame = NULL; + } while(ret == MFX_ERR_MORE_SURFACE); + + return ret; +} diff --git a/libavfilter/qsvvpp.h b/libavfilter/qsvvpp.h new file mode 100644 index 0000000000000..ff02b64c411a4 --- /dev/null +++ b/libavfilter/qsvvpp.h @@ -0,0 +1,74 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Intel Quick Sync Video VPP base function + */ + +#ifndef AVFILTER_QSVVPP_H +#define AVFILTER_QSVVPP_H + +#include + +#include "avfilter.h" + +#define FF_INLINK_IDX(link) ((int)((link)->dstpad - (link)->dst->input_pads)) +#define FF_OUTLINK_IDX(link) ((int)((link)->srcpad - (link)->src->output_pads)) + +#define QSV_VERSION_ATLEAST(MAJOR, MINOR) \ + (MFX_VERSION_MAJOR > (MAJOR) || \ + MFX_VERSION_MAJOR == (MAJOR) && MFX_VERSION_MINOR >= (MINOR)) + +#define QSV_RUNTIME_VERSION_ATLEAST(MFX_VERSION, MAJOR, MINOR) \ + (MFX_VERSION.Major > (MAJOR)) || \ + (MFX_VERSION.Major == (MAJOR) && MFX_VERSION.Minor >= (MINOR)) + +typedef struct QSVVPPContext QSVVPPContext; + +typedef struct QSVVPPCrop { + int in_idx; ///< Input index + int x, y, w, h; ///< Crop rectangle +} QSVVPPCrop; + +typedef struct QSVVPPParam { + /* default is ff_filter_frame */ + int (*filter_frame)(AVFilterLink *outlink, AVFrame *frame); + + /* To fill with MFX enhanced filter configurations */ + int num_ext_buf; + mfxExtBuffer **ext_buf; + + /* Real output format */ + enum AVPixelFormat out_sw_format; + + /* Crop information for each input, if needed */ + int num_crop; + QSVVPPCrop *crop; +} QSVVPPParam; + +/* create and initialize the QSV session */ +int ff_qsvvpp_create(AVFilterContext *avctx, QSVVPPContext **vpp, QSVVPPParam *param); + +/* release the resources (eg.surfaces) */ +int ff_qsvvpp_free(QSVVPPContext **vpp); + +/* vpp filter frame and call the cb if needed */ +int ff_qsvvpp_filter_frame(QSVVPPContext *vpp, AVFilterLink *inlink, AVFrame *frame); + +#endif /* AVFILTER_QSVVPP_H */ diff --git a/libavfilter/src_movie.c b/libavfilter/src_movie.c index 258ba504a5717..bcabfcc4c295e 100644 --- a/libavfilter/src_movie.c +++ b/libavfilter/src_movie.c @@ -239,8 +239,6 @@ static av_cold int movie_common_init(AVFilterContext *ctx) return AVERROR_PATCHWELCOME; } - av_register_all(); - // Try to find the movie format (container) iformat = movie->format_name ? av_find_input_format(movie->format_name) : NULL; diff --git a/libavfilter/tests/filtfmts.c b/libavfilter/tests/filtfmts.c index 199d74d7a93f6..a958621f1c2cd 100644 --- a/libavfilter/tests/filtfmts.c +++ b/libavfilter/tests/filtfmts.c @@ -73,7 +73,7 @@ static void print_formats(AVFilterContext *filter_ctx) int main(int argc, char **argv) { - AVFilter *filter; + const AVFilter *filter; AVFilterContext *filter_ctx; AVFilterGraph *graph_ctx; const char *filter_name; @@ -97,8 +97,6 @@ int main(int argc, char **argv) if (!graph_ctx) return 1; - avfilter_register_all(); - /* get a corresponding filter and open it */ if (!(filter = avfilter_get_by_name(filter_name))) { fprintf(stderr, "Unrecognized filter with name '%s'\n", filter_name); diff --git a/libavfilter/threshold.h b/libavfilter/threshold.h new file mode 100644 index 0000000000000..775a9f9cae911 --- /dev/null +++ b/libavfilter/threshold.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2016 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFILTER_THRESHOLD_H +#define AVFILTER_THRESHOLD_H + +#include "avfilter.h" +#include "framesync.h" + +typedef struct ThresholdContext { + const AVClass *class; + + int depth; + int planes; + int bpc; + + int nb_planes; + int width[4], height[4]; + + void (*threshold)(const uint8_t *in, const uint8_t *threshold, + const uint8_t *min, const uint8_t *max, + uint8_t *out, + ptrdiff_t ilinesize, ptrdiff_t tlinesize, + ptrdiff_t flinesize, ptrdiff_t slinesize, + ptrdiff_t olinesize, + int w, int h); + + AVFrame *frames[4]; + FFFrameSync fs; +} ThresholdContext; + +void ff_threshold_init(ThresholdContext *s); +void ff_threshold_init_x86(ThresholdContext *s); + +#endif /* AVFILTER_THRESHOLD_H */ diff --git a/libavfilter/unsharp.h b/libavfilter/unsharp.h index 340a6a0caf41b..caff986fc1bd5 100644 --- a/libavfilter/unsharp.h +++ b/libavfilter/unsharp.h @@ -24,38 +24,10 @@ #include "config.h" #include "avfilter.h" -#if CONFIG_OPENCL -#include "libavutil/opencl.h" -#endif #define MIN_MATRIX_SIZE 3 #define MAX_MATRIX_SIZE 63 -#if CONFIG_OPENCL - -typedef struct UnsharpOpenclContext { - cl_command_queue command_queue; - cl_program program; - cl_kernel kernel_default; - cl_kernel kernel_luma; - cl_kernel kernel_chroma; - cl_mem cl_luma_mask; - cl_mem cl_chroma_mask; - cl_mem cl_luma_mask_x; - cl_mem cl_chroma_mask_x; - cl_mem cl_luma_mask_y; - cl_mem cl_chroma_mask_y; - int in_plane_size[8]; - int out_plane_size[8]; - int plane_num; - cl_mem cl_inbuf; - size_t cl_inbuf_size; - cl_mem cl_outbuf; - size_t cl_outbuf_size; - int use_fast_kernels; -} UnsharpOpenclContext; - -#endif typedef struct UnsharpFilterParam { int msize_x; ///< matrix width @@ -76,9 +48,6 @@ typedef struct UnsharpContext { UnsharpFilterParam chroma; ///< chroma parameters (width, height, amount) int hsub, vsub; int opencl; -#if CONFIG_OPENCL - UnsharpOpenclContext opencl_ctx; -#endif int (* apply_unsharp)(AVFilterContext *ctx, AVFrame *in, AVFrame *out); } UnsharpContext; diff --git a/libavfilter/unsharp_opencl.c b/libavfilter/unsharp_opencl.c deleted file mode 100644 index 15454558465fa..0000000000000 --- a/libavfilter/unsharp_opencl.c +++ /dev/null @@ -1,422 +0,0 @@ -/* - * Copyright (C) 2013 Wei Gao - * Copyright (C) 2013 Lenny Wang - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file - * unsharp input video - */ - -#include "unsharp_opencl.h" -#include "libavutil/common.h" -#include "libavutil/opencl_internal.h" - -#define PLANE_NUM 3 -#define ROUND_TO_16(a) (((((a) - 1)/16)+1)*16) - -static inline void add_mask_counter(uint32_t *dst, uint32_t *counter1, uint32_t *counter2, int len) -{ - int i; - for (i = 0; i < len; i++) { - dst[i] = counter1[i] + counter2[i]; - } -} - -static int compute_mask(int step, uint32_t *mask) -{ - int i, z, ret = 0; - int counter_size = sizeof(uint32_t) * (2 * step + 1); - uint32_t *temp1_counter, *temp2_counter, **counter = NULL; - temp1_counter = av_mallocz(counter_size); - if (!temp1_counter) { - ret = AVERROR(ENOMEM); - goto end; - } - temp2_counter = av_mallocz(counter_size); - if (!temp2_counter) { - ret = AVERROR(ENOMEM); - goto end; - } - counter = av_mallocz_array(2 * step + 1, sizeof(uint32_t *)); - if (!counter) { - ret = AVERROR(ENOMEM); - goto end; - } - for (i = 0; i < 2 * step + 1; i++) { - counter[i] = av_mallocz(counter_size); - if (!counter[i]) { - ret = AVERROR(ENOMEM); - goto end; - } - } - for (i = 0; i < 2 * step + 1; i++) { - memset(temp1_counter, 0, counter_size); - temp1_counter[i] = 1; - for (z = 0; z < step * 2; z += 2) { - add_mask_counter(temp2_counter, counter[z], temp1_counter, step * 2); - memcpy(counter[z], temp1_counter, counter_size); - add_mask_counter(temp1_counter, counter[z + 1], temp2_counter, step * 2); - memcpy(counter[z + 1], temp2_counter, counter_size); - } - } - memcpy(mask, temp1_counter, counter_size); -end: - av_freep(&temp1_counter); - av_freep(&temp2_counter); - for (i = 0; counter && i < 2 * step + 1; i++) { - av_freep(&counter[i]); - } - av_freep(&counter); - return ret; -} - -static int copy_separable_masks(cl_mem cl_mask_x, cl_mem cl_mask_y, int step_x, int step_y) -{ - int ret = 0; - uint32_t *mask_x, *mask_y; - size_t size_mask_x = sizeof(uint32_t) * (2 * step_x + 1); - size_t size_mask_y = sizeof(uint32_t) * (2 * step_y + 1); - mask_x = av_mallocz_array(2 * step_x + 1, sizeof(uint32_t)); - if (!mask_x) { - ret = AVERROR(ENOMEM); - goto end; - } - mask_y = av_mallocz_array(2 * step_y + 1, sizeof(uint32_t)); - if (!mask_y) { - ret = AVERROR(ENOMEM); - goto end; - } - - ret = compute_mask(step_x, mask_x); - if (ret < 0) - goto end; - ret = compute_mask(step_y, mask_y); - if (ret < 0) - goto end; - - ret = av_opencl_buffer_write(cl_mask_x, (uint8_t *)mask_x, size_mask_x); - ret = av_opencl_buffer_write(cl_mask_y, (uint8_t *)mask_y, size_mask_y); -end: - av_freep(&mask_x); - av_freep(&mask_y); - - return ret; -} - -static int generate_mask(AVFilterContext *ctx) -{ - cl_mem masks[4]; - cl_mem mask_matrix[2]; - int i, ret = 0, step_x[2], step_y[2]; - - UnsharpContext *unsharp = ctx->priv; - mask_matrix[0] = unsharp->opencl_ctx.cl_luma_mask; - mask_matrix[1] = unsharp->opencl_ctx.cl_chroma_mask; - masks[0] = unsharp->opencl_ctx.cl_luma_mask_x; - masks[1] = unsharp->opencl_ctx.cl_luma_mask_y; - masks[2] = unsharp->opencl_ctx.cl_chroma_mask_x; - masks[3] = unsharp->opencl_ctx.cl_chroma_mask_y; - step_x[0] = unsharp->luma.steps_x; - step_x[1] = unsharp->chroma.steps_x; - step_y[0] = unsharp->luma.steps_y; - step_y[1] = unsharp->chroma.steps_y; - - /* use default kernel if any matrix dim larger than 8 due to limited local mem size */ - if (step_x[0]>8 || step_x[1]>8 || step_y[0]>8 || step_y[1]>8) - unsharp->opencl_ctx.use_fast_kernels = 0; - else - unsharp->opencl_ctx.use_fast_kernels = 1; - - if (!masks[0] || !masks[1] || !masks[2] || !masks[3]) { - av_log(ctx, AV_LOG_ERROR, "Luma mask and chroma mask should not be NULL\n"); - return AVERROR(EINVAL); - } - if (!mask_matrix[0] || !mask_matrix[1]) { - av_log(ctx, AV_LOG_ERROR, "Luma mask and chroma mask should not be NULL\n"); - return AVERROR(EINVAL); - } - for (i = 0; i < 2; i++) { - ret = copy_separable_masks(masks[2*i], masks[2*i+1], step_x[i], step_y[i]); - if (ret < 0) - return ret; - } - return ret; -} - -int ff_opencl_apply_unsharp(AVFilterContext *ctx, AVFrame *in, AVFrame *out) -{ - int ret; - AVFilterLink *link = ctx->inputs[0]; - UnsharpContext *unsharp = ctx->priv; - cl_int status; - FFOpenclParam kernel1 = {0}; - FFOpenclParam kernel2 = {0}; - int width = link->w; - int height = link->h; - int cw = AV_CEIL_RSHIFT(link->w, unsharp->hsub); - int ch = AV_CEIL_RSHIFT(link->h, unsharp->vsub); - size_t globalWorkSize1d = width * height + 2 * ch * cw; - size_t globalWorkSize2dLuma[2]; - size_t globalWorkSize2dChroma[2]; - size_t localWorkSize2d[2] = {16, 16}; - - if (unsharp->opencl_ctx.use_fast_kernels) { - globalWorkSize2dLuma[0] = (size_t)ROUND_TO_16(width); - globalWorkSize2dLuma[1] = (size_t)ROUND_TO_16(height); - globalWorkSize2dChroma[0] = (size_t)ROUND_TO_16(cw); - globalWorkSize2dChroma[1] = (size_t)(2*ROUND_TO_16(ch)); - - kernel1.ctx = ctx; - kernel1.kernel = unsharp->opencl_ctx.kernel_luma; - ret = avpriv_opencl_set_parameter(&kernel1, - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_inbuf), - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_outbuf), - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_luma_mask_x), - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_luma_mask_y), - FF_OPENCL_PARAM_INFO(unsharp->luma.amount), - FF_OPENCL_PARAM_INFO(unsharp->luma.scalebits), - FF_OPENCL_PARAM_INFO(unsharp->luma.halfscale), - FF_OPENCL_PARAM_INFO(in->linesize[0]), - FF_OPENCL_PARAM_INFO(out->linesize[0]), - FF_OPENCL_PARAM_INFO(width), - FF_OPENCL_PARAM_INFO(height), - NULL); - if (ret < 0) - return ret; - - kernel2.ctx = ctx; - kernel2.kernel = unsharp->opencl_ctx.kernel_chroma; - ret = avpriv_opencl_set_parameter(&kernel2, - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_inbuf), - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_outbuf), - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_chroma_mask_x), - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_chroma_mask_y), - FF_OPENCL_PARAM_INFO(unsharp->chroma.amount), - FF_OPENCL_PARAM_INFO(unsharp->chroma.scalebits), - FF_OPENCL_PARAM_INFO(unsharp->chroma.halfscale), - FF_OPENCL_PARAM_INFO(in->linesize[0]), - FF_OPENCL_PARAM_INFO(in->linesize[1]), - FF_OPENCL_PARAM_INFO(out->linesize[0]), - FF_OPENCL_PARAM_INFO(out->linesize[1]), - FF_OPENCL_PARAM_INFO(link->w), - FF_OPENCL_PARAM_INFO(link->h), - FF_OPENCL_PARAM_INFO(cw), - FF_OPENCL_PARAM_INFO(ch), - NULL); - if (ret < 0) - return ret; - status = clEnqueueNDRangeKernel(unsharp->opencl_ctx.command_queue, - unsharp->opencl_ctx.kernel_luma, 2, NULL, - globalWorkSize2dLuma, localWorkSize2d, 0, NULL, NULL); - status |=clEnqueueNDRangeKernel(unsharp->opencl_ctx.command_queue, - unsharp->opencl_ctx.kernel_chroma, 2, NULL, - globalWorkSize2dChroma, localWorkSize2d, 0, NULL, NULL); - if (status != CL_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "OpenCL run kernel error occurred: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - } else { /* use default kernel */ - kernel1.ctx = ctx; - kernel1.kernel = unsharp->opencl_ctx.kernel_default; - - ret = avpriv_opencl_set_parameter(&kernel1, - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_inbuf), - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_outbuf), - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_luma_mask), - FF_OPENCL_PARAM_INFO(unsharp->opencl_ctx.cl_chroma_mask), - FF_OPENCL_PARAM_INFO(unsharp->luma.amount), - FF_OPENCL_PARAM_INFO(unsharp->chroma.amount), - FF_OPENCL_PARAM_INFO(unsharp->luma.steps_x), - FF_OPENCL_PARAM_INFO(unsharp->luma.steps_y), - FF_OPENCL_PARAM_INFO(unsharp->chroma.steps_x), - FF_OPENCL_PARAM_INFO(unsharp->chroma.steps_y), - FF_OPENCL_PARAM_INFO(unsharp->luma.scalebits), - FF_OPENCL_PARAM_INFO(unsharp->chroma.scalebits), - FF_OPENCL_PARAM_INFO(unsharp->luma.halfscale), - FF_OPENCL_PARAM_INFO(unsharp->chroma.halfscale), - FF_OPENCL_PARAM_INFO(in->linesize[0]), - FF_OPENCL_PARAM_INFO(in->linesize[1]), - FF_OPENCL_PARAM_INFO(out->linesize[0]), - FF_OPENCL_PARAM_INFO(out->linesize[1]), - FF_OPENCL_PARAM_INFO(link->h), - FF_OPENCL_PARAM_INFO(link->w), - FF_OPENCL_PARAM_INFO(ch), - FF_OPENCL_PARAM_INFO(cw), - NULL); - if (ret < 0) - return ret; - status = clEnqueueNDRangeKernel(unsharp->opencl_ctx.command_queue, - unsharp->opencl_ctx.kernel_default, 1, NULL, - &globalWorkSize1d, NULL, 0, NULL, NULL); - if (status != CL_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "OpenCL run kernel error occurred: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - } - //blocking map is suffficient, no need for clFinish - //clFinish(unsharp->opencl_ctx.command_queue); - - return av_opencl_buffer_read_image(out->data, unsharp->opencl_ctx.out_plane_size, - unsharp->opencl_ctx.plane_num, unsharp->opencl_ctx.cl_outbuf, - unsharp->opencl_ctx.cl_outbuf_size); -} - -int ff_opencl_unsharp_init(AVFilterContext *ctx) -{ - int ret = 0; - char build_opts[96]; - UnsharpContext *unsharp = ctx->priv; - ret = av_opencl_init(NULL); - if (ret < 0) - return ret; - ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_luma_mask, - sizeof(uint32_t) * (2 * unsharp->luma.steps_x + 1) * (2 * unsharp->luma.steps_y + 1), - CL_MEM_READ_ONLY, NULL); - if (ret < 0) - return ret; - ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_chroma_mask, - sizeof(uint32_t) * (2 * unsharp->chroma.steps_x + 1) * (2 * unsharp->chroma.steps_y + 1), - CL_MEM_READ_ONLY, NULL); - // separable filters - if (ret < 0) - return ret; - ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_luma_mask_x, - sizeof(uint32_t) * (2 * unsharp->luma.steps_x + 1), - CL_MEM_READ_ONLY, NULL); - if (ret < 0) - return ret; - ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_luma_mask_y, - sizeof(uint32_t) * (2 * unsharp->luma.steps_y + 1), - CL_MEM_READ_ONLY, NULL); - if (ret < 0) - return ret; - ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_chroma_mask_x, - sizeof(uint32_t) * (2 * unsharp->chroma.steps_x + 1), - CL_MEM_READ_ONLY, NULL); - if (ret < 0) - return ret; - ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_chroma_mask_y, - sizeof(uint32_t) * (2 * unsharp->chroma.steps_y + 1), - CL_MEM_READ_ONLY, NULL); - if (ret < 0) - return ret; - ret = generate_mask(ctx); - if (ret < 0) - return ret; - unsharp->opencl_ctx.plane_num = PLANE_NUM; - unsharp->opencl_ctx.command_queue = av_opencl_get_command_queue(); - if (!unsharp->opencl_ctx.command_queue) { - av_log(ctx, AV_LOG_ERROR, "Unable to get OpenCL command queue in filter 'unsharp'\n"); - return AVERROR(EINVAL); - } - snprintf(build_opts, 96, "-D LU_RADIUS_X=%d -D LU_RADIUS_Y=%d -D CH_RADIUS_X=%d -D CH_RADIUS_Y=%d", - 2*unsharp->luma.steps_x+1, 2*unsharp->luma.steps_y+1, 2*unsharp->chroma.steps_x+1, 2*unsharp->chroma.steps_y+1); - unsharp->opencl_ctx.program = av_opencl_compile("unsharp", build_opts); - if (!unsharp->opencl_ctx.program) { - av_log(ctx, AV_LOG_ERROR, "OpenCL failed to compile program 'unsharp'\n"); - return AVERROR(EINVAL); - } - if (unsharp->opencl_ctx.use_fast_kernels) { - if (!unsharp->opencl_ctx.kernel_luma) { - unsharp->opencl_ctx.kernel_luma = clCreateKernel(unsharp->opencl_ctx.program, "unsharp_luma", &ret); - if (ret != CL_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "OpenCL failed to create kernel 'unsharp_luma'\n"); - return ret; - } - } - if (!unsharp->opencl_ctx.kernel_chroma) { - unsharp->opencl_ctx.kernel_chroma = clCreateKernel(unsharp->opencl_ctx.program, "unsharp_chroma", &ret); - if (ret < 0) { - av_log(ctx, AV_LOG_ERROR, "OpenCL failed to create kernel 'unsharp_chroma'\n"); - return ret; - } - } - } - else { - if (!unsharp->opencl_ctx.kernel_default) { - unsharp->opencl_ctx.kernel_default = clCreateKernel(unsharp->opencl_ctx.program, "unsharp_default", &ret); - if (ret < 0) { - av_log(ctx, AV_LOG_ERROR, "OpenCL failed to create kernel 'unsharp_default'\n"); - return ret; - } - } - } - return ret; -} - -void ff_opencl_unsharp_uninit(AVFilterContext *ctx) -{ - UnsharpContext *unsharp = ctx->priv; - av_opencl_buffer_release(&unsharp->opencl_ctx.cl_inbuf); - av_opencl_buffer_release(&unsharp->opencl_ctx.cl_outbuf); - av_opencl_buffer_release(&unsharp->opencl_ctx.cl_luma_mask); - av_opencl_buffer_release(&unsharp->opencl_ctx.cl_chroma_mask); - av_opencl_buffer_release(&unsharp->opencl_ctx.cl_luma_mask_x); - av_opencl_buffer_release(&unsharp->opencl_ctx.cl_chroma_mask_x); - av_opencl_buffer_release(&unsharp->opencl_ctx.cl_luma_mask_y); - av_opencl_buffer_release(&unsharp->opencl_ctx.cl_chroma_mask_y); - clReleaseKernel(unsharp->opencl_ctx.kernel_default); - clReleaseKernel(unsharp->opencl_ctx.kernel_luma); - clReleaseKernel(unsharp->opencl_ctx.kernel_chroma); - clReleaseProgram(unsharp->opencl_ctx.program); - unsharp->opencl_ctx.command_queue = NULL; - av_opencl_uninit(); -} - -int ff_opencl_unsharp_process_inout_buf(AVFilterContext *ctx, AVFrame *in, AVFrame *out) -{ - int ret = 0; - AVFilterLink *link = ctx->inputs[0]; - UnsharpContext *unsharp = ctx->priv; - int ch = AV_CEIL_RSHIFT(link->h, unsharp->vsub); - - if ((!unsharp->opencl_ctx.cl_inbuf) || (!unsharp->opencl_ctx.cl_outbuf)) { - unsharp->opencl_ctx.in_plane_size[0] = (in->linesize[0] * in->height); - unsharp->opencl_ctx.in_plane_size[1] = (in->linesize[1] * ch); - unsharp->opencl_ctx.in_plane_size[2] = (in->linesize[2] * ch); - unsharp->opencl_ctx.out_plane_size[0] = (out->linesize[0] * out->height); - unsharp->opencl_ctx.out_plane_size[1] = (out->linesize[1] * ch); - unsharp->opencl_ctx.out_plane_size[2] = (out->linesize[2] * ch); - unsharp->opencl_ctx.cl_inbuf_size = unsharp->opencl_ctx.in_plane_size[0] + - unsharp->opencl_ctx.in_plane_size[1] + - unsharp->opencl_ctx.in_plane_size[2]; - unsharp->opencl_ctx.cl_outbuf_size = unsharp->opencl_ctx.out_plane_size[0] + - unsharp->opencl_ctx.out_plane_size[1] + - unsharp->opencl_ctx.out_plane_size[2]; - if (!unsharp->opencl_ctx.cl_inbuf) { - ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_inbuf, - unsharp->opencl_ctx.cl_inbuf_size, - CL_MEM_READ_ONLY, NULL); - if (ret < 0) - return ret; - } - if (!unsharp->opencl_ctx.cl_outbuf) { - ret = av_opencl_buffer_create(&unsharp->opencl_ctx.cl_outbuf, - unsharp->opencl_ctx.cl_outbuf_size, - CL_MEM_READ_WRITE, NULL); - if (ret < 0) - return ret; - } - } - return av_opencl_buffer_write_image(unsharp->opencl_ctx.cl_inbuf, - unsharp->opencl_ctx.cl_inbuf_size, - 0, in->data, unsharp->opencl_ctx.in_plane_size, - unsharp->opencl_ctx.plane_num); -} diff --git a/libavfilter/unsharp_opencl_kernel.h b/libavfilter/unsharp_opencl_kernel.h deleted file mode 100644 index 307d0f1814ca8..0000000000000 --- a/libavfilter/unsharp_opencl_kernel.h +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Copyright (C) 2013 Wei Gao - * Copyright (C) 2013 Lenny Wang - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVFILTER_UNSHARP_OPENCL_KERNEL_H -#define AVFILTER_UNSHARP_OPENCL_KERNEL_H - -#include "libavutil/opencl.h" - -const char *ff_kernel_unsharp_opencl = AV_OPENCL_KERNEL( -inline unsigned char clip_uint8(int a) -{ - if (a & (~0xFF)) - return (-a)>>31; - else - return a; -} - -kernel void unsharp_luma( - global unsigned char *src, - global unsigned char *dst, - global int *mask_x, - global int *mask_y, - int amount, - int scalebits, - int halfscale, - int src_stride, - int dst_stride, - int width, - int height) -{ - int2 threadIdx, blockIdx, globalIdx; - threadIdx.x = get_local_id(0); - threadIdx.y = get_local_id(1); - blockIdx.x = get_group_id(0); - blockIdx.y = get_group_id(1); - globalIdx.x = get_global_id(0); - globalIdx.y = get_global_id(1); - - if (!amount) { - if (globalIdx.x < width && globalIdx.y < height) - dst[globalIdx.x + globalIdx.y*dst_stride] = src[globalIdx.x + globalIdx.y*src_stride]; - return; - } - - local unsigned int l[32][32]; - local unsigned int lcx[LU_RADIUS_X]; - local unsigned int lcy[LU_RADIUS_Y]; - int indexIx, indexIy, i, j; - - //load up tile: actual workspace + halo of 8 points in x and y \n - for(i = 0; i <= 1; i++) { - indexIy = -8 + (blockIdx.y + i) * 16 + threadIdx.y; - indexIy = indexIy < 0 ? 0 : indexIy; - indexIy = indexIy >= height ? height - 1: indexIy; - for(j = 0; j <= 1; j++) { - indexIx = -8 + (blockIdx.x + j) * 16 + threadIdx.x; - indexIx = indexIx < 0 ? 0 : indexIx; - indexIx = indexIx >= width ? width - 1: indexIx; - l[i*16 + threadIdx.y][j*16 + threadIdx.x] = src[indexIy*src_stride + indexIx]; - } - } - - int indexL = threadIdx.y*16 + threadIdx.x; - if (indexL < LU_RADIUS_X) - lcx[indexL] = mask_x[indexL]; - if (indexL < LU_RADIUS_Y) - lcy[indexL] = mask_y[indexL]; - barrier(CLK_LOCAL_MEM_FENCE); - - //needed for unsharp mask application in the end \n - int orig_value = (int)l[threadIdx.y + 8][threadIdx.x + 8]; - - int idx, idy, maskIndex; - int temp[2] = {0}; - int steps_x = (LU_RADIUS_X-1)/2; - int steps_y = (LU_RADIUS_Y-1)/2; - - // compute the actual workspace + left&right halos \n - \n#pragma unroll\n - for (j = 0; j <=1; j++) { - //extra work to cover left and right halos \n - idx = 16*j + threadIdx.x; - \n#pragma unroll\n - for (i = -steps_y; i <= steps_y; i++) { - idy = 8 + i + threadIdx.y; - maskIndex = (i + steps_y); - temp[j] += (int)l[idy][idx] * lcy[maskIndex]; - } - } - barrier(CLK_LOCAL_MEM_FENCE); - //save results from the vertical filter in local memory \n - idy = 8 + threadIdx.y; - \n#pragma unroll\n - for (j = 0; j <=1; j++) { - idx = 16*j + threadIdx.x; - l[idy][idx] = temp[j]; - } - barrier(CLK_LOCAL_MEM_FENCE); - - //compute results with the horizontal filter \n - int sum = 0; - idy = 8 + threadIdx.y; - \n#pragma unroll\n - for (j = -steps_x; j <= steps_x; j++) { - idx = 8 + j + threadIdx.x; - maskIndex = j + steps_x; - sum += (int)l[idy][idx] * lcx[maskIndex]; - } - - int res = orig_value + (((orig_value - (int)((sum + halfscale) >> scalebits)) * amount) >> 16); - - if (globalIdx.x < width && globalIdx.y < height) - dst[globalIdx.x + globalIdx.y*dst_stride] = clip_uint8(res); -} - -kernel void unsharp_chroma( - global unsigned char *src_y, - global unsigned char *dst_y, - global int *mask_x, - global int *mask_y, - int amount, - int scalebits, - int halfscale, - int src_stride_lu, - int src_stride_ch, - int dst_stride_lu, - int dst_stride_ch, - int width, - int height, - int cw, - int ch) -{ - global unsigned char *dst_u = dst_y + height * dst_stride_lu; - global unsigned char *dst_v = dst_u + ch * dst_stride_ch; - global unsigned char *src_u = src_y + height * src_stride_lu; - global unsigned char *src_v = src_u + ch * src_stride_ch; - int2 threadIdx, blockIdx, globalIdx; - threadIdx.x = get_local_id(0); - threadIdx.y = get_local_id(1); - blockIdx.x = get_group_id(0); - blockIdx.y = get_group_id(1); - globalIdx.x = get_global_id(0); - globalIdx.y = get_global_id(1); - int padch = get_global_size(1)/2; - global unsigned char *src = globalIdx.y>=padch ? src_v : src_u; - global unsigned char *dst = globalIdx.y>=padch ? dst_v : dst_u; - - blockIdx.y = globalIdx.y>=padch ? blockIdx.y - get_num_groups(1)/2 : blockIdx.y; - globalIdx.y = globalIdx.y>=padch ? globalIdx.y - padch : globalIdx.y; - - if (!amount) { - if (globalIdx.x < cw && globalIdx.y < ch) - dst[globalIdx.x + globalIdx.y*dst_stride_ch] = src[globalIdx.x + globalIdx.y*src_stride_ch]; - return; - } - - local unsigned int l[32][32]; - local unsigned int lcx[CH_RADIUS_X]; - local unsigned int lcy[CH_RADIUS_Y]; - int indexIx, indexIy, i, j; - for(i = 0; i <= 1; i++) { - indexIy = -8 + (blockIdx.y + i) * 16 + threadIdx.y; - indexIy = indexIy < 0 ? 0 : indexIy; - indexIy = indexIy >= ch ? ch - 1: indexIy; - for(j = 0; j <= 1; j++) { - indexIx = -8 + (blockIdx.x + j) * 16 + threadIdx.x; - indexIx = indexIx < 0 ? 0 : indexIx; - indexIx = indexIx >= cw ? cw - 1: indexIx; - l[i*16 + threadIdx.y][j*16 + threadIdx.x] = src[indexIy * src_stride_ch + indexIx]; - } - } - - int indexL = threadIdx.y*16 + threadIdx.x; - if (indexL < CH_RADIUS_X) - lcx[indexL] = mask_x[indexL]; - if (indexL < CH_RADIUS_Y) - lcy[indexL] = mask_y[indexL]; - barrier(CLK_LOCAL_MEM_FENCE); - - int orig_value = (int)l[threadIdx.y + 8][threadIdx.x + 8]; - - int idx, idy, maskIndex; - int steps_x = CH_RADIUS_X/2; - int steps_y = CH_RADIUS_Y/2; - int temp[2] = {0,0}; - - \n#pragma unroll\n - for (j = 0; j <= 1; j++) { - idx = 16*j + threadIdx.x; - \n#pragma unroll\n - for (i = -steps_y; i <= steps_y; i++) { - idy = 8 + i + threadIdx.y; - maskIndex = i + steps_y; - temp[j] += (int)l[idy][idx] * lcy[maskIndex]; - } - } - - barrier(CLK_LOCAL_MEM_FENCE); - idy = 8 + threadIdx.y; - \n#pragma unroll\n - for (j = 0; j <= 1; j++) { - idx = 16*j + threadIdx.x; - l[idy][idx] = temp[j]; - } - barrier(CLK_LOCAL_MEM_FENCE); - - //compute results with the horizontal filter \n - int sum = 0; - idy = 8 + threadIdx.y; - \n#pragma unroll\n - for (j = -steps_x; j <= steps_x; j++) { - idx = 8 + j + threadIdx.x; - maskIndex = j + steps_x; - sum += (int)l[idy][idx] * lcx[maskIndex]; - } - - int res = orig_value + (((orig_value - (int)((sum + halfscale) >> scalebits)) * amount) >> 16); - - if (globalIdx.x < cw && globalIdx.y < ch) - dst[globalIdx.x + globalIdx.y*dst_stride_ch] = clip_uint8(res); -} - -kernel void unsharp_default(global unsigned char *src, - global unsigned char *dst, - const global unsigned int *mask_lu, - const global unsigned int *mask_ch, - int amount_lu, - int amount_ch, - int step_x_lu, - int step_y_lu, - int step_x_ch, - int step_y_ch, - int scalebits_lu, - int scalebits_ch, - int halfscale_lu, - int halfscale_ch, - int src_stride_lu, - int src_stride_ch, - int dst_stride_lu, - int dst_stride_ch, - int height, - int width, - int ch, - int cw) -{ - global unsigned char *dst_y = dst; - global unsigned char *dst_u = dst_y + height * dst_stride_lu; - global unsigned char *dst_v = dst_u + ch * dst_stride_ch; - - global unsigned char *src_y = src; - global unsigned char *src_u = src_y + height * src_stride_lu; - global unsigned char *src_v = src_u + ch * src_stride_ch; - - global unsigned char *temp_dst; - global unsigned char *temp_src; - const global unsigned int *temp_mask; - int global_id = get_global_id(0); - int i, j, x, y, temp_src_stride, temp_dst_stride, temp_height, temp_width, temp_steps_x, temp_steps_y, - temp_amount, temp_scalebits, temp_halfscale, sum, idx_x, idx_y, temp, res; - if (global_id < width * height) { - y = global_id / width; - x = global_id % width; - temp_dst = dst_y; - temp_src = src_y; - temp_src_stride = src_stride_lu; - temp_dst_stride = dst_stride_lu; - temp_height = height; - temp_width = width; - temp_steps_x = step_x_lu; - temp_steps_y = step_y_lu; - temp_mask = mask_lu; - temp_amount = amount_lu; - temp_scalebits = scalebits_lu; - temp_halfscale = halfscale_lu; - } else if ((global_id >= width * height) && (global_id < width * height + ch * cw)) { - y = (global_id - width * height) / cw; - x = (global_id - width * height) % cw; - temp_dst = dst_u; - temp_src = src_u; - temp_src_stride = src_stride_ch; - temp_dst_stride = dst_stride_ch; - temp_height = ch; - temp_width = cw; - temp_steps_x = step_x_ch; - temp_steps_y = step_y_ch; - temp_mask = mask_ch; - temp_amount = amount_ch; - temp_scalebits = scalebits_ch; - temp_halfscale = halfscale_ch; - } else { - y = (global_id - width * height - ch * cw) / cw; - x = (global_id - width * height - ch * cw) % cw; - temp_dst = dst_v; - temp_src = src_v; - temp_src_stride = src_stride_ch; - temp_dst_stride = dst_stride_ch; - temp_height = ch; - temp_width = cw; - temp_steps_x = step_x_ch; - temp_steps_y = step_y_ch; - temp_mask = mask_ch; - temp_amount = amount_ch; - temp_scalebits = scalebits_ch; - temp_halfscale = halfscale_ch; - } - if (temp_amount) { - sum = 0; - for (j = 0; j <= 2 * temp_steps_y; j++) { - idx_y = (y - temp_steps_y + j) <= 0 ? 0 : (y - temp_steps_y + j) >= temp_height ? temp_height-1 : y - temp_steps_y + j; - for (i = 0; i <= 2 * temp_steps_x; i++) { - idx_x = (x - temp_steps_x + i) <= 0 ? 0 : (x - temp_steps_x + i) >= temp_width ? temp_width-1 : x - temp_steps_x + i; - sum += temp_mask[i + j * (2 * temp_steps_x + 1)] * temp_src[idx_x + idx_y * temp_src_stride]; - } - } - temp = (int)temp_src[x + y * temp_src_stride]; - res = temp + (((temp - (int)((sum + temp_halfscale) >> temp_scalebits)) * temp_amount) >> 16); - temp_dst[x + y * temp_dst_stride] = clip_uint8(res); - } else { - temp_dst[x + y * temp_dst_stride] = temp_src[x + y * temp_src_stride]; - } -} -); - -#endif /* AVFILTER_UNSHARP_OPENCL_KERNEL_H */ diff --git a/libavfilter/vaapi_vpp.c b/libavfilter/vaapi_vpp.c new file mode 100644 index 0000000000000..c5bbc3b85b994 --- /dev/null +++ b/libavfilter/vaapi_vpp.c @@ -0,0 +1,373 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/avassert.h" +#include "libavutil/pixdesc.h" +#include "formats.h" +#include "internal.h" +#include "vaapi_vpp.h" + +int ff_vaapi_vpp_query_formats(AVFilterContext *avctx) +{ + enum AVPixelFormat pix_fmts[] = { + AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE, + }; + int err; + + if ((err = ff_formats_ref(ff_make_format_list(pix_fmts), + &avctx->inputs[0]->out_formats)) < 0) + return err; + if ((err = ff_formats_ref(ff_make_format_list(pix_fmts), + &avctx->outputs[0]->in_formats)) < 0) + return err; + + return 0; +} + +void ff_vaapi_vpp_pipeline_uninit(AVFilterContext *avctx) +{ + VAAPIVPPContext *ctx = avctx->priv; + int i; + for (i = 0; i < ctx->nb_filter_buffers; i++) { + if (ctx->filter_buffers[i] != VA_INVALID_ID) { + vaDestroyBuffer(ctx->hwctx->display, ctx->filter_buffers[i]); + ctx->filter_buffers[i] = VA_INVALID_ID; + } + } + ctx->nb_filter_buffers = 0; + + if (ctx->va_context != VA_INVALID_ID) { + vaDestroyContext(ctx->hwctx->display, ctx->va_context); + ctx->va_context = VA_INVALID_ID; + } + + if (ctx->va_config != VA_INVALID_ID) { + vaDestroyConfig(ctx->hwctx->display, ctx->va_config); + ctx->va_config = VA_INVALID_ID; + } + + av_buffer_unref(&ctx->device_ref); + ctx->hwctx = NULL; +} + +int ff_vaapi_vpp_config_input(AVFilterLink *inlink) +{ + AVFilterContext *avctx = inlink->dst; + VAAPIVPPContext *ctx = avctx->priv; + + if (ctx->pipeline_uninit) + ctx->pipeline_uninit(avctx); + + if (!inlink->hw_frames_ctx) { + av_log(avctx, AV_LOG_ERROR, "A hardware frames reference is " + "required to associate the processing device.\n"); + return AVERROR(EINVAL); + } + + ctx->input_frames_ref = av_buffer_ref(inlink->hw_frames_ctx); + if (!ctx->input_frames_ref) { + av_log(avctx, AV_LOG_ERROR, "A input frames reference create " + "failed.\n"); + return AVERROR(ENOMEM); + } + ctx->input_frames = (AVHWFramesContext*)ctx->input_frames_ref->data; + + return 0; +} + +int ff_vaapi_vpp_config_output(AVFilterLink *outlink) +{ + AVFilterContext *avctx = outlink->src; + VAAPIVPPContext *ctx = avctx->priv; + AVVAAPIHWConfig *hwconfig = NULL; + AVHWFramesConstraints *constraints = NULL; + AVHWFramesContext *output_frames; + AVVAAPIFramesContext *va_frames; + VAStatus vas; + int err, i; + + if (ctx->pipeline_uninit) + ctx->pipeline_uninit(avctx); + + if (!ctx->output_width) + ctx->output_width = avctx->inputs[0]->w; + if (!ctx->output_height) + ctx->output_height = avctx->inputs[0]->h; + + av_assert0(ctx->input_frames); + ctx->device_ref = av_buffer_ref(ctx->input_frames->device_ref); + if (!ctx->device_ref) { + av_log(avctx, AV_LOG_ERROR, "A device reference create " + "failed.\n"); + return AVERROR(ENOMEM); + } + ctx->hwctx = ((AVHWDeviceContext*)ctx->device_ref->data)->hwctx; + + av_assert0(ctx->va_config == VA_INVALID_ID); + vas = vaCreateConfig(ctx->hwctx->display, VAProfileNone, + VAEntrypointVideoProc, NULL, 0, &ctx->va_config); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to create processing pipeline " + "config: %d (%s).\n", vas, vaErrorStr(vas)); + err = AVERROR(EIO); + goto fail; + } + + hwconfig = av_hwdevice_hwconfig_alloc(ctx->device_ref); + if (!hwconfig) { + err = AVERROR(ENOMEM); + goto fail; + } + hwconfig->config_id = ctx->va_config; + + constraints = av_hwdevice_get_hwframe_constraints(ctx->device_ref, + hwconfig); + if (!constraints) { + err = AVERROR(ENOMEM); + goto fail; + } + + if (ctx->output_format == AV_PIX_FMT_NONE) + ctx->output_format = ctx->input_frames->sw_format; + if (constraints->valid_sw_formats) { + for (i = 0; constraints->valid_sw_formats[i] != AV_PIX_FMT_NONE; i++) { + if (ctx->output_format == constraints->valid_sw_formats[i]) + break; + } + if (constraints->valid_sw_formats[i] == AV_PIX_FMT_NONE) { + av_log(avctx, AV_LOG_ERROR, "Hardware does not support output " + "format %s.\n", av_get_pix_fmt_name(ctx->output_format)); + err = AVERROR(EINVAL); + goto fail; + } + } + + if (ctx->output_width < constraints->min_width || + ctx->output_height < constraints->min_height || + ctx->output_width > constraints->max_width || + ctx->output_height > constraints->max_height) { + av_log(avctx, AV_LOG_ERROR, "Hardware does not support scaling to " + "size %dx%d (constraints: width %d-%d height %d-%d).\n", + ctx->output_width, ctx->output_height, + constraints->min_width, constraints->max_width, + constraints->min_height, constraints->max_height); + err = AVERROR(EINVAL); + goto fail; + } + + outlink->hw_frames_ctx = av_hwframe_ctx_alloc(ctx->device_ref); + if (!outlink->hw_frames_ctx) { + av_log(avctx, AV_LOG_ERROR, "Failed to create HW frame context " + "for output.\n"); + err = AVERROR(ENOMEM); + goto fail; + } + + output_frames = (AVHWFramesContext*)outlink->hw_frames_ctx->data; + + output_frames->format = AV_PIX_FMT_VAAPI; + output_frames->sw_format = ctx->output_format; + output_frames->width = ctx->output_width; + output_frames->height = ctx->output_height; + + output_frames->initial_pool_size = 4; + + err = ff_filter_init_hw_frames(avctx, outlink, 10); + if (err < 0) + goto fail; + + err = av_hwframe_ctx_init(outlink->hw_frames_ctx); + if (err < 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to initialise VAAPI frame " + "context for output: %d\n", err); + goto fail; + } + + va_frames = output_frames->hwctx; + + av_assert0(ctx->va_context == VA_INVALID_ID); + vas = vaCreateContext(ctx->hwctx->display, ctx->va_config, + ctx->output_width, ctx->output_height, + VA_PROGRESSIVE, + va_frames->surface_ids, va_frames->nb_surfaces, + &ctx->va_context); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to create processing pipeline " + "context: %d (%s).\n", vas, vaErrorStr(vas)); + return AVERROR(EIO); + } + + outlink->w = ctx->output_width; + outlink->h = ctx->output_height; + + if (ctx->build_filter_params) { + err = ctx->build_filter_params(avctx); + if (err < 0) + goto fail; + } + + av_freep(&hwconfig); + av_hwframe_constraints_free(&constraints); + return 0; + +fail: + av_buffer_unref(&outlink->hw_frames_ctx); + av_freep(&hwconfig); + av_hwframe_constraints_free(&constraints); + return err; +} + +int ff_vaapi_vpp_colour_standard(enum AVColorSpace av_cs) +{ + switch(av_cs) { +#define CS(av, va) case AVCOL_SPC_ ## av: return VAProcColorStandard ## va; + CS(BT709, BT709); + CS(BT470BG, BT601); + CS(SMPTE170M, SMPTE170M); + CS(SMPTE240M, SMPTE240M); +#undef CS + default: + return VAProcColorStandardNone; + } +} + +int ff_vaapi_vpp_make_param_buffers(AVFilterContext *avctx, + int type, + const void *data, + size_t size, + int count) +{ + VAStatus vas; + VABufferID buffer; + VAAPIVPPContext *ctx = avctx->priv; + + av_assert0(ctx->nb_filter_buffers + 1 <= VAProcFilterCount); + + vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, + type, size, count, (void*)data, &buffer); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to create parameter " + "buffer (type %d): %d (%s).\n", + type, vas, vaErrorStr(vas)); + return AVERROR(EIO); + } + + ctx->filter_buffers[ctx->nb_filter_buffers++] = buffer; + + av_log(avctx, AV_LOG_DEBUG, "Param buffer (type %d, %zu bytes, count %d) " + "is %#x.\n", type, size, count, buffer); + return 0; +} + + +int ff_vaapi_vpp_render_picture(AVFilterContext *avctx, + VAProcPipelineParameterBuffer *params, + VASurfaceID output_surface) +{ + VABufferID params_id; + VAStatus vas; + int err = 0; + VAAPIVPPContext *ctx = avctx->priv; + + vas = vaBeginPicture(ctx->hwctx->display, + ctx->va_context, output_surface); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to attach new picture: " + "%d (%s).\n", vas, vaErrorStr(vas)); + err = AVERROR(EIO); + goto fail; + } + + vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, + VAProcPipelineParameterBufferType, + sizeof(*params), 1, params, ¶ms_id); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to create parameter buffer: " + "%d (%s).\n", vas, vaErrorStr(vas)); + err = AVERROR(EIO); + goto fail_after_begin; + } + av_log(avctx, AV_LOG_DEBUG, "Pipeline parameter buffer is %#x.\n", + params_id); + + vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context, + ¶ms_id, 1); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to render parameter buffer: " + "%d (%s).\n", vas, vaErrorStr(vas)); + err = AVERROR(EIO); + goto fail_after_begin; + } + + vas = vaEndPicture(ctx->hwctx->display, ctx->va_context); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to start picture processing: " + "%d (%s).\n", vas, vaErrorStr(vas)); + err = AVERROR(EIO); + goto fail_after_render; + } + + if (CONFIG_VAAPI_1 || ctx->hwctx->driver_quirks & + AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS) { + vas = vaDestroyBuffer(ctx->hwctx->display, params_id); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to free parameter buffer: " + "%d (%s).\n", vas, vaErrorStr(vas)); + // And ignore. + } + } + + return 0; + + // We want to make sure that if vaBeginPicture has been called, we also + // call vaRenderPicture and vaEndPicture. These calls may well fail or + // do something else nasty, but once we're in this failure case there + // isn't much else we can do. +fail_after_begin: + vaRenderPicture(ctx->hwctx->display, ctx->va_context, ¶ms_id, 1); +fail_after_render: + vaEndPicture(ctx->hwctx->display, ctx->va_context); +fail: + return err; +} + +void ff_vaapi_vpp_ctx_init(AVFilterContext *avctx) +{ + int i; + VAAPIVPPContext *ctx = avctx->priv; + + ctx->va_config = VA_INVALID_ID; + ctx->va_context = VA_INVALID_ID; + ctx->valid_ids = 1; + + for (i = 0; i < VAProcFilterCount; i++) + ctx->filter_buffers[i] = VA_INVALID_ID; + ctx->nb_filter_buffers = 0; +} + +void ff_vaapi_vpp_ctx_uninit(AVFilterContext *avctx) +{ + VAAPIVPPContext *ctx = avctx->priv; + if (ctx->valid_ids && ctx->pipeline_uninit) + ctx->pipeline_uninit(avctx); + + av_buffer_unref(&ctx->input_frames_ref); + av_buffer_unref(&ctx->device_ref); +} diff --git a/libavfilter/vaapi_vpp.h b/libavfilter/vaapi_vpp.h new file mode 100644 index 0000000000000..0bc31018d4c7a --- /dev/null +++ b/libavfilter/vaapi_vpp.h @@ -0,0 +1,79 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFILTER_VAAPI_VPP_H +#define AVFILTER_VAAPI_VPP_H + +#include +#include + +#include "libavutil/hwcontext.h" +#include "libavutil/hwcontext_vaapi.h" + +#include "avfilter.h" + +typedef struct VAAPIVPPContext { + const AVClass *class; + + AVVAAPIDeviceContext *hwctx; + AVBufferRef *device_ref; + + int valid_ids; + VAConfigID va_config; + VAContextID va_context; + + AVBufferRef *input_frames_ref; + AVHWFramesContext *input_frames; + + enum AVPixelFormat output_format; + int output_width; // computed width + int output_height; // computed height + + VABufferID filter_buffers[VAProcFilterCount]; + int nb_filter_buffers; + + int (*build_filter_params)(AVFilterContext *avctx); + + void (*pipeline_uninit)(AVFilterContext *avctx); +} VAAPIVPPContext; + +void ff_vaapi_vpp_ctx_init(AVFilterContext *avctx); + +void ff_vaapi_vpp_ctx_uninit(AVFilterContext *avctx); + +int ff_vaapi_vpp_query_formats(AVFilterContext *avctx); + +void ff_vaapi_vpp_pipeline_uninit(AVFilterContext *avctx); + +int ff_vaapi_vpp_config_input(AVFilterLink *inlink); + +int ff_vaapi_vpp_config_output(AVFilterLink *outlink); + +int ff_vaapi_vpp_colour_standard(enum AVColorSpace av_cs); + +int ff_vaapi_vpp_make_param_buffers(AVFilterContext *avctx, + int type, + const void *data, + size_t size, + int count); + +int ff_vaapi_vpp_render_picture(AVFilterContext *avctx, + VAProcPipelineParameterBuffer *params, + VASurfaceID output_surface); + +#endif /* AVFILTER_VAAPI_VPP_H */ diff --git a/libavfilter/version.h b/libavfilter/version.h index 3e67ad354c215..87468df539980 100644 --- a/libavfilter/version.h +++ b/libavfilter/version.h @@ -29,8 +29,8 @@ #include "libavutil/version.h" -#define LIBAVFILTER_VERSION_MAJOR 6 -#define LIBAVFILTER_VERSION_MINOR 107 +#define LIBAVFILTER_VERSION_MAJOR 7 +#define LIBAVFILTER_VERSION_MINOR 16 #define LIBAVFILTER_VERSION_MICRO 100 #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ @@ -49,26 +49,17 @@ * the public API and may change, break or disappear at any time. */ -#ifndef FF_API_OLD_FILTER_OPTS -#define FF_API_OLD_FILTER_OPTS (LIBAVFILTER_VERSION_MAJOR < 7) -#endif #ifndef FF_API_OLD_FILTER_OPTS_ERROR -#define FF_API_OLD_FILTER_OPTS_ERROR (LIBAVFILTER_VERSION_MAJOR < 7) -#endif -#ifndef FF_API_AVFILTER_OPEN -#define FF_API_AVFILTER_OPEN (LIBAVFILTER_VERSION_MAJOR < 7) -#endif -#ifndef FF_API_AVFILTER_INIT_FILTER -#define FF_API_AVFILTER_INIT_FILTER (LIBAVFILTER_VERSION_MAJOR < 7) +#define FF_API_OLD_FILTER_OPTS_ERROR (LIBAVFILTER_VERSION_MAJOR < 8) #endif -#ifndef FF_API_OLD_FILTER_REGISTER -#define FF_API_OLD_FILTER_REGISTER (LIBAVFILTER_VERSION_MAJOR < 7) +#ifndef FF_API_LAVR_OPTS +#define FF_API_LAVR_OPTS (LIBAVFILTER_VERSION_MAJOR < 8) #endif -#ifndef FF_API_NOCONST_GET_NAME -#define FF_API_NOCONST_GET_NAME (LIBAVFILTER_VERSION_MAJOR < 7) +#ifndef FF_API_FILTER_GET_SET +#define FF_API_FILTER_GET_SET (LIBAVFILTER_VERSION_MAJOR < 8) #endif -#ifndef FF_API_LAVR_OPTS -#define FF_API_LAVR_OPTS (LIBAVFILTER_VERSION_MAJOR < 7) +#ifndef FF_API_NEXT +#define FF_API_NEXT (LIBAVFILTER_VERSION_MAJOR < 8) #endif #endif /* AVFILTER_VERSION_H */ diff --git a/libavfilter/vf_aspect.c b/libavfilter/vf_aspect.c index bf3082485169f..c042698ef7acc 100644 --- a/libavfilter/vf_aspect.c +++ b/libavfilter/vf_aspect.c @@ -61,35 +61,9 @@ typedef struct AspectContext { AVRational dar; AVRational sar; int max; -#if FF_API_OLD_FILTER_OPTS - float aspect_den; -#endif char *ratio_expr; } AspectContext; -static av_cold int init(AVFilterContext *ctx) -{ -#if FF_API_OLD_FILTER_OPTS - AspectContext *s = ctx->priv; - int ret; - - if (s->ratio_expr && s->aspect_den > 0) { - double num; - av_log(ctx, AV_LOG_WARNING, - "num:den syntax is deprecated, please use num/den or named options instead\n"); - ret = av_expr_parse_and_eval(&num, s->ratio_expr, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, 0, ctx); - if (ret < 0) { - av_log(ctx, AV_LOG_ERROR, "Unable to parse ratio numerator \"%s\"\n", s->ratio_expr); - return AVERROR(EINVAL); - } - s->sar = s->dar = av_d2q(num / s->aspect_den, s->max); - } -#endif - - return 0; -} - static int filter_frame(AVFilterLink *link, AVFrame *frame) { AspectContext *s = link->dst->priv; @@ -151,38 +125,34 @@ static int get_aspect_ratio(AVFilterLink *inlink, AVRational *aspect_ratio) #if CONFIG_SETDAR_FILTER -static int setdar_config_props(AVFilterLink *inlink) +static int setdar_config_props(AVFilterLink *outlink) { - AspectContext *s = inlink->dst->priv; + AVFilterContext *ctx = outlink->src; + AVFilterLink *inlink = ctx->inputs[0]; + AspectContext *s = ctx->priv; AVRational dar; AVRational old_dar; AVRational old_sar = inlink->sample_aspect_ratio; int ret; -#if FF_API_OLD_FILTER_OPTS - if (!(s->ratio_expr && s->aspect_den > 0)) { -#endif if ((ret = get_aspect_ratio(inlink, &s->dar))) return ret; -#if FF_API_OLD_FILTER_OPTS - } -#endif if (s->dar.num && s->dar.den) { av_reduce(&s->sar.num, &s->sar.den, s->dar.num * inlink->h, s->dar.den * inlink->w, INT_MAX); - inlink->sample_aspect_ratio = s->sar; + outlink->sample_aspect_ratio = s->sar; dar = s->dar; } else { - inlink->sample_aspect_ratio = (AVRational){ 1, 1 }; + outlink->sample_aspect_ratio = (AVRational){ 1, 1 }; dar = (AVRational){ inlink->w, inlink->h }; } compute_dar(&old_dar, old_sar, inlink->w, inlink->h); - av_log(inlink->dst, AV_LOG_VERBOSE, "w:%d h:%d dar:%d/%d sar:%d/%d -> dar:%d/%d sar:%d/%d\n", + av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d dar:%d/%d sar:%d/%d -> dar:%d/%d sar:%d/%d\n", inlink->w, inlink->h, old_dar.num, old_dar.den, old_sar.num, old_sar.den, - dar.num, dar.den, inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den); + dar.num, dar.den, outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den); return 0; } @@ -191,9 +161,6 @@ static const AVOption setdar_options[] = { { "dar", "set display aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS }, { "ratio", "set display aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS }, { "r", "set display aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS }, -#if FF_API_OLD_FILTER_OPTS - { "dar_den", NULL, OFFSET(aspect_den), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, 0, FLT_MAX, FLAGS }, -#endif { "max", "set max value for nominator or denominator in the ratio", OFFSET(max), AV_OPT_TYPE_INT, {.i64=100}, 1, INT_MAX, FLAGS }, { NULL } }; @@ -204,7 +171,6 @@ static const AVFilterPad avfilter_vf_setdar_inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, - .config_props = setdar_config_props, .filter_frame = filter_frame, }, { NULL } @@ -214,6 +180,7 @@ static const AVFilterPad avfilter_vf_setdar_outputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, + .config_props = setdar_config_props, }, { NULL } }; @@ -221,7 +188,6 @@ static const AVFilterPad avfilter_vf_setdar_outputs[] = { AVFilter ff_vf_setdar = { .name = "setdar", .description = NULL_IF_CONFIG_SMALL("Set the frame display aspect ratio."), - .init = init, .priv_size = sizeof(AspectContext), .priv_class = &setdar_class, .inputs = avfilter_vf_setdar_inputs, @@ -232,29 +198,25 @@ AVFilter ff_vf_setdar = { #if CONFIG_SETSAR_FILTER -static int setsar_config_props(AVFilterLink *inlink) +static int setsar_config_props(AVFilterLink *outlink) { - AspectContext *s = inlink->dst->priv; + AVFilterContext *ctx = outlink->src; + AVFilterLink *inlink = ctx->inputs[0]; + AspectContext *s = ctx->priv; AVRational old_sar = inlink->sample_aspect_ratio; AVRational old_dar, dar; int ret; -#if FF_API_OLD_FILTER_OPTS - if (!(s->ratio_expr && s->aspect_den > 0)) { -#endif if ((ret = get_aspect_ratio(inlink, &s->sar))) return ret; -#if FF_API_OLD_FILTER_OPTS - } -#endif - inlink->sample_aspect_ratio = s->sar; + outlink->sample_aspect_ratio = s->sar; compute_dar(&old_dar, old_sar, inlink->w, inlink->h); compute_dar(&dar, s->sar, inlink->w, inlink->h); - av_log(inlink->dst, AV_LOG_VERBOSE, "w:%d h:%d sar:%d/%d dar:%d/%d -> sar:%d/%d dar:%d/%d\n", + av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d sar:%d/%d dar:%d/%d -> sar:%d/%d dar:%d/%d\n", inlink->w, inlink->h, old_sar.num, old_sar.den, old_dar.num, old_dar.den, - inlink->sample_aspect_ratio.num, inlink->sample_aspect_ratio.den, dar.num, dar.den); + outlink->sample_aspect_ratio.num, outlink->sample_aspect_ratio.den, dar.num, dar.den); return 0; } @@ -263,9 +225,6 @@ static const AVOption setsar_options[] = { { "sar", "set sample (pixel) aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS }, { "ratio", "set sample (pixel) aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS }, { "r", "set sample (pixel) aspect ratio", OFFSET(ratio_expr), AV_OPT_TYPE_STRING, { .str = "0" }, .flags = FLAGS }, -#if FF_API_OLD_FILTER_OPTS - { "sar_den", NULL, OFFSET(aspect_den), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, 0, FLT_MAX, FLAGS }, -#endif { "max", "set max value for nominator or denominator in the ratio", OFFSET(max), AV_OPT_TYPE_INT, {.i64=100}, 1, INT_MAX, FLAGS }, { NULL } }; @@ -276,7 +235,6 @@ static const AVFilterPad avfilter_vf_setsar_inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, - .config_props = setsar_config_props, .filter_frame = filter_frame, }, { NULL } @@ -286,6 +244,7 @@ static const AVFilterPad avfilter_vf_setsar_outputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, + .config_props = setsar_config_props, }, { NULL } }; @@ -293,7 +252,6 @@ static const AVFilterPad avfilter_vf_setsar_outputs[] = { AVFilter ff_vf_setsar = { .name = "setsar", .description = NULL_IF_CONFIG_SMALL("Set the pixel sample aspect ratio."), - .init = init, .priv_size = sizeof(AspectContext), .priv_class = &setsar_class, .inputs = avfilter_vf_setsar_inputs, diff --git a/libavfilter/vf_avgblur_opencl.c b/libavfilter/vf_avgblur_opencl.c new file mode 100644 index 0000000000000..48cebb5887039 --- /dev/null +++ b/libavfilter/vf_avgblur_opencl.c @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2018 Dylan Fernando + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/common.h" +#include "libavutil/imgutils.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "internal.h" +#include "opencl.h" +#include "opencl_source.h" +#include "video.h" + + +typedef struct AverageBlurOpenCLContext { + OpenCLFilterContext ocf; + + int initialised; + cl_kernel kernel_horiz; + cl_kernel kernel_vert; + cl_command_queue command_queue; + + int radius; + int radiusV; + int planes; + +} AverageBlurOpenCLContext; + + +static int avgblur_opencl_init(AVFilterContext *avctx) +{ + AverageBlurOpenCLContext *ctx = avctx->priv; + cl_int cle; + int err; + + err = ff_opencl_filter_load_program(avctx, &ff_opencl_source_avgblur, 1); + if (err < 0) + goto fail; + + ctx->command_queue = clCreateCommandQueue(ctx->ocf.hwctx->context, + ctx->ocf.hwctx->device_id, + 0, &cle); + if (!ctx->command_queue) { + av_log(avctx, AV_LOG_ERROR, "Failed to create OpenCL " + "command queue: %d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + + ctx->kernel_horiz = clCreateKernel(ctx->ocf.program,"avgblur_horiz", &cle); + if (!ctx->kernel_horiz) { + av_log(avctx, AV_LOG_ERROR, "Failed to create kernel: %d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + + ctx->kernel_vert = clCreateKernel(ctx->ocf.program,"avgblur_vert", &cle); + if (!ctx->kernel_vert) { + av_log(avctx, AV_LOG_ERROR, "Failed to create kernel: %d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + + if (ctx->radiusV <= 0) { + ctx->radiusV = ctx->radius; + } + + ctx->initialised = 1; + return 0; + +fail: + if (ctx->command_queue) + clReleaseCommandQueue(ctx->command_queue); + if (ctx->kernel_horiz) + clReleaseKernel(ctx->kernel_horiz); + if (ctx->kernel_vert) + clReleaseKernel(ctx->kernel_vert); + return err; +} + +static int avgblur_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) +{ + AVFilterContext *avctx = inlink->dst; + AVFilterLink *outlink = avctx->outputs[0]; + AverageBlurOpenCLContext *ctx = avctx->priv; + AVFrame *output = NULL; + AVFrame *intermediate = NULL; + cl_int cle; + size_t global_work[2]; + cl_mem src, dst, inter; + int err, p, radius_x, radius_y; + + av_log(ctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(input->format), + input->width, input->height, input->pts); + + if (!input->hw_frames_ctx) + return AVERROR(EINVAL); + + if (!ctx->initialised) { + err = avgblur_opencl_init(avctx); + if (err < 0) + goto fail; + + } + + output = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!output) { + err = AVERROR(ENOMEM); + goto fail; + } + + intermediate = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!intermediate) { + err = AVERROR(ENOMEM); + goto fail; + } + + for (p = 0; p < FF_ARRAY_ELEMS(output->data); p++) { + src = (cl_mem) input->data[p]; + dst = (cl_mem)output->data[p]; + inter = (cl_mem) intermediate->data[p]; + + if (!dst) + break; + + radius_x = ctx->radius; + radius_y = ctx->radiusV; + + if (!(ctx->planes & (1 << p))) { + radius_x = 0; + radius_y = 0; + } + + cle = clSetKernelArg(ctx->kernel_horiz, 0, sizeof(cl_mem), &inter); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "destination image argument: %d.\n", cle); + err = AVERROR_UNKNOWN; + goto fail; + } + cle = clSetKernelArg(ctx->kernel_horiz, 1, sizeof(cl_mem), &src); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "source image argument: %d.\n", cle); + err = AVERROR_UNKNOWN; + goto fail; + } + cle = clSetKernelArg(ctx->kernel_horiz, 2, sizeof(cl_int), &radius_x); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "sizeX argument: %d.\n", cle); + err = AVERROR_UNKNOWN; + goto fail; + } + + err = ff_opencl_filter_work_size_from_image(avctx, global_work, + intermediate, p, 0); + if (err < 0) + goto fail; + + av_log(avctx, AV_LOG_DEBUG, "Run kernel on plane %d " + "(%"SIZE_SPECIFIER"x%"SIZE_SPECIFIER").\n", + p, global_work[0], global_work[1]); + + cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel_horiz, 2, NULL, + global_work, NULL, + 0, NULL, NULL); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to enqueue kernel: %d.\n", + cle); + err = AVERROR(EIO); + goto fail; + } + + cle = clSetKernelArg(ctx->kernel_vert, 0, sizeof(cl_mem), &dst); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "destination image argument: %d.\n", cle); + err = AVERROR_UNKNOWN; + goto fail; + } + cle = clSetKernelArg(ctx->kernel_vert, 1, sizeof(cl_mem), &inter); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "source image argument: %d.\n", cle); + err = AVERROR_UNKNOWN; + goto fail; + } + cle = clSetKernelArg(ctx->kernel_vert, 2, sizeof(cl_int), &radius_y); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "sizeY argument: %d.\n", cle); + err = AVERROR_UNKNOWN; + goto fail; + } + + err = ff_opencl_filter_work_size_from_image(avctx, global_work, + output, p, 0); + if (err < 0) + goto fail; + + av_log(avctx, AV_LOG_DEBUG, "Run kernel on plane %d " + "(%"SIZE_SPECIFIER"x%"SIZE_SPECIFIER").\n", + p, global_work[0], global_work[1]); + + cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel_vert, 2, NULL, + global_work, NULL, + 0, NULL, NULL); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to enqueue kernel: %d.\n", + cle); + err = AVERROR(EIO); + goto fail; + } + + } + + cle = clFinish(ctx->command_queue); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to finish command queue: %d.\n", + cle); + err = AVERROR(EIO); + goto fail; + } + + err = av_frame_copy_props(output, input); + if (err < 0) + goto fail; + + av_frame_free(&input); + av_frame_free(&intermediate); + + av_log(ctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(output->format), + output->width, output->height, output->pts); + + return ff_filter_frame(outlink, output); + +fail: + clFinish(ctx->command_queue); + av_frame_free(&input); + av_frame_free(&output); + av_frame_free(&intermediate); + return err; +} + +static av_cold void avgblur_opencl_uninit(AVFilterContext *avctx) +{ + AverageBlurOpenCLContext *ctx = avctx->priv; + cl_int cle; + + + if (ctx->kernel_horiz) { + cle = clReleaseKernel(ctx->kernel_horiz); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "kernel: %d.\n", cle); + } + + if (ctx->kernel_vert) { + cle = clReleaseKernel(ctx->kernel_vert); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "kernel: %d.\n", cle); + } + + if (ctx->command_queue) { + cle = clReleaseCommandQueue(ctx->command_queue); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "command queue: %d.\n", cle); + } + + ff_opencl_filter_uninit(avctx); +} + +#define OFFSET(x) offsetof(AverageBlurOpenCLContext, x) +#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM) +static const AVOption avgblur_opencl_options[] = { + { "sizeX", "set horizontal size", OFFSET(radius), AV_OPT_TYPE_INT, {.i64=1}, 1, 1024, FLAGS }, + { "planes", "set planes to filter", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=0xF}, 0, 0xF, FLAGS }, + { "sizeY", "set vertical size", OFFSET(radiusV), AV_OPT_TYPE_INT, {.i64=0}, 0, 1024, FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(avgblur_opencl); + +static const AVFilterPad avgblur_opencl_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = &avgblur_opencl_filter_frame, + .config_props = &ff_opencl_filter_config_input, + }, + { NULL } +}; + +static const AVFilterPad avgblur_opencl_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &ff_opencl_filter_config_output, + }, + { NULL } +}; + +AVFilter ff_vf_avgblur_opencl = { + .name = "avgblur_opencl", + .description = NULL_IF_CONFIG_SMALL("Apply average blur filter"), + .priv_size = sizeof(AverageBlurOpenCLContext), + .priv_class = &avgblur_opencl_class, + .init = &ff_opencl_filter_init, + .uninit = &avgblur_opencl_uninit, + .query_formats = &ff_opencl_filter_query_formats, + .inputs = avgblur_opencl_inputs, + .outputs = avgblur_opencl_outputs, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; diff --git a/libavfilter/vf_blend.c b/libavfilter/vf_blend.c index 054c0d55d099d..70c37c75da76d 100644 --- a/libavfilter/vf_blend.c +++ b/libavfilter/vf_blend.c @@ -524,19 +524,12 @@ static int config_output(AVFilterLink *outlink) av_log(ctx, AV_LOG_ERROR, "inputs must be of same pixel format\n"); return AVERROR(EINVAL); } - if (toplink->w != bottomlink->w || - toplink->h != bottomlink->h || - toplink->sample_aspect_ratio.num != bottomlink->sample_aspect_ratio.num || - toplink->sample_aspect_ratio.den != bottomlink->sample_aspect_ratio.den) { + if (toplink->w != bottomlink->w || toplink->h != bottomlink->h) { av_log(ctx, AV_LOG_ERROR, "First input link %s parameters " - "(size %dx%d, SAR %d:%d) do not match the corresponding " - "second input link %s parameters (%dx%d, SAR %d:%d)\n", + "(size %dx%d) do not match the corresponding " + "second input link %s parameters (size %dx%d)\n", ctx->input_pads[TOP].name, toplink->w, toplink->h, - toplink->sample_aspect_ratio.num, - toplink->sample_aspect_ratio.den, - ctx->input_pads[BOTTOM].name, bottomlink->w, bottomlink->h, - bottomlink->sample_aspect_ratio.num, - bottomlink->sample_aspect_ratio.den); + ctx->input_pads[BOTTOM].name, bottomlink->w, bottomlink->h); return AVERROR(EINVAL); } } diff --git a/libavfilter/vf_convolution.c b/libavfilter/vf_convolution.c index 602031999f338..ce09e338cc5b1 100644 --- a/libavfilter/vf_convolution.c +++ b/libavfilter/vf_convolution.c @@ -48,7 +48,7 @@ typedef struct ConvolutionContext { int nb_threads; int planewidth[4]; int planeheight[4]; - int matrix[4][25]; + int matrix[4][49]; int matrix_length[4]; int copy[4]; @@ -86,6 +86,14 @@ static const int same5x5[25] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +static const int same7x7[49] = {0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0}; + static int query_formats(AVFilterContext *ctx) { static const enum AVPixelFormat pix_fmts[] = { @@ -585,6 +593,81 @@ static int filter16_5x5(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) return 0; } +static int filter16_7x7(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ConvolutionContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *in = td->in; + AVFrame *out = td->out; + const int plane = td->plane; + const int peak = (1 << s->depth) - 1; + const int stride = in->linesize[plane] / 2; + const int bstride = s->bstride; + const int height = s->planeheight[plane]; + const int width = s->planewidth[plane]; + const int slice_start = (height * jobnr) / nb_jobs; + const int slice_end = (height * (jobnr+1)) / nb_jobs; + const uint16_t *src = (const uint16_t *)in->data[plane] + slice_start * stride; + uint16_t *dst = (uint16_t *)out->data[plane] + slice_start * (out->linesize[plane] / 2); + uint16_t *p0 = (uint16_t *)s->bptrs[jobnr] + 32; + uint16_t *p1 = p0 + bstride; + uint16_t *p2 = p1 + bstride; + uint16_t *p3 = p2 + bstride; + uint16_t *p4 = p3 + bstride; + uint16_t *p5 = p4 + bstride; + uint16_t *p6 = p5 + bstride; + uint16_t *orig = p0, *end = p6; + const int *matrix = s->matrix[plane]; + float rdiv = s->rdiv[plane]; + float bias = s->bias[plane]; + int y, x, i; + + line_copy16(p0, src + 3 * stride * (slice_start < 3 ? 1 : -1), width, 3); + line_copy16(p1, src + 2 * stride * (slice_start < 2 ? 1 : -1), width, 3); + line_copy16(p2, src + stride * (slice_start == 0 ? 1 : -1), width, 3); + line_copy16(p3, src, width, 3); + src += stride; + line_copy16(p4, src, width, 3); + src += stride; + line_copy16(p5, src, width, 3); + + for (y = slice_start; y < slice_end; y++) { + uint16_t *array[] = { + p0 - 3, p0 - 2, p0 - 1, p0, p0 + 1, p0 + 2, p0 + 3, + p1 - 3, p1 - 2, p1 - 1, p1, p1 + 1, p1 + 2, p1 + 3, + p2 - 3, p2 - 2, p2 - 1, p2, p2 + 1, p2 + 2, p2 + 3, + p3 - 3, p3 - 2, p3 - 1, p3, p3 + 1, p3 + 2, p3 + 3, + p4 - 3, p4 - 2, p4 - 1, p4, p4 + 1, p4 + 2, p4 + 3, + p5 - 3, p5 - 2, p5 - 1, p5, p5 + 1, p5 + 2, p5 + 3, + p6 - 3, p6 - 2, p6 - 1, p6, p6 + 1, p6 + 2, p6 + 3, + }; + + src += stride * (y < height - 3 ? 1 : -1); + line_copy16(p6, src, width, 3); + + for (x = 0; x < width; x++) { + int sum = 0; + + for (i = 0; i < 25; i++) { + sum += *(array[i] + x) * matrix[i]; + } + sum = (int)(sum * rdiv + bias + 0.5f); + dst[x] = av_clip(sum, 0, peak); + } + + p0 = p1; + p1 = p2; + p2 = p3; + p3 = p4; + p4 = p5; + p5 = p6; + p6 = (p6 == end) ? orig: p6 + bstride; + dst += out->linesize[plane] / 2; + } + + return 0; +} + static int filter_3x3(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { ConvolutionContext *s = ctx->priv; @@ -705,6 +788,80 @@ static int filter_5x5(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) return 0; } +static int filter_7x7(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ConvolutionContext *s = ctx->priv; + ThreadData *td = arg; + AVFrame *in = td->in; + AVFrame *out = td->out; + const int plane = td->plane; + const int stride = in->linesize[plane]; + const int bstride = s->bstride; + const int height = s->planeheight[plane]; + const int width = s->planewidth[plane]; + const int slice_start = (height * jobnr) / nb_jobs; + const int slice_end = (height * (jobnr+1)) / nb_jobs; + const uint8_t *src = in->data[plane] + slice_start * stride; + uint8_t *dst = out->data[plane] + slice_start * out->linesize[plane]; + uint8_t *p0 = s->bptrs[jobnr] + 32; + uint8_t *p1 = p0 + bstride; + uint8_t *p2 = p1 + bstride; + uint8_t *p3 = p2 + bstride; + uint8_t *p4 = p3 + bstride; + uint8_t *p5 = p4 + bstride; + uint8_t *p6 = p5 + bstride; + uint8_t *orig = p0, *end = p6; + const int *matrix = s->matrix[plane]; + float rdiv = s->rdiv[plane]; + float bias = s->bias[plane]; + int y, x, i; + + line_copy8(p0, src + 3 * stride * (slice_start < 3 ? 1 : -1), width, 3); + line_copy8(p1, src + 2 * stride * (slice_start < 2 ? 1 : -1), width, 3); + line_copy8(p2, src + stride * (slice_start == 0 ? 1 : -1), width, 3); + line_copy8(p3, src, width, 3); + src += stride; + line_copy8(p4, src, width, 3); + src += stride; + line_copy8(p5, src, width, 3); + + for (y = slice_start; y < slice_end; y++) { + uint8_t *array[] = { + p0 - 3, p0 - 2, p0 - 1, p0, p0 + 1, p0 + 2, p0 + 3, + p1 - 3, p1 - 2, p1 - 1, p1, p1 + 1, p1 + 2, p1 + 3, + p2 - 3, p2 - 2, p2 - 1, p2, p2 + 1, p2 + 2, p2 + 3, + p3 - 3, p3 - 2, p3 - 1, p3, p3 + 1, p3 + 2, p3 + 3, + p4 - 3, p4 - 2, p4 - 1, p4, p4 + 1, p4 + 2, p4 + 3, + p5 - 3, p5 - 2, p5 - 1, p5, p5 + 1, p5 + 2, p5 + 3, + p6 - 3, p6 - 2, p6 - 1, p6, p6 + 1, p6 + 2, p6 + 3, + }; + + src += stride * (y < height - 3 ? 1 : -1); + line_copy8(p6, src, width, 3); + + for (x = 0; x < width; x++) { + int sum = 0; + + for (i = 0; i < 49; i++) { + sum += *(array[i] + x) * matrix[i]; + } + sum = (int)(sum * rdiv + bias + 0.5f); + dst[x] = av_clip_uint8(sum); + } + + p0 = p1; + p1 = p2; + p2 = p3; + p3 = p4; + p4 = p5; + p5 = p6; + p6 = (p6 == end) ? orig: p6 + bstride; + dst += out->linesize[plane]; + } + + return 0; +} + static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; @@ -725,14 +882,14 @@ static int config_input(AVFilterLink *inlink) if (!s->bptrs) return AVERROR(ENOMEM); - s->bstride = s->planewidth[0] + 32; + s->bstride = s->planewidth[0] + 64; s->bpc = (s->depth + 7) / 8; - s->buffer = av_malloc_array(5 * s->bstride * s->nb_threads, s->bpc); + s->buffer = av_malloc_array(7 * s->bstride * s->nb_threads, s->bpc); if (!s->buffer) return AVERROR(ENOMEM); for (p = 0; p < s->nb_threads; p++) { - s->bptrs[p] = s->buffer + 5 * s->bstride * s->bpc * p; + s->bptrs[p] = s->buffer + 7 * s->bstride * s->bpc * p; } if (!strcmp(ctx->filter->name, "convolution")) { @@ -742,6 +899,8 @@ static int config_input(AVFilterLink *inlink) s->filter[p] = filter16_3x3; else if (s->size[p] == 5) s->filter[p] = filter16_5x5; + else if (s->size[p] == 7) + s->filter[p] = filter16_7x7; } } } else if (!strcmp(ctx->filter->name, "prewitt")) { @@ -808,7 +967,7 @@ static av_cold int init(AVFilterContext *ctx) char *p, *arg, *saveptr = NULL; p = s->matrix_str[i]; - while (s->matrix_length[i] < 25) { + while (s->matrix_length[i] < 49) { if (!(arg = av_strtok(p, " ", &saveptr))) break; @@ -829,9 +988,18 @@ static av_cold int init(AVFilterContext *ctx) s->copy[i] = 1; else s->filter[i] = filter_5x5; + } else if (s->matrix_length[i] == 49) { + s->size[i] = 7; + if (!memcmp(matrix, same7x7, sizeof(same7x7))) + s->copy[i] = 1; + else + s->filter[i] = filter_7x7; } else { return AVERROR(EINVAL); } + + if (s->copy[i] && (s->rdiv[i] != 1. || s->bias[i] != 0.)) + s->copy[i] = 0; } } else if (!strcmp(ctx->filter->name, "prewitt")) { for (i = 0; i < 4; i++) { diff --git a/libavfilter/vf_convolution_opencl.c b/libavfilter/vf_convolution_opencl.c new file mode 100644 index 0000000000000..2df51e05340b0 --- /dev/null +++ b/libavfilter/vf_convolution_opencl.c @@ -0,0 +1,368 @@ +/* + * Copyright (c) 2018 Danil Iashchenko + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/common.h" +#include "libavutil/imgutils.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "libavutil/avstring.h" + + +#include "avfilter.h" +#include "internal.h" +#include "opencl.h" +#include "opencl_source.h" +#include "video.h" + +typedef struct ConvolutionOpenCLContext { + OpenCLFilterContext ocf; + + int initialised; + cl_kernel kernel; + cl_command_queue command_queue; + + char *matrix_str[4]; + + cl_mem matrix[4]; + cl_int matrix_sizes[4]; + cl_int dims[4]; + cl_float rdivs[4]; + cl_float biases[4]; + +} ConvolutionOpenCLContext; + + +static int convolution_opencl_init(AVFilterContext *avctx) +{ + ConvolutionOpenCLContext *ctx = avctx->priv; + cl_int cle; + int err; + + err = ff_opencl_filter_load_program(avctx, &ff_opencl_source_convolution, 1); + if (err < 0) + goto fail; + + ctx->command_queue = clCreateCommandQueue(ctx->ocf.hwctx->context, + ctx->ocf.hwctx->device_id, + 0, &cle); + if (!ctx->command_queue) { + av_log(avctx, AV_LOG_ERROR, "Failed to create OpenCL " + "command queue: %d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + + ctx->kernel = clCreateKernel(ctx->ocf.program, "convolution_global", &cle); + if (!ctx->kernel) { + av_log(avctx, AV_LOG_ERROR, "Failed to create kernel: %d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + + ctx->initialised = 1; + return 0; + +fail: + if (ctx->command_queue) + clReleaseCommandQueue(ctx->command_queue); + if (ctx->kernel) + clReleaseKernel(ctx->kernel); + return err; +} + + + +static int convolution_opencl_make_filter_params(AVFilterContext *avctx) +{ + ConvolutionOpenCLContext *ctx = avctx->priv; + float *matrix = NULL; + size_t matrix_bytes; + cl_mem buffer; + cl_int cle; + int i, j; + int sscanf_err; + char *p, *arg, *saveptr = NULL; + float input_matrix[4][49]; + + for (i = 0; i < 4; i++) { + ctx->biases[i] = ctx->biases[i] / 255.0; + } + + for (i = 0; i < 4; i++) { + p = ctx->matrix_str[i]; + while (ctx->matrix_sizes[i] < 49) { + arg = av_strtok(p, " ", &saveptr); + if (!arg) { + break; + } + p = NULL; + sscanf_err = sscanf(arg, "%f", &input_matrix[i][ctx->matrix_sizes[i]]); + if (sscanf_err != 1) { + av_log(ctx, AV_LOG_ERROR, "Matrix is sequence of 9, 25 or 49 signed numbers\n"); + return AVERROR(EINVAL); + } + ctx->matrix_sizes[i]++; + } + if (ctx->matrix_sizes[i] == 9) { + ctx->dims[i] = 3; + } else if (ctx->matrix_sizes[i] == 25) { + ctx->dims[i] = 5; + } else if (ctx->matrix_sizes[i] == 49) { + ctx->dims[i] = 7; + } else { + av_log(ctx, AV_LOG_ERROR, "Invalid matrix size:%d\n", ctx->matrix_sizes[i]); + return AVERROR(EINVAL); + } + + } + + for (j = 0; j < 4; j++) { + matrix_bytes = sizeof(float)*ctx->matrix_sizes[j]; + matrix = av_malloc(matrix_bytes); + if (!matrix) { + av_freep(&matrix); + return AVERROR(ENOMEM); + } + + for (i = 0; i < ctx->matrix_sizes[j]; i++) + matrix[i] = input_matrix[j][i]; + + buffer = clCreateBuffer(ctx->ocf.hwctx->context, + CL_MEM_READ_ONLY | + CL_MEM_COPY_HOST_PTR | + CL_MEM_HOST_NO_ACCESS, + matrix_bytes, matrix, &cle); + if (!buffer) { + av_log(avctx, AV_LOG_ERROR, "Failed to create matrix buffer: " + "%d.\n", cle); + av_freep(&matrix); + return AVERROR(EIO); + } + ctx->matrix[j] = buffer; + av_freep(&matrix); + } + + return 0; +} + +static int convolution_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) +{ + AVFilterContext *avctx = inlink->dst; + AVFilterLink *outlink = avctx->outputs[0]; + ConvolutionOpenCLContext *ctx = avctx->priv; + AVFrame *output = NULL; + cl_int cle; + size_t global_work[2]; + cl_mem src, dst; + int err, p; + + av_log(ctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(input->format), + input->width, input->height, input->pts); + + if (!input->hw_frames_ctx) + return AVERROR(EINVAL); + + if (!ctx->initialised) { + err = convolution_opencl_init(avctx); + if (err < 0) + goto fail; + + err = convolution_opencl_make_filter_params(avctx); + if (err < 0) + goto fail; + } + + output = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!output) { + err = AVERROR(ENOMEM); + goto fail; + } + + for (p = 0; p < FF_ARRAY_ELEMS(output->data); p++) { + src = (cl_mem) input->data[p]; + dst = (cl_mem)output->data[p]; + + if (!dst) + break; + + cle = clSetKernelArg(ctx->kernel, 0, sizeof(cl_mem), &dst); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "destination image argument: %d.\n", cle); + goto fail; + } + cle = clSetKernelArg(ctx->kernel, 1, sizeof(cl_mem), &src); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "source image argument: %d.\n", cle); + goto fail; + } + cle = clSetKernelArg(ctx->kernel, 2, sizeof(cl_int), &ctx->dims[p]); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "matrix size argument: %d.\n", cle); + goto fail; + } + cle = clSetKernelArg(ctx->kernel, 3, sizeof(cl_mem), &ctx->matrix[p]); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "matrix argument: %d.\n", cle); + goto fail; + } + cle = clSetKernelArg(ctx->kernel, 4, sizeof(cl_float), &ctx->rdivs[p]); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "rdiv argument: %d.\n", cle); + goto fail; + } + cle = clSetKernelArg(ctx->kernel, 5, sizeof(cl_float), &ctx->biases[p]); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "bias argument: %d.\n", cle); + goto fail; + } + + + err = ff_opencl_filter_work_size_from_image(avctx, global_work, output, p, 0); + if (err < 0) + goto fail; + + av_log(avctx, AV_LOG_DEBUG, "Run kernel on plane %d " + "(%"SIZE_SPECIFIER"x%"SIZE_SPECIFIER").\n", + p, global_work[0], global_work[1]); + + cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel, 2, NULL, + global_work, NULL, + 0, NULL, NULL); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to enqueue kernel: %d.\n", + cle); + err = AVERROR(EIO); + goto fail; + } + } + + cle = clFinish(ctx->command_queue); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to finish command queue: %d.\n", + cle); + err = AVERROR(EIO); + goto fail; + } + + err = av_frame_copy_props(output, input); + if (err < 0) + goto fail; + + av_frame_free(&input); + + av_log(ctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(output->format), + output->width, output->height, output->pts); + + return ff_filter_frame(outlink, output); + +fail: + clFinish(ctx->command_queue); + av_frame_free(&input); + av_frame_free(&output); + return err; +} + +static av_cold void convolution_opencl_uninit(AVFilterContext *avctx) +{ + ConvolutionOpenCLContext *ctx = avctx->priv; + cl_int cle; + int i; + + for (i = 0; i < 4; i++) { + clReleaseMemObject(ctx->matrix[i]); + } + + if (ctx->kernel) { + cle = clReleaseKernel(ctx->kernel); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "kernel: %d.\n", cle); + } + + if (ctx->command_queue) { + cle = clReleaseCommandQueue(ctx->command_queue); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "command queue: %d.\n", cle); + } + + ff_opencl_filter_uninit(avctx); +} + +#define OFFSET(x) offsetof(ConvolutionOpenCLContext, x) +#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM) +static const AVOption convolution_opencl_options[] = { + { "0m", "set matrix for 2nd plane", OFFSET(matrix_str[0]), AV_OPT_TYPE_STRING, {.str="0 0 0 0 1 0 0 0 0"}, 0, 0, FLAGS }, + { "1m", "set matrix for 2nd plane", OFFSET(matrix_str[1]), AV_OPT_TYPE_STRING, {.str="0 0 0 0 1 0 0 0 0"}, 0, 0, FLAGS }, + { "2m", "set matrix for 3rd plane", OFFSET(matrix_str[2]), AV_OPT_TYPE_STRING, {.str="0 0 0 0 1 0 0 0 0"}, 0, 0, FLAGS }, + { "3m", "set matrix for 4th plane", OFFSET(matrix_str[3]), AV_OPT_TYPE_STRING, {.str="0 0 0 0 1 0 0 0 0"}, 0, 0, FLAGS }, + { "0rdiv", "set rdiv for 1nd plane", OFFSET(rdivs[0]), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, INT_MAX, FLAGS}, + { "1rdiv", "set rdiv for 2nd plane", OFFSET(rdivs[1]), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, INT_MAX, FLAGS}, + { "2rdiv", "set rdiv for 3rd plane", OFFSET(rdivs[2]), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, INT_MAX, FLAGS}, + { "3rdiv", "set rdiv for 4th plane", OFFSET(rdivs[3]), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, INT_MAX, FLAGS}, + { "0bias", "set bias for 1st plane", OFFSET(biases[0]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS}, + { "1bias", "set bias for 2nd plane", OFFSET(biases[1]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS}, + { "2bias", "set bias for 3rd plane", OFFSET(biases[2]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS}, + { "3bias", "set bias for 4th plane", OFFSET(biases[3]), AV_OPT_TYPE_FLOAT, {.dbl=0.0}, 0.0, INT_MAX, FLAGS}, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(convolution_opencl); + +static const AVFilterPad convolution_opencl_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = &convolution_opencl_filter_frame, + .config_props = &ff_opencl_filter_config_input, + }, + { NULL } +}; + +static const AVFilterPad convolution_opencl_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &ff_opencl_filter_config_output, + }, + { NULL } +}; + +AVFilter ff_vf_convolution_opencl = { + .name = "convolution_opencl", + .description = NULL_IF_CONFIG_SMALL("Apply convolution mask to input video"), + .priv_size = sizeof(ConvolutionOpenCLContext), + .priv_class = &convolution_opencl_class, + .init = &ff_opencl_filter_init, + .uninit = &convolution_opencl_uninit, + .query_formats = &ff_opencl_filter_query_formats, + .inputs = convolution_opencl_inputs, + .outputs = convolution_opencl_outputs, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; diff --git a/libavfilter/vf_convolve.c b/libavfilter/vf_convolve.c index e00a44d63d776..982eda1cbcf03 100644 --- a/libavfilter/vf_convolve.c +++ b/libavfilter/vf_convolve.c @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "libavutil/imgutils.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" @@ -29,12 +31,14 @@ #include "internal.h" #include "video.h" +#define MAX_THREADS 16 + typedef struct ConvolveContext { const AVClass *class; FFFrameSync fs; - FFTContext *fft[4]; - FFTContext *ifft[4]; + FFTContext *fft[4][MAX_THREADS]; + FFTContext *ifft[4][MAX_THREADS]; int fft_bits[4]; int fft_len[4]; @@ -49,8 +53,11 @@ typedef struct ConvolveContext { int depth; int planes; int impulse; + float noise; int nb_planes; int got_impulse[4]; + + int (*filter)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); } ConvolveContext; #define OFFSET(x) offsetof(ConvolveContext, x) @@ -61,11 +68,10 @@ static const AVOption convolve_options[] = { { "impulse", "when to process impulses", OFFSET(impulse), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "impulse" }, { "first", "process only first impulse, ignore rest", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "impulse" }, { "all", "process all impulses", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "impulse" }, + { "noise", "set noise", OFFSET(noise), AV_OPT_TYPE_FLOAT, {.dbl=0.0000001}, 0, 1, FLAGS }, { NULL }, }; -FRAMESYNC_DEFINE_CLASS(convolve, ConvolveContext, fs); - static int query_formats(AVFilterContext *ctx) { static const enum AVPixelFormat pixel_fmts_fftfilt[] = { @@ -112,7 +118,7 @@ static int config_input_main(AVFilterLink *inlink) for (i = 0; i < s->nb_planes; i++) { int w = s->planewidth[i]; int h = s->planeheight[i]; - int n = FFMAX(w, h) * 10/9; + int n = FFMAX(w, h); for (fft_bits = 1; 1 << fft_bits < n; fft_bits++); @@ -152,106 +158,288 @@ static int config_input_impulse(AVFilterLink *inlink) return 0; } -static void fft_horizontal(ConvolveContext *s, FFTComplex *fft_hdata, - AVFrame *in, int w, int h, int n, int plane, float scale) +typedef struct ThreadData { + FFTComplex *hdata, *vdata; + int plane, n; +} ThreadData; + +static int fft_horizontal(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ConvolveContext *s = ctx->priv; + ThreadData *td = arg; + FFTComplex *hdata = td->hdata; + const int plane = td->plane; + const int n = td->n; + int start = (n * jobnr) / nb_jobs; + int end = (n * (jobnr+1)) / nb_jobs; + int y; + + for (y = start; y < end; y++) { + av_fft_permute(s->fft[plane][jobnr], hdata + y * n); + av_fft_calc(s->fft[plane][jobnr], hdata + y * n); + } + + return 0; +} + +static void get_input(ConvolveContext *s, FFTComplex *fft_hdata, + AVFrame *in, int w, int h, int n, int plane, float scale) { + const int iw = (n - w) / 2, ih = (n - h) / 2; int y, x; - for (y = 0; y < h; y++) { - if (s->depth == 8) { + if (s->depth == 8) { + for (y = 0; y < h; y++) { const uint8_t *src = in->data[plane] + in->linesize[plane] * y; for (x = 0; x < w; x++) { - fft_hdata[y * n + x].re = src[x] * scale; + fft_hdata[(y + ih) * n + iw + x].re = src[x] * scale; + fft_hdata[(y + ih) * n + iw + x].im = 0; + } + + for (x = 0; x < iw; x++) { + fft_hdata[(y + ih) * n + x].re = fft_hdata[(y + ih) * n + iw].re; + fft_hdata[(y + ih) * n + x].im = 0; + } + + for (x = n - iw; x < n; x++) { + fft_hdata[(y + ih) * n + x].re = fft_hdata[(y + ih) * n + n - iw - 1].re; + fft_hdata[(y + ih) * n + x].im = 0; + } + } + + for (y = 0; y < ih; y++) { + for (x = 0; x < n; x++) { + fft_hdata[y * n + x].re = fft_hdata[ih * n + x].re; fft_hdata[y * n + x].im = 0; } - } else { - const uint16_t *src = (const uint16_t *)(in->data[plane] + in->linesize[plane] * y); + } - for (x = 0; x < w; x++) { - fft_hdata[y * n + x].re = src[x] * scale; + for (y = n - ih; y < n; y++) { + for (x = 0; x < n; x++) { + fft_hdata[y * n + x].re = fft_hdata[(n - ih - 1) * n + x].re; fft_hdata[y * n + x].im = 0; } } - for (; x < n; x++) { - fft_hdata[y * n + x].re = 0; - fft_hdata[y * n + x].im = 0; + } else { + for (y = 0; y < h; y++) { + const uint16_t *src = (const uint16_t *)(in->data[plane] + in->linesize[plane] * y); + + for (x = 0; x < w; x++) { + fft_hdata[(y + ih) * n + iw + x].re = src[x] * scale; + fft_hdata[(y + ih) * n + iw + x].im = 0; + } + + for (x = 0; x < iw; x++) { + fft_hdata[(y + ih) * n + x].re = fft_hdata[(y + ih) * n + iw].re; + fft_hdata[(y + ih) * n + x].im = 0; + } + + for (x = n - iw; x < n; x++) { + fft_hdata[(y + ih) * n + x].re = fft_hdata[(y + ih) * n + n - iw - 1].re; + fft_hdata[(y + ih) * n + x].im = 0; + } } - } - for (; y < n; y++) { - for (x = 0; x < n; x++) { - fft_hdata[y * n + x].re = 0; - fft_hdata[y * n + x].im = 0; + for (y = 0; y < ih; y++) { + for (x = 0; x < n; x++) { + fft_hdata[y * n + x].re = fft_hdata[ih * n + x].re; + fft_hdata[y * n + x].im = 0; + } } - } - for (y = 0; y < n; y++) { - av_fft_permute(s->fft[plane], fft_hdata + y * n); - av_fft_calc(s->fft[plane], fft_hdata + y * n); + for (y = n - ih; y < n; y++) { + for (x = 0; x < n; x++) { + fft_hdata[y * n + x].re = fft_hdata[(n - ih - 1) * n + x].re; + fft_hdata[y * n + x].im = 0; + } + } } } -static void fft_vertical(ConvolveContext *s, FFTComplex *fft_hdata, FFTComplex *fft_vdata, - int n, int plane) +static int fft_vertical(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { + ConvolveContext *s = ctx->priv; + ThreadData *td = arg; + FFTComplex *hdata = td->hdata; + FFTComplex *vdata = td->vdata; + const int plane = td->plane; + const int n = td->n; + int start = (n * jobnr) / nb_jobs; + int end = (n * (jobnr+1)) / nb_jobs; int y, x; - for (y = 0; y < n; y++) { + for (y = start; y < end; y++) { for (x = 0; x < n; x++) { - fft_vdata[y * n + x].re = fft_hdata[x * n + y].re; - fft_vdata[y * n + x].im = fft_hdata[x * n + y].im; + vdata[y * n + x].re = hdata[x * n + y].re; + vdata[y * n + x].im = hdata[x * n + y].im; } - for (; x < n; x++) { - fft_vdata[y * n + x].re = 0; - fft_vdata[y * n + x].im = 0; - } - av_fft_permute(s->fft[plane], fft_vdata + y * n); - av_fft_calc(s->fft[plane], fft_vdata + y * n); + + av_fft_permute(s->fft[plane][jobnr], vdata + y * n); + av_fft_calc(s->fft[plane][jobnr], vdata + y * n); } + + return 0; } -static void ifft_vertical(ConvolveContext *s, int n, int plane) +static int ifft_vertical(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) { + ConvolveContext *s = ctx->priv; + ThreadData *td = arg; + FFTComplex *hdata = td->hdata; + FFTComplex *vdata = td->vdata; + const int plane = td->plane; + const int n = td->n; + int start = (n * jobnr) / nb_jobs; + int end = (n * (jobnr+1)) / nb_jobs; int y, x; - for (y = 0; y < n; y++) { - av_fft_permute(s->ifft[plane], s->fft_vdata[plane] + y * n); - av_fft_calc(s->ifft[plane], s->fft_vdata[plane] + y * n); + for (y = start; y < end; y++) { + av_fft_permute(s->ifft[plane][jobnr], vdata + y * n); + av_fft_calc(s->ifft[plane][jobnr], vdata + y * n); + for (x = 0; x < n; x++) { - s->fft_hdata[plane][x * n + y].re = s->fft_vdata[plane][y * n + x].re; - s->fft_hdata[plane][x * n + y].im = s->fft_vdata[plane][y * n + x].im; + hdata[x * n + y].re = vdata[y * n + x].re; + hdata[x * n + y].im = vdata[y * n + x].im; } } + + return 0; +} + +static int ifft_horizontal(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ConvolveContext *s = ctx->priv; + ThreadData *td = arg; + FFTComplex *hdata = td->hdata; + const int plane = td->plane; + const int n = td->n; + int start = (n * jobnr) / nb_jobs; + int end = (n * (jobnr+1)) / nb_jobs; + int y; + + for (y = start; y < end; y++) { + av_fft_permute(s->ifft[plane][jobnr], hdata + y * n); + av_fft_calc(s->ifft[plane][jobnr], hdata + y * n); + } + + return 0; } -static void ifft_horizontal(ConvolveContext *s, AVFrame *out, - int w, int h, int n, int plane) +static void get_output(ConvolveContext *s, FFTComplex *input, AVFrame *out, + int w, int h, int n, int plane, float scale) { - const float scale = 1.f / (n * n); const int max = (1 << s->depth) - 1; - const int oh = h / 2; - const int ow = w / 2; + const int hh = h / 2; + const int hw = w / 2; int y, x; - for (y = 0; y < n; y++) { - av_fft_permute(s->ifft[plane], s->fft_hdata[plane] + y * n); - av_fft_calc(s->ifft[plane], s->fft_hdata[plane] + y * n); - } - if (s->depth == 8) { - for (y = 0; y < h; y++) { + for (y = 0; y < hh; y++) { + uint8_t *dst = out->data[plane] + (y + hh) * out->linesize[plane] + hw; + for (x = 0; x < hw; x++) + dst[x] = av_clip_uint8(input[y * n + x].re * scale); + } + for (y = 0; y < hh; y++) { + uint8_t *dst = out->data[plane] + (y + hh) * out->linesize[plane]; + for (x = 0; x < hw; x++) + dst[x] = av_clip_uint8(input[y * n + n - hw + x].re * scale); + } + for (y = 0; y < hh; y++) { + uint8_t *dst = out->data[plane] + y * out->linesize[plane] + hw; + for (x = 0; x < hw; x++) + dst[x] = av_clip_uint8(input[(n - hh + y) * n + x].re * scale); + } + for (y = 0; y < hh; y++) { uint8_t *dst = out->data[plane] + y * out->linesize[plane]; - for (x = 0; x < w; x++) - dst[x] = av_clip_uint8(s->fft_hdata[plane][(y+oh) * n + x+ow].re * scale); + for (x = 0; x < hw; x++) + dst[x] = av_clip_uint8(input[(n - hh + y) * n + n - hw + x].re * scale); } } else { - for (y = 0; y < h; y++) { + for (y = 0; y < hh; y++) { + uint16_t *dst = (uint16_t *)(out->data[plane] + (y + hh) * out->linesize[plane] + hw * 2); + for (x = 0; x < hw; x++) + dst[x] = av_clip(input[y * n + x].re * scale, 0, max); + } + for (y = 0; y < hh; y++) { + uint16_t *dst = (uint16_t *)(out->data[plane] + (y + hh) * out->linesize[plane]); + for (x = 0; x < hw; x++) + dst[x] = av_clip(input[y * n + n - hw + x].re * scale, 0, max); + } + for (y = 0; y < hh; y++) { + uint16_t *dst = (uint16_t *)(out->data[plane] + y * out->linesize[plane] + hw * 2); + for (x = 0; x < hw; x++) + dst[x] = av_clip(input[(n - hh + y) * n + x].re * scale, 0, max); + } + for (y = 0; y < hh; y++) { uint16_t *dst = (uint16_t *)(out->data[plane] + y * out->linesize[plane]); - for (x = 0; x < w; x++) - dst[x] = av_clip(s->fft_hdata[plane][(y+oh) * n + x+ow].re * scale, 0, max); + for (x = 0; x < hw; x++) + dst[x] = av_clip(input[(n - hh + y) * n + n - hw + x].re * scale, 0, max); + } + } +} + +static int complex_multiply(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ConvolveContext *s = ctx->priv; + ThreadData *td = arg; + FFTComplex *input = td->hdata; + FFTComplex *filter = td->vdata; + const float noise = s->noise; + const int n = td->n; + int start = (n * jobnr) / nb_jobs; + int end = (n * (jobnr+1)) / nb_jobs; + int y, x; + + for (y = start; y < end; y++) { + int yn = y * n; + + for (x = 0; x < n; x++) { + FFTSample re, im, ire, iim; + + re = input[yn + x].re; + im = input[yn + x].im; + ire = filter[yn + x].re + noise; + iim = filter[yn + x].im; + + input[yn + x].re = ire * re - iim * im; + input[yn + x].im = iim * re + ire * im; + } + } + + return 0; +} + +static int complex_divide(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + ConvolveContext *s = ctx->priv; + ThreadData *td = arg; + FFTComplex *input = td->hdata; + FFTComplex *filter = td->vdata; + const float noise = s->noise; + const int n = td->n; + int start = (n * jobnr) / nb_jobs; + int end = (n * (jobnr+1)) / nb_jobs; + int y, x; + + for (y = start; y < end; y++) { + int yn = y * n; + + for (x = 0; x < n; x++) { + FFTSample re, im, ire, iim, div; + + re = input[yn + x].re; + im = input[yn + x].im; + ire = filter[yn + x].re; + iim = filter[yn + x].im; + div = ire * ire + iim * iim + noise; + + input[yn + x].re = (ire * re + iim * im) / div; + input[yn + x].im = (ire * im - iim * re) / div; } } + + return 0; } static int do_convolve(FFFrameSync *fs) @@ -269,18 +457,26 @@ static int do_convolve(FFFrameSync *fs) return ff_filter_frame(outlink, mainpic); for (plane = 0; plane < s->nb_planes; plane++) { + FFTComplex *filter = s->fft_vdata_impulse[plane]; + FFTComplex *input = s->fft_vdata[plane]; const int n = s->fft_len[plane]; const int w = s->planewidth[plane]; const int h = s->planeheight[plane]; float total = 0; + ThreadData td; if (!(s->planes & (1 << plane))) { continue; } - fft_horizontal(s, s->fft_hdata[plane], mainpic, w, h, n, plane, 1.f); - fft_vertical(s, s->fft_hdata[plane], s->fft_vdata[plane], - n, plane); + td.plane = plane, td.n = n; + get_input(s, s->fft_hdata[plane], mainpic, w, h, n, plane, 1.f); + + td.hdata = s->fft_hdata[plane]; + td.vdata = s->fft_vdata[plane]; + + ctx->internal->execute(ctx, fft_horizontal, &td, NULL, FFMIN3(MAX_THREADS, n, ff_filter_get_nb_threads(ctx))); + ctx->internal->execute(ctx, fft_vertical, &td, NULL, FFMIN3(MAX_THREADS, n, ff_filter_get_nb_threads(ctx))); if ((!s->impulse && !s->got_impulse[plane]) || s->impulse) { if (s->depth == 8) { @@ -300,29 +496,29 @@ static int do_convolve(FFFrameSync *fs) } total = FFMAX(1, total); - fft_horizontal(s, s->fft_hdata_impulse[plane], impulsepic, w, h, n, plane, 1 / total); - fft_vertical(s, s->fft_hdata_impulse[plane], s->fft_vdata_impulse[plane], - n, plane); + get_input(s, s->fft_hdata_impulse[plane], impulsepic, w, h, n, plane, 1.f / total); + + td.hdata = s->fft_hdata_impulse[plane]; + td.vdata = s->fft_vdata_impulse[plane]; + + ctx->internal->execute(ctx, fft_horizontal, &td, NULL, FFMIN3(MAX_THREADS, n, ff_filter_get_nb_threads(ctx))); + ctx->internal->execute(ctx, fft_vertical, &td, NULL, FFMIN3(MAX_THREADS, n, ff_filter_get_nb_threads(ctx))); s->got_impulse[plane] = 1; } - for (y = 0; y < n; y++) { - for (x = 0; x < n; x++) { - FFTSample re, im, ire, iim; + td.hdata = input; + td.vdata = filter; - re = s->fft_vdata[plane][y*n + x].re; - im = s->fft_vdata[plane][y*n + x].im; - ire = s->fft_vdata_impulse[plane][y*n + x].re; - iim = s->fft_vdata_impulse[plane][y*n + x].im; + ctx->internal->execute(ctx, s->filter, &td, NULL, FFMIN3(MAX_THREADS, n, ff_filter_get_nb_threads(ctx))); - s->fft_vdata[plane][y*n + x].re = ire * re - iim * im; - s->fft_vdata[plane][y*n + x].im = iim * re + ire * im; - } - } + td.hdata = s->fft_hdata[plane]; + td.vdata = s->fft_vdata[plane]; - ifft_vertical(s, n, plane); - ifft_horizontal(s, mainpic, w, h, n, plane); + ctx->internal->execute(ctx, ifft_vertical, &td, NULL, FFMIN3(MAX_THREADS, n, ff_filter_get_nb_threads(ctx))); + ctx->internal->execute(ctx, ifft_horizontal, &td, NULL, FFMIN3(MAX_THREADS, n, ff_filter_get_nb_threads(ctx))); + + get_output(s, s->fft_hdata[plane], mainpic, w, h, n, plane, 1.f / (n * n)); } return ff_filter_frame(outlink, mainpic); @@ -333,7 +529,7 @@ static int config_output(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; ConvolveContext *s = ctx->priv; AVFilterLink *mainlink = ctx->inputs[0]; - int ret, i; + int ret, i, j; s->fs.on_event = do_convolve; ret = ff_framesync_init_dualinput(&s->fs, ctx); @@ -349,10 +545,12 @@ static int config_output(AVFilterLink *outlink) return ret; for (i = 0; i < s->nb_planes; i++) { - s->fft[i] = av_fft_init(s->fft_bits[i], 0); - s->ifft[i] = av_fft_init(s->fft_bits[i], 1); - if (!s->fft[i] || !s->ifft[i]) - return AVERROR(ENOMEM); + for (j = 0; j < MAX_THREADS; j++) { + s->fft[i][j] = av_fft_init(s->fft_bits[i], 0); + s->ifft[i][j] = av_fft_init(s->fft_bits[i], 1); + if (!s->fft[i][j] || !s->ifft[i][j]) + return AVERROR(ENOMEM); + } } return 0; @@ -364,18 +562,36 @@ static int activate(AVFilterContext *ctx) return ff_framesync_activate(&s->fs); } +static av_cold int init(AVFilterContext *ctx) +{ + ConvolveContext *s = ctx->priv; + + if (!strcmp(ctx->filter->name, "convolve")) { + s->filter = complex_multiply; + } else if (!strcmp(ctx->filter->name, "deconvolve")) { + s->filter = complex_divide; + } else { + return AVERROR_BUG; + } + + return 0; +} + static av_cold void uninit(AVFilterContext *ctx) { ConvolveContext *s = ctx->priv; - int i; + int i, j; for (i = 0; i < 4; i++) { av_freep(&s->fft_hdata[i]); av_freep(&s->fft_vdata[i]); av_freep(&s->fft_hdata_impulse[i]); av_freep(&s->fft_vdata_impulse[i]); - av_fft_end(s->fft[i]); - av_fft_end(s->ifft[i]); + + for (j = 0; j < MAX_THREADS; j++) { + av_fft_end(s->fft[i][j]); + av_fft_end(s->ifft[i][j]); + } } ff_framesync_uninit(&s->fs); @@ -403,10 +619,15 @@ static const AVFilterPad convolve_outputs[] = { { NULL } }; +#if CONFIG_CONVOLVE_FILTER + +FRAMESYNC_DEFINE_CLASS(convolve, ConvolveContext, fs); + AVFilter ff_vf_convolve = { .name = "convolve", .description = NULL_IF_CONFIG_SMALL("Convolve first video stream with second video stream."), .preinit = convolve_framesync_preinit, + .init = init, .uninit = uninit, .query_formats = query_formats, .activate = activate, @@ -414,5 +635,37 @@ AVFilter ff_vf_convolve = { .priv_class = &convolve_class, .inputs = convolve_inputs, .outputs = convolve_outputs, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS, }; + +#endif /* CONFIG_CONVOLVE_FILTER */ + +#if CONFIG_DECONVOLVE_FILTER + +static const AVOption deconvolve_options[] = { + { "planes", "set planes to deconvolve", OFFSET(planes), AV_OPT_TYPE_INT, {.i64=7}, 0, 15, FLAGS }, + { "impulse", "when to process impulses", OFFSET(impulse), AV_OPT_TYPE_INT, {.i64=1}, 0, 1, FLAGS, "impulse" }, + { "first", "process only first impulse, ignore rest", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "impulse" }, + { "all", "process all impulses", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "impulse" }, + { "noise", "set noise", OFFSET(noise), AV_OPT_TYPE_FLOAT, {.dbl=0.0000001}, 0, 1, FLAGS }, + { NULL }, +}; + +FRAMESYNC_DEFINE_CLASS(deconvolve, ConvolveContext, fs); + +AVFilter ff_vf_deconvolve = { + .name = "deconvolve", + .description = NULL_IF_CONFIG_SMALL("Deconvolve first video stream with second video stream."), + .preinit = deconvolve_framesync_preinit, + .init = init, + .uninit = uninit, + .query_formats = query_formats, + .activate = activate, + .priv_size = sizeof(ConvolveContext), + .priv_class = &deconvolve_class, + .inputs = convolve_inputs, + .outputs = convolve_outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_INTERNAL | AVFILTER_FLAG_SLICE_THREADS, +}; + +#endif /* CONFIG_DECONVOLVE_FILTER */ diff --git a/libavfilter/vf_crop.c b/libavfilter/vf_crop.c index 7c31c1665d91c..84be4c7d0d240 100644 --- a/libavfilter/vf_crop.c +++ b/libavfilter/vf_crop.c @@ -262,6 +262,7 @@ static int filter_frame(AVFilterLink *link, AVFrame *frame) NAN : frame->pkt_pos; s->var_values[VAR_X] = av_expr_eval(s->x_pexpr, s->var_values, NULL); s->var_values[VAR_Y] = av_expr_eval(s->y_pexpr, s->var_values, NULL); + /* It is necessary if x is expressed from y */ s->var_values[VAR_X] = av_expr_eval(s->x_pexpr, s->var_values, NULL); normalize_double(&s->x, s->var_values[VAR_X]); @@ -287,7 +288,7 @@ static int filter_frame(AVFilterLink *link, AVFrame *frame) frame->data[0] += s->y * frame->linesize[0]; frame->data[0] += s->x * s->max_step[0]; - if (!(desc->flags & AV_PIX_FMT_FLAG_PAL || desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL)) { + if (!(desc->flags & AV_PIX_FMT_FLAG_PAL || desc->flags & FF_PSEUDOPAL)) { for (i = 1; i < 3; i ++) { if (frame->data[i]) { frame->data[i] += (s->y >> s->vsub) * frame->linesize[i]; diff --git a/libavfilter/vf_deinterlace_qsv.c b/libavfilter/vf_deinterlace_qsv.c index 2810bffe461b8..c9e76c6056a1a 100644 --- a/libavfilter/vf_deinterlace_qsv.c +++ b/libavfilter/vf_deinterlace_qsv.c @@ -35,6 +35,7 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/time.h" +#include "libavfilter/qsvvpp.h" #include "avfilter.h" #include "formats.h" @@ -68,13 +69,18 @@ typedef struct QSVDeintContext { int nb_surface_ptrs; mfxExtOpaqueSurfaceAlloc opaque_alloc; - mfxExtBuffer *ext_buffers[1]; + mfxExtVPPDeinterlacing deint_conf; + mfxExtBuffer *ext_buffers[2]; + int num_ext_buffers; QSVFrame *work_frames; int64_t last_pts; int eof; + + /* option for Deinterlacing algorithm to be used */ + int mode; } QSVDeintContext; static void qsvdeint_uninit(AVFilterContext *ctx) @@ -210,8 +216,20 @@ static int init_out_session(AVFilterContext *ctx) return AVERROR_UNKNOWN; } + if (QSV_RUNTIME_VERSION_ATLEAST(ver, 1, 25)) { + err = MFXJoinSession(device_hwctx->session, s->session); + if (err != MFX_ERR_NONE) + return AVERROR_UNKNOWN; + } + memset(&par, 0, sizeof(par)); + s->deint_conf.Header.BufferId = MFX_EXTBUFF_VPP_DEINTERLACING; + s->deint_conf.Header.BufferSz = sizeof(s->deint_conf); + s->deint_conf.Mode = s->mode; + + s->ext_buffers[s->num_ext_buffers++] = (mfxExtBuffer *)&s->deint_conf; + if (opaque) { s->surface_ptrs = av_mallocz_array(hw_frames_hwctx->nb_surfaces, sizeof(*s->surface_ptrs)); @@ -230,10 +248,7 @@ static int init_out_session(AVFilterContext *ctx) s->opaque_alloc.Header.BufferId = MFX_EXTBUFF_OPAQUE_SURFACE_ALLOCATION; s->opaque_alloc.Header.BufferSz = sizeof(s->opaque_alloc); - s->ext_buffers[0] = (mfxExtBuffer*)&s->opaque_alloc; - - par.ExtParam = s->ext_buffers; - par.NumExtParam = FF_ARRAY_ELEMS(s->ext_buffers); + s->ext_buffers[s->num_ext_buffers++] = (mfxExtBuffer *)&s->opaque_alloc; par.IOPattern = MFX_IOPATTERN_IN_OPAQUE_MEMORY | MFX_IOPATTERN_OUT_OPAQUE_MEMORY; } else { @@ -261,6 +276,9 @@ static int init_out_session(AVFilterContext *ctx) par.IOPattern = MFX_IOPATTERN_IN_VIDEO_MEMORY | MFX_IOPATTERN_OUT_VIDEO_MEMORY; } + par.ExtParam = s->ext_buffers; + par.NumExtParam = s->num_ext_buffers; + par.AsyncDepth = 1; // TODO async par.vpp.In = hw_frames_hwctx->surfaces[0].Info; @@ -529,6 +547,9 @@ static int qsvdeint_request_frame(AVFilterLink *outlink) #define OFFSET(x) offsetof(QSVDeintContext, x) #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM static const AVOption options[] = { + { "mode", "set deinterlace mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64 = MFX_DEINTERLACING_ADVANCED}, MFX_DEINTERLACING_BOB, MFX_DEINTERLACING_ADVANCED, FLAGS, "mode"}, + { "bob", "bob algorithm", 0, AV_OPT_TYPE_CONST, {.i64 = MFX_DEINTERLACING_BOB}, MFX_DEINTERLACING_BOB, MFX_DEINTERLACING_ADVANCED, FLAGS, "mode"}, + { "advanced", "Motion adaptive algorithm", 0, AV_OPT_TYPE_CONST, {.i64 = MFX_DEINTERLACING_ADVANCED}, MFX_DEINTERLACING_BOB, MFX_DEINTERLACING_ADVANCED, FLAGS, "mode"}, { NULL }, }; diff --git a/libavfilter/vf_deinterlace_vaapi.c b/libavfilter/vf_deinterlace_vaapi.c index 44c5ae7642cbd..f7a262d0c6be1 100644 --- a/libavfilter/vf_deinterlace_vaapi.c +++ b/libavfilter/vf_deinterlace_vaapi.c @@ -18,13 +18,8 @@ #include -#include -#include - #include "libavutil/avassert.h" #include "libavutil/common.h" -#include "libavutil/hwcontext.h" -#include "libavutil/hwcontext_vaapi.h" #include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" @@ -33,31 +28,17 @@ #include "formats.h" #include "internal.h" #include "video.h" +#include "vaapi_vpp.h" #define MAX_REFERENCES 8 typedef struct DeintVAAPIContext { - const AVClass *class; - - AVVAAPIDeviceContext *hwctx; - AVBufferRef *device_ref; + VAAPIVPPContext vpp_ctx; // must be the first field int mode; int field_rate; int auto_enable; - int valid_ids; - VAConfigID va_config; - VAContextID va_context; - - AVBufferRef *input_frames_ref; - AVHWFramesContext *input_frames; - - AVBufferRef *output_frames_ref; - AVHWFramesContext *output_frames; - int output_height; - int output_width; - VAProcFilterCapDeinterlacing deint_caps[VAProcDeinterlacingCount]; int nb_deint_caps; @@ -67,8 +48,6 @@ typedef struct DeintVAAPIContext { int queue_count; AVFrame *frame_queue[MAX_REFERENCES]; int extra_delay_for_timestamps; - - VABufferID filter_buffer; } DeintVAAPIContext; static const char *deint_vaapi_mode_name(int mode) @@ -85,82 +64,29 @@ static const char *deint_vaapi_mode_name(int mode) } } -static int deint_vaapi_query_formats(AVFilterContext *avctx) +static void deint_vaapi_pipeline_uninit(AVFilterContext *avctx) { - enum AVPixelFormat pix_fmts[] = { - AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE, - }; - int err; - - if ((err = ff_formats_ref(ff_make_format_list(pix_fmts), - &avctx->inputs[0]->out_formats)) < 0) - return err; - if ((err = ff_formats_ref(ff_make_format_list(pix_fmts), - &avctx->outputs[0]->in_formats)) < 0) - return err; - - return 0; -} - -static int deint_vaapi_pipeline_uninit(AVFilterContext *avctx) -{ - DeintVAAPIContext *ctx = avctx->priv; + DeintVAAPIContext *ctx = avctx->priv; int i; for (i = 0; i < ctx->queue_count; i++) av_frame_free(&ctx->frame_queue[i]); ctx->queue_count = 0; - if (ctx->filter_buffer != VA_INVALID_ID) { - vaDestroyBuffer(ctx->hwctx->display, ctx->filter_buffer); - ctx->filter_buffer = VA_INVALID_ID; - } - - if (ctx->va_context != VA_INVALID_ID) { - vaDestroyContext(ctx->hwctx->display, ctx->va_context); - ctx->va_context = VA_INVALID_ID; - } - - if (ctx->va_config != VA_INVALID_ID) { - vaDestroyConfig(ctx->hwctx->display, ctx->va_config); - ctx->va_config = VA_INVALID_ID; - } - - av_buffer_unref(&ctx->device_ref); - ctx->hwctx = NULL; - - return 0; -} - -static int deint_vaapi_config_input(AVFilterLink *inlink) -{ - AVFilterContext *avctx = inlink->dst; - DeintVAAPIContext *ctx = avctx->priv; - - deint_vaapi_pipeline_uninit(avctx); - - if (!inlink->hw_frames_ctx) { - av_log(avctx, AV_LOG_ERROR, "A hardware frames reference is " - "required to associate the processing device.\n"); - return AVERROR(EINVAL); - } - - ctx->input_frames_ref = av_buffer_ref(inlink->hw_frames_ctx); - ctx->input_frames = (AVHWFramesContext*)ctx->input_frames_ref->data; - - return 0; + ff_vaapi_vpp_pipeline_uninit(avctx); } static int deint_vaapi_build_filter_params(AVFilterContext *avctx) { - DeintVAAPIContext *ctx = avctx->priv; + VAAPIVPPContext *vpp_ctx = avctx->priv; + DeintVAAPIContext *ctx = avctx->priv; VAStatus vas; VAProcFilterParameterBufferDeinterlacing params; int i; ctx->nb_deint_caps = VAProcDeinterlacingCount; - vas = vaQueryVideoProcFilterCaps(ctx->hwctx->display, - ctx->va_context, + vas = vaQueryVideoProcFilterCaps(vpp_ctx->hwctx->display, + vpp_ctx->va_context, VAProcFilterDeinterlacing, &ctx->deint_caps, &ctx->nb_deint_caps); @@ -194,20 +120,17 @@ static int deint_vaapi_build_filter_params(AVFilterContext *avctx) params.algorithm = ctx->mode; params.flags = 0; - av_assert0(ctx->filter_buffer == VA_INVALID_ID); - vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, - VAProcFilterParameterBufferType, - sizeof(params), 1, ¶ms, - &ctx->filter_buffer); - if (vas != VA_STATUS_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to create deinterlace " - "parameter buffer: %d (%s).\n", vas, vaErrorStr(vas)); - return AVERROR(EIO); - } - - vas = vaQueryVideoProcPipelineCaps(ctx->hwctx->display, - ctx->va_context, - &ctx->filter_buffer, 1, + vas = ff_vaapi_vpp_make_param_buffers(avctx, + VAProcFilterParameterBufferType, + ¶ms, + sizeof(params), + 1); + if (vas) + return vas; + + vas = vaQueryVideoProcPipelineCaps(vpp_ctx->hwctx->display, + vpp_ctx->va_context, + &vpp_ctx->filter_buffers[0], 1, &ctx->pipeline_caps); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to query pipeline " @@ -234,159 +157,35 @@ static int deint_vaapi_build_filter_params(AVFilterContext *avctx) static int deint_vaapi_config_output(AVFilterLink *outlink) { - AVFilterContext *avctx = outlink->src; - AVFilterLink *inlink = avctx->inputs[0]; - DeintVAAPIContext *ctx = avctx->priv; - AVVAAPIHWConfig *hwconfig = NULL; - AVHWFramesConstraints *constraints = NULL; - AVVAAPIFramesContext *va_frames; - VAStatus vas; + AVFilterLink *inlink = outlink->src->inputs[0]; + AVFilterContext *avctx = outlink->src; + DeintVAAPIContext *ctx = avctx->priv; int err; - deint_vaapi_pipeline_uninit(avctx); - - av_assert0(ctx->input_frames); - ctx->device_ref = av_buffer_ref(ctx->input_frames->device_ref); - ctx->hwctx = ((AVHWDeviceContext*)ctx->device_ref->data)->hwctx; - - ctx->output_width = ctx->input_frames->width; - ctx->output_height = ctx->input_frames->height; - - av_assert0(ctx->va_config == VA_INVALID_ID); - vas = vaCreateConfig(ctx->hwctx->display, VAProfileNone, - VAEntrypointVideoProc, 0, 0, &ctx->va_config); - if (vas != VA_STATUS_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to create processing pipeline " - "config: %d (%s).\n", vas, vaErrorStr(vas)); - err = AVERROR(EIO); - goto fail; - } - - hwconfig = av_hwdevice_hwconfig_alloc(ctx->device_ref); - if (!hwconfig) { - err = AVERROR(ENOMEM); - goto fail; - } - hwconfig->config_id = ctx->va_config; - - constraints = av_hwdevice_get_hwframe_constraints(ctx->device_ref, - hwconfig); - if (!constraints) { - err = AVERROR(ENOMEM); - goto fail; - } - - if (ctx->output_width < constraints->min_width || - ctx->output_height < constraints->min_height || - ctx->output_width > constraints->max_width || - ctx->output_height > constraints->max_height) { - av_log(avctx, AV_LOG_ERROR, "Hardware does not support " - "deinterlacing to size %dx%d " - "(constraints: width %d-%d height %d-%d).\n", - ctx->output_width, ctx->output_height, - constraints->min_width, constraints->max_width, - constraints->min_height, constraints->max_height); - err = AVERROR(EINVAL); - goto fail; - } - - ctx->output_frames_ref = av_hwframe_ctx_alloc(ctx->device_ref); - if (!ctx->output_frames_ref) { - av_log(avctx, AV_LOG_ERROR, "Failed to create HW frame context " - "for output.\n"); - err = AVERROR(ENOMEM); - goto fail; - } - - ctx->output_frames = (AVHWFramesContext*)ctx->output_frames_ref->data; - - ctx->output_frames->format = AV_PIX_FMT_VAAPI; - ctx->output_frames->sw_format = ctx->input_frames->sw_format; - ctx->output_frames->width = ctx->output_width; - ctx->output_frames->height = ctx->output_height; - - // The number of output frames we need is determined by what follows - // the filter. If it's an encoder with complex frame reference - // structures then this could be very high. - ctx->output_frames->initial_pool_size = 10; - - err = av_hwframe_ctx_init(ctx->output_frames_ref); - if (err < 0) { - av_log(avctx, AV_LOG_ERROR, "Failed to initialise VAAPI frame " - "context for output: %d\n", err); - goto fail; - } - - va_frames = ctx->output_frames->hwctx; - - av_assert0(ctx->va_context == VA_INVALID_ID); - vas = vaCreateContext(ctx->hwctx->display, ctx->va_config, - ctx->output_width, ctx->output_height, 0, - va_frames->surface_ids, va_frames->nb_surfaces, - &ctx->va_context); - if (vas != VA_STATUS_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to create processing pipeline " - "context: %d (%s).\n", vas, vaErrorStr(vas)); - err = AVERROR(EIO); - goto fail; - } - - err = deint_vaapi_build_filter_params(avctx); + err = ff_vaapi_vpp_config_output(outlink); if (err < 0) - goto fail; - - outlink->w = inlink->w; - outlink->h = inlink->h; - + return err; outlink->time_base = av_mul_q(inlink->time_base, (AVRational) { 1, ctx->field_rate }); outlink->frame_rate = av_mul_q(inlink->frame_rate, (AVRational) { ctx->field_rate, 1 }); - outlink->hw_frames_ctx = av_buffer_ref(ctx->output_frames_ref); - if (!outlink->hw_frames_ctx) { - err = AVERROR(ENOMEM); - goto fail; - } - - av_freep(&hwconfig); - av_hwframe_constraints_free(&constraints); return 0; - -fail: - av_buffer_unref(&ctx->output_frames_ref); - av_freep(&hwconfig); - av_hwframe_constraints_free(&constraints); - return err; -} - -static int vaapi_proc_colour_standard(enum AVColorSpace av_cs) -{ - switch(av_cs) { -#define CS(av, va) case AVCOL_SPC_ ## av: return VAProcColorStandard ## va; - CS(BT709, BT709); - CS(BT470BG, BT470BG); - CS(SMPTE170M, SMPTE170M); - CS(SMPTE240M, SMPTE240M); -#undef CS - default: - return VAProcColorStandardNone; - } } static int deint_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) { AVFilterContext *avctx = inlink->dst; AVFilterLink *outlink = avctx->outputs[0]; - DeintVAAPIContext *ctx = avctx->priv; - AVFrame *output_frame = NULL; + VAAPIVPPContext *vpp_ctx = avctx->priv; + DeintVAAPIContext *ctx = avctx->priv; + AVFrame *output_frame = NULL; VASurfaceID input_surface, output_surface; VASurfaceID backward_references[MAX_REFERENCES]; VASurfaceID forward_references[MAX_REFERENCES]; VAProcPipelineParameterBuffer params; VAProcFilterParameterBufferDeinterlacing *filter_params; VARectangle input_region; - VABufferID params_id; VAStatus vas; void *filter_params_addr = NULL; int err, i, field, current_frame_index; @@ -431,8 +230,8 @@ static int deint_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) av_log(avctx, AV_LOG_DEBUG, "\n"); for (field = 0; field < ctx->field_rate; field++) { - output_frame = ff_get_video_buffer(outlink, ctx->output_width, - ctx->output_height); + output_frame = ff_get_video_buffer(outlink, vpp_ctx->output_width, + vpp_ctx->output_height); if (!output_frame) { err = AVERROR(ENOMEM); goto fail; @@ -454,7 +253,7 @@ static int deint_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) params.surface = input_surface; params.surface_region = &input_region; params.surface_color_standard = - vaapi_proc_colour_standard(input_frame->colorspace); + ff_vaapi_vpp_colour_standard(input_frame->colorspace); params.output_region = NULL; params.output_background_color = 0xff000000; @@ -464,7 +263,7 @@ static int deint_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) params.filter_flags = VA_FRAME_PICTURE; if (!ctx->auto_enable || input_frame->interlaced_frame) { - vas = vaMapBuffer(ctx->hwctx->display, ctx->filter_buffer, + vas = vaMapBuffer(vpp_ctx->hwctx->display, vpp_ctx->filter_buffers[0], &filter_params_addr); if (vas != VA_STATUS_SUCCESS) { av_log(avctx, AV_LOG_ERROR, "Failed to map filter parameter " @@ -481,12 +280,12 @@ static int deint_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) filter_params->flags |= field ? 0 : VA_DEINTERLACING_BOTTOM_FIELD; } filter_params_addr = NULL; - vas = vaUnmapBuffer(ctx->hwctx->display, ctx->filter_buffer); + vas = vaUnmapBuffer(vpp_ctx->hwctx->display, vpp_ctx->filter_buffers[0]); if (vas != VA_STATUS_SUCCESS) av_log(avctx, AV_LOG_ERROR, "Failed to unmap filter parameter " "buffer: %d (%s).\n", vas, vaErrorStr(vas)); - params.filters = &ctx->filter_buffer; + params.filters = &vpp_ctx->filter_buffers[0]; params.num_filters = 1; params.forward_references = forward_references; @@ -501,53 +300,9 @@ static int deint_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) params.num_filters = 0; } - vas = vaBeginPicture(ctx->hwctx->display, - ctx->va_context, output_surface); - if (vas != VA_STATUS_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to attach new picture: " - "%d (%s).\n", vas, vaErrorStr(vas)); - err = AVERROR(EIO); + err = ff_vaapi_vpp_render_picture(avctx, ¶ms, output_surface); + if (err < 0) goto fail; - } - - vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, - VAProcPipelineParameterBufferType, - sizeof(params), 1, ¶ms, ¶ms_id); - if (vas != VA_STATUS_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to create parameter buffer: " - "%d (%s).\n", vas, vaErrorStr(vas)); - err = AVERROR(EIO); - goto fail_after_begin; - } - av_log(avctx, AV_LOG_DEBUG, "Pipeline parameter buffer is %#x.\n", - params_id); - - vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context, - ¶ms_id, 1); - if (vas != VA_STATUS_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to render parameter buffer: " - "%d (%s).\n", vas, vaErrorStr(vas)); - err = AVERROR(EIO); - goto fail_after_begin; - } - - vas = vaEndPicture(ctx->hwctx->display, ctx->va_context); - if (vas != VA_STATUS_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to start picture processing: " - "%d (%s).\n", vas, vaErrorStr(vas)); - err = AVERROR(EIO); - goto fail_after_render; - } - - if (CONFIG_VAAPI_1 || ctx->hwctx->driver_quirks & - AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS) { - vas = vaDestroyBuffer(ctx->hwctx->display, params_id); - if (vas != VA_STATUS_SUCCESS) { - av_log(avctx, AV_LOG_ERROR, "Failed to free parameter buffer: " - "%d (%s).\n", vas, vaErrorStr(vas)); - // And ignore. - } - } err = av_frame_copy_props(output_frame, input_frame); if (err < 0) @@ -573,41 +328,25 @@ static int deint_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) return err; -fail_after_begin: - vaRenderPicture(ctx->hwctx->display, ctx->va_context, ¶ms_id, 1); -fail_after_render: - vaEndPicture(ctx->hwctx->display, ctx->va_context); fail: if (filter_params_addr) - vaUnmapBuffer(ctx->hwctx->display, ctx->filter_buffer); + vaUnmapBuffer(vpp_ctx->hwctx->display, vpp_ctx->filter_buffers[0]); av_frame_free(&output_frame); return err; } static av_cold int deint_vaapi_init(AVFilterContext *avctx) { - DeintVAAPIContext *ctx = avctx->priv; + VAAPIVPPContext *vpp_ctx = avctx->priv; - ctx->va_config = VA_INVALID_ID; - ctx->va_context = VA_INVALID_ID; - ctx->filter_buffer = VA_INVALID_ID; - ctx->valid_ids = 1; + ff_vaapi_vpp_ctx_init(avctx); + vpp_ctx->pipeline_uninit = deint_vaapi_pipeline_uninit; + vpp_ctx->build_filter_params = deint_vaapi_build_filter_params; + vpp_ctx->output_format = AV_PIX_FMT_NONE; return 0; } -static av_cold void deint_vaapi_uninit(AVFilterContext *avctx) -{ - DeintVAAPIContext *ctx = avctx->priv; - - if (ctx->valid_ids) - deint_vaapi_pipeline_uninit(avctx); - - av_buffer_unref(&ctx->input_frames_ref); - av_buffer_unref(&ctx->output_frames_ref); - av_buffer_unref(&ctx->device_ref); -} - #define OFFSET(x) offsetof(DeintVAAPIContext, x) #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM) static const AVOption deint_vaapi_options[] = { @@ -615,22 +354,22 @@ static const AVOption deint_vaapi_options[] = { OFFSET(mode), AV_OPT_TYPE_INT, { .i64 = VAProcDeinterlacingNone }, VAProcDeinterlacingNone, VAProcDeinterlacingCount - 1, FLAGS, "mode" }, { "default", "Use the highest-numbered (and therefore possibly most advanced) deinterlacing algorithm", - 0, AV_OPT_TYPE_CONST, { .i64 = VAProcDeinterlacingNone }, .unit = "mode" }, + 0, AV_OPT_TYPE_CONST, { .i64 = VAProcDeinterlacingNone }, 0, 0, FLAGS, "mode" }, { "bob", "Use the bob deinterlacing algorithm", - 0, AV_OPT_TYPE_CONST, { .i64 = VAProcDeinterlacingBob }, .unit = "mode" }, + 0, AV_OPT_TYPE_CONST, { .i64 = VAProcDeinterlacingBob }, 0, 0, FLAGS, "mode" }, { "weave", "Use the weave deinterlacing algorithm", - 0, AV_OPT_TYPE_CONST, { .i64 = VAProcDeinterlacingWeave }, .unit = "mode" }, + 0, AV_OPT_TYPE_CONST, { .i64 = VAProcDeinterlacingWeave }, 0, 0, FLAGS, "mode" }, { "motion_adaptive", "Use the motion adaptive deinterlacing algorithm", - 0, AV_OPT_TYPE_CONST, { .i64 = VAProcDeinterlacingMotionAdaptive }, .unit = "mode" }, + 0, AV_OPT_TYPE_CONST, { .i64 = VAProcDeinterlacingMotionAdaptive }, 0, 0, FLAGS, "mode" }, { "motion_compensated", "Use the motion compensated deinterlacing algorithm", - 0, AV_OPT_TYPE_CONST, { .i64 = VAProcDeinterlacingMotionCompensated }, .unit = "mode" }, + 0, AV_OPT_TYPE_CONST, { .i64 = VAProcDeinterlacingMotionCompensated }, 0, 0, FLAGS, "mode" }, { "rate", "Generate output at frame rate or field rate", OFFSET(field_rate), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 2, FLAGS, "rate" }, { "frame", "Output at frame rate (one frame of output for each field-pair)", - 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, .unit = "rate" }, + 0, AV_OPT_TYPE_CONST, { .i64 = 1 }, 0, 0, FLAGS, "rate" }, { "field", "Output at field rate (one frame of output for each field)", - 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, .unit = "rate" }, + 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, 0, 0, FLAGS, "rate" }, { "auto", "Only deinterlace fields, passing frames through unchanged", OFFSET(auto_enable), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, FLAGS }, @@ -650,7 +389,7 @@ static const AVFilterPad deint_vaapi_inputs[] = { .name = "default", .type = AVMEDIA_TYPE_VIDEO, .filter_frame = &deint_vaapi_filter_frame, - .config_props = &deint_vaapi_config_input, + .config_props = &ff_vaapi_vpp_config_input, }, { NULL } }; @@ -669,8 +408,8 @@ AVFilter ff_vf_deinterlace_vaapi = { .description = NULL_IF_CONFIG_SMALL("Deinterlacing of VAAPI surfaces"), .priv_size = sizeof(DeintVAAPIContext), .init = &deint_vaapi_init, - .uninit = &deint_vaapi_uninit, - .query_formats = &deint_vaapi_query_formats, + .uninit = &ff_vaapi_vpp_ctx_uninit, + .query_formats = &ff_vaapi_vpp_query_formats, .inputs = deint_vaapi_inputs, .outputs = deint_vaapi_outputs, .priv_class = &deint_vaapi_class, diff --git a/libavfilter/vf_deshake.c b/libavfilter/vf_deshake.c index 64b48c6d02fde..55ce5e18a1cdc 100644 --- a/libavfilter/vf_deshake.c +++ b/libavfilter/vf_deshake.c @@ -60,7 +60,6 @@ #include "libavutil/qsort.h" #include "deshake.h" -#include "deshake_opencl.h" #define OFFSET(x) offsetof(DeshakeContext, x) #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM @@ -83,7 +82,7 @@ static const AVOption deshake_options[] = { { "exhaustive", "exhaustive search", 0, AV_OPT_TYPE_CONST, {.i64=EXHAUSTIVE}, INT_MIN, INT_MAX, FLAGS, "smode" }, { "less", "less exhaustive search", 0, AV_OPT_TYPE_CONST, {.i64=SMART_EXHAUSTIVE}, INT_MIN, INT_MAX, FLAGS, "smode" }, { "filename", "set motion search detailed log file name", OFFSET(filename), AV_OPT_TYPE_STRING, {.str=NULL}, .flags = FLAGS }, - { "opencl", "use OpenCL filtering capabilities", OFFSET(opencl), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, .flags = FLAGS }, + { "opencl", "ignored", OFFSET(opencl), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, .flags = FLAGS }, { NULL } }; @@ -341,13 +340,8 @@ static int deshake_transform_c(AVFilterContext *ctx, static av_cold int init(AVFilterContext *ctx) { - int ret; DeshakeContext *deshake = ctx->priv; - deshake->sad = av_pixelutils_get_sad_fn(4, 4, 1, deshake); // 16x16, 2nd source unaligned - if (!deshake->sad) - return AVERROR(EINVAL); - deshake->refcount = 20; // XXX: add to options? deshake->blocksize /= 2; deshake->blocksize = av_clip(deshake->blocksize, 4, 128); @@ -369,17 +363,7 @@ static av_cold int init(AVFilterContext *ctx) deshake->cx &= ~15; } deshake->transform = deshake_transform_c; - if (!CONFIG_OPENCL && deshake->opencl) { - av_log(ctx, AV_LOG_ERROR, "OpenCL support was not enabled in this build, cannot be selected\n"); - return AVERROR(EINVAL); - } - if (CONFIG_OPENCL && deshake->opencl) { - deshake->transform = ff_opencl_transform; - ret = ff_opencl_deshake_init(ctx); - if (ret < 0) - return ret; - } av_log(ctx, AV_LOG_VERBOSE, "cx: %d, cy: %d, cw: %d, ch: %d, rx: %d, ry: %d, edge: %d blocksize: %d contrast: %d search: %d\n", deshake->cx, deshake->cy, deshake->cw, deshake->ch, deshake->rx, deshake->ry, deshake->edge, deshake->blocksize * 2, deshake->contrast, deshake->search); @@ -416,9 +400,6 @@ static int config_props(AVFilterLink *link) static av_cold void uninit(AVFilterContext *ctx) { DeshakeContext *deshake = ctx->priv; - if (CONFIG_OPENCL && deshake->opencl) { - ff_opencl_deshake_uninit(ctx); - } av_frame_free(&deshake->ref); av_freep(&deshake->angles); deshake->angles_size = 0; @@ -439,6 +420,7 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(link->format); const int chroma_width = AV_CEIL_RSHIFT(link->w, desc->log2_chroma_w); const int chroma_height = AV_CEIL_RSHIFT(link->h, desc->log2_chroma_h); + int aligned; out = ff_get_video_buffer(outlink, outlink->w, outlink->h); if (!out) { @@ -447,11 +429,10 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) } av_frame_copy_props(out, in); - if (CONFIG_OPENCL && deshake->opencl) { - ret = ff_opencl_deshake_process_inout_buf(link->dst,in, out); - if (ret < 0) - goto fail; - } + aligned = !((intptr_t)in->data[0] & 15 | in->linesize[0] & 15); + deshake->sad = av_pixelutils_get_sad_fn(4, 4, aligned, deshake); // 16x16, 2nd source unaligned + if (!deshake->sad) + return AVERROR(EINVAL); if (deshake->cx < 0 || deshake->cy < 0 || deshake->cw < 0 || deshake->ch < 0) { // Find the most likely global motion for the current frame diff --git a/libavfilter/vf_drawbox.c b/libavfilter/vf_drawbox.c index 88bb9ae5c0105..c9cb63dbd1344 100644 --- a/libavfilter/vf_drawbox.c +++ b/libavfilter/vf_drawbox.c @@ -47,7 +47,7 @@ static const char *const var_names[] = { "h", ///< height of the rendered box "w", ///< width of the rendered box "t", - "max", + "fill", NULL }; @@ -80,6 +80,7 @@ typedef struct DrawBoxContext { char *w_expr, *h_expr; ///< expression for width and height char *t_expr; ///< expression for thickness int have_alpha; + int replace; } DrawBoxContext; static const int NUM_EXPR_EVALS = 5; @@ -213,7 +214,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) int plane, x, y, xb = s->x, yb = s->y; unsigned char *row[4]; - if (s->have_alpha) { + if (s->have_alpha && s->replace) { for (y = FFMAX(yb, 0); y < frame->height && y < (yb + s->h); y++) { row[0] = frame->data[0] + y * frame->linesize[0]; row[3] = frame->data[3] + y * frame->linesize[3]; @@ -286,6 +287,7 @@ static const AVOption drawbox_options[] = { { "c", "set color of the box", OFFSET(color_str), AV_OPT_TYPE_STRING, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS }, { "thickness", "set the box thickness", OFFSET(t_expr), AV_OPT_TYPE_STRING, { .str="3" }, CHAR_MIN, CHAR_MAX, FLAGS }, { "t", "set the box thickness", OFFSET(t_expr), AV_OPT_TYPE_STRING, { .str="3" }, CHAR_MIN, CHAR_MAX, FLAGS }, + { "replace", "replace color & alpha", OFFSET(replace), AV_OPT_TYPE_BOOL, { .i64=0 }, 0, 1, FLAGS }, { NULL } }; @@ -354,7 +356,7 @@ static int drawgrid_filter_frame(AVFilterLink *inlink, AVFrame *frame) int plane, x, y; uint8_t *row[4]; - if (drawgrid->have_alpha) { + if (drawgrid->have_alpha && drawgrid->replace) { for (y = 0; y < frame->height; y++) { row[0] = frame->data[0] + y * frame->linesize[0]; row[3] = frame->data[3] + y * frame->linesize[3]; @@ -418,6 +420,7 @@ static const AVOption drawgrid_options[] = { { "c", "set color of the grid", OFFSET(color_str), AV_OPT_TYPE_STRING, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS }, { "thickness", "set grid line thickness", OFFSET(t_expr), AV_OPT_TYPE_STRING, {.str="1"}, CHAR_MIN, CHAR_MAX, FLAGS }, { "t", "set grid line thickness", OFFSET(t_expr), AV_OPT_TYPE_STRING, {.str="1"}, CHAR_MIN, CHAR_MAX, FLAGS }, + { "replace", "replace color & alpha", OFFSET(replace), AV_OPT_TYPE_BOOL, { .i64=0 }, 0, 1, FLAGS }, { NULL } }; diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c index f6151443bbb5c..e8905a40d3ead 100644 --- a/libavfilter/vf_drawtext.c +++ b/libavfilter/vf_drawtext.c @@ -238,7 +238,7 @@ static const AVOption drawtext_options[]= { {"rate", "set rate (timecode only)", OFFSET(tc_rate), AV_OPT_TYPE_RATIONAL, {.dbl=0}, 0, INT_MAX, FLAGS}, {"reload", "reload text file for each frame", OFFSET(reload), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS}, { "alpha", "apply alpha while rendering", OFFSET(a_expr), AV_OPT_TYPE_STRING, { .str = "1" }, .flags = FLAGS }, - {"fix_bounds", "check and fix text coords to avoid clipping", OFFSET(fix_bounds), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS}, + {"fix_bounds", "check and fix text coords to avoid clipping", OFFSET(fix_bounds), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS}, {"start_number", "start frame number for n/frame_num variable", OFFSET(start_number), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS}, #if CONFIG_LIBFRIBIDI @@ -1390,6 +1390,7 @@ static int draw_text(AVFilterContext *ctx, AVFrame *frame, s->x = s->var_values[VAR_X] = av_expr_eval(s->x_pexpr, s->var_values, &s->prng); s->y = s->var_values[VAR_Y] = av_expr_eval(s->y_pexpr, s->var_values, &s->prng); + /* It is necessary if x is expressed from y */ s->x = s->var_values[VAR_X] = av_expr_eval(s->x_pexpr, s->var_values, &s->prng); update_alpha(s); @@ -1401,6 +1402,32 @@ static int draw_text(AVFilterContext *ctx, AVFrame *frame, box_w = FFMIN(width - 1 , max_text_line_w); box_h = FFMIN(height - 1, y + s->max_glyph_h); + if (s->fix_bounds) { + + /* calculate footprint of text effects */ + int boxoffset = s->draw_box ? FFMAX(s->boxborderw, 0) : 0; + int borderoffset = s->borderw ? FFMAX(s->borderw, 0) : 0; + + int offsetleft = FFMAX3(boxoffset, borderoffset, + (s->shadowx < 0 ? FFABS(s->shadowx) : 0)); + int offsettop = FFMAX3(boxoffset, borderoffset, + (s->shadowy < 0 ? FFABS(s->shadowy) : 0)); + + int offsetright = FFMAX3(boxoffset, borderoffset, + (s->shadowx > 0 ? s->shadowx : 0)); + int offsetbottom = FFMAX3(boxoffset, borderoffset, + (s->shadowy > 0 ? s->shadowy : 0)); + + + if (s->x - offsetleft < 0) s->x = offsetleft; + if (s->y - offsettop < 0) s->y = offsettop; + + if (s->x + box_w + offsetright > width) + s->x = FFMAX(width - box_w - offsetright, 0); + if (s->y + box_h + offsetbottom > height) + s->y = FFMAX(height - box_h - offsetbottom, 0); + } + /* draw box */ if (s->draw_box) ff_blend_rectangle(&s->dc, &boxcolor, diff --git a/libavfilter/vf_entropy.c b/libavfilter/vf_entropy.c new file mode 100644 index 0000000000000..e6002ce27a27e --- /dev/null +++ b/libavfilter/vf_entropy.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2017 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/imgutils.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "avfilter.h" +#include "drawutils.h" +#include "formats.h" +#include "internal.h" +#include "video.h" + +typedef struct EntropyContext { + const AVClass *class; + + int mode; + + int nb_planes; + int planeheight[4]; + int planewidth[4]; + int depth; + int is_rgb; + uint8_t rgba_map[4]; + char planenames[4]; + int64_t *histogram; +} EntropyContext; + +#define OFFSET(x) offsetof(EntropyContext, x) +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM +static const AVOption entropy_options[] = { + { "mode", "set kind of histogram entropy measurement", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "mode" }, + { "normal", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "mode" }, + { "diff", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "mode" }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(entropy); + +static int query_formats(AVFilterContext *ctx) +{ + static const enum AVPixelFormat pixfmts[] = { + AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV411P, + AV_PIX_FMT_YUV440P, + AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ411P, + AV_PIX_FMT_YUVJ440P, + AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV420P9, + AV_PIX_FMT_YUV444P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV420P10, + AV_PIX_FMT_YUV440P10, + AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV420P12, + AV_PIX_FMT_YUV440P12, + AV_PIX_FMT_YUV444P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV420P14, + AV_PIX_FMT_YUV444P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV420P16, + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, + AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_NONE + }; + + AVFilterFormats *formats = ff_make_format_list(pixfmts); + if (!formats) + return AVERROR(ENOMEM); + return ff_set_common_formats(ctx, formats); +} + +static int config_input(AVFilterLink *inlink) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + AVFilterContext *ctx = inlink->dst; + EntropyContext *s = ctx->priv; + + s->nb_planes = desc->nb_components; + + s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h); + s->planeheight[0] = s->planeheight[3] = inlink->h; + s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w); + s->planewidth[0] = s->planewidth[3] = inlink->w; + + s->depth = desc->comp[0].depth; + s->is_rgb = ff_fill_rgba_map(s->rgba_map, inlink->format) >= 0; + + s->planenames[0] = s->is_rgb ? 'R' : 'Y'; + s->planenames[1] = s->is_rgb ? 'G' : 'U'; + s->planenames[2] = s->is_rgb ? 'B' : 'V'; + s->planenames[3] = 'A'; + + s->histogram = av_malloc_array(1 << s->depth, sizeof(*s->histogram)); + if (!s->histogram) + return AVERROR(ENOMEM); + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + EntropyContext *s = ctx->priv; + int plane, y, x; + + for (plane = 0; plane < s->nb_planes; plane++) { + int cidx = s->is_rgb ? s->rgba_map[plane] : plane; + const uint8_t *src8 = in->data[plane]; + const uint16_t *src16 = (const uint16_t *)in->data[plane]; + float total = s->planewidth[plane] * s->planeheight[plane]; + float entropy = 0; + char metabuf[128]; + char key[128]; + + memset(s->histogram, 0, (1 << s->depth) * sizeof(*s->histogram)); + + if (s->depth <= 8) { + for (y = 0; y < s->planeheight[plane]; y++) { + for (x = 0; x < s->planewidth[plane]; x++) { + s->histogram[src8[x]]++; + } + + src8 += in->linesize[plane]; + } + } else { + for (y = 0; y < s->planeheight[plane]; y++) { + for (x = 0; x < s->planewidth[plane]; x++) { + s->histogram[src16[x]]++; + } + + src16 += in->linesize[plane] / 2; + } + } + + for (y = 0; y < 1 << s->depth; y++) { + if (s->mode == 0) { + if (s->histogram[y]) { + float p = s->histogram[y] / total; + entropy += -log2(p) * p; + } + } else if (s->mode == 1) { + if (y && (s->histogram[y] - s->histogram[y - 1]) != 0) { + float p = FFABS(s->histogram[y] - s->histogram[y - 1]) / total; + entropy += -log2(p) * p; + } + } + } + + snprintf(key, sizeof(key), "lavfi.entropy.entropy.%s.%c", s->mode ? "diff" : "normal", s->planenames[cidx]); + snprintf(metabuf, sizeof(metabuf), "%f", entropy); + av_dict_set(&in->metadata, key, metabuf, 0); + snprintf(key, sizeof(key), "lavfi.entropy.normalized_entropy.%s.%c", s->mode ? "diff" : "normal", s->planenames[cidx]); + snprintf(metabuf, sizeof(metabuf), "%f", entropy / log2(1 << s->depth)); + av_dict_set(&in->metadata, key, metabuf, 0); + } + + return ff_filter_frame(outlink, in); +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + EntropyContext *s = ctx->priv; + + av_freep(&s->histogram); +} + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame, + .config_props = config_input, + }, + { NULL } +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +AVFilter ff_vf_entropy = { + .name = "entropy", + .description = NULL_IF_CONFIG_SMALL("Measure video frames entropy."), + .priv_size = sizeof(EntropyContext), + .uninit = uninit, + .query_formats = query_formats, + .inputs = inputs, + .outputs = outputs, + .priv_class = &entropy_class, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, +}; diff --git a/libavfilter/vf_fftfilt.c b/libavfilter/vf_fftfilt.c index 7f60ca1f87b7e..af44b1e22ee62 100644 --- a/libavfilter/vf_fftfilt.c +++ b/libavfilter/vf_fftfilt.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2015 Arwa Arif + * Copyright (c) 2017 Paul B Mahol * * This file is part of FFmpeg. * @@ -64,6 +65,8 @@ typedef struct FFTFILTContext { AVExpr *weight_expr[MAX_PLANES]; double *weight[MAX_PLANES]; + void (*rdft_horizontal)(struct FFTFILTContext *s, AVFrame *in, int w, int h, int plane); + void (*irdft_horizontal)(struct FFTFILTContext *s, AVFrame *out, int w, int h, int plane); } FFTFILTContext; static const char *const var_names[] = { "X", "Y", "W", "H", "N", NULL }; @@ -111,7 +114,7 @@ static void copy_rev (FFTSample *dest, int w, int w2) } /*Horizontal pass - RDFT*/ -static void rdft_horizontal(FFTFILTContext *s, AVFrame *in, int w, int h, int plane) +static void rdft_horizontal8(FFTFILTContext *s, AVFrame *in, int w, int h, int plane) { int i, j; @@ -126,6 +129,23 @@ static void rdft_horizontal(FFTFILTContext *s, AVFrame *in, int w, int h, int pl av_rdft_calc(s->hrdft[plane], s->rdft_hdata[plane] + i * s->rdft_hlen[plane]); } +static void rdft_horizontal16(FFTFILTContext *s, AVFrame *in, int w, int h, int plane) +{ + const uint16_t *src = (const uint16_t *)in->data[plane]; + int linesize = in->linesize[plane] / 2; + int i, j; + + for (i = 0; i < h; i++) { + for (j = 0; j < w; j++) + s->rdft_hdata[plane][i * s->rdft_hlen[plane] + j] = *(src + linesize * i + j); + + copy_rev(s->rdft_hdata[plane] + i * s->rdft_hlen[plane], w, s->rdft_hlen[plane]); + } + + for (i = 0; i < h; i++) + av_rdft_calc(s->hrdft[plane], s->rdft_hdata[plane] + i * s->rdft_hlen[plane]); +} + /*Vertical pass - RDFT*/ static void rdft_vertical(FFTFILTContext *s, int h, int plane) { @@ -156,7 +176,7 @@ static void irdft_vertical(FFTFILTContext *s, int h, int plane) } /*Horizontal pass - IRDFT*/ -static void irdft_horizontal(FFTFILTContext *s, AVFrame *out, int w, int h, int plane) +static void irdft_horizontal8(FFTFILTContext *s, AVFrame *out, int w, int h, int plane) { int i, j; @@ -171,6 +191,24 @@ static void irdft_horizontal(FFTFILTContext *s, AVFrame *out, int w, int h, int s->rdft_vlen[plane]), 0, 255); } +static void irdft_horizontal16(FFTFILTContext *s, AVFrame *out, int w, int h, int plane) +{ + uint16_t *dst = (uint16_t *)out->data[plane]; + int linesize = out->linesize[plane] / 2; + int max = (1 << s->depth) - 1; + int i, j; + + for (i = 0; i < h; i++) + av_rdft_calc(s->ihrdft[plane], s->rdft_hdata[plane] + i * s->rdft_hlen[plane]); + + for (i = 0; i < h; i++) + for (j = 0; j < w; j++) + *(dst + linesize * i + j) = av_clip(s->rdft_hdata[plane][i + *s->rdft_hlen[plane] + j] * 4 / + (s->rdft_hlen[plane] * + s->rdft_vlen[plane]), 0, max); +} + static av_cold int initialize(AVFilterContext *ctx) { FFTFILTContext *s = ctx->priv; @@ -276,6 +314,16 @@ static int config_props(AVFilterLink *inlink) if (s->eval_mode == EVAL_MODE_INIT) do_eval(s, inlink, plane); } + + if (s->depth <= 8) { + s->rdft_horizontal = rdft_horizontal8; + s->irdft_horizontal = irdft_horizontal8; + } else if (s->depth > 8) { + s->rdft_horizontal = rdft_horizontal16; + s->irdft_horizontal = irdft_horizontal16; + } else { + return AVERROR_BUG; + } return 0; } @@ -302,7 +350,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) if (s->eval_mode == EVAL_MODE_FRAME) do_eval(s, inlink, plane); - rdft_horizontal(s, in, w, h, plane); + s->rdft_horizontal(s, in, w, h, plane); rdft_vertical(s, h, plane); /*Change user defined parameters*/ @@ -314,7 +362,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) s->rdft_vdata[plane][0] += s->rdft_hlen[plane] * s->rdft_vlen[plane] * s->dc[plane]; irdft_vertical(s, h, plane); - irdft_horizontal(s, out, w, h, plane); + s->irdft_horizontal(s, out, w, h, plane); } av_frame_free(&in); @@ -344,6 +392,15 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVJ422P, + AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV420P10, + AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV420P14, + AV_PIX_FMT_YUV420P16, + AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV422P10, + AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV422P14, + AV_PIX_FMT_YUV422P16, + AV_PIX_FMT_YUV444P9, AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV444P14, + AV_PIX_FMT_YUV444P16, AV_PIX_FMT_NONE }; diff --git a/libavfilter/vf_fillborders.c b/libavfilter/vf_fillborders.c new file mode 100644 index 0000000000000..df883bc62e9e1 --- /dev/null +++ b/libavfilter/vf_fillborders.c @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2017 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/colorspace.h" +#include "libavutil/common.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "avfilter.h" +#include "drawutils.h" +#include "formats.h" +#include "internal.h" +#include "video.h" + +enum { Y, U, V, A }; +enum { R, G, B }; + +enum FillMode { FM_SMEAR, FM_MIRROR, FM_FIXED, FM_NB_MODES }; + +typedef struct Borders { + int left, right, top, bottom; +} Borders; + +typedef struct FillBordersContext { + const AVClass *class; + int left, right, top, bottom; + int mode; + + int nb_planes; + int depth; + Borders borders[4]; + int planewidth[4]; + int planeheight[4]; + uint8_t fill[4]; + uint8_t yuv_color[4]; + uint8_t rgba_color[4]; + + void (*fillborders)(struct FillBordersContext *s, AVFrame *frame); +} FillBordersContext; + +static int query_formats(AVFilterContext *ctx) +{ + static const enum AVPixelFormat pix_fmts[] = { + AV_PIX_FMT_YUVA444P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUV440P, + AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVJ440P, + AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV420P, + AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ420P, + AV_PIX_FMT_YUVJ411P, AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV410P, + AV_PIX_FMT_YUV420P9, AV_PIX_FMT_YUV422P9, AV_PIX_FMT_YUV444P9, + AV_PIX_FMT_YUV420P10, AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10, + AV_PIX_FMT_YUV420P12, AV_PIX_FMT_YUV422P12, AV_PIX_FMT_YUV444P12, AV_PIX_FMT_YUV440P12, + AV_PIX_FMT_YUV420P14, AV_PIX_FMT_YUV422P14, AV_PIX_FMT_YUV444P14, + AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, + AV_PIX_FMT_YUVA420P9, AV_PIX_FMT_YUVA422P9, AV_PIX_FMT_YUVA444P9, + AV_PIX_FMT_YUVA420P10, AV_PIX_FMT_YUVA422P10, AV_PIX_FMT_YUVA444P10, + AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUVA444P16, + AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, + AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, + AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_NONE + }; + AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); + if (!fmts_list) + return AVERROR(ENOMEM); + return ff_set_common_formats(ctx, fmts_list); +} + +static void smear_borders8(FillBordersContext *s, AVFrame *frame) +{ + int p, y; + + for (p = 0; p < s->nb_planes; p++) { + uint8_t *ptr = frame->data[p]; + int linesize = frame->linesize[p]; + + for (y = s->borders[p].top; y < s->planeheight[p] - s->borders[p].bottom; y++) { + memset(ptr + y * linesize, + *(ptr + y * linesize + s->borders[p].left), + s->borders[p].left); + memset(ptr + y * linesize + s->planewidth[p] - s->borders[p].right, + *(ptr + y * linesize + s->planewidth[p] - s->borders[p].right - 1), + s->borders[p].right); + } + + for (y = 0; y < s->borders[p].top; y++) { + memcpy(ptr + y * linesize, + ptr + s->borders[p].top * linesize, s->planewidth[p]); + } + + for (y = s->planeheight[p] - s->borders[p].bottom; y < s->planeheight[p]; y++) { + memcpy(ptr + y * linesize, + ptr + (s->planeheight[p] - s->borders[p].bottom - 1) * linesize, + s->planewidth[p]); + } + } +} + +static void smear_borders16(FillBordersContext *s, AVFrame *frame) +{ + int p, y, x; + + for (p = 0; p < s->nb_planes; p++) { + uint16_t *ptr = (uint16_t *)frame->data[p]; + int linesize = frame->linesize[p] / 2; + + for (y = s->borders[p].top; y < s->planeheight[p] - s->borders[p].bottom; y++) { + for (x = 0; x < s->borders[p].left; x++) { + ptr[y * linesize + x] = *(ptr + y * linesize + s->borders[p].left); + } + + for (x = 0; x < s->borders[p].right; x++) { + ptr[y * linesize + s->planewidth[p] - s->borders[p].right + x] = + *(ptr + y * linesize + s->planewidth[p] - s->borders[p].right - 1); + } + } + + for (y = 0; y < s->borders[p].top; y++) { + memcpy(ptr + y * linesize, + ptr + s->borders[p].top * linesize, s->planewidth[p] * 2); + } + + for (y = s->planeheight[p] - s->borders[p].bottom; y < s->planeheight[p]; y++) { + memcpy(ptr + y * linesize, + ptr + (s->planeheight[p] - s->borders[p].bottom - 1) * linesize, + s->planewidth[p] * 2); + } + } +} + +static void mirror_borders8(FillBordersContext *s, AVFrame *frame) +{ + int p, y, x; + + for (p = 0; p < s->nb_planes; p++) { + uint8_t *ptr = frame->data[p]; + int linesize = frame->linesize[p]; + + for (y = s->borders[p].top; y < s->planeheight[p] - s->borders[p].bottom; y++) { + for (x = 0; x < s->borders[p].left; x++) { + ptr[y * linesize + x] = ptr[y * linesize + s->borders[p].left * 2 - 1 - x]; + } + + for (x = 0; x < s->borders[p].right; x++) { + ptr[y * linesize + s->planewidth[p] - s->borders[p].right + x] = + ptr[y * linesize + s->planewidth[p] - s->borders[p].right - 1 - x]; + } + } + + for (y = 0; y < s->borders[p].top; y++) { + memcpy(ptr + y * linesize, + ptr + (s->borders[p].top * 2 - 1 - y) * linesize, + s->planewidth[p]); + } + + for (y = 0; y < s->borders[p].bottom; y++) { + memcpy(ptr + (s->planeheight[p] - s->borders[p].bottom + y) * linesize, + ptr + (s->planeheight[p] - s->borders[p].bottom - 1 - y) * linesize, + s->planewidth[p]); + } + } +} + +static void mirror_borders16(FillBordersContext *s, AVFrame *frame) +{ + int p, y, x; + + for (p = 0; p < s->nb_planes; p++) { + uint16_t *ptr = (uint16_t *)frame->data[p]; + int linesize = frame->linesize[p] / 2; + + for (y = s->borders[p].top; y < s->planeheight[p] - s->borders[p].bottom; y++) { + for (x = 0; x < s->borders[p].left; x++) { + ptr[y * linesize + x] = ptr[y * linesize + s->borders[p].left * 2 - 1 - x]; + } + + for (x = 0; x < s->borders[p].right; x++) { + ptr[y * linesize + s->planewidth[p] - s->borders[p].right + x] = + ptr[y * linesize + s->planewidth[p] - s->borders[p].right - 1 - x]; + } + } + + for (y = 0; y < s->borders[p].top; y++) { + memcpy(ptr + y * linesize, + ptr + (s->borders[p].top * 2 - 1 - y) * linesize, + s->planewidth[p] * 2); + } + + for (y = 0; y < s->borders[p].bottom; y++) { + memcpy(ptr + (s->planeheight[p] - s->borders[p].bottom + y) * linesize, + ptr + (s->planeheight[p] - s->borders[p].bottom - 1 - y) * linesize, + s->planewidth[p] * 2); + } + } +} + +static void fixed_borders8(FillBordersContext *s, AVFrame *frame) +{ + int p, y; + + for (p = 0; p < s->nb_planes; p++) { + uint8_t *ptr = frame->data[p]; + uint8_t fill = s->fill[p]; + int linesize = frame->linesize[p]; + + for (y = s->borders[p].top; y < s->planeheight[p] - s->borders[p].bottom; y++) { + memset(ptr + y * linesize, fill, s->borders[p].left); + memset(ptr + y * linesize + s->planewidth[p] - s->borders[p].right, fill, + s->borders[p].right); + } + + for (y = 0; y < s->borders[p].top; y++) { + memset(ptr + y * linesize, fill, s->planewidth[p]); + } + + for (y = s->planeheight[p] - s->borders[p].bottom; y < s->planeheight[p]; y++) { + memset(ptr + y * linesize, fill, s->planewidth[p]); + } + } +} + +static void fixed_borders16(FillBordersContext *s, AVFrame *frame) +{ + int p, y, x; + + for (p = 0; p < s->nb_planes; p++) { + uint16_t *ptr = (uint16_t *)frame->data[p]; + uint16_t fill = s->fill[p] << (s->depth - 8); + int linesize = frame->linesize[p] / 2; + + for (y = s->borders[p].top; y < s->planeheight[p] - s->borders[p].bottom; y++) { + for (x = 0; x < s->borders[p].left; x++) { + ptr[y * linesize + x] = fill; + } + + for (x = 0; x < s->borders[p].right; x++) { + ptr[y * linesize + s->planewidth[p] - s->borders[p].right + x] = fill; + } + } + + for (y = 0; y < s->borders[p].top; y++) { + for (x = 0; x < s->planewidth[p]; x++) { + ptr[y * linesize + x] = fill; + } + } + + for (y = s->planeheight[p] - s->borders[p].bottom; y < s->planeheight[p]; y++) { + for (x = 0; x < s->planewidth[p]; x++) { + ptr[y * linesize + x] = fill; + } + } + } +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *frame) +{ + FillBordersContext *s = inlink->dst->priv; + + s->fillborders(s, frame); + + return ff_filter_frame(inlink->dst->outputs[0], frame); +} + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + FillBordersContext *s = ctx->priv; + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + + s->nb_planes = desc->nb_components; + s->depth = desc->comp[0].depth; + + s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h); + s->planeheight[0] = s->planeheight[3] = inlink->h; + s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w); + s->planewidth[0] = s->planewidth[3] = inlink->w; + + s->borders[0].left = s->borders[3].left = s->left; + s->borders[0].right = s->borders[3].right = s->right; + s->borders[0].top = s->borders[3].top = s->top; + s->borders[0].bottom = s->borders[3].bottom = s->bottom; + + s->borders[1].left = s->left >> desc->log2_chroma_w; + s->borders[1].right = s->right >> desc->log2_chroma_w; + s->borders[1].top = s->top >> desc->log2_chroma_h; + s->borders[1].bottom = s->bottom >> desc->log2_chroma_h; + + s->borders[2].left = s->left >> desc->log2_chroma_w; + s->borders[2].right = s->right >> desc->log2_chroma_w; + s->borders[2].top = s->top >> desc->log2_chroma_h; + s->borders[2].bottom = s->bottom >> desc->log2_chroma_h; + + if (inlink->w < s->left + s->right || + inlink->w <= s->left || + inlink->w <= s->right || + inlink->h < s->top + s->bottom || + inlink->h <= s->top || + inlink->h <= s->bottom || + inlink->w < s->left * 2 || + inlink->w < s->right * 2 || + inlink->h < s->top * 2 || + inlink->h < s->bottom * 2) { + av_log(ctx, AV_LOG_ERROR, "Borders are bigger than input frame size.\n"); + return AVERROR(EINVAL); + } + + switch (s->mode) { + case FM_SMEAR: s->fillborders = s->depth <= 8 ? smear_borders8 : smear_borders16; break; + case FM_MIRROR: s->fillborders = s->depth <= 8 ? mirror_borders8 : mirror_borders16; break; + case FM_FIXED: s->fillborders = s->depth <= 8 ? fixed_borders8 : fixed_borders16; break; + } + + s->yuv_color[Y] = RGB_TO_Y_CCIR(s->rgba_color[R], s->rgba_color[G], s->rgba_color[B]); + s->yuv_color[U] = RGB_TO_U_CCIR(s->rgba_color[R], s->rgba_color[G], s->rgba_color[B], 0); + s->yuv_color[V] = RGB_TO_V_CCIR(s->rgba_color[R], s->rgba_color[G], s->rgba_color[B], 0); + s->yuv_color[A] = s->rgba_color[A]; + + if (desc->flags & AV_PIX_FMT_FLAG_RGB) { + uint8_t rgba_map[4]; + int i; + + ff_fill_rgba_map(rgba_map, inlink->format); + for (i = 0; i < 4; i++) + s->fill[rgba_map[i]] = s->rgba_color[i]; + } else { + memcpy(s->fill, s->yuv_color, sizeof(s->yuv_color)); + } + + return 0; +} + +#define OFFSET(x) offsetof(FillBordersContext, x) +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption fillborders_options[] = { + { "left", "set the left fill border", OFFSET(left), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS }, + { "right", "set the right fill border", OFFSET(right), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS }, + { "top", "set the top fill border", OFFSET(top), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS }, + { "bottom", "set the bottom fill border", OFFSET(bottom), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX, FLAGS }, + { "mode", "set the fill borders mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64=FM_SMEAR}, 0, FM_NB_MODES-1, FLAGS, "mode" }, + { "smear", NULL, 0, AV_OPT_TYPE_CONST, {.i64=FM_SMEAR}, 0, 0, FLAGS, "mode" }, + { "mirror", NULL, 0, AV_OPT_TYPE_CONST, {.i64=FM_MIRROR}, 0, 0, FLAGS, "mode" }, + { "fixed", NULL, 0, AV_OPT_TYPE_CONST, {.i64=FM_FIXED}, 0, 0, FLAGS, "mode" }, + { "color", "set the color for the fixed mode", OFFSET(rgba_color), AV_OPT_TYPE_COLOR, {.str = "black"}, .flags = FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(fillborders); + +static const AVFilterPad fillborders_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_input, + .filter_frame = filter_frame, + .needs_writable = 1, + }, + { NULL } +}; + +static const AVFilterPad fillborders_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +AVFilter ff_vf_fillborders = { + .name = "fillborders", + .description = NULL_IF_CONFIG_SMALL("Fill borders of the input video."), + .priv_size = sizeof(FillBordersContext), + .priv_class = &fillborders_class, + .query_formats = query_formats, + .inputs = fillborders_inputs, + .outputs = fillborders_outputs, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, +}; diff --git a/libavfilter/vf_fps.c b/libavfilter/vf_fps.c index dbafd2c35a66e..9167a00a13ccb 100644 --- a/libavfilter/vf_fps.c +++ b/libavfilter/vf_fps.c @@ -2,6 +2,7 @@ * Copyright 2007 Bobby Bingham * Copyright 2012 Robert Nagy * Copyright 2012 Anton Khirnov + * Copyright 2018 Calvin Walton * * This file is part of FFmpeg. * @@ -28,17 +29,12 @@ #include #include -#include "libavutil/common.h" -#include "libavutil/fifo.h" +#include "libavutil/avassert.h" #include "libavutil/mathematics.h" #include "libavutil/opt.h" -#include "libavutil/parseutils.h" - -#define FF_INTERNAL_FIELDS 1 -#include "framequeue.h" #include "avfilter.h" +#include "filters.h" #include "internal.h" -#include "video.h" enum EOFAction { EOF_ACTION_ROUND, @@ -49,18 +45,27 @@ enum EOFAction { typedef struct FPSContext { const AVClass *class; - AVFifoBuffer *fifo; ///< store frames until we get two successive timestamps - - /* timestamps in input timebase */ - int64_t first_pts; ///< pts of the first frame that arrived on this filter - double start_time; ///< pts, in seconds, of the expected first frame AVRational framerate; ///< target framerate int rounding; ///< AVRounding method for timestamps int eof_action; ///< action performed for last frame in FIFO + /* Set during outlink configuration */ + int64_t in_pts_off; ///< input frame pts offset for start_time handling + int64_t out_pts_off; ///< output frame pts offset for start_time handling + + /* Runtime state */ + int status; ///< buffered input status + int64_t status_pts; ///< buffered input status timestamp + + AVFrame *frames[2]; ///< buffered frames + int frames_count; ///< number of buffered frames + + int64_t next_pts; ///< pts of the next frame to output + /* statistics */ + int cur_frame_out; ///< number of times current frame has been output int frames_in; ///< number of frames on input int frames_out; ///< number of frames on output int dup; ///< number of frames duplicated @@ -91,231 +96,238 @@ static av_cold int init(AVFilterContext *ctx) { FPSContext *s = ctx->priv; - if (!(s->fifo = av_fifo_alloc_array(2, sizeof(AVFrame*)))) - return AVERROR(ENOMEM); - - s->first_pts = AV_NOPTS_VALUE; + s->status_pts = AV_NOPTS_VALUE; + s->next_pts = AV_NOPTS_VALUE; av_log(ctx, AV_LOG_VERBOSE, "fps=%d/%d\n", s->framerate.num, s->framerate.den); return 0; } -static void flush_fifo(AVFifoBuffer *fifo) +/* Remove the first frame from the buffer, returning it */ +static AVFrame *shift_frame(AVFilterContext *ctx, FPSContext *s) { - while (av_fifo_size(fifo)) { - AVFrame *tmp; - av_fifo_generic_read(fifo, &tmp, sizeof(tmp), NULL); - av_frame_free(&tmp); + AVFrame *frame; + + /* Must only be called when there are frames in the buffer */ + av_assert1(s->frames_count > 0); + + frame = s->frames[0]; + s->frames[0] = s->frames[1]; + s->frames[1] = NULL; + s->frames_count--; + + /* Update statistics counters */ + s->frames_out += s->cur_frame_out; + if (s->cur_frame_out > 1) { + av_log(ctx, AV_LOG_DEBUG, "Duplicated frame with pts %"PRId64" %d times\n", + frame->pts, s->cur_frame_out - 1); + s->dup += s->cur_frame_out - 1; + } else if (s->cur_frame_out == 0) { + av_log(ctx, AV_LOG_DEBUG, "Dropping frame with pts %"PRId64"\n", + frame->pts); + s->drop++; } + s->cur_frame_out = 0; + + return frame; } static av_cold void uninit(AVFilterContext *ctx) { FPSContext *s = ctx->priv; - if (s->fifo) { - s->drop += av_fifo_size(s->fifo) / sizeof(AVFrame*); - flush_fifo(s->fifo); - av_fifo_freep(&s->fifo); + + AVFrame *frame; + + while (s->frames_count > 0) { + frame = shift_frame(ctx, s); + av_frame_free(&frame); } av_log(ctx, AV_LOG_VERBOSE, "%d frames in, %d frames out; %d frames dropped, " "%d frames duplicated.\n", s->frames_in, s->frames_out, s->drop, s->dup); } -static int config_props(AVFilterLink* link) +static int config_props(AVFilterLink* outlink) { - FPSContext *s = link->src->priv; - - link->time_base = av_inv_q(s->framerate); - link->frame_rate= s->framerate; - link->w = link->src->inputs[0]->w; - link->h = link->src->inputs[0]->h; + AVFilterContext *ctx = outlink->src; + AVFilterLink *inlink = ctx->inputs[0]; + FPSContext *s = ctx->priv; + + outlink->time_base = av_inv_q(s->framerate); + outlink->frame_rate = s->framerate; + + /* Calculate the input and output pts offsets for start_time */ + if (s->start_time != DBL_MAX && s->start_time != AV_NOPTS_VALUE) { + double first_pts = s->start_time * AV_TIME_BASE; + if (first_pts < INT64_MIN || first_pts > INT64_MAX) { + av_log(ctx, AV_LOG_ERROR, "Start time %f cannot be represented in internal time base\n", + s->start_time); + return AVERROR(EINVAL); + } + s->in_pts_off = av_rescale_q_rnd(first_pts, AV_TIME_BASE_Q, inlink->time_base, + s->rounding | AV_ROUND_PASS_MINMAX); + s->out_pts_off = av_rescale_q_rnd(first_pts, AV_TIME_BASE_Q, outlink->time_base, + s->rounding | AV_ROUND_PASS_MINMAX); + s->next_pts = s->out_pts_off; + av_log(ctx, AV_LOG_VERBOSE, "Set first pts to (in:%"PRId64" out:%"PRId64") from start time %f\n", + s->in_pts_off, s->out_pts_off, s->start_time); + } return 0; } -static int request_frame(AVFilterLink *outlink) +/* Read a frame from the input and save it in the buffer */ +static int read_frame(AVFilterContext *ctx, FPSContext *s, AVFilterLink *inlink, AVFilterLink *outlink) { - AVFilterContext *ctx = outlink->src; - FPSContext *s = ctx->priv; + AVFrame *frame; int ret; + int64_t in_pts; - ret = ff_request_frame(ctx->inputs[0]); - - /* flush the fifo */ - if (ret == AVERROR_EOF && av_fifo_size(s->fifo)) { - int i; - for (i = 0; av_fifo_size(s->fifo); i++) { - AVFrame *buf; - - av_fifo_generic_read(s->fifo, &buf, sizeof(buf), NULL); - if (av_fifo_size(s->fifo)) { - buf->pts = av_rescale_q(s->first_pts, ctx->inputs[0]->time_base, - outlink->time_base) + s->frames_out; - - if ((ret = ff_filter_frame(outlink, buf)) < 0) - return ret; - - s->frames_out++; - } else { - /* This is the last frame, we may have to duplicate it to match - * the last frame duration */ - int j; - int eof_rounding = (s->eof_action == EOF_ACTION_PASS) ? AV_ROUND_UP : s->rounding; - int delta = av_rescale_q_rnd(ctx->inputs[0]->current_pts - s->first_pts, - ctx->inputs[0]->time_base, - outlink->time_base, eof_rounding) - s->frames_out; - av_log(ctx, AV_LOG_DEBUG, "EOF frames_out:%d delta:%d\n", s->frames_out, delta); - /* if the delta is equal to 1, it means we just need to output - * the last frame. Greater than 1 means we will need duplicate - * delta-1 frames */ - if (delta > 0 ) { - for (j = 0; j < delta; j++) { - AVFrame *dup = av_frame_clone(buf); - - av_log(ctx, AV_LOG_DEBUG, "Duplicating frame.\n"); - dup->pts = av_rescale_q(s->first_pts, ctx->inputs[0]->time_base, - outlink->time_base) + s->frames_out; - - if ((ret = ff_filter_frame(outlink, dup)) < 0) - return ret; - - s->frames_out++; - if (j > 0) s->dup++; - } - av_frame_free(&buf); - } else { - /* for delta less or equal to 0, we should drop the frame, - * otherwise, we will have one or more extra frames */ - av_frame_free(&buf); - s->drop++; - } - } - } - return 0; - } + /* Must only be called when we have buffer room available */ + av_assert1(s->frames_count < 2); - return ret; -} + ret = ff_inlink_consume_frame(inlink, &frame); + /* Caller must have run ff_inlink_check_available_frame first */ + av_assert1(ret); + if (ret < 0) + return ret; -static int write_to_fifo(AVFifoBuffer *fifo, AVFrame *buf) -{ - int ret; + /* Convert frame pts to output timebase. + * The dance with offsets is required to match the rounding behaviour of the + * previous version of the fps filter when using the start_time option. */ + in_pts = frame->pts; + frame->pts = s->out_pts_off + av_rescale_q_rnd(in_pts - s->in_pts_off, + inlink->time_base, outlink->time_base, + s->rounding | AV_ROUND_PASS_MINMAX); - if (!av_fifo_space(fifo) && - (ret = av_fifo_realloc2(fifo, 2*av_fifo_size(fifo)))) { - av_frame_free(&buf); - return ret; - } + av_log(ctx, AV_LOG_DEBUG, "Read frame with in pts %"PRId64", out pts %"PRId64"\n", + in_pts, frame->pts); - av_fifo_generic_write(fifo, &buf, sizeof(buf), NULL); - return 0; + s->frames[s->frames_count++] = frame; + s->frames_in++; + + return 1; } -static int filter_frame(AVFilterLink *inlink, AVFrame *buf) +/* Write a frame to the output */ +static int write_frame(AVFilterContext *ctx, FPSContext *s, AVFilterLink *outlink, int *again) { - AVFilterContext *ctx = inlink->dst; - FPSContext *s = ctx->priv; - AVFilterLink *outlink = ctx->outputs[0]; - int64_t delta; - int i, ret; + AVFrame *frame; - s->frames_in++; - /* discard frames until we get the first timestamp */ - if (s->first_pts == AV_NOPTS_VALUE) { - if (buf->pts != AV_NOPTS_VALUE) { - ret = write_to_fifo(s->fifo, buf); - if (ret < 0) - return ret; + av_assert1(s->frames_count == 2 || (s->status && s->frames_count == 1)); - if (s->start_time != DBL_MAX && s->start_time != AV_NOPTS_VALUE) { - double first_pts = s->start_time * AV_TIME_BASE; - first_pts = FFMIN(FFMAX(first_pts, INT64_MIN), INT64_MAX); - s->first_pts = av_rescale_q(first_pts, AV_TIME_BASE_Q, - inlink->time_base); - av_log(ctx, AV_LOG_VERBOSE, "Set first pts to (in:%"PRId64" out:%"PRId64")\n", - s->first_pts, av_rescale_q(first_pts, AV_TIME_BASE_Q, - outlink->time_base)); - } else { - s->first_pts = buf->pts; - } + /* We haven't yet determined the pts of the first frame */ + if (s->next_pts == AV_NOPTS_VALUE) { + if (s->frames[0]->pts != AV_NOPTS_VALUE) { + s->next_pts = s->frames[0]->pts; + av_log(ctx, AV_LOG_VERBOSE, "Set first pts to %"PRId64"\n", s->next_pts); } else { av_log(ctx, AV_LOG_WARNING, "Discarding initial frame(s) with no " "timestamp.\n"); - av_frame_free(&buf); - s->drop++; + frame = shift_frame(ctx, s); + av_frame_free(&frame); + *again = 1; + return 0; } - return 0; } - /* now wait for the next timestamp */ - if (buf->pts == AV_NOPTS_VALUE || av_fifo_size(s->fifo) <= 0) { - return write_to_fifo(s->fifo, buf); - } + /* There are two conditions where we want to drop a frame: + * - If we have two buffered frames and the second frame is acceptable + * as the next output frame, then drop the first buffered frame. + * - If we have status (EOF) set, drop frames when we hit the + * status timestamp. */ + if ((s->frames_count == 2 && s->frames[1]->pts <= s->next_pts) || + (s->status && s->status_pts <= s->next_pts)) { + + frame = shift_frame(ctx, s); + av_frame_free(&frame); + *again = 1; + return 0; - /* number of output frames */ - delta = av_rescale_q_rnd(buf->pts - s->first_pts, inlink->time_base, - outlink->time_base, s->rounding) - s->frames_out ; + /* Output a copy of the first buffered frame */ + } else { + frame = av_frame_clone(s->frames[0]); + if (!frame) + return AVERROR(ENOMEM); + frame->pts = s->next_pts++; - if (delta < 1) { - /* drop everything buffered except the last */ - int drop = av_fifo_size(s->fifo)/sizeof(AVFrame*); + av_log(ctx, AV_LOG_DEBUG, "Writing frame with pts %"PRId64" to pts %"PRId64"\n", + s->frames[0]->pts, frame->pts); + s->cur_frame_out++; - av_log(ctx, AV_LOG_DEBUG, "Dropping %d frame(s).\n", drop); - s->drop += drop; + return ff_filter_frame(outlink, frame); + } +} - flush_fifo(s->fifo); - ret = write_to_fifo(s->fifo, buf); +/* Convert status_pts to outlink timebase */ +static void update_eof_pts(AVFilterContext *ctx, FPSContext *s, AVFilterLink *inlink, AVFilterLink *outlink, int64_t status_pts) +{ + int eof_rounding = (s->eof_action == EOF_ACTION_PASS) ? AV_ROUND_UP : s->rounding; + s->status_pts = av_rescale_q_rnd(status_pts, inlink->time_base, outlink->time_base, + eof_rounding | AV_ROUND_PASS_MINMAX); - return ret; - } + av_log(ctx, AV_LOG_DEBUG, "EOF is at pts %"PRId64"\n", s->status_pts); +} - /* can output >= 1 frames */ - for (i = 0; i < delta; i++) { - AVFrame *buf_out; - av_fifo_generic_read(s->fifo, &buf_out, sizeof(buf_out), NULL); +static int activate(AVFilterContext *ctx) +{ + FPSContext *s = ctx->priv; + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; - /* duplicate the frame if needed */ - if (!av_fifo_size(s->fifo) && i < delta - 1) { - AVFrame *dup = av_frame_clone(buf_out); + int ret; + int again = 0; + int64_t status_pts; - av_log(ctx, AV_LOG_DEBUG, "Duplicating frame.\n"); - if (dup) - ret = write_to_fifo(s->fifo, dup); - else - ret = AVERROR(ENOMEM); + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); - if (ret < 0) { - av_frame_free(&buf_out); - av_frame_free(&buf); - return ret; - } + /* No buffered status: normal operation */ + if (!s->status) { - s->dup++; + /* Read available input frames if we have room */ + while (s->frames_count < 2 && ff_inlink_check_available_frame(inlink)) { + ret = read_frame(ctx, s, inlink, outlink); + if (ret < 0) + return ret; } - buf_out->pts = av_rescale_q(s->first_pts, inlink->time_base, - outlink->time_base) + s->frames_out; - - if ((ret = ff_filter_frame(outlink, buf_out)) < 0) { - av_frame_free(&buf); - return ret; + /* We do not yet have enough frames to produce output */ + if (s->frames_count < 2) { + /* Check if we've hit EOF (or otherwise that an error status is set) */ + ret = ff_inlink_acknowledge_status(inlink, &s->status, &status_pts); + if (ret > 0) + update_eof_pts(ctx, s, inlink, outlink, status_pts); + + if (!ret) { + /* If someone wants us to output, we'd better ask for more input */ + FF_FILTER_FORWARD_WANTED(outlink, inlink); + return 0; + } } + } - s->frames_out++; + /* Buffered frames are available, so generate an output frame */ + if (s->frames_count > 0) { + ret = write_frame(ctx, s, outlink, &again); + /* Couldn't generate a frame, so schedule us to perform another step */ + if (again) + ff_filter_set_ready(ctx, 100); + return ret; } - flush_fifo(s->fifo); - ret = write_to_fifo(s->fifo, buf); + /* No frames left, so forward the status */ + if (s->status && s->frames_count == 0) { + ff_outlink_set_status(outlink, s->status, s->next_pts); + return 0; + } - return ret; + return FFERROR_NOT_READY; } static const AVFilterPad avfilter_vf_fps_inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, - .filter_frame = filter_frame, }, { NULL } }; @@ -324,8 +336,7 @@ static const AVFilterPad avfilter_vf_fps_outputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, - .request_frame = request_frame, - .config_props = config_props + .config_props = config_props, }, { NULL } }; @@ -337,6 +348,7 @@ AVFilter ff_vf_fps = { .uninit = uninit, .priv_size = sizeof(FPSContext), .priv_class = &fps_class, + .activate = activate, .inputs = avfilter_vf_fps_inputs, .outputs = avfilter_vf_fps_outputs, }; diff --git a/libavfilter/vf_framepack.c b/libavfilter/vf_framepack.c index a5cd9540b97ce..12a29964c47c2 100644 --- a/libavfilter/vf_framepack.c +++ b/libavfilter/vf_framepack.c @@ -324,6 +324,8 @@ static int try_push_frame(AVFilterContext *ctx) if (!stereo) return AVERROR(ENOMEM); stereo->type = s->format; + stereo->view = i == LEFT ? AV_STEREO3D_VIEW_LEFT + : AV_STEREO3D_VIEW_RIGHT; // filter the frame and immediately relinquish its pointer ret = ff_filter_frame(outlink, s->input_views[i]); diff --git a/libavfilter/vf_framerate.c b/libavfilter/vf_framerate.c index dc8b05f40f261..3e2615be5e695 100644 --- a/libavfilter/vf_framerate.c +++ b/libavfilter/vf_framerate.c @@ -38,47 +38,7 @@ #include "avfilter.h" #include "internal.h" #include "video.h" - -#define N_SRCE 3 - -typedef struct FrameRateContext { - const AVClass *class; - // parameters - AVRational dest_frame_rate; ///< output frames per second - int flags; ///< flags affecting frame rate conversion algorithm - double scene_score; ///< score that denotes a scene change has happened - int interp_start; ///< start of range to apply linear interpolation - int interp_end; ///< end of range to apply linear interpolation - - int line_size[4]; ///< bytes of pixel data per line for each plane - int vsub; - - int frst, next, prev, crnt, last; - int pending_srce_frames; ///< how many input frames are still waiting to be processed - int flush; ///< are we flushing final frames - int pending_end_frame; ///< flag indicating we are waiting to call filter_frame() - - AVRational srce_time_base; ///< timebase of source - - AVRational dest_time_base; ///< timebase of destination - int32_t dest_frame_num; - int64_t last_dest_frame_pts; ///< pts of the last frame output - int64_t average_srce_pts_dest_delta;///< average input pts delta converted from input rate to output rate - int64_t average_dest_pts_delta; ///< calculated average output pts delta - - av_pixelutils_sad_fn sad; ///< Sum of the absolute difference function (scene detect only) - double prev_mafd; ///< previous MAFD (scene detect only) - - AVFrame *srce[N_SRCE]; ///< buffered source frames - int64_t srce_pts_dest[N_SRCE]; ///< pts for source frames scaled to output timebase - int64_t pts; ///< pts of frame we are working on - - int (*blend_frames)(AVFilterContext *ctx, float interpolate, - AVFrame *copy_src1, AVFrame *copy_src2); - int max; - int bitdepth; - AVFrame *work; -} FrameRateContext; +#include "framerate.h" #define OFFSET(x) offsetof(FrameRateContext, x) #define V AV_OPT_FLAG_VIDEO_PARAM @@ -90,7 +50,7 @@ static const AVOption framerate_options[] = { {"interp_start", "point to start linear interpolation", OFFSET(interp_start), AV_OPT_TYPE_INT, {.i64=15}, 0, 255, V|F }, {"interp_end", "point to end linear interpolation", OFFSET(interp_end), AV_OPT_TYPE_INT, {.i64=240}, 0, 255, V|F }, - {"scene", "scene change level", OFFSET(scene_score), AV_OPT_TYPE_DOUBLE, {.dbl=7.0}, 0, INT_MAX, V|F }, + {"scene", "scene change level", OFFSET(scene_score), AV_OPT_TYPE_DOUBLE, {.dbl=8.2}, 0, INT_MAX, V|F }, {"flags", "set flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64=1}, 0, INT_MAX, V|F, "flags" }, {"scene_change_detect", "enable scene change detection", 0, AV_OPT_TYPE_CONST, {.i64=FRAMERATE_FLAG_SCD}, INT_MIN, INT_MAX, V|F, "flags" }, @@ -101,25 +61,6 @@ static const AVOption framerate_options[] = { AVFILTER_DEFINE_CLASS(framerate); -static void next_source(AVFilterContext *ctx) -{ - FrameRateContext *s = ctx->priv; - int i; - - ff_dlog(ctx, "next_source()\n"); - - if (s->srce[s->last] && s->srce[s->last] != s->srce[s->last-1]) { - ff_dlog(ctx, "next_source() unlink %d\n", s->last); - av_frame_free(&s->srce[s->last]); - } - for (i = s->last; i > s->frst; i--) { - ff_dlog(ctx, "next_source() copy %d to %d\n", i - 1, i); - s->srce[i] = s->srce[i - 1]; - } - ff_dlog(ctx, "next_source() make %d null\n", s->frst); - s->srce[s->frst] = NULL; -} - static av_always_inline int64_t sad_8x8_16(const uint16_t *src1, ptrdiff_t stride1, const uint16_t *src2, ptrdiff_t stride2) { @@ -135,41 +76,35 @@ static av_always_inline int64_t sad_8x8_16(const uint16_t *src1, ptrdiff_t strid return sum; } -static double get_scene_score16(AVFilterContext *ctx, AVFrame *crnt, AVFrame *next) +static int64_t scene_sad16(FrameRateContext *s, const uint16_t *p1, int p1_linesize, const uint16_t* p2, int p2_linesize, const int width, const int height) { - FrameRateContext *s = ctx->priv; - double ret = 0; - - ff_dlog(ctx, "get_scene_score16()\n"); + int64_t sad; + int x, y; + for (sad = y = 0; y < height - 7; y += 8) { + for (x = 0; x < width - 7; x += 8) { + sad += sad_8x8_16(p1 + y * p1_linesize + x, + p1_linesize, + p2 + y * p2_linesize + x, + p2_linesize); + } + } + return sad; +} - if (crnt && - crnt->height == next->height && - crnt->width == next->width) { - int x, y; - int64_t sad; - double mafd, diff; - const uint16_t *p1 = (const uint16_t *)crnt->data[0]; - const uint16_t *p2 = (const uint16_t *)next->data[0]; - const int p1_linesize = crnt->linesize[0] / 2; - const int p2_linesize = next->linesize[0] / 2; - - ff_dlog(ctx, "get_scene_score16() process\n"); - - for (sad = y = 0; y < crnt->height; y += 8) { - for (x = 0; x < p1_linesize; x += 8) { - sad += sad_8x8_16(p1 + y * p1_linesize + x, - p1_linesize, - p2 + y * p2_linesize + x, - p2_linesize); - } +static int64_t scene_sad8(FrameRateContext *s, uint8_t *p1, int p1_linesize, uint8_t* p2, int p2_linesize, const int width, const int height) +{ + int64_t sad; + int x, y; + for (sad = y = 0; y < height - 7; y += 8) { + for (x = 0; x < width - 7; x += 8) { + sad += s->sad(p1 + y * p1_linesize + x, + p1_linesize, + p2 + y * p2_linesize + x, + p2_linesize); } - mafd = sad / (crnt->height * crnt->width * 3); - diff = fabs(mafd - s->prev_mafd); - ret = av_clipf(FFMIN(mafd, diff), 0, 100.0); - s->prev_mafd = mafd; } - ff_dlog(ctx, "get_scene_score16() result is:%f\n", ret); - return ret; + emms_c(); + return sad; } static double get_scene_score(AVFilterContext *ctx, AVFrame *crnt, AVFrame *next) @@ -179,358 +114,159 @@ static double get_scene_score(AVFilterContext *ctx, AVFrame *crnt, AVFrame *next ff_dlog(ctx, "get_scene_score()\n"); - if (crnt && - crnt->height == next->height && + if (crnt->height == next->height && crnt->width == next->width) { - int x, y; int64_t sad; double mafd, diff; - uint8_t *p1 = crnt->data[0]; - uint8_t *p2 = next->data[0]; - const int p1_linesize = crnt->linesize[0]; - const int p2_linesize = next->linesize[0]; ff_dlog(ctx, "get_scene_score() process\n"); + if (s->bitdepth == 8) + sad = scene_sad8(s, crnt->data[0], crnt->linesize[0], next->data[0], next->linesize[0], crnt->width, crnt->height); + else + sad = scene_sad16(s, (const uint16_t*)crnt->data[0], crnt->linesize[0] / 2, (const uint16_t*)next->data[0], next->linesize[0] / 2, crnt->width, crnt->height); - for (sad = y = 0; y < crnt->height; y += 8) { - for (x = 0; x < p1_linesize; x += 8) { - sad += s->sad(p1 + y * p1_linesize + x, - p1_linesize, - p2 + y * p2_linesize + x, - p2_linesize); - } - } - emms_c(); - mafd = sad / (crnt->height * crnt->width * 3); + mafd = (double)sad * 100.0 / FFMAX(1, (crnt->height & ~7) * (crnt->width & ~7)) / (1 << s->bitdepth); diff = fabs(mafd - s->prev_mafd); ret = av_clipf(FFMIN(mafd, diff), 0, 100.0); s->prev_mafd = mafd; } - ff_dlog(ctx, "get_scene_score() result is:%f\n", ret); + ff_dlog(ctx, "get_scene_score() result is:%f\n", ret); return ret; } -static int blend_frames16(AVFilterContext *ctx, float interpolate, - AVFrame *copy_src1, AVFrame *copy_src2) +typedef struct ThreadData { + AVFrame *copy_src1, *copy_src2; + uint16_t src1_factor, src2_factor; +} ThreadData; + +static int filter_slice(AVFilterContext *ctx, void *arg, int job, int nb_jobs) { FrameRateContext *s = ctx->priv; - AVFilterLink *outlink = ctx->outputs[0]; - double interpolate_scene_score = 0; + ThreadData *td = arg; + uint16_t src1_factor = td->src1_factor; + uint16_t src2_factor = td->src2_factor; + int plane; - if ((s->flags & FRAMERATE_FLAG_SCD) && copy_src2) { - interpolate_scene_score = get_scene_score16(ctx, copy_src1, copy_src2); - ff_dlog(ctx, "blend_frames16() interpolate scene score:%f\n", interpolate_scene_score); + for (plane = 0; plane < 4 && td->copy_src1->data[plane] && td->copy_src2->data[plane]; plane++) { + int cpy_line_width = s->line_size[plane]; + uint8_t *cpy_src1_data = td->copy_src1->data[plane]; + int cpy_src1_line_size = td->copy_src1->linesize[plane]; + uint8_t *cpy_src2_data = td->copy_src2->data[plane]; + int cpy_src2_line_size = td->copy_src2->linesize[plane]; + int cpy_src_h = (plane > 0 && plane < 3) ? (td->copy_src1->height >> s->vsub) : (td->copy_src1->height); + uint8_t *cpy_dst_data = s->work->data[plane]; + int cpy_dst_line_size = s->work->linesize[plane]; + const int start = (cpy_src_h * job ) / nb_jobs; + const int end = (cpy_src_h * (job+1)) / nb_jobs; + cpy_src1_data += start * cpy_src1_line_size; + cpy_src2_data += start * cpy_src2_line_size; + cpy_dst_data += start * cpy_dst_line_size; + + s->blend(cpy_src1_data, cpy_src1_line_size, + cpy_src2_data, cpy_src2_line_size, + cpy_dst_data, cpy_dst_line_size, + cpy_line_width, end - start, + src1_factor, src2_factor, s->blend_factor_max >> 1); } - // decide if the shot-change detection allows us to blend two frames - if (interpolate_scene_score < s->scene_score && copy_src2) { - uint16_t src2_factor = fabsf(interpolate) * (1 << (s->bitdepth - 8)); - uint16_t src1_factor = s->max - src2_factor; - const int half = s->max / 2; - const int uv = (s->max + 1) * half; - const int shift = s->bitdepth; - int plane, line, pixel; - - // get work-space for output frame - s->work = ff_get_video_buffer(outlink, outlink->w, outlink->h); - if (!s->work) - return AVERROR(ENOMEM); - av_frame_copy_props(s->work, s->srce[s->crnt]); - - ff_dlog(ctx, "blend_frames16() INTERPOLATE to create work frame\n"); - for (plane = 0; plane < 4 && copy_src1->data[plane] && copy_src2->data[plane]; plane++) { - int cpy_line_width = s->line_size[plane]; - const uint16_t *cpy_src1_data = (const uint16_t *)copy_src1->data[plane]; - int cpy_src1_line_size = copy_src1->linesize[plane] / 2; - const uint16_t *cpy_src2_data = (const uint16_t *)copy_src2->data[plane]; - int cpy_src2_line_size = copy_src2->linesize[plane] / 2; - int cpy_src_h = (plane > 0 && plane < 3) ? (copy_src1->height >> s->vsub) : (copy_src1->height); - uint16_t *cpy_dst_data = (uint16_t *)s->work->data[plane]; - int cpy_dst_line_size = s->work->linesize[plane] / 2; - - if (plane <1 || plane >2) { - // luma or alpha - for (line = 0; line < cpy_src_h; line++) { - for (pixel = 0; pixel < cpy_line_width; pixel++) - cpy_dst_data[pixel] = ((cpy_src1_data[pixel] * src1_factor) + (cpy_src2_data[pixel] * src2_factor) + half) >> shift; - cpy_src1_data += cpy_src1_line_size; - cpy_src2_data += cpy_src2_line_size; - cpy_dst_data += cpy_dst_line_size; - } - } else { - // chroma - for (line = 0; line < cpy_src_h; line++) { - for (pixel = 0; pixel < cpy_line_width; pixel++) { - cpy_dst_data[pixel] = (((cpy_src1_data[pixel] - half) * src1_factor) + ((cpy_src2_data[pixel] - half) * src2_factor) + uv) >> shift; - } - cpy_src1_data += cpy_src1_line_size; - cpy_src2_data += cpy_src2_line_size; - cpy_dst_data += cpy_dst_line_size; - } - } - } - return 1; - } return 0; } -static int blend_frames8(AVFilterContext *ctx, float interpolate, - AVFrame *copy_src1, AVFrame *copy_src2) +static int blend_frames(AVFilterContext *ctx, int interpolate) { FrameRateContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; double interpolate_scene_score = 0; - if ((s->flags & FRAMERATE_FLAG_SCD) && copy_src2) { - interpolate_scene_score = get_scene_score(ctx, copy_src1, copy_src2); - ff_dlog(ctx, "blend_frames8() interpolate scene score:%f\n", interpolate_scene_score); + if ((s->flags & FRAMERATE_FLAG_SCD)) { + if (s->score >= 0.0) + interpolate_scene_score = s->score; + else + interpolate_scene_score = s->score = get_scene_score(ctx, s->f0, s->f1); + ff_dlog(ctx, "blend_frames() interpolate scene score:%f\n", interpolate_scene_score); } // decide if the shot-change detection allows us to blend two frames - if (interpolate_scene_score < s->scene_score && copy_src2) { - uint16_t src2_factor = fabsf(interpolate); - uint16_t src1_factor = 256 - src2_factor; - int plane, line, pixel; + if (interpolate_scene_score < s->scene_score) { + ThreadData td; + td.copy_src1 = s->f0; + td.copy_src2 = s->f1; + td.src2_factor = interpolate; + td.src1_factor = s->blend_factor_max - td.src2_factor; // get work-space for output frame s->work = ff_get_video_buffer(outlink, outlink->w, outlink->h); if (!s->work) return AVERROR(ENOMEM); - av_frame_copy_props(s->work, s->srce[s->crnt]); - - ff_dlog(ctx, "blend_frames8() INTERPOLATE to create work frame\n"); - for (plane = 0; plane < 4 && copy_src1->data[plane] && copy_src2->data[plane]; plane++) { - int cpy_line_width = s->line_size[plane]; - uint8_t *cpy_src1_data = copy_src1->data[plane]; - int cpy_src1_line_size = copy_src1->linesize[plane]; - uint8_t *cpy_src2_data = copy_src2->data[plane]; - int cpy_src2_line_size = copy_src2->linesize[plane]; - int cpy_src_h = (plane > 0 && plane < 3) ? (copy_src1->height >> s->vsub) : (copy_src1->height); - uint8_t *cpy_dst_data = s->work->data[plane]; - int cpy_dst_line_size = s->work->linesize[plane]; - if (plane <1 || plane >2) { - // luma or alpha - for (line = 0; line < cpy_src_h; line++) { - for (pixel = 0; pixel < cpy_line_width; pixel++) { - // integer version of (src1 * src1_factor) + (src2 + src2_factor) + 0.5 - // 0.5 is for rounding - // 128 is the integer representation of 0.5 << 8 - cpy_dst_data[pixel] = ((cpy_src1_data[pixel] * src1_factor) + (cpy_src2_data[pixel] * src2_factor) + 128) >> 8; - } - cpy_src1_data += cpy_src1_line_size; - cpy_src2_data += cpy_src2_line_size; - cpy_dst_data += cpy_dst_line_size; - } - } else { - // chroma - for (line = 0; line < cpy_src_h; line++) { - for (pixel = 0; pixel < cpy_line_width; pixel++) { - // as above - // because U and V are based around 128 we have to subtract 128 from the components. - // 32896 is the integer representation of 128.5 << 8 - cpy_dst_data[pixel] = (((cpy_src1_data[pixel] - 128) * src1_factor) + ((cpy_src2_data[pixel] - 128) * src2_factor) + 32896) >> 8; - } - cpy_src1_data += cpy_src1_line_size; - cpy_src2_data += cpy_src2_line_size; - cpy_dst_data += cpy_dst_line_size; - } - } - } + av_frame_copy_props(s->work, s->f0); + + ff_dlog(ctx, "blend_frames() INTERPOLATE to create work frame\n"); + ctx->internal->execute(ctx, filter_slice, &td, NULL, FFMIN(FFMAX(1, outlink->h >> 2), ff_filter_get_nb_threads(ctx))); return 1; } return 0; } -static int process_work_frame(AVFilterContext *ctx, int stop) +static int process_work_frame(AVFilterContext *ctx) { FrameRateContext *s = ctx->priv; - int64_t work_next_pts; - AVFrame *copy_src1; - float interpolate; - - ff_dlog(ctx, "process_work_frame()\n"); - - ff_dlog(ctx, "process_work_frame() pending_input_frames %d\n", s->pending_srce_frames); - - if (s->srce[s->prev]) ff_dlog(ctx, "process_work_frame() srce prev pts:%"PRId64"\n", s->srce[s->prev]->pts); - if (s->srce[s->crnt]) ff_dlog(ctx, "process_work_frame() srce crnt pts:%"PRId64"\n", s->srce[s->crnt]->pts); - if (s->srce[s->next]) ff_dlog(ctx, "process_work_frame() srce next pts:%"PRId64"\n", s->srce[s->next]->pts); + int64_t work_pts; + int64_t interpolate, interpolate8; + int ret; - if (!s->srce[s->crnt]) { - // the filter cannot do anything - ff_dlog(ctx, "process_work_frame() no current frame cached: move on to next frame, do not output a frame\n"); - next_source(ctx); + if (!s->f1) return 0; - } - - work_next_pts = s->pts + s->average_dest_pts_delta; - - ff_dlog(ctx, "process_work_frame() work crnt pts:%"PRId64"\n", s->pts); - ff_dlog(ctx, "process_work_frame() work next pts:%"PRId64"\n", work_next_pts); - if (s->srce[s->prev]) - ff_dlog(ctx, "process_work_frame() srce prev pts:%"PRId64" at dest time base:%u/%u\n", - s->srce_pts_dest[s->prev], s->dest_time_base.num, s->dest_time_base.den); - if (s->srce[s->crnt]) - ff_dlog(ctx, "process_work_frame() srce crnt pts:%"PRId64" at dest time base:%u/%u\n", - s->srce_pts_dest[s->crnt], s->dest_time_base.num, s->dest_time_base.den); - if (s->srce[s->next]) - ff_dlog(ctx, "process_work_frame() srce next pts:%"PRId64" at dest time base:%u/%u\n", - s->srce_pts_dest[s->next], s->dest_time_base.num, s->dest_time_base.den); - - av_assert0(s->srce[s->next]); - - // should filter be skipping input frame (output frame rate is lower than input frame rate) - if (!s->flush && s->pts >= s->srce_pts_dest[s->next]) { - ff_dlog(ctx, "process_work_frame() work crnt pts >= srce next pts: SKIP FRAME, move on to next frame, do not output a frame\n"); - next_source(ctx); - s->pending_srce_frames--; + if (!s->f0 && !s->flush) return 0; - } - // calculate interpolation - interpolate = ((s->pts - s->srce_pts_dest[s->crnt]) * 256.0 / s->average_srce_pts_dest_delta); - ff_dlog(ctx, "process_work_frame() interpolate:%f/256\n", interpolate); - copy_src1 = s->srce[s->crnt]; - if (interpolate > s->interp_end) { - ff_dlog(ctx, "process_work_frame() source is:NEXT\n"); - copy_src1 = s->srce[s->next]; - } - if (s->srce[s->prev] && interpolate < -s->interp_end) { - ff_dlog(ctx, "process_work_frame() source is:PREV\n"); - copy_src1 = s->srce[s->prev]; - } + work_pts = s->start_pts + av_rescale_q(s->n, av_inv_q(s->dest_frame_rate), s->dest_time_base); - // decide whether to blend two frames - if ((interpolate >= s->interp_start && interpolate <= s->interp_end) || (interpolate <= -s->interp_start && interpolate >= -s->interp_end)) { - AVFrame *copy_src2; + if (work_pts >= s->pts1 && !s->flush) + return 0; - if (interpolate > 0) { - ff_dlog(ctx, "process_work_frame() interpolate source is:NEXT\n"); - copy_src2 = s->srce[s->next]; + if (!s->f0) { + s->work = av_frame_clone(s->f1); + } else { + if (work_pts >= s->pts1 + s->delta && s->flush) + return 0; + + interpolate = av_rescale(work_pts - s->pts0, s->blend_factor_max, s->delta); + interpolate8 = av_rescale(work_pts - s->pts0, 256, s->delta); + ff_dlog(ctx, "process_work_frame() interpolate: %"PRId64"/256\n", interpolate8); + if (interpolate >= s->blend_factor_max || interpolate8 > s->interp_end) { + s->work = av_frame_clone(s->f1); + } else if (interpolate <= 0 || interpolate8 < s->interp_start) { + s->work = av_frame_clone(s->f0); } else { - ff_dlog(ctx, "process_work_frame() interpolate source is:PREV\n"); - copy_src2 = s->srce[s->prev]; + ret = blend_frames(ctx, interpolate); + if (ret < 0) + return ret; + if (ret == 0) + s->work = av_frame_clone(interpolate > (s->blend_factor_max >> 1) ? s->f1 : s->f0); } - if (s->blend_frames(ctx, interpolate, copy_src1, copy_src2)) - goto copy_done; - else - ff_dlog(ctx, "process_work_frame() CUT - DON'T INTERPOLATE\n"); } - ff_dlog(ctx, "process_work_frame() COPY to the work frame\n"); - // copy the frame we decided is our base source - s->work = av_frame_clone(copy_src1); if (!s->work) return AVERROR(ENOMEM); -copy_done: - s->work->pts = s->pts; - - // should filter be re-using input frame (output frame rate is higher than input frame rate) - if (!s->flush && (work_next_pts + s->average_dest_pts_delta) < (s->srce_pts_dest[s->crnt] + s->average_srce_pts_dest_delta)) { - ff_dlog(ctx, "process_work_frame() REPEAT FRAME\n"); - } else { - ff_dlog(ctx, "process_work_frame() CONSUME FRAME, move to next frame\n"); - s->pending_srce_frames--; - next_source(ctx); - } - ff_dlog(ctx, "process_work_frame() output a frame\n"); - s->dest_frame_num++; - if (stop) - s->pending_end_frame = 0; - s->last_dest_frame_pts = s->work->pts; + s->work->pts = work_pts; + s->n++; return 1; } -static void set_srce_frame_dest_pts(AVFilterContext *ctx) -{ - FrameRateContext *s = ctx->priv; - - ff_dlog(ctx, "set_srce_frame_output_pts()\n"); - - // scale the input pts from the timebase difference between input and output - if (s->srce[s->prev]) - s->srce_pts_dest[s->prev] = av_rescale_q(s->srce[s->prev]->pts, s->srce_time_base, s->dest_time_base); - if (s->srce[s->crnt]) - s->srce_pts_dest[s->crnt] = av_rescale_q(s->srce[s->crnt]->pts, s->srce_time_base, s->dest_time_base); - if (s->srce[s->next]) - s->srce_pts_dest[s->next] = av_rescale_q(s->srce[s->next]->pts, s->srce_time_base, s->dest_time_base); -} - -static void set_work_frame_pts(AVFilterContext *ctx) -{ - FrameRateContext *s = ctx->priv; - int64_t pts, average_srce_pts_delta = 0; - - ff_dlog(ctx, "set_work_frame_pts()\n"); - - av_assert0(s->srce[s->next]); - av_assert0(s->srce[s->crnt]); - - ff_dlog(ctx, "set_work_frame_pts() srce crnt pts:%"PRId64"\n", s->srce[s->crnt]->pts); - ff_dlog(ctx, "set_work_frame_pts() srce next pts:%"PRId64"\n", s->srce[s->next]->pts); - if (s->srce[s->prev]) - ff_dlog(ctx, "set_work_frame_pts() srce prev pts:%"PRId64"\n", s->srce[s->prev]->pts); - - average_srce_pts_delta = s->average_srce_pts_dest_delta; - ff_dlog(ctx, "set_work_frame_pts() initial average srce pts:%"PRId64"\n", average_srce_pts_delta); - - set_srce_frame_dest_pts(ctx); - - // calculate the PTS delta - if ((pts = (s->srce_pts_dest[s->next] - s->srce_pts_dest[s->crnt]))) { - average_srce_pts_delta = average_srce_pts_delta?((average_srce_pts_delta+pts)>>1):pts; - } else if (s->srce[s->prev] && (pts = (s->srce_pts_dest[s->crnt] - s->srce_pts_dest[s->prev]))) { - average_srce_pts_delta = average_srce_pts_delta?((average_srce_pts_delta+pts)>>1):pts; - } - - s->average_srce_pts_dest_delta = average_srce_pts_delta; - ff_dlog(ctx, "set_work_frame_pts() average srce pts:%"PRId64"\n", average_srce_pts_delta); - ff_dlog(ctx, "set_work_frame_pts() average srce pts:%"PRId64" at dest time base:%u/%u\n", - s->average_srce_pts_dest_delta, s->dest_time_base.num, s->dest_time_base.den); - - if (ctx->inputs[0] && !s->average_dest_pts_delta) { - int64_t d = av_q2d(av_inv_q(av_mul_q(s->dest_time_base, s->dest_frame_rate))); - s->average_dest_pts_delta = d; - ff_dlog(ctx, "set_work_frame_pts() average dest pts delta:%"PRId64"\n", s->average_dest_pts_delta); - } - - if (!s->dest_frame_num) { - s->pts = s->last_dest_frame_pts = s->srce_pts_dest[s->crnt]; - } else { - s->pts = s->last_dest_frame_pts + s->average_dest_pts_delta; - } - - ff_dlog(ctx, "set_work_frame_pts() calculated pts:%"PRId64" at dest time base:%u/%u\n", - s->pts, s->dest_time_base.num, s->dest_time_base.den); -} - static av_cold int init(AVFilterContext *ctx) { FrameRateContext *s = ctx->priv; - - s->dest_frame_num = 0; - - s->crnt = (N_SRCE)>>1; - s->last = N_SRCE - 1; - - s->next = s->crnt - 1; - s->prev = s->crnt + 1; - + s->start_pts = AV_NOPTS_VALUE; return 0; } static av_cold void uninit(AVFilterContext *ctx) { FrameRateContext *s = ctx->priv; - int i; - - for (i = s->frst; i < s->last; i++) { - if (s->srce[i] && (s->srce[i] != s->srce[i + 1])) - av_frame_free(&s->srce[i]); - } - av_frame_free(&s->srce[s->last]); + av_frame_free(&s->f0); + av_frame_free(&s->f1); } static int query_formats(AVFilterContext *ctx) @@ -554,6 +290,50 @@ static int query_formats(AVFilterContext *ctx) return ff_set_common_formats(ctx, fmts_list); } +static void blend_frames_c(BLEND_FUNC_PARAMS) +{ + int line, pixel; + for (line = 0; line < height; line++) { + for (pixel = 0; pixel < width; pixel++) + dst[pixel] = ((src1[pixel] * factor1) + (src2[pixel] * factor2) + half) >> BLEND_FACTOR_DEPTH8; + src1 += src1_linesize; + src2 += src2_linesize; + dst += dst_linesize; + } +} + +static void blend_frames16_c(BLEND_FUNC_PARAMS) +{ + int line, pixel; + uint16_t *dstw = (uint16_t *)dst; + uint16_t *src1w = (uint16_t *)src1; + uint16_t *src2w = (uint16_t *)src2; + width /= 2; + src1_linesize /= 2; + src2_linesize /= 2; + dst_linesize /= 2; + for (line = 0; line < height; line++) { + for (pixel = 0; pixel < width; pixel++) + dstw[pixel] = ((src1w[pixel] * factor1) + (src2w[pixel] * factor2) + half) >> BLEND_FACTOR_DEPTH16; + src1w += src1_linesize; + src2w += src2_linesize; + dstw += dst_linesize; + } +} + +void ff_framerate_init(FrameRateContext *s) +{ + if (s->bitdepth == 8) { + s->blend_factor_max = 1 << BLEND_FACTOR_DEPTH8; + s->blend = blend_frames_c; + } else { + s->blend_factor_max = 1 << BLEND_FACTOR_DEPTH16; + s->blend = blend_frames16_c; + } + if (ARCH_X86) + ff_framerate_init_x86(s); +} + static int config_input(AVFilterLink *inlink) { AVFilterContext *ctx = inlink->dst; @@ -575,11 +355,7 @@ static int config_input(AVFilterLink *inlink) s->srce_time_base = inlink->time_base; - if (s->bitdepth == 8) - s->blend_frames = blend_frames8; - else - s->blend_frames = blend_frames16; - s->max = 1 << (s->bitdepth); + ff_framerate_init(s); return 0; } @@ -589,28 +365,48 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *inpicref) int ret; AVFilterContext *ctx = inlink->dst; FrameRateContext *s = ctx->priv; - - // we have one new frame - s->pending_srce_frames++; + int64_t pts; if (inpicref->interlaced_frame) av_log(ctx, AV_LOG_WARNING, "Interlaced frame found - the output will not be correct.\n"); - // store the pointer to the new frame - av_frame_free(&s->srce[s->frst]); - s->srce[s->frst] = inpicref; + if (inpicref->pts == AV_NOPTS_VALUE) { + av_log(ctx, AV_LOG_WARNING, "Ignoring frame without PTS.\n"); + return 0; + } - if (!s->pending_end_frame && s->srce[s->crnt]) { - set_work_frame_pts(ctx); - s->pending_end_frame = 1; - } else { - set_srce_frame_dest_pts(ctx); + pts = av_rescale_q(inpicref->pts, s->srce_time_base, s->dest_time_base); + if (s->f1 && pts == s->pts1) { + av_log(ctx, AV_LOG_WARNING, "Ignoring frame with same PTS.\n"); + return 0; + } + + av_frame_free(&s->f0); + s->f0 = s->f1; + s->pts0 = s->pts1; + s->f1 = inpicref; + s->pts1 = pts; + s->delta = s->pts1 - s->pts0; + s->score = -1.0; + + if (s->delta < 0) { + av_log(ctx, AV_LOG_WARNING, "PTS discontinuity.\n"); + s->start_pts = s->pts1; + s->n = 0; + av_frame_free(&s->f0); } - ret = process_work_frame(ctx, 1); - if (ret < 0) - return ret; - return ret ? ff_filter_frame(ctx->outputs[0], s->work) : 0; + if (s->start_pts == AV_NOPTS_VALUE) + s->start_pts = s->pts1; + + do { + ret = process_work_frame(ctx); + if (ret <= 0) + return ret; + ret = ff_filter_frame(ctx->outputs[0], s->work); + } while (ret >= 0); + + return ret; } static int config_output(AVFilterLink *outlink) @@ -662,50 +458,21 @@ static int request_frame(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; FrameRateContext *s = ctx->priv; - int ret, i; + int ret; ff_dlog(ctx, "request_frame()\n"); - // if there is no "next" frame AND we are not in flush then get one from our input filter - if (!s->srce[s->frst] && !s->flush) - goto request; - - ff_dlog(ctx, "request_frame() REPEAT or FLUSH\n"); - - if (s->pending_srce_frames <= 0) { - ff_dlog(ctx, "request_frame() nothing else to do, return:EOF\n"); - return AVERROR_EOF; - } - - // otherwise, make brand-new frame and pass to our output filter - ff_dlog(ctx, "request_frame() FLUSH\n"); - - // back fill at end of file when source has no more frames - for (i = s->last; i > s->frst; i--) { - if (!s->srce[i - 1] && s->srce[i]) { - ff_dlog(ctx, "request_frame() copy:%d to:%d\n", i, i - 1); - s->srce[i - 1] = s->srce[i]; - } - } - - set_work_frame_pts(ctx); - ret = process_work_frame(ctx, 0); - if (ret < 0) - return ret; - if (ret) - return ff_filter_frame(ctx->outputs[0], s->work); - -request: - ff_dlog(ctx, "request_frame() call source's request_frame()\n"); ret = ff_request_frame(ctx->inputs[0]); - if (ret < 0 && (ret != AVERROR_EOF)) { - ff_dlog(ctx, "request_frame() source's request_frame() returned error:%d\n", ret); - return ret; - } else if (ret == AVERROR_EOF) { + if (ret == AVERROR_EOF && s->f1 && !s->flush) { s->flush = 1; + ret = process_work_frame(ctx); + if (ret < 0) + return ret; + ret = ret ? ff_filter_frame(ctx->outputs[0], s->work) : AVERROR_EOF; } + ff_dlog(ctx, "request_frame() source's request_frame() returned:%d\n", ret); - return 0; + return ret; } static const AVFilterPad framerate_inputs[] = { @@ -738,4 +505,5 @@ AVFilter ff_vf_framerate = { .query_formats = query_formats, .inputs = framerate_inputs, .outputs = framerate_outputs, + .flags = AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/vf_geq.c b/libavfilter/vf_geq.c index 36dbd421ce16c..2aa1259c9a780 100644 --- a/libavfilter/vf_geq.c +++ b/libavfilter/vf_geq.c @@ -33,11 +33,17 @@ #include "libavutil/pixdesc.h" #include "internal.h" +static const char *const var_names[] = { "X", "Y", "W", "H", "N", "SW", "SH", "T", NULL }; +enum { VAR_X, VAR_Y, VAR_W, VAR_H, VAR_N, VAR_SW, VAR_SH, VAR_T, VAR_VARS_NB }; + typedef struct GEQContext { const AVClass *class; AVExpr *e[4]; ///< expressions for each plane char *expr_str[4+3]; ///< expression strings for each plane AVFrame *picref; ///< current input buffer + uint8_t *dst; ///< reference pointer to the 8bits output + uint16_t *dst16; ///< reference pointer to the 16bits output + double values[VAR_VARS_NB]; ///< expression values int hsub, vsub; ///< chroma subsampling int planes; ///< number of planes int is_rgb; @@ -107,9 +113,6 @@ static double cb(void *priv, double x, double y) { return getpix(priv, x, y, 1) static double cr(void *priv, double x, double y) { return getpix(priv, x, y, 2); } static double alpha(void *priv, double x, double y) { return getpix(priv, x, y, 3); } -static const char *const var_names[] = { "X", "Y", "W", "H", "N", "SW", "SH", "T", NULL }; -enum { VAR_X, VAR_Y, VAR_W, VAR_H, VAR_N, VAR_SW, VAR_SH, VAR_T, VAR_VARS_NB }; - static av_cold int geq_init(AVFilterContext *ctx) { GEQContext *geq = ctx->priv; @@ -226,8 +229,62 @@ static int geq_config_props(AVFilterLink *inlink) geq->hsub = desc->log2_chroma_w; geq->vsub = desc->log2_chroma_h; + geq->bps = desc->comp[0].depth; geq->planes = desc->nb_components; - geq->bps = desc->comp[0].depth; + return 0; +} + +typedef struct ThreadData { + int height; + int width; + int plane; + int linesize; +} ThreadData; + +static int slice_geq_filter(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) +{ + GEQContext *geq = ctx->priv; + ThreadData *td = arg; + const int height = td->height; + const int width = td->width; + const int plane = td->plane; + const int linesize = td->linesize; + const int slice_start = (height * jobnr) / nb_jobs; + const int slice_end = (height * (jobnr+1)) / nb_jobs; + int x, y; + uint8_t *ptr; + uint16_t *ptr16; + + double values[VAR_VARS_NB]; + values[VAR_W] = geq->values[VAR_W]; + values[VAR_H] = geq->values[VAR_H]; + values[VAR_N] = geq->values[VAR_N]; + values[VAR_SW] = geq->values[VAR_SW]; + values[VAR_SH] = geq->values[VAR_SH]; + values[VAR_T] = geq->values[VAR_T]; + + if (geq->bps == 8) { + for (y = slice_start; y < slice_end; y++) { + ptr = geq->dst + linesize * y; + values[VAR_Y] = y; + + for (x = 0; x < width; x++) { + values[VAR_X] = x; + ptr[x] = av_expr_eval(geq->e[plane], values, geq); + } + ptr += linesize; + } + } + else { + for (y = slice_start; y < slice_end; y++) { + ptr16 = geq->dst16 + (linesize/2) * y; + values[VAR_Y] = y; + for (x = 0; x < width; x++) { + values[VAR_X] = x; + ptr16[x] = av_expr_eval(geq->e[plane], values, geq); + } + } + } return 0; } @@ -235,13 +292,14 @@ static int geq_config_props(AVFilterLink *inlink) static int geq_filter_frame(AVFilterLink *inlink, AVFrame *in) { int plane; - GEQContext *geq = inlink->dst->priv; + AVFilterContext *ctx = inlink->dst; + const int nb_threads = ff_filter_get_nb_threads(ctx); + GEQContext *geq = ctx->priv; AVFilterLink *outlink = inlink->dst->outputs[0]; AVFrame *out; - double values[VAR_VARS_NB] = { - [VAR_N] = inlink->frame_count_out, - [VAR_T] = in->pts == AV_NOPTS_VALUE ? NAN : in->pts * av_q2d(inlink->time_base), - }; + + geq->values[VAR_N] = inlink->frame_count_out, + geq->values[VAR_T] = in->pts == AV_NOPTS_VALUE ? NAN : in->pts * av_q2d(inlink->time_base), geq->picref = in; out = ff_get_video_buffer(outlink, outlink->w, outlink->h); @@ -252,34 +310,25 @@ static int geq_filter_frame(AVFilterLink *inlink, AVFrame *in) av_frame_copy_props(out, in); for (plane = 0; plane < geq->planes && out->data[plane]; plane++) { - int x, y; - uint8_t *dst = out->data[plane]; - uint16_t *dst16 = (uint16_t*)out->data[plane]; + const int width = (plane == 1 || plane == 2) ? AV_CEIL_RSHIFT(inlink->w, geq->hsub) : inlink->w; + const int height = (plane == 1 || plane == 2) ? AV_CEIL_RSHIFT(inlink->h, geq->vsub) : inlink->h; const int linesize = out->linesize[plane]; - const int w = (plane == 1 || plane == 2) ? AV_CEIL_RSHIFT(inlink->w, geq->hsub) : inlink->w; - const int h = (plane == 1 || plane == 2) ? AV_CEIL_RSHIFT(inlink->h, geq->vsub) : inlink->h; + ThreadData td; - values[VAR_W] = w; - values[VAR_H] = h; - values[VAR_SW] = w / (double)inlink->w; - values[VAR_SH] = h / (double)inlink->h; + geq->dst = out->data[plane]; + geq->dst16 = (uint16_t*)out->data[plane]; - for (y = 0; y < h; y++) { - values[VAR_Y] = y; - if (geq->bps > 8) { - for (x = 0; x < w; x++) { - values[VAR_X] = x; - dst16[x] = av_expr_eval(geq->e[plane], values, geq); - } - dst16 += linesize / 2; - } else { - for (x = 0; x < w; x++) { - values[VAR_X] = x; - dst[x] = av_expr_eval(geq->e[plane], values, geq); - } - dst += linesize; - } - } + geq->values[VAR_W] = width; + geq->values[VAR_H] = height; + geq->values[VAR_SW] = width / (double)inlink->w; + geq->values[VAR_SH] = height / (double)inlink->h; + + td.width = width; + td.height = height; + td.plane = plane; + td.linesize = linesize; + + ctx->internal->execute(ctx, slice_geq_filter, &td, NULL, FFMIN(height, nb_threads)); } av_frame_free(&geq->picref); @@ -323,5 +372,5 @@ AVFilter ff_vf_geq = { .inputs = geq_inputs, .outputs = geq_outputs, .priv_class = &geq_class, - .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC, + .flags = AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC | AVFILTER_FLAG_SLICE_THREADS, }; diff --git a/libavfilter/vf_hflip.c b/libavfilter/vf_hflip.c index cf20c193f7c10..b77afc77fc9ec 100644 --- a/libavfilter/vf_hflip.c +++ b/libavfilter/vf_hflip.c @@ -29,6 +29,7 @@ #include "libavutil/opt.h" #include "avfilter.h" #include "formats.h" +#include "hflip.h" #include "internal.h" #include "video.h" #include "libavutil/pixdesc.h" @@ -36,13 +37,6 @@ #include "libavutil/intreadwrite.h" #include "libavutil/imgutils.h" -typedef struct FlipContext { - const AVClass *class; - int max_step[4]; ///< max pixel step for each plane, expressed as a number of bytes - int planewidth[4]; ///< width of each plane - int planeheight[4]; ///< height of each plane -} FlipContext; - static const AVOption hflip_options[] = { { NULL } }; @@ -67,12 +61,77 @@ static int query_formats(AVFilterContext *ctx) return ff_set_common_formats(ctx, pix_fmts); } +static void hflip_byte_c(const uint8_t *src, uint8_t *dst, int w) +{ + int j; + + for (j = 0; j < w; j++) + dst[j] = src[-j]; +} + +static void hflip_short_c(const uint8_t *ssrc, uint8_t *ddst, int w) +{ + const uint16_t *src = (const uint16_t *)ssrc; + uint16_t *dst = (uint16_t *)ddst; + int j; + + for (j = 0; j < w; j++) + dst[j] = src[-j]; +} + +static void hflip_dword_c(const uint8_t *ssrc, uint8_t *ddst, int w) +{ + const uint32_t *src = (const uint32_t *)ssrc; + uint32_t *dst = (uint32_t *)ddst; + int j; + + for (j = 0; j < w; j++) + dst[j] = src[-j]; +} + +static void hflip_b24_c(const uint8_t *src, uint8_t *dst, int w) +{ + const uint8_t *in = src; + uint8_t *out = dst; + int j; + + for (j = 0; j < w; j++, out += 3, in -= 3) { + int32_t v = AV_RB24(in); + + AV_WB24(out, v); + } +} + +static void hflip_b48_c(const uint8_t *src, uint8_t *dst, int w) +{ + const uint8_t *in = src; + uint8_t *out = dst; + int j; + + for (j = 0; j < w; j++, out += 6, in -= 6) { + int64_t v = AV_RB48(in); + + AV_WB48(out, v); + } +} + +static void hflip_qword_c(const uint8_t *ssrc, uint8_t *ddst, int w) +{ + const uint64_t *src = (const uint64_t *)ssrc; + uint64_t *dst = (uint64_t *)ddst; + int j; + + for (j = 0; j < w; j++) + dst[j] = src[-j]; +} + static int config_props(AVFilterLink *inlink) { FlipContext *s = inlink->dst->priv; const AVPixFmtDescriptor *pix_desc = av_pix_fmt_desc_get(inlink->format); const int hsub = pix_desc->log2_chroma_w; const int vsub = pix_desc->log2_chroma_h; + int nb_planes; av_image_fill_max_pixsteps(s->max_step, NULL, pix_desc); s->planewidth[0] = s->planewidth[3] = inlink->w; @@ -80,6 +139,30 @@ static int config_props(AVFilterLink *inlink) s->planeheight[0] = s->planeheight[3] = inlink->h; s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, vsub); + nb_planes = av_pix_fmt_count_planes(inlink->format); + + return ff_hflip_init(s, s->max_step, nb_planes); +} + +int ff_hflip_init(FlipContext *s, int step[4], int nb_planes) +{ + int i; + + for (i = 0; i < nb_planes; i++) { + switch (step[i]) { + case 1: s->flip_line[i] = hflip_byte_c; break; + case 2: s->flip_line[i] = hflip_short_c; break; + case 3: s->flip_line[i] = hflip_b24_c; break; + case 4: s->flip_line[i] = hflip_dword_c; break; + case 6: s->flip_line[i] = hflip_b48_c; break; + case 8: s->flip_line[i] = hflip_qword_c; break; + default: + return AVERROR_BUG; + } + } + if (ARCH_X86) + ff_hflip_init_x86(s, step, nb_planes); + return 0; } @@ -94,7 +177,7 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int job, int nb_jobs) AVFrame *in = td->in; AVFrame *out = td->out; uint8_t *inrow, *outrow; - int i, j, plane, step; + int i, plane, step; for (plane = 0; plane < 4 && in->data[plane] && in->linesize[plane]; plane++) { const int width = s->planewidth[plane]; @@ -107,45 +190,7 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int job, int nb_jobs) outrow = out->data[plane] + start * out->linesize[plane]; inrow = in ->data[plane] + start * in->linesize[plane] + (width - 1) * step; for (i = start; i < end; i++) { - switch (step) { - case 1: - for (j = 0; j < width; j++) - outrow[j] = inrow[-j]; - break; - - case 2: - { - uint16_t *outrow16 = (uint16_t *)outrow; - uint16_t * inrow16 = (uint16_t *) inrow; - for (j = 0; j < width; j++) - outrow16[j] = inrow16[-j]; - } - break; - - case 3: - { - uint8_t *in = inrow; - uint8_t *out = outrow; - for (j = 0; j < width; j++, out += 3, in -= 3) { - int32_t v = AV_RB24(in); - AV_WB24(out, v); - } - } - break; - - case 4: - { - uint32_t *outrow32 = (uint32_t *)outrow; - uint32_t * inrow32 = (uint32_t *) inrow; - for (j = 0; j < width; j++) - outrow32[j] = inrow32[-j]; - } - break; - - default: - for (j = 0; j < width; j++) - memcpy(outrow + j*step, inrow - j*step, step); - } + s->flip_line[plane](inrow, outrow, width); inrow += in ->linesize[plane]; outrow += out->linesize[plane]; diff --git a/libavfilter/vf_hwmap.c b/libavfilter/vf_hwmap.c index 8277241dc4e1f..290559a06ab9f 100644 --- a/libavfilter/vf_hwmap.c +++ b/libavfilter/vf_hwmap.c @@ -114,7 +114,8 @@ static int hwmap_config_output(AVFilterLink *outlink) err = av_hwframe_ctx_create_derived(&ctx->hwframes_ref, outlink->format, device, - inlink->hw_frames_ctx, 0); + inlink->hw_frames_ctx, + ctx->mode); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to create derived " "frames context: %d.\n", err); @@ -142,7 +143,9 @@ static int hwmap_config_output(AVFilterLink *outlink) frames->sw_format = hwfc->sw_format; frames->width = hwfc->width; frames->height = hwfc->height; - frames->initial_pool_size = 64; + + if (avctx->extra_hw_frames >= 0) + frames->initial_pool_size = 2 + avctx->extra_hw_frames; err = av_hwframe_ctx_init(ctx->hwframes_ref); if (err < 0) { @@ -222,6 +225,9 @@ static int hwmap_config_output(AVFilterLink *outlink) hwfc->width = inlink->w; hwfc->height = inlink->h; + if (avctx->extra_hw_frames >= 0) + hwfc->initial_pool_size = 2 + avctx->extra_hw_frames; + err = av_hwframe_ctx_init(ctx->hwframes_ref); if (err < 0) { av_log(avctx, AV_LOG_ERROR, "Failed to create frame " diff --git a/libavfilter/vf_hwupload.c b/libavfilter/vf_hwupload.c index 157686b7b3b81..50bc7e10f6eb9 100644 --- a/libavfilter/vf_hwupload.c +++ b/libavfilter/vf_hwupload.c @@ -131,6 +131,9 @@ static int hwupload_config_output(AVFilterLink *outlink) ctx->hwframes->width = inlink->w; ctx->hwframes->height = inlink->h; + if (avctx->extra_hw_frames >= 0) + ctx->hwframes->initial_pool_size = 2 + avctx->extra_hw_frames; + err = av_hwframe_ctx_init(ctx->hwframes_ref); if (err < 0) goto fail; diff --git a/libavfilter/vf_hysteresis.c b/libavfilter/vf_hysteresis.c index a788e1b9ee64b..551b33f33258b 100644 --- a/libavfilter/vf_hysteresis.c +++ b/libavfilter/vf_hysteresis.c @@ -33,6 +33,7 @@ typedef struct HysteresisContext { const AVClass *class; + FFFrameSync fs; int planes; int threshold; @@ -40,7 +41,6 @@ typedef struct HysteresisContext { int width[4], height[4]; int nb_planes; int depth; - FFFrameSync fs; uint8_t *map; uint32_t *xy; @@ -58,8 +58,6 @@ static const AVOption hysteresis_options[] = { { NULL } }; -AVFILTER_DEFINE_CLASS(hysteresis); - static int query_formats(AVFilterContext *ctx) { static const enum AVPixelFormat pix_fmts[] = { @@ -301,20 +299,13 @@ static int config_output(AVFilterLink *outlink) av_log(ctx, AV_LOG_ERROR, "inputs must be of same pixel format\n"); return AVERROR(EINVAL); } - if (base->w != alt->w || - base->h != alt->h || - base->sample_aspect_ratio.num != alt->sample_aspect_ratio.num || - base->sample_aspect_ratio.den != alt->sample_aspect_ratio.den) { + if (base->w != alt->w || base->h != alt->h) { av_log(ctx, AV_LOG_ERROR, "First input link %s parameters " - "(size %dx%d, SAR %d:%d) do not match the corresponding " - "second input link %s parameters (%dx%d, SAR %d:%d)\n", + "(size %dx%d) do not match the corresponding " + "second input link %s parameters (size %dx%d)\n", ctx->input_pads[0].name, base->w, base->h, - base->sample_aspect_ratio.num, - base->sample_aspect_ratio.den, ctx->input_pads[1].name, - alt->w, alt->h, - alt->sample_aspect_ratio.num, - alt->sample_aspect_ratio.den); + alt->w, alt->h); return AVERROR(EINVAL); } @@ -357,6 +348,8 @@ static av_cold void uninit(AVFilterContext *ctx) av_freep(&s->xy); } +FRAMESYNC_DEFINE_CLASS(hysteresis, HysteresisContext, fs); + static const AVFilterPad hysteresis_inputs[] = { { .name = "base", @@ -382,6 +375,7 @@ static const AVFilterPad hysteresis_outputs[] = { AVFilter ff_vf_hysteresis = { .name = "hysteresis", .description = NULL_IF_CONFIG_SMALL("Grow first stream into second stream by connecting components."), + .preinit = hysteresis_framesync_preinit, .priv_size = sizeof(HysteresisContext), .uninit = uninit, .query_formats = query_formats, diff --git a/libavfilter/vf_idet.c b/libavfilter/vf_idet.c index 14f031aaa9570..02ae2edcb99ec 100644 --- a/libavfilter/vf_idet.c +++ b/libavfilter/vf_idet.c @@ -392,6 +392,8 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUV444P16, AV_PIX_FMT_YUVA420P, + AV_PIX_FMT_YUVA422P, + AV_PIX_FMT_YUVA444P, AV_PIX_FMT_NONE }; AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); diff --git a/libavfilter/vf_interlace.c b/libavfilter/vf_interlace.c index 731069818f227..24c422ded2665 100644 --- a/libavfilter/vf_interlace.c +++ b/libavfilter/vf_interlace.c @@ -185,6 +185,25 @@ static av_cold void uninit(AVFilterContext *ctx) av_frame_free(&s->next); } +void ff_interlace_init(InterlaceContext *s, int depth) +{ + if (s->lowpass) { + if (s->lowpass == VLPF_LIN) { + if (depth > 8) + s->lowpass_line = lowpass_line_c_16; + else + s->lowpass_line = lowpass_line_c; + } else if (s->lowpass == VLPF_CMP) { + if (depth > 8) + s->lowpass_line = lowpass_line_complex_c_16; + else + s->lowpass_line = lowpass_line_complex_c; + } + if (ARCH_X86) + ff_interlace_init_x86(s, depth); + } +} + static int config_out_props(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; @@ -210,21 +229,7 @@ static int config_out_props(AVFilterLink *outlink) outlink->frame_rate.den *= 2; s->csp = av_pix_fmt_desc_get(outlink->format); - if (s->lowpass) { - if (s->lowpass == VLPF_LIN) { - if (s->csp->comp[0].depth > 8) - s->lowpass_line = lowpass_line_c_16; - else - s->lowpass_line = lowpass_line_c; - } else if (s->lowpass == VLPF_CMP) { - if (s->csp->comp[0].depth > 8) - s->lowpass_line = lowpass_line_complex_c_16; - else - s->lowpass_line = lowpass_line_complex_c; - } - if (ARCH_X86) - ff_interlace_init_x86(s); - } + ff_interlace_init(s, s->csp->comp[0].depth); av_log(ctx, AV_LOG_VERBOSE, "%s interlacing %s lowpass filter\n", s->scan == MODE_TFF ? "tff" : "bff", (s->lowpass) ? "with" : "without"); diff --git a/libavfilter/vf_libvmaf.c b/libavfilter/vf_libvmaf.c index 2c3a9f33493ad..42c6b66b69a53 100644 --- a/libavfilter/vf_libvmaf.c +++ b/libavfilter/vf_libvmaf.c @@ -40,7 +40,6 @@ typedef struct LIBVMAFContext { const AVClass *class; FFFrameSync fs; const AVPixFmtDescriptor *desc; - char *format; int width; int height; double vmaf_score; @@ -62,6 +61,7 @@ typedef struct LIBVMAFContext { int ssim; int ms_ssim; char *pool; + int error; } LIBVMAFContext; #define OFFSET(x) offsetof(LIBVMAFContext, x) @@ -130,6 +130,8 @@ FRAMESYNC_DEFINE_CLASS(libvmaf, LIBVMAFContext, fs); \ ret = !s->frame_set; \ \ + av_frame_unref(s->gref); \ + av_frame_unref(s->gmain); \ s->frame_set = 0; \ \ pthread_cond_signal(&s->cond); \ @@ -149,6 +151,7 @@ static void compute_vmaf_score(LIBVMAFContext *s) { int (*read_frame)(float *ref_data, float *main_data, float *temp_data, int stride, void *ctx); + char *format; if (s->desc->comp[0].depth <= 8) { read_frame = read_frame_8bit; @@ -156,48 +159,65 @@ static void compute_vmaf_score(LIBVMAFContext *s) read_frame = read_frame_10bit; } - s->vmaf_score = compute_vmaf(s->format, s->width, s->height, read_frame, s, - s->model_path, s->log_path, s->log_fmt, 0, 0, - s->enable_transform, s->phone_model, s->psnr, - s->ssim, s->ms_ssim, s->pool); + format = (char *) s->desc->name; + + s->error = compute_vmaf(&s->vmaf_score, format, s->width, s->height, + read_frame, s, s->model_path, s->log_path, + s->log_fmt, 0, 0, s->enable_transform, + s->phone_model, s->psnr, s->ssim, + s->ms_ssim, s->pool); } static void *call_vmaf(void *ctx) { LIBVMAFContext *s = (LIBVMAFContext *) ctx; compute_vmaf_score(s); - av_log(ctx, AV_LOG_INFO, "VMAF score: %f\n",s->vmaf_score); + if (!s->error) { + av_log(ctx, AV_LOG_INFO, "VMAF score: %f\n",s->vmaf_score); + } else { + pthread_mutex_lock(&s->lock); + pthread_cond_signal(&s->cond); + pthread_mutex_unlock(&s->lock); + } pthread_exit(NULL); + return NULL; } static int do_vmaf(FFFrameSync *fs) { AVFilterContext *ctx = fs->parent; LIBVMAFContext *s = ctx->priv; - AVFrame *main, *ref; + AVFrame *master, *ref; int ret; - ret = ff_framesync_dualinput_get(fs, &main, &ref); + ret = ff_framesync_dualinput_get(fs, &master, &ref); if (ret < 0) return ret; if (!ref) - return ff_filter_frame(ctx->outputs[0], main); + return ff_filter_frame(ctx->outputs[0], master); pthread_mutex_lock(&s->lock); - while (s->frame_set != 0) { + while (s->frame_set && !s->error) { pthread_cond_wait(&s->cond, &s->lock); } + if (s->error) { + av_log(ctx, AV_LOG_ERROR, + "libvmaf encountered an error, check log for details\n"); + pthread_mutex_unlock(&s->lock); + return AVERROR(EINVAL); + } + av_frame_ref(s->gref, ref); - av_frame_ref(s->gmain, main); + av_frame_ref(s->gmain, master); s->frame_set = 1; pthread_cond_signal(&s->cond); pthread_mutex_unlock(&s->lock); - return ff_filter_frame(ctx->outputs[0], main); + return ff_filter_frame(ctx->outputs[0], master); } static av_cold int init(AVFilterContext *ctx) @@ -206,6 +226,7 @@ static av_cold int init(AVFilterContext *ctx) s->gref = av_frame_alloc(); s->gmain = av_frame_alloc(); + s->error = 0; pthread_mutex_init(&s->lock, NULL); pthread_cond_init (&s->cond, NULL); @@ -258,7 +279,6 @@ static int config_input_ref(AVFilterLink *inlink) return 0; } - static int config_output(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; diff --git a/libavfilter/vf_lut.c b/libavfilter/vf_lut.c index 11c039ead771a..26f2945c847f0 100644 --- a/libavfilter/vf_lut.c +++ b/libavfilter/vf_lut.c @@ -135,9 +135,13 @@ static av_cold void uninit(AVFilterContext *ctx) AV_PIX_FMT_GBRP16LE, AV_PIX_FMT_GBRAP12LE, \ AV_PIX_FMT_GBRAP16LE +#define GRAY_FORMATS \ + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9LE, AV_PIX_FMT_GRAY10LE, \ + AV_PIX_FMT_GRAY12LE, AV_PIX_FMT_GRAY16LE + static const enum AVPixelFormat yuv_pix_fmts[] = { YUV_FORMATS, AV_PIX_FMT_NONE }; static const enum AVPixelFormat rgb_pix_fmts[] = { RGB_FORMATS, AV_PIX_FMT_NONE }; -static const enum AVPixelFormat all_pix_fmts[] = { RGB_FORMATS, YUV_FORMATS, AV_PIX_FMT_NONE }; +static const enum AVPixelFormat all_pix_fmts[] = { RGB_FORMATS, YUV_FORMATS, GRAY_FORMATS, AV_PIX_FMT_NONE }; static int query_formats(AVFilterContext *ctx) { diff --git a/libavfilter/vf_lut2.c b/libavfilter/vf_lut2.c index 585d121ca3539..1385cba9b129d 100644 --- a/libavfilter/vf_lut2.c +++ b/libavfilter/vf_lut2.c @@ -304,20 +304,13 @@ static int lut2_config_output(AVFilterLink *outlink) av_log(ctx, AV_LOG_ERROR, "inputs must be of same pixel format\n"); return AVERROR(EINVAL); } - if (srcx->w != srcy->w || - srcx->h != srcy->h || - srcx->sample_aspect_ratio.num != srcy->sample_aspect_ratio.num || - srcx->sample_aspect_ratio.den != srcy->sample_aspect_ratio.den) { + if (srcx->w != srcy->w || srcx->h != srcy->h) { av_log(ctx, AV_LOG_ERROR, "First input link %s parameters " - "(size %dx%d, SAR %d:%d) do not match the corresponding " - "second input link %s parameters (%dx%d, SAR %d:%d)\n", + "(size %dx%d) do not match the corresponding " + "second input link %s parameters (size %dx%d)\n", ctx->input_pads[0].name, srcx->w, srcx->h, - srcx->sample_aspect_ratio.num, - srcx->sample_aspect_ratio.den, ctx->input_pads[1].name, - srcy->w, srcy->h, - srcy->sample_aspect_ratio.num, - srcy->sample_aspect_ratio.den); + srcy->w, srcy->h); return AVERROR(EINVAL); } diff --git a/libavfilter/vf_maskedclamp.c b/libavfilter/vf_maskedclamp.c index 67a979f8c06ae..9812e08533a7c 100644 --- a/libavfilter/vf_maskedclamp.c +++ b/libavfilter/vf_maskedclamp.c @@ -235,27 +235,15 @@ static int config_output(AVFilterLink *outlink) av_log(ctx, AV_LOG_ERROR, "inputs must be of same pixel format\n"); return AVERROR(EINVAL); } - if (base->w != dark->w || - base->h != dark->h || - base->sample_aspect_ratio.num != dark->sample_aspect_ratio.num || - base->sample_aspect_ratio.den != dark->sample_aspect_ratio.den || - base->w != bright->w || - base->h != bright->h || - base->sample_aspect_ratio.num != bright->sample_aspect_ratio.num || - base->sample_aspect_ratio.den != bright->sample_aspect_ratio.den) { + if (base->w != dark->w || base->h != dark->h || + base->w != bright->w || base->h != bright->h) { av_log(ctx, AV_LOG_ERROR, "First input link %s parameters " - "(size %dx%d, SAR %d:%d) do not match the corresponding " - "second input link %s parameters (%dx%d, SAR %d:%d) " - "and/or third input link %s parameters (%dx%d, SAR %d:%d)\n", + "(size %dx%d) do not match the corresponding " + "second input link %s parameters (%dx%d) " + "and/or third input link %s parameters (size %dx%d)\n", ctx->input_pads[0].name, base->w, base->h, - base->sample_aspect_ratio.num, - base->sample_aspect_ratio.den, ctx->input_pads[1].name, dark->w, dark->h, - dark->sample_aspect_ratio.num, - dark->sample_aspect_ratio.den, - ctx->input_pads[2].name, bright->w, bright->h, - bright->sample_aspect_ratio.num, - bright->sample_aspect_ratio.den); + ctx->input_pads[2].name, bright->w, bright->h); return AVERROR(EINVAL); } diff --git a/libavfilter/vf_maskedmerge.c b/libavfilter/vf_maskedmerge.c index d31b92659e2f4..86559abdacf19 100644 --- a/libavfilter/vf_maskedmerge.c +++ b/libavfilter/vf_maskedmerge.c @@ -199,27 +199,15 @@ static int config_output(AVFilterLink *outlink) av_log(ctx, AV_LOG_ERROR, "inputs must be of same pixel format\n"); return AVERROR(EINVAL); } - if (base->w != overlay->w || - base->h != overlay->h || - base->sample_aspect_ratio.num != overlay->sample_aspect_ratio.num || - base->sample_aspect_ratio.den != overlay->sample_aspect_ratio.den || - base->w != mask->w || - base->h != mask->h || - base->sample_aspect_ratio.num != mask->sample_aspect_ratio.num || - base->sample_aspect_ratio.den != mask->sample_aspect_ratio.den) { + if (base->w != overlay->w || base->h != overlay->h || + base->w != mask->w || base->h != mask->h) { av_log(ctx, AV_LOG_ERROR, "First input link %s parameters " - "(size %dx%d, SAR %d:%d) do not match the corresponding " - "second input link %s parameters (%dx%d, SAR %d:%d) " - "and/or third input link %s parameters (%dx%d, SAR %d:%d)\n", + "(size %dx%d) do not match the corresponding " + "second input link %s parameters (size %dx%d) " + "and/or third input link %s parameters (size %dx%d)\n", ctx->input_pads[0].name, base->w, base->h, - base->sample_aspect_ratio.num, - base->sample_aspect_ratio.den, ctx->input_pads[1].name, overlay->w, overlay->h, - overlay->sample_aspect_ratio.num, - overlay->sample_aspect_ratio.den, - ctx->input_pads[2].name, mask->w, mask->h, - mask->sample_aspect_ratio.num, - mask->sample_aspect_ratio.den); + ctx->input_pads[2].name, mask->w, mask->h); return AVERROR(EINVAL); } diff --git a/libavfilter/vf_minterpolate.c b/libavfilter/vf_minterpolate.c index 6c5c26400557d..d53431593d136 100644 --- a/libavfilter/vf_minterpolate.c +++ b/libavfilter/vf_minterpolate.c @@ -145,12 +145,18 @@ typedef struct Block { struct Block *subs; } Block; -typedef struct Pixel { +typedef struct PixelMVS { int16_t mvs[NB_PIXEL_MVS][2]; +} PixelMVS; + +typedef struct PixelWeights { uint32_t weights[NB_PIXEL_MVS]; +} PixelWeights; + +typedef struct PixelRefs { int8_t refs[NB_PIXEL_MVS]; int nb; -} Pixel; +} PixelRefs; typedef struct Frame { AVFrame *avf; @@ -172,7 +178,9 @@ typedef struct MIContext { Frame frames[NB_FRAMES]; Cluster clusters[NB_CLUSTERS]; Block *int_blocks; - Pixel *pixels; + PixelMVS *pixel_mvs; + PixelWeights *pixel_weights; + PixelRefs *pixel_refs; int (*mv_table[3])[2][2]; int64_t out_pts; int b_width, b_height, b_count; @@ -331,7 +339,7 @@ static int config_input(AVFilterLink *inlink) const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); const int height = inlink->h; const int width = inlink->w; - int i; + int i, ret = 0; mi_ctx->log2_chroma_h = desc->log2_chroma_h; mi_ctx->log2_chroma_w = desc->log2_chroma_w; @@ -353,8 +361,13 @@ static int config_input(AVFilterLink *inlink) } if (mi_ctx->mi_mode == MI_MODE_MCI) { - if (!(mi_ctx->pixels = av_mallocz_array(width * height, sizeof(Pixel)))) - return AVERROR(ENOMEM); + mi_ctx->pixel_mvs = av_mallocz_array(width * height, sizeof(PixelMVS)); + mi_ctx->pixel_weights = av_mallocz_array(width * height, sizeof(PixelWeights)); + mi_ctx->pixel_refs = av_mallocz_array(width * height, sizeof(PixelRefs)); + if (!mi_ctx->pixel_mvs || !mi_ctx->pixel_weights || !mi_ctx->pixel_refs) { + ret = AVERROR(ENOMEM); + goto fail; + } if (mi_ctx->me_mode == ME_MODE_BILAT) if (!(mi_ctx->int_blocks = av_mallocz_array(mi_ctx->b_count, sizeof(Block)))) @@ -383,6 +396,13 @@ static int config_input(AVFilterLink *inlink) me_ctx->get_cost = &get_sbad_ob; return 0; +fail: + for (i = 0; i < NB_FRAMES; i++) + av_freep(&mi_ctx->frames[i].blocks); + av_freep(&mi_ctx->pixel_mvs); + av_freep(&mi_ctx->pixel_weights); + av_freep(&mi_ctx->pixel_refs); + return ret; } static int config_output(AVFilterLink *outlink) @@ -833,18 +853,18 @@ static int detect_scene_change(MIContext *mi_ctx) #define ADD_PIXELS(b_weight, mv_x, mv_y)\ do {\ - if (!b_weight || pixel->nb + 1 >= NB_PIXEL_MVS)\ + if (!b_weight || pixel_refs->nb + 1 >= NB_PIXEL_MVS)\ continue;\ - pixel->refs[pixel->nb] = 1;\ - pixel->weights[pixel->nb] = b_weight * (ALPHA_MAX - alpha);\ - pixel->mvs[pixel->nb][0] = av_clip((mv_x * alpha) / ALPHA_MAX, x_min, x_max);\ - pixel->mvs[pixel->nb][1] = av_clip((mv_y * alpha) / ALPHA_MAX, y_min, y_max);\ - pixel->nb++;\ - pixel->refs[pixel->nb] = 2;\ - pixel->weights[pixel->nb] = b_weight * alpha;\ - pixel->mvs[pixel->nb][0] = av_clip(-mv_x * (ALPHA_MAX - alpha) / ALPHA_MAX, x_min, x_max);\ - pixel->mvs[pixel->nb][1] = av_clip(-mv_y * (ALPHA_MAX - alpha) / ALPHA_MAX, y_min, y_max);\ - pixel->nb++;\ + pixel_refs->refs[pixel_refs->nb] = 1;\ + pixel_weights->weights[pixel_refs->nb] = b_weight * (ALPHA_MAX - alpha);\ + pixel_mvs->mvs[pixel_refs->nb][0] = av_clip((mv_x * alpha) / ALPHA_MAX, x_min, x_max);\ + pixel_mvs->mvs[pixel_refs->nb][1] = av_clip((mv_y * alpha) / ALPHA_MAX, y_min, y_max);\ + pixel_refs->nb++;\ + pixel_refs->refs[pixel_refs->nb] = 2;\ + pixel_weights->weights[pixel_refs->nb] = b_weight * alpha;\ + pixel_mvs->mvs[pixel_refs->nb][0] = av_clip(-mv_x * (ALPHA_MAX - alpha) / ALPHA_MAX, x_min, x_max);\ + pixel_mvs->mvs[pixel_refs->nb][1] = av_clip(-mv_y * (ALPHA_MAX - alpha) / ALPHA_MAX, y_min, y_max);\ + pixel_refs->nb++;\ } while(0) static void bidirectional_obmc(MIContext *mi_ctx, int alpha) @@ -856,7 +876,7 @@ static void bidirectional_obmc(MIContext *mi_ctx, int alpha) for (y = 0; y < height; y++) for (x = 0; x < width; x++) - mi_ctx->pixels[x + y * width].nb = 0; + mi_ctx->pixel_refs[x + y * width].nb = 0; for (dir = 0; dir < 2; dir++) for (mb_y = 0; mb_y < mi_ctx->b_height; mb_y++) @@ -887,7 +907,9 @@ static void bidirectional_obmc(MIContext *mi_ctx, int alpha) int x_min = -x; int x_max = width - x - 1; int obmc_weight = obmc_tab_linear[4 - mi_ctx->log2_mb_size][(x - start_x) + ((y - start_y) << (mi_ctx->log2_mb_size + 1))]; - Pixel *pixel = &mi_ctx->pixels[x + y * width]; + PixelMVS *pixel_mvs = &mi_ctx->pixel_mvs[x + y * width]; + PixelWeights *pixel_weights = &mi_ctx->pixel_weights[x + y * width]; + PixelRefs *pixel_refs = &mi_ctx->pixel_refs[x + y * width]; ADD_PIXELS(obmc_weight, mv_x, mv_y); } @@ -909,36 +931,38 @@ static void set_frame_data(MIContext *mi_ctx, int alpha, AVFrame *avf_out) int x_mv, y_mv; int weight_sum = 0; int i, val = 0; - Pixel *pixel = &mi_ctx->pixels[x + y * avf_out->width]; - - for (i = 0; i < pixel->nb; i++) - weight_sum += pixel->weights[i]; - - if (!weight_sum || !pixel->nb) { - pixel->weights[0] = ALPHA_MAX - alpha; - pixel->refs[0] = 1; - pixel->mvs[0][0] = 0; - pixel->mvs[0][1] = 0; - pixel->weights[1] = alpha; - pixel->refs[1] = 2; - pixel->mvs[1][0] = 0; - pixel->mvs[1][1] = 0; - pixel->nb = 2; + PixelMVS *pixel_mvs = &mi_ctx->pixel_mvs[x + y * avf_out->width]; + PixelWeights *pixel_weights = &mi_ctx->pixel_weights[x + y * avf_out->width]; + PixelRefs *pixel_refs = &mi_ctx->pixel_refs[x + y * avf_out->width]; + + for (i = 0; i < pixel_refs->nb; i++) + weight_sum += pixel_weights->weights[i]; + + if (!weight_sum || !pixel_refs->nb) { + pixel_weights->weights[0] = ALPHA_MAX - alpha; + pixel_refs->refs[0] = 1; + pixel_mvs->mvs[0][0] = 0; + pixel_mvs->mvs[0][1] = 0; + pixel_weights->weights[1] = alpha; + pixel_refs->refs[1] = 2; + pixel_mvs->mvs[1][0] = 0; + pixel_mvs->mvs[1][1] = 0; + pixel_refs->nb = 2; weight_sum = ALPHA_MAX; } - for (i = 0; i < pixel->nb; i++) { - Frame *frame = &mi_ctx->frames[pixel->refs[i]]; + for (i = 0; i < pixel_refs->nb; i++) { + Frame *frame = &mi_ctx->frames[pixel_refs->refs[i]]; if (chroma) { - x_mv = (x >> mi_ctx->log2_chroma_w) + pixel->mvs[i][0] / (1 << mi_ctx->log2_chroma_w); - y_mv = (y >> mi_ctx->log2_chroma_h) + pixel->mvs[i][1] / (1 << mi_ctx->log2_chroma_h); + x_mv = (x >> mi_ctx->log2_chroma_w) + pixel_mvs->mvs[i][0] / (1 << mi_ctx->log2_chroma_w); + y_mv = (y >> mi_ctx->log2_chroma_h) + pixel_mvs->mvs[i][1] / (1 << mi_ctx->log2_chroma_h); } else { - x_mv = x + pixel->mvs[i][0]; - y_mv = y + pixel->mvs[i][1]; + x_mv = x + pixel_mvs->mvs[i][0]; + y_mv = y + pixel_mvs->mvs[i][1]; } - val += pixel->weights[i] * frame->avf->data[plane][x_mv + y_mv * frame->avf->linesize[plane]]; + val += pixel_weights->weights[i] * frame->avf->data[plane][x_mv + y_mv * frame->avf->linesize[plane]]; } val = ROUNDED_DIV(val, weight_sum); @@ -979,7 +1003,9 @@ static void var_size_bmc(MIContext *mi_ctx, Block *block, int x_mb, int y_mb, in for (x = start_x; x < end_x; x++) { int x_min = -x; int x_max = width - x - 1; - Pixel *pixel = &mi_ctx->pixels[x + y * width]; + PixelMVS *pixel_mvs = &mi_ctx->pixel_mvs[x + y * width]; + PixelWeights *pixel_weights = &mi_ctx->pixel_weights[x + y * width]; + PixelRefs *pixel_refs = &mi_ctx->pixel_refs[x + y * width]; ADD_PIXELS(PX_WEIGHT_MAX, mv_x, mv_y); } @@ -1028,7 +1054,9 @@ static void bilateral_obmc(MIContext *mi_ctx, Block *block, int mb_x, int mb_y, int x_min = -x; int x_max = width - x - 1; int obmc_weight = obmc_tab_linear[4 - mi_ctx->log2_mb_size][(x - start_x) + ((y - start_y) << (mi_ctx->log2_mb_size + 1))]; - Pixel *pixel = &mi_ctx->pixels[x + y * width]; + PixelMVS *pixel_mvs = &mi_ctx->pixel_mvs[x + y * width]; + PixelWeights *pixel_weights = &mi_ctx->pixel_weights[x + y * width]; + PixelRefs *pixel_refs = &mi_ctx->pixel_refs[x + y * width]; if (mi_ctx->mc_mode == MC_MODE_AOBMC) { nb_x = (((x - start_x) >> (mi_ctx->log2_mb_size - 1)) * 2 - 3) / 2; @@ -1112,7 +1140,7 @@ static void interpolate(AVFilterLink *inlink, AVFrame *avf_out) for (y = 0; y < mi_ctx->frames[0].avf->height; y++) for (x = 0; x < mi_ctx->frames[0].avf->width; x++) - mi_ctx->pixels[x + y * mi_ctx->frames[0].avf->width].nb = 0; + mi_ctx->pixel_refs[x + y * mi_ctx->frames[0].avf->width].nb = 0; for (mb_y = 0; mb_y < mi_ctx->b_height; mb_y++) for (mb_x = 0; mb_x < mi_ctx->b_width; mb_x++) { @@ -1195,7 +1223,9 @@ static av_cold void uninit(AVFilterContext *ctx) MIContext *mi_ctx = ctx->priv; int i, m; - av_freep(&mi_ctx->pixels); + av_freep(&mi_ctx->pixel_mvs); + av_freep(&mi_ctx->pixel_weights); + av_freep(&mi_ctx->pixel_refs); if (mi_ctx->int_blocks) for (m = 0; m < mi_ctx->b_count; m++) free_blocks(&mi_ctx->int_blocks[m], 0); diff --git a/libavfilter/vf_misc_vaapi.c b/libavfilter/vf_misc_vaapi.c new file mode 100644 index 0000000000000..30b808a993460 --- /dev/null +++ b/libavfilter/vf_misc_vaapi.c @@ -0,0 +1,289 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include + +#include "libavutil/avassert.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "vaapi_vpp.h" + +// Denoise min/max/default Values +#define DENOISE_MIN 0 +#define DENOISE_MAX 64 +#define DENOISE_DEFAULT 0 + +// Sharpness min/max/default values +#define SHARPNESS_MIN 0 +#define SHARPNESS_MAX 64 +#define SHARPNESS_DEFAULT 44 + +typedef struct DenoiseVAAPIContext { + VAAPIVPPContext vpp_ctx; // must be the first field + + int denoise; // enable denoise algo. +} DenoiseVAAPIContext; + +typedef struct SharpnessVAAPIContext { + VAAPIVPPContext vpp_ctx; // must be the first field + + int sharpness; // enable sharpness. +} SharpnessVAAPIContext; + +static float map(int x, int in_min, int in_max, float out_min, float out_max) +{ + double slope, output; + + slope = 1.0 * (out_max - out_min) / (in_max - in_min); + output = out_min + slope * (x - in_min); + + return (float)output; +} + +static int denoise_vaapi_build_filter_params(AVFilterContext *avctx) +{ + VAAPIVPPContext *vpp_ctx = avctx->priv; + DenoiseVAAPIContext *ctx = avctx->priv; + + VAProcFilterCap caps; + + VAStatus vas; + uint32_t num_caps = 1; + + VAProcFilterParameterBuffer denoise; + + vas = vaQueryVideoProcFilterCaps(vpp_ctx->hwctx->display, vpp_ctx->va_context, + VAProcFilterNoiseReduction, + &caps, &num_caps); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to query denoise caps " + "context: %d (%s).\n", vas, vaErrorStr(vas)); + return AVERROR(EIO); + } + + denoise.type = VAProcFilterNoiseReduction; + denoise.value = map(ctx->denoise, DENOISE_MIN, DENOISE_MAX, + caps.range.min_value, + caps.range.max_value); + ff_vaapi_vpp_make_param_buffers(avctx, VAProcFilterParameterBufferType, + &denoise, sizeof(denoise), 1); + + return 0; +} + +static int sharpness_vaapi_build_filter_params(AVFilterContext *avctx) +{ + VAAPIVPPContext *vpp_ctx = avctx->priv; + SharpnessVAAPIContext *ctx = avctx->priv; + + VAProcFilterCap caps; + + VAStatus vas; + uint32_t num_caps = 1; + + VAProcFilterParameterBuffer sharpness; + + vas = vaQueryVideoProcFilterCaps(vpp_ctx->hwctx->display, vpp_ctx->va_context, + VAProcFilterSharpening, + &caps, &num_caps); + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to query sharpness caps " + "context: %d (%s).\n", vas, vaErrorStr(vas)); + return AVERROR(EIO); + } + + sharpness.type = VAProcFilterSharpening; + sharpness.value = map(ctx->sharpness, + SHARPNESS_MIN, SHARPNESS_MAX, + caps.range.min_value, + caps.range.max_value); + ff_vaapi_vpp_make_param_buffers(avctx, + VAProcFilterParameterBufferType, + &sharpness, sizeof(sharpness), 1); + + return 0; +} + +static int misc_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) +{ + AVFilterContext *avctx = inlink->dst; + AVFilterLink *outlink = avctx->outputs[0]; + VAAPIVPPContext *vpp_ctx = avctx->priv; + AVFrame *output_frame = NULL; + VASurfaceID input_surface, output_surface; + VARectangle input_region; + + VAProcPipelineParameterBuffer params; + int err; + + av_log(avctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(input_frame->format), + input_frame->width, input_frame->height, input_frame->pts); + + if (vpp_ctx->va_context == VA_INVALID_ID) + return AVERROR(EINVAL); + + input_surface = (VASurfaceID)(uintptr_t)input_frame->data[3]; + av_log(avctx, AV_LOG_DEBUG, "Using surface %#x for misc vpp input.\n", + input_surface); + + output_frame = ff_get_video_buffer(outlink, vpp_ctx->output_width, + vpp_ctx->output_height); + if (!output_frame) { + err = AVERROR(ENOMEM); + goto fail; + } + + output_surface = (VASurfaceID)(uintptr_t)output_frame->data[3]; + av_log(avctx, AV_LOG_DEBUG, "Using surface %#x for misc vpp output.\n", + output_surface); + memset(¶ms, 0, sizeof(params)); + input_region = (VARectangle) { + .x = 0, + .y = 0, + .width = input_frame->width, + .height = input_frame->height, + }; + + if (vpp_ctx->nb_filter_buffers) { + params.filters = &vpp_ctx->filter_buffers[0]; + params.num_filters = vpp_ctx->nb_filter_buffers; + } + params.surface = input_surface; + params.surface_region = &input_region; + params.surface_color_standard = + ff_vaapi_vpp_colour_standard(input_frame->colorspace); + + params.output_region = NULL; + params.output_background_color = 0xff000000; + params.output_color_standard = params.surface_color_standard; + + params.pipeline_flags = 0; + params.filter_flags = VA_FRAME_PICTURE; + + err = ff_vaapi_vpp_render_picture(avctx, ¶ms, output_surface); + if (err < 0) + goto fail; + + err = av_frame_copy_props(output_frame, input_frame); + if (err < 0) + goto fail; + av_frame_free(&input_frame); + + av_log(avctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(output_frame->format), + output_frame->width, output_frame->height, output_frame->pts); + + return ff_filter_frame(outlink, output_frame); + +fail: + av_frame_free(&input_frame); + av_frame_free(&output_frame); + return err; +} + +static av_cold int denoise_vaapi_init(AVFilterContext *avctx) +{ + VAAPIVPPContext *vpp_ctx = avctx->priv; + + ff_vaapi_vpp_ctx_init(avctx); + vpp_ctx->pipeline_uninit = ff_vaapi_vpp_pipeline_uninit; + vpp_ctx->build_filter_params = denoise_vaapi_build_filter_params; + vpp_ctx->output_format = AV_PIX_FMT_NONE; + + return 0; +} + +static av_cold int sharpness_vaapi_init(AVFilterContext *avctx) +{ + VAAPIVPPContext *vpp_ctx = avctx->priv; + + ff_vaapi_vpp_ctx_init(avctx); + vpp_ctx->pipeline_uninit = ff_vaapi_vpp_pipeline_uninit; + vpp_ctx->build_filter_params = sharpness_vaapi_build_filter_params; + vpp_ctx->output_format = AV_PIX_FMT_NONE; + + return 0; +} + +#define DOFFSET(x) offsetof(DenoiseVAAPIContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM) +static const AVOption denoise_vaapi_options[] = { + { "denoise", "denoise level", + DOFFSET(denoise), AV_OPT_TYPE_INT, { .i64 = DENOISE_DEFAULT }, DENOISE_MIN, DENOISE_MAX, .flags = FLAGS }, + { NULL }, +}; + +#define SOFFSET(x) offsetof(SharpnessVAAPIContext, x) +static const AVOption sharpness_vaapi_options[] = { + { "sharpness", "sharpness level", + SOFFSET(sharpness), AV_OPT_TYPE_INT, { .i64 = SHARPNESS_DEFAULT }, SHARPNESS_MIN, SHARPNESS_MAX, .flags = FLAGS }, + { NULL }, +}; + +AVFILTER_DEFINE_CLASS(denoise_vaapi); +AVFILTER_DEFINE_CLASS(sharpness_vaapi); + +static const AVFilterPad misc_vaapi_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = &misc_vaapi_filter_frame, + .config_props = &ff_vaapi_vpp_config_input, + }, + { NULL } +}; + +static const AVFilterPad misc_vaapi_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &ff_vaapi_vpp_config_output, + }, + { NULL } +}; + +AVFilter ff_vf_denoise_vaapi = { + .name = "denoise_vaapi", + .description = NULL_IF_CONFIG_SMALL("VAAPI VPP for de-noise"), + .priv_size = sizeof(DenoiseVAAPIContext), + .init = &denoise_vaapi_init, + .uninit = &ff_vaapi_vpp_ctx_uninit, + .query_formats = &ff_vaapi_vpp_query_formats, + .inputs = misc_vaapi_inputs, + .outputs = misc_vaapi_outputs, + .priv_class = &denoise_vaapi_class, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; + +AVFilter ff_vf_sharpness_vaapi = { + .name = "sharpness_vaapi", + .description = NULL_IF_CONFIG_SMALL("VAAPI VPP for sharpness"), + .priv_size = sizeof(SharpnessVAAPIContext), + .init = &sharpness_vaapi_init, + .uninit = &ff_vaapi_vpp_ctx_uninit, + .query_formats = &ff_vaapi_vpp_query_formats, + .inputs = misc_vaapi_inputs, + .outputs = misc_vaapi_outputs, + .priv_class = &sharpness_vaapi_class, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; diff --git a/libavfilter/vf_mix.c b/libavfilter/vf_mix.c new file mode 100644 index 0000000000000..261ab066efc89 --- /dev/null +++ b/libavfilter/vf_mix.c @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2017 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avstring.h" +#include "libavutil/imgutils.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "framesync.h" +#include "video.h" + +typedef struct MixContext { + const AVClass *class; + const AVPixFmtDescriptor *desc; + char *weights_str; + int nb_inputs; + int duration; + float *weights; + float wfactor; + + int depth; + int nb_planes; + int linesize[4]; + int height[4]; + + AVFrame **frames; + FFFrameSync fs; +} MixContext; + +static int query_formats(AVFilterContext *ctx) +{ + AVFilterFormats *pix_fmts = NULL; + int fmt, ret; + + for (fmt = 0; av_pix_fmt_desc_get(fmt); fmt++) { + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt); + if (!(desc->flags & AV_PIX_FMT_FLAG_PAL || + desc->flags & AV_PIX_FMT_FLAG_HWACCEL || + desc->flags & AV_PIX_FMT_FLAG_BITSTREAM) && + (ret = ff_add_format(&pix_fmts, fmt)) < 0) + return ret; + } + + return ff_set_common_formats(ctx, pix_fmts); +} + +static av_cold int init(AVFilterContext *ctx) +{ + MixContext *s = ctx->priv; + char *p, *arg, *saveptr = NULL; + int i, ret; + + s->frames = av_calloc(s->nb_inputs, sizeof(*s->frames)); + if (!s->frames) + return AVERROR(ENOMEM); + + s->weights = av_calloc(s->nb_inputs, sizeof(*s->weights)); + if (!s->weights) + return AVERROR(ENOMEM); + + for (i = 0; i < s->nb_inputs; i++) { + AVFilterPad pad = { 0 }; + + pad.type = AVMEDIA_TYPE_VIDEO; + pad.name = av_asprintf("input%d", i); + if (!pad.name) + return AVERROR(ENOMEM); + + if ((ret = ff_insert_inpad(ctx, i, &pad)) < 0) { + av_freep(&pad.name); + return ret; + } + } + + p = s->weights_str; + for (i = 0; i < s->nb_inputs; i++) { + if (!(arg = av_strtok(p, " ", &saveptr))) + break; + + p = NULL; + sscanf(arg, "%f", &s->weights[i]); + s->wfactor += s->weights[i]; + } + s->wfactor = 1 / s->wfactor; + + return 0; +} + +static int process_frame(FFFrameSync *fs) +{ + AVFilterContext *ctx = fs->parent; + AVFilterLink *outlink = ctx->outputs[0]; + MixContext *s = fs->opaque; + AVFrame **in = s->frames; + AVFrame *out; + int i, p, ret, x, y; + + for (i = 0; i < s->nb_inputs; i++) { + if ((ret = ff_framesync_get_frame(&s->fs, i, &in[i], 0)) < 0) + return ret; + } + + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) + return AVERROR(ENOMEM); + out->pts = av_rescale_q(s->fs.pts, s->fs.time_base, outlink->time_base); + + if (s->depth <= 8) { + for (p = 0; p < s->nb_planes; p++) { + uint8_t *dst = out->data[p]; + + for (y = 0; y < s->height[p]; y++) { + for (x = 0; x < s->linesize[p]; x++) { + int val = 0; + + for (i = 0; i < s->nb_inputs; i++) { + uint8_t src = in[i]->data[p][y * s->linesize[p] + x]; + + val += src * s->weights[i]; + } + + dst[x] = val * s->wfactor; + } + + dst += out->linesize[p]; + } + } + } else { + for (p = 0; p < s->nb_planes; p++) { + uint16_t *dst = (uint16_t *)out->data[p]; + + for (y = 0; y < s->height[p]; y++) { + for (x = 0; x < s->linesize[p]; x++) { + int val = 0; + + for (i = 0; i < s->nb_inputs; i++) { + uint16_t src = AV_RN16(in[i]->data[p] + y * s->linesize[p] + x * 2); + + val += src * s->weights[i]; + } + + dst[x] = val * s->wfactor; + } + + dst += out->linesize[p] / 2; + } + } + } + + return ff_filter_frame(outlink, out); +} + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + MixContext *s = ctx->priv; + AVRational time_base = ctx->inputs[0]->time_base; + AVRational frame_rate = ctx->inputs[0]->frame_rate; + AVFilterLink *inlink = ctx->inputs[0]; + int height = ctx->inputs[0]->h; + int width = ctx->inputs[0]->w; + FFFrameSyncIn *in; + int i, ret; + + for (i = 1; i < s->nb_inputs; i++) { + if (ctx->inputs[i]->h != height || ctx->inputs[i]->w != width) { + av_log(ctx, AV_LOG_ERROR, "Input %d size (%dx%d) does not match input %d size (%dx%d).\n", i, ctx->inputs[i]->w, ctx->inputs[i]->h, 0, width, height); + return AVERROR(EINVAL); + } + } + + s->desc = av_pix_fmt_desc_get(outlink->format); + if (!s->desc) + return AVERROR_BUG; + s->nb_planes = av_pix_fmt_count_planes(outlink->format); + s->depth = s->desc->comp[0].depth; + + outlink->w = width; + outlink->h = height; + outlink->time_base = time_base; + outlink->frame_rate = frame_rate; + + if ((ret = ff_framesync_init(&s->fs, ctx, s->nb_inputs)) < 0) + return ret; + + in = s->fs.in; + s->fs.opaque = s; + s->fs.on_event = process_frame; + + if ((ret = av_image_fill_linesizes(s->linesize, inlink->format, inlink->w)) < 0) + return ret; + + s->height[1] = s->height[2] = AV_CEIL_RSHIFT(inlink->h, s->desc->log2_chroma_h); + s->height[0] = s->height[3] = inlink->h; + + for (i = 0; i < s->nb_inputs; i++) { + AVFilterLink *inlink = ctx->inputs[i]; + + in[i].time_base = inlink->time_base; + in[i].sync = 1; + in[i].before = EXT_STOP; + in[i].after = (s->duration == 1 || (s->duration == 2 && i == 0)) ? EXT_STOP : EXT_INFINITY; + } + + return ff_framesync_configure(&s->fs); +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + MixContext *s = ctx->priv; + int i; + + ff_framesync_uninit(&s->fs); + av_freep(&s->frames); + av_freep(&s->weights); + + for (i = 0; i < ctx->nb_inputs; i++) + av_freep(&ctx->input_pads[i].name); +} + +static int activate(AVFilterContext *ctx) +{ + MixContext *s = ctx->priv; + return ff_framesync_activate(&s->fs); +} + +#define OFFSET(x) offsetof(MixContext, x) +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption mix_options[] = { + { "inputs", "set number of inputs", OFFSET(nb_inputs), AV_OPT_TYPE_INT, {.i64=2}, 2, INT_MAX, .flags = FLAGS }, + { "weights", "set weight for each input", OFFSET(weights_str), AV_OPT_TYPE_STRING, {.str="1 1"}, 0, 0, .flags = FLAGS }, + { "duration", "how to determine end of stream", OFFSET(duration), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, .flags = FLAGS, "duration" }, + { "longest", "Duration of longest input", 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "duration" }, + { "shortest", "Duration of shortest input", 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "duration" }, + { "first", "Duration of first input", 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "duration" }, + { NULL }, +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_output, + }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(mix); + +AVFilter ff_vf_mix = { + .name = "mix", + .description = NULL_IF_CONFIG_SMALL("Mix video inputs."), + .priv_size = sizeof(MixContext), + .priv_class = &mix_class, + .query_formats = query_formats, + .outputs = outputs, + .init = init, + .uninit = uninit, + .activate = activate, + .flags = AVFILTER_FLAG_DYNAMIC_INPUTS, +}; diff --git a/libavfilter/vf_normalize.c b/libavfilter/vf_normalize.c new file mode 100644 index 0000000000000..5c1fe98c60c23 --- /dev/null +++ b/libavfilter/vf_normalize.c @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2017 Richard Ling + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * Normalize RGB video (aka histogram stretching, contrast stretching). + * See: https://en.wikipedia.org/wiki/Normalization_(image_processing) + * + * For each channel of each frame, the filter computes the input range and maps + * it linearly to the user-specified output range. The output range defaults + * to the full dynamic range from pure black to pure white. + * + * Naively maximising the dynamic range of each frame of video in isolation + * may cause flickering (rapid changes in brightness of static objects in the + * scene) when small dark or bright objects enter or leave the scene. This + * filter can apply temporal smoothing to the input range to reduce flickering. + * Temporal smoothing is similar to the auto-exposure (automatic gain control) + * on a video camera, which performs the same function; and, like a video + * camera, it may cause a period of over- or under-exposure of the video. + * + * The filter can normalize the R,G,B channels independently, which may cause + * color shifting, or link them together as a single channel, which prevents + * color shifting. More precisely, linked normalization preserves hue (as it's + * defined in HSV/HSL color spaces) while independent normalization does not. + * Independent normalization can be used to remove color casts, such as the + * blue cast from underwater video, restoring more natural colors. The filter + * can also combine independent and linked normalization in any ratio. + * + * Finally the overall strength of the filter can be adjusted, from no effect + * to full normalization. + * + * The 5 AVOptions are: + * blackpt, Colors which define the output range. The minimum input value + * whitept is mapped to the blackpt. The maximum input value is mapped to + * the whitept. The defaults are black and white respectively. + * Specifying white for blackpt and black for whitept will give + * color-inverted, normalized video. Shades of grey can be used + * to reduce the dynamic range (contrast). Specifying saturated + * colors here can create some interesting effects. + * + * smoothing The amount of temporal smoothing, expressed in frames (>=0). + * the minimum and maximum input values of each channel are + * smoothed using a rolling average over the current frame and + * that many previous frames of video. Defaults to 0 (no temporal + * smoothing). + * + * independence + * Controls the ratio of independent (color shifting) channel + * normalization to linked (color preserving) normalization. 0.0 + * is fully linked, 1.0 is fully independent. Defaults to fully + * independent. + * + * strength Overall strength of the filter. 1.0 is full strength. 0.0 is + * a rather expensive no-op. Values in between can give a gentle + * boost to low-contrast video without creating an artificial + * over-processed look. The default is full strength. + */ + +#include "libavutil/imgutils.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "video.h" + +typedef struct NormalizeContext { + const AVClass *class; + + // Storage for the corresponding AVOptions + uint8_t blackpt[4]; + uint8_t whitept[4]; + int smoothing; + float independence; + float strength; + + int co[4]; // Offsets to R,G,B,A bytes respectively in each pixel + int num_components; // Number of components in the pixel format + int history_len; // Number of frames to average; based on smoothing factor + int frame_num; // Increments on each frame, starting from 0. + + // Per-extremum, per-channel history, for temporal smoothing. + struct { + uint8_t *history; // History entries. + uint32_t history_sum; // Sum of history entries. + } min[3], max[3]; // Min and max for each channel in {R,G,B}. + uint8_t *history_mem; // Single allocation for above history entries + +} NormalizeContext; + +#define OFFSET(x) offsetof(NormalizeContext, x) +#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM + +static const AVOption normalize_options[] = { + { "blackpt", "output color to which darkest input color is mapped", OFFSET(blackpt), AV_OPT_TYPE_COLOR, { .str = "black" }, CHAR_MIN, CHAR_MAX, FLAGS }, + { "whitept", "output color to which brightest input color is mapped", OFFSET(whitept), AV_OPT_TYPE_COLOR, { .str = "white" }, CHAR_MIN, CHAR_MAX, FLAGS }, + { "smoothing", "amount of temporal smoothing of the input range, to reduce flicker", OFFSET(smoothing), AV_OPT_TYPE_INT, {.i64=0}, 0, INT_MAX/8, FLAGS }, + { "independence", "proportion of independent to linked channel normalization", OFFSET(independence), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, 1.0, FLAGS }, + { "strength", "strength of filter, from no effect to full normalization", OFFSET(strength), AV_OPT_TYPE_FLOAT, {.dbl=1.0}, 0.0, 1.0, FLAGS }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(normalize); + +// This function is the main guts of the filter. Normalizes the input frame +// into the output frame. The frames are known to have the same dimensions +// and pixel format. +static void normalize(NormalizeContext *s, AVFrame *in, AVFrame *out) +{ + // Per-extremum, per-channel local variables. + struct { + uint8_t in; // Original input byte value for this frame. + float smoothed; // Smoothed input value [0,255]. + float out; // Output value [0,255]. + } min[3], max[3]; // Min and max for each channel in {R,G,B}. + + float rgb_min_smoothed; // Min input range for linked normalization + float rgb_max_smoothed; // Max input range for linked normalization + uint8_t lut[3][256]; // Lookup table + int x, y, c; + + // First, scan the input frame to find, for each channel, the minimum + // (min.in) and maximum (max.in) values present in the channel. + for (c = 0; c < 3; c++) + min[c].in = max[c].in = in->data[0][s->co[c]]; + for (y = 0; y < in->height; y++) { + uint8_t *inp = in->data[0] + y * in->linesize[0]; + uint8_t *outp = out->data[0] + y * out->linesize[0]; + for (x = 0; x < in->width; x++) { + for (c = 0; c < 3; c++) { + min[c].in = FFMIN(min[c].in, inp[s->co[c]]); + max[c].in = FFMAX(max[c].in, inp[s->co[c]]); + } + inp += s->num_components; + outp += s->num_components; + } + } + + // Next, for each channel, push min.in and max.in into their respective + // histories, to determine the min.smoothed and max.smoothed for this frame. + { + int history_idx = s->frame_num % s->history_len; + // Assume the history is not yet full; num_history_vals is the number + // of frames received so far including the current frame. + int num_history_vals = s->frame_num + 1; + if (s->frame_num >= s->history_len) { + //The history is full; drop oldest value and cap num_history_vals. + for (c = 0; c < 3; c++) { + s->min[c].history_sum -= s->min[c].history[history_idx]; + s->max[c].history_sum -= s->max[c].history[history_idx]; + } + num_history_vals = s->history_len; + } + // For each extremum, update history_sum and calculate smoothed value + // as the rolling average of the history entries. + for (c = 0; c < 3; c++) { + s->min[c].history_sum += (s->min[c].history[history_idx] = min[c].in); + min[c].smoothed = s->min[c].history_sum / (float)num_history_vals; + s->max[c].history_sum += (s->max[c].history[history_idx] = max[c].in); + max[c].smoothed = s->max[c].history_sum / (float)num_history_vals; + } + } + + // Determine the input range for linked normalization. This is simply the + // minimum of the per-channel minimums, and the maximum of the per-channel + // maximums. + rgb_min_smoothed = FFMIN3(min[0].smoothed, min[1].smoothed, min[2].smoothed); + rgb_max_smoothed = FFMAX3(max[0].smoothed, max[1].smoothed, max[2].smoothed); + + // Now, process each channel to determine the input and output range and + // build the lookup tables. + for (c = 0; c < 3; c++) { + int in_val; + // Adjust the input range for this channel [min.smoothed,max.smoothed] + // by mixing in the correct proportion of the linked normalization + // input range [rgb_min_smoothed,rgb_max_smoothed]. + min[c].smoothed = (min[c].smoothed * s->independence) + + (rgb_min_smoothed * (1.0f - s->independence)); + max[c].smoothed = (max[c].smoothed * s->independence) + + (rgb_max_smoothed * (1.0f - s->independence)); + + // Calculate the output range [min.out,max.out] as a ratio of the full- + // strength output range [blackpt,whitept] and the original input range + // [min.in,max.in], based on the user-specified filter strength. + min[c].out = (s->blackpt[c] * s->strength) + + (min[c].in * (1.0f - s->strength)); + max[c].out = (s->whitept[c] * s->strength) + + (max[c].in * (1.0f - s->strength)); + + // Now, build a lookup table which linearly maps the adjusted input range + // [min.smoothed,max.smoothed] to the output range [min.out,max.out]. + // Perform the linear interpolation for each x: + // lut[x] = (int)(float(x - min.smoothed) * scale + max.out + 0.5) + // where scale = (max.out - min.out) / (max.smoothed - min.smoothed) + if (min[c].smoothed == max[c].smoothed) { + // There is no dynamic range to expand. No mapping for this channel. + for (in_val = min[c].in; in_val <= max[c].in; in_val++) + lut[c][in_val] = min[c].out; + } else { + // We must set lookup values for all values in the original input + // range [min.in,max.in]. Since the original input range may be + // larger than [min.smoothed,max.smoothed], some output values may + // fall outside the [0,255] dynamic range. We need to clamp them. + float scale = (max[c].out - min[c].out) / (max[c].smoothed - min[c].smoothed); + for (in_val = min[c].in; in_val <= max[c].in; in_val++) { + int out_val = (in_val - min[c].smoothed) * scale + min[c].out + 0.5f; + out_val = FFMAX(out_val, 0); + out_val = FFMIN(out_val, 255); + lut[c][in_val] = out_val; + } + } + } + + // Finally, process the pixels of the input frame using the lookup tables. + for (y = 0; y < in->height; y++) { + uint8_t *inp = in->data[0] + y * in->linesize[0]; + uint8_t *outp = out->data[0] + y * out->linesize[0]; + for (x = 0; x < in->width; x++) { + for (c = 0; c < 3; c++) + outp[s->co[c]] = lut[c][inp[s->co[c]]]; + if (s->num_components == 4) + // Copy alpha as-is. + outp[s->co[3]] = inp[s->co[3]]; + inp += s->num_components; + outp += s->num_components; + } + } + + s->frame_num++; +} + +// Now we define all the functions accessible from the ff_vf_normalize class, +// which is ffmpeg's interface to our filter. See doc/filter_design.txt and +// doc/writing_filters.txt for descriptions of what these interface functions +// are expected to do. + +// Set the pixel formats that our filter supports. We should be able to process +// any 8-bit RGB formats. 16-bit support might be useful one day. +static int query_formats(AVFilterContext *ctx) +{ + static const enum AVPixelFormat pixel_fmts[] = { + AV_PIX_FMT_RGB24, + AV_PIX_FMT_BGR24, + AV_PIX_FMT_ARGB, + AV_PIX_FMT_RGBA, + AV_PIX_FMT_ABGR, + AV_PIX_FMT_BGRA, + AV_PIX_FMT_0RGB, + AV_PIX_FMT_RGB0, + AV_PIX_FMT_0BGR, + AV_PIX_FMT_BGR0, + AV_PIX_FMT_NONE + }; + // According to filter_design.txt, using ff_set_common_formats() this way + // ensures the pixel formats of the input and output will be the same. That + // saves a bit of effort possibly needing to handle format conversions. + AVFilterFormats *formats = ff_make_format_list(pixel_fmts); + if (!formats) + return AVERROR(ENOMEM); + return ff_set_common_formats(ctx, formats); +} + +// At this point we know the pixel format used for both input and output. We +// can also access the frame rate of the input video and allocate some memory +// appropriately +static int config_input(AVFilterLink *inlink) +{ + NormalizeContext *s = inlink->dst->priv; + // Store offsets to R,G,B,A bytes respectively in each pixel + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + int c; + + for (c = 0; c < 4; ++c) + s->co[c] = desc->comp[c].offset; + s->num_components = desc->nb_components; + // Convert smoothing value to history_len (a count of frames to average, + // must be at least 1). Currently this is a direct assignment, but the + // smoothing value was originally envisaged as a number of seconds. In + // future it would be nice to set history_len using a number of seconds, + // but VFR video is currently an obstacle to doing so. + s->history_len = s->smoothing + 1; + // Allocate the history buffers -- there are 6 -- one for each extrema. + // s->smoothing is limited to INT_MAX/8, so that (s->history_len * 6) + // can't overflow on 32bit causing a too-small allocation. + s->history_mem = av_malloc(s->history_len * 6); + if (s->history_mem == NULL) + return AVERROR(ENOMEM); + + for (c = 0; c < 3; c++) { + s->min[c].history = s->history_mem + (c*2) * s->history_len; + s->max[c].history = s->history_mem + (c*2+1) * s->history_len; + } + return 0; +} + +// Free any memory allocations here +static av_cold void uninit(AVFilterContext *ctx) +{ + NormalizeContext *s = ctx->priv; + + av_freep(&s->history_mem); +} + +// This function is pretty much standard from doc/writing_filters.txt. It +// tries to do in-place filtering where possible, only allocating a new output +// frame when absolutely necessary. +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + NormalizeContext *s = ctx->priv; + AVFrame *out; + // Set 'direct' if we can modify the input frame in-place. Otherwise we + // need to retrieve a new frame from the output link. + int direct = av_frame_is_writable(in) && !ctx->is_disabled; + + if (direct) { + out = in; + } else { + out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + av_frame_copy_props(out, in); + } + + // Now we've got the input and output frames (which may be the same frame) + // perform the filtering with our custom function. + normalize(s, in, out); + + if (ctx->is_disabled) { + av_frame_free(&out); + return ff_filter_frame(outlink, in); + } + + if (!direct) + av_frame_free(&in); + + return ff_filter_frame(outlink, out); +} + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame, + .config_props = config_input, + }, + { NULL } +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +AVFilter ff_vf_normalize = { + .name = "normalize", + .description = NULL_IF_CONFIG_SMALL("Normalize RGB video."), + .priv_size = sizeof(NormalizeContext), + .priv_class = &normalize_class, + .uninit = uninit, + .query_formats = query_formats, + .inputs = inputs, + .outputs = outputs, +}; diff --git a/libavfilter/vf_ocr.c b/libavfilter/vf_ocr.c index e003982f05fcd..abfff494387b0 100644 --- a/libavfilter/vf_ocr.c +++ b/libavfilter/vf_ocr.c @@ -90,9 +90,7 @@ static int query_formats(AVFilterContext *ctx) AVFilterFormats *fmts_list = ff_make_format_list(pix_fmts); if (!fmts_list) return AVERROR(ENOMEM); - ff_set_common_formats(ctx, fmts_list); - - return 0; + return ff_set_common_formats(ctx, fmts_list); } static int filter_frame(AVFilterLink *inlink, AVFrame *in) diff --git a/libavfilter/vf_overlay.c b/libavfilter/vf_overlay.c index 5bf3d66cf1f2b..c6a6ac82f397a 100644 --- a/libavfilter/vf_overlay.c +++ b/libavfilter/vf_overlay.c @@ -109,6 +109,7 @@ typedef struct OverlayContext { uint8_t overlay_rgba_map[4]; uint8_t overlay_has_alpha; int format; ///< OverlayFormat + int alpha_format; int eval_mode; ///< EvalMode FFFrameSync fs; @@ -148,6 +149,7 @@ static void eval_expr(AVFilterContext *ctx) s->var_values[VAR_X] = av_expr_eval(s->x_pexpr, s->var_values, NULL); s->var_values[VAR_Y] = av_expr_eval(s->y_pexpr, s->var_values, NULL); + /* It is necessary if x is expressed from y */ s->var_values[VAR_X] = av_expr_eval(s->x_pexpr, s->var_values, NULL); s->x = normalize_xy(s->var_values[VAR_X], s->hsub); s->y = normalize_xy(s->var_values[VAR_Y], s->vsub); @@ -401,9 +403,10 @@ static int config_output(AVFilterLink *outlink) * Blend image in src to destination buffer dst at position (x, y). */ -static void blend_image_packed_rgb(AVFilterContext *ctx, +static av_always_inline void blend_image_packed_rgb(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, - int main_has_alpha, int x, int y) + int main_has_alpha, int x, int y, + int is_straight) { OverlayContext *s = ctx->priv; int i, imax, j, jmax; @@ -454,9 +457,12 @@ static void blend_image_packed_rgb(AVFilterContext *ctx, default: // main_value = main_value * (1 - alpha) + overlay_value * alpha // since alpha is in the range 0-255, the result must divided by 255 - d[dr] = FAST_DIV255(d[dr] * (255 - alpha) + S[sr] * alpha); - d[dg] = FAST_DIV255(d[dg] * (255 - alpha) + S[sg] * alpha); - d[db] = FAST_DIV255(d[db] * (255 - alpha) + S[sb] * alpha); + d[dr] = is_straight ? FAST_DIV255(d[dr] * (255 - alpha) + S[sr] * alpha) : + FFMIN(FAST_DIV255(d[dr] * (255 - alpha)) + S[sr], 255); + d[dg] = is_straight ? FAST_DIV255(d[dg] * (255 - alpha) + S[sg] * alpha) : + FFMIN(FAST_DIV255(d[dg] * (255 - alpha)) + S[sg], 255); + d[db] = is_straight ? FAST_DIV255(d[db] * (255 - alpha) + S[sb] * alpha) : + FFMIN(FAST_DIV255(d[db] * (255 - alpha)) + S[sb], 255); } if (main_has_alpha) { switch (alpha) { @@ -487,7 +493,9 @@ static av_always_inline void blend_plane(AVFilterContext *ctx, int main_has_alpha, int dst_plane, int dst_offset, - int dst_step) + int dst_step, + int straight, + int yuv) { int src_wp = AV_CEIL_RSHIFT(src_w, hsub); int src_hp = AV_CEIL_RSHIFT(src_h, vsub); @@ -546,7 +554,14 @@ static av_always_inline void blend_plane(AVFilterContext *ctx, alpha_d = da[0]; alpha = UNPREMULTIPLY_ALPHA(alpha, alpha_d); } - *d = FAST_DIV255(*d * (255 - alpha) + *s * alpha); + if (straight) { + *d = FAST_DIV255(*d * (255 - alpha) + *s * alpha); + } else { + if (i && yuv) + *d = av_clip(FAST_DIV255((*d - 128) * (255 - alpha)) + *s - 128, -128, 128) + 128; + else + *d = FFMIN(FAST_DIV255(*d * (255 - alpha)) + *s, 255); + } s++; d += dst_step; da += 1 << hsub; @@ -605,7 +620,8 @@ static av_always_inline void blend_image_yuv(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int hsub, int vsub, int main_has_alpha, - int x, int y) + int x, int y, + int is_straight) { OverlayContext *s = ctx->priv; const int src_w = src->width; @@ -614,11 +630,11 @@ static av_always_inline void blend_image_yuv(AVFilterContext *ctx, const int dst_h = dst->height; blend_plane(ctx, dst, src, src_w, src_h, dst_w, dst_h, 0, 0, 0, x, y, main_has_alpha, - s->main_desc->comp[0].plane, s->main_desc->comp[0].offset, s->main_desc->comp[0].step); + s->main_desc->comp[0].plane, s->main_desc->comp[0].offset, s->main_desc->comp[0].step, is_straight, 1); blend_plane(ctx, dst, src, src_w, src_h, dst_w, dst_h, 1, hsub, vsub, x, y, main_has_alpha, - s->main_desc->comp[1].plane, s->main_desc->comp[1].offset, s->main_desc->comp[1].step); + s->main_desc->comp[1].plane, s->main_desc->comp[1].offset, s->main_desc->comp[1].step, is_straight, 1); blend_plane(ctx, dst, src, src_w, src_h, dst_w, dst_h, 2, hsub, vsub, x, y, main_has_alpha, - s->main_desc->comp[2].plane, s->main_desc->comp[2].offset, s->main_desc->comp[2].step); + s->main_desc->comp[2].plane, s->main_desc->comp[2].offset, s->main_desc->comp[2].step, is_straight, 1); if (main_has_alpha) alpha_composite(src, dst, src_w, src_h, dst_w, dst_h, x, y); @@ -628,7 +644,8 @@ static av_always_inline void blend_image_planar_rgb(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int hsub, int vsub, int main_has_alpha, - int x, int y) + int x, int y, + int is_straight) { OverlayContext *s = ctx->priv; const int src_w = src->width; @@ -637,11 +654,11 @@ static av_always_inline void blend_image_planar_rgb(AVFilterContext *ctx, const int dst_h = dst->height; blend_plane(ctx, dst, src, src_w, src_h, dst_w, dst_h, 0, 0, 0, x, y, main_has_alpha, - s->main_desc->comp[1].plane, s->main_desc->comp[1].offset, s->main_desc->comp[1].step); + s->main_desc->comp[1].plane, s->main_desc->comp[1].offset, s->main_desc->comp[1].step, is_straight, 0); blend_plane(ctx, dst, src, src_w, src_h, dst_w, dst_h, 1, hsub, vsub, x, y, main_has_alpha, - s->main_desc->comp[2].plane, s->main_desc->comp[2].offset, s->main_desc->comp[2].step); + s->main_desc->comp[2].plane, s->main_desc->comp[2].offset, s->main_desc->comp[2].step, is_straight, 0); blend_plane(ctx, dst, src, src_w, src_h, dst_w, dst_h, 2, hsub, vsub, x, y, main_has_alpha, - s->main_desc->comp[0].plane, s->main_desc->comp[0].offset, s->main_desc->comp[0].step); + s->main_desc->comp[0].plane, s->main_desc->comp[0].offset, s->main_desc->comp[0].step, is_straight, 0); if (main_has_alpha) alpha_composite(src, dst, src_w, src_h, dst_w, dst_h, x, y); @@ -649,52 +666,102 @@ static av_always_inline void blend_image_planar_rgb(AVFilterContext *ctx, static void blend_image_yuv420(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) { - blend_image_yuv(ctx, dst, src, 1, 1, 0, x, y); + blend_image_yuv(ctx, dst, src, 1, 1, 0, x, y, 1); } static void blend_image_yuva420(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) { - blend_image_yuv(ctx, dst, src, 1, 1, 1, x, y); + blend_image_yuv(ctx, dst, src, 1, 1, 1, x, y, 1); } static void blend_image_yuv422(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) { - blend_image_yuv(ctx, dst, src, 1, 0, 0, x, y); + blend_image_yuv(ctx, dst, src, 1, 0, 0, x, y, 1); } static void blend_image_yuva422(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) { - blend_image_yuv(ctx, dst, src, 1, 0, 1, x, y); + blend_image_yuv(ctx, dst, src, 1, 0, 1, x, y, 1); } static void blend_image_yuv444(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) { - blend_image_yuv(ctx, dst, src, 0, 0, 0, x, y); + blend_image_yuv(ctx, dst, src, 0, 0, 0, x, y, 1); } static void blend_image_yuva444(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) { - blend_image_yuv(ctx, dst, src, 0, 0, 1, x, y); + blend_image_yuv(ctx, dst, src, 0, 0, 1, x, y, 1); } static void blend_image_gbrp(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) { - blend_image_planar_rgb(ctx, dst, src, 0, 0, 0, x, y); + blend_image_planar_rgb(ctx, dst, src, 0, 0, 0, x, y, 1); } static void blend_image_gbrap(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) { - blend_image_planar_rgb(ctx, dst, src, 0, 0, 1, x, y); + blend_image_planar_rgb(ctx, dst, src, 0, 0, 1, x, y, 1); +} + +static void blend_image_yuv420_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +{ + blend_image_yuv(ctx, dst, src, 1, 1, 0, x, y, 0); +} + +static void blend_image_yuva420_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +{ + blend_image_yuv(ctx, dst, src, 1, 1, 1, x, y, 0); +} + +static void blend_image_yuv422_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +{ + blend_image_yuv(ctx, dst, src, 1, 0, 0, x, y, 0); +} + +static void blend_image_yuva422_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +{ + blend_image_yuv(ctx, dst, src, 1, 0, 1, x, y, 0); +} + +static void blend_image_yuv444_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +{ + blend_image_yuv(ctx, dst, src, 0, 0, 0, x, y, 0); +} + +static void blend_image_yuva444_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +{ + blend_image_yuv(ctx, dst, src, 0, 0, 1, x, y, 0); +} + +static void blend_image_gbrp_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +{ + blend_image_planar_rgb(ctx, dst, src, 0, 0, 0, x, y, 0); +} + +static void blend_image_gbrap_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +{ + blend_image_planar_rgb(ctx, dst, src, 0, 0, 1, x, y, 0); } static void blend_image_rgb(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) { - blend_image_packed_rgb(ctx, dst, src, 0, x, y); + blend_image_packed_rgb(ctx, dst, src, 0, x, y, 1); } static void blend_image_rgba(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) { - blend_image_packed_rgb(ctx, dst, src, 1, x, y); + blend_image_packed_rgb(ctx, dst, src, 1, x, y, 1); +} + +static void blend_image_rgb_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +{ + blend_image_packed_rgb(ctx, dst, src, 0, x, y, 0); +} + +static void blend_image_rgba_pm(AVFilterContext *ctx, AVFrame *dst, const AVFrame *src, int x, int y) +{ + blend_image_packed_rgb(ctx, dst, src, 1, x, y, 0); } static int config_input_main(AVFilterLink *inlink) @@ -754,6 +821,52 @@ static int config_input_main(AVFilterLink *inlink) } break; } + + if (!s->alpha_format) + return 0; + + switch (s->format) { + case OVERLAY_FORMAT_YUV420: + s->blend_image = s->main_has_alpha ? blend_image_yuva420_pm : blend_image_yuv420_pm; + break; + case OVERLAY_FORMAT_YUV422: + s->blend_image = s->main_has_alpha ? blend_image_yuva422_pm : blend_image_yuv422_pm; + break; + case OVERLAY_FORMAT_YUV444: + s->blend_image = s->main_has_alpha ? blend_image_yuva444_pm : blend_image_yuv444_pm; + break; + case OVERLAY_FORMAT_RGB: + s->blend_image = s->main_has_alpha ? blend_image_rgba_pm : blend_image_rgb_pm; + break; + case OVERLAY_FORMAT_GBRP: + s->blend_image = s->main_has_alpha ? blend_image_gbrap_pm : blend_image_gbrp_pm; + break; + case OVERLAY_FORMAT_AUTO: + switch (inlink->format) { + case AV_PIX_FMT_YUVA420P: + s->blend_image = blend_image_yuva420_pm; + break; + case AV_PIX_FMT_YUVA422P: + s->blend_image = blend_image_yuva422_pm; + break; + case AV_PIX_FMT_YUVA444P: + s->blend_image = blend_image_yuva444_pm; + break; + case AV_PIX_FMT_ARGB: + case AV_PIX_FMT_RGBA: + case AV_PIX_FMT_BGRA: + case AV_PIX_FMT_ABGR: + s->blend_image = blend_image_rgba_pm; + break; + case AV_PIX_FMT_GBRAP: + s->blend_image = blend_image_gbrap_pm; + break; + default: + av_assert0(0); + break; + } + break; + } return 0; } @@ -835,6 +948,9 @@ static const AVOption overlay_options[] = { { "gbrp", "", 0, AV_OPT_TYPE_CONST, {.i64=OVERLAY_FORMAT_GBRP}, .flags = FLAGS, .unit = "format" }, { "auto", "", 0, AV_OPT_TYPE_CONST, {.i64=OVERLAY_FORMAT_AUTO}, .flags = FLAGS, .unit = "format" }, { "repeatlast", "repeat overlay of the last overlay frame", OFFSET(fs.opt_repeatlast), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS }, + { "alpha", "alpha format", OFFSET(alpha_format), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "alpha_format" }, + { "straight", "", 0, AV_OPT_TYPE_CONST, {.i64=0}, .flags = FLAGS, .unit = "alpha_format" }, + { "premultiplied", "", 0, AV_OPT_TYPE_CONST, {.i64=1}, .flags = FLAGS, .unit = "alpha_format" }, { NULL } }; diff --git a/libavfilter/vf_overlay_opencl.c b/libavfilter/vf_overlay_opencl.c new file mode 100644 index 0000000000000..b43050df583b1 --- /dev/null +++ b/libavfilter/vf_overlay_opencl.c @@ -0,0 +1,357 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/log.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "framesync.h" +#include "internal.h" +#include "opencl.h" +#include "opencl_source.h" +#include "video.h" + +typedef struct OverlayOpenCLContext { + OpenCLFilterContext ocf; + + int initialised; + cl_kernel kernel; + cl_command_queue command_queue; + + FFFrameSync fs; + + int nb_planes; + int x_subsample; + int y_subsample; + int alpha_separate; + + int x_position; + int y_position; +} OverlayOpenCLContext; + +static int overlay_opencl_load(AVFilterContext *avctx, + enum AVPixelFormat main_format, + enum AVPixelFormat overlay_format) +{ + OverlayOpenCLContext *ctx = avctx->priv; + cl_int cle; + const char *source = ff_opencl_source_overlay; + const char *kernel; + const AVPixFmtDescriptor *main_desc, *overlay_desc; + int err, i, main_planes, overlay_planes; + + main_desc = av_pix_fmt_desc_get(main_format); + overlay_desc = av_pix_fmt_desc_get(overlay_format); + + main_planes = overlay_planes = 0; + for (i = 0; i < main_desc->nb_components; i++) + main_planes = FFMAX(main_planes, + main_desc->comp[i].plane + 1); + for (i = 0; i < overlay_desc->nb_components; i++) + overlay_planes = FFMAX(overlay_planes, + overlay_desc->comp[i].plane + 1); + + ctx->nb_planes = main_planes; + ctx->x_subsample = 1 << main_desc->log2_chroma_w; + ctx->y_subsample = 1 << main_desc->log2_chroma_h; + + if (ctx->x_position % ctx->x_subsample || + ctx->y_position % ctx->y_subsample) { + av_log(avctx, AV_LOG_WARNING, "Warning: overlay position (%d, %d) " + "does not match subsampling (%d, %d).\n", + ctx->x_position, ctx->y_position, + ctx->x_subsample, ctx->y_subsample); + } + + if (main_planes == overlay_planes) { + if (main_desc->nb_components == overlay_desc->nb_components) + kernel = "overlay_no_alpha"; + else + kernel = "overlay_internal_alpha"; + ctx->alpha_separate = 0; + } else { + kernel = "overlay_external_alpha"; + ctx->alpha_separate = 1; + } + + av_log(avctx, AV_LOG_DEBUG, "Using kernel %s.\n", kernel); + + err = ff_opencl_filter_load_program(avctx, &source, 1); + if (err < 0) + goto fail; + + ctx->command_queue = clCreateCommandQueue(ctx->ocf.hwctx->context, + ctx->ocf.hwctx->device_id, + 0, &cle); + if (!ctx->command_queue) { + av_log(avctx, AV_LOG_ERROR, "Failed to create OpenCL " + "command queue: %d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + + ctx->kernel = clCreateKernel(ctx->ocf.program, kernel, &cle); + if (!ctx->kernel) { + av_log(avctx, AV_LOG_ERROR, "Failed to create kernel: %d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + + ctx->initialised = 1; + return 0; + +fail: + if (ctx->command_queue) + clReleaseCommandQueue(ctx->command_queue); + if (ctx->kernel) + clReleaseKernel(ctx->kernel); + return err; +} + +static int overlay_opencl_blend(FFFrameSync *fs) +{ + AVFilterContext *avctx = fs->parent; + AVFilterLink *outlink = avctx->outputs[0]; + OverlayOpenCLContext *ctx = avctx->priv; + AVFrame *input_main, *input_overlay; + AVFrame *output; + cl_mem mem; + cl_int cle, x, y; + size_t global_work[2]; + int kernel_arg = 0; + int err, plane; + + err = ff_framesync_get_frame(fs, 0, &input_main, 0); + if (err < 0) + return err; + err = ff_framesync_get_frame(fs, 1, &input_overlay, 0); + if (err < 0) + return err; + + if (!ctx->initialised) { + AVHWFramesContext *main_fc = + (AVHWFramesContext*)input_main->hw_frames_ctx->data; + AVHWFramesContext *overlay_fc = + (AVHWFramesContext*)input_overlay->hw_frames_ctx->data; + + err = overlay_opencl_load(avctx, main_fc->sw_format, + overlay_fc->sw_format); + if (err < 0) + return err; + } + + output = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!output) { + err = AVERROR(ENOMEM); + goto fail; + } + + for (plane = 0; plane < ctx->nb_planes; plane++) { + kernel_arg = 0; + + mem = (cl_mem)output->data[plane]; + cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_mem), &mem); + if (cle != CL_SUCCESS) + goto fail_kernel_arg; + + mem = (cl_mem)input_main->data[plane]; + cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_mem), &mem); + if (cle != CL_SUCCESS) + goto fail_kernel_arg; + + mem = (cl_mem)input_overlay->data[plane]; + cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_mem), &mem); + if (cle != CL_SUCCESS) + goto fail_kernel_arg; + + if (ctx->alpha_separate) { + mem = (cl_mem)input_overlay->data[ctx->nb_planes]; + cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_mem), &mem); + if (cle != CL_SUCCESS) + goto fail_kernel_arg; + } + + x = ctx->x_position / (plane == 0 ? 1 : ctx->x_subsample); + y = ctx->y_position / (plane == 0 ? 1 : ctx->y_subsample); + + cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_int), &x); + if (cle != CL_SUCCESS) + goto fail_kernel_arg; + cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_int), &y); + if (cle != CL_SUCCESS) + goto fail_kernel_arg; + + if (ctx->alpha_separate) { + cl_int alpha_adj_x = plane == 0 ? 1 : ctx->x_subsample; + cl_int alpha_adj_y = plane == 0 ? 1 : ctx->y_subsample; + + cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_int), &alpha_adj_x); + if (cle != CL_SUCCESS) + goto fail_kernel_arg; + cle = clSetKernelArg(ctx->kernel, kernel_arg++, sizeof(cl_int), &alpha_adj_y); + if (cle != CL_SUCCESS) + goto fail_kernel_arg; + } + + err = ff_opencl_filter_work_size_from_image(avctx, global_work, + output, plane, 0); + if (err < 0) + goto fail; + + cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel, 2, NULL, + global_work, NULL, 0, NULL, NULL); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to enqueue " + "overlay kernel for plane %d: %d.\n", cle, plane); + err = AVERROR(EIO); + goto fail; + } + } + + cle = clFinish(ctx->command_queue); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to finish " + "command queue: %d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + + err = av_frame_copy_props(output, input_main); + + av_log(avctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(output->format), + output->width, output->height, output->pts); + + return ff_filter_frame(outlink, output); + +fail_kernel_arg: + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel arg %d: %d.\n", + kernel_arg, cle); + err = AVERROR(EIO); +fail: + av_frame_free(&output); + return err; +} + +static int overlay_opencl_config_output(AVFilterLink *outlink) +{ + AVFilterContext *avctx = outlink->src; + OverlayOpenCLContext *ctx = avctx->priv; + int err; + + err = ff_opencl_filter_config_output(outlink); + if (err < 0) + return err; + + err = ff_framesync_init_dualinput(&ctx->fs, avctx); + if (err < 0) + return err; + + return ff_framesync_configure(&ctx->fs); +} + +static av_cold int overlay_opencl_init(AVFilterContext *avctx) +{ + OverlayOpenCLContext *ctx = avctx->priv; + + ctx->fs.on_event = &overlay_opencl_blend; + + return ff_opencl_filter_init(avctx); +} + +static int overlay_opencl_activate(AVFilterContext *avctx) +{ + OverlayOpenCLContext *ctx = avctx->priv; + + return ff_framesync_activate(&ctx->fs); +} + +static av_cold void overlay_opencl_uninit(AVFilterContext *avctx) +{ + OverlayOpenCLContext *ctx = avctx->priv; + cl_int cle; + + if (ctx->kernel) { + cle = clReleaseKernel(ctx->kernel); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "kernel: %d.\n", cle); + } + + if (ctx->command_queue) { + cle = clReleaseCommandQueue(ctx->command_queue); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "command queue: %d.\n", cle); + } + + ff_opencl_filter_uninit(avctx); + + ff_framesync_uninit(&ctx->fs); +} + +#define OFFSET(x) offsetof(OverlayOpenCLContext, x) +#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM) +static const AVOption overlay_opencl_options[] = { + { "x", "Overlay x position", + OFFSET(x_position), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, .flags = FLAGS }, + { "y", "Overlay y position", + OFFSET(y_position), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, .flags = FLAGS }, + { NULL }, +}; + +AVFILTER_DEFINE_CLASS(overlay_opencl); + +static const AVFilterPad overlay_opencl_inputs[] = { + { + .name = "main", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &ff_opencl_filter_config_input, + }, + { + .name = "overlay", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &ff_opencl_filter_config_input, + }, + { NULL } +}; + +static const AVFilterPad overlay_opencl_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &overlay_opencl_config_output, + }, + { NULL } +}; + +AVFilter ff_vf_overlay_opencl = { + .name = "overlay_opencl", + .description = NULL_IF_CONFIG_SMALL("Overlay one video on top of another"), + .priv_size = sizeof(OverlayOpenCLContext), + .priv_class = &overlay_opencl_class, + .init = &overlay_opencl_init, + .uninit = &overlay_opencl_uninit, + .query_formats = &ff_opencl_filter_query_formats, + .activate = &overlay_opencl_activate, + .inputs = overlay_opencl_inputs, + .outputs = overlay_opencl_outputs, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; diff --git a/libavfilter/vf_overlay_qsv.c b/libavfilter/vf_overlay_qsv.c new file mode 100644 index 0000000000000..6c3efdbeb5f5a --- /dev/null +++ b/libavfilter/vf_overlay_qsv.c @@ -0,0 +1,493 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * A hardware accelerated overlay filter based on Intel Quick Sync Video VPP + */ + +#include "libavutil/opt.h" +#include "libavutil/common.h" +#include "libavutil/pixdesc.h" +#include "libavutil/eval.h" +#include "libavutil/hwcontext.h" +#include "libavutil/avstring.h" +#include "libavutil/avassert.h" +#include "libavutil/imgutils.h" +#include "libavutil/mathematics.h" + +#include "internal.h" +#include "avfilter.h" +#include "formats.h" +#include "video.h" + +#include "qsvvpp.h" + +#define MAIN 0 +#define OVERLAY 1 + +#define OFFSET(x) offsetof(QSVOverlayContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM) + +enum var_name { + VAR_MAIN_iW, VAR_MW, + VAR_MAIN_iH, VAR_MH, + VAR_OVERLAY_iW, + VAR_OVERLAY_iH, + VAR_OVERLAY_X, VAR_OX, + VAR_OVERLAY_Y, VAR_OY, + VAR_OVERLAY_W, VAR_OW, + VAR_OVERLAY_H, VAR_OH, + VAR_VARS_NB +}; + +enum EOFAction { + EOF_ACTION_REPEAT, + EOF_ACTION_ENDALL +}; + +typedef struct QSVOverlayContext { + const AVClass *class; + + QSVVPPContext *qsv; + QSVVPPParam qsv_param; + mfxExtVPPComposite comp_conf; + double var_values[VAR_VARS_NB]; + + char *overlay_ox, *overlay_oy, *overlay_ow, *overlay_oh; + uint16_t overlay_alpha, overlay_pixel_alpha; + + enum EOFAction eof_action; /* action to take on EOF from source */ + + AVFrame *main; + AVFrame *over_prev, *over_next; +} QSVOverlayContext; + +static const char *const var_names[] = { + "main_w", "W", /* input width of the main layer */ + "main_h", "H", /* input height of the main layer */ + "overlay_iw", /* input width of the overlay layer */ + "overlay_ih", /* input height of the overlay layer */ + "overlay_x", "x", /* x position of the overlay layer inside of main */ + "overlay_y", "y", /* y position of the overlay layer inside of main */ + "overlay_w", "w", /* output width of overlay layer */ + "overlay_h", "h", /* output height of overlay layer */ + NULL +}; + +static const AVOption options[] = { + { "x", "Overlay x position", OFFSET(overlay_ox), AV_OPT_TYPE_STRING, { .str="0"}, 0, 255, .flags = FLAGS}, + { "y", "Overlay y position", OFFSET(overlay_oy), AV_OPT_TYPE_STRING, { .str="0"}, 0, 255, .flags = FLAGS}, + { "w", "Overlay width", OFFSET(overlay_ow), AV_OPT_TYPE_STRING, { .str="overlay_iw"}, 0, 255, .flags = FLAGS}, + { "h", "Overlay height", OFFSET(overlay_oh), AV_OPT_TYPE_STRING, { .str="overlay_ih*w/overlay_iw"}, 0, 255, .flags = FLAGS}, + { "alpha", "Overlay global alpha", OFFSET(overlay_alpha), AV_OPT_TYPE_INT, { .i64 = 255}, 0, 255, .flags = FLAGS}, + { "eof_action", "Action to take when encountering EOF from secondary input ", + OFFSET(eof_action), AV_OPT_TYPE_INT, { .i64 = EOF_ACTION_REPEAT }, + EOF_ACTION_REPEAT, EOF_ACTION_ENDALL, .flags = FLAGS, "eof_action" }, + { "repeat", "Repeat the previous frame.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_REPEAT }, .flags = FLAGS, "eof_action" }, + { "endall", "End both streams.", 0, AV_OPT_TYPE_CONST, { .i64 = EOF_ACTION_ENDALL }, .flags = FLAGS, "eof_action" }, + { NULL } +}; + +static int eval_expr(AVFilterContext *ctx) +{ + QSVOverlayContext *vpp = ctx->priv; + double *var_values = vpp->var_values; + int ret = 0; + AVExpr *ox_expr = NULL, *oy_expr = NULL; + AVExpr *ow_expr = NULL, *oh_expr = NULL; + +#define PASS_EXPR(e, s) {\ + ret = av_expr_parse(&e, s, var_names, NULL, NULL, NULL, NULL, 0, ctx); \ + if (ret < 0) {\ + av_log(ctx, AV_LOG_ERROR, "Error when passing '%s'.\n", s);\ + goto release;\ + }\ +} + PASS_EXPR(ox_expr, vpp->overlay_ox); + PASS_EXPR(oy_expr, vpp->overlay_oy); + PASS_EXPR(ow_expr, vpp->overlay_ow); + PASS_EXPR(oh_expr, vpp->overlay_oh); +#undef PASS_EXPR + + var_values[VAR_OVERLAY_W] = + var_values[VAR_OW] = av_expr_eval(ow_expr, var_values, NULL); + var_values[VAR_OVERLAY_H] = + var_values[VAR_OH] = av_expr_eval(oh_expr, var_values, NULL); + + /* calc again in case ow is relative to oh */ + var_values[VAR_OVERLAY_W] = + var_values[VAR_OW] = av_expr_eval(ow_expr, var_values, NULL); + + var_values[VAR_OVERLAY_X] = + var_values[VAR_OX] = av_expr_eval(ox_expr, var_values, NULL); + var_values[VAR_OVERLAY_Y] = + var_values[VAR_OY] = av_expr_eval(oy_expr, var_values, NULL); + + /* calc again in case ox is relative to oy */ + var_values[VAR_OVERLAY_X] = + var_values[VAR_OX] = av_expr_eval(ox_expr, var_values, NULL); + + /* calc overlay_w and overlay_h again incase relative to ox,oy */ + var_values[VAR_OVERLAY_W] = + var_values[VAR_OW] = av_expr_eval(ow_expr, var_values, NULL); + var_values[VAR_OVERLAY_H] = + var_values[VAR_OH] = av_expr_eval(oh_expr, var_values, NULL); + var_values[VAR_OVERLAY_W] = + var_values[VAR_OW] = av_expr_eval(ow_expr, var_values, NULL); + +release: + av_expr_free(ox_expr); + av_expr_free(oy_expr); + av_expr_free(ow_expr); + av_expr_free(oh_expr); + + return ret; +} + +static int have_alpha_planar(AVFilterLink *link) +{ + enum AVPixelFormat pix_fmt; + const AVPixFmtDescriptor *desc; + AVHWFramesContext *fctx; + + if (link->format == AV_PIX_FMT_QSV) { + fctx = (AVHWFramesContext *)link->hw_frames_ctx->data; + pix_fmt = fctx->sw_format; + } + + desc = av_pix_fmt_desc_get(pix_fmt); + if (!desc) + return 0; + + return !!(desc->flags & AV_PIX_FMT_FLAG_ALPHA); +} + +static int config_main_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + QSVOverlayContext *vpp = ctx->priv; + mfxVPPCompInputStream *st = &vpp->comp_conf.InputStream[0]; + + av_log(ctx, AV_LOG_DEBUG, "Input[%d] is of %s.\n", FF_INLINK_IDX(inlink), + av_get_pix_fmt_name(inlink->format)); + + vpp->var_values[VAR_MAIN_iW] = + vpp->var_values[VAR_MW] = inlink->w; + vpp->var_values[VAR_MAIN_iH] = + vpp->var_values[VAR_MH] = inlink->h; + + st->DstX = 0; + st->DstY = 0; + st->DstW = inlink->w; + st->DstH = inlink->h; + st->GlobalAlphaEnable = 0; + st->PixelAlphaEnable = 0; + + return 0; +} + +static int config_overlay_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + QSVOverlayContext *vpp = ctx->priv; + mfxVPPCompInputStream *st = &vpp->comp_conf.InputStream[1]; + int ret = 0; + + av_log(ctx, AV_LOG_DEBUG, "Input[%d] is of %s.\n", FF_INLINK_IDX(inlink), + av_get_pix_fmt_name(inlink->format)); + + vpp->var_values[VAR_OVERLAY_iW] = inlink->w; + vpp->var_values[VAR_OVERLAY_iH] = inlink->h; + + ret = eval_expr(ctx); + if (ret < 0) + return ret; + + st->DstX = vpp->var_values[VAR_OX]; + st->DstY = vpp->var_values[VAR_OY]; + st->DstW = vpp->var_values[VAR_OW]; + st->DstH = vpp->var_values[VAR_OH]; + st->GlobalAlpha = vpp->overlay_alpha; + st->GlobalAlphaEnable = (st->GlobalAlpha < 255); + st->PixelAlphaEnable = have_alpha_planar(inlink); + + return 0; +} + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + QSVOverlayContext *vpp = ctx->priv; + AVFilterLink *in0 = ctx->inputs[0]; + AVFilterLink *in1 = ctx->inputs[1]; + + av_log(ctx, AV_LOG_DEBUG, "Output is of %s.\n", av_get_pix_fmt_name(outlink->format)); + if ((in0->format == AV_PIX_FMT_QSV && in1->format != AV_PIX_FMT_QSV) || + (in0->format != AV_PIX_FMT_QSV && in1->format == AV_PIX_FMT_QSV)) { + av_log(ctx, AV_LOG_ERROR, "Mixing hardware and software pixel formats is not supported.\n"); + return AVERROR(EINVAL); + } else if (in0->format == AV_PIX_FMT_QSV) { + AVHWFramesContext *hw_frame0 = (AVHWFramesContext *)in0->hw_frames_ctx->data; + AVHWFramesContext *hw_frame1 = (AVHWFramesContext *)in1->hw_frames_ctx->data; + + if (hw_frame0->device_ctx != hw_frame1->device_ctx) { + av_log(ctx, AV_LOG_ERROR, "Inputs with different underlying QSV devices are forbidden.\n"); + return AVERROR(EINVAL); + } + } + + outlink->w = vpp->var_values[VAR_MW]; + outlink->h = vpp->var_values[VAR_MH]; + outlink->frame_rate = in0->frame_rate; + outlink->time_base = av_inv_q(outlink->frame_rate); + + return ff_qsvvpp_create(ctx, &vpp->qsv, &vpp->qsv_param); +} + +static int blend_frame(AVFilterContext *ctx, AVFrame *mpic, AVFrame *opic) +{ + int ret = 0; + QSVOverlayContext *vpp = ctx->priv; + AVFrame *opic_copy = NULL; + + ret = ff_qsvvpp_filter_frame(vpp->qsv, ctx->inputs[0], mpic); + if (ret == 0 || ret == AVERROR(EAGAIN)) { + /* Reference the overlay frame. Because: + * 1. ff_qsvvpp_filter_frame will take control of the given frame + * 2. We need to repeat the overlay frame when 2nd input goes into EOF + */ + opic_copy = av_frame_clone(opic); + if (!opic_copy) + return AVERROR(ENOMEM); + + ret = ff_qsvvpp_filter_frame(vpp->qsv, ctx->inputs[1], opic_copy); + } + + return ret; +} + +static int handle_overlay_eof(AVFilterContext *ctx) +{ + int ret = 0; + QSVOverlayContext *s = ctx->priv; + /* Repeat previous frame on secondary input */ + if (s->over_prev && s->eof_action == EOF_ACTION_REPEAT) + ret = blend_frame(ctx, s->main, s->over_prev); + /* End both streams */ + else if (s->eof_action == EOF_ACTION_ENDALL) + return AVERROR_EOF; + + s->main = NULL; + + return ret; +} + +static int request_frame(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + QSVOverlayContext *s = ctx->priv; + AVRational tb_main = ctx->inputs[MAIN]->time_base; + AVRational tb_over = ctx->inputs[OVERLAY]->time_base; + int ret = 0; + + /* get a frame on the main input */ + if (!s->main) { + ret = ff_request_frame(ctx->inputs[MAIN]); + if (ret < 0) + return ret; + } + + /* get a new frame on the overlay input, on EOF check setting 'eof_action' */ + if (!s->over_next) { + ret = ff_request_frame(ctx->inputs[OVERLAY]); + if (ret == AVERROR_EOF) + return handle_overlay_eof(ctx); + else if (ret < 0) + return ret; + } + + while (s->main->pts != AV_NOPTS_VALUE && + s->over_next->pts != AV_NOPTS_VALUE && + av_compare_ts(s->over_next->pts, tb_over, s->main->pts, tb_main) < 0) { + av_frame_free(&s->over_prev); + FFSWAP(AVFrame*, s->over_prev, s->over_next); + + ret = ff_request_frame(ctx->inputs[OVERLAY]); + if (ret == AVERROR_EOF) + return handle_overlay_eof(ctx); + else if (ret < 0) + return ret; + } + + if (s->main->pts == AV_NOPTS_VALUE || + s->over_next->pts == AV_NOPTS_VALUE || + !av_compare_ts(s->over_next->pts, tb_over, s->main->pts, tb_main)) { + ret = blend_frame(ctx, s->main, s->over_next); + av_frame_free(&s->over_prev); + FFSWAP(AVFrame*, s->over_prev, s->over_next); + } else if (s->over_prev) { + ret = blend_frame(ctx, s->main, s->over_prev); + } else { + av_frame_free(&s->main); + ret = AVERROR(EAGAIN); + } + + s->main = NULL; + + return ret; +} + +static int filter_frame_main(AVFilterLink *inlink, AVFrame *frame) +{ + QSVOverlayContext *s = inlink->dst->priv; + + av_assert0(!s->main); + s->main = frame; + + return 0; +} + +static int filter_frame_overlay(AVFilterLink *inlink, AVFrame *frame) +{ + QSVOverlayContext *s = inlink->dst->priv; + + av_assert0(!s->over_next); + s->over_next = frame; + + return 0; +} + +static int overlay_qsv_init(AVFilterContext *ctx) +{ + QSVOverlayContext *vpp = ctx->priv; + + /* fill composite config */ + vpp->comp_conf.Header.BufferId = MFX_EXTBUFF_VPP_COMPOSITE; + vpp->comp_conf.Header.BufferSz = sizeof(vpp->comp_conf); + vpp->comp_conf.NumInputStream = ctx->nb_inputs; + vpp->comp_conf.InputStream = av_mallocz_array(ctx->nb_inputs, + sizeof(*vpp->comp_conf.InputStream)); + if (!vpp->comp_conf.InputStream) + return AVERROR(ENOMEM); + + /* initialize QSVVPP params */ + vpp->qsv_param.filter_frame = NULL; + vpp->qsv_param.ext_buf = av_mallocz(sizeof(*vpp->qsv_param.ext_buf)); + if (!vpp->qsv_param.ext_buf) + return AVERROR(ENOMEM); + + vpp->qsv_param.ext_buf[0] = (mfxExtBuffer *)&vpp->comp_conf; + vpp->qsv_param.num_ext_buf = 1; + vpp->qsv_param.out_sw_format = AV_PIX_FMT_NV12; + vpp->qsv_param.num_crop = 0; + + return 0; +} + +static void overlay_qsv_uninit(AVFilterContext *ctx) +{ + QSVOverlayContext *vpp = ctx->priv; + + av_frame_free(&vpp->main); + av_frame_free(&vpp->over_prev); + av_frame_free(&vpp->over_next); + ff_qsvvpp_free(&vpp->qsv); + av_freep(&vpp->comp_conf.InputStream); + av_freep(&vpp->qsv_param.ext_buf); +} + +static int overlay_qsv_query_formats(AVFilterContext *ctx) +{ + int i; + int ret; + + static const enum AVPixelFormat main_in_fmts[] = { + AV_PIX_FMT_YUV420P, + AV_PIX_FMT_NV12, + AV_PIX_FMT_YUYV422, + AV_PIX_FMT_RGB32, + AV_PIX_FMT_QSV, + AV_PIX_FMT_NONE + }; + static const enum AVPixelFormat out_pix_fmts[] = { + AV_PIX_FMT_NV12, + AV_PIX_FMT_QSV, + AV_PIX_FMT_NONE + }; + + for (i = 0; i < ctx->nb_inputs; i++) { + ret = ff_formats_ref(ff_make_format_list(main_in_fmts), &ctx->inputs[i]->out_formats); + if (ret < 0) + return ret; + } + + ret = ff_formats_ref(ff_make_format_list(out_pix_fmts), &ctx->outputs[0]->in_formats); + if (ret < 0) + return ret; + + return 0; +} + +static const AVClass overlay_qsv_class = { + .class_name = "overlay_qsv", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const AVFilterPad overlay_qsv_inputs[] = { + { + .name = "main", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame_main, + .config_props = config_main_input, + .needs_fifo = 1, + }, + { + .name = "overlay", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame_overlay, + .config_props = config_overlay_input, + .needs_fifo = 1, + }, + { NULL } +}; + +static const AVFilterPad overlay_qsv_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_output, + .request_frame = request_frame, + }, + { NULL } +}; + +AVFilter ff_vf_overlay_qsv = { + .name = "overlay_qsv", + .description = NULL_IF_CONFIG_SMALL("Quick Sync Video overlay."), + .priv_size = sizeof(QSVOverlayContext), + .query_formats = overlay_qsv_query_formats, + .init = overlay_qsv_init, + .uninit = overlay_qsv_uninit, + .inputs = overlay_qsv_inputs, + .outputs = overlay_qsv_outputs, + .priv_class = &overlay_qsv_class, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; diff --git a/libavfilter/vf_palettegen.c b/libavfilter/vf_palettegen.c index 03de3173483e2..5ff73e6b2b0d9 100644 --- a/libavfilter/vf_palettegen.c +++ b/libavfilter/vf_palettegen.c @@ -27,6 +27,7 @@ #include "libavutil/internal.h" #include "libavutil/opt.h" #include "libavutil/qsort.h" +#include "libavutil/intreadwrite.h" #include "avfilter.h" #include "internal.h" @@ -74,6 +75,7 @@ typedef struct PaletteGenContext { struct range_box boxes[256]; // define the segmentation of the colorspace (the final palette) int nb_boxes; // number of boxes (increase will segmenting them) int palette_pushed; // if the palette frame is pushed into the outlink or not + uint8_t transparency_color[4]; // background color for transparency } PaletteGenContext; #define OFFSET(x) offsetof(PaletteGenContext, x) @@ -81,6 +83,7 @@ typedef struct PaletteGenContext { static const AVOption palettegen_options[] = { { "max_colors", "set the maximum number of colors to use in the palette", OFFSET(max_colors), AV_OPT_TYPE_INT, {.i64=256}, 4, 256, FLAGS }, { "reserve_transparent", "reserve a palette entry for transparency", OFFSET(reserve_transparent), AV_OPT_TYPE_BOOL, {.i64=1}, 0, 1, FLAGS }, + { "transparency_color", "set a background color for transparency", OFFSET(transparency_color), AV_OPT_TYPE_COLOR, {.str="lime"}, CHAR_MIN, CHAR_MAX, FLAGS }, { "stats_mode", "set statistics mode", OFFSET(stats_mode), AV_OPT_TYPE_INT, {.i64=STATS_MODE_ALL_FRAMES}, 0, NB_STATS_MODE-1, FLAGS, "mode" }, { "full", "compute full frame histograms", 0, AV_OPT_TYPE_CONST, {.i64=STATS_MODE_ALL_FRAMES}, INT_MIN, INT_MAX, FLAGS, "mode" }, { "diff", "compute histograms only for the part that differs from previous frame", 0, AV_OPT_TYPE_CONST, {.i64=STATS_MODE_DIFF_FRAMES}, INT_MIN, INT_MAX, FLAGS, "mode" }, @@ -250,7 +253,7 @@ static void write_palette(AVFilterContext *ctx, AVFrame *out) if (s->reserve_transparent) { av_assert0(s->nb_boxes < 256); - pal[out->width - pal_linesize - 1] = 0x0000ff00; // add a green transparent color + pal[out->width - pal_linesize - 1] = AV_RB32(&s->transparency_color) >> 8; } } diff --git a/libavfilter/vf_paletteuse.c b/libavfilter/vf_paletteuse.c index 79a06728919e9..604a8af29c655 100644 --- a/libavfilter/vf_paletteuse.c +++ b/libavfilter/vf_paletteuse.c @@ -56,7 +56,7 @@ enum diff_mode { }; struct color_node { - uint8_t val[3]; + uint8_t val[4]; uint8_t palette_id; int split; int left_id, right_id; @@ -86,6 +86,8 @@ typedef struct PaletteUseContext { struct cache_node cache[CACHE_SIZE]; /* lookup cache */ struct color_node map[AVPALETTE_COUNT]; /* 3D-Tree (KD-Tree with K=3) for reverse colormap */ uint32_t palette[AVPALETTE_COUNT]; + int transparency_index; /* index in the palette of transparency. -1 if there is no transparency in the palette. */ + int trans_thresh; int palette_loaded; int dither; int new; @@ -116,6 +118,8 @@ static const AVOption paletteuse_options[] = { { "bayer_scale", "set scale for bayer dithering", OFFSET(bayer_scale), AV_OPT_TYPE_INT, {.i64=2}, 0, 5, FLAGS }, { "diff_mode", "set frame difference mode", OFFSET(diff_mode), AV_OPT_TYPE_INT, {.i64=DIFF_MODE_NONE}, 0, NB_DIFF_MODE-1, FLAGS, "diff_mode" }, { "rectangle", "process smallest different rectangle", 0, AV_OPT_TYPE_CONST, {.i64=DIFF_MODE_RECTANGLE}, INT_MIN, INT_MAX, FLAGS, "diff_mode" }, + { "new", "take new palette for each output frame", OFFSET(new), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS }, + { "alpha_threshold", "set the alpha threshold for transparency", OFFSET(trans_thresh), AV_OPT_TYPE_INT, {.i64=128}, 0, 255 }, /* following are the debug options, not part of the official API */ { "debug_kdtree", "save Graphviz graph of the kdtree in specified file", OFFSET(dot_filename), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, @@ -125,7 +129,6 @@ static const AVOption paletteuse_options[] = { { "bruteforce", "brute-force into the palette", 0, AV_OPT_TYPE_CONST, {.i64=COLOR_SEARCH_BRUTEFORCE}, INT_MIN, INT_MAX, FLAGS, "search" }, { "mean_err", "compute and print mean error", OFFSET(calc_mean_err), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS }, { "debug_accuracy", "test color search accuracy", OFFSET(debug_accuracy), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS }, - { "new", "take new palette for each output frame", OFFSET(new), AV_OPT_TYPE_BOOL, {.i64=0}, 0, 1, FLAGS }, { NULL } }; @@ -157,34 +160,43 @@ static int query_formats(AVFilterContext *ctx) static av_always_inline int dither_color(uint32_t px, int er, int eg, int eb, int scale, int shift) { - return av_clip_uint8((px >> 16 & 0xff) + ((er * scale) / (1<> 24 ) << 24 + | av_clip_uint8((px >> 16 & 0xff) + ((er * scale) / (1<> 8 & 0xff) + ((eg * scale) / (1<= trans_thresh && c2[0] >= trans_thresh) { + return dr*dr + dg*dg + db*db; + } else { + return 255*255 + 255*255 + 255*255; + } } -static av_always_inline uint8_t colormap_nearest_bruteforce(const uint32_t *palette, const uint8_t *rgb) +static av_always_inline uint8_t colormap_nearest_bruteforce(const uint32_t *palette, const uint8_t *argb, const int trans_thresh) { int i, pal_id = -1, min_dist = INT_MAX; for (i = 0; i < AVPALETTE_COUNT; i++) { const uint32_t c = palette[i]; - if ((c & 0xff000000) == 0xff000000) { // ignore transparent entry - const uint8_t palrgb[] = { + if (c >> 24 >= trans_thresh) { // ignore transparent entry + const uint8_t palargb[] = { + palette[i]>>24 & 0xff, palette[i]>>16 & 0xff, palette[i]>> 8 & 0xff, palette[i] & 0xff, }; - const int d = diff(palrgb, rgb); + const int d = diff(palargb, argb, trans_thresh); if (d < min_dist) { pal_id = i; min_dist = d; @@ -203,13 +215,14 @@ struct nearest_color { static void colormap_nearest_node(const struct color_node *map, const int node_pos, const uint8_t *target, + const int trans_thresh, struct nearest_color *nearest) { const struct color_node *kd = map + node_pos; const int s = kd->split; int dx, nearer_kd_id, further_kd_id; const uint8_t *current = kd->val; - const int current_to_target = diff(target, current); + const int current_to_target = diff(target, current, trans_thresh); if (current_to_target < nearest->dist_sqd) { nearest->node_pos = node_pos; @@ -223,17 +236,17 @@ static void colormap_nearest_node(const struct color_node *map, else nearer_kd_id = kd->right_id, further_kd_id = kd->left_id; if (nearer_kd_id != -1) - colormap_nearest_node(map, nearer_kd_id, target, nearest); + colormap_nearest_node(map, nearer_kd_id, target, trans_thresh, nearest); if (further_kd_id != -1 && dx*dx < nearest->dist_sqd) - colormap_nearest_node(map, further_kd_id, target, nearest); + colormap_nearest_node(map, further_kd_id, target, trans_thresh, nearest); } } -static av_always_inline uint8_t colormap_nearest_recursive(const struct color_node *node, const uint8_t *rgb) +static av_always_inline uint8_t colormap_nearest_recursive(const struct color_node *node, const uint8_t *rgb, const int trans_thresh) { struct nearest_color res = {.dist_sqd = INT_MAX, .node_pos = -1}; - colormap_nearest_node(node, 0, rgb, &res); + colormap_nearest_node(node, 0, rgb, trans_thresh, &res); return node[res.node_pos].palette_id; } @@ -242,7 +255,7 @@ struct stack_node { int dx2; }; -static av_always_inline uint8_t colormap_nearest_iterative(const struct color_node *root, const uint8_t *target) +static av_always_inline uint8_t colormap_nearest_iterative(const struct color_node *root, const uint8_t *target, const int trans_thresh) { int pos = 0, best_node_id = -1, best_dist = INT_MAX, cur_color_id = 0; struct stack_node nodes[16]; @@ -252,7 +265,7 @@ static av_always_inline uint8_t colormap_nearest_iterative(const struct color_no const struct color_node *kd = &root[cur_color_id]; const uint8_t *current = kd->val; - const int current_to_target = diff(target, current); + const int current_to_target = diff(target, current, trans_thresh); /* Compare current color node to the target and update our best node if * it's actually better. */ @@ -314,32 +327,35 @@ static av_always_inline uint8_t colormap_nearest_iterative(const struct color_no return root[best_node_id].palette_id; } -#define COLORMAP_NEAREST(search, palette, root, target) \ - search == COLOR_SEARCH_NNS_ITERATIVE ? colormap_nearest_iterative(root, target) : \ - search == COLOR_SEARCH_NNS_RECURSIVE ? colormap_nearest_recursive(root, target) : \ - colormap_nearest_bruteforce(palette, target) +#define COLORMAP_NEAREST(search, palette, root, target, trans_thresh) \ + search == COLOR_SEARCH_NNS_ITERATIVE ? colormap_nearest_iterative(root, target, trans_thresh) : \ + search == COLOR_SEARCH_NNS_RECURSIVE ? colormap_nearest_recursive(root, target, trans_thresh) : \ + colormap_nearest_bruteforce(palette, target, trans_thresh) /** * Check if the requested color is in the cache already. If not, find it in the * color tree and cache it. - * Note: r, g, and b are the component of c but are passed as well to avoid + * Note: a, r, g, and b are the components of color, but are passed as well to avoid * recomputing them (they are generally computed by the caller for other uses). */ -static av_always_inline int color_get(struct cache_node *cache, uint32_t color, - uint8_t r, uint8_t g, uint8_t b, - const struct color_node *map, - const uint32_t *palette, +static av_always_inline int color_get(PaletteUseContext *s, uint32_t color, + uint8_t a, uint8_t r, uint8_t g, uint8_t b, const enum color_search_method search_method) { int i; - const uint8_t rgb[] = {r, g, b}; + const uint8_t argb_elts[] = {a, r, g, b}; const uint8_t rhash = r & ((1<cache[hash]; struct cached_color *e; + // first, check for transparency + if (a < s->trans_thresh && s->transparency_index >= 0) { + return s->transparency_index; + } + for (i = 0; i < node->nb_entries; i++) { e = &node->entries[i]; if (e->color == color) @@ -351,21 +367,24 @@ static av_always_inline int color_get(struct cache_node *cache, uint32_t color, if (!e) return AVERROR(ENOMEM); e->color = color; - e->pal_entry = COLORMAP_NEAREST(search_method, palette, map, rgb); + e->pal_entry = COLORMAP_NEAREST(search_method, s->palette, s->map, argb_elts, s->trans_thresh); + return e->pal_entry; } -static av_always_inline int get_dst_color_err(struct cache_node *cache, - uint32_t c, const struct color_node *map, - const uint32_t *palette, - int *er, int *eg, int *eb, +static av_always_inline int get_dst_color_err(PaletteUseContext *s, + uint32_t c, int *er, int *eg, int *eb, const enum color_search_method search_method) { + const uint8_t a = c >> 24 & 0xff; const uint8_t r = c >> 16 & 0xff; const uint8_t g = c >> 8 & 0xff; const uint8_t b = c & 0xff; - const int dstx = color_get(cache, c, r, g, b, map, palette, search_method); - const uint32_t dstc = palette[dstx]; + uint32_t dstc; + const int dstx = color_get(s, c, a, r, g, b, search_method); + if (dstx < 0) + return dstx; + dstc = s->palette[dstx]; *er = r - (dstc >> 16 & 0xff); *eg = g - (dstc >> 8 & 0xff); *eb = b - (dstc & 0xff); @@ -378,9 +397,6 @@ static av_always_inline int set_frame(PaletteUseContext *s, AVFrame *out, AVFram const enum color_search_method search_method) { int x, y; - const struct color_node *map = s->map; - struct cache_node *cache = s->cache; - const uint32_t *palette = s->palette; const int src_linesize = in ->linesize[0] >> 2; const int dst_linesize = out->linesize[0]; uint32_t *src = ((uint32_t *)in ->data[0]) + y_start*src_linesize; @@ -395,14 +411,14 @@ static av_always_inline int set_frame(PaletteUseContext *s, AVFrame *out, AVFram if (dither == DITHERING_BAYER) { const int d = s->ordered_dither[(y & 7)<<3 | (x & 7)]; + const uint8_t a8 = src[x] >> 24 & 0xff; const uint8_t r8 = src[x] >> 16 & 0xff; const uint8_t g8 = src[x] >> 8 & 0xff; const uint8_t b8 = src[x] & 0xff; const uint8_t r = av_clip_uint8(r8 + d); const uint8_t g = av_clip_uint8(g8 + d); const uint8_t b = av_clip_uint8(b8 + d); - const uint32_t c = r<<16 | g<<8 | b; - const int color = color_get(cache, c, r, g, b, map, palette, search_method); + const int color = color_get(s, src[x], a8, r, g, b, search_method); if (color < 0) return color; @@ -410,7 +426,7 @@ static av_always_inline int set_frame(PaletteUseContext *s, AVFrame *out, AVFram } else if (dither == DITHERING_HECKBERT) { const int right = x < w - 1, down = y < h - 1; - const int color = get_dst_color_err(cache, src[x], map, palette, &er, &eg, &eb, search_method); + const int color = get_dst_color_err(s, src[x], &er, &eg, &eb, search_method); if (color < 0) return color; @@ -422,7 +438,7 @@ static av_always_inline int set_frame(PaletteUseContext *s, AVFrame *out, AVFram } else if (dither == DITHERING_FLOYD_STEINBERG) { const int right = x < w - 1, down = y < h - 1, left = x > x_start; - const int color = get_dst_color_err(cache, src[x], map, palette, &er, &eg, &eb, search_method); + const int color = get_dst_color_err(s, src[x], &er, &eg, &eb, search_method); if (color < 0) return color; @@ -436,7 +452,7 @@ static av_always_inline int set_frame(PaletteUseContext *s, AVFrame *out, AVFram } else if (dither == DITHERING_SIERRA2) { const int right = x < w - 1, down = y < h - 1, left = x > x_start; const int right2 = x < w - 2, left2 = x > x_start + 1; - const int color = get_dst_color_err(cache, src[x], map, palette, &er, &eg, &eb, search_method); + const int color = get_dst_color_err(s, src[x], &er, &eg, &eb, search_method); if (color < 0) return color; @@ -455,7 +471,7 @@ static av_always_inline int set_frame(PaletteUseContext *s, AVFrame *out, AVFram } else if (dither == DITHERING_SIERRA2_4A) { const int right = x < w - 1, down = y < h - 1, left = x > x_start; - const int color = get_dst_color_err(cache, src[x], map, palette, &er, &eg, &eb, search_method); + const int color = get_dst_color_err(s, src[x], &er, &eg, &eb, search_method); if (color < 0) return color; @@ -466,10 +482,11 @@ static av_always_inline int set_frame(PaletteUseContext *s, AVFrame *out, AVFram if ( down) src[src_linesize + x ] = dither_color(src[src_linesize + x ], er, eg, eb, 1, 2); } else { + const uint8_t a = src[x] >> 24 & 0xff; const uint8_t r = src[x] >> 16 & 0xff; const uint8_t g = src[x] >> 8 & 0xff; const uint8_t b = src[x] & 0xff; - const int color = color_get(cache, src[x] & 0xffffff, r, g, b, map, palette, search_method); + const int color = color_get(s, src[x], a, r, g, b, search_method); if (color < 0) return color; @@ -489,19 +506,20 @@ static void disp_node(AVBPrint *buf, int depth) { const struct color_node *node = &map[node_id]; - const uint32_t fontcolor = node->val[0] > 0x50 && - node->val[1] > 0x50 && - node->val[2] > 0x50 ? 0 : 0xffffff; + const uint32_t fontcolor = node->val[1] > 0x50 && + node->val[2] > 0x50 && + node->val[3] > 0x50 ? 0 : 0xffffff; + const int rgb_comp = node->split - 1; av_bprintf(buf, "%*cnode%d [" "label=\"%c%02X%c%02X%c%02X%c\" " "fillcolor=\"#%02x%02x%02x\" " "fontcolor=\"#%06"PRIX32"\"]\n", depth*INDENT, ' ', node->palette_id, - "[ "[node->split], node->val[0], - "][ "[node->split], node->val[1], - " ]["[node->split], node->val[2], - " ]"[node->split], - node->val[0], node->val[1], node->val[2], + "[ "[rgb_comp], node->val[1], + "][ "[rgb_comp], node->val[2], + " ]["[rgb_comp], node->val[3], + " ]"[rgb_comp], + node->val[1], node->val[2], node->val[3], fontcolor); if (parent_id != -1) av_bprintf(buf, "%*cnode%d -> node%d\n", depth*INDENT, ' ', @@ -536,7 +554,7 @@ static int disp_tree(const struct color_node *node, const char *fname) return 0; } -static int debug_accuracy(const struct color_node *node, const uint32_t *palette, +static int debug_accuracy(const struct color_node *node, const uint32_t *palette, const int trans_thresh, const enum color_search_method search_method) { int r, g, b, ret = 0; @@ -544,16 +562,16 @@ static int debug_accuracy(const struct color_node *node, const uint32_t *palette for (r = 0; r < 256; r++) { for (g = 0; g < 256; g++) { for (b = 0; b < 256; b++) { - const uint8_t rgb[] = {r, g, b}; - const int r1 = COLORMAP_NEAREST(search_method, palette, node, rgb); - const int r2 = colormap_nearest_bruteforce(palette, rgb); + const uint8_t argb[] = {0xff, r, g, b}; + const int r1 = COLORMAP_NEAREST(search_method, palette, node, argb, trans_thresh); + const int r2 = colormap_nearest_bruteforce(palette, argb, trans_thresh); if (r1 != r2) { const uint32_t c1 = palette[r1]; const uint32_t c2 = palette[r2]; - const uint8_t palrgb1[] = { c1>>16 & 0xff, c1>> 8 & 0xff, c1 & 0xff }; - const uint8_t palrgb2[] = { c2>>16 & 0xff, c2>> 8 & 0xff, c2 & 0xff }; - const int d1 = diff(palrgb1, rgb); - const int d2 = diff(palrgb2, rgb); + const uint8_t palargb1[] = { 0xff, c1>>16 & 0xff, c1>> 8 & 0xff, c1 & 0xff }; + const uint8_t palargb2[] = { 0xff, c2>>16 & 0xff, c2>> 8 & 0xff, c2 & 0xff }; + const int d1 = diff(palargb1, argb, trans_thresh); + const int d2 = diff(palargb2, argb, trans_thresh); if (d1 != d2) { av_log(NULL, AV_LOG_ERROR, "/!\\ %02X%02X%02X: %d ! %d (%06"PRIX32" ! %06"PRIX32") / dist: %d ! %d\n", @@ -584,17 +602,19 @@ static int cmp_##name(const void *pa, const void *pb) \ { \ const struct color *a = pa; \ const struct color *b = pb; \ - return (a->value >> (8 * (2 - (pos))) & 0xff) \ - - (b->value >> (8 * (2 - (pos))) & 0xff); \ + return (a->value >> (8 * (3 - (pos))) & 0xff) \ + - (b->value >> (8 * (3 - (pos))) & 0xff); \ } -DECLARE_CMP_FUNC(r, 0) -DECLARE_CMP_FUNC(g, 1) -DECLARE_CMP_FUNC(b, 2) +DECLARE_CMP_FUNC(a, 0) +DECLARE_CMP_FUNC(r, 1) +DECLARE_CMP_FUNC(g, 2) +DECLARE_CMP_FUNC(b, 3) -static const cmp_func cmp_funcs[] = {cmp_r, cmp_g, cmp_b}; +static const cmp_func cmp_funcs[] = {cmp_a, cmp_r, cmp_g, cmp_b}; static int get_next_color(const uint8_t *color_used, const uint32_t *palette, + const int trans_thresh, int *component, const struct color_rect *box) { int wr, wg, wb; @@ -609,11 +629,16 @@ static int get_next_color(const uint8_t *color_used, const uint32_t *palette, for (i = 0; i < AVPALETTE_COUNT; i++) { const uint32_t c = palette[i]; + const uint8_t a = c >> 24 & 0xff; const uint8_t r = c >> 16 & 0xff; const uint8_t g = c >> 8 & 0xff; const uint8_t b = c & 0xff; - if (color_used[i] || + if (a < trans_thresh) { + continue; + } + + if (color_used[i] || (a != 0xff) || r < box->min[0] || g < box->min[1] || b < box->min[2] || r > box->max[0] || g > box->max[1] || b > box->max[2]) continue; @@ -639,9 +664,9 @@ static int get_next_color(const uint8_t *color_used, const uint32_t *palette, wr = ranges.max[0] - ranges.min[0]; wg = ranges.max[1] - ranges.min[1]; wb = ranges.max[2] - ranges.min[2]; - if (wr >= wg && wr >= wb) longest = 0; - if (wg >= wr && wg >= wb) longest = 1; - if (wb >= wr && wb >= wg) longest = 2; + if (wr >= wg && wr >= wb) longest = 1; + if (wg >= wr && wg >= wb) longest = 2; + if (wb >= wr && wb >= wg) longest = 3; cmpf = cmp_funcs[longest]; *component = longest; @@ -655,6 +680,7 @@ static int colormap_insert(struct color_node *map, uint8_t *color_used, int *nb_used, const uint32_t *palette, + const int trans_thresh, const struct color_rect *box) { uint32_t c; @@ -662,7 +688,7 @@ static int colormap_insert(struct color_node *map, int node_left_id = -1, node_right_id = -1; struct color_node *node; struct color_rect box1, box2; - const int pal_id = get_next_color(color_used, palette, &component, box); + const int pal_id = get_next_color(color_used, palette, trans_thresh, &component, box); if (pal_id < 0) return -1; @@ -673,21 +699,22 @@ static int colormap_insert(struct color_node *map, node = &map[cur_id]; node->split = component; node->palette_id = pal_id; - node->val[0] = c>>16 & 0xff; - node->val[1] = c>> 8 & 0xff; - node->val[2] = c & 0xff; + node->val[0] = c>>24 & 0xff; + node->val[1] = c>>16 & 0xff; + node->val[2] = c>> 8 & 0xff; + node->val[3] = c & 0xff; color_used[pal_id] = 1; /* get the two boxes this node creates */ box1 = box2 = *box; - box1.max[component] = node->val[component]; - box2.min[component] = node->val[component] + 1; + box1.max[component-1] = node->val[component]; + box2.min[component-1] = node->val[component] + 1; - node_left_id = colormap_insert(map, color_used, nb_used, palette, &box1); + node_left_id = colormap_insert(map, color_used, nb_used, palette, trans_thresh, &box1); - if (box2.min[component] <= box2.max[component]) - node_right_id = colormap_insert(map, color_used, nb_used, palette, &box2); + if (box2.min[component-1] <= box2.max[component-1]) + node_right_id = colormap_insert(map, color_used, nb_used, palette, trans_thresh, &box2); node->left_id = node_left_id; node->right_id = node_right_id; @@ -711,6 +738,16 @@ static void load_colormap(PaletteUseContext *s) /* disable transparent colors and dups */ qsort(s->palette, AVPALETTE_COUNT, sizeof(*s->palette), cmp_pal_entry); + // update transparency index: + if (s->transparency_index >= 0) { + for (i = 0; i < AVPALETTE_COUNT; i++) { + if ((s->palette[i]>>24 & 0xff) == 0) { + s->transparency_index = i; // we are assuming at most one transparent color in palette + break; + } + } + } + for (i = 0; i < AVPALETTE_COUNT; i++) { const uint32_t c = s->palette[i]; if (i != 0 && c == last_color) { @@ -718,7 +755,7 @@ static void load_colormap(PaletteUseContext *s) continue; } last_color = c; - if ((c & 0xff000000) != 0xff000000) { + if (c >> 24 < s->trans_thresh) { color_used[i] = 1; // ignore transparent color(s) continue; } @@ -727,13 +764,13 @@ static void load_colormap(PaletteUseContext *s) box.min[0] = box.min[1] = box.min[2] = 0x00; box.max[0] = box.max[1] = box.max[2] = 0xff; - colormap_insert(s->map, color_used, &nb_used, s->palette, &box); + colormap_insert(s->map, color_used, &nb_used, s->palette, s->trans_thresh, &box); if (s->dot_filename) disp_tree(s->map, s->dot_filename); if (s->debug_accuracy) { - if (!debug_accuracy(s->map, s->palette, s->color_search_method)) + if (!debug_accuracy(s->map, s->palette, s->trans_thresh, s->color_search_method)) av_log(NULL, AV_LOG_INFO, "Accuracy check passed\n"); } } @@ -754,9 +791,9 @@ static void debug_mean_error(PaletteUseContext *s, const AVFrame *in1, for (x = 0; x < in1->width; x++) { const uint32_t c1 = src1[x]; const uint32_t c2 = palette[src2[x]]; - const uint8_t rgb1[] = {c1 >> 16 & 0xff, c1 >> 8 & 0xff, c1 & 0xff}; - const uint8_t rgb2[] = {c2 >> 16 & 0xff, c2 >> 8 & 0xff, c2 & 0xff}; - mean_err += diff(rgb1, rgb2); + const uint8_t argb1[] = {0xff, c1 >> 16 & 0xff, c1 >> 8 & 0xff, c1 & 0xff}; + const uint8_t argb2[] = {0xff, c2 >> 16 & 0xff, c2 >> 8 & 0xff, c2 & 0xff}; + mean_err += diff(argb1, argb2, s->trans_thresh); } src1 += src1_linesize; src2 += src2_linesize; @@ -857,9 +894,9 @@ static void set_processing_window(enum diff_mode diff_mode, *hp = height; } -static AVFrame *apply_palette(AVFilterLink *inlink, AVFrame *in) +static int apply_palette(AVFilterLink *inlink, AVFrame *in, AVFrame **outf) { - int x, y, w, h; + int x, y, w, h, ret; AVFilterContext *ctx = inlink->dst; PaletteUseContext *s = ctx->priv; AVFilterLink *outlink = inlink->dst->outputs[0]; @@ -867,7 +904,8 @@ static AVFrame *apply_palette(AVFilterLink *inlink, AVFrame *in) AVFrame *out = ff_get_video_buffer(outlink, outlink->w, outlink->h); if (!out) { av_frame_free(&in); - return NULL; + *outf = NULL; + return AVERROR(ENOMEM); } av_frame_copy_props(out, in); @@ -881,21 +919,25 @@ static AVFrame *apply_palette(AVFilterLink *inlink, AVFrame *in) av_frame_make_writable(s->last_in) < 0) { av_frame_free(&in); av_frame_free(&out); - return NULL; + *outf = NULL; + return AVERROR(ENOMEM); } ff_dlog(ctx, "%dx%d rect: (%d;%d) -> (%d,%d) [area:%dx%d]\n", w, h, x, y, x+w, y+h, in->width, in->height); - if (s->set_frame(s, out, in, x, y, w, h) < 0) { + ret = s->set_frame(s, out, in, x, y, w, h); + if (ret < 0) { av_frame_free(&out); - return NULL; + *outf = NULL; + return ret; } memcpy(out->data[1], s->palette, AVPALETTE_SIZE); if (s->calc_mean_err) debug_mean_error(s, in, out, inlink->frame_count_out); av_frame_free(&in); - return out; + *outf = out; + return 0; } static int config_output(AVFilterLink *outlink) @@ -941,6 +983,8 @@ static void load_palette(PaletteUseContext *s, const AVFrame *palette_frame) const uint32_t *p = (const uint32_t *)palette_frame->data[0]; const int p_linesize = palette_frame->linesize[0] >> 2; + s->transparency_index = -1; + if (s->new) { memset(s->palette, 0, sizeof(s->palette)); memset(s->map, 0, sizeof(s->map)); @@ -951,8 +995,13 @@ static void load_palette(PaletteUseContext *s, const AVFrame *palette_frame) i = 0; for (y = 0; y < palette_frame->height; y++) { - for (x = 0; x < palette_frame->width; x++) - s->palette[i++] = p[x]; + for (x = 0; x < palette_frame->width; x++) { + s->palette[i] = p[x]; + if (p[x]>>24 < s->trans_thresh) { + s->transparency_index = i; // we are assuming at most one transparent color in palette + } + i++; + } p += p_linesize; } @@ -967,7 +1016,7 @@ static int load_apply_palette(FFFrameSync *fs) AVFilterContext *ctx = fs->parent; AVFilterLink *inlink = ctx->inputs[0]; PaletteUseContext *s = ctx->priv; - AVFrame *master, *second, *out; + AVFrame *master, *second, *out = NULL; int ret; // writable for error diffusal dithering @@ -981,12 +1030,13 @@ static int load_apply_palette(FFFrameSync *fs) if (!s->palette_loaded) { load_palette(s, second); } - out = apply_palette(inlink, master); + ret = apply_palette(inlink, master, &out); + if (ret < 0) + goto error; return ff_filter_frame(ctx->outputs[0], out); error: av_frame_free(&master); - av_frame_free(&second); return ret; } diff --git a/libavfilter/vf_pixdesctest.c b/libavfilter/vf_pixdesctest.c index d6423acb91067..2d0749e20bc0b 100644 --- a/libavfilter/vf_pixdesctest.c +++ b/libavfilter/vf_pixdesctest.c @@ -81,7 +81,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) /* copy palette */ if (priv->pix_desc->flags & AV_PIX_FMT_FLAG_PAL || - priv->pix_desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) + ((priv->pix_desc->flags & FF_PSEUDOPAL) && out->data[1] && in->data[1])) memcpy(out->data[1], in->data[1], AVPALETTE_SIZE); for (c = 0; c < priv->pix_desc->nb_components; c++) { diff --git a/libavfilter/vf_premultiply.c b/libavfilter/vf_premultiply.c index 5120adc476693..4f250df3f4e4f 100644 --- a/libavfilter/vf_premultiply.c +++ b/libavfilter/vf_premultiply.c @@ -272,7 +272,7 @@ static void unpremultiply8offset(const uint8_t *msrc, const uint8_t *asrc, for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { if (asrc[x] > 0 && asrc[x] < 255) - dst[x] = FFMIN((msrc[x] - offset) * 255 / asrc[x] + offset, 255); + dst[x] = FFMIN(FFMAX(msrc[x] - offset, 0) * 255 / asrc[x] + offset, 255); else dst[x] = msrc[x]; } @@ -350,7 +350,7 @@ static void unpremultiply16offset(const uint8_t *mmsrc, const uint8_t *aasrc, for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { if (asrc[x] > 0 && asrc[x] < max) - dst[x] = FFMAX(FFMIN((msrc[x] - offset) * (unsigned)max / asrc[x] + offset, max), 0); + dst[x] = FFMAX(FFMIN(FFMAX(msrc[x] - offset, 0) * (unsigned)max / asrc[x] + offset, max), 0); else dst[x] = msrc[x]; } @@ -607,9 +607,10 @@ static int activate(AVFilterContext *ctx) int64_t pts; if ((ret = ff_inlink_consume_frame(ctx->inputs[0], &frame)) > 0) { - if ((ret = filter_frame(ctx, &out, frame, frame)) < 0) - return ret; + ret = filter_frame(ctx, &out, frame, frame); av_frame_free(&frame); + if (ret < 0) + return ret; ret = ff_filter_frame(ctx->outputs[0], out); } if (ret < 0) { diff --git a/libavfilter/vf_procamp_vaapi.c b/libavfilter/vf_procamp_vaapi.c new file mode 100644 index 0000000000000..10eccbe97d783 --- /dev/null +++ b/libavfilter/vf_procamp_vaapi.c @@ -0,0 +1,270 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include + +#include "libavutil/avassert.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "formats.h" +#include "internal.h" +#include "vaapi_vpp.h" + +// ProcAmp Min/Max/Default Values +#define BRIGHTNESS_MIN -100.0F +#define BRIGHTNESS_MAX 100.0F +#define BRIGHTNESS_DEFAULT 0.0F + +#define CONTRAST_MIN 0.0F +#define CONTRAST_MAX 10.0F +#define CONTRAST_DEFAULT 1.0F + +#define HUE_MIN -180.0F +#define HUE_MAX 180.0F +#define HUE_DEFAULT 0.0F + +#define SATURATION_MIN 0.0F +#define SATURATION_MAX 10.0F +#define SATURATION_DEFAULT 1.0F + +typedef struct ProcampVAAPIContext { + VAAPIVPPContext vpp_ctx; // must be the first field + + float bright; + float hue; + float saturation; + float contrast; +} ProcampVAAPIContext; + +static float map(float x, float in_min, float in_max, float out_min, float out_max) +{ + double slope, output; + + slope = 1.0 * (out_max - out_min) / (in_max - in_min); + output = out_min + slope * (x - in_min); + + return (float)output; +} + +static int procamp_vaapi_build_filter_params(AVFilterContext *avctx) +{ + VAAPIVPPContext *vpp_ctx = avctx->priv; + ProcampVAAPIContext *ctx = avctx->priv; + VAStatus vas; + VAProcFilterParameterBufferColorBalance procamp_params[4]; + VAProcFilterCapColorBalance procamp_caps[VAProcColorBalanceCount]; + int num_caps; + int i = 0; + + memset(&procamp_params, 0, sizeof(procamp_params)); + memset(&procamp_caps, 0, sizeof(procamp_caps)); + + num_caps = VAProcColorBalanceCount; + vas = vaQueryVideoProcFilterCaps(vpp_ctx->hwctx->display, vpp_ctx->va_context, + VAProcFilterColorBalance, &procamp_caps, &num_caps); + + if (vas != VA_STATUS_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to query procamp " + "filter caps: %d (%s).\n", vas, vaErrorStr(vas)); + return AVERROR(EIO); + } + + /* brightness */ + procamp_params[i].type = VAProcFilterColorBalance; + procamp_params[i].attrib = VAProcColorBalanceBrightness; + procamp_params[i].value = map(ctx->bright, BRIGHTNESS_MIN, BRIGHTNESS_MAX, + procamp_caps[VAProcColorBalanceBrightness-1].range.min_value, + procamp_caps[VAProcColorBalanceBrightness-1].range.max_value); + i++; + + /* contrast */ + procamp_params[i].type = VAProcFilterColorBalance; + procamp_params[i].attrib = VAProcColorBalanceContrast; + procamp_params[i].value = map(ctx->contrast, CONTRAST_MIN, CONTRAST_MAX, + procamp_caps[VAProcColorBalanceContrast-1].range.min_value, + procamp_caps[VAProcColorBalanceContrast-1].range.max_value); + i++; + + /* hue */ + procamp_params[i].type = VAProcFilterColorBalance; + procamp_params[i].attrib = VAProcColorBalanceHue; + procamp_params[i].value = map(ctx->hue, HUE_MIN, HUE_MAX, + procamp_caps[VAProcColorBalanceHue-1].range.min_value, + procamp_caps[VAProcColorBalanceHue-1].range.max_value); + i++; + + /* saturation */ + procamp_params[i].type = VAProcFilterColorBalance; + procamp_params[i].attrib = VAProcColorBalanceSaturation; + procamp_params[i].value = map(ctx->saturation, SATURATION_MIN, SATURATION_MAX, + procamp_caps[VAProcColorBalanceSaturation-1].range.min_value, + procamp_caps[VAProcColorBalanceSaturation-1].range.max_value); + i++; + + return ff_vaapi_vpp_make_param_buffers(avctx, + VAProcFilterParameterBufferType, + &procamp_params, + sizeof(procamp_params[0]), + i); +} + +static int procamp_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) +{ + AVFilterContext *avctx = inlink->dst; + AVFilterLink *outlink = avctx->outputs[0]; + VAAPIVPPContext *vpp_ctx = avctx->priv; + AVFrame *output_frame = NULL; + VASurfaceID input_surface, output_surface; + VAProcPipelineParameterBuffer params; + VARectangle input_region; + int err; + + av_log(avctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(input_frame->format), + input_frame->width, input_frame->height, input_frame->pts); + + if (vpp_ctx->va_context == VA_INVALID_ID) + return AVERROR(EINVAL); + + input_surface = (VASurfaceID)(uintptr_t)input_frame->data[3]; + av_log(avctx, AV_LOG_DEBUG, "Using surface %#x for procamp input.\n", + input_surface); + + output_frame = ff_get_video_buffer(outlink, vpp_ctx->output_width, + vpp_ctx->output_height); + if (!output_frame) { + err = AVERROR(ENOMEM); + goto fail; + } + + output_surface = (VASurfaceID)(uintptr_t)output_frame->data[3]; + av_log(avctx, AV_LOG_DEBUG, "Using surface %#x for procamp output.\n", + output_surface); + memset(¶ms, 0, sizeof(params)); + input_region = (VARectangle) { + .x = 0, + .y = 0, + .width = input_frame->width, + .height = input_frame->height, + }; + + params.surface = input_surface; + params.surface_region = &input_region; + params.surface_color_standard = + ff_vaapi_vpp_colour_standard(input_frame->colorspace); + + params.output_region = NULL; + params.output_background_color = 0xff000000; + params.output_color_standard = params.surface_color_standard; + + params.pipeline_flags = 0; + params.filter_flags = VA_FRAME_PICTURE; + + params.filters = &vpp_ctx->filter_buffers[0]; + params.num_filters = 1; + + err = ff_vaapi_vpp_render_picture(avctx, ¶ms, output_surface); + if (err < 0) + goto fail; + + err = av_frame_copy_props(output_frame, input_frame); + if (err < 0) + goto fail; + av_frame_free(&input_frame); + + av_log(avctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(output_frame->format), + output_frame->width, output_frame->height, output_frame->pts); + + return ff_filter_frame(outlink, output_frame); + +fail: + av_frame_free(&input_frame); + av_frame_free(&output_frame); + return err; +} + +static av_cold int procamp_vaapi_init(AVFilterContext *avctx) +{ + VAAPIVPPContext *vpp_ctx = avctx->priv; + + ff_vaapi_vpp_ctx_init(avctx); + vpp_ctx->pipeline_uninit = ff_vaapi_vpp_pipeline_uninit; + vpp_ctx->build_filter_params = procamp_vaapi_build_filter_params; + vpp_ctx->output_format = AV_PIX_FMT_NONE; + + return 0; +} + +#define OFFSET(x) offsetof(ProcampVAAPIContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM) +static const AVOption procamp_vaapi_options[] = { + { "b", "Output video brightness", + OFFSET(bright), AV_OPT_TYPE_FLOAT, { .dbl = BRIGHTNESS_DEFAULT }, BRIGHTNESS_MIN, BRIGHTNESS_MAX, .flags = FLAGS }, + { "brightness", "Output video brightness", + OFFSET(bright), AV_OPT_TYPE_FLOAT, { .dbl = BRIGHTNESS_DEFAULT }, BRIGHTNESS_MIN, BRIGHTNESS_MAX, .flags = FLAGS }, + { "s", "Output video saturation", + OFFSET(saturation), AV_OPT_TYPE_FLOAT, { .dbl = SATURATION_DEFAULT }, SATURATION_MIN, SATURATION_MAX, .flags = FLAGS }, + { "saturatio", "Output video saturation", + OFFSET(saturation), AV_OPT_TYPE_FLOAT, { .dbl = SATURATION_DEFAULT }, SATURATION_MIN, SATURATION_MAX, .flags = FLAGS }, + { "c", "Output video contrast", + OFFSET(contrast), AV_OPT_TYPE_FLOAT, { .dbl = CONTRAST_DEFAULT }, CONTRAST_MIN, CONTRAST_MAX, .flags = FLAGS }, + { "contrast", "Output video contrast", + OFFSET(contrast), AV_OPT_TYPE_FLOAT, { .dbl = CONTRAST_DEFAULT }, CONTRAST_MIN, CONTRAST_MAX, .flags = FLAGS }, + { "h", "Output video hue", + OFFSET(hue), AV_OPT_TYPE_FLOAT, { .dbl = HUE_DEFAULT }, HUE_MIN, HUE_MAX, .flags = FLAGS }, + { "hue", "Output video hue", + OFFSET(hue), AV_OPT_TYPE_FLOAT, { .dbl = HUE_DEFAULT }, HUE_MIN, HUE_MAX, .flags = FLAGS }, + { NULL }, +}; + +AVFILTER_DEFINE_CLASS(procamp_vaapi); + +static const AVFilterPad procamp_vaapi_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = &procamp_vaapi_filter_frame, + .config_props = &ff_vaapi_vpp_config_input, + }, + { NULL } +}; + +static const AVFilterPad procamp_vaapi_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &ff_vaapi_vpp_config_output, + }, + { NULL } +}; + +AVFilter ff_vf_procamp_vaapi = { + .name = "procamp_vaapi", + .description = NULL_IF_CONFIG_SMALL("ProcAmp (color balance) adjustments for hue, saturation, brightness, contrast"), + .priv_size = sizeof(ProcampVAAPIContext), + .init = &procamp_vaapi_init, + .uninit = &ff_vaapi_vpp_ctx_uninit, + .query_formats = &ff_vaapi_vpp_query_formats, + .inputs = procamp_vaapi_inputs, + .outputs = procamp_vaapi_outputs, + .priv_class = &procamp_vaapi_class, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; diff --git a/libavfilter/vf_program_opencl.c b/libavfilter/vf_program_opencl.c new file mode 100644 index 0000000000000..a0027923fb2b0 --- /dev/null +++ b/libavfilter/vf_program_opencl.c @@ -0,0 +1,440 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avstring.h" +#include "libavutil/log.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "framesync.h" +#include "internal.h" +#include "opencl.h" +#include "video.h" + +typedef struct ProgramOpenCLContext { + OpenCLFilterContext ocf; + + int loaded; + cl_uint index; + cl_kernel kernel; + cl_command_queue command_queue; + + FFFrameSync fs; + AVFrame **frames; + + const char *source_file; + const char *kernel_name; + int nb_inputs; + int width, height; + enum AVPixelFormat source_format; + AVRational source_rate; +} ProgramOpenCLContext; + +static int program_opencl_load(AVFilterContext *avctx) +{ + ProgramOpenCLContext *ctx = avctx->priv; + cl_int cle; + int err; + + err = ff_opencl_filter_load_program_from_file(avctx, ctx->source_file); + if (err < 0) + return err; + + ctx->command_queue = clCreateCommandQueue(ctx->ocf.hwctx->context, + ctx->ocf.hwctx->device_id, + 0, &cle); + if (!ctx->command_queue) { + av_log(avctx, AV_LOG_ERROR, "Failed to create OpenCL " + "command queue: %d.\n", cle); + return AVERROR(EIO); + } + + ctx->kernel = clCreateKernel(ctx->ocf.program, ctx->kernel_name, &cle); + if (!ctx->kernel) { + if (cle == CL_INVALID_KERNEL_NAME) { + av_log(avctx, AV_LOG_ERROR, "Kernel function '%s' not found in " + "program.\n", ctx->kernel_name); + } else { + av_log(avctx, AV_LOG_ERROR, "Failed to create kernel: %d.\n", cle); + } + return AVERROR(EIO); + } + + ctx->loaded = 1; + return 0; +} + +static int program_opencl_run(AVFilterContext *avctx) +{ + AVFilterLink *outlink = avctx->outputs[0]; + ProgramOpenCLContext *ctx = avctx->priv; + AVFrame *output = NULL; + cl_int cle; + size_t global_work[2]; + cl_mem src, dst; + int err, input, plane; + + if (!ctx->loaded) { + err = program_opencl_load(avctx); + if (err < 0) + return err; + } + + output = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!output) { + err = AVERROR(ENOMEM); + goto fail; + } + + for (plane = 0; plane < FF_ARRAY_ELEMS(output->data); plane++) { + dst = (cl_mem)output->data[plane]; + if (!dst) + break; + + cle = clSetKernelArg(ctx->kernel, 0, sizeof(cl_mem), &dst); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "destination image argument: %d.\n", cle); + err = AVERROR_UNKNOWN; + goto fail; + } + cle = clSetKernelArg(ctx->kernel, 1, sizeof(cl_uint), &ctx->index); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "index argument: %d.\n", cle); + err = AVERROR_UNKNOWN; + goto fail; + } + + for (input = 0; input < ctx->nb_inputs; input++) { + av_assert0(ctx->frames[input]); + + src = (cl_mem)ctx->frames[input]->data[plane]; + av_assert0(src); + + cle = clSetKernelArg(ctx->kernel, 2 + input, sizeof(cl_mem), &src); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "source image argument %d: %d.\n", input, cle); + err = AVERROR_UNKNOWN; + goto fail; + } + } + + err = ff_opencl_filter_work_size_from_image(avctx, global_work, + output, plane, 0); + if (err < 0) + goto fail; + + av_log(avctx, AV_LOG_DEBUG, "Run kernel on plane %d " + "(%zux%zu).\n", plane, global_work[0], global_work[1]); + + cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel, 2, NULL, + global_work, NULL, 0, NULL, NULL); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to enqueue kernel: %d.\n", + cle); + err = AVERROR(EIO); + goto fail; + } + } + + cle = clFinish(ctx->command_queue); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to finish command queue: %d.\n", + cle); + err = AVERROR(EIO); + goto fail; + } + + if (ctx->nb_inputs > 0) { + err = av_frame_copy_props(output, ctx->frames[0]); + if (err < 0) + goto fail; + } else { + output->pts = ctx->index; + } + ++ctx->index; + + av_log(ctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(output->format), + output->width, output->height, output->pts); + + return ff_filter_frame(outlink, output); + +fail: + clFinish(ctx->command_queue); + av_frame_free(&output); + return err; +} + +static int program_opencl_request_frame(AVFilterLink *outlink) +{ + AVFilterContext *avctx = outlink->src; + + return program_opencl_run(avctx); +} + +static int program_opencl_filter(FFFrameSync *fs) +{ + AVFilterContext *avctx = fs->parent; + ProgramOpenCLContext *ctx = avctx->priv; + int err, i; + + for (i = 0; i < ctx->nb_inputs; i++) { + err = ff_framesync_get_frame(&ctx->fs, i, &ctx->frames[i], 0); + if (err < 0) + return err; + } + + return program_opencl_run(avctx); +} + +static int program_opencl_activate(AVFilterContext *avctx) +{ + ProgramOpenCLContext *ctx = avctx->priv; + + av_assert0(ctx->nb_inputs > 0); + + return ff_framesync_activate(&ctx->fs); +} + +static int program_opencl_config_output(AVFilterLink *outlink) +{ + AVFilterContext *avctx = outlink->src; + ProgramOpenCLContext *ctx = avctx->priv; + int err; + + err = ff_opencl_filter_config_output(outlink); + if (err < 0) + return err; + + if (ctx->nb_inputs > 0) { + FFFrameSyncIn *in; + int i; + + err = ff_framesync_init(&ctx->fs, avctx, ctx->nb_inputs); + if (err < 0) + return err; + + ctx->fs.opaque = ctx; + ctx->fs.on_event = &program_opencl_filter; + + in = ctx->fs.in; + for (i = 0; i < ctx->nb_inputs; i++) { + const AVFilterLink *inlink = avctx->inputs[i]; + + in[i].time_base = inlink->time_base; + in[i].sync = 1; + in[i].before = EXT_STOP; + in[i].after = EXT_INFINITY; + } + + err = ff_framesync_configure(&ctx->fs); + if (err < 0) + return err; + + } else { + outlink->time_base = av_inv_q(ctx->source_rate); + } + + return 0; +} + +static av_cold int program_opencl_init(AVFilterContext *avctx) +{ + ProgramOpenCLContext *ctx = avctx->priv; + int err; + + ff_opencl_filter_init(avctx); + + ctx->ocf.output_width = ctx->width; + ctx->ocf.output_height = ctx->height; + + if (!strcmp(avctx->filter->name, "openclsrc")) { + if (!ctx->ocf.output_width || !ctx->ocf.output_height) { + av_log(avctx, AV_LOG_ERROR, "OpenCL source requires output " + "dimensions to be specified.\n"); + return AVERROR(EINVAL); + } + + ctx->nb_inputs = 0; + ctx->ocf.output_format = ctx->source_format; + } else { + int i; + + ctx->frames = av_mallocz_array(ctx->nb_inputs, + sizeof(*ctx->frames)); + if (!ctx->frames) + return AVERROR(ENOMEM); + + for (i = 0; i < ctx->nb_inputs; i++) { + AVFilterPad input; + memset(&input, 0, sizeof(input)); + + input.type = AVMEDIA_TYPE_VIDEO; + input.name = av_asprintf("input%d", i); + if (!input.name) + return AVERROR(ENOMEM); + + input.config_props = &ff_opencl_filter_config_input; + + err = ff_insert_inpad(avctx, i, &input); + if (err < 0) { + av_freep(&input.name); + return err; + } + } + } + + return 0; +} + +static av_cold void program_opencl_uninit(AVFilterContext *avctx) +{ + ProgramOpenCLContext *ctx = avctx->priv; + cl_int cle; + int i; + + if (ctx->nb_inputs > 0) { + ff_framesync_uninit(&ctx->fs); + + av_freep(&ctx->frames); + for (i = 0; i < avctx->nb_inputs; i++) + av_freep(&avctx->input_pads[i].name); + } + + if (ctx->kernel) { + cle = clReleaseKernel(ctx->kernel); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "kernel: %d.\n", cle); + } + + if (ctx->command_queue) { + cle = clReleaseCommandQueue(ctx->command_queue); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "command queue: %d.\n", cle); + } + + ff_opencl_filter_uninit(avctx); +} + +#define OFFSET(x) offsetof(ProgramOpenCLContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM) + +#if CONFIG_PROGRAM_OPENCL_FILTER + +static const AVOption program_opencl_options[] = { + { "source", "OpenCL program source file", OFFSET(source_file), + AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS }, + { "kernel", "Kernel name in program", OFFSET(kernel_name), + AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS }, + + { "inputs", "Number of inputs", OFFSET(nb_inputs), + AV_OPT_TYPE_INT, { .i64 = 1 }, 1, INT_MAX, FLAGS }, + + { "size", "Video size", OFFSET(width), + AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, FLAGS }, + { "s", "Video size", OFFSET(width), + AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, FLAGS }, + + { NULL }, +}; + +FRAMESYNC_DEFINE_CLASS(program_opencl, ProgramOpenCLContext, fs); + +static const AVFilterPad program_opencl_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &program_opencl_config_output, + }, + { NULL } +}; + +AVFilter ff_vf_program_opencl = { + .name = "program_opencl", + .description = NULL_IF_CONFIG_SMALL("Filter video using an OpenCL program"), + .priv_size = sizeof(ProgramOpenCLContext), + .priv_class = &program_opencl_class, + .preinit = &program_opencl_framesync_preinit, + .init = &program_opencl_init, + .uninit = &program_opencl_uninit, + .query_formats = &ff_opencl_filter_query_formats, + .activate = &program_opencl_activate, + .inputs = NULL, + .outputs = program_opencl_outputs, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; + +#endif + +#if CONFIG_OPENCLSRC_FILTER + +static const AVOption openclsrc_options[] = { + { "source", "OpenCL program source file", OFFSET(source_file), + AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS }, + { "kernel", "Kernel name in program", OFFSET(kernel_name), + AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS }, + + { "size", "Video size", OFFSET(width), + AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, FLAGS }, + { "s", "Video size", OFFSET(width), + AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, 0, FLAGS }, + + { "format", "Video format", OFFSET(source_format), + AV_OPT_TYPE_PIXEL_FMT, { .i64 = AV_PIX_FMT_NONE }, -1, INT_MAX, FLAGS }, + + { "rate", "Video frame rate", OFFSET(source_rate), + AV_OPT_TYPE_VIDEO_RATE, { .str = "25" }, 0, INT_MAX, FLAGS }, + { "r", "Video frame rate", OFFSET(source_rate), + AV_OPT_TYPE_VIDEO_RATE, { .str = "25" }, 0, INT_MAX, FLAGS }, + + { NULL }, +}; + +AVFILTER_DEFINE_CLASS(openclsrc); + +static const AVFilterPad openclsrc_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &program_opencl_config_output, + .request_frame = &program_opencl_request_frame, + }, + { NULL } +}; + +AVFilter ff_vsrc_openclsrc = { + .name = "openclsrc", + .description = NULL_IF_CONFIG_SMALL("Generate video using an OpenCL program"), + .priv_size = sizeof(ProgramOpenCLContext), + .priv_class = &openclsrc_class, + .init = &program_opencl_init, + .uninit = &program_opencl_uninit, + .query_formats = &ff_opencl_filter_query_formats, + .inputs = NULL, + .outputs = openclsrc_outputs, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; + +#endif diff --git a/libavfilter/vf_pseudocolor.c b/libavfilter/vf_pseudocolor.c index f8f5372752904..2e7a3a95f808f 100644 --- a/libavfilter/vf_pseudocolor.c +++ b/libavfilter/vf_pseudocolor.c @@ -94,7 +94,7 @@ static const AVOption pseudocolor_options[] = { }; static const enum AVPixelFormat pix_fmts[] = { - AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY16, + AV_PIX_FMT_GRAY8, AV_PIX_FMT_GRAY9, AV_PIX_FMT_GRAY10, AV_PIX_FMT_GRAY12, AV_PIX_FMT_GRAY16, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUVA420P, AV_PIX_FMT_YUV422P, AV_PIX_FMT_YUVA422P, AV_PIX_FMT_YUV444P, AV_PIX_FMT_GBRP, @@ -114,7 +114,10 @@ static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV420P16, AV_PIX_FMT_YUVA420P16, AV_PIX_FMT_YUV422P16, AV_PIX_FMT_YUVA422P16, AV_PIX_FMT_YUV444P16, AV_PIX_FMT_YUVA444P16, + AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRAP10, + AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRAP12, + AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, AV_PIX_FMT_GBRAP16, AV_PIX_FMT_NONE }; @@ -531,11 +534,17 @@ static int config_input(AVFilterLink *inlink) case AV_PIX_FMT_YUV444P14: case AV_PIX_FMT_YUV444P16: case AV_PIX_FMT_YUVA444P16: + case AV_PIX_FMT_GBRP9: case AV_PIX_FMT_GBRP10: - case AV_PIX_FMT_GBRAP10: + case AV_PIX_FMT_GBRP12: + case AV_PIX_FMT_GBRP14: case AV_PIX_FMT_GBRP16: + case AV_PIX_FMT_GBRAP10: + case AV_PIX_FMT_GBRAP12: case AV_PIX_FMT_GBRAP16: + case AV_PIX_FMT_GRAY9: case AV_PIX_FMT_GRAY10: + case AV_PIX_FMT_GRAY12: case AV_PIX_FMT_GRAY16: s->filter[0] = s->filter[1] = s->filter[2] = s->filter[3] = pseudocolor_filter_16; break; diff --git a/libavfilter/vf_psnr.c b/libavfilter/vf_psnr.c index 493a501a7a41e..153d694b7f0f0 100644 --- a/libavfilter/vf_psnr.c +++ b/libavfilter/vf_psnr.c @@ -270,7 +270,7 @@ static int query_formats(AVFilterContext *ctx) AV_PIX_FMT_YUVJ440P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_GBRP, AV_PIX_FMT_GBRP9, AV_PIX_FMT_GBRP10, AV_PIX_FMT_GBRP12, AV_PIX_FMT_GBRP14, AV_PIX_FMT_GBRP16, - AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP16, + AV_PIX_FMT_GBRAP, AV_PIX_FMT_GBRAP10, AV_PIX_FMT_GBRAP12, AV_PIX_FMT_GBRAP16, AV_PIX_FMT_NONE }; diff --git a/libavfilter/vf_scale.c b/libavfilter/vf_scale.c index 3329c1234663e..f741419e7e23b 100644 --- a/libavfilter/vf_scale.c +++ b/libavfilter/vf_scale.c @@ -261,11 +261,10 @@ static int config_props(AVFilterLink *outlink) /* TODO: make algorithm configurable */ - scale->input_is_pal = desc->flags & AV_PIX_FMT_FLAG_PAL || - desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL; + scale->input_is_pal = desc->flags & AV_PIX_FMT_FLAG_PAL; if (outfmt == AV_PIX_FMT_PAL8) outfmt = AV_PIX_FMT_BGR8; scale->output_is_pal = av_pix_fmt_desc_get(outfmt)->flags & AV_PIX_FMT_FLAG_PAL || - av_pix_fmt_desc_get(outfmt)->flags & AV_PIX_FMT_FLAG_PSEUDOPAL; + av_pix_fmt_desc_get(outfmt)->flags & FF_PSEUDOPAL; if (scale->sws) sws_freeContext(scale->sws); @@ -362,6 +361,7 @@ static int config_props_ref(AVFilterLink *outlink) outlink->h = inlink->h; outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; outlink->time_base = inlink->time_base; + outlink->frame_rate = inlink->frame_rate; return 0; } @@ -577,7 +577,9 @@ static const AVOption scale_options[] = { { "in_range", "set input color range", OFFSET( in_range), AV_OPT_TYPE_INT, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 2, FLAGS, "range" }, { "out_range", "set output color range", OFFSET(out_range), AV_OPT_TYPE_INT, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 2, FLAGS, "range" }, { "auto", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 0, FLAGS, "range" }, + { "unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_UNSPECIFIED }, 0, 0, FLAGS, "range" }, { "full", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_JPEG}, 0, 0, FLAGS, "range" }, + { "limited",NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG}, 0, 0, FLAGS, "range" }, { "jpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_JPEG}, 0, 0, FLAGS, "range" }, { "mpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG}, 0, 0, FLAGS, "range" }, { "tv", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG}, 0, 0, FLAGS, "range" }, diff --git a/libavfilter/vf_scale_qsv.c b/libavfilter/vf_scale_qsv.c index a5f5be7d66d79..d1189942d126c 100644 --- a/libavfilter/vf_scale_qsv.c +++ b/libavfilter/vf_scale_qsv.c @@ -36,6 +36,7 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "libavutil/time.h" +#include "libavfilter/qsvvpp.h" #include "avfilter.h" #include "formats.h" @@ -71,7 +72,6 @@ enum var_name { typedef struct QSVScaleContext { const AVClass *class; - AVBufferRef *out_frames_ref; /* a clone of the main session, used internally for scaling */ mfxSession session; @@ -134,7 +134,6 @@ static void qsvscale_uninit(AVFilterContext *ctx) MFXClose(s->session); s->session = NULL; } - av_buffer_unref(&s->out_frames_ref); av_freep(&s->mem_ids_in); av_freep(&s->mem_ids_out); @@ -165,6 +164,7 @@ static int init_out_pool(AVFilterContext *ctx, int out_width, int out_height) { QSVScaleContext *s = ctx->priv; + AVFilterLink *outlink = ctx->outputs[0]; AVHWFramesContext *in_frames_ctx; AVHWFramesContext *out_frames_ctx; @@ -185,21 +185,25 @@ static int init_out_pool(AVFilterContext *ctx, in_format = in_frames_ctx->sw_format; out_format = (s->format == AV_PIX_FMT_NONE) ? in_format : s->format; - s->out_frames_ref = av_hwframe_ctx_alloc(in_frames_ctx->device_ref); - if (!s->out_frames_ref) + outlink->hw_frames_ctx = av_hwframe_ctx_alloc(in_frames_ctx->device_ref); + if (!outlink->hw_frames_ctx) return AVERROR(ENOMEM); - out_frames_ctx = (AVHWFramesContext*)s->out_frames_ref->data; + out_frames_ctx = (AVHWFramesContext*)outlink->hw_frames_ctx->data; out_frames_hwctx = out_frames_ctx->hwctx; out_frames_ctx->format = AV_PIX_FMT_QSV; out_frames_ctx->width = FFALIGN(out_width, 32); out_frames_ctx->height = FFALIGN(out_height, 32); out_frames_ctx->sw_format = out_format; - out_frames_ctx->initial_pool_size = 32; + out_frames_ctx->initial_pool_size = 4; out_frames_hwctx->frame_type = in_frames_hwctx->frame_type; - ret = av_hwframe_ctx_init(s->out_frames_ref); + ret = ff_filter_init_hw_frames(ctx, outlink, 32); + if (ret < 0) + return ret; + + ret = av_hwframe_ctx_init(outlink->hw_frames_ctx); if (ret < 0) return ret; @@ -266,7 +270,7 @@ static int init_out_session(AVFilterContext *ctx) QSVScaleContext *s = ctx->priv; AVHWFramesContext *in_frames_ctx = (AVHWFramesContext*)ctx->inputs[0]->hw_frames_ctx->data; - AVHWFramesContext *out_frames_ctx = (AVHWFramesContext*)s->out_frames_ref->data; + AVHWFramesContext *out_frames_ctx = (AVHWFramesContext*)ctx->outputs[0]->hw_frames_ctx->data; AVQSVFramesContext *in_frames_hwctx = in_frames_ctx->hwctx; AVQSVFramesContext *out_frames_hwctx = out_frames_ctx->hwctx; AVQSVDeviceContext *device_hwctx = in_frames_ctx->device_ctx->hwctx; @@ -312,6 +316,12 @@ static int init_out_session(AVFilterContext *ctx) return AVERROR_UNKNOWN; } + if (QSV_RUNTIME_VERSION_ATLEAST(ver, 1, 25)) { + err = MFXJoinSession(device_hwctx->session, s->session); + if (err != MFX_ERR_NONE) + return AVERROR_UNKNOWN; + } + memset(&par, 0, sizeof(par)); if (opaque) { @@ -407,8 +417,6 @@ static int init_out_session(AVFilterContext *ctx) static int init_scale_session(AVFilterContext *ctx, int in_width, int in_height, int out_width, int out_height) { - QSVScaleContext *s = ctx->priv; - int ret; qsvscale_uninit(ctx); @@ -421,11 +429,6 @@ static int init_scale_session(AVFilterContext *ctx, int in_width, int in_height, if (ret < 0) return ret; - av_buffer_unref(&ctx->outputs[0]->hw_frames_ctx); - ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(s->out_frames_ref); - if (!ctx->outputs[0]->hw_frames_ctx) - return AVERROR(ENOMEM); - return 0; } diff --git a/libavfilter/vf_scale_vaapi.c b/libavfilter/vf_scale_vaapi.c index 22e928c098871..d6529d5235a66 100644 --- a/libavfilter/vf_scale_vaapi.c +++ b/libavfilter/vf_scale_vaapi.c @@ -18,12 +18,7 @@ #include -#include -#include - #include "libavutil/avassert.h" -#include "libavutil/hwcontext.h" -#include "libavutil/hwcontext_vaapi.h" #include "libavutil/mem.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" @@ -33,288 +28,91 @@ #include "internal.h" #include "scale.h" #include "video.h" +#include "vaapi_vpp.h" typedef struct ScaleVAAPIContext { - const AVClass *class; - - AVVAAPIDeviceContext *hwctx; - AVBufferRef *device_ref; - - int valid_ids; - VAConfigID va_config; - VAContextID va_context; - - AVBufferRef *input_frames_ref; - AVHWFramesContext *input_frames; - - AVBufferRef *output_frames_ref; - AVHWFramesContext *output_frames; + VAAPIVPPContext vpp_ctx; // must be the first field char *output_format_string; - enum AVPixelFormat output_format; char *w_expr; // width expression string char *h_expr; // height expression string - - int output_width; // computed width - int output_height; // computed height } ScaleVAAPIContext; - -static int scale_vaapi_query_formats(AVFilterContext *avctx) -{ - enum AVPixelFormat pix_fmts[] = { - AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE, - }; - int err; - - if ((err = ff_formats_ref(ff_make_format_list(pix_fmts), - &avctx->inputs[0]->out_formats)) < 0) - return err; - if ((err = ff_formats_ref(ff_make_format_list(pix_fmts), - &avctx->outputs[0]->in_formats)) < 0) - return err; - - return 0; -} - -static int scale_vaapi_pipeline_uninit(ScaleVAAPIContext *ctx) -{ - if (ctx->va_context != VA_INVALID_ID) { - vaDestroyContext(ctx->hwctx->display, ctx->va_context); - ctx->va_context = VA_INVALID_ID; - } - - if (ctx->va_config != VA_INVALID_ID) { - vaDestroyConfig(ctx->hwctx->display, ctx->va_config); - ctx->va_config = VA_INVALID_ID; - } - - av_buffer_unref(&ctx->output_frames_ref); - av_buffer_unref(&ctx->device_ref); - ctx->hwctx = 0; - - return 0; -} - -static int scale_vaapi_config_input(AVFilterLink *inlink) -{ - AVFilterContext *avctx = inlink->dst; - ScaleVAAPIContext *ctx = avctx->priv; - - scale_vaapi_pipeline_uninit(ctx); - - if (!inlink->hw_frames_ctx) { - av_log(avctx, AV_LOG_ERROR, "A hardware frames reference is " - "required to associate the processing device.\n"); - return AVERROR(EINVAL); - } - - ctx->input_frames_ref = av_buffer_ref(inlink->hw_frames_ctx); - ctx->input_frames = (AVHWFramesContext*)ctx->input_frames_ref->data; - - return 0; -} - static int scale_vaapi_config_output(AVFilterLink *outlink) { - AVFilterLink *inlink = outlink->src->inputs[0]; - AVFilterContext *avctx = outlink->src; - ScaleVAAPIContext *ctx = avctx->priv; - AVVAAPIHWConfig *hwconfig = NULL; - AVHWFramesConstraints *constraints = NULL; - AVVAAPIFramesContext *va_frames; - VAStatus vas; - int err, i; - - scale_vaapi_pipeline_uninit(ctx); - - ctx->device_ref = av_buffer_ref(ctx->input_frames->device_ref); - ctx->hwctx = ((AVHWDeviceContext*)ctx->device_ref->data)->hwctx; - - av_assert0(ctx->va_config == VA_INVALID_ID); - vas = vaCreateConfig(ctx->hwctx->display, VAProfileNone, - VAEntrypointVideoProc, 0, 0, &ctx->va_config); - if (vas != VA_STATUS_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Failed to create processing pipeline " - "config: %d (%s).\n", vas, vaErrorStr(vas)); - err = AVERROR(EIO); - goto fail; - } - - hwconfig = av_hwdevice_hwconfig_alloc(ctx->device_ref); - if (!hwconfig) { - err = AVERROR(ENOMEM); - goto fail; - } - hwconfig->config_id = ctx->va_config; - - constraints = av_hwdevice_get_hwframe_constraints(ctx->device_ref, - hwconfig); - if (!constraints) { - err = AVERROR(ENOMEM); - goto fail; - } - - if (ctx->output_format == AV_PIX_FMT_NONE) - ctx->output_format = ctx->input_frames->sw_format; - if (constraints->valid_sw_formats) { - for (i = 0; constraints->valid_sw_formats[i] != AV_PIX_FMT_NONE; i++) { - if (ctx->output_format == constraints->valid_sw_formats[i]) - break; - } - if (constraints->valid_sw_formats[i] == AV_PIX_FMT_NONE) { - av_log(ctx, AV_LOG_ERROR, "Hardware does not support output " - "format %s.\n", av_get_pix_fmt_name(ctx->output_format)); - err = AVERROR(EINVAL); - goto fail; - } - } + AVFilterLink *inlink = outlink->src->inputs[0]; + AVFilterContext *avctx = outlink->src; + VAAPIVPPContext *vpp_ctx = avctx->priv; + ScaleVAAPIContext *ctx = avctx->priv; + int err; if ((err = ff_scale_eval_dimensions(ctx, ctx->w_expr, ctx->h_expr, inlink, outlink, - &ctx->output_width, &ctx->output_height)) < 0) - goto fail; - - if (ctx->output_width < constraints->min_width || - ctx->output_height < constraints->min_height || - ctx->output_width > constraints->max_width || - ctx->output_height > constraints->max_height) { - av_log(ctx, AV_LOG_ERROR, "Hardware does not support scaling to " - "size %dx%d (constraints: width %d-%d height %d-%d).\n", - ctx->output_width, ctx->output_height, - constraints->min_width, constraints->max_width, - constraints->min_height, constraints->max_height); - err = AVERROR(EINVAL); - goto fail; - } - - ctx->output_frames_ref = av_hwframe_ctx_alloc(ctx->device_ref); - if (!ctx->output_frames_ref) { - av_log(ctx, AV_LOG_ERROR, "Failed to create HW frame context " - "for output.\n"); - err = AVERROR(ENOMEM); - goto fail; - } - - ctx->output_frames = (AVHWFramesContext*)ctx->output_frames_ref->data; - - ctx->output_frames->format = AV_PIX_FMT_VAAPI; - ctx->output_frames->sw_format = ctx->output_format; - ctx->output_frames->width = ctx->output_width; - ctx->output_frames->height = ctx->output_height; - - // The number of output frames we need is determined by what follows - // the filter. If it's an encoder with complex frame reference - // structures then this could be very high. - ctx->output_frames->initial_pool_size = 10; - - err = av_hwframe_ctx_init(ctx->output_frames_ref); - if (err < 0) { - av_log(ctx, AV_LOG_ERROR, "Failed to initialise VAAPI frame " - "context for output: %d\n", err); - goto fail; - } - - va_frames = ctx->output_frames->hwctx; - - av_assert0(ctx->va_context == VA_INVALID_ID); - vas = vaCreateContext(ctx->hwctx->display, ctx->va_config, - ctx->output_width, ctx->output_height, - VA_PROGRESSIVE, - va_frames->surface_ids, va_frames->nb_surfaces, - &ctx->va_context); - if (vas != VA_STATUS_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Failed to create processing pipeline " - "context: %d (%s).\n", vas, vaErrorStr(vas)); - return AVERROR(EIO); - } + &vpp_ctx->output_width, &vpp_ctx->output_height)) < 0) + return err; - outlink->w = ctx->output_width; - outlink->h = ctx->output_height; + err = ff_vaapi_vpp_config_output(outlink); + if (err < 0) + return err; - outlink->hw_frames_ctx = av_buffer_ref(ctx->output_frames_ref); - if (!outlink->hw_frames_ctx) { - err = AVERROR(ENOMEM); - goto fail; - } + if (inlink->sample_aspect_ratio.num) + outlink->sample_aspect_ratio = av_mul_q((AVRational){outlink->h * inlink->w, outlink->w * inlink->h}, inlink->sample_aspect_ratio); + else + outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; - av_freep(&hwconfig); - av_hwframe_constraints_free(&constraints); return 0; - -fail: - av_buffer_unref(&ctx->output_frames_ref); - av_freep(&hwconfig); - av_hwframe_constraints_free(&constraints); - return err; -} - -static int vaapi_proc_colour_standard(enum AVColorSpace av_cs) -{ - switch(av_cs) { -#define CS(av, va) case AVCOL_SPC_ ## av: return VAProcColorStandard ## va; - CS(BT709, BT709); - CS(BT470BG, BT601); - CS(SMPTE170M, SMPTE170M); - CS(SMPTE240M, SMPTE240M); -#undef CS - default: - return VAProcColorStandardNone; - } } static int scale_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) { - AVFilterContext *avctx = inlink->dst; - AVFilterLink *outlink = avctx->outputs[0]; - ScaleVAAPIContext *ctx = avctx->priv; - AVFrame *output_frame = NULL; + AVFilterContext *avctx = inlink->dst; + AVFilterLink *outlink = avctx->outputs[0]; + VAAPIVPPContext *vpp_ctx = avctx->priv; + AVFrame *output_frame = NULL; VASurfaceID input_surface, output_surface; VAProcPipelineParameterBuffer params; - VABufferID params_id; VARectangle input_region; - VAStatus vas; int err; - av_log(ctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", + av_log(avctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", av_get_pix_fmt_name(input_frame->format), input_frame->width, input_frame->height, input_frame->pts); - if (ctx->va_context == VA_INVALID_ID) + if (vpp_ctx->va_context == VA_INVALID_ID) return AVERROR(EINVAL); input_surface = (VASurfaceID)(uintptr_t)input_frame->data[3]; - av_log(ctx, AV_LOG_DEBUG, "Using surface %#x for scale input.\n", + av_log(avctx, AV_LOG_DEBUG, "Using surface %#x for scale input.\n", input_surface); - output_frame = ff_get_video_buffer(outlink, ctx->output_width, - ctx->output_height); + output_frame = ff_get_video_buffer(outlink, vpp_ctx->output_width, + vpp_ctx->output_height); if (!output_frame) { err = AVERROR(ENOMEM); goto fail; } output_surface = (VASurfaceID)(uintptr_t)output_frame->data[3]; - av_log(ctx, AV_LOG_DEBUG, "Using surface %#x for scale output.\n", + av_log(avctx, AV_LOG_DEBUG, "Using surface %#x for scale output.\n", output_surface); memset(¶ms, 0, sizeof(params)); - // If there were top/left cropping, it could be taken into - // account here. input_region = (VARectangle) { - .x = 0, - .y = 0, - .width = input_frame->width, - .height = input_frame->height, + .x = input_frame->crop_left, + .y = input_frame->crop_top, + .width = input_frame->width - + (input_frame->crop_left + input_frame->crop_right), + .height = input_frame->height - + (input_frame->crop_top + input_frame->crop_bottom), }; params.surface = input_surface; params.surface_region = &input_region; params.surface_color_standard = - vaapi_proc_colour_standard(input_frame->colorspace); + ff_vaapi_vpp_colour_standard(input_frame->colorspace); params.output_region = 0; params.output_background_color = 0xff000000; @@ -323,71 +121,22 @@ static int scale_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) params.pipeline_flags = 0; params.filter_flags = VA_FILTER_SCALING_HQ; - vas = vaBeginPicture(ctx->hwctx->display, - ctx->va_context, output_surface); - if (vas != VA_STATUS_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Failed to attach new picture: " - "%d (%s).\n", vas, vaErrorStr(vas)); - err = AVERROR(EIO); + err = ff_vaapi_vpp_render_picture(avctx, ¶ms, output_surface); + if (err < 0) goto fail; - } - - vas = vaCreateBuffer(ctx->hwctx->display, ctx->va_context, - VAProcPipelineParameterBufferType, - sizeof(params), 1, ¶ms, ¶ms_id); - if (vas != VA_STATUS_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Failed to create parameter buffer: " - "%d (%s).\n", vas, vaErrorStr(vas)); - err = AVERROR(EIO); - goto fail_after_begin; - } - av_log(ctx, AV_LOG_DEBUG, "Pipeline parameter buffer is %#x.\n", - params_id); - - vas = vaRenderPicture(ctx->hwctx->display, ctx->va_context, - ¶ms_id, 1); - if (vas != VA_STATUS_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Failed to render parameter buffer: " - "%d (%s).\n", vas, vaErrorStr(vas)); - err = AVERROR(EIO); - goto fail_after_begin; - } - vas = vaEndPicture(ctx->hwctx->display, ctx->va_context); - if (vas != VA_STATUS_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Failed to start picture processing: " - "%d (%s).\n", vas, vaErrorStr(vas)); - err = AVERROR(EIO); - goto fail_after_render; - } - - if (CONFIG_VAAPI_1 || ctx->hwctx->driver_quirks & - AV_VAAPI_DRIVER_QUIRK_RENDER_PARAM_BUFFERS) { - vas = vaDestroyBuffer(ctx->hwctx->display, params_id); - if (vas != VA_STATUS_SUCCESS) { - av_log(ctx, AV_LOG_ERROR, "Failed to free parameter buffer: " - "%d (%s).\n", vas, vaErrorStr(vas)); - // And ignore. - } - } + err = av_frame_copy_props(output_frame, input_frame); + if (err < 0) + goto fail; - av_frame_copy_props(output_frame, input_frame); av_frame_free(&input_frame); - av_log(ctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n", + av_log(avctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n", av_get_pix_fmt_name(output_frame->format), output_frame->width, output_frame->height, output_frame->pts); return ff_filter_frame(outlink, output_frame); - // We want to make sure that if vaBeginPicture has been called, we also - // call vaRenderPicture and vaEndPicture. These calls may well fail or - // do something else nasty, but once we're in this failure case there - // isn't much else we can do. -fail_after_begin: - vaRenderPicture(ctx->hwctx->display, ctx->va_context, ¶ms_id, 1); -fail_after_render: - vaEndPicture(ctx->hwctx->display, ctx->va_context); fail: av_frame_free(&input_frame); av_frame_free(&output_frame); @@ -396,39 +145,26 @@ static int scale_vaapi_filter_frame(AVFilterLink *inlink, AVFrame *input_frame) static av_cold int scale_vaapi_init(AVFilterContext *avctx) { - ScaleVAAPIContext *ctx = avctx->priv; + VAAPIVPPContext *vpp_ctx = avctx->priv; + ScaleVAAPIContext *ctx = avctx->priv; - ctx->va_config = VA_INVALID_ID; - ctx->va_context = VA_INVALID_ID; - ctx->valid_ids = 1; + ff_vaapi_vpp_ctx_init(avctx); + vpp_ctx->pipeline_uninit = ff_vaapi_vpp_pipeline_uninit; if (ctx->output_format_string) { - ctx->output_format = av_get_pix_fmt(ctx->output_format_string); - if (ctx->output_format == AV_PIX_FMT_NONE) { - av_log(ctx, AV_LOG_ERROR, "Invalid output format.\n"); + vpp_ctx->output_format = av_get_pix_fmt(ctx->output_format_string); + if (vpp_ctx->output_format == AV_PIX_FMT_NONE) { + av_log(avctx, AV_LOG_ERROR, "Invalid output format.\n"); return AVERROR(EINVAL); } } else { // Use the input format once that is configured. - ctx->output_format = AV_PIX_FMT_NONE; + vpp_ctx->output_format = AV_PIX_FMT_NONE; } return 0; } -static av_cold void scale_vaapi_uninit(AVFilterContext *avctx) -{ - ScaleVAAPIContext *ctx = avctx->priv; - - if (ctx->valid_ids) - scale_vaapi_pipeline_uninit(ctx); - - av_buffer_unref(&ctx->input_frames_ref); - av_buffer_unref(&ctx->output_frames_ref); - av_buffer_unref(&ctx->device_ref); -} - - #define OFFSET(x) offsetof(ScaleVAAPIContext, x) #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM) static const AVOption scale_vaapi_options[] = { @@ -441,19 +177,14 @@ static const AVOption scale_vaapi_options[] = { { NULL }, }; -static const AVClass scale_vaapi_class = { - .class_name = "scale_vaapi", - .item_name = av_default_item_name, - .option = scale_vaapi_options, - .version = LIBAVUTIL_VERSION_INT, -}; +AVFILTER_DEFINE_CLASS(scale_vaapi); static const AVFilterPad scale_vaapi_inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_VIDEO, .filter_frame = &scale_vaapi_filter_frame, - .config_props = &scale_vaapi_config_input, + .config_props = &ff_vaapi_vpp_config_input, }, { NULL } }; @@ -472,8 +203,8 @@ AVFilter ff_vf_scale_vaapi = { .description = NULL_IF_CONFIG_SMALL("Scale to/from VAAPI surfaces."), .priv_size = sizeof(ScaleVAAPIContext), .init = &scale_vaapi_init, - .uninit = &scale_vaapi_uninit, - .query_formats = &scale_vaapi_query_formats, + .uninit = &ff_vaapi_vpp_ctx_uninit, + .query_formats = &ff_vaapi_vpp_query_formats, .inputs = scale_vaapi_inputs, .outputs = scale_vaapi_outputs, .priv_class = &scale_vaapi_class, diff --git a/libavfilter/vf_setparams.c b/libavfilter/vf_setparams.c new file mode 100644 index 0000000000000..8427f98ba824a --- /dev/null +++ b/libavfilter/vf_setparams.c @@ -0,0 +1,83 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/pixfmt.h" +#include "libavutil/opt.h" +#include "avfilter.h" +#include "internal.h" +#include "video.h" + +typedef struct SetParamsContext { + const AVClass *class; + int color_range; +} SetParamsContext; + +#define OFFSET(x) offsetof(SetParamsContext, x) +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM + +static const AVOption setrange_options[] = { + {"range", "select color range", OFFSET(color_range), AV_OPT_TYPE_INT, {.i64=-1},-1, AVCOL_RANGE_NB-1, FLAGS, "range"}, + {"auto", "keep the same color range", 0, AV_OPT_TYPE_CONST, {.i64=-1}, 0, 0, FLAGS, "range"}, + {"unspecified", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_UNSPECIFIED}, 0, 0, FLAGS, "range"}, + {"unknown", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_UNSPECIFIED}, 0, 0, FLAGS, "range"}, + {"limited", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG}, 0, 0, FLAGS, "range"}, + {"tv", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG}, 0, 0, FLAGS, "range"}, + {"mpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_MPEG}, 0, 0, FLAGS, "range"}, + {"full", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, FLAGS, "range"}, + {"pc", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, FLAGS, "range"}, + {"jpeg", NULL, 0, AV_OPT_TYPE_CONST, {.i64=AVCOL_RANGE_JPEG}, 0, 0, FLAGS, "range"}, + {NULL} +}; + +AVFILTER_DEFINE_CLASS(setrange); + +static int filter_frame(AVFilterLink *inlink, AVFrame *frame) +{ + AVFilterContext *ctx = inlink->dst; + SetParamsContext *s = ctx->priv; + + if (s->color_range >= 0) + frame->color_range = s->color_range; + return ff_filter_frame(ctx->outputs[0], frame); +} + +static const AVFilterPad inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +AVFilter ff_vf_setrange = { + .name = "setrange", + .description = NULL_IF_CONFIG_SMALL("Force color range for the output video frame."), + .priv_size = sizeof(SetParamsContext), + .priv_class = &setrange_class, + .inputs = inputs, + .outputs = outputs, +}; diff --git a/libavfilter/vf_showinfo.c b/libavfilter/vf_showinfo.c index 14b8aa4aff1e7..d1d1415c0b791 100644 --- a/libavfilter/vf_showinfo.c +++ b/libavfilter/vf_showinfo.c @@ -29,6 +29,7 @@ #include "libavutil/imgutils.h" #include "libavutil/internal.h" #include "libavutil/pixdesc.h" +#include "libavutil/spherical.h" #include "libavutil/stereo3d.h" #include "libavutil/timestamp.h" @@ -36,6 +37,45 @@ #include "internal.h" #include "video.h" +static void dump_spherical(AVFilterContext *ctx, AVFrame *frame, AVFrameSideData *sd) +{ + AVSphericalMapping *spherical = (AVSphericalMapping *)sd->data; + double yaw, pitch, roll; + + av_log(ctx, AV_LOG_INFO, "spherical information: "); + if (sd->size < sizeof(*spherical)) { + av_log(ctx, AV_LOG_INFO, "invalid data"); + return; + } + + if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR) + av_log(ctx, AV_LOG_INFO, "equirectangular "); + else if (spherical->projection == AV_SPHERICAL_CUBEMAP) + av_log(ctx, AV_LOG_INFO, "cubemap "); + else if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) + av_log(ctx, AV_LOG_INFO, "tiled equirectangular "); + else { + av_log(ctx, AV_LOG_WARNING, "unknown"); + return; + } + + yaw = ((double)spherical->yaw) / (1 << 16); + pitch = ((double)spherical->pitch) / (1 << 16); + roll = ((double)spherical->roll) / (1 << 16); + av_log(ctx, AV_LOG_INFO, "(%f/%f/%f) ", yaw, pitch, roll); + + if (spherical->projection == AV_SPHERICAL_EQUIRECTANGULAR_TILE) { + size_t l, t, r, b; + av_spherical_tile_bounds(spherical, frame->width, frame->height, + &l, &t, &r, &b); + av_log(ctx, AV_LOG_INFO, + "[%"SIZE_SPECIFIER", %"SIZE_SPECIFIER", %"SIZE_SPECIFIER", %"SIZE_SPECIFIER"] ", + l, t, r, b); + } else if (spherical->projection == AV_SPHERICAL_CUBEMAP) { + av_log(ctx, AV_LOG_INFO, "[pad %"PRIu32"] ", spherical->padding); + } +} + static void dump_stereo3d(AVFilterContext *ctx, AVFrameSideData *sd) { AVStereo3D *stereo; @@ -48,19 +88,7 @@ static void dump_stereo3d(AVFilterContext *ctx, AVFrameSideData *sd) stereo = (AVStereo3D *)sd->data; - av_log(ctx, AV_LOG_INFO, "type - "); - switch (stereo->type) { - case AV_STEREO3D_2D: av_log(ctx, AV_LOG_INFO, "2D"); break; - case AV_STEREO3D_SIDEBYSIDE: av_log(ctx, AV_LOG_INFO, "side by side"); break; - case AV_STEREO3D_TOPBOTTOM: av_log(ctx, AV_LOG_INFO, "top and bottom"); break; - case AV_STEREO3D_FRAMESEQUENCE: av_log(ctx, AV_LOG_INFO, "frame alternate"); break; - case AV_STEREO3D_CHECKERBOARD: av_log(ctx, AV_LOG_INFO, "checkerboard"); break; - case AV_STEREO3D_LINES: av_log(ctx, AV_LOG_INFO, "interleaved lines"); break; - case AV_STEREO3D_COLUMNS: av_log(ctx, AV_LOG_INFO, "interleaved columns"); break; - case AV_STEREO3D_SIDEBYSIDE_QUINCUNX: av_log(ctx, AV_LOG_INFO, "side by side " - "(quincunx subsampling)"); break; - default: av_log(ctx, AV_LOG_WARNING, "unknown"); break; - } + av_log(ctx, AV_LOG_INFO, "type - %s", av_stereo3d_type_name(stereo->type)); if (stereo->flags & AV_STEREO3D_FLAG_INVERT) av_log(ctx, AV_LOG_INFO, " (inverted)"); @@ -140,6 +168,9 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *frame) case AV_FRAME_DATA_A53_CC: av_log(ctx, AV_LOG_INFO, "A/53 closed captions (%d bytes)", sd->size); break; + case AV_FRAME_DATA_SPHERICAL: + dump_spherical(ctx, frame, sd); + break; case AV_FRAME_DATA_STEREO3D: dump_stereo3d(ctx, sd); break; diff --git a/libavfilter/vf_shuffleplanes.c b/libavfilter/vf_shuffleplanes.c index 4bc7b79f8743c..32d2d585f3ba3 100644 --- a/libavfilter/vf_shuffleplanes.c +++ b/libavfilter/vf_shuffleplanes.c @@ -69,7 +69,7 @@ static av_cold int shuffleplanes_config_input(AVFilterLink *inlink) } if ((desc->flags & AV_PIX_FMT_FLAG_PAL || - desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) && + desc->flags & FF_PSEUDOPAL) && (i == 1) != (s->map[i] == 1)) { av_log(ctx, AV_LOG_ERROR, "Cannot map between a palette plane and a data plane.\n"); diff --git a/libavfilter/vf_signature.c b/libavfilter/vf_signature.c index f0078ba1a6eb1..d07b213f3125a 100644 --- a/libavfilter/vf_signature.c +++ b/libavfilter/vf_signature.c @@ -576,7 +576,8 @@ static int export(AVFilterContext *ctx, StreamContext *sc, int input) /* error already handled */ av_assert0(av_get_frame_filename(filename, sizeof(filename), sic->filename, input) == 0); } else { - strcpy(filename, sic->filename); + if (av_strlcpy(filename, sic->filename, sizeof(filename)) >= sizeof(filename)) + return AVERROR(EINVAL); } if (sic->format == FORMAT_XML) { return xml_export(ctx, sc, filename); diff --git a/libavfilter/vf_stack.c b/libavfilter/vf_stack.c index 2467302159f3f..b2b8c68041d21 100644 --- a/libavfilter/vf_stack.c +++ b/libavfilter/vf_stack.c @@ -105,6 +105,7 @@ static int process_frame(FFFrameSync *fs) if (!out) return AVERROR(ENOMEM); out->pts = av_rescale_q(s->fs.pts, s->fs.time_base, outlink->time_base); + out->sample_aspect_ratio = outlink->sample_aspect_ratio; for (i = 0; i < s->nb_inputs; i++) { AVFilterLink *inlink = ctx->inputs[i]; @@ -147,6 +148,7 @@ static int config_output(AVFilterLink *outlink) StackContext *s = ctx->priv; AVRational time_base = ctx->inputs[0]->time_base; AVRational frame_rate = ctx->inputs[0]->frame_rate; + AVRational sar = ctx->inputs[0]->sample_aspect_ratio; int height = ctx->inputs[0]->h; int width = ctx->inputs[0]->w; FFFrameSyncIn *in; @@ -179,6 +181,7 @@ static int config_output(AVFilterLink *outlink) outlink->h = height; outlink->time_base = time_base; outlink->frame_rate = frame_rate; + outlink->sample_aspect_ratio = sar; if ((ret = ff_framesync_init(&s->fs, ctx, s->nb_inputs)) < 0) return ret; diff --git a/libavfilter/vf_subtitles.c b/libavfilter/vf_subtitles.c index 66a564699a0b2..a7b02461f2dd4 100644 --- a/libavfilter/vf_subtitles.c +++ b/libavfilter/vf_subtitles.c @@ -413,7 +413,7 @@ static av_cold int init_subtitles(AVFilterContext *ctx) * * That API is old and needs to be reworked to match behaviour with A/V. */ - av_codec_set_pkt_timebase(dec_ctx, st->time_base); + dec_ctx->pkt_timebase = st->time_base; ret = avcodec_open2(dec_ctx, NULL, &codec_opts); if (ret < 0) diff --git a/libavfilter/vf_threshold.c b/libavfilter/vf_threshold.c index 88f6ef28d78f0..58b5d148368d1 100644 --- a/libavfilter/vf_threshold.c +++ b/libavfilter/vf_threshold.c @@ -31,27 +31,7 @@ #include "framesync.h" #include "internal.h" #include "video.h" - -typedef struct ThresholdContext { - const AVClass *class; - - int planes; - int bpc; - - int nb_planes; - int width[4], height[4]; - - void (*threshold)(const uint8_t *in, const uint8_t *threshold, - const uint8_t *min, const uint8_t *max, - uint8_t *out, - ptrdiff_t ilinesize, ptrdiff_t tlinesize, - ptrdiff_t flinesize, ptrdiff_t slinesize, - ptrdiff_t olinesize, - int w, int h); - - AVFrame *frames[4]; - FFFrameSync fs; -} ThresholdContext; +#include "threshold.h" #define OFFSET(x) offsetof(ThresholdContext, x) #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM @@ -155,7 +135,7 @@ static void threshold8(const uint8_t *in, const uint8_t *threshold, in += ilinesize; threshold += tlinesize; min += flinesize; - max += flinesize; + max += slinesize; out += olinesize; } } @@ -183,7 +163,7 @@ static void threshold16(const uint8_t *iin, const uint8_t *tthreshold, in += ilinesize / 2; threshold += tlinesize / 2; min += flinesize / 2; - max += flinesize / 2; + max += slinesize / 2; out += olinesize / 2; } } @@ -203,8 +183,16 @@ static int config_input(AVFilterLink *inlink) s->height[0] = s->height[3] = inlink->h; s->width[1] = s->width[2] = AV_CEIL_RSHIFT(inlink->w, hsub); s->width[0] = s->width[3] = inlink->w; + s->depth = desc->comp[0].depth; + + ff_threshold_init(s); - if (desc->comp[0].depth == 8) { + return 0; +} + +void ff_threshold_init(ThresholdContext *s) +{ + if (s->depth == 8) { s->threshold = threshold8; s->bpc = 1; } else { @@ -212,7 +200,8 @@ static int config_input(AVFilterLink *inlink) s->bpc = 2; } - return 0; + if (ARCH_X86) + ff_threshold_init_x86(s); } static int config_output(AVFilterLink *outlink) diff --git a/libavfilter/vf_tile.c b/libavfilter/vf_tile.c index 87e0b940cfcc6..439689a14d466 100644 --- a/libavfilter/vf_tile.c +++ b/libavfilter/vf_tile.c @@ -23,6 +23,7 @@ * tile video filter */ +#include "libavutil/imgutils.h" #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "avfilter.h" @@ -36,16 +37,17 @@ typedef struct TileContext { unsigned w, h; unsigned margin; unsigned padding; + unsigned overlap; + unsigned init_padding; unsigned current; unsigned nb_frames; FFDrawContext draw; FFDrawColor blank; AVFrame *out_ref; + AVFrame *prev_out_ref; uint8_t rgba_color[4]; } TileContext; -#define REASONABLE_SIZE 1024 - #define OFFSET(x) offsetof(TileContext, x) #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM @@ -59,6 +61,10 @@ static const AVOption tile_options[] = { { "padding", "set inner border thickness in pixels", OFFSET(padding), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1024, FLAGS }, { "color", "set the color of the unused area", OFFSET(rgba_color), AV_OPT_TYPE_COLOR, {.str = "black"}, .flags = FLAGS }, + { "overlap", "set how many frames to overlap for each render", OFFSET(overlap), + AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS }, + { "init_padding", " set how many frames to initially pad", OFFSET(init_padding), + AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS }, { NULL } }; @@ -68,12 +74,21 @@ static av_cold int init(AVFilterContext *ctx) { TileContext *tile = ctx->priv; - if (tile->w > REASONABLE_SIZE || tile->h > REASONABLE_SIZE) { + if (tile->w > UINT_MAX / tile->h) { av_log(ctx, AV_LOG_ERROR, "Tile size %ux%u is insane.\n", tile->w, tile->h); return AVERROR(EINVAL); } + if (tile->padding) { + if ((tile->w - 1 > (UINT32_MAX - 2 * tile->margin) / tile->padding) || + (tile->h - 1 > (UINT32_MAX - 2 * tile->margin) / tile->padding)) { + av_log(ctx, AV_LOG_ERROR, "Combination of Tile size %ux%u, padding %d and margin %d overflows.\n", + tile->w, tile->h, tile->padding, tile->margin); + return AVERROR(EINVAL); + } + } + if (tile->nb_frames == 0) { tile->nb_frames = tile->w * tile->h; } else if (tile->nb_frames > tile->w * tile->h) { @@ -82,6 +97,17 @@ static av_cold int init(AVFilterContext *ctx) return AVERROR(EINVAL); } + if (tile->overlap >= tile->nb_frames) { + av_log(ctx, AV_LOG_WARNING, "overlap must be less than %d\n", tile->nb_frames); + tile->overlap = tile->nb_frames - 1; + } + + if (tile->init_padding >= tile->nb_frames) { + av_log(ctx, AV_LOG_WARNING, "init_padding must be less than %d\n", tile->nb_frames); + } else { + tile->current = tile->init_padding; + } + return 0; } @@ -112,19 +138,19 @@ static int config_props(AVFilterLink *outlink) outlink->h = tile->h * inlink->h + total_margin_h; outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; outlink->frame_rate = av_mul_q(inlink->frame_rate, - av_make_q(1, tile->nb_frames)); + av_make_q(1, tile->nb_frames - tile->overlap)); ff_draw_init(&tile->draw, inlink->format, 0); ff_draw_color(&tile->draw, &tile->blank, tile->rgba_color); return 0; } -static void get_current_tile_pos(AVFilterContext *ctx, unsigned *x, unsigned *y) +static void get_tile_pos(AVFilterContext *ctx, unsigned *x, unsigned *y, unsigned current) { TileContext *tile = ctx->priv; AVFilterLink *inlink = ctx->inputs[0]; - const unsigned tx = tile->current % tile->w; - const unsigned ty = tile->current / tile->w; + const unsigned tx = current % tile->w; + const unsigned ty = current / tile->w; *x = tile->margin + (inlink->w + tile->padding) * tx; *y = tile->margin + (inlink->h + tile->padding) * ty; @@ -136,12 +162,13 @@ static void draw_blank_frame(AVFilterContext *ctx, AVFrame *out_buf) AVFilterLink *inlink = ctx->inputs[0]; unsigned x0, y0; - get_current_tile_pos(ctx, &x0, &y0); + get_tile_pos(ctx, &x0, &y0, tile->current); ff_fill_rectangle(&tile->draw, &tile->blank, out_buf->data, out_buf->linesize, x0, y0, inlink->w, inlink->h); tile->current++; } + static int end_last_frame(AVFilterContext *ctx) { TileContext *tile = ctx->priv; @@ -151,8 +178,13 @@ static int end_last_frame(AVFilterContext *ctx) while (tile->current < tile->nb_frames) draw_blank_frame(ctx, out_buf); + tile->current = tile->overlap; + if (tile->current) { + av_frame_free(&tile->prev_out_ref); + tile->prev_out_ref = av_frame_clone(out_buf); + } ret = ff_filter_frame(outlink, out_buf); - tile->current = 0; + tile->out_ref = NULL; return ret; } @@ -167,7 +199,7 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref) AVFilterLink *outlink = ctx->outputs[0]; unsigned x0, y0; - if (!tile->current) { + if (!tile->out_ref) { tile->out_ref = ff_get_video_buffer(outlink, outlink->w, outlink->h); if (!tile->out_ref) { av_frame_free(&picref); @@ -178,14 +210,29 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *picref) tile->out_ref->height = outlink->h; /* fill surface once for margin/padding */ - if (tile->margin || tile->padding) + if (tile->margin || tile->padding || tile->init_padding) ff_fill_rectangle(&tile->draw, &tile->blank, tile->out_ref->data, tile->out_ref->linesize, 0, 0, outlink->w, outlink->h); + tile->init_padding = 0; + } + + if (tile->prev_out_ref) { + unsigned x1, y1, i; + + for (i = tile->nb_frames - tile->overlap; i < tile->nb_frames; i++) { + get_tile_pos(ctx, &x1, &y1, i); + get_tile_pos(ctx, &x0, &y0, i - (tile->nb_frames - tile->overlap)); + ff_copy_rectangle2(&tile->draw, + tile->out_ref->data, tile->out_ref->linesize, + tile->prev_out_ref->data, tile->prev_out_ref->linesize, + x0, y0, x1, y1, inlink->w, inlink->h); + + } } - get_current_tile_pos(ctx, &x0, &y0); + get_tile_pos(ctx, &x0, &y0, tile->current); ff_copy_rectangle2(&tile->draw, tile->out_ref->data, tile->out_ref->linesize, picref->data, picref->linesize, @@ -206,11 +253,18 @@ static int request_frame(AVFilterLink *outlink) int r; r = ff_request_frame(inlink); - if (r == AVERROR_EOF && tile->current) + if (r == AVERROR_EOF && tile->current && tile->out_ref) r = end_last_frame(ctx); return r; } +static av_cold void uninit(AVFilterContext *ctx) +{ + TileContext *tile = ctx->priv; + + av_frame_free(&tile->prev_out_ref); +} + static const AVFilterPad tile_inputs[] = { { .name = "default", @@ -234,6 +288,7 @@ AVFilter ff_vf_tile = { .name = "tile", .description = NULL_IF_CONFIG_SMALL("Tile several successive frames together."), .init = init, + .uninit = uninit, .query_formats = query_formats, .priv_size = sizeof(TileContext), .inputs = tile_inputs, diff --git a/libavfilter/vf_transpose.c b/libavfilter/vf_transpose.c index 982fb0c8ca496..74a4bbcf58b47 100644 --- a/libavfilter/vf_transpose.c +++ b/libavfilter/vf_transpose.c @@ -27,6 +27,7 @@ #include +#include "libavutil/avassert.h" #include "libavutil/imgutils.h" #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" @@ -51,19 +52,24 @@ enum TransposeDir { TRANSPOSE_CLOCK_FLIP, }; +typedef struct TransVtable { + void (*transpose_8x8)(uint8_t *src, ptrdiff_t src_linesize, + uint8_t *dst, ptrdiff_t dst_linesize); + void (*transpose_block)(uint8_t *src, ptrdiff_t src_linesize, + uint8_t *dst, ptrdiff_t dst_linesize, + int w, int h); +} TransVtable; + typedef struct TransContext { const AVClass *class; int hsub, vsub; + int planes; int pixsteps[4]; int passthrough; ///< PassthroughType, landscape passthrough mode enabled int dir; ///< TransposeDir - void (*transpose_8x8)(uint8_t *src, ptrdiff_t src_linesize, - uint8_t *dst, ptrdiff_t dst_linesize); - void (*transpose_block)(uint8_t *src, ptrdiff_t src_linesize, - uint8_t *dst, ptrdiff_t dst_linesize, - int w, int h); + TransVtable vtables[4]; } TransContext; static int query_formats(AVFilterContext *ctx) @@ -215,6 +221,10 @@ static int config_props_output(AVFilterLink *outlink) s->hsub = desc_in->log2_chroma_w; s->vsub = desc_in->log2_chroma_h; + s->planes = av_pix_fmt_count_planes(outlink->format); + + av_assert0(desc_in->nb_components == desc_out->nb_components); + av_image_fill_max_pixsteps(s->pixsteps, NULL, desc_out); @@ -227,19 +237,22 @@ static int config_props_output(AVFilterLink *outlink) else outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; - switch (s->pixsteps[0]) { - case 1: s->transpose_block = transpose_block_8_c; - s->transpose_8x8 = transpose_8x8_8_c; break; - case 2: s->transpose_block = transpose_block_16_c; - s->transpose_8x8 = transpose_8x8_16_c; break; - case 3: s->transpose_block = transpose_block_24_c; - s->transpose_8x8 = transpose_8x8_24_c; break; - case 4: s->transpose_block = transpose_block_32_c; - s->transpose_8x8 = transpose_8x8_32_c; break; - case 6: s->transpose_block = transpose_block_48_c; - s->transpose_8x8 = transpose_8x8_48_c; break; - case 8: s->transpose_block = transpose_block_64_c; - s->transpose_8x8 = transpose_8x8_64_c; break; + for (int i = 0; i < 4; i++) { + TransVtable *v = &s->vtables[i]; + switch (s->pixsteps[i]) { + case 1: v->transpose_block = transpose_block_8_c; + v->transpose_8x8 = transpose_8x8_8_c; break; + case 2: v->transpose_block = transpose_block_16_c; + v->transpose_8x8 = transpose_8x8_16_c; break; + case 3: v->transpose_block = transpose_block_24_c; + v->transpose_8x8 = transpose_8x8_24_c; break; + case 4: v->transpose_block = transpose_block_32_c; + v->transpose_8x8 = transpose_8x8_32_c; break; + case 6: v->transpose_block = transpose_block_48_c; + v->transpose_8x8 = transpose_8x8_48_c; break; + case 8: v->transpose_block = transpose_block_64_c; + v->transpose_8x8 = transpose_8x8_64_c; break; + } } av_log(ctx, AV_LOG_VERBOSE, @@ -272,7 +285,7 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, AVFrame *in = td->in; int plane; - for (plane = 0; out->data[plane]; plane++) { + for (plane = 0; plane < s->planes; plane++) { int hsub = plane == 1 || plane == 2 ? s->hsub : 0; int vsub = plane == 1 || plane == 2 ? s->vsub : 0; int pixstep = s->pixsteps[plane]; @@ -284,6 +297,7 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, uint8_t *dst, *src; int dstlinesize, srclinesize; int x, y; + TransVtable *v = &s->vtables[plane]; dstlinesize = out->linesize[plane]; dst = out->data[plane] + start * dstlinesize; @@ -302,20 +316,20 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, for (y = start; y < end - 7; y += 8) { for (x = 0; x < outw - 7; x += 8) { - s->transpose_8x8(src + x * srclinesize + y * pixstep, + v->transpose_8x8(src + x * srclinesize + y * pixstep, srclinesize, dst + (y - start) * dstlinesize + x * pixstep, dstlinesize); } if (outw - x > 0 && end - y > 0) - s->transpose_block(src + x * srclinesize + y * pixstep, + v->transpose_block(src + x * srclinesize + y * pixstep, srclinesize, dst + (y - start) * dstlinesize + x * pixstep, dstlinesize, outw - x, end - y); } if (end - y > 0) - s->transpose_block(src + 0 * srclinesize + y * pixstep, + v->transpose_block(src + 0 * srclinesize + y * pixstep, srclinesize, dst + (y - start) * dstlinesize + 0 * pixstep, dstlinesize, outw, end - y); diff --git a/libavfilter/vf_unsharp.c b/libavfilter/vf_unsharp.c index 438ff6d8fb219..41ccc56942b69 100644 --- a/libavfilter/vf_unsharp.c +++ b/libavfilter/vf_unsharp.c @@ -46,7 +46,6 @@ #include "libavutil/opt.h" #include "libavutil/pixdesc.h" #include "unsharp.h" -#include "unsharp_opencl.h" static void apply_unsharp( uint8_t *dst, int dst_stride, const uint8_t *src, int src_stride, @@ -134,10 +133,8 @@ static void set_filter_param(UnsharpFilterParam *fp, int msize_x, int msize_y, f static av_cold int init(AVFilterContext *ctx) { - int ret = 0; UnsharpContext *s = ctx->priv; - set_filter_param(&s->luma, s->lmsize_x, s->lmsize_y, s->lamount); set_filter_param(&s->chroma, s->cmsize_x, s->cmsize_y, s->camount); @@ -146,16 +143,6 @@ static av_cold int init(AVFilterContext *ctx) return AVERROR(EINVAL); } s->apply_unsharp = apply_unsharp_c; - if (!CONFIG_OPENCL && s->opencl) { - av_log(ctx, AV_LOG_ERROR, "OpenCL support was not enabled in this build, cannot be selected\n"); - return AVERROR(EINVAL); - } - if (CONFIG_OPENCL && s->opencl) { - s->apply_unsharp = ff_opencl_apply_unsharp; - ret = ff_opencl_unsharp_init(ctx); - if (ret < 0) - return ret; - } return 0; } @@ -227,10 +214,6 @@ static av_cold void uninit(AVFilterContext *ctx) { UnsharpContext *s = ctx->priv; - if (CONFIG_OPENCL && s->opencl) { - ff_opencl_unsharp_uninit(ctx); - } - free_filter_param(&s->luma); free_filter_param(&s->chroma); } @@ -248,14 +231,9 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) return AVERROR(ENOMEM); } av_frame_copy_props(out, in); - if (CONFIG_OPENCL && s->opencl) { - ret = ff_opencl_unsharp_process_inout_buf(link->dst, in, out); - if (ret < 0) - goto end; - } ret = s->apply_unsharp(link->dst, in, out); -end: + av_frame_free(&in); if (ret < 0) { @@ -282,7 +260,7 @@ static const AVOption unsharp_options[] = { { "cy", "set chroma matrix vertical size", OFFSET(cmsize_y), AV_OPT_TYPE_INT, { .i64 = 5 }, MIN_SIZE, MAX_SIZE, FLAGS }, { "chroma_amount", "set chroma effect strength", OFFSET(camount), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, -2, 5, FLAGS }, { "ca", "set chroma effect strength", OFFSET(camount), AV_OPT_TYPE_FLOAT, { .dbl = 0 }, -2, 5, FLAGS }, - { "opencl", "use OpenCL filtering capabilities", OFFSET(opencl), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, + { "opencl", "ignored", OFFSET(opencl), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, FLAGS }, { NULL } }; diff --git a/libavfilter/vf_unsharp_opencl.c b/libavfilter/vf_unsharp_opencl.c new file mode 100644 index 0000000000000..19c91857cb719 --- /dev/null +++ b/libavfilter/vf_unsharp_opencl.c @@ -0,0 +1,481 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/common.h" +#include "libavutil/imgutils.h" +#include "libavutil/mem.h" +#include "libavutil/opt.h" +#include "libavutil/pixdesc.h" + +#include "avfilter.h" +#include "internal.h" +#include "opencl.h" +#include "opencl_source.h" +#include "video.h" + +#define MAX_DIAMETER 23 + +typedef struct UnsharpOpenCLContext { + OpenCLFilterContext ocf; + + int initialised; + cl_kernel kernel; + cl_command_queue command_queue; + + float luma_size_x; + float luma_size_y; + float luma_amount; + float chroma_size_x; + float chroma_size_y; + float chroma_amount; + + int global; + + int nb_planes; + struct { + float blur_x[MAX_DIAMETER]; + float blur_y[MAX_DIAMETER]; + + cl_mem matrix; + cl_mem coef_x; + cl_mem coef_y; + + cl_int size_x; + cl_int size_y; + cl_float amount; + cl_float threshold; + } plane[4]; +} UnsharpOpenCLContext; + + +static int unsharp_opencl_init(AVFilterContext *avctx) +{ + UnsharpOpenCLContext *ctx = avctx->priv; + cl_int cle; + int err; + + err = ff_opencl_filter_load_program(avctx, &ff_opencl_source_unsharp, 1); + if (err < 0) + goto fail; + + ctx->command_queue = clCreateCommandQueue(ctx->ocf.hwctx->context, + ctx->ocf.hwctx->device_id, + 0, &cle); + if (!ctx->command_queue) { + av_log(avctx, AV_LOG_ERROR, "Failed to create OpenCL " + "command queue: %d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + + // Use global kernel if mask size will be too big for the local store.. + ctx->global = (ctx->luma_size_x > 17.0f || + ctx->luma_size_y > 17.0f || + ctx->chroma_size_x > 17.0f || + ctx->chroma_size_y > 17.0f); + + ctx->kernel = clCreateKernel(ctx->ocf.program, + ctx->global ? "unsharp_global" + : "unsharp_local", &cle); + if (!ctx->kernel) { + av_log(avctx, AV_LOG_ERROR, "Failed to create kernel: %d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + + ctx->initialised = 1; + return 0; + +fail: + if (ctx->command_queue) + clReleaseCommandQueue(ctx->command_queue); + if (ctx->kernel) + clReleaseKernel(ctx->kernel); + return err; +} + +static int unsharp_opencl_make_filter_params(AVFilterContext *avctx) +{ + UnsharpOpenCLContext *ctx = avctx->priv; + const AVPixFmtDescriptor *desc; + float *matrix; + double val, sum; + cl_int cle; + cl_mem buffer; + size_t matrix_bytes; + float diam_x, diam_y, amount; + int err, p, x, y, size_x, size_y; + + desc = av_pix_fmt_desc_get(ctx->ocf.output_format); + + ctx->nb_planes = 0; + for (p = 0; p < desc->nb_components; p++) + ctx->nb_planes = FFMAX(ctx->nb_planes, desc->comp[p].plane + 1); + + for (p = 0; p < ctx->nb_planes; p++) { + if (p == 0 || (desc->flags & AV_PIX_FMT_FLAG_RGB)) { + diam_x = ctx->luma_size_x; + diam_y = ctx->luma_size_y; + amount = ctx->luma_amount; + } else { + diam_x = ctx->chroma_size_x; + diam_y = ctx->chroma_size_y; + amount = ctx->chroma_amount; + } + size_x = (int)ceil(diam_x) | 1; + size_y = (int)ceil(diam_y) | 1; + matrix_bytes = size_x * size_y * sizeof(float); + + matrix = av_malloc(matrix_bytes); + if (!matrix) { + err = AVERROR(ENOMEM); + goto fail; + } + + sum = 0.0; + for (x = 0; x < size_x; x++) { + double dx = (double)(x - size_x / 2) / diam_x; + sum += ctx->plane[p].blur_x[x] = exp(-16.0 * (dx * dx)); + } + for (x = 0; x < size_x; x++) + ctx->plane[p].blur_x[x] /= sum; + + sum = 0.0; + for (y = 0; y < size_y; y++) { + double dy = (double)(y - size_y / 2) / diam_y; + sum += ctx->plane[p].blur_y[y] = exp(-16.0 * (dy * dy)); + } + for (y = 0; y < size_y; y++) + ctx->plane[p].blur_y[y] /= sum; + + for (y = 0; y < size_y; y++) { + for (x = 0; x < size_x; x++) { + val = ctx->plane[p].blur_x[x] * ctx->plane[p].blur_y[y]; + matrix[y * size_x + x] = val; + } + } + + if (ctx->global) { + buffer = clCreateBuffer(ctx->ocf.hwctx->context, + CL_MEM_READ_ONLY | + CL_MEM_COPY_HOST_PTR | + CL_MEM_HOST_NO_ACCESS, + matrix_bytes, matrix, &cle); + if (!buffer) { + av_log(avctx, AV_LOG_ERROR, "Failed to create matrix buffer: " + "%d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + ctx->plane[p].matrix = buffer; + } else { + buffer = clCreateBuffer(ctx->ocf.hwctx->context, + CL_MEM_READ_ONLY | + CL_MEM_COPY_HOST_PTR | + CL_MEM_HOST_NO_ACCESS, + sizeof(ctx->plane[p].blur_x), + ctx->plane[p].blur_x, &cle); + if (!buffer) { + av_log(avctx, AV_LOG_ERROR, "Failed to create x-coef buffer: " + "%d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + ctx->plane[p].coef_x = buffer; + + buffer = clCreateBuffer(ctx->ocf.hwctx->context, + CL_MEM_READ_ONLY | + CL_MEM_COPY_HOST_PTR | + CL_MEM_HOST_NO_ACCESS, + sizeof(ctx->plane[p].blur_y), + ctx->plane[p].blur_y, &cle); + if (!buffer) { + av_log(avctx, AV_LOG_ERROR, "Failed to create y-coef buffer: " + "%d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + ctx->plane[p].coef_y = buffer; + } + + av_freep(&matrix); + + ctx->plane[p].size_x = size_x; + ctx->plane[p].size_y = size_y; + ctx->plane[p].amount = amount; + } + + err = 0; +fail: + av_freep(&matrix); + return err; +} + +static int unsharp_opencl_filter_frame(AVFilterLink *inlink, AVFrame *input) +{ + AVFilterContext *avctx = inlink->dst; + AVFilterLink *outlink = avctx->outputs[0]; + UnsharpOpenCLContext *ctx = avctx->priv; + AVFrame *output = NULL; + cl_int cle; + size_t global_work[2]; + size_t local_work[2]; + cl_mem src, dst; + int err, p; + + av_log(ctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(input->format), + input->width, input->height, input->pts); + + if (!input->hw_frames_ctx) + return AVERROR(EINVAL); + + if (!ctx->initialised) { + err = unsharp_opencl_init(avctx); + if (err < 0) + goto fail; + + err = unsharp_opencl_make_filter_params(avctx); + if (err < 0) + goto fail; + } + + output = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!output) { + err = AVERROR(ENOMEM); + goto fail; + } + + for (p = 0; p < FF_ARRAY_ELEMS(output->data); p++) { + src = (cl_mem) input->data[p]; + dst = (cl_mem)output->data[p]; + + if (!dst) + break; + + cle = clSetKernelArg(ctx->kernel, 0, sizeof(cl_mem), &dst); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "destination image argument: %d.\n", cle); + goto fail; + } + cle = clSetKernelArg(ctx->kernel, 1, sizeof(cl_mem), &src); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "source image argument: %d.\n", cle); + goto fail; + } + cle = clSetKernelArg(ctx->kernel, 2, sizeof(cl_int), &ctx->plane[p].size_x); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "matrix size argument: %d.\n", cle); + goto fail; + } + cle = clSetKernelArg(ctx->kernel, 3, sizeof(cl_int), &ctx->plane[p].size_y); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "matrix size argument: %d.\n", cle); + goto fail; + } + cle = clSetKernelArg(ctx->kernel, 4, sizeof(cl_float), &ctx->plane[p].amount); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "amount argument: %d.\n", cle); + goto fail; + } + if (ctx->global) { + cle = clSetKernelArg(ctx->kernel, 5, sizeof(cl_mem), &ctx->plane[p].matrix); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "matrix argument: %d.\n", cle); + goto fail; + } + } else { + cle = clSetKernelArg(ctx->kernel, 5, sizeof(cl_mem), &ctx->plane[p].coef_x); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "x-coef argument: %d.\n", cle); + goto fail; + } + cle = clSetKernelArg(ctx->kernel, 6, sizeof(cl_mem), &ctx->plane[p].coef_y); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to set kernel " + "y-coef argument: %d.\n", cle); + goto fail; + } + } + + err = ff_opencl_filter_work_size_from_image(avctx, global_work, output, p, + ctx->global ? 0 : 16); + if (err < 0) + goto fail; + + local_work[0] = 16; + local_work[1] = 16; + + av_log(avctx, AV_LOG_DEBUG, "Run kernel on plane %d " + "(%"SIZE_SPECIFIER"x%"SIZE_SPECIFIER").\n", + p, global_work[0], global_work[1]); + + cle = clEnqueueNDRangeKernel(ctx->command_queue, ctx->kernel, 2, NULL, + global_work, ctx->global ? NULL : local_work, + 0, NULL, NULL); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to enqueue kernel: %d.\n", + cle); + err = AVERROR(EIO); + goto fail; + } + } + + cle = clFinish(ctx->command_queue); + if (cle != CL_SUCCESS) { + av_log(avctx, AV_LOG_ERROR, "Failed to finish command queue: %d.\n", + cle); + err = AVERROR(EIO); + goto fail; + } + + err = av_frame_copy_props(output, input); + if (err < 0) + goto fail; + + av_frame_free(&input); + + av_log(ctx, AV_LOG_DEBUG, "Filter output: %s, %ux%u (%"PRId64").\n", + av_get_pix_fmt_name(output->format), + output->width, output->height, output->pts); + + return ff_filter_frame(outlink, output); + +fail: + clFinish(ctx->command_queue); + av_frame_free(&input); + av_frame_free(&output); + return err; +} + +static av_cold void unsharp_opencl_uninit(AVFilterContext *avctx) +{ + UnsharpOpenCLContext *ctx = avctx->priv; + cl_int cle; + int i; + + for (i = 0; i < ctx->nb_planes; i++) { + if (ctx->plane[i].matrix) + clReleaseMemObject(ctx->plane[i].matrix); + if (ctx->plane[i].coef_x) + clReleaseMemObject(ctx->plane[i].coef_x); + if (ctx->plane[i].coef_y) + clReleaseMemObject(ctx->plane[i].coef_y); + } + + if (ctx->kernel) { + cle = clReleaseKernel(ctx->kernel); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "kernel: %d.\n", cle); + } + + if (ctx->command_queue) { + cle = clReleaseCommandQueue(ctx->command_queue); + if (cle != CL_SUCCESS) + av_log(avctx, AV_LOG_ERROR, "Failed to release " + "command queue: %d.\n", cle); + } + + ff_opencl_filter_uninit(avctx); +} + +#define OFFSET(x) offsetof(UnsharpOpenCLContext, x) +#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM | AV_OPT_FLAG_VIDEO_PARAM) +static const AVOption unsharp_opencl_options[] = { + { "luma_msize_x", "Set luma mask horizontal diameter (pixels)", + OFFSET(luma_size_x), AV_OPT_TYPE_FLOAT, + { .dbl = 5.0 }, 1, MAX_DIAMETER, FLAGS }, + { "lx", "Set luma mask horizontal diameter (pixels)", + OFFSET(luma_size_x), AV_OPT_TYPE_FLOAT, + { .dbl = 5.0 }, 1, MAX_DIAMETER, FLAGS }, + { "luma_msize_y", "Set luma mask vertical diameter (pixels)", + OFFSET(luma_size_y), AV_OPT_TYPE_FLOAT, + { .dbl = 5.0 }, 1, MAX_DIAMETER, FLAGS }, + { "ly", "Set luma mask vertical diameter (pixels)", + OFFSET(luma_size_y), AV_OPT_TYPE_FLOAT, + { .dbl = 5.0 }, 1, MAX_DIAMETER, FLAGS }, + { "luma_amount", "Set luma amount (multiplier)", + OFFSET(luma_amount), AV_OPT_TYPE_FLOAT, + { .dbl = 1.0 }, -10, 10, FLAGS }, + { "la", "Set luma amount (multiplier)", + OFFSET(luma_amount), AV_OPT_TYPE_FLOAT, + { .dbl = 1.0 }, -10, 10, FLAGS }, + + { "chroma_msize_x", "Set chroma mask horizontal diameter (pixels after subsampling)", + OFFSET(chroma_size_x), AV_OPT_TYPE_FLOAT, + { .dbl = 5.0 }, 1, MAX_DIAMETER, FLAGS }, + { "cx", "Set chroma mask horizontal diameter (pixels after subsampling)", + OFFSET(chroma_size_x), AV_OPT_TYPE_FLOAT, + { .dbl = 5.0 }, 1, MAX_DIAMETER, FLAGS }, + { "chroma_msize_y", "Set chroma mask vertical diameter (pixels after subsampling)", + OFFSET(chroma_size_y), AV_OPT_TYPE_FLOAT, + { .dbl = 5.0 }, 1, MAX_DIAMETER, FLAGS }, + { "cy", "Set chroma mask vertical diameter (pixels after subsampling)", + OFFSET(chroma_size_y), AV_OPT_TYPE_FLOAT, + { .dbl = 5.0 }, 1, MAX_DIAMETER, FLAGS }, + { "chroma_amount", "Set chroma amount (multiplier)", + OFFSET(chroma_amount), AV_OPT_TYPE_FLOAT, + { .dbl = 0.0 }, -10, 10, FLAGS }, + { "ca", "Set chroma amount (multiplier)", + OFFSET(chroma_amount), AV_OPT_TYPE_FLOAT, + { .dbl = 0.0 }, -10, 10, FLAGS }, + + { NULL } +}; + +AVFILTER_DEFINE_CLASS(unsharp_opencl); + +static const AVFilterPad unsharp_opencl_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = &unsharp_opencl_filter_frame, + .config_props = &ff_opencl_filter_config_input, + }, + { NULL } +}; + +static const AVFilterPad unsharp_opencl_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = &ff_opencl_filter_config_output, + }, + { NULL } +}; + +AVFilter ff_vf_unsharp_opencl = { + .name = "unsharp_opencl", + .description = NULL_IF_CONFIG_SMALL("Apply unsharp mask to input video"), + .priv_size = sizeof(UnsharpOpenCLContext), + .priv_class = &unsharp_opencl_class, + .init = &ff_opencl_filter_init, + .uninit = &unsharp_opencl_uninit, + .query_formats = &ff_opencl_filter_query_formats, + .inputs = unsharp_opencl_inputs, + .outputs = unsharp_opencl_outputs, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; diff --git a/libavfilter/vf_vaguedenoiser.c b/libavfilter/vf_vaguedenoiser.c index 2b93e70e57d28..b323ce54796a2 100644 --- a/libavfilter/vf_vaguedenoiser.c +++ b/libavfilter/vf_vaguedenoiser.c @@ -42,6 +42,7 @@ typedef struct VagueDenoiserContext { int planes; int depth; + int bpc; int peak; int nb_planes; int planeheight[4]; @@ -135,6 +136,7 @@ static int config_input(AVFilterLink *inlink) int p, i, nsteps_width, nsteps_height, nsteps_max; s->depth = desc->comp[0].depth; + s->bpc = (s->depth + 7) / 8; s->nb_planes = desc->nb_components; s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h); @@ -410,7 +412,7 @@ static void filter(VagueDenoiserContext *s, AVFrame *in, AVFrame *out) if (!((1 << p) & s->planes)) { av_image_copy_plane(out->data[p], out->linesize[p], in->data[p], in->linesize[p], - s->planewidth[p], s->planeheight[p]); + s->planewidth[p] * s->bpc, s->planeheight[p]); continue; } diff --git a/libavfilter/vf_vfrdet.c b/libavfilter/vf_vfrdet.c new file mode 100644 index 0000000000000..cac96e29a2cf7 --- /dev/null +++ b/libavfilter/vf_vfrdet.c @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2017 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/common.h" +#include "libavutil/opt.h" +#include "internal.h" + +typedef struct VFRDETContext { + const AVClass *class; + + int64_t prev_pts; + int64_t delta; + int64_t min_delta; + int64_t max_delta; + + uint64_t vfr; + uint64_t cfr; +} VFRDETContext; + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + VFRDETContext *s = ctx->priv; + + if (s->prev_pts != AV_NOPTS_VALUE) { + int64_t delta = in->pts - s->prev_pts; + + if (s->delta == AV_NOPTS_VALUE) { + s->delta = delta; + } + + if (s->delta != delta) { + s->vfr++; + s->delta = delta; + s->min_delta = FFMIN(delta, s->min_delta); + s->max_delta = FFMAX(delta, s->max_delta); + } else { + s->cfr++; + } + } + + s->prev_pts = in->pts; + + return ff_filter_frame(ctx->outputs[0], in); +} + +static av_cold int init(AVFilterContext *ctx) +{ + VFRDETContext *s = ctx->priv; + + s->prev_pts = AV_NOPTS_VALUE; + s->delta = AV_NOPTS_VALUE; + s->min_delta = INT64_MAX; + s->max_delta = INT64_MIN; + + return 0; +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + VFRDETContext *s = ctx->priv; + + av_log(ctx, AV_LOG_INFO, "VFR:%f (%"PRIu64"/%"PRIu64")", s->vfr / (float)(s->vfr + s->cfr), s->vfr, s->cfr); + if (s->vfr) + av_log(ctx, AV_LOG_INFO, " min: %"PRId64" max: %"PRId64")", s->min_delta, s->max_delta); + av_log(ctx, AV_LOG_INFO, "\n"); +} + +static const AVFilterPad vfrdet_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad vfrdet_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + }, + { NULL } +}; + +AVFilter ff_vf_vfrdet = { + .name = "vfrdet", + .description = NULL_IF_CONFIG_SMALL("Variable frame rate detect filter."), + .priv_size = sizeof(VFRDETContext), + .init = init, + .uninit = uninit, + .inputs = vfrdet_inputs, + .outputs = vfrdet_outputs, +}; diff --git a/libavfilter/vf_vidstabdetect.c b/libavfilter/vf_vidstabdetect.c index 63a178a0c2b5c..fd7ff3be24b0e 100644 --- a/libavfilter/vf_vidstabdetect.c +++ b/libavfilter/vf_vidstabdetect.c @@ -107,10 +107,11 @@ static int config_input(AVFilterLink *inlink) VSMotionDetect* md = &(s->md); VSFrameInfo fi; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + int is_planar = desc->flags & AV_PIX_FMT_FLAG_PLANAR; vsFrameInfoInit(&fi, inlink->w, inlink->h, ff_av2vs_pixfmt(ctx, inlink->format)); - if (fi.bytesPerPixel != av_get_bits_per_pixel(desc)/8) { + if (!is_planar && fi.bytesPerPixel != av_get_bits_per_pixel(desc)/8) { av_log(ctx, AV_LOG_ERROR, "pixel-format error: wrong bits/per/pixel, please report a BUG"); return AVERROR(EINVAL); } diff --git a/libavfilter/vf_vidstabtransform.c b/libavfilter/vf_vidstabtransform.c index 11a0e3d512520..d1ec1391cbb87 100644 --- a/libavfilter/vf_vidstabtransform.c +++ b/libavfilter/vf_vidstabtransform.c @@ -146,6 +146,7 @@ static int config_input(AVFilterLink *inlink) FILE *f; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format); + int is_planar = desc->flags & AV_PIX_FMT_FLAG_PLANAR; VSTransformData *td = &(tc->td); @@ -161,7 +162,7 @@ static int config_input(AVFilterLink *inlink) return AVERROR(EINVAL); } - if (fi_src.bytesPerPixel != av_get_bits_per_pixel(desc)/8 || + if ((!is_planar && fi_src.bytesPerPixel != av_get_bits_per_pixel(desc)/8) || fi_src.log2ChromaW != desc->log2_chroma_w || fi_src.log2ChromaH != desc->log2_chroma_h) { av_log(ctx, AV_LOG_ERROR, "pixel-format error: bpp %i<>%i ", diff --git a/libavfilter/vf_vpp_qsv.c b/libavfilter/vf_vpp_qsv.c new file mode 100644 index 0000000000000..6be7098ae91f0 --- /dev/null +++ b/libavfilter/vf_vpp_qsv.c @@ -0,0 +1,428 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + ** @file + ** Hardware accelerated common filters based on Intel Quick Sync Video VPP + **/ + +#include + +#include "libavutil/opt.h" +#include "libavutil/eval.h" +#include "libavutil/avassert.h" +#include "libavutil/pixdesc.h" +#include "libavutil/mathematics.h" + +#include "formats.h" +#include "internal.h" +#include "avfilter.h" +#include "libavcodec/avcodec.h" +#include "libavformat/avformat.h" + +#include "qsvvpp.h" + +#define OFFSET(x) offsetof(VPPContext, x) +#define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM) + +/* number of video enhancement filters */ +#define ENH_FILTERS_COUNT (5) + +typedef struct VPPContext{ + const AVClass *class; + + QSVVPPContext *qsv; + + /* Video Enhancement Algorithms */ + mfxExtVPPDeinterlacing deinterlace_conf; + mfxExtVPPFrameRateConversion frc_conf; + mfxExtVPPDenoise denoise_conf; + mfxExtVPPDetail detail_conf; + mfxExtVPPProcAmp procamp_conf; + + int out_width; + int out_height; + + AVRational framerate; /* target framerate */ + int use_frc; /* use framerate conversion */ + int deinterlace; /* deinterlace mode : 0=off, 1=bob, 2=advanced */ + int denoise; /* Enable Denoise algorithm. Value [0, 100] */ + int detail; /* Enable Detail Enhancement algorithm. */ + /* Level is the optional, value [0, 100] */ + int use_crop; /* 1 = use crop; 0=none */ + int crop_w; + int crop_h; + int crop_x; + int crop_y; + + /* param for the procamp */ + int procamp; /* enable procamp */ + float hue; + float saturation; + float contrast; + float brightness; + + char *cx, *cy, *cw, *ch; + char *ow, *oh; +} VPPContext; + +static const AVOption options[] = { + { "deinterlace", "deinterlace mode: 0=off, 1=bob, 2=advanced", OFFSET(deinterlace), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, MFX_DEINTERLACING_ADVANCED, .flags = FLAGS, "deinterlace" }, + { "bob", "Bob deinterlace mode.", 0, AV_OPT_TYPE_CONST, { .i64 = MFX_DEINTERLACING_BOB }, .flags = FLAGS, "deinterlace" }, + { "advanced", "Advanced deinterlace mode. ", 0, AV_OPT_TYPE_CONST, { .i64 = MFX_DEINTERLACING_ADVANCED }, .flags = FLAGS, "deinterlace" }, + + { "denoise", "denoise level [0, 100]", OFFSET(denoise), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 100, .flags = FLAGS }, + { "detail", "enhancement level [0, 100]", OFFSET(detail), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 100, .flags = FLAGS }, + { "framerate", "output framerate", OFFSET(framerate), AV_OPT_TYPE_RATIONAL, { .dbl = 0.0 },0, DBL_MAX, .flags = FLAGS }, + { "procamp", "Enable ProcAmp", OFFSET(procamp), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = FLAGS}, + { "hue", "ProcAmp hue", OFFSET(hue), AV_OPT_TYPE_FLOAT, { .dbl = 0.0 }, -180.0, 180.0, .flags = FLAGS}, + { "saturation", "ProcAmp saturation", OFFSET(saturation), AV_OPT_TYPE_FLOAT, { .dbl = 1.0 }, 0.0, 10.0, .flags = FLAGS}, + { "contrast", "ProcAmp contrast", OFFSET(contrast), AV_OPT_TYPE_FLOAT, { .dbl = 1.0 }, 0.0, 10.0, .flags = FLAGS}, + { "brightness", "ProcAmp brightness", OFFSET(brightness), AV_OPT_TYPE_FLOAT, { .dbl = 0.0 }, -100.0, 100.0, .flags = FLAGS}, + + { "cw", "set the width crop area expression", OFFSET(cw), AV_OPT_TYPE_STRING, { .str = "iw" }, CHAR_MIN, CHAR_MAX, FLAGS }, + { "ch", "set the height crop area expression", OFFSET(ch), AV_OPT_TYPE_STRING, { .str = "ih" }, CHAR_MIN, CHAR_MAX, FLAGS }, + { "cx", "set the x crop area expression", OFFSET(cx), AV_OPT_TYPE_STRING, { .str = "(in_w-out_w)/2" }, CHAR_MIN, CHAR_MAX, FLAGS }, + { "cy", "set the y crop area expression", OFFSET(cy), AV_OPT_TYPE_STRING, { .str = "(in_h-out_h)/2" }, CHAR_MIN, CHAR_MAX, FLAGS }, + + { "w", "Output video width", OFFSET(ow), AV_OPT_TYPE_STRING, { .str="cw" }, 0, 255, .flags = FLAGS }, + { "width", "Output video width", OFFSET(ow), AV_OPT_TYPE_STRING, { .str="cw" }, 0, 255, .flags = FLAGS }, + { "h", "Output video height", OFFSET(oh), AV_OPT_TYPE_STRING, { .str="w*ch/cw" }, 0, 255, .flags = FLAGS }, + { "height", "Output video height", OFFSET(oh), AV_OPT_TYPE_STRING, { .str="w*ch/cw" }, 0, 255, .flags = FLAGS }, + { NULL } +}; + +static const char *const var_names[] = { + "iw", "in_w", + "ih", "in_h", + "ow", "out_w", "w", + "oh", "out_h", "h", + "cw", + "ch", + "cx", + "cy", + NULL +}; + +enum var_name { + VAR_iW, VAR_IN_W, + VAR_iH, VAR_IN_H, + VAR_oW, VAR_OUT_W, VAR_W, + VAR_oH, VAR_OUT_H, VAR_H, + CW, + CH, + CX, + CY, + VAR_VARS_NB +}; + +static int eval_expr(AVFilterContext *ctx) +{ +#define PASS_EXPR(e, s) {\ + ret = av_expr_parse(&e, s, var_names, NULL, NULL, NULL, NULL, 0, ctx); \ + if (ret < 0) {\ + av_log(ctx, AV_LOG_ERROR, "Error when passing '%s'.\n", s);\ + goto release;\ + }\ +} +#define CALC_EXPR(e, v, i) {\ + i = v = av_expr_eval(e, var_values, NULL); \ +} + VPPContext *vpp = ctx->priv; + double var_values[VAR_VARS_NB] = { NAN }; + AVExpr *w_expr = NULL, *h_expr = NULL; + AVExpr *cw_expr = NULL, *ch_expr = NULL; + AVExpr *cx_expr = NULL, *cy_expr = NULL; + int ret = 0; + + PASS_EXPR(cw_expr, vpp->cw); + PASS_EXPR(ch_expr, vpp->ch); + + PASS_EXPR(w_expr, vpp->ow); + PASS_EXPR(h_expr, vpp->oh); + + PASS_EXPR(cx_expr, vpp->cx); + PASS_EXPR(cy_expr, vpp->cy); + + var_values[VAR_iW] = + var_values[VAR_IN_W] = ctx->inputs[0]->w; + + var_values[VAR_iH] = + var_values[VAR_IN_H] = ctx->inputs[0]->h; + + /* crop params */ + CALC_EXPR(cw_expr, var_values[CW], vpp->crop_w); + CALC_EXPR(ch_expr, var_values[CH], vpp->crop_h); + + /* calc again in case cw is relative to ch */ + CALC_EXPR(cw_expr, var_values[CW], vpp->crop_w); + + CALC_EXPR(w_expr, + var_values[VAR_OUT_W] = var_values[VAR_oW] = var_values[VAR_W], + vpp->out_width); + CALC_EXPR(h_expr, + var_values[VAR_OUT_H] = var_values[VAR_oH] = var_values[VAR_H], + vpp->out_height); + + /* calc again in case ow is relative to oh */ + CALC_EXPR(w_expr, + var_values[VAR_OUT_W] = var_values[VAR_oW] = var_values[VAR_W], + vpp->out_width); + + + CALC_EXPR(cx_expr, var_values[CX], vpp->crop_x); + CALC_EXPR(cy_expr, var_values[CY], vpp->crop_y); + + /* calc again in case cx is relative to cy */ + CALC_EXPR(cx_expr, var_values[CX], vpp->crop_x); + + if ((vpp->crop_w != var_values[VAR_iW]) || (vpp->crop_h != var_values[VAR_iH])) + vpp->use_crop = 1; + +release: + av_expr_free(w_expr); + av_expr_free(h_expr); + av_expr_free(cw_expr); + av_expr_free(ch_expr); + av_expr_free(cx_expr); + av_expr_free(cy_expr); +#undef PASS_EXPR +#undef CALC_EXPR + + return ret; +} + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + VPPContext *vpp = ctx->priv; + int ret; + + if (vpp->framerate.den == 0 || vpp->framerate.num == 0) + vpp->framerate = inlink->frame_rate; + + if (av_cmp_q(vpp->framerate, inlink->frame_rate)) + vpp->use_frc = 1; + + ret = eval_expr(ctx); + if (ret != 0) { + av_log(ctx, AV_LOG_ERROR, "Fail to eval expr.\n"); + return ret; + } + + if (vpp->out_height == 0 || vpp->out_width == 0) { + vpp->out_width = inlink->w; + vpp->out_height = inlink->h; + } + + if (vpp->use_crop) { + vpp->crop_x = FFMAX(vpp->crop_x, 0); + vpp->crop_y = FFMAX(vpp->crop_y, 0); + + if(vpp->crop_w + vpp->crop_x > inlink->w) + vpp->crop_x = inlink->w - vpp->crop_w; + if(vpp->crop_h + vpp->crop_y > inlink->h) + vpp->crop_y = inlink->h - vpp->crop_h; + } + + return 0; +} + +static int config_output(AVFilterLink *outlink) +{ + AVFilterContext *ctx = outlink->src; + VPPContext *vpp = ctx->priv; + QSVVPPParam param = { NULL }; + QSVVPPCrop crop = { 0 }; + mfxExtBuffer *ext_buf[ENH_FILTERS_COUNT]; + AVFilterLink *inlink = ctx->inputs[0]; + + outlink->w = vpp->out_width; + outlink->h = vpp->out_height; + outlink->frame_rate = vpp->framerate; + outlink->time_base = av_inv_q(vpp->framerate); + + param.filter_frame = NULL; + param.out_sw_format = AV_PIX_FMT_NV12; + param.num_ext_buf = 0; + param.ext_buf = ext_buf; + + if (vpp->use_crop) { + crop.in_idx = 0; + crop.x = vpp->crop_x; + crop.y = vpp->crop_y; + crop.w = vpp->crop_w; + crop.h = vpp->crop_h; + + param.num_crop = 1; + param.crop = &crop; + } + + if (vpp->deinterlace) { + memset(&vpp->deinterlace_conf, 0, sizeof(mfxExtVPPDeinterlacing)); + vpp->deinterlace_conf.Header.BufferId = MFX_EXTBUFF_VPP_DEINTERLACING; + vpp->deinterlace_conf.Header.BufferSz = sizeof(mfxExtVPPDeinterlacing); + vpp->deinterlace_conf.Mode = vpp->deinterlace == 1 ? + MFX_DEINTERLACING_BOB : MFX_DEINTERLACING_ADVANCED; + + param.ext_buf[param.num_ext_buf++] = (mfxExtBuffer*)&vpp->deinterlace_conf; + } + + if (vpp->use_frc) { + memset(&vpp->frc_conf, 0, sizeof(mfxExtVPPFrameRateConversion)); + vpp->frc_conf.Header.BufferId = MFX_EXTBUFF_VPP_FRAME_RATE_CONVERSION; + vpp->frc_conf.Header.BufferSz = sizeof(mfxExtVPPFrameRateConversion); + vpp->frc_conf.Algorithm = MFX_FRCALGM_DISTRIBUTED_TIMESTAMP; + + param.ext_buf[param.num_ext_buf++] = (mfxExtBuffer*)&vpp->frc_conf; + } + + if (vpp->denoise) { + memset(&vpp->denoise_conf, 0, sizeof(mfxExtVPPDenoise)); + vpp->denoise_conf.Header.BufferId = MFX_EXTBUFF_VPP_DENOISE; + vpp->denoise_conf.Header.BufferSz = sizeof(mfxExtVPPDenoise); + vpp->denoise_conf.DenoiseFactor = vpp->denoise; + + param.ext_buf[param.num_ext_buf++] = (mfxExtBuffer*)&vpp->denoise_conf; + } + + if (vpp->detail) { + memset(&vpp->detail_conf, 0, sizeof(mfxExtVPPDetail)); + vpp->detail_conf.Header.BufferId = MFX_EXTBUFF_VPP_DETAIL; + vpp->detail_conf.Header.BufferSz = sizeof(mfxExtVPPDetail); + vpp->detail_conf.DetailFactor = vpp->detail; + + param.ext_buf[param.num_ext_buf++] = (mfxExtBuffer*)&vpp->detail_conf; + } + + if (vpp->procamp) { + memset(&vpp->procamp_conf, 0, sizeof(mfxExtVPPProcAmp)); + vpp->procamp_conf.Header.BufferId = MFX_EXTBUFF_VPP_PROCAMP; + vpp->procamp_conf.Header.BufferSz = sizeof(mfxExtVPPProcAmp); + vpp->procamp_conf.Hue = vpp->hue; + vpp->procamp_conf.Saturation = vpp->saturation; + vpp->procamp_conf.Contrast = vpp->contrast; + vpp->procamp_conf.Brightness = vpp->brightness; + + param.ext_buf[param.num_ext_buf++] = (mfxExtBuffer*)&vpp->procamp_conf; + } + + if (vpp->use_frc || vpp->use_crop || vpp->deinterlace || vpp->denoise || + vpp->detail || vpp->procamp || inlink->w != outlink->w || inlink->h != outlink->h) + return ff_qsvvpp_create(ctx, &vpp->qsv, ¶m); + else { + av_log(ctx, AV_LOG_VERBOSE, "qsv vpp pass through mode.\n"); + if (inlink->hw_frames_ctx) + outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx); + } + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *picref) +{ + int ret = 0; + AVFilterContext *ctx = inlink->dst; + VPPContext *vpp = inlink->dst->priv; + AVFilterLink *outlink = ctx->outputs[0]; + + if (vpp->qsv) + ret = ff_qsvvpp_filter_frame(vpp->qsv, inlink, picref); + else { + if (picref->pts != AV_NOPTS_VALUE) + picref->pts = av_rescale_q(picref->pts, inlink->time_base, outlink->time_base); + ret = ff_filter_frame(outlink, picref); + } + + return ret; +} + +static int query_formats(AVFilterContext *ctx) +{ + int ret; + AVFilterFormats *in_fmts, *out_fmts; + static const enum AVPixelFormat in_pix_fmts[] = { + AV_PIX_FMT_YUV420P, + AV_PIX_FMT_NV12, + AV_PIX_FMT_YUYV422, + AV_PIX_FMT_RGB32, + AV_PIX_FMT_QSV, + AV_PIX_FMT_NONE + }; + static const enum AVPixelFormat out_pix_fmts[] = { + AV_PIX_FMT_NV12, + AV_PIX_FMT_QSV, + AV_PIX_FMT_NONE + }; + + in_fmts = ff_make_format_list(in_pix_fmts); + out_fmts = ff_make_format_list(out_pix_fmts); + ret = ff_formats_ref(in_fmts, &ctx->inputs[0]->out_formats); + if (ret < 0) + return ret; + ret = ff_formats_ref(out_fmts, &ctx->outputs[0]->in_formats); + if (ret < 0) + return ret; + + return 0; +} + +static av_cold void vpp_uninit(AVFilterContext *ctx) +{ + VPPContext *vpp = ctx->priv; + + ff_qsvvpp_free(&vpp->qsv); +} + +static const AVClass vpp_class = { + .class_name = "vpp_qsv", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const AVFilterPad vpp_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_input, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad vpp_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_output, + }, + { NULL } +}; + +AVFilter ff_vf_vpp_qsv = { + .name = "vpp_qsv", + .description = NULL_IF_CONFIG_SMALL("Quick Sync Video VPP."), + .priv_size = sizeof(VPPContext), + .query_formats = query_formats, + .uninit = vpp_uninit, + .inputs = vpp_inputs, + .outputs = vpp_outputs, + .priv_class = &vpp_class, + .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, +}; diff --git a/libavfilter/vf_waveform.c b/libavfilter/vf_waveform.c index 0c574742a0a4d..428147c607c78 100644 --- a/libavfilter/vf_waveform.c +++ b/libavfilter/vf_waveform.c @@ -36,6 +36,7 @@ enum FilterType { CHROMA, COLOR, ACOLOR, + XFLAT, NB_FILTERS }; @@ -89,6 +90,7 @@ typedef struct WaveformContext { int max; int size; int scale; + uint8_t grat_yuva_color[4]; int shift_w[4], shift_h[4]; GraticuleLines *glines; int nb_glines; @@ -135,10 +137,12 @@ static const AVOption waveform_options[] = { { "chroma", NULL, 0, AV_OPT_TYPE_CONST, {.i64=CHROMA}, 0, 0, FLAGS, "filter" }, { "color", NULL, 0, AV_OPT_TYPE_CONST, {.i64=COLOR}, 0, 0, FLAGS, "filter" }, { "acolor", NULL, 0, AV_OPT_TYPE_CONST, {.i64=ACOLOR}, 0, 0, FLAGS, "filter" }, - { "graticule", "set graticule", OFFSET(graticule), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "graticule" }, - { "g", "set graticule", OFFSET(graticule), AV_OPT_TYPE_INT, {.i64=0}, 0, 1, FLAGS, "graticule" }, - { "none", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "graticule" }, - { "green", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "graticule" }, + { "xflat", NULL, 0, AV_OPT_TYPE_CONST, {.i64=XFLAT}, 0, 0, FLAGS, "filter" }, + { "graticule", "set graticule", OFFSET(graticule), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, FLAGS, "graticule" }, + { "g", "set graticule", OFFSET(graticule), AV_OPT_TYPE_INT, {.i64=0}, 0, 2, FLAGS, "graticule" }, + { "none", NULL, 0, AV_OPT_TYPE_CONST, {.i64=0}, 0, 0, FLAGS, "graticule" }, + { "green", NULL, 0, AV_OPT_TYPE_CONST, {.i64=1}, 0, 0, FLAGS, "graticule" }, + { "orange", NULL, 0, AV_OPT_TYPE_CONST, {.i64=2}, 0, 0, FLAGS, "graticule" }, { "opacity", "set graticule opacity", OFFSET(opacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, FLAGS }, { "o", "set graticule opacity", OFFSET(opacity), AV_OPT_TYPE_FLOAT, {.dbl=0.75}, 0, 1, FLAGS }, { "flags", "set graticule flags", OFFSET(flags), AV_OPT_TYPE_FLAGS, {.i64=1}, 0, 3, FLAGS, "flags" }, @@ -291,10 +295,12 @@ static int query_formats(AVFilterContext *ctx) switch (s->filter) { case LOWPASS: in_pix_fmts = in_lowpass_pix_fmts; break; case CHROMA: + case XFLAT: case AFLAT: case FLAT: in_pix_fmts = in_flat_pix_fmts; break; case ACOLOR: case COLOR: in_pix_fmts = in_color_pix_fmts; break; + default: return AVERROR_BUG; } if (!ctx->inputs[0]->out_formats) { @@ -618,6 +624,22 @@ static void update(uint8_t *target, int max, int intensity) *target = 255; } +static void update_cr(uint8_t *target, int unused, int intensity) +{ + if (*target - intensity > 0) + *target -= intensity; + else + *target = 0; +} + +static void update16_cr(uint16_t *target, int unused, int intensity, int limit) +{ + if (*target - intensity > 0) + *target -= intensity; + else + *target = 0; +} + static av_always_inline void lowpass16(WaveformContext *s, AVFrame *in, AVFrame *out, int component, int intensity, @@ -1013,256 +1035,276 @@ static av_always_inline void flat(WaveformContext *s, envelope(s, out, plane, (plane + 1) % s->ncomp, column ? offset_x : offset_y); } -static av_always_inline void aflat16(WaveformContext *s, - AVFrame *in, AVFrame *out, - int component, int intensity, - int offset_y, int offset_x, - int column, int mirror) -{ - const int plane = s->desc->comp[component].plane; - const int c0_linesize = in->linesize[ plane + 0 ] / 2; - const int c1_linesize = in->linesize[(plane + 1) % s->ncomp] / 2; - const int c2_linesize = in->linesize[(plane + 2) % s->ncomp] / 2; - const int c0_shift_w = s->shift_w[ component + 0 ]; - const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp]; - const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp]; - const int c0_shift_h = s->shift_h[ component + 0 ]; - const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp]; - const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp]; - const int d0_linesize = out->linesize[ plane + 0 ] / 2; - const int d1_linesize = out->linesize[(plane + 1) % s->ncomp] / 2; - const int d2_linesize = out->linesize[(plane + 2) % s->ncomp] / 2; - const int limit = s->max - 1; - const int max = limit - intensity; - const int mid = s->max / 2; - const int src_h = in->height; - const int src_w = in->width; - int x, y; - - if (column) { - const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1); - const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1); - const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1); - - for (x = 0; x < src_w; x++) { - const uint16_t *c0_data = (uint16_t *)in->data[plane + 0]; - const uint16_t *c1_data = (uint16_t *)in->data[(plane + 1) % s->ncomp]; - const uint16_t *c2_data = (uint16_t *)in->data[(plane + 2) % s->ncomp]; - uint16_t *d0_data = (uint16_t *)out->data[plane] + offset_y * d0_linesize + offset_x; - uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x; - uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x; - uint16_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1); - uint16_t * const d0 = (mirror ? d0_bottom_line : d0_data); - uint16_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1); - uint16_t * const d1 = (mirror ? d1_bottom_line : d1_data); - uint16_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1); - uint16_t * const d2 = (mirror ? d2_bottom_line : d2_data); - - for (y = 0; y < src_h; y++) { - const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit) + mid; - const int c1 = FFMIN(c1_data[x >> c1_shift_w], limit) - mid; - const int c2 = FFMIN(c2_data[x >> c2_shift_w], limit) - mid; - uint16_t *target; - - target = d0 + x + d0_signed_linesize * c0; - update16(target, max, intensity, limit); - - target = d1 + x + d1_signed_linesize * (c0 + c1); - update16(target, max, intensity, limit); - - target = d2 + x + d2_signed_linesize * (c0 + c2); - update16(target, max, intensity, limit); - - if (!c0_shift_h || (y & c0_shift_h)) - c0_data += c0_linesize; - if (!c1_shift_h || (y & c1_shift_h)) - c1_data += c1_linesize; - if (!c2_shift_h || (y & c2_shift_h)) - c2_data += c2_linesize; - d0_data += d0_linesize; - d1_data += d1_linesize; - d2_data += d2_linesize; - } - } - } else { - const uint16_t *c0_data = (uint16_t *)in->data[plane]; - const uint16_t *c1_data = (uint16_t *)in->data[(plane + 1) % s->ncomp]; - const uint16_t *c2_data = (uint16_t *)in->data[(plane + 2) % s->ncomp]; - uint16_t *d0_data = (uint16_t *)out->data[plane] + offset_y * d0_linesize + offset_x; - uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x; - uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x; - - if (mirror) { - d0_data += s->size - 1; - d1_data += s->size - 1; - d2_data += s->size - 1; - } - - for (y = 0; y < src_h; y++) { - for (x = 0; x < src_w; x++) { - const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit) + mid; - const int c1 = FFMIN(c1_data[x >> c1_shift_w], limit) - mid; - const int c2 = FFMIN(c2_data[x >> c2_shift_w], limit) - mid; - uint16_t *target; - - if (mirror) { - target = d0_data - c0; - update16(target, max, intensity, limit); - target = d1_data - (c0 + c1); - update16(target, max, intensity, limit); - target = d2_data - (c0 + c2); - update16(target, max, intensity, limit); - } else { - target = d0_data + c0; - update16(target, max, intensity, limit); - target = d1_data + (c0 + c1); - update16(target, max, intensity, limit); - target = d2_data + (c0 + c2); - update16(target, max, intensity, limit); - } - } - - if (!c0_shift_h || (y & c0_shift_h)) - c0_data += c0_linesize; - if (!c1_shift_h || (y & c1_shift_h)) - c1_data += c1_linesize; - if (!c2_shift_h || (y & c2_shift_h)) - c2_data += c2_linesize; - d0_data += d0_linesize; - d1_data += d1_linesize; - d2_data += d2_linesize; - } - } - - envelope16(s, out, plane, (plane + 0) % s->ncomp, column ? offset_x : offset_y); - envelope16(s, out, plane, (plane + 1) % s->ncomp, column ? offset_x : offset_y); - envelope16(s, out, plane, (plane + 2) % s->ncomp, column ? offset_x : offset_y); +#define AFLAT16(name, update_cr, column, mirror) \ +static av_always_inline void name (WaveformContext *s, \ + AVFrame *in, AVFrame *out, \ + int component, int intensity, \ + int offset_y, int offset_x, \ + int unused1, int unused2) \ +{ \ + const int plane = s->desc->comp[component].plane; \ + const int c0_linesize = in->linesize[ plane + 0 ] / 2; \ + const int c1_linesize = in->linesize[(plane + 1) % s->ncomp] / 2; \ + const int c2_linesize = in->linesize[(plane + 2) % s->ncomp] / 2; \ + const int c0_shift_w = s->shift_w[ component + 0 ]; \ + const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp]; \ + const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp]; \ + const int c0_shift_h = s->shift_h[ component + 0 ]; \ + const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp]; \ + const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp]; \ + const int d0_linesize = out->linesize[ plane + 0 ] / 2; \ + const int d1_linesize = out->linesize[(plane + 1) % s->ncomp] / 2; \ + const int d2_linesize = out->linesize[(plane + 2) % s->ncomp] / 2; \ + const int limit = s->max - 1; \ + const int max = limit - intensity; \ + const int mid = s->max / 2; \ + const int src_h = in->height; \ + const int src_w = in->width; \ + int x, y; \ + \ + if (column) { \ + const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1); \ + const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1); \ + const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1); \ + \ + for (x = 0; x < src_w; x++) { \ + const uint16_t *c0_data = (uint16_t *)in->data[plane + 0]; \ + const uint16_t *c1_data = (uint16_t *)in->data[(plane + 1) % s->ncomp]; \ + const uint16_t *c2_data = (uint16_t *)in->data[(plane + 2) % s->ncomp]; \ + uint16_t *d0_data = (uint16_t *)out->data[plane] + offset_y * d0_linesize + offset_x; \ + uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x; \ + uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x; \ + uint16_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1); \ + uint16_t * const d0 = (mirror ? d0_bottom_line : d0_data); \ + uint16_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1); \ + uint16_t * const d1 = (mirror ? d1_bottom_line : d1_data); \ + uint16_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1); \ + uint16_t * const d2 = (mirror ? d2_bottom_line : d2_data); \ + \ + for (y = 0; y < src_h; y++) { \ + const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit) + mid; \ + const int c1 = FFMIN(c1_data[x >> c1_shift_w], limit) - mid; \ + const int c2 = FFMIN(c2_data[x >> c2_shift_w], limit) - mid; \ + uint16_t *target; \ + \ + target = d0 + x + d0_signed_linesize * c0; \ + update16(target, max, intensity, limit); \ + \ + target = d1 + x + d1_signed_linesize * (c0 + c1); \ + update16(target, max, intensity, limit); \ + \ + target = d2 + x + d2_signed_linesize * (c0 + c2); \ + update_cr(target, max, intensity, limit); \ + \ + if (!c0_shift_h || (y & c0_shift_h)) \ + c0_data += c0_linesize; \ + if (!c1_shift_h || (y & c1_shift_h)) \ + c1_data += c1_linesize; \ + if (!c2_shift_h || (y & c2_shift_h)) \ + c2_data += c2_linesize; \ + d0_data += d0_linesize; \ + d1_data += d1_linesize; \ + d2_data += d2_linesize; \ + } \ + } \ + } else { \ + const uint16_t *c0_data = (uint16_t *)in->data[plane]; \ + const uint16_t *c1_data = (uint16_t *)in->data[(plane + 1) % s->ncomp]; \ + const uint16_t *c2_data = (uint16_t *)in->data[(plane + 2) % s->ncomp]; \ + uint16_t *d0_data = (uint16_t *)out->data[plane] + offset_y * d0_linesize + offset_x; \ + uint16_t *d1_data = (uint16_t *)out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x; \ + uint16_t *d2_data = (uint16_t *)out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x; \ + \ + if (mirror) { \ + d0_data += s->size - 1; \ + d1_data += s->size - 1; \ + d2_data += s->size - 1; \ + } \ + \ + for (y = 0; y < src_h; y++) { \ + for (x = 0; x < src_w; x++) { \ + const int c0 = FFMIN(c0_data[x >> c0_shift_w], limit) + mid; \ + const int c1 = FFMIN(c1_data[x >> c1_shift_w], limit) - mid; \ + const int c2 = FFMIN(c2_data[x >> c2_shift_w], limit) - mid; \ + uint16_t *target; \ + \ + if (mirror) { \ + target = d0_data - c0; \ + update16(target, max, intensity, limit); \ + target = d1_data - (c0 + c1); \ + update16(target, max, intensity, limit); \ + target = d2_data - (c0 + c2); \ + update_cr(target, max, intensity, limit); \ + } else { \ + target = d0_data + c0; \ + update16(target, max, intensity, limit); \ + target = d1_data + (c0 + c1); \ + update16(target, max, intensity, limit); \ + target = d2_data + (c0 + c2); \ + update_cr(target, max, intensity, limit); \ + } \ + } \ + \ + if (!c0_shift_h || (y & c0_shift_h)) \ + c0_data += c0_linesize; \ + if (!c1_shift_h || (y & c1_shift_h)) \ + c1_data += c1_linesize; \ + if (!c2_shift_h || (y & c2_shift_h)) \ + c2_data += c2_linesize; \ + d0_data += d0_linesize; \ + d1_data += d1_linesize; \ + d2_data += d2_linesize; \ + } \ + } \ + \ + envelope16(s, out, plane, (plane + 0) % s->ncomp, column ? offset_x : offset_y); \ + envelope16(s, out, plane, (plane + 1) % s->ncomp, column ? offset_x : offset_y); \ + envelope16(s, out, plane, (plane + 2) % s->ncomp, column ? offset_x : offset_y); \ } -static av_always_inline void aflat(WaveformContext *s, - AVFrame *in, AVFrame *out, - int component, int intensity, - int offset_y, int offset_x, - int column, int mirror) -{ - const int plane = s->desc->comp[component].plane; - const int c0_linesize = in->linesize[ plane + 0 ]; - const int c1_linesize = in->linesize[(plane + 1) % s->ncomp]; - const int c2_linesize = in->linesize[(plane + 2) % s->ncomp]; - const int c0_shift_w = s->shift_w[ component + 0 ]; - const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp]; - const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp]; - const int c0_shift_h = s->shift_h[ component + 0 ]; - const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp]; - const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp]; - const int d0_linesize = out->linesize[ plane + 0 ]; - const int d1_linesize = out->linesize[(plane + 1) % s->ncomp]; - const int d2_linesize = out->linesize[(plane + 2) % s->ncomp]; - const int max = 255 - intensity; - const int src_h = in->height; - const int src_w = in->width; - int x, y; - - if (column) { - const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1); - const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1); - const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1); - - for (x = 0; x < src_w; x++) { - const uint8_t *c0_data = in->data[plane + 0]; - const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp]; - const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp]; - uint8_t *d0_data = out->data[plane] + offset_y * d0_linesize + offset_x; - uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x; - uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x; - uint8_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1); - uint8_t * const d0 = (mirror ? d0_bottom_line : d0_data); - uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1); - uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data); - uint8_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1); - uint8_t * const d2 = (mirror ? d2_bottom_line : d2_data); - - for (y = 0; y < src_h; y++) { - const int c0 = c0_data[x >> c0_shift_w] + 128; - const int c1 = c1_data[x >> c1_shift_w] - 128; - const int c2 = c2_data[x >> c2_shift_w] - 128; - uint8_t *target; - - target = d0 + x + d0_signed_linesize * c0; - update(target, max, intensity); - - target = d1 + x + d1_signed_linesize * (c0 + c1); - update(target, max, intensity); - - target = d2 + x + d2_signed_linesize * (c0 + c2); - update(target, max, intensity); - - if (!c0_shift_h || (y & c0_shift_h)) - c0_data += c0_linesize; - if (!c1_shift_h || (y & c1_shift_h)) - c1_data += c1_linesize; - if (!c1_shift_h || (y & c1_shift_h)) - c2_data += c1_linesize; - d0_data += d0_linesize; - d1_data += d1_linesize; - d2_data += d2_linesize; - } - } - } else { - const uint8_t *c0_data = in->data[plane]; - const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp]; - const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp]; - uint8_t *d0_data = out->data[plane] + offset_y * d0_linesize + offset_x; - uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x; - uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x; - - if (mirror) { - d0_data += s->size - 1; - d1_data += s->size - 1; - d2_data += s->size - 1; - } - - for (y = 0; y < src_h; y++) { - for (x = 0; x < src_w; x++) { - const int c0 = c0_data[x >> c0_shift_w] + 128; - const int c1 = c1_data[x >> c1_shift_w] - 128; - const int c2 = c2_data[x >> c2_shift_w] - 128; - uint8_t *target; - - if (mirror) { - target = d0_data - c0; - update(target, max, intensity); - target = d1_data - (c0 + c1); - update(target, max, intensity); - target = d2_data - (c0 + c2); - update(target, max, intensity); - } else { - target = d0_data + c0; - update(target, max, intensity); - target = d1_data + (c0 + c1); - update(target, max, intensity); - target = d2_data + (c0 + c2); - update(target, max, intensity); - } - } - - if (!c0_shift_h || (y & c0_shift_h)) - c0_data += c0_linesize; - if (!c1_shift_h || (y & c1_shift_h)) - c1_data += c1_linesize; - if (!c2_shift_h || (y & c2_shift_h)) - c2_data += c2_linesize; - d0_data += d0_linesize; - d1_data += d1_linesize; - d2_data += d2_linesize; - } - } - - envelope(s, out, plane, (plane + 0) % s->ncomp, column ? offset_x : offset_y); - envelope(s, out, plane, (plane + 1) % s->ncomp, column ? offset_x : offset_y); - envelope(s, out, plane, (plane + 2) % s->ncomp, column ? offset_x : offset_y); +#define AFLAT(name, update_cr, column, mirror) \ +static av_always_inline void name(WaveformContext *s, \ + AVFrame *in, AVFrame *out, \ + int component, int intensity, \ + int offset_y, int offset_x, \ + int unused1, int unused2) \ +{ \ + const int plane = s->desc->comp[component].plane; \ + const int c0_linesize = in->linesize[ plane + 0 ]; \ + const int c1_linesize = in->linesize[(plane + 1) % s->ncomp]; \ + const int c2_linesize = in->linesize[(plane + 2) % s->ncomp]; \ + const int c0_shift_w = s->shift_w[ component + 0 ]; \ + const int c1_shift_w = s->shift_w[(component + 1) % s->ncomp]; \ + const int c2_shift_w = s->shift_w[(component + 2) % s->ncomp]; \ + const int c0_shift_h = s->shift_h[ component + 0 ]; \ + const int c1_shift_h = s->shift_h[(component + 1) % s->ncomp]; \ + const int c2_shift_h = s->shift_h[(component + 2) % s->ncomp]; \ + const int d0_linesize = out->linesize[ plane + 0 ]; \ + const int d1_linesize = out->linesize[(plane + 1) % s->ncomp]; \ + const int d2_linesize = out->linesize[(plane + 2) % s->ncomp]; \ + const int max = 255 - intensity; \ + const int src_h = in->height; \ + const int src_w = in->width; \ + int x, y; \ + \ + if (column) { \ + const int d0_signed_linesize = d0_linesize * (mirror == 1 ? -1 : 1); \ + const int d1_signed_linesize = d1_linesize * (mirror == 1 ? -1 : 1); \ + const int d2_signed_linesize = d2_linesize * (mirror == 1 ? -1 : 1); \ + \ + for (x = 0; x < src_w; x++) { \ + const uint8_t *c0_data = in->data[plane + 0]; \ + const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp]; \ + const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp]; \ + uint8_t *d0_data = out->data[plane] + offset_y * d0_linesize + offset_x; \ + uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x; \ + uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x; \ + uint8_t * const d0_bottom_line = d0_data + d0_linesize * (s->size - 1); \ + uint8_t * const d0 = (mirror ? d0_bottom_line : d0_data); \ + uint8_t * const d1_bottom_line = d1_data + d1_linesize * (s->size - 1); \ + uint8_t * const d1 = (mirror ? d1_bottom_line : d1_data); \ + uint8_t * const d2_bottom_line = d2_data + d2_linesize * (s->size - 1); \ + uint8_t * const d2 = (mirror ? d2_bottom_line : d2_data); \ + \ + for (y = 0; y < src_h; y++) { \ + const int c0 = c0_data[x >> c0_shift_w] + 128; \ + const int c1 = c1_data[x >> c1_shift_w] - 128; \ + const int c2 = c2_data[x >> c2_shift_w] - 128; \ + uint8_t *target; \ + \ + target = d0 + x + d0_signed_linesize * c0; \ + update(target, max, intensity); \ + \ + target = d1 + x + d1_signed_linesize * (c0 + c1); \ + update(target, max, intensity); \ + \ + target = d2 + x + d2_signed_linesize * (c0 + c2); \ + update_cr(target, max, intensity); \ + \ + if (!c0_shift_h || (y & c0_shift_h)) \ + c0_data += c0_linesize; \ + if (!c1_shift_h || (y & c1_shift_h)) \ + c1_data += c1_linesize; \ + if (!c1_shift_h || (y & c1_shift_h)) \ + c2_data += c1_linesize; \ + d0_data += d0_linesize; \ + d1_data += d1_linesize; \ + d2_data += d2_linesize; \ + } \ + } \ + } else { \ + const uint8_t *c0_data = in->data[plane]; \ + const uint8_t *c1_data = in->data[(plane + 1) % s->ncomp]; \ + const uint8_t *c2_data = in->data[(plane + 2) % s->ncomp]; \ + uint8_t *d0_data = out->data[plane] + offset_y * d0_linesize + offset_x; \ + uint8_t *d1_data = out->data[(plane + 1) % s->ncomp] + offset_y * d1_linesize + offset_x; \ + uint8_t *d2_data = out->data[(plane + 2) % s->ncomp] + offset_y * d2_linesize + offset_x; \ + \ + if (mirror) { \ + d0_data += s->size - 1; \ + d1_data += s->size - 1; \ + d2_data += s->size - 1; \ + } \ + \ + for (y = 0; y < src_h; y++) { \ + for (x = 0; x < src_w; x++) { \ + const int c0 = c0_data[x >> c0_shift_w] + 128; \ + const int c1 = c1_data[x >> c1_shift_w] - 128; \ + const int c2 = c2_data[x >> c2_shift_w] - 128; \ + uint8_t *target; \ + \ + if (mirror) { \ + target = d0_data - c0; \ + update(target, max, intensity); \ + target = d1_data - (c0 + c1); \ + update(target, max, intensity); \ + target = d2_data - (c0 + c2); \ + update_cr(target, max, intensity); \ + } else { \ + target = d0_data + c0; \ + update(target, max, intensity); \ + target = d1_data + (c0 + c1); \ + update(target, max, intensity); \ + target = d2_data + (c0 + c2); \ + update_cr(target, max, intensity); \ + } \ + } \ + \ + if (!c0_shift_h || (y & c0_shift_h)) \ + c0_data += c0_linesize; \ + if (!c1_shift_h || (y & c1_shift_h)) \ + c1_data += c1_linesize; \ + if (!c2_shift_h || (y & c2_shift_h)) \ + c2_data += c2_linesize; \ + d0_data += d0_linesize; \ + d1_data += d1_linesize; \ + d2_data += d2_linesize; \ + } \ + } \ + \ + envelope(s, out, plane, (plane + 0) % s->ncomp, column ? offset_x : offset_y); \ + envelope(s, out, plane, (plane + 1) % s->ncomp, column ? offset_x : offset_y); \ + envelope(s, out, plane, (plane + 2) % s->ncomp, column ? offset_x : offset_y); \ } +AFLAT16(aflat16_row, update16, 0, 0) +AFLAT16(aflat16_row_mirror, update16, 0, 1) +AFLAT16(aflat16_column, update16, 1, 0) +AFLAT16(aflat16_column_mirror, update16, 1, 1) +AFLAT16(xflat16_row, update16_cr, 0, 0) +AFLAT16(xflat16_row_mirror, update16_cr, 0, 1) +AFLAT16(xflat16_column, update16_cr, 1, 0) +AFLAT16(xflat16_column_mirror, update16_cr, 1, 1) + +AFLAT(aflat_row, update, 0, 0) +AFLAT(aflat_row_mirror, update, 0, 1) +AFLAT(aflat_column, update, 1, 0) +AFLAT(aflat_column_mirror, update, 1, 1) +AFLAT(xflat_row, update_cr, 0, 0) +AFLAT(xflat_row_mirror, update_cr, 0, 1) +AFLAT(xflat_column, update_cr, 1, 0) +AFLAT(xflat_column_mirror, update_cr, 1, 1) + static av_always_inline void chroma16(WaveformContext *s, AVFrame *in, AVFrame *out, int component, int intensity, @@ -1838,7 +1880,6 @@ static av_always_inline void acolor(WaveformContext *s, } static const uint8_t black_yuva_color[4] = { 0, 127, 127, 255 }; -static const uint8_t green_yuva_color[4] = { 255, 0, 0, 255 }; static const uint8_t black_gbrp_color[4] = { 0, 0, 0, 255 }; static const GraticuleLines aflat_digital8[] = { @@ -2299,7 +2340,7 @@ static void graticule_none(WaveformContext *s, AVFrame *out) { } -static void graticule_green_row(WaveformContext *s, AVFrame *out) +static void graticule_row(WaveformContext *s, AVFrame *out) { const int step = (s->flags & 2) + 1; const float o1 = s->opacity; @@ -2313,7 +2354,7 @@ static void graticule_green_row(WaveformContext *s, AVFrame *out) k++; for (p = 0; p < s->ncomp; p++) { - const int v = green_yuva_color[p]; + const int v = s->grat_yuva_color[p]; for (l = 0; l < s->nb_glines; l++) { const uint16_t pos = s->glines[l].line[c].pos; int x = offset_x + (s->mirror ? s->size - 1 - pos : pos); @@ -2331,7 +2372,7 @@ static void graticule_green_row(WaveformContext *s, AVFrame *out) if (x < 0) x = 4; - draw_vtext(out, x, offset_y + 2, o1, o2, name, green_yuva_color); + draw_vtext(out, x, offset_y + 2, o1, o2, name, s->grat_yuva_color); } offset_x += s->size * (s->display == STACK); @@ -2339,12 +2380,12 @@ static void graticule_green_row(WaveformContext *s, AVFrame *out) } } -static void graticule16_green_row(WaveformContext *s, AVFrame *out) +static void graticule16_row(WaveformContext *s, AVFrame *out) { const int step = (s->flags & 2) + 1; const float o1 = s->opacity; const float o2 = 1. - o1; - const int mult = s->size / 256; + const int mult = s->max / 256; const int height = s->display == PARADE ? out->height / s->acomp : out->height; int k = 0, c, p, l, offset_x = 0, offset_y = 0; @@ -2354,7 +2395,7 @@ static void graticule16_green_row(WaveformContext *s, AVFrame *out) k++; for (p = 0; p < s->ncomp; p++) { - const int v = green_yuva_color[p] * mult; + const int v = s->grat_yuva_color[p] * mult; for (l = 0; l < s->nb_glines ; l++) { const uint16_t pos = s->glines[l].line[c].pos; int x = offset_x + (s->mirror ? s->size - 1 - pos : pos); @@ -2372,7 +2413,7 @@ static void graticule16_green_row(WaveformContext *s, AVFrame *out) if (x < 0) x = 4; - draw_vtext16(out, x, offset_y + 2, mult, o1, o2, name, green_yuva_color); + draw_vtext16(out, x, offset_y + 2, mult, o1, o2, name, s->grat_yuva_color); } offset_x += s->size * (s->display == STACK); @@ -2380,7 +2421,7 @@ static void graticule16_green_row(WaveformContext *s, AVFrame *out) } } -static void graticule_green_column(WaveformContext *s, AVFrame *out) +static void graticule_column(WaveformContext *s, AVFrame *out) { const int step = (s->flags & 2) + 1; const float o1 = s->opacity; @@ -2394,7 +2435,7 @@ static void graticule_green_column(WaveformContext *s, AVFrame *out) k++; for (p = 0; p < s->ncomp; p++) { - const int v = green_yuva_color[p]; + const int v = s->grat_yuva_color[p]; for (l = 0; l < s->nb_glines ; l++) { const uint16_t pos = s->glines[l].line[c].pos; int y = offset_y + (s->mirror ? s->size - 1 - pos : pos); @@ -2412,7 +2453,7 @@ static void graticule_green_column(WaveformContext *s, AVFrame *out) if (y < 0) y = 4; - draw_htext(out, 2 + offset_x, y, o1, o2, name, green_yuva_color); + draw_htext(out, 2 + offset_x, y, o1, o2, name, s->grat_yuva_color); } offset_y += s->size * (s->display == STACK); @@ -2420,12 +2461,12 @@ static void graticule_green_column(WaveformContext *s, AVFrame *out) } } -static void graticule16_green_column(WaveformContext *s, AVFrame *out) +static void graticule16_column(WaveformContext *s, AVFrame *out) { const int step = (s->flags & 2) + 1; const float o1 = s->opacity; const float o2 = 1. - o1; - const int mult = s->size / 256; + const int mult = s->max / 256; const int width = s->display == PARADE ? out->width / s->acomp : out->width; int k = 0, c, p, l, offset_x = 0, offset_y = 0; @@ -2435,7 +2476,7 @@ static void graticule16_green_column(WaveformContext *s, AVFrame *out) k++; for (p = 0; p < s->ncomp; p++) { - const int v = green_yuva_color[p] * mult; + const int v = s->grat_yuva_color[p] * mult; for (l = 0; l < s->nb_glines ; l++) { const uint16_t pos = s->glines[l].line[c].pos; int y = offset_y + (s->mirror ? s->size - 1 - pos : pos); @@ -2453,7 +2494,7 @@ static void graticule16_green_column(WaveformContext *s, AVFrame *out) if (y < 0) y = 4; - draw_htext16(out, 2 + offset_x, y, mult, o1, o2, name, green_yuva_color); + draw_htext16(out, 2 + offset_x, y, mult, o1, o2, name, s->grat_yuva_color); } offset_y += s->size * (s->display == STACK); @@ -2480,6 +2521,7 @@ static int config_input(AVFilterLink *inlink) s->graticulef = graticule_none; switch (s->filter) { + case XFLAT: case AFLAT: s->size = 256 * 2; break; case FLAT: s->size = 256 * 3; break; default: s->size = 256; break; @@ -2503,14 +2545,14 @@ static int config_input(AVFilterLink *inlink) case 0x1011: case 0x0111: case 0x0011: s->waveform = flat16; break; - case 0x1102: - case 0x1002: - case 0x0102: - case 0x0002: s->waveform = aflat; break; - case 0x1112: - case 0x1012: - case 0x0112: - case 0x0012: s->waveform = aflat16; break; + case 0x1102: s->waveform = aflat_column_mirror; break; + case 0x1002: s->waveform = aflat_row_mirror; break; + case 0x0102: s->waveform = aflat_column; break; + case 0x0002: s->waveform = aflat_row; break; + case 0x1112: s->waveform = aflat16_column_mirror; break; + case 0x1012: s->waveform = aflat16_row_mirror; break; + case 0x0112: s->waveform = aflat16_column; break; + case 0x0012: s->waveform = aflat16_row; break; case 0x1103: case 0x1003: case 0x0103: @@ -2535,19 +2577,32 @@ static int config_input(AVFilterLink *inlink) case 0x1015: case 0x0115: case 0x0015: s->waveform = acolor16; break; + case 0x1106: s->waveform = xflat_column_mirror; break; + case 0x1006: s->waveform = xflat_row_mirror; break; + case 0x0106: s->waveform = xflat_column; break; + case 0x0006: s->waveform = xflat_row; break; + case 0x1116: s->waveform = xflat16_column_mirror; break; + case 0x1016: s->waveform = xflat16_row_mirror; break; + case 0x0116: s->waveform = xflat16_column; break; + case 0x0016: s->waveform = xflat16_row; break; } + s->grat_yuva_color[0] = 255; + s->grat_yuva_color[2] = s->graticule == 2 ? 255 : 0; + s->grat_yuva_color[3] = 255; + switch (s->filter) { case LOWPASS: case COLOR: case ACOLOR: case CHROMA: case AFLAT: + case XFLAT: case FLAT: if (s->graticule && s->mode == 1) - s->graticulef = s->bits > 8 ? graticule16_green_column : graticule_green_column; + s->graticulef = s->bits > 8 ? graticule16_column : graticule_column; else if (s->graticule && s->mode == 0) - s->graticulef = s->bits > 8 ? graticule16_green_row : graticule_green_row; + s->graticulef = s->bits > 8 ? graticule16_row : graticule_row; break; } @@ -2610,6 +2665,7 @@ static int config_input(AVFilterLink *inlink) break; } break; + case XFLAT: case AFLAT: switch (s->scale) { case DIGITAL: diff --git a/libavfilter/vf_yadif.c b/libavfilter/vf_yadif.c index 694ac44999ff1..f58d8ac2bce32 100644 --- a/libavfilter/vf_yadif.c +++ b/libavfilter/vf_yadif.c @@ -123,18 +123,20 @@ static void filter_edges(void *dst1, void *prev1, void *cur1, void *next1, uint8_t *prev2 = parity ? prev : cur ; uint8_t *next2 = parity ? cur : next; + const int edge = MAX_ALIGN - 1; + /* Only edge pixels need to be processed here. A constant value of false * for is_not_edge should let the compiler ignore the whole branch. */ FILTER(0, 3, 0) - dst = (uint8_t*)dst1 + w - (MAX_ALIGN-1); - prev = (uint8_t*)prev1 + w - (MAX_ALIGN-1); - cur = (uint8_t*)cur1 + w - (MAX_ALIGN-1); - next = (uint8_t*)next1 + w - (MAX_ALIGN-1); + dst = (uint8_t*)dst1 + w - edge; + prev = (uint8_t*)prev1 + w - edge; + cur = (uint8_t*)cur1 + w - edge; + next = (uint8_t*)next1 + w - edge; prev2 = (uint8_t*)(parity ? prev : cur); next2 = (uint8_t*)(parity ? cur : next); - FILTER(w - (MAX_ALIGN-1), w - 3, 1) + FILTER(w - edge, w - 3, 1) FILTER(w - 3, w, 0) } @@ -167,19 +169,22 @@ static void filter_edges_16bit(void *dst1, void *prev1, void *cur1, void *next1, int x; uint16_t *prev2 = parity ? prev : cur ; uint16_t *next2 = parity ? cur : next; + + const int edge = MAX_ALIGN / 2 - 1; + mrefs /= 2; prefs /= 2; FILTER(0, 3, 0) - dst = (uint16_t*)dst1 + w - (MAX_ALIGN/2-1); - prev = (uint16_t*)prev1 + w - (MAX_ALIGN/2-1); - cur = (uint16_t*)cur1 + w - (MAX_ALIGN/2-1); - next = (uint16_t*)next1 + w - (MAX_ALIGN/2-1); + dst = (uint16_t*)dst1 + w - edge; + prev = (uint16_t*)prev1 + w - edge; + cur = (uint16_t*)cur1 + w - edge; + next = (uint16_t*)next1 + w - edge; prev2 = (uint16_t*)(parity ? prev : cur); next2 = (uint16_t*)(parity ? cur : next); - FILTER(w - (MAX_ALIGN/2-1), w - 3, 1) + FILTER(w - edge, w - 3, 1) FILTER(w - 3, w, 0) } @@ -193,6 +198,7 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) int slice_start = (td->h * jobnr ) / nb_jobs; int slice_end = (td->h * (jobnr+1)) / nb_jobs; int y; + int edge = 3 + MAX_ALIGN / df - 1; /* filtering reads 3 pixels to the left/right; to avoid invalid reads, * we need to call the c variant which avoids this for border pixels @@ -205,7 +211,7 @@ static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) uint8_t *dst = &td->frame->data[td->plane][y * td->frame->linesize[td->plane]]; int mode = y == 1 || y + 2 == td->h ? 2 : s->mode; s->filter_line(dst + pix_3, prev + pix_3, cur + pix_3, - next + pix_3, td->w - (3 + MAX_ALIGN/df-1), + next + pix_3, td->w - edge, y + 1 < td->h ? refs : -refs, y ? -refs : refs, td->parity ^ td->tff, mode); diff --git a/libavfilter/vf_zscale.c b/libavfilter/vf_zscale.c index c303dd4d63dc7..6e1d36cb4cf23 100644 --- a/libavfilter/vf_zscale.c +++ b/libavfilter/vf_zscale.c @@ -321,7 +321,7 @@ static int print_zimg_error(AVFilterContext *ctx) av_log(ctx, AV_LOG_ERROR, "code %d: %s\n", err_code, err_msg); - return err_code; + return AVERROR_EXTERNAL; } static int convert_chroma_location(enum AVChromaLocation chroma_location) @@ -353,16 +353,26 @@ static int convert_matrix(enum AVColorSpace colorspace) return ZIMG_MATRIX_709; case AVCOL_SPC_UNSPECIFIED: return ZIMG_MATRIX_UNSPECIFIED; + case AVCOL_SPC_FCC: + return ZIMG_MATRIX_FCC; case AVCOL_SPC_BT470BG: return ZIMG_MATRIX_470BG; case AVCOL_SPC_SMPTE170M: return ZIMG_MATRIX_170M; + case AVCOL_SPC_SMPTE240M: + return ZIMG_MATRIX_240M; case AVCOL_SPC_YCGCO: return ZIMG_MATRIX_YCGCO; case AVCOL_SPC_BT2020_NCL: return ZIMG_MATRIX_2020_NCL; case AVCOL_SPC_BT2020_CL: return ZIMG_MATRIX_2020_CL; + case AVCOL_SPC_CHROMA_DERIVED_NCL: + return ZIMG_MATRIX_CHROMATICITY_DERIVED_NCL; + case AVCOL_SPC_CHROMA_DERIVED_CL: + return ZIMG_MATRIX_CHROMATICITY_DERIVED_CL; + case AVCOL_SPC_ICTCP: + return ZIMG_MATRIX_ICTCP; } return ZIMG_MATRIX_UNSPECIFIED; } @@ -374,10 +384,22 @@ static int convert_trc(enum AVColorTransferCharacteristic color_trc) return ZIMG_TRANSFER_UNSPECIFIED; case AVCOL_TRC_BT709: return ZIMG_TRANSFER_709; + case AVCOL_TRC_GAMMA22: + return ZIMG_TRANSFER_470_M; + case AVCOL_TRC_GAMMA28: + return ZIMG_TRANSFER_470_BG; case AVCOL_TRC_SMPTE170M: return ZIMG_TRANSFER_601; + case AVCOL_TRC_SMPTE240M: + return ZIMG_TRANSFER_240M; case AVCOL_TRC_LINEAR: return ZIMG_TRANSFER_LINEAR; + case AVCOL_TRC_LOG: + return ZIMG_TRANSFER_LOG_100; + case AVCOL_TRC_LOG_SQRT: + return ZIMG_TRANSFER_LOG_316; + case AVCOL_TRC_IEC61966_2_4: + return ZIMG_TRANSFER_IEC_61966_2_4; case AVCOL_TRC_BT2020_10: return ZIMG_TRANSFER_2020_10; case AVCOL_TRC_BT2020_12: @@ -399,14 +421,26 @@ static int convert_primaries(enum AVColorPrimaries color_primaries) return ZIMG_PRIMARIES_UNSPECIFIED; case AVCOL_PRI_BT709: return ZIMG_PRIMARIES_709; + case AVCOL_PRI_BT470M: + return ZIMG_PRIMARIES_470_M; + case AVCOL_PRI_BT470BG: + return ZIMG_PRIMARIES_470_BG; case AVCOL_PRI_SMPTE170M: return ZIMG_PRIMARIES_170M; case AVCOL_PRI_SMPTE240M: return ZIMG_PRIMARIES_240M; + case AVCOL_PRI_FILM: + return ZIMG_PRIMARIES_FILM; case AVCOL_PRI_BT2020: return ZIMG_PRIMARIES_2020; + case AVCOL_PRI_SMPTE428: + return ZIMG_PRIMARIES_ST428; + case AVCOL_PRI_SMPTE431: + return ZIMG_PRIMARIES_ST431_2; case AVCOL_PRI_SMPTE432: return ZIMG_PRIMARIES_ST432_1; + case AVCOL_PRI_JEDEC_P22: + return ZIMG_PRIMARIES_EBU3213_E; } return ZIMG_PRIMARIES_UNSPECIFIED; } @@ -581,7 +615,7 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) s->alpha_dst_format.width = out->width; s->alpha_dst_format.height = out->height; s->alpha_dst_format.depth = odesc->comp[0].depth; - s->alpha_dst_format.pixel_type = (desc->flags & AV_PIX_FMT_FLAG_FLOAT) ? ZIMG_PIXEL_FLOAT : odesc->comp[0].depth > 8 ? ZIMG_PIXEL_WORD : ZIMG_PIXEL_BYTE; + s->alpha_dst_format.pixel_type = (odesc->flags & AV_PIX_FMT_FLAG_FLOAT) ? ZIMG_PIXEL_FLOAT : odesc->comp[0].depth > 8 ? ZIMG_PIXEL_WORD : ZIMG_PIXEL_BYTE; s->alpha_dst_format.color_family = ZIMG_COLOR_GREY; zimg_filter_graph_free(s->alpha_graph); @@ -624,7 +658,7 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) ret = zimg_filter_graph_process(s->graph, &src_buf, &dst_buf, s->tmp, 0, 0, 0, 0); if (ret) { - print_zimg_error(link->dst); + ret = print_zimg_error(link->dst); goto fail; } @@ -639,7 +673,7 @@ static int filter_frame(AVFilterLink *link, AVFrame *in) ret = zimg_filter_graph_process(s->alpha_graph, &src_buf, &dst_buf, s->tmp, 0, 0, 0, 0); if (ret) { - print_zimg_error(link->dst); + ret = print_zimg_error(link->dst); goto fail; } } else if (odesc->flags & AV_PIX_FMT_FLAG_ALPHA) { @@ -673,6 +707,7 @@ static void uninit(AVFilterContext *ctx) ZScaleContext *s = ctx->priv; zimg_filter_graph_free(s->graph); + zimg_filter_graph_free(s->alpha_graph); av_freep(&s->tmp); s->tmp_size = 0; } @@ -734,8 +769,8 @@ static const AVOption zscale_options[] = { { "unknown", 0, 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, FLAGS, "range" }, { "tv", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_RANGE_LIMITED}, 0, 0, FLAGS, "range" }, { "pc", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_RANGE_FULL}, 0, 0, FLAGS, "range" }, - { "primaries", "set color primaries", OFFSET(primaries), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_PRIMARIES_ST432_1, FLAGS, "primaries" }, - { "p", "set color primaries", OFFSET(primaries), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_PRIMARIES_ST432_1, FLAGS, "primaries" }, + { "primaries", "set color primaries", OFFSET(primaries), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "primaries" }, + { "p", "set color primaries", OFFSET(primaries), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "primaries" }, { "input", 0, 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, FLAGS, "primaries" }, { "709", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_709}, 0, 0, FLAGS, "primaries" }, { "unspecified", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_UNSPECIFIED}, 0, 0, FLAGS, "primaries" }, @@ -744,12 +779,18 @@ static const AVOption zscale_options[] = { { "2020", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_2020}, 0, 0, FLAGS, "primaries" }, { "unknown", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_UNSPECIFIED}, 0, 0, FLAGS, "primaries" }, { "bt709", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_709}, 0, 0, FLAGS, "primaries" }, + { "bt470m", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_470_M}, 0, 0, FLAGS, "primaries" }, + { "bt470bg", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_470_BG}, 0, 0, FLAGS, "primaries" }, { "smpte170m", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_170M}, 0, 0, FLAGS, "primaries" }, { "smpte240m", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_240M}, 0, 0, FLAGS, "primaries" }, + { "film", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_FILM}, 0, 0, FLAGS, "primaries" }, { "bt2020", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_2020}, 0, 0, FLAGS, "primaries" }, + { "smpte428", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_ST428}, 0, 0, FLAGS, "primaries" }, + { "smpte431", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_ST431_2}, 0, 0, FLAGS, "primaries" }, { "smpte432", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_ST432_1}, 0, 0, FLAGS, "primaries" }, - { "transfer", "set transfer characteristic", OFFSET(trc), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_TRANSFER_ARIB_B67, FLAGS, "transfer" }, - { "t", "set transfer characteristic", OFFSET(trc), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_TRANSFER_ARIB_B67, FLAGS, "transfer" }, + { "jedec-p22", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_PRIMARIES_EBU3213_E}, 0, 0, FLAGS, "primaries" }, + { "transfer", "set transfer characteristic", OFFSET(trc), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "transfer" }, + { "t", "set transfer characteristic", OFFSET(trc), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "transfer" }, { "input", 0, 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, FLAGS, "transfer" }, { "709", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_709}, 0, 0, FLAGS, "transfer" }, { "unspecified", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_UNSPECIFIED}, 0, 0, FLAGS, "transfer" }, @@ -758,16 +799,21 @@ static const AVOption zscale_options[] = { { "2020_10", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_2020_10}, 0, 0, FLAGS, "transfer" }, { "2020_12", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_2020_12}, 0, 0, FLAGS, "transfer" }, { "unknown", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_UNSPECIFIED}, 0, 0, FLAGS, "transfer" }, + { "bt470m", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_470_M}, 0, 0, FLAGS, "transfer" }, + { "bt470bg", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_470_BG}, 0, 0, FLAGS, "transfer" }, { "smpte170m", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_601}, 0, 0, FLAGS, "transfer" }, { "bt709", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_709}, 0, 0, FLAGS, "transfer" }, { "linear", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_LINEAR}, 0, 0, FLAGS, "transfer" }, + { "log100", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_LOG_100}, 0, 0, FLAGS, "transfer" }, + { "log316", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_LOG_316}, 0, 0, FLAGS, "transfer" }, { "bt2020-10", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_2020_10}, 0, 0, FLAGS, "transfer" }, { "bt2020-12", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_2020_12}, 0, 0, FLAGS, "transfer" }, { "smpte2084", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_ST2084}, 0, 0, FLAGS, "transfer" }, + { "iec61966-2-4", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_IEC_61966_2_4},0, 0, FLAGS, "transfer" }, { "iec61966-2-1", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_IEC_61966_2_1},0, 0, FLAGS, "transfer" }, { "arib-std-b67", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_TRANSFER_ARIB_B67}, 0, 0, FLAGS, "transfer" }, - { "matrix", "set colorspace matrix", OFFSET(colorspace), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_MATRIX_2020_CL, FLAGS, "matrix" }, - { "m", "set colorspace matrix", OFFSET(colorspace), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_MATRIX_2020_CL, FLAGS, "matrix" }, + { "matrix", "set colorspace matrix", OFFSET(colorspace), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "matrix" }, + { "m", "set colorspace matrix", OFFSET(colorspace), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "matrix" }, { "input", 0, 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, FLAGS, "matrix" }, { "709", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_709}, 0, 0, FLAGS, "matrix" }, { "unspecified", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_UNSPECIFIED}, 0, 0, FLAGS, "matrix" }, @@ -776,21 +822,27 @@ static const AVOption zscale_options[] = { { "2020_ncl", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_2020_NCL}, 0, 0, FLAGS, "matrix" }, { "2020_cl", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_2020_CL}, 0, 0, FLAGS, "matrix" }, { "unknown", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_UNSPECIFIED}, 0, 0, FLAGS, "matrix" }, + { "gbr", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_RGB}, 0, 0, FLAGS, "matrix" }, { "bt709", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_709}, 0, 0, FLAGS, "matrix" }, + { "fcc", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_FCC}, 0, 0, FLAGS, "matrix" }, { "bt470bg", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_470BG}, 0, 0, FLAGS, "matrix" }, { "smpte170m", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_170M}, 0, 0, FLAGS, "matrix" }, + { "smpte2400m", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_240M}, 0, 0, FLAGS, "matrix" }, { "ycgco", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_YCGCO}, 0, 0, FLAGS, "matrix" }, { "bt2020nc", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_2020_NCL}, 0, 0, FLAGS, "matrix" }, { "bt2020c", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_2020_CL}, 0, 0, FLAGS, "matrix" }, + { "chroma-derived-nc",0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_CHROMATICITY_DERIVED_NCL}, 0, 0, FLAGS, "matrix" }, + { "chroma-derived-c", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_CHROMATICITY_DERIVED_CL}, 0, 0, FLAGS, "matrix" }, + { "ictcp", 0, 0, AV_OPT_TYPE_CONST, {.i64 = ZIMG_MATRIX_ICTCP}, 0, 0, FLAGS, "matrix" }, { "in_range", "set input color range", OFFSET(range_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_RANGE_FULL, FLAGS, "range" }, { "rangein", "set input color range", OFFSET(range_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_RANGE_FULL, FLAGS, "range" }, { "rin", "set input color range", OFFSET(range_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_RANGE_FULL, FLAGS, "range" }, - { "primariesin", "set input color primaries", OFFSET(primaries_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_PRIMARIES_ST432_1, FLAGS, "primaries" }, - { "pin", "set input color primaries", OFFSET(primaries_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_PRIMARIES_ST432_1, FLAGS, "primaries" }, - { "transferin", "set input transfer characteristic", OFFSET(trc_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_TRANSFER_ARIB_B67, FLAGS, "transfer" }, - { "tin", "set input transfer characteristic", OFFSET(trc_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_TRANSFER_ARIB_B67, FLAGS, "transfer" }, - { "matrixin", "set input colorspace matrix", OFFSET(colorspace_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_MATRIX_2020_CL, FLAGS, "matrix" }, - { "min", "set input colorspace matrix", OFFSET(colorspace_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_MATRIX_2020_CL, FLAGS, "matrix" }, + { "primariesin", "set input color primaries", OFFSET(primaries_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "primaries" }, + { "pin", "set input color primaries", OFFSET(primaries_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "primaries" }, + { "transferin", "set input transfer characteristic", OFFSET(trc_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "transfer" }, + { "tin", "set input transfer characteristic", OFFSET(trc_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "transfer" }, + { "matrixin", "set input colorspace matrix", OFFSET(colorspace_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "matrix" }, + { "min", "set input colorspace matrix", OFFSET(colorspace_in), AV_OPT_TYPE_INT, {.i64 = -1}, -1, INT_MAX, FLAGS, "matrix" }, { "chromal", "set output chroma location", OFFSET(chromal), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_CHROMA_BOTTOM, FLAGS, "chroma" }, { "c", "set output chroma location", OFFSET(chromal), AV_OPT_TYPE_INT, {.i64 = -1}, -1, ZIMG_CHROMA_BOTTOM, FLAGS, "chroma" }, { "input", 0, 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, FLAGS, "chroma" }, diff --git a/libavfilter/video.c b/libavfilter/video.c index 6f9020b9fe0e2..7a8e587798839 100644 --- a/libavfilter/video.c +++ b/libavfilter/video.c @@ -43,6 +43,7 @@ AVFrame *ff_null_get_video_buffer(AVFilterLink *link, int w, int h) AVFrame *ff_default_get_video_buffer(AVFilterLink *link, int w, int h) { + AVFrame *frame = NULL; int pool_width = 0; int pool_height = 0; int pool_align = 0; @@ -86,7 +87,13 @@ AVFrame *ff_default_get_video_buffer(AVFilterLink *link, int w, int h) } } - return ff_frame_pool_get(link->frame_pool); + frame = ff_frame_pool_get(link->frame_pool); + if (!frame) + return NULL; + + frame->sample_aspect_ratio = link->sample_aspect_ratio; + + return frame; } AVFrame *ff_get_video_buffer(AVFilterLink *link, int w, int h) diff --git a/libavfilter/vsrc_testsrc.c b/libavfilter/vsrc_testsrc.c index fe0d50aa41a6a..a790974d14213 100644 --- a/libavfilter/vsrc_testsrc.c +++ b/libavfilter/vsrc_testsrc.c @@ -857,8 +857,8 @@ static void test2_fill_picture(AVFilterContext *ctx, AVFrame *frame) uint8_t alpha[256]; r = s->pts; - for (y = ymin; y < ymax - 15; y += 16) { - for (x = xmin; x < xmax - 15; x += 16) { + for (y = ymin; y + 15 < ymax; y += 16) { + for (x = xmin; x + 15 < xmax; x += 16) { if ((x ^ y) & 16) continue; for (i = 0; i < 256; i++) { diff --git a/libavfilter/x86/Makefile b/libavfilter/x86/Makefile index 34316258839cd..4d4c5e503a98b 100644 --- a/libavfilter/x86/Makefile +++ b/libavfilter/x86/Makefile @@ -5,6 +5,8 @@ OBJS-$(CONFIG_COLORSPACE_FILTER) += x86/colorspacedsp_init.o OBJS-$(CONFIG_EQ_FILTER) += x86/vf_eq.o OBJS-$(CONFIG_FSPP_FILTER) += x86/vf_fspp_init.o OBJS-$(CONFIG_GRADFUN_FILTER) += x86/vf_gradfun_init.o +OBJS-$(CONFIG_FRAMERATE_FILTER) += x86/vf_framerate_init.o +OBJS-$(CONFIG_HFLIP_FILTER) += x86/vf_hflip_init.o OBJS-$(CONFIG_HQDN3D_FILTER) += x86/vf_hqdn3d_init.o OBJS-$(CONFIG_IDET_FILTER) += x86/vf_idet_init.o OBJS-$(CONFIG_INTERLACE_FILTER) += x86/vf_interlace_init.o @@ -20,6 +22,7 @@ OBJS-$(CONFIG_SPP_FILTER) += x86/vf_spp.o OBJS-$(CONFIG_SSIM_FILTER) += x86/vf_ssim_init.o OBJS-$(CONFIG_STEREO3D_FILTER) += x86/vf_stereo3d_init.o OBJS-$(CONFIG_TBLEND_FILTER) += x86/vf_blend_init.o +OBJS-$(CONFIG_THRESHOLD_FILTER) += x86/vf_threshold_init.o OBJS-$(CONFIG_TINTERLACE_FILTER) += x86/vf_tinterlace_init.o OBJS-$(CONFIG_VOLUME_FILTER) += x86/af_volume_init.o OBJS-$(CONFIG_W3FDIF_FILTER) += x86/vf_w3fdif_init.o @@ -29,8 +32,10 @@ X86ASM-OBJS-$(CONFIG_AFIR_FILTER) += x86/af_afir.o X86ASM-OBJS-$(CONFIG_BLEND_FILTER) += x86/vf_blend.o X86ASM-OBJS-$(CONFIG_BWDIF_FILTER) += x86/vf_bwdif.o X86ASM-OBJS-$(CONFIG_COLORSPACE_FILTER) += x86/colorspacedsp.o +X86ASM-OBJS-$(CONFIG_FRAMERATE_FILTER) += x86/vf_framerate.o X86ASM-OBJS-$(CONFIG_FSPP_FILTER) += x86/vf_fspp.o X86ASM-OBJS-$(CONFIG_GRADFUN_FILTER) += x86/vf_gradfun.o +X86ASM-OBJS-$(CONFIG_HFLIP_FILTER) += x86/vf_hflip.o X86ASM-OBJS-$(CONFIG_HQDN3D_FILTER) += x86/vf_hqdn3d.o X86ASM-OBJS-$(CONFIG_IDET_FILTER) += x86/vf_idet.o X86ASM-OBJS-$(CONFIG_INTERLACE_FILTER) += x86/vf_interlace.o @@ -46,6 +51,7 @@ X86ASM-OBJS-$(CONFIG_SHOWCQT_FILTER) += x86/avf_showcqt.o X86ASM-OBJS-$(CONFIG_SSIM_FILTER) += x86/vf_ssim.o X86ASM-OBJS-$(CONFIG_STEREO3D_FILTER) += x86/vf_stereo3d.o X86ASM-OBJS-$(CONFIG_TBLEND_FILTER) += x86/vf_blend.o +X86ASM-OBJS-$(CONFIG_THRESHOLD_FILTER) += x86/vf_threshold.o X86ASM-OBJS-$(CONFIG_TINTERLACE_FILTER) += x86/vf_interlace.o X86ASM-OBJS-$(CONFIG_VOLUME_FILTER) += x86/af_volume.o X86ASM-OBJS-$(CONFIG_W3FDIF_FILTER) += x86/vf_w3fdif.o diff --git a/libavfilter/x86/vf_blend.asm b/libavfilter/x86/vf_blend.asm index 4916aaf251e01..251bbb5a1206f 100644 --- a/libavfilter/x86/vf_blend.asm +++ b/libavfilter/x86/vf_blend.asm @@ -2,6 +2,8 @@ ;* x86-optimized functions for blend filter ;* ;* Copyright (C) 2015 Paul B Mahol +;* Copyright (C) 2018 Henrik Gramner +;* Copyright (C) 2018 Jokyo Images ;* ;* This file is part of FFmpeg. ;* @@ -25,6 +27,8 @@ SECTION_RODATA ps_255: times 4 dd 255.0 +pd_32768 : times 4 dd 32768 +pd_65535 : times 4 dd 65535 pw_1: times 8 dw 1 pw_128: times 8 dw 128 pw_255: times 8 dw 255 @@ -34,10 +38,13 @@ pb_255: times 16 db 255 SECTION .text -%macro BLEND_INIT 2 +%macro BLEND_INIT 2-3 %if ARCH_X86_64 cglobal blend_%1, 6, 9, %2, top, top_linesize, bottom, bottom_linesize, dst, dst_linesize, width, end, x mov widthd, dword widthm + %if %0 == 3; is 16 bit + add widthq, widthq ; doesn't compile on x86_32 + %endif %else cglobal blend_%1, 5, 7, %2, top, top_linesize, bottom, bottom_linesize, dst, end, x %define dst_linesizeq r5mp @@ -59,8 +66,8 @@ cglobal blend_%1, 5, 7, %2, top, top_linesize, bottom, bottom_linesize, dst, end REP_RET %endmacro -%macro BLEND_SIMPLE 2 -BLEND_INIT %1, 2 +%macro BLEND_SIMPLE 2-3 +BLEND_INIT %1, 2, %3 .nextrow: mov xq, widthq @@ -74,39 +81,43 @@ BLEND_INIT %1, 2 BLEND_END %endmacro -INIT_XMM sse2 -BLEND_SIMPLE xor, xor -BLEND_SIMPLE or, or -BLEND_SIMPLE and, and -BLEND_SIMPLE addition, addusb -BLEND_SIMPLE subtract, subusb -BLEND_SIMPLE darken, minub -BLEND_SIMPLE lighten, maxub - -BLEND_INIT grainextract, 4 - pxor m2, m2 - mova m3, [pw_128] +; %1 name , %2 src (b or w), %3 inter (w or d), %4 (1 if 16bit, not set if 8 bit) +%macro GRAINEXTRACT 3-4 +BLEND_INIT %1, 6, %4 + pxor m4, m4 +%if %0 == 4 ; 16 bit + VBROADCASTI128 m5, [pd_32768] +%else + VBROADCASTI128 m5, [pw_128] +%endif .nextrow: mov xq, widthq - .loop: - movh m0, [topq + xq] - movh m1, [bottomq + xq] - punpcklbw m0, m2 - punpcklbw m1, m2 - paddw m0, m3 - psubw m0, m1 - packuswb m0, m0 - movh [dstq + xq], m0 - add xq, mmsize / 2 + movu m1, [topq + xq] + movu m3, [bottomq + xq] + + punpckl%2%3 m0, m1, m4 + punpckh%2%3 m1, m4 + punpckl%2%3 m2, m3, m4 + punpckh%2%3 m3, m4 + + padd%3 m0, m5 + padd%3 m1, m5 + psub%3 m0, m2 + psub%3 m1, m3 + + packus%3%2 m0, m1 + + mova [dstq + xq], m0 + add xq, mmsize jl .loop BLEND_END +%endmacro %macro MULTIPLY 3 ; a, b, pw_1 pmullw %1, %2 ; xxxxxxxx a * b paddw %1, %3 - mova %2, %1 - psrlw %2, 8 + psrlw %2, %1, 8 paddw %1, %2 psrlw %1, 8 ; 00xx00xx a * b / 255 %endmacro @@ -118,92 +129,118 @@ BLEND_END pxor %1, %4 ; 00xx00xx 255 - x / 255 %endmacro -BLEND_INIT multiply, 4 - pxor m2, m2 - mova m3, [pw_1] +%macro BLEND_MULTIPLY 0 +BLEND_INIT multiply, 6 + pxor m4, m4 + VBROADCASTI128 m5, [pw_1] .nextrow: mov xq, widthq .loop: - ; word - ; |--| - movh m0, [topq + xq] ; 0000xxxx - movh m1, [bottomq + xq] - punpcklbw m0, m2 ; 00xx00xx - punpcklbw m1, m2 - - MULTIPLY m0, m1, m3 - - packuswb m0, m0 ; 0000xxxx - movh [dstq + xq], m0 - add xq, mmsize / 2 - + movu m1, [topq + xq] + movu m3, [bottomq + xq] + punpcklbw m0, m1, m4 + punpckhbw m1, m4 + punpcklbw m2, m3, m4 + punpckhbw m3, m4 + + MULTIPLY m0, m2, m5 + MULTIPLY m1, m3, m5 + + packuswb m0, m1 + mova [dstq + xq], m0 + add xq, mmsize jl .loop BLEND_END +%endmacro -BLEND_INIT screen, 5 - pxor m2, m2 - mova m3, [pw_1] - mova m4, [pw_255] +%macro BLEND_SCREEN 0 +BLEND_INIT screen, 7 + pxor m4, m4 + + VBROADCASTI128 m5, [pw_1] + VBROADCASTI128 m6, [pw_255] .nextrow: mov xq, widthq .loop: - movh m0, [topq + xq] ; 0000xxxx - movh m1, [bottomq + xq] - punpcklbw m0, m2 ; 00xx00xx - punpcklbw m1, m2 - - SCREEN m0, m1, m3, m4 - - packuswb m0, m0 ; 0000xxxx - movh [dstq + xq], m0 - add xq, mmsize / 2 - + movu m1, [topq + xq] + movu m3, [bottomq + xq] + punpcklbw m0, m1, m4 + punpckhbw m1, m4 + punpcklbw m2, m3, m4 + punpckhbw m3, m4 + + SCREEN m0, m2, m5, m6 + SCREEN m1, m3, m5, m6 + + packuswb m0, m1 + mova [dstq + xq], m0 + add xq, mmsize jl .loop BLEND_END +%endmacro + +;%1 name, %2 (b or w), %3 (set if 16 bit) +%macro AVERAGE 2-3 +BLEND_INIT %1, 3, %3 + pcmpeqb m2, m2 -BLEND_INIT average, 3 - pxor m2, m2 .nextrow: mov xq, widthq - .loop: - movh m0, [topq + xq] - movh m1, [bottomq + xq] - punpcklbw m0, m2 - punpcklbw m1, m2 - paddw m0, m1 - psrlw m0, 1 - packuswb m0, m0 - movh [dstq + xq], m0 - add xq, mmsize / 2 +.loop: + movu m0, [topq + xq] + movu m1, [bottomq + xq] + pxor m0, m2 + pxor m1, m2 + pavg%2 m0, m1 + pxor m0, m2 + mova [dstq + xq], m0 + add xq, mmsize jl .loop BLEND_END +%endmacro -BLEND_INIT grainmerge, 4 - pxor m2, m2 - mova m3, [pw_128] +; %1 name , %2 src (b or w), %3 inter (w or d), %4 (1 if 16bit, not set if 8 bit) +%macro GRAINMERGE 3-4 +BLEND_INIT %1, 6, %4 + pxor m4, m4 +%if %0 == 4 ; 16 bit + VBROADCASTI128 m5, [pd_32768] +%else + VBROADCASTI128 m5, [pw_128] +%endif .nextrow: mov xq, widthq .loop: - movh m0, [topq + xq] - movh m1, [bottomq + xq] - punpcklbw m0, m2 - punpcklbw m1, m2 - paddw m0, m1 - psubw m0, m3 - packuswb m0, m0 - movh [dstq + xq], m0 - add xq, mmsize / 2 + movu m1, [topq + xq] + movu m3, [bottomq + xq] + + punpckl%2%3 m0, m1, m4 + punpckh%2%3 m1, m4 + punpckl%2%3 m2, m3, m4 + punpckh%2%3 m3, m4 + + padd%3 m0, m2 + padd%3 m1, m3 + psub%3 m0, m5 + psub%3 m1, m5 + + packus%3%2 m0, m1 + + mova [dstq + xq], m0 + add xq, mmsize jl .loop BLEND_END +%endmacro +%macro HARDMIX 0 BLEND_INIT hardmix, 5 - mova m2, [pb_255] - mova m3, [pb_128] - mova m4, [pb_127] + VBROADCASTI128 m2, [pb_255] + VBROADCASTI128 m3, [pb_128] + VBROADCASTI128 m4, [pb_127] .nextrow: mov xq, widthq @@ -218,7 +255,9 @@ BLEND_INIT hardmix, 5 add xq, mmsize jl .loop BLEND_END +%endmacro +%macro DIVIDE 0 BLEND_INIT divide, 4 pxor m2, m2 mova m3, [ps_255] @@ -247,9 +286,12 @@ BLEND_INIT divide, 4 jl .loop BLEND_END +%endmacro -BLEND_INIT phoenix, 4 - mova m3, [pb_255] +%macro PHOENIX 2-3 +; %1 name, %2 b or w, %3 (opt) 1 if 16 bit +BLEND_INIT %1, 4, %3 + VBROADCASTI128 m3, [pb_255] .nextrow: mov xq, widthq @@ -257,18 +299,20 @@ BLEND_INIT phoenix, 4 movu m0, [topq + xq] movu m1, [bottomq + xq] mova m2, m0 - pminub m0, m1 - pmaxub m1, m2 + pminu%2 m0, m1 + pmaxu%2 m1, m2 mova m2, m3 - psubusb m2, m1 - paddusb m2, m0 + psubus%2 m2, m1 + paddus%2 m2, m0 mova [dstq + xq], m2 add xq, mmsize jl .loop BLEND_END +%endmacro -%macro BLEND_ABS 0 -BLEND_INIT difference, 5 +; %1 name , %2 src (b or w), %3 inter (w or d), %4 (1 if 16bit, not set if 8 bit) +%macro DIFFERENCE 3-4 +BLEND_INIT %1, 5, %4 pxor m2, m2 .nextrow: mov xq, widthq @@ -276,64 +320,92 @@ BLEND_INIT difference, 5 .loop: movu m0, [topq + xq] movu m1, [bottomq + xq] - punpckhbw m3, m0, m2 - punpcklbw m0, m2 - punpckhbw m4, m1, m2 - punpcklbw m1, m2 - psubw m0, m1 - psubw m3, m4 + punpckh%2%3 m3, m0, m2 + punpckl%2%3 m0, m2 + punpckh%2%3 m4, m1, m2 + punpckl%2%3 m1, m2 + psub%3 m0, m1 + psub%3 m3, m4 +%if %0 == 4; 16 bit + pabsd m0, m0 + pabsd m3, m3 +%else ABS2 m0, m3, m1, m4 - packuswb m0, m3 +%endif + packus%3%2 m0, m3 mova [dstq + xq], m0 add xq, mmsize jl .loop BLEND_END +%endmacro -BLEND_INIT extremity, 8 +; %1 name , %2 src (b or w), %3 inter (w or d), %4 (1 if 16bit, not set if 8 bit) +%macro EXTREMITY 3-4 +BLEND_INIT %1, 8, %4 pxor m2, m2 - mova m4, [pw_255] +%if %0 == 4; 16 bit + VBROADCASTI128 m4, [pd_65535] +%else + VBROADCASTI128 m4, [pw_255] +%endif .nextrow: mov xq, widthq .loop: movu m0, [topq + xq] movu m1, [bottomq + xq] - punpckhbw m5, m0, m2 - punpcklbw m0, m2 - punpckhbw m6, m1, m2 - punpcklbw m1, m2 - psubw m3, m4, m0 - psubw m7, m4, m5 - psubw m3, m1 - psubw m7, m6 + punpckh%2%3 m5, m0, m2 + punpckl%2%3 m0, m2 + punpckh%2%3 m6, m1, m2 + punpckl%2%3 m1, m2 + psub%3 m3, m4, m0 + psub%3 m7, m4, m5 + psub%3 m3, m1 + psub%3 m7, m6 +%if %0 == 4; 16 bit + pabsd m3, m3 + pabsd m7, m7 +%else ABS2 m3, m7, m1, m6 - packuswb m3, m7 +%endif + packus%3%2 m3, m7 mova [dstq + xq], m3 add xq, mmsize jl .loop BLEND_END +%endmacro -BLEND_INIT negation, 8 +%macro NEGATION 3-4 +BLEND_INIT %1, 8, %4 pxor m2, m2 - mova m4, [pw_255] +%if %0 == 4; 16 bit + VBROADCASTI128 m4, [pd_65535] +%else + VBROADCASTI128 m4, [pw_255] +%endif .nextrow: mov xq, widthq .loop: movu m0, [topq + xq] movu m1, [bottomq + xq] - punpckhbw m5, m0, m2 - punpcklbw m0, m2 - punpckhbw m6, m1, m2 - punpcklbw m1, m2 - psubw m3, m4, m0 - psubw m7, m4, m5 - psubw m3, m1 - psubw m7, m6 + punpckh%2%3 m5, m0, m2 + punpckl%2%3 m0, m2 + punpckh%2%3 m6, m1, m2 + punpckl%2%3 m1, m2 + psub%3 m3, m4, m0 + psub%3 m7, m4, m5 + psub%3 m3, m1 + psub%3 m7, m6 +%if %0 == 4; 16 bit + pabsd m3, m3 + pabsd m7, m7 +%else ABS2 m3, m7, m1, m6 - psubw m0, m4, m3 - psubw m1, m4, m7 - packuswb m0, m1 +%endif + psub%3 m0, m4, m3 + psub%3 m1, m4, m7 + packus%3%2 m0, m1 mova [dstq + xq], m0 add xq, mmsize jl .loop @@ -341,6 +413,86 @@ BLEND_END %endmacro INIT_XMM sse2 -BLEND_ABS +BLEND_SIMPLE xor, xor +BLEND_SIMPLE or, or +BLEND_SIMPLE and, and +BLEND_SIMPLE addition, addusb +BLEND_SIMPLE subtract, subusb +BLEND_SIMPLE darken, minub +BLEND_SIMPLE lighten, maxub +GRAINEXTRACT grainextract, b, w +BLEND_MULTIPLY +BLEND_SCREEN +AVERAGE average, b +GRAINMERGE grainmerge, b, w +HARDMIX +PHOENIX phoenix, b +DIFFERENCE difference, b, w +DIVIDE +EXTREMITY extremity, b, w +NEGATION negation, b, w + +%if ARCH_X86_64 +BLEND_SIMPLE addition_16, addusw, 1 +BLEND_SIMPLE and_16, and, 1 +BLEND_SIMPLE or_16, or, 1 +BLEND_SIMPLE subtract_16, subusw, 1 +BLEND_SIMPLE xor_16, xor, 1 +AVERAGE average_16, w, 1 +%endif + INIT_XMM ssse3 -BLEND_ABS +DIFFERENCE difference, b, w +EXTREMITY extremity, b, w +NEGATION negation, b, w + +INIT_XMM sse4 +%if ARCH_X86_64 +BLEND_SIMPLE darken_16, minuw, 1 +BLEND_SIMPLE lighten_16, maxuw, 1 +GRAINEXTRACT grainextract_16, w, d, 1 +GRAINMERGE grainmerge_16, w, d, 1 +PHOENIX phoenix_16, w, 1 +DIFFERENCE difference_16, w, d, 1 +EXTREMITY extremity_16, w, d, 1 +NEGATION negation_16, w, d, 1 +%endif + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +BLEND_SIMPLE xor, xor +BLEND_SIMPLE or, or +BLEND_SIMPLE and, and +BLEND_SIMPLE addition, addusb +BLEND_SIMPLE subtract, subusb +BLEND_SIMPLE darken, minub +BLEND_SIMPLE lighten, maxub +GRAINEXTRACT grainextract, b, w +BLEND_MULTIPLY +BLEND_SCREEN +AVERAGE average, b +GRAINMERGE grainmerge, b, w +HARDMIX +PHOENIX phoenix, b + +DIFFERENCE difference, b, w +EXTREMITY extremity, b, w +NEGATION negation, b, w + +%if ARCH_X86_64 +BLEND_SIMPLE addition_16, addusw, 1 +BLEND_SIMPLE and_16, and, 1 +BLEND_SIMPLE darken_16, minuw, 1 +BLEND_SIMPLE lighten_16, maxuw, 1 +BLEND_SIMPLE or_16, or, 1 +BLEND_SIMPLE subtract_16, subusw, 1 +BLEND_SIMPLE xor_16, xor, 1 +GRAINEXTRACT grainextract_16, w, d, 1 +AVERAGE average_16, w, 1 +GRAINMERGE grainmerge_16, w, d, 1 +PHOENIX phoenix_16, w, 1 +DIFFERENCE difference_16, w, d, 1 +EXTREMITY extremity_16, w, d, 1 +NEGATION negation_16, w, d, 1 +%endif +%endif diff --git a/libavfilter/x86/vf_blend_init.c b/libavfilter/x86/vf_blend_init.c index a4fc9af2469de..acf28559ff7be 100644 --- a/libavfilter/x86/vf_blend_init.c +++ b/libavfilter/x86/vf_blend_init.c @@ -31,58 +31,173 @@ void ff_blend_##name##_##opt(const uint8_t *top, ptrdiff_t top_linesize, \ struct FilterParams *param, double *values, int starty); BLEND_FUNC(addition, sse2) +BLEND_FUNC(addition, avx2) BLEND_FUNC(grainmerge, sse2) +BLEND_FUNC(grainmerge, avx2) BLEND_FUNC(average, sse2) +BLEND_FUNC(average, avx2) BLEND_FUNC(and, sse2) +BLEND_FUNC(and, avx2) BLEND_FUNC(darken, sse2) +BLEND_FUNC(darken, avx2) BLEND_FUNC(grainextract, sse2) +BLEND_FUNC(grainextract, avx2) BLEND_FUNC(multiply, sse2) +BLEND_FUNC(multiply, avx2) BLEND_FUNC(screen, sse2) +BLEND_FUNC(screen, avx2) BLEND_FUNC(hardmix, sse2) +BLEND_FUNC(hardmix, avx2) BLEND_FUNC(divide, sse2) BLEND_FUNC(lighten, sse2) +BLEND_FUNC(lighten, avx2) BLEND_FUNC(or, sse2) +BLEND_FUNC(or, avx2) BLEND_FUNC(phoenix, sse2) +BLEND_FUNC(phoenix, avx2) BLEND_FUNC(subtract, sse2) +BLEND_FUNC(subtract, avx2) BLEND_FUNC(xor, sse2) +BLEND_FUNC(xor, avx2) BLEND_FUNC(difference, sse2) BLEND_FUNC(difference, ssse3) +BLEND_FUNC(difference, avx2) BLEND_FUNC(extremity, sse2) BLEND_FUNC(extremity, ssse3) +BLEND_FUNC(extremity, avx2) BLEND_FUNC(negation, sse2) BLEND_FUNC(negation, ssse3) +BLEND_FUNC(negation, avx2) + +#if ARCH_X86_64 +BLEND_FUNC(addition_16, sse2) +BLEND_FUNC(addition_16, avx2) +BLEND_FUNC(grainmerge_16, sse4) +BLEND_FUNC(grainmerge_16, avx2) +BLEND_FUNC(average_16, sse2) +BLEND_FUNC(average_16, avx2) +BLEND_FUNC(and_16, sse2) +BLEND_FUNC(and_16, avx2) +BLEND_FUNC(darken_16, sse4) +BLEND_FUNC(darken_16, avx2) +BLEND_FUNC(grainextract_16, sse4) +BLEND_FUNC(grainextract_16, avx2) +BLEND_FUNC(difference_16, sse4) +BLEND_FUNC(difference_16, avx2) +BLEND_FUNC(extremity_16, sse4) +BLEND_FUNC(extremity_16, avx2) +BLEND_FUNC(negation_16, sse4) +BLEND_FUNC(negation_16, avx2) +BLEND_FUNC(lighten_16, sse4) +BLEND_FUNC(lighten_16, avx2) +BLEND_FUNC(or_16, sse2) +BLEND_FUNC(or_16, avx2) +BLEND_FUNC(phoenix_16, sse4) +BLEND_FUNC(phoenix_16, avx2) +BLEND_FUNC(subtract_16, sse2) +BLEND_FUNC(subtract_16, avx2) +BLEND_FUNC(xor_16, sse2) +BLEND_FUNC(xor_16, avx2) +#endif /* ARCH_X86_64 */ av_cold void ff_blend_init_x86(FilterParams *param, int is_16bit) { int cpu_flags = av_get_cpu_flags(); - if (EXTERNAL_SSE2(cpu_flags) && param->opacity == 1 && !is_16bit) { - switch (param->mode) { - case BLEND_ADDITION: param->blend = ff_blend_addition_sse2; break; - case BLEND_GRAINMERGE: param->blend = ff_blend_grainmerge_sse2; break; - case BLEND_AND: param->blend = ff_blend_and_sse2; break; - case BLEND_AVERAGE: param->blend = ff_blend_average_sse2; break; - case BLEND_DARKEN: param->blend = ff_blend_darken_sse2; break; - case BLEND_GRAINEXTRACT: param->blend = ff_blend_grainextract_sse2; break; - case BLEND_DIVIDE: param->blend = ff_blend_divide_sse2; break; - case BLEND_HARDMIX: param->blend = ff_blend_hardmix_sse2; break; - case BLEND_LIGHTEN: param->blend = ff_blend_lighten_sse2; break; - case BLEND_MULTIPLY: param->blend = ff_blend_multiply_sse2; break; - case BLEND_OR: param->blend = ff_blend_or_sse2; break; - case BLEND_PHOENIX: param->blend = ff_blend_phoenix_sse2; break; - case BLEND_SCREEN: param->blend = ff_blend_screen_sse2; break; - case BLEND_SUBTRACT: param->blend = ff_blend_subtract_sse2; break; - case BLEND_XOR: param->blend = ff_blend_xor_sse2; break; - case BLEND_DIFFERENCE: param->blend = ff_blend_difference_sse2; break; - case BLEND_EXTREMITY: param->blend = ff_blend_extremity_sse2; break; - case BLEND_NEGATION: param->blend = ff_blend_negation_sse2; break; + if (!is_16bit) { + if (EXTERNAL_SSE2(cpu_flags) && param->opacity == 1) { + switch (param->mode) { + case BLEND_ADDITION: param->blend = ff_blend_addition_sse2; break; + case BLEND_GRAINMERGE: param->blend = ff_blend_grainmerge_sse2; break; + case BLEND_AND: param->blend = ff_blend_and_sse2; break; + case BLEND_AVERAGE: param->blend = ff_blend_average_sse2; break; + case BLEND_DARKEN: param->blend = ff_blend_darken_sse2; break; + case BLEND_GRAINEXTRACT: param->blend = ff_blend_grainextract_sse2; break; + case BLEND_DIVIDE: param->blend = ff_blend_divide_sse2; break; + case BLEND_HARDMIX: param->blend = ff_blend_hardmix_sse2; break; + case BLEND_LIGHTEN: param->blend = ff_blend_lighten_sse2; break; + case BLEND_MULTIPLY: param->blend = ff_blend_multiply_sse2; break; + case BLEND_OR: param->blend = ff_blend_or_sse2; break; + case BLEND_PHOENIX: param->blend = ff_blend_phoenix_sse2; break; + case BLEND_SCREEN: param->blend = ff_blend_screen_sse2; break; + case BLEND_SUBTRACT: param->blend = ff_blend_subtract_sse2; break; + case BLEND_XOR: param->blend = ff_blend_xor_sse2; break; + case BLEND_DIFFERENCE: param->blend = ff_blend_difference_sse2; break; + case BLEND_EXTREMITY: param->blend = ff_blend_extremity_sse2; break; + case BLEND_NEGATION: param->blend = ff_blend_negation_sse2; break; + } } - } - if (EXTERNAL_SSSE3(cpu_flags) && param->opacity == 1 && !is_16bit) { - switch (param->mode) { - case BLEND_DIFFERENCE: param->blend = ff_blend_difference_ssse3; break; - case BLEND_EXTREMITY: param->blend = ff_blend_extremity_ssse3; break; - case BLEND_NEGATION: param->blend = ff_blend_negation_ssse3; break; + if (EXTERNAL_SSSE3(cpu_flags) && param->opacity == 1) { + switch (param->mode) { + case BLEND_DIFFERENCE: param->blend = ff_blend_difference_ssse3; break; + case BLEND_EXTREMITY: param->blend = ff_blend_extremity_ssse3; break; + case BLEND_NEGATION: param->blend = ff_blend_negation_ssse3; break; + } + } + + if (EXTERNAL_AVX2_FAST(cpu_flags) && param->opacity == 1) { + switch (param->mode) { + case BLEND_ADDITION: param->blend = ff_blend_addition_avx2; break; + case BLEND_GRAINMERGE: param->blend = ff_blend_grainmerge_avx2; break; + case BLEND_AND: param->blend = ff_blend_and_avx2; break; + case BLEND_AVERAGE: param->blend = ff_blend_average_avx2; break; + case BLEND_DARKEN: param->blend = ff_blend_darken_avx2; break; + case BLEND_GRAINEXTRACT: param->blend = ff_blend_grainextract_avx2; break; + case BLEND_HARDMIX: param->blend = ff_blend_hardmix_avx2; break; + case BLEND_LIGHTEN: param->blend = ff_blend_lighten_avx2; break; + case BLEND_MULTIPLY: param->blend = ff_blend_multiply_avx2; break; + case BLEND_OR: param->blend = ff_blend_or_avx2; break; + case BLEND_PHOENIX: param->blend = ff_blend_phoenix_avx2; break; + case BLEND_SCREEN: param->blend = ff_blend_screen_avx2; break; + case BLEND_SUBTRACT: param->blend = ff_blend_subtract_avx2; break; + case BLEND_XOR: param->blend = ff_blend_xor_avx2; break; + case BLEND_DIFFERENCE: param->blend = ff_blend_difference_avx2; break; + case BLEND_EXTREMITY: param->blend = ff_blend_extremity_avx2; break; + case BLEND_NEGATION: param->blend = ff_blend_negation_avx2; break; + } + } + } else { /* is_16_bit */ +#if ARCH_X86_64 + if (EXTERNAL_SSE2(cpu_flags) && param->opacity == 1) { + switch (param->mode) { + case BLEND_ADDITION: param->blend = ff_blend_addition_16_sse2; break; + case BLEND_AND: param->blend = ff_blend_and_16_sse2; break; + case BLEND_AVERAGE: param->blend = ff_blend_average_16_sse2; break; + case BLEND_OR: param->blend = ff_blend_or_16_sse2; break; + case BLEND_SUBTRACT: param->blend = ff_blend_subtract_16_sse2; break; + case BLEND_XOR: param->blend = ff_blend_xor_16_sse2; break; + } + } + if (EXTERNAL_SSE4(cpu_flags) && param->opacity == 1) { + switch (param->mode) { + case BLEND_GRAINMERGE: param->blend = ff_blend_grainmerge_16_sse4; break; + case BLEND_DARKEN: param->blend = ff_blend_darken_16_sse4; break; + case BLEND_GRAINEXTRACT: param->blend = ff_blend_grainextract_16_sse4; break; + case BLEND_DIFFERENCE: param->blend = ff_blend_difference_16_sse4; break; + case BLEND_EXTREMITY: param->blend = ff_blend_extremity_16_sse4; break; + case BLEND_NEGATION: param->blend = ff_blend_negation_16_sse4; break; + case BLEND_LIGHTEN: param->blend = ff_blend_lighten_16_sse4; break; + case BLEND_PHOENIX: param->blend = ff_blend_phoenix_16_sse4; break; + } + } + if (EXTERNAL_AVX2_FAST(cpu_flags) && param->opacity == 1) { + switch (param->mode) { + case BLEND_ADDITION: param->blend = ff_blend_addition_16_avx2; break; + case BLEND_GRAINMERGE: param->blend = ff_blend_grainmerge_16_avx2; break; + case BLEND_AND: param->blend = ff_blend_and_16_avx2; break; + case BLEND_AVERAGE: param->blend = ff_blend_average_16_avx2; break; + case BLEND_DARKEN: param->blend = ff_blend_darken_16_avx2; break; + case BLEND_GRAINEXTRACT: param->blend = ff_blend_grainextract_16_avx2; break; + case BLEND_DIFFERENCE: param->blend = ff_blend_difference_16_avx2; break; + case BLEND_EXTREMITY: param->blend = ff_blend_extremity_16_avx2; break; + case BLEND_NEGATION: param->blend = ff_blend_negation_16_avx2; break; + case BLEND_LIGHTEN: param->blend = ff_blend_lighten_16_avx2; break; + case BLEND_OR: param->blend = ff_blend_or_16_avx2; break; + case BLEND_PHOENIX: param->blend = ff_blend_phoenix_16_avx2; break; + case BLEND_SUBTRACT: param->blend = ff_blend_subtract_16_avx2; break; + case BLEND_XOR: param->blend = ff_blend_xor_16_avx2; break; + } } +#endif /* ARCH_X86_64 */ } } diff --git a/libavfilter/x86/vf_framerate.asm b/libavfilter/x86/vf_framerate.asm new file mode 100644 index 0000000000000..7a30c870bd5ae --- /dev/null +++ b/libavfilter/x86/vf_framerate.asm @@ -0,0 +1,134 @@ +;***************************************************************************** +;* x86-optimized functions for framerate filter +;* +;* Copyright (C) 2018 Marton Balint +;* +;* Based on vf_blend.asm, Copyright (C) 2015 Paul B Mahol +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +SECTION .text + + +%macro XSPLAT 3 +%if cpuflag(avx2) + vpbroadcast%3 %1, %2 +%else + movd %1, %2 +%ifidn %3, d + SPLATD %1 +%else + SPLATW %1, %1 +%endif +%endif +%endmacro + + +%macro BLEND_INIT 0-1 +%if ARCH_X86_64 +cglobal blend_frames%1, 6, 9, 5, src1, src1_linesize, src2, src2_linesize, dst, dst_linesize, width, end, x + mov widthd, dword widthm +%else +cglobal blend_frames%1, 5, 7, 5, src1, src1_linesize, src2, src2_linesize, dst, end, x +%define dst_linesizeq r5mp +%define widthq r6mp +%endif + mov endd, dword r7m + add src1q, widthq + add src2q, widthq + add dstq, widthq + neg widthq +%endmacro + + +%macro BLEND_LOOP 4 +.nextrow: + mov xq, widthq + + .loop: + movu m0, [src1q + xq] + movu m1, [src2q + xq] + SBUTTERFLY %1%2, 0, 1, 4 ; aAbBcCdD + ; eEfFgGhH + pmadd%3 m0, m2 + pmadd%3 m1, m2 + + padd%2 m0, m3 + padd%2 m1, m3 + psrl%2 m0, %4 ; 0A0B0C0D + psrl%2 m1, %4 ; 0E0F0G0H + + packus%2%1 m0, m1 ; ABCDEFGH + movu [dstq + xq], m0 + add xq, mmsize + jl .loop + add src1q, src1_linesizeq + add src2q, src2_linesizeq + add dstq, dst_linesizeq + sub endd, 1 + jg .nextrow +REP_RET +%endmacro + + +%macro BLEND_FRAMES 0 + BLEND_INIT + + XSPLAT m2, r8m, w ; factor1 + XSPLAT m3, r9m, w ; factor2 + + psllw m3, 8 + por m2, m3 ; interleaved factors + + XSPLAT m3, r10m, w ; half + + BLEND_LOOP b, w, ubsw, 7 +%endmacro + + +%macro BLEND_FRAMES16 0 + BLEND_INIT 16 + + XSPLAT m2, r8m, d ; factor1 + XSPLAT m3, r9m, d ; factor2 + + pslld m3, 16 + por m2, m3 ; interleaved factors + + XSPLAT m3, r10m, d ; half + + BLEND_LOOP w, d, wd, 15 +%endmacro + + +INIT_XMM ssse3 +BLEND_FRAMES + +INIT_XMM sse4 +BLEND_FRAMES16 + + +%if HAVE_AVX2_EXTERNAL + +INIT_YMM avx2 +BLEND_FRAMES +BLEND_FRAMES16 + +%endif diff --git a/libavfilter/x86/vf_framerate_init.c b/libavfilter/x86/vf_framerate_init.c new file mode 100644 index 0000000000000..9d40faf0a4f25 --- /dev/null +++ b/libavfilter/x86/vf_framerate_init.c @@ -0,0 +1,42 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavfilter/framerate.h" + +void ff_blend_frames_ssse3(BLEND_FUNC_PARAMS); +void ff_blend_frames_avx2(BLEND_FUNC_PARAMS); +void ff_blend_frames16_sse4(BLEND_FUNC_PARAMS); +void ff_blend_frames16_avx2(BLEND_FUNC_PARAMS); + +void ff_framerate_init_x86(FrameRateContext *s) +{ + int cpu_flags = av_get_cpu_flags(); + if (s->bitdepth == 8) { + if (EXTERNAL_AVX2_FAST(cpu_flags)) + s->blend = ff_blend_frames_avx2; + else if (EXTERNAL_SSSE3(cpu_flags)) + s->blend = ff_blend_frames_ssse3; + } else { + if (EXTERNAL_AVX2_FAST(cpu_flags)) + s->blend = ff_blend_frames16_avx2; + else if (EXTERNAL_SSE4(cpu_flags)) + s->blend = ff_blend_frames16_sse4; + } +} diff --git a/libavfilter/x86/vf_hflip.asm b/libavfilter/x86/vf_hflip.asm new file mode 100644 index 0000000000000..285618954f219 --- /dev/null +++ b/libavfilter/x86/vf_hflip.asm @@ -0,0 +1,90 @@ +;***************************************************************************** +;* x86-optimized functions for hflip filter +;* +;* Copyright (C) 2017 Paul B Mahol +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;***************************************************************************** + +%include "libavutil/x86/x86util.asm" + +SECTION_RODATA + +pb_flip_byte: db 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0 +pb_flip_short: db 14,15,12,13,10,11,8,9,6,7,4,5,2,3,0,1 + +SECTION .text + +;%1 byte or short, %2 b or w, %3 size in byte (1 for byte, 2 for short) +%macro HFLIP 3 +cglobal hflip_%1, 3, 5, 3, src, dst, w, r, x + VBROADCASTI128 m0, [pb_flip_%1] + xor xq, xq +%if %3 == 1 + movsxdifnidn wq, wd +%else ; short + add wd, wd +%endif + mov rq, wq + and rq, 2 * mmsize - 1 + cmp wq, 2 * mmsize + jl .loop1 + sub wq, rq + + .loop0: + neg xq +%if mmsize == 32 + vpermq m1, [srcq + xq - mmsize + %3], 0x4e; flip each lane at load + vpermq m2, [srcq + xq - 2 * mmsize + %3], 0x4e; flip each lane at load +%else + movu m1, [srcq + xq - mmsize + %3] + movu m2, [srcq + xq - 2 * mmsize + %3] +%endif + pshufb m1, m0 + pshufb m2, m0 + neg xq + movu [dstq + xq ], m1 + movu [dstq + xq + mmsize], m2 + add xq, mmsize * 2 + cmp xq, wq + jl .loop0 + + cmp rq, 0 + je .end + add wq, rq + + .loop1: + neg xq + mov r%2, [srcq + xq] + neg xq + mov [dstq + xq], r%2 + add xq, %3 + cmp xq, wq + jl .loop1 + .end: + RET +%endmacro + +INIT_XMM ssse3 +HFLIP byte, b, 1 +HFLIP short, w, 2 + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +HFLIP byte, b, 1 +HFLIP short, w, 2 +%endif diff --git a/libavfilter/x86/vf_hflip_init.c b/libavfilter/x86/vf_hflip_init.c new file mode 100644 index 0000000000000..0ac399b0d415e --- /dev/null +++ b/libavfilter/x86/vf_hflip_init.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavfilter/hflip.h" + +void ff_hflip_byte_ssse3(const uint8_t *src, uint8_t *dst, int w); +void ff_hflip_byte_avx2(const uint8_t *src, uint8_t *dst, int w); +void ff_hflip_short_ssse3(const uint8_t *src, uint8_t *dst, int w); +void ff_hflip_short_avx2(const uint8_t *src, uint8_t *dst, int w); + +av_cold void ff_hflip_init_x86(FlipContext *s, int step[4], int nb_planes) +{ + int cpu_flags = av_get_cpu_flags(); + int i; + + for (i = 0; i < nb_planes; i++) { + if (step[i] == 1) { + if (EXTERNAL_SSSE3(cpu_flags)) { + s->flip_line[i] = ff_hflip_byte_ssse3; + } + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + s->flip_line[i] = ff_hflip_byte_avx2; + } + } else if (step[i] == 2) { + if (EXTERNAL_SSSE3(cpu_flags)) { + s->flip_line[i] = ff_hflip_short_ssse3; + } + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + s->flip_line[i] = ff_hflip_short_avx2; + } + } + } +} diff --git a/libavfilter/x86/vf_interlace.asm b/libavfilter/x86/vf_interlace.asm index 7c0065d4d9489..a6c65b805dc26 100644 --- a/libavfilter/x86/vf_interlace.asm +++ b/libavfilter/x86/vf_interlace.asm @@ -39,9 +39,23 @@ SECTION .text pcmpeq%1 m6, m6 + test hq, mmsize + je .loop + + ;process 1 * mmsize + movu m0, [mrefq+hq] + pavg%1 m0, [prefq+hq] + pxor m0, m6 + pxor m2, m6, [srcq+hq] + pavg%1 m0, m2 + pxor m0, m6 + mova [dstq+hq], m0 + add hq, mmsize + jge .end + .loop: - mova m0, [mrefq+hq] - mova m1, [mrefq+hq+mmsize] + movu m0, [mrefq+hq] + movu m1, [mrefq+hq+mmsize] pavg%1 m0, [prefq+hq] pavg%1 m1, [prefq+hq+mmsize] pxor m0, m6 @@ -57,7 +71,9 @@ SECTION .text add hq, 2*mmsize jl .loop -REP_RET + +.end: + REP_RET %endmacro %macro LOWPASS_LINE 0 @@ -73,8 +89,8 @@ cglobal lowpass_line_16, 5, 5, 7, dst, h, src, mref, pref cglobal lowpass_line_complex, 5, 5, 8, dst, h, src, mref, pref pxor m7, m7 .loop: - mova m0, [srcq+mrefq] - mova m2, [srcq+prefq] + movu m0, [srcq+mrefq] + movu m2, [srcq+prefq] mova m1, m0 mova m3, m2 punpcklbw m0, m7 @@ -85,7 +101,7 @@ cglobal lowpass_line_complex, 5, 5, 8, dst, h, src, mref, pref paddw m1, m3 mova m6, m0 mova m5, m1 - mova m2, [srcq] + movu m2, [srcq] mova m3, m2 punpcklbw m2, m7 punpckhbw m3, m7 @@ -100,8 +116,8 @@ cglobal lowpass_line_complex, 5, 5, 8, dst, h, src, mref, pref pcmpgtw m6, m2 pcmpgtw m5, m3 packsswb m6, m5 - mova m2, [srcq+mrefq*2] - mova m4, [srcq+prefq*2] + movu m2, [srcq+mrefq*2] + movu m4, [srcq+prefq*2] mova m3, m2 mova m5, m4 punpcklbw m2, m7 @@ -118,8 +134,9 @@ cglobal lowpass_line_complex, 5, 5, 8, dst, h, src, mref, pref psrlw m1, 3 packuswb m0, m1 mova m1, m0 - pmaxub m0, [srcq] - pminub m1, [srcq] + movu m2, [srcq] + pmaxub m0, m2 + pminub m1, m2 pand m0, m6 pandn m6, m1 por m0, m6 @@ -134,18 +151,18 @@ REP_RET cglobal lowpass_line_complex_12, 5, 5, 8, 16, dst, h, src, mref, pref, clip_max movd m7, DWORD clip_maxm SPLATW m7, m7, 0 - mova [rsp], m7 + movu [rsp], m7 .loop: - mova m0, [srcq+mrefq] - mova m1, [srcq+mrefq+mmsize] - mova m2, [srcq+prefq] - mova m3, [srcq+prefq+mmsize] + movu m0, [srcq+mrefq] + movu m1, [srcq+mrefq+mmsize] + movu m2, [srcq+prefq] + movu m3, [srcq+prefq+mmsize] paddw m0, m2 paddw m1, m3 mova m6, m0 mova m7, m1 - mova m2, [srcq] - mova m3, [srcq+mmsize] + movu m2, [srcq] + movu m3, [srcq+mmsize] paddw m0, m2 paddw m1, m3 psllw m2, 1 @@ -156,10 +173,10 @@ cglobal lowpass_line_complex_12, 5, 5, 8, 16, dst, h, src, mref, pref, clip_max psllw m1, 1 pcmpgtw m6, m2 pcmpgtw m7, m3 - mova m2, [srcq+2*mrefq] - mova m3, [srcq+2*mrefq+mmsize] - mova m4, [srcq+2*prefq] - mova m5, [srcq+2*prefq+mmsize] + movu m2, [srcq+2*mrefq] + movu m3, [srcq+2*mrefq+mmsize] + movu m4, [srcq+2*prefq] + movu m5, [srcq+2*prefq+mmsize] paddw m2, m4 paddw m3, m5 paddw m0, [pw_4] @@ -172,10 +189,12 @@ cglobal lowpass_line_complex_12, 5, 5, 8, 16, dst, h, src, mref, pref, clip_max pminsw m1, [rsp] mova m2, m0 mova m3, m1 - pmaxsw m0, [srcq] - pmaxsw m1, [srcq+mmsize] - pminsw m2, [srcq] - pminsw m3, [srcq+mmsize] + movu m4, [srcq] + pmaxsw m0, m4 + pminsw m2, m4 + movu m4, [srcq + mmsize] + pmaxsw m1, m4 + pminsw m3, m4 pand m0, m6 pand m1, m7 pandn m6, m2 @@ -198,5 +217,10 @@ LOWPASS_LINE INIT_XMM avx LOWPASS_LINE +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +LOWPASS_LINE +%endif + INIT_XMM sse2 LOWPASS_LINE_COMPLEX diff --git a/libavfilter/x86/vf_interlace_init.c b/libavfilter/x86/vf_interlace_init.c index 70fe86ccff046..0de0fea382e53 100644 --- a/libavfilter/x86/vf_interlace_init.c +++ b/libavfilter/x86/vf_interlace_init.c @@ -32,6 +32,9 @@ void ff_lowpass_line_sse2(uint8_t *dstp, ptrdiff_t linesize, void ff_lowpass_line_avx (uint8_t *dstp, ptrdiff_t linesize, const uint8_t *srcp, ptrdiff_t mref, ptrdiff_t pref, int clip_max); +void ff_lowpass_line_avx2 (uint8_t *dstp, ptrdiff_t linesize, + const uint8_t *srcp, ptrdiff_t mref, + ptrdiff_t pref, int clip_max); void ff_lowpass_line_16_sse2(uint8_t *dstp, ptrdiff_t linesize, const uint8_t *srcp, ptrdiff_t mref, @@ -39,6 +42,9 @@ void ff_lowpass_line_16_sse2(uint8_t *dstp, ptrdiff_t linesize, void ff_lowpass_line_16_avx (uint8_t *dstp, ptrdiff_t linesize, const uint8_t *srcp, ptrdiff_t mref, ptrdiff_t pref, int clip_max); +void ff_lowpass_line_16_avx2 (uint8_t *dstp, ptrdiff_t linesize, + const uint8_t *srcp, ptrdiff_t mref, + ptrdiff_t pref, int clip_max); void ff_lowpass_line_complex_sse2(uint8_t *dstp, ptrdiff_t linesize, const uint8_t *srcp, ptrdiff_t mref, @@ -48,11 +54,11 @@ void ff_lowpass_line_complex_12_sse2(uint8_t *dstp, ptrdiff_t linesize, const uint8_t *srcp, ptrdiff_t mref, ptrdiff_t pref, int clip_max); -av_cold void ff_interlace_init_x86(InterlaceContext *s) +av_cold void ff_interlace_init_x86(InterlaceContext *s, int depth) { int cpu_flags = av_get_cpu_flags(); - if (s->csp->comp[0].depth > 8) { + if (depth > 8) { if (EXTERNAL_SSE2(cpu_flags)) { if (s->lowpass == VLPF_LIN) s->lowpass_line = ff_lowpass_line_16_sse2; @@ -62,6 +68,9 @@ av_cold void ff_interlace_init_x86(InterlaceContext *s) if (EXTERNAL_AVX(cpu_flags)) if (s->lowpass == VLPF_LIN) s->lowpass_line = ff_lowpass_line_16_avx; + if (EXTERNAL_AVX2_FAST(cpu_flags)) + if (s->lowpass == VLPF_LIN) + s->lowpass_line = ff_lowpass_line_16_avx2; } else { if (EXTERNAL_SSE2(cpu_flags)) { if (s->lowpass == VLPF_LIN) @@ -72,5 +81,8 @@ av_cold void ff_interlace_init_x86(InterlaceContext *s) if (EXTERNAL_AVX(cpu_flags)) if (s->lowpass == VLPF_LIN) s->lowpass_line = ff_lowpass_line_avx; + if (EXTERNAL_AVX2_FAST(cpu_flags)) + if (s->lowpass == VLPF_LIN) + s->lowpass_line = ff_lowpass_line_avx2; } } diff --git a/libavfilter/x86/vf_threshold.asm b/libavfilter/x86/vf_threshold.asm new file mode 100644 index 0000000000000..098069b0835b6 --- /dev/null +++ b/libavfilter/x86/vf_threshold.asm @@ -0,0 +1,92 @@ +;***************************************************************************** +;* x86-optimized functions for threshold filter +;* +;* Copyright (C) 2017 Paul B Mahol +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;***************************************************************************** + +%include "libavutil/x86/x86util.asm" + +SECTION_RODATA + +pb_128: times 16 db 128 +pb_128_0 : times 8 db 0, 128 + +SECTION .text + +;%1 depth (8 or 16) ; %2 b or w ; %3 constant +%macro THRESHOLD 3 +%if ARCH_X86_64 +cglobal threshold%1, 10, 13, 5, in, threshold, min, max, out, ilinesize, tlinesize, flinesize, slinesize, olinesize, w, h, x + mov wd, dword wm + mov hd, dword hm +%else +cglobal threshold%1, 5, 7, 5, in, threshold, min, max, out, w, x + mov wd, r10m +%define ilinesizeq r5mp +%define tlinesizeq r6mp +%define flinesizeq r7mp +%define slinesizeq r8mp +%define olinesizeq r9mp +%define hd r11mp +%endif + VBROADCASTI128 m4, [%3] +%if %1 == 16 + add wq, wq ; w *= 2 (16 bits instead of 8) +%endif + add inq, wq + add thresholdq, wq + add minq, wq + add maxq, wq + add outq, wq + neg wq +.nextrow: + mov xq, wq + + .loop: + movu m1, [inq + xq] + movu m0, [thresholdq + xq] + movu m2, [minq + xq] + movu m3, [maxq + xq] + pxor m0, m4 + pxor m1, m4 + pcmpgt%2 m0, m1 + PBLENDVB m3, m2, m0 + movu [outq + xq], m3 + add xq, mmsize + jl .loop + + add inq, ilinesizeq + add thresholdq, tlinesizeq + add minq, flinesizeq + add maxq, slinesizeq + add outq, olinesizeq + sub hd, 1 + jg .nextrow +RET +%endmacro + +INIT_XMM sse4 +THRESHOLD 8, b, pb_128 +THRESHOLD 16, w, pb_128_0 + +%if HAVE_AVX2_EXTERNAL +INIT_YMM avx2 +THRESHOLD 8, b, pb_128 +THRESHOLD 16, w, pb_128_0 +%endif diff --git a/libavfilter/x86/vf_threshold_init.c b/libavfilter/x86/vf_threshold_init.c new file mode 100644 index 0000000000000..8e4229679194b --- /dev/null +++ b/libavfilter/x86/vf_threshold_init.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/attributes.h" +#include "libavutil/cpu.h" +#include "libavutil/x86/cpu.h" +#include "libavfilter/threshold.h" + +#define THRESHOLD_FUNC(depth, opt) \ +void ff_threshold##depth##_##opt(const uint8_t *in, const uint8_t *threshold,\ + const uint8_t *min, const uint8_t *max, \ + uint8_t *out, \ + ptrdiff_t ilinesize, ptrdiff_t tlinesize, \ + ptrdiff_t flinesize, ptrdiff_t slinesize, \ + ptrdiff_t olinesize, \ + int w, int h); + +THRESHOLD_FUNC(8, sse4) +THRESHOLD_FUNC(8, avx2) +THRESHOLD_FUNC(16, sse4) +THRESHOLD_FUNC(16, avx2) + +av_cold void ff_threshold_init_x86(ThresholdContext *s) +{ + int cpu_flags = av_get_cpu_flags(); + + if (s->depth == 8) { + if (EXTERNAL_SSE4(cpu_flags)) { + s->threshold = ff_threshold8_sse4; + } + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + s->threshold = ff_threshold8_avx2; + } + } else if (s->depth == 16) { + if (EXTERNAL_SSE4(cpu_flags)) { + s->threshold = ff_threshold16_sse4; + } + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + s->threshold = ff_threshold16_avx2; + } + } +} diff --git a/libavfilter/x86/vf_tinterlace_init.c b/libavfilter/x86/vf_tinterlace_init.c index 209812964d0ed..2c9b1de581f37 100644 --- a/libavfilter/x86/vf_tinterlace_init.c +++ b/libavfilter/x86/vf_tinterlace_init.c @@ -33,6 +33,9 @@ void ff_lowpass_line_sse2(uint8_t *dstp, ptrdiff_t linesize, void ff_lowpass_line_avx (uint8_t *dstp, ptrdiff_t linesize, const uint8_t *srcp, ptrdiff_t mref, ptrdiff_t pref, int clip_max); +void ff_lowpass_line_avx2 (uint8_t *dstp, ptrdiff_t linesize, + const uint8_t *srcp, ptrdiff_t mref, + ptrdiff_t pref, int clip_max); void ff_lowpass_line_16_sse2(uint8_t *dstp, ptrdiff_t linesize, const uint8_t *srcp, ptrdiff_t mref, @@ -40,6 +43,9 @@ void ff_lowpass_line_16_sse2(uint8_t *dstp, ptrdiff_t linesize, void ff_lowpass_line_16_avx (uint8_t *dstp, ptrdiff_t linesize, const uint8_t *srcp, ptrdiff_t mref, ptrdiff_t pref, int clip_max); +void ff_lowpass_line_16_avx2 (uint8_t *dstp, ptrdiff_t linesize, + const uint8_t *srcp, ptrdiff_t mref, + ptrdiff_t pref, int clip_max); void ff_lowpass_line_complex_sse2(uint8_t *dstp, ptrdiff_t linesize, const uint8_t *srcp, ptrdiff_t mref, @@ -63,6 +69,11 @@ av_cold void ff_tinterlace_init_x86(TInterlaceContext *s) if (EXTERNAL_AVX(cpu_flags)) if (!(s->flags & TINTERLACE_FLAG_CVLPF)) s->lowpass_line = ff_lowpass_line_16_avx; + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + if (!(s->flags & TINTERLACE_FLAG_CVLPF)) { + s->lowpass_line = ff_lowpass_line_16_avx2; + } + } } else { if (EXTERNAL_SSE2(cpu_flags)) { if (!(s->flags & TINTERLACE_FLAG_CVLPF)) @@ -73,5 +84,10 @@ av_cold void ff_tinterlace_init_x86(TInterlaceContext *s) if (EXTERNAL_AVX(cpu_flags)) if (!(s->flags & TINTERLACE_FLAG_CVLPF)) s->lowpass_line = ff_lowpass_line_avx; + if (EXTERNAL_AVX2_FAST(cpu_flags)) { + if (!(s->flags & TINTERLACE_FLAG_CVLPF)) { + s->lowpass_line = ff_lowpass_line_avx2; + } + } } } diff --git a/libavfilter/x86/yadif-16.asm b/libavfilter/x86/yadif-16.asm index 79d127dfaae6a..9053b378a5b6a 100644 --- a/libavfilter/x86/yadif-16.asm +++ b/libavfilter/x86/yadif-16.asm @@ -54,30 +54,6 @@ SECTION .text %endif %endmacro -%macro PMINSD 3 -%if cpuflag(sse4) - pminsd %1, %2 -%else - mova %3, %2 - pcmpgtd %3, %1 - pand %1, %3 - pandn %3, %2 - por %1, %3 -%endif -%endmacro - -%macro PMAXSD 3 -%if cpuflag(sse4) - pmaxsd %1, %2 -%else - mova %3, %1 - pcmpgtd %3, %2 - pand %1, %3 - pandn %3, %2 - por %1, %3 -%endif -%endmacro - %macro PMAXUW 2 %if cpuflag(sse4) pmaxuw %1, %2 diff --git a/libavformat/.gitignore b/libavformat/.gitignore index cdc24b717fe35..fb70c122c43dc 100644 --- a/libavformat/.gitignore +++ b/libavformat/.gitignore @@ -1 +1,3 @@ /protocol_list.c +/muxer_list.c +/demuxer_list.c diff --git a/libavformat/Makefile b/libavformat/Makefile index df709c29dd253..dd88765801400 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -4,6 +4,14 @@ DESC = FFmpeg container format library HEADERS = avformat.h \ avio.h \ version.h \ + avc.h \ + url.h \ + internal.h \ + avio_internal.h \ + flv.h \ + id3v2.h \ + os_support.h \ + metadata.h \ OBJS = allformats.o \ avio.o \ @@ -23,6 +31,8 @@ OBJS = allformats.o \ sdp.o \ url.o \ utils.o \ + avc.o \ + ijkutils.o \ OBJS-$(HAVE_LIBC_MSVCRT) += file_open.o @@ -87,11 +97,17 @@ OBJS-$(CONFIG_AIFF_MUXER) += aiffenc.o id3v2enc.o OBJS-$(CONFIG_AIX_DEMUXER) += aixdec.o OBJS-$(CONFIG_AMR_DEMUXER) += amr.o OBJS-$(CONFIG_AMR_MUXER) += amr.o +OBJS-$(CONFIG_AMRNB_DEMUXER) += amr.o +OBJS-$(CONFIG_AMRWB_DEMUXER) += amr.o OBJS-$(CONFIG_ANM_DEMUXER) += anm.o OBJS-$(CONFIG_APC_DEMUXER) += apc.o OBJS-$(CONFIG_APE_DEMUXER) += ape.o apetag.o img2.o OBJS-$(CONFIG_APNG_DEMUXER) += apngdec.o OBJS-$(CONFIG_APNG_MUXER) += apngenc.o +OBJS-$(CONFIG_APTX_DEMUXER) += aptxdec.o rawdec.o +OBJS-$(CONFIG_APTX_MUXER) += rawenc.o +OBJS-$(CONFIG_APTX_HD_DEMUXER) += aptxdec.o rawdec.o +OBJS-$(CONFIG_APTX_HD_MUXER) += rawenc.o OBJS-$(CONFIG_AQTITLE_DEMUXER) += aqtitledec.o subtitles.o OBJS-$(CONFIG_ASF_DEMUXER) += asfdec_f.o asf.o asfcrypt.o \ avlanguage.o @@ -120,20 +136,23 @@ OBJS-$(CONFIG_BOA_DEMUXER) += boadec.o OBJS-$(CONFIG_BFSTM_DEMUXER) += brstm.o OBJS-$(CONFIG_BRSTM_DEMUXER) += brstm.o OBJS-$(CONFIG_C93_DEMUXER) += c93.o voc_packet.o vocdec.o voc.o -OBJS-$(CONFIG_CAF_DEMUXER) += cafdec.o caf.o mov.o mov_chan.o \ - replaygain.o +OBJS-$(CONFIG_CAF_DEMUXER) += cafdec.o caf.o mov_chan.o mov_esds.o OBJS-$(CONFIG_CAF_MUXER) += cafenc.o caf.o riff.o OBJS-$(CONFIG_CAVSVIDEO_DEMUXER) += cavsvideodec.o rawdec.o OBJS-$(CONFIG_CAVSVIDEO_MUXER) += rawenc.o OBJS-$(CONFIG_CDG_DEMUXER) += cdg.o OBJS-$(CONFIG_CDXL_DEMUXER) += cdxl.o OBJS-$(CONFIG_CINE_DEMUXER) += cinedec.o +OBJS-$(CONFIG_CODEC2_DEMUXER) += codec2.o rawdec.o pcm.o +OBJS-$(CONFIG_CODEC2_MUXER) += codec2.o rawenc.o +OBJS-$(CONFIG_CODEC2RAW_DEMUXER) += codec2.o rawdec.o pcm.o +OBJS-$(CONFIG_CODEC2RAW_MUXER) += rawenc.o OBJS-$(CONFIG_CONCAT_DEMUXER) += concatdec.o OBJS-$(CONFIG_CRC_MUXER) += crcenc.o OBJS-$(CONFIG_DATA_DEMUXER) += rawdec.o OBJS-$(CONFIG_DATA_MUXER) += rawenc.o -OBJS-$(CONFIG_DASH_MUXER) += dash.o dashenc.o -OBJS-$(CONFIG_DASH_DEMUXER) += dashdec.o +OBJS-$(CONFIG_DASH_MUXER) += dash.o dashenc.o hlsplaylist.o +OBJS-$(CONFIG_DASH_DEMUXER) += dash.o dashdec.o OBJS-$(CONFIG_DAUD_DEMUXER) += dauddec.o OBJS-$(CONFIG_DAUD_MUXER) += daudenc.o OBJS-$(CONFIG_DCSTR_DEMUXER) += dcstr.o @@ -158,11 +177,10 @@ OBJS-$(CONFIG_EA_DEMUXER) += electronicarts.o OBJS-$(CONFIG_EAC3_DEMUXER) += ac3dec.o rawdec.o OBJS-$(CONFIG_EAC3_MUXER) += rawenc.o OBJS-$(CONFIG_EPAF_DEMUXER) += epafdec.o pcm.o -OBJS-$(CONFIG_FFM_DEMUXER) += ffmdec.o -OBJS-$(CONFIG_FFM_MUXER) += ffmenc.o OBJS-$(CONFIG_FFMETADATA_DEMUXER) += ffmetadec.o OBJS-$(CONFIG_FFMETADATA_MUXER) += ffmetaenc.o OBJS-$(CONFIG_FIFO_MUXER) += fifo.o +OBJS-$(CONFIG_FIFO_TEST_MUXER) += fifo_test.o OBJS-$(CONFIG_FILMSTRIP_DEMUXER) += filmstripdec.o OBJS-$(CONFIG_FILMSTRIP_MUXER) += filmstripenc.o OBJS-$(CONFIG_FITS_DEMUXER) += fitsdec.o @@ -212,7 +230,7 @@ OBJS-$(CONFIG_HDS_MUXER) += hdsenc.o OBJS-$(CONFIG_HEVC_DEMUXER) += hevcdec.o rawdec.o OBJS-$(CONFIG_HEVC_MUXER) += rawenc.o OBJS-$(CONFIG_HLS_DEMUXER) += hls.o -OBJS-$(CONFIG_HLS_MUXER) += hlsenc.o +OBJS-$(CONFIG_HLS_MUXER) += hlsenc.o hlsplaylist.o OBJS-$(CONFIG_HNM_DEMUXER) += hnm.o OBJS-$(CONFIG_ICO_DEMUXER) += icodec.o OBJS-$(CONFIG_ICO_MUXER) += icoenc.o @@ -292,7 +310,7 @@ OBJS-$(CONFIG_MLV_DEMUXER) += mlvdec.o riffdec.o OBJS-$(CONFIG_MM_DEMUXER) += mm.o OBJS-$(CONFIG_MMF_DEMUXER) += mmf.o OBJS-$(CONFIG_MMF_MUXER) += mmf.o rawenc.o -OBJS-$(CONFIG_MOV_DEMUXER) += mov.o mov_chan.o replaygain.o +OBJS-$(CONFIG_MOV_DEMUXER) += mov.o mov_chan.o mov_esds.o replaygain.o OBJS-$(CONFIG_MOV_MUXER) += movenc.o avc.o hevc.o vpcc.o \ movenchint.o mov_chan.o rtp.o \ movenccenc.o rawutils.o @@ -328,6 +346,7 @@ OBJS-$(CONFIG_MXF_MUXER) += mxfenc.o mxf.o audiointerleave.o OBJS-$(CONFIG_MXG_DEMUXER) += mxg.o OBJS-$(CONFIG_NC_DEMUXER) += ncdec.o OBJS-$(CONFIG_NISTSPHERE_DEMUXER) += nistspheredec.o pcm.o +OBJS-$(CONFIG_NSP_DEMUXER) += nspdec.o OBJS-$(CONFIG_NSV_DEMUXER) += nsvdec.o OBJS-$(CONFIG_NULL_MUXER) += nullenc.o OBJS-$(CONFIG_NUT_DEMUXER) += nutdec.o nut.o isom.o @@ -443,6 +462,8 @@ OBJS-$(CONFIG_S337M_DEMUXER) += s337m.o spdif.o OBJS-$(CONFIG_SAMI_DEMUXER) += samidec.o subtitles.o OBJS-$(CONFIG_SAP_DEMUXER) += sapdec.o OBJS-$(CONFIG_SAP_MUXER) += sapenc.o +OBJS-$(CONFIG_SBC_DEMUXER) += sbcdec.o rawdec.o +OBJS-$(CONFIG_SBC_MUXER) += rawenc.o OBJS-$(CONFIG_SBG_DEMUXER) += sbgdec.o OBJS-$(CONFIG_SCC_DEMUXER) += sccdec.o subtitles.o OBJS-$(CONFIG_SCC_MUXER) += sccenc.o subtitles.o @@ -451,6 +472,7 @@ OBJS-$(CONFIG_SDR2_DEMUXER) += sdr2.o OBJS-$(CONFIG_SDS_DEMUXER) += sdsdec.o OBJS-$(CONFIG_SDX_DEMUXER) += sdxdec.o OBJS-$(CONFIG_SEGAFILM_DEMUXER) += segafilm.o +OBJS-$(CONFIG_SEGAFILM_MUXER) += segafilmenc.o OBJS-$(CONFIG_SEGMENT_MUXER) += segment.o OBJS-$(CONFIG_SHORTEN_DEMUXER) += shortendec.o rawdec.o OBJS-$(CONFIG_SIFF_DEMUXER) += siff.o @@ -471,6 +493,7 @@ OBJS-$(CONFIG_SRT_DEMUXER) += srtdec.o subtitles.o OBJS-$(CONFIG_SRT_MUXER) += srtenc.o OBJS-$(CONFIG_STL_DEMUXER) += stldec.o subtitles.o OBJS-$(CONFIG_STR_DEMUXER) += psxstr.o +OBJS-$(CONFIG_STREAM_SEGMENT_MUXER) += segment.o OBJS-$(CONFIG_SUBVIEWER1_DEMUXER) += subviewer1dec.o subtitles.o OBJS-$(CONFIG_SUBVIEWER_DEMUXER) += subviewerdec.o subtitles.o OBJS-$(CONFIG_SUP_DEMUXER) += supdec.o @@ -491,6 +514,7 @@ OBJS-$(CONFIG_TRUEHD_MUXER) += rawenc.o OBJS-$(CONFIG_TTA_DEMUXER) += tta.o apetag.o img2.o OBJS-$(CONFIG_TTA_MUXER) += ttaenc.o apetag.o img2.o OBJS-$(CONFIG_TTY_DEMUXER) += tty.o sauce.o +OBJS-$(CONFIG_TY_DEMUXER) += ty.o OBJS-$(CONFIG_TXD_DEMUXER) += txd.o OBJS-$(CONFIG_UNCODEDFRAMECRC_MUXER) += uncodedframecrcenc.o framehash.o OBJS-$(CONFIG_V210_DEMUXER) += v210.o @@ -548,7 +572,12 @@ OBJS-$(CONFIG_CHROMAPRINT_MUXER) += chromaprint.o OBJS-$(CONFIG_LIBGME_DEMUXER) += libgme.o OBJS-$(CONFIG_LIBMODPLUG_DEMUXER) += libmodplug.o OBJS-$(CONFIG_LIBOPENMPT_DEMUXER) += libopenmpt.o -OBJS-$(CONFIG_LIBRTMP) += librtmp.o +OBJS-$(CONFIG_LIBRTMP_PROTOCOL) += librtmp.o +OBJS-$(CONFIG_LIBRTMPE_PROTOCOL) += librtmp.o +OBJS-$(CONFIG_LIBRTMPS_PROTOCOL) += librtmp.o +OBJS-$(CONFIG_LIBRTMPT_PROTOCOL) += librtmp.o +OBJS-$(CONFIG_LIBRTMPTE_PROTOCOL) += librtmp.o +OBJS-$(CONFIG_LIBSRT_PROTOCOL) += libsrt.o OBJS-$(CONFIG_LIBSSH_PROTOCOL) += libssh.o OBJS-$(CONFIG_LIBSMBCLIENT_PROTOCOL) += libsmbclient.o @@ -560,7 +589,7 @@ OBJS-$(CONFIG_CACHE_PROTOCOL) += cache.o OBJS-$(CONFIG_CONCAT_PROTOCOL) += concat.o OBJS-$(CONFIG_CRYPTO_PROTOCOL) += crypto.o OBJS-$(CONFIG_DATA_PROTOCOL) += data_uri.o -OBJS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpcrypt.o rtmpdh.o +OBJS-$(CONFIG_FFRTMPCRYPT_PROTOCOL) += rtmpcrypt.o rtmpdigest.o rtmpdh.o OBJS-$(CONFIG_FFRTMPHTTP_PROTOCOL) += rtmphttp.o OBJS-$(CONFIG_FILE_PROTOCOL) += file.o OBJS-$(CONFIG_FTP_PROTOCOL) += ftp.o @@ -575,22 +604,24 @@ OBJS-$(CONFIG_MMSH_PROTOCOL) += mmsh.o mms.o asf.o OBJS-$(CONFIG_MMST_PROTOCOL) += mmst.o mms.o asf.o OBJS-$(CONFIG_PIPE_PROTOCOL) += file.o OBJS-$(CONFIG_PROMPEG_PROTOCOL) += prompeg.o -OBJS-$(CONFIG_RTMP_PROTOCOL) += rtmpproto.o rtmppkt.o -OBJS-$(CONFIG_RTMPE_PROTOCOL) += rtmpproto.o rtmppkt.o -OBJS-$(CONFIG_RTMPS_PROTOCOL) += rtmpproto.o rtmppkt.o -OBJS-$(CONFIG_RTMPT_PROTOCOL) += rtmpproto.o rtmppkt.o -OBJS-$(CONFIG_RTMPTE_PROTOCOL) += rtmpproto.o rtmppkt.o -OBJS-$(CONFIG_RTMPTS_PROTOCOL) += rtmpproto.o rtmppkt.o +OBJS-$(CONFIG_RTMP_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o +OBJS-$(CONFIG_RTMPE_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o +OBJS-$(CONFIG_RTMPS_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o +OBJS-$(CONFIG_RTMPT_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o +OBJS-$(CONFIG_RTMPTE_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o +OBJS-$(CONFIG_RTMPTS_PROTOCOL) += rtmpproto.o rtmpdigest.o rtmppkt.o OBJS-$(CONFIG_RTP_PROTOCOL) += rtpproto.o OBJS-$(CONFIG_SCTP_PROTOCOL) += sctp.o OBJS-$(CONFIG_SRTP_PROTOCOL) += srtpproto.o srtp.o OBJS-$(CONFIG_SUBFILE_PROTOCOL) += subfile.o OBJS-$(CONFIG_TEE_PROTOCOL) += teeproto.o tee_common.o OBJS-$(CONFIG_TCP_PROTOCOL) += tcp.o -OBJS-$(CONFIG_TLS_GNUTLS_PROTOCOL) += tls_gnutls.o tls.o -OBJS-$(CONFIG_TLS_OPENSSL_PROTOCOL) += tls_openssl.o tls.o -OBJS-$(CONFIG_TLS_SCHANNEL_PROTOCOL) += tls_schannel.o tls.o -OBJS-$(CONFIG_TLS_SECURETRANSPORT_PROTOCOL) += tls_securetransport.o tls.o +TLS-OBJS-$(CONFIG_GNUTLS) += tls_gnutls.o +TLS-OBJS-$(CONFIG_LIBTLS) += tls_libtls.o +TLS-OBJS-$(CONFIG_OPENSSL) += tls_openssl.o +TLS-OBJS-$(CONFIG_SECURETRANSPORT) += tls_securetransport.o +TLS-OBJS-$(CONFIG_SCHANNEL) += tls_schannel.o +OBJS-$(CONFIG_TLS_PROTOCOL) += tls.o $(TLS-OBJS-yes) OBJS-$(CONFIG_UDP_PROTOCOL) += udp.o OBJS-$(CONFIG_UDPLITE_PROTOCOL) += udp.o OBJS-$(CONFIG_UNIX_PROTOCOL) += unix.o diff --git a/libavformat/aacdec.c b/libavformat/aacdec.c index 364b33404fc07..685458b9114d0 100644 --- a/libavformat/aacdec.c +++ b/libavformat/aacdec.c @@ -22,8 +22,10 @@ #include "libavutil/intreadwrite.h" #include "avformat.h" +#include "avio_internal.h" #include "internal.h" #include "id3v1.h" +#include "id3v2.h" #include "apetag.h" #define ADTS_HEADER_SIZE 7 @@ -116,13 +118,56 @@ static int adts_aac_read_header(AVFormatContext *s) return 0; } +static int handle_id3(AVFormatContext *s, AVPacket *pkt) +{ + AVDictionary *metadata = NULL; + AVIOContext ioctx; + ID3v2ExtraMeta *id3v2_extra_meta = NULL; + int ret; + + ret = av_append_packet(s->pb, pkt, ff_id3v2_tag_len(pkt->data) - pkt->size); + if (ret < 0) { + av_packet_unref(pkt); + return ret; + } + + ffio_init_context(&ioctx, pkt->data, pkt->size, 0, NULL, NULL, NULL, NULL); + ff_id3v2_read_dict(&ioctx, &metadata, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); + if ((ret = ff_id3v2_parse_priv_dict(&metadata, &id3v2_extra_meta)) < 0) + goto error; + + if (metadata) { + if ((ret = av_dict_copy(&s->metadata, metadata, 0)) < 0) + goto error; + s->event_flags |= AVFMT_EVENT_FLAG_METADATA_UPDATED; + } + +error: + av_packet_unref(pkt); + ff_id3v2_free_extra_meta(&id3v2_extra_meta); + av_dict_free(&metadata); + + return ret; +} + static int adts_aac_read_packet(AVFormatContext *s, AVPacket *pkt) { int ret, fsize; - ret = av_get_packet(s->pb, pkt, ADTS_HEADER_SIZE); + // Parse all the ID3 headers between frames + while (1) { + ret = av_get_packet(s->pb, pkt, FFMAX(ID3v2_HEADER_SIZE, ADTS_HEADER_SIZE)); + if (ret >= ID3v2_HEADER_SIZE && ff_id3v2_match(pkt->data, ID3v2_DEFAULT_MAGIC)) { + if ((ret = handle_id3(s, pkt)) >= 0) { + continue; + } + } + break; + } + if (ret < 0) return ret; + if (ret < ADTS_HEADER_SIZE) { av_packet_unref(pkt); return AVERROR(EIO); @@ -139,7 +184,11 @@ static int adts_aac_read_packet(AVFormatContext *s, AVPacket *pkt) return AVERROR_INVALIDDATA; } - return av_append_packet(s->pb, pkt, fsize - ADTS_HEADER_SIZE); + ret = av_append_packet(s->pb, pkt, fsize - pkt->size); + if (ret < 0) + av_packet_unref(pkt); + + return ret; } AVInputFormat ff_aac_demuxer = { diff --git a/libavformat/ac3dec.c b/libavformat/ac3dec.c index e85b0ac7c9e20..6f423ff7eb2d7 100644 --- a/libavformat/ac3dec.c +++ b/libavformat/ac3dec.c @@ -19,6 +19,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "libavutil/avassert.h" #include "libavutil/crc.h" #include "libavcodec/ac3_parser.h" #include "avformat.h" @@ -28,8 +29,6 @@ static int ac3_eac3_probe(AVProbeData *p, enum AVCodecID expected_codec_id) { int max_frames, first_frames = 0, frames; const uint8_t *buf, *buf2, *end; - AC3HeaderInfo *phdr = NULL; - GetBitContext gbc; enum AVCodecID codec_id = AV_CODEC_ID_AC3; max_frames = 0; @@ -44,39 +43,49 @@ static int ac3_eac3_probe(AVProbeData *p, enum AVCodecID expected_codec_id) for(frames = 0; buf2 < end; frames++) { uint8_t buf3[4096]; - int i; - if(!memcmp(buf2, "\x1\x10\0\0\0\0\0\0", 8)) + uint8_t bitstream_id; + uint16_t frame_size; + int i, ret; + + if(!memcmp(buf2, "\x1\x10\0\0\0\0\0\0", 8)) { + if (buf2 + 16 > end) + break; buf2+=16; + } if (buf[0] == 0x77 && buf[1] == 0x0B) { for(i=0; i<8; i+=2) { buf3[i ] = buf2[i+1]; buf3[i+1] = buf2[i ]; } - init_get_bits(&gbc, buf3, 54); + ret = av_ac3_parse_header(buf3, 8, &bitstream_id, + &frame_size); }else - init_get_bits(&gbc, buf2, 54); - if(avpriv_ac3_parse_header(&gbc, &phdr) < 0) + ret = av_ac3_parse_header(buf2, end - buf2, &bitstream_id, + &frame_size); + if (ret < 0) break; - if(buf2 + phdr->frame_size > end) + if(buf2 + frame_size > end) break; if (buf[0] == 0x77 && buf[1] == 0x0B) { - av_assert0(phdr->frame_size <= sizeof(buf3)); - for(i=8; iframe_size; i+=2) { + av_assert0(frame_size <= sizeof(buf3)); + for(i = 8; i < frame_size; i += 2) { buf3[i ] = buf2[i+1]; buf3[i+1] = buf2[i ]; } + if (av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, buf3 + 2, frame_size - 2)) + break; + } else { + if (av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, buf2 + 2, frame_size - 2)) + break; } - if(av_crc(av_crc_get_table(AV_CRC_16_ANSI), 0, gbc.buffer + 2, phdr->frame_size - 2)) - break; - if (phdr->bitstream_id > 10) + if (bitstream_id > 10) codec_id = AV_CODEC_ID_EAC3; - buf2 += phdr->frame_size; + buf2 += frame_size; } max_frames = FFMAX(max_frames, frames); if(buf == p->buf) first_frames = frames; } - av_freep(&phdr); if(codec_id != expected_codec_id) return 0; // keep this in sync with mp3 probe, both need to avoid // issues with MPEG-files! diff --git a/libavformat/adtsenc.c b/libavformat/adtsenc.c index a046c2f2f43bb..3c2840c6abefb 100644 --- a/libavformat/adtsenc.c +++ b/libavformat/adtsenc.c @@ -85,7 +85,7 @@ static int adts_decode_extradata(AVFormatContext *s, ADTSContext *adts, const ui init_put_bits(&pb, adts->pce_data, MAX_PCE_SIZE); put_bits(&pb, 3, 5); //ID_PCE - adts->pce_size = (avpriv_copy_pce_data(&pb, &gb) + 3) / 8; + adts->pce_size = (ff_copy_pce_data(&pb, &gb) + 3) / 8; flush_put_bits(&pb); } @@ -94,13 +94,15 @@ static int adts_decode_extradata(AVFormatContext *s, ADTSContext *adts, const ui return 0; } -static int adts_write_header(AVFormatContext *s) +static int adts_init(AVFormatContext *s) { ADTSContext *adts = s->priv_data; AVCodecParameters *par = s->streams[0]->codecpar; - if (adts->id3v2tag) - ff_id3v2_write_simple(s, 4, ID3v2_DEFAULT_MAGIC); + if (par->codec_id != AV_CODEC_ID_AAC) { + av_log(s, AV_LOG_ERROR, "Only AAC streams can be muxed by the ADTS muxer\n"); + return AVERROR(EINVAL); + } if (par->extradata_size > 0) return adts_decode_extradata(s, adts, par->extradata, par->extradata_size); @@ -108,6 +110,16 @@ static int adts_write_header(AVFormatContext *s) return 0; } +static int adts_write_header(AVFormatContext *s) +{ + ADTSContext *adts = s->priv_data; + + if (adts->id3v2tag) + ff_id3v2_write_simple(s, 4, ID3v2_DEFAULT_MAGIC); + + return 0; +} + static int adts_write_frame_header(ADTSContext *ctx, uint8_t *buf, int size, int pce_size) { @@ -220,6 +232,7 @@ AVOutputFormat ff_adts_muxer = { .priv_data_size = sizeof(ADTSContext), .audio_codec = AV_CODEC_ID_AAC, .video_codec = AV_CODEC_ID_NONE, + .init = adts_init, .write_header = adts_write_header, .write_packet = adts_write_packet, .write_trailer = adts_write_trailer, diff --git a/libavformat/aiffdec.c b/libavformat/aiffdec.c index 99e05c78ecac3..7c701e0c70076 100644 --- a/libavformat/aiffdec.c +++ b/libavformat/aiffdec.c @@ -81,11 +81,10 @@ static void get_meta(AVFormatContext *s, const char *key, int size) av_free(str); return; } - size += (size&1)-res; + size -= res; str[res] = 0; av_dict_set(&s->metadata, key, str, AV_DICT_DONT_STRDUP_VAL); - }else - size+= size&1; + } avio_skip(s->pb, size); } @@ -325,6 +324,16 @@ static int aiff_read_header(AVFormatContext *s) if(ff_mov_read_chan(s, pb, st, size) < 0) return AVERROR_INVALIDDATA; break; + case MKTAG('A','P','C','M'): /* XA ADPCM compressed sound chunk */ + st->codecpar->codec_id = AV_CODEC_ID_ADPCM_XA; + aiff->data_end = avio_tell(pb) + size; + offset = avio_tell(pb) + 8; + /* This field is unknown and its data seems to be irrelevant */ + avio_rb32(pb); + st->codecpar->block_align = avio_rb32(pb); + + goto got_sound; + break; case 0: if (offset > 0 && st->codecpar->block_align) // COMM && SSND goto got_sound; diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 405ddb5ad9f00..2e733d9282f53 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -20,376 +20,603 @@ */ #include "libavutil/thread.h" +#include "libavformat/internal.h" #include "avformat.h" #include "rtp.h" #include "rdt.h" #include "url.h" #include "version.h" -#define REGISTER_MUXER(X, x) \ - { \ - extern AVOutputFormat ff_##x##_muxer; \ - if (CONFIG_##X##_MUXER) \ - av_register_output_format(&ff_##x##_muxer); \ +/* (de)muxers */ +extern AVOutputFormat ff_a64_muxer; +extern AVInputFormat ff_aa_demuxer; +extern AVInputFormat ff_aac_demuxer; +extern AVInputFormat ff_ac3_demuxer; +extern AVOutputFormat ff_ac3_muxer; +extern AVInputFormat ff_acm_demuxer; +extern AVInputFormat ff_act_demuxer; +extern AVInputFormat ff_adf_demuxer; +extern AVInputFormat ff_adp_demuxer; +extern AVInputFormat ff_ads_demuxer; +extern AVOutputFormat ff_adts_muxer; +extern AVInputFormat ff_adx_demuxer; +extern AVOutputFormat ff_adx_muxer; +extern AVInputFormat ff_aea_demuxer; +extern AVInputFormat ff_afc_demuxer; +extern AVInputFormat ff_aiff_demuxer; +extern AVOutputFormat ff_aiff_muxer; +extern AVInputFormat ff_aix_demuxer; +extern AVInputFormat ff_amr_demuxer; +extern AVOutputFormat ff_amr_muxer; +extern AVInputFormat ff_amrnb_demuxer; +extern AVInputFormat ff_amrwb_demuxer; +extern AVInputFormat ff_anm_demuxer; +extern AVInputFormat ff_apc_demuxer; +extern AVInputFormat ff_ape_demuxer; +extern AVInputFormat ff_apng_demuxer; +extern AVOutputFormat ff_apng_muxer; +extern AVInputFormat ff_aptx_demuxer; +extern AVOutputFormat ff_aptx_muxer; +extern AVInputFormat ff_aptx_hd_demuxer; +extern AVOutputFormat ff_aptx_hd_muxer; +extern AVInputFormat ff_aqtitle_demuxer; +extern AVInputFormat ff_asf_demuxer; +extern AVOutputFormat ff_asf_muxer; +extern AVInputFormat ff_asf_o_demuxer; +extern AVInputFormat ff_ass_demuxer; +extern AVOutputFormat ff_ass_muxer; +extern AVInputFormat ff_ast_demuxer; +extern AVOutputFormat ff_ast_muxer; +extern AVOutputFormat ff_asf_stream_muxer; +extern AVInputFormat ff_au_demuxer; +extern AVOutputFormat ff_au_muxer; +extern AVInputFormat ff_avi_demuxer; +extern AVOutputFormat ff_avi_muxer; +extern AVInputFormat ff_avisynth_demuxer; +extern AVOutputFormat ff_avm2_muxer; +extern AVInputFormat ff_avr_demuxer; +extern AVInputFormat ff_avs_demuxer; +extern AVInputFormat ff_bethsoftvid_demuxer; +extern AVInputFormat ff_bfi_demuxer; +extern AVInputFormat ff_bintext_demuxer; +extern AVInputFormat ff_bink_demuxer; +extern AVInputFormat ff_bit_demuxer; +extern AVOutputFormat ff_bit_muxer; +extern AVInputFormat ff_bmv_demuxer; +extern AVInputFormat ff_bfstm_demuxer; +extern AVInputFormat ff_brstm_demuxer; +extern AVInputFormat ff_boa_demuxer; +extern AVInputFormat ff_c93_demuxer; +extern AVInputFormat ff_caf_demuxer; +extern AVOutputFormat ff_caf_muxer; +extern AVInputFormat ff_cavsvideo_demuxer; +extern AVOutputFormat ff_cavsvideo_muxer; +extern AVInputFormat ff_cdg_demuxer; +extern AVInputFormat ff_cdxl_demuxer; +extern AVInputFormat ff_cine_demuxer; +extern AVInputFormat ff_codec2_demuxer; +extern AVOutputFormat ff_codec2_muxer; +extern AVInputFormat ff_codec2raw_demuxer; +extern AVOutputFormat ff_codec2raw_muxer; +extern AVInputFormat ff_concat_demuxer; +extern AVOutputFormat ff_crc_muxer; +extern AVInputFormat ff_dash_demuxer; +extern AVOutputFormat ff_dash_muxer; +extern AVInputFormat ff_data_demuxer; +extern AVOutputFormat ff_data_muxer; +extern AVInputFormat ff_daud_demuxer; +extern AVOutputFormat ff_daud_muxer; +extern AVInputFormat ff_dcstr_demuxer; +extern AVInputFormat ff_dfa_demuxer; +extern AVInputFormat ff_dirac_demuxer; +extern AVOutputFormat ff_dirac_muxer; +extern AVInputFormat ff_dnxhd_demuxer; +extern AVOutputFormat ff_dnxhd_muxer; +extern AVInputFormat ff_dsf_demuxer; +extern AVInputFormat ff_dsicin_demuxer; +extern AVInputFormat ff_dss_demuxer; +extern AVInputFormat ff_dts_demuxer; +extern AVOutputFormat ff_dts_muxer; +extern AVInputFormat ff_dtshd_demuxer; +extern AVInputFormat ff_dv_demuxer; +extern AVOutputFormat ff_dv_muxer; +extern AVInputFormat ff_dvbsub_demuxer; +extern AVInputFormat ff_dvbtxt_demuxer; +extern AVInputFormat ff_dxa_demuxer; +extern AVInputFormat ff_ea_demuxer; +extern AVInputFormat ff_ea_cdata_demuxer; +extern AVInputFormat ff_eac3_demuxer; +extern AVOutputFormat ff_eac3_muxer; +extern AVInputFormat ff_epaf_demuxer; +extern AVOutputFormat ff_f4v_muxer; +extern AVInputFormat ff_ffmetadata_demuxer; +extern AVOutputFormat ff_ffmetadata_muxer; +extern AVOutputFormat ff_fifo_muxer; +extern AVOutputFormat ff_fifo_test_muxer; +extern AVInputFormat ff_filmstrip_demuxer; +extern AVOutputFormat ff_filmstrip_muxer; +extern AVInputFormat ff_fits_demuxer; +extern AVOutputFormat ff_fits_muxer; +extern AVInputFormat ff_flac_demuxer; +extern AVOutputFormat ff_flac_muxer; +extern AVInputFormat ff_flic_demuxer; +extern AVInputFormat ff_flv_demuxer; +extern AVOutputFormat ff_flv_muxer; +extern AVInputFormat ff_live_flv_demuxer; +extern AVInputFormat ff_fourxm_demuxer; +extern AVOutputFormat ff_framecrc_muxer; +extern AVOutputFormat ff_framehash_muxer; +extern AVOutputFormat ff_framemd5_muxer; +extern AVInputFormat ff_frm_demuxer; +extern AVInputFormat ff_fsb_demuxer; +extern AVInputFormat ff_g722_demuxer; +extern AVOutputFormat ff_g722_muxer; +extern AVInputFormat ff_g723_1_demuxer; +extern AVOutputFormat ff_g723_1_muxer; +extern AVInputFormat ff_g726_demuxer; +extern AVOutputFormat ff_g726_muxer; +extern AVInputFormat ff_g726le_demuxer; +extern AVOutputFormat ff_g726le_muxer; +extern AVInputFormat ff_g729_demuxer; +extern AVInputFormat ff_gdv_demuxer; +extern AVInputFormat ff_genh_demuxer; +extern AVInputFormat ff_gif_demuxer; +extern AVOutputFormat ff_gif_muxer; +extern AVInputFormat ff_gsm_demuxer; +extern AVOutputFormat ff_gsm_muxer; +extern AVInputFormat ff_gxf_demuxer; +extern AVOutputFormat ff_gxf_muxer; +extern AVInputFormat ff_h261_demuxer; +extern AVOutputFormat ff_h261_muxer; +extern AVInputFormat ff_h263_demuxer; +extern AVOutputFormat ff_h263_muxer; +extern AVInputFormat ff_h264_demuxer; +extern AVOutputFormat ff_h264_muxer; +extern AVOutputFormat ff_hash_muxer; +extern AVOutputFormat ff_hds_muxer; +extern AVInputFormat ff_hevc_demuxer; +extern AVOutputFormat ff_hevc_muxer; +extern AVInputFormat ff_hls_demuxer; +extern AVOutputFormat ff_hls_muxer; +extern AVInputFormat ff_hnm_demuxer; +extern AVInputFormat ff_ico_demuxer; +extern AVOutputFormat ff_ico_muxer; +extern AVInputFormat ff_idcin_demuxer; +extern AVInputFormat ff_idf_demuxer; +extern AVInputFormat ff_iff_demuxer; +extern AVInputFormat ff_ilbc_demuxer; +extern AVOutputFormat ff_ilbc_muxer; +extern AVInputFormat ff_image2_demuxer; +extern AVOutputFormat ff_image2_muxer; +extern AVInputFormat ff_image2pipe_demuxer; +extern AVOutputFormat ff_image2pipe_muxer; +extern AVInputFormat ff_image2_alias_pix_demuxer; +extern AVInputFormat ff_image2_brender_pix_demuxer; +extern AVInputFormat ff_ingenient_demuxer; +extern AVInputFormat ff_ipmovie_demuxer; +extern AVOutputFormat ff_ipod_muxer; +extern AVInputFormat ff_ircam_demuxer; +extern AVOutputFormat ff_ircam_muxer; +extern AVOutputFormat ff_ismv_muxer; +extern AVInputFormat ff_iss_demuxer; +extern AVInputFormat ff_iv8_demuxer; +extern AVInputFormat ff_ivf_demuxer; +extern AVOutputFormat ff_ivf_muxer; +extern AVInputFormat ff_ivr_demuxer; +extern AVInputFormat ff_jacosub_demuxer; +extern AVOutputFormat ff_jacosub_muxer; +extern AVInputFormat ff_jv_demuxer; +extern AVOutputFormat ff_latm_muxer; +extern AVInputFormat ff_lmlm4_demuxer; +extern AVInputFormat ff_loas_demuxer; +extern AVInputFormat ff_lrc_demuxer; +extern AVOutputFormat ff_lrc_muxer; +extern AVInputFormat ff_lvf_demuxer; +extern AVInputFormat ff_lxf_demuxer; +extern AVInputFormat ff_m4v_demuxer; +extern AVOutputFormat ff_m4v_muxer; +extern AVOutputFormat ff_md5_muxer; +extern AVInputFormat ff_matroska_demuxer; +extern AVOutputFormat ff_matroska_muxer; +extern AVOutputFormat ff_matroska_audio_muxer; +extern AVInputFormat ff_mgsts_demuxer; +extern AVInputFormat ff_microdvd_demuxer; +extern AVOutputFormat ff_microdvd_muxer; +extern AVInputFormat ff_mjpeg_demuxer; +extern AVOutputFormat ff_mjpeg_muxer; +extern AVInputFormat ff_mjpeg_2000_demuxer; +extern AVInputFormat ff_mlp_demuxer; +extern AVOutputFormat ff_mlp_muxer; +extern AVInputFormat ff_mlv_demuxer; +extern AVInputFormat ff_mm_demuxer; +extern AVInputFormat ff_mmf_demuxer; +extern AVOutputFormat ff_mmf_muxer; +extern AVInputFormat ff_mov_demuxer; +extern AVOutputFormat ff_mov_muxer; +extern AVOutputFormat ff_mp2_muxer; +extern AVInputFormat ff_mp3_demuxer; +extern AVOutputFormat ff_mp3_muxer; +extern AVOutputFormat ff_mp4_muxer; +extern AVInputFormat ff_mpc_demuxer; +extern AVInputFormat ff_mpc8_demuxer; +extern AVOutputFormat ff_mpeg1system_muxer; +extern AVOutputFormat ff_mpeg1vcd_muxer; +extern AVOutputFormat ff_mpeg1video_muxer; +extern AVOutputFormat ff_mpeg2dvd_muxer; +extern AVOutputFormat ff_mpeg2svcd_muxer; +extern AVOutputFormat ff_mpeg2video_muxer; +extern AVOutputFormat ff_mpeg2vob_muxer; +extern AVInputFormat ff_mpegps_demuxer; +extern AVInputFormat ff_mpegts_demuxer; +extern AVOutputFormat ff_mpegts_muxer; +extern AVInputFormat ff_mpegtsraw_demuxer; +extern AVInputFormat ff_mpegvideo_demuxer; +extern AVInputFormat ff_mpjpeg_demuxer; +extern AVOutputFormat ff_mpjpeg_muxer; +extern AVInputFormat ff_mpl2_demuxer; +extern AVInputFormat ff_mpsub_demuxer; +extern AVInputFormat ff_msf_demuxer; +extern AVInputFormat ff_msnwc_tcp_demuxer; +extern AVInputFormat ff_mtaf_demuxer; +extern AVInputFormat ff_mtv_demuxer; +extern AVInputFormat ff_musx_demuxer; +extern AVInputFormat ff_mv_demuxer; +extern AVInputFormat ff_mvi_demuxer; +extern AVInputFormat ff_mxf_demuxer; +extern AVOutputFormat ff_mxf_muxer; +extern AVOutputFormat ff_mxf_d10_muxer; +extern AVOutputFormat ff_mxf_opatom_muxer; +extern AVInputFormat ff_mxg_demuxer; +extern AVInputFormat ff_nc_demuxer; +extern AVInputFormat ff_nistsphere_demuxer; +extern AVInputFormat ff_nsp_demuxer; +extern AVInputFormat ff_nsv_demuxer; +extern AVOutputFormat ff_null_muxer; +extern AVInputFormat ff_nut_demuxer; +extern AVOutputFormat ff_nut_muxer; +extern AVInputFormat ff_nuv_demuxer; +extern AVOutputFormat ff_oga_muxer; +extern AVInputFormat ff_ogg_demuxer; +extern AVOutputFormat ff_ogg_muxer; +extern AVOutputFormat ff_ogv_muxer; +extern AVInputFormat ff_oma_demuxer; +extern AVOutputFormat ff_oma_muxer; +extern AVOutputFormat ff_opus_muxer; +extern AVInputFormat ff_paf_demuxer; +extern AVInputFormat ff_pcm_alaw_demuxer; +extern AVOutputFormat ff_pcm_alaw_muxer; +extern AVInputFormat ff_pcm_mulaw_demuxer; +extern AVOutputFormat ff_pcm_mulaw_muxer; +extern AVInputFormat ff_pcm_f64be_demuxer; +extern AVOutputFormat ff_pcm_f64be_muxer; +extern AVInputFormat ff_pcm_f64le_demuxer; +extern AVOutputFormat ff_pcm_f64le_muxer; +extern AVInputFormat ff_pcm_f32be_demuxer; +extern AVOutputFormat ff_pcm_f32be_muxer; +extern AVInputFormat ff_pcm_f32le_demuxer; +extern AVOutputFormat ff_pcm_f32le_muxer; +extern AVInputFormat ff_pcm_s32be_demuxer; +extern AVOutputFormat ff_pcm_s32be_muxer; +extern AVInputFormat ff_pcm_s32le_demuxer; +extern AVOutputFormat ff_pcm_s32le_muxer; +extern AVInputFormat ff_pcm_s24be_demuxer; +extern AVOutputFormat ff_pcm_s24be_muxer; +extern AVInputFormat ff_pcm_s24le_demuxer; +extern AVOutputFormat ff_pcm_s24le_muxer; +extern AVInputFormat ff_pcm_s16be_demuxer; +extern AVOutputFormat ff_pcm_s16be_muxer; +extern AVInputFormat ff_pcm_s16le_demuxer; +extern AVOutputFormat ff_pcm_s16le_muxer; +extern AVInputFormat ff_pcm_s8_demuxer; +extern AVOutputFormat ff_pcm_s8_muxer; +extern AVInputFormat ff_pcm_u32be_demuxer; +extern AVOutputFormat ff_pcm_u32be_muxer; +extern AVInputFormat ff_pcm_u32le_demuxer; +extern AVOutputFormat ff_pcm_u32le_muxer; +extern AVInputFormat ff_pcm_u24be_demuxer; +extern AVOutputFormat ff_pcm_u24be_muxer; +extern AVInputFormat ff_pcm_u24le_demuxer; +extern AVOutputFormat ff_pcm_u24le_muxer; +extern AVInputFormat ff_pcm_u16be_demuxer; +extern AVOutputFormat ff_pcm_u16be_muxer; +extern AVInputFormat ff_pcm_u16le_demuxer; +extern AVOutputFormat ff_pcm_u16le_muxer; +extern AVInputFormat ff_pcm_u8_demuxer; +extern AVOutputFormat ff_pcm_u8_muxer; +extern AVInputFormat ff_pjs_demuxer; +extern AVInputFormat ff_pmp_demuxer; +extern AVOutputFormat ff_psp_muxer; +extern AVInputFormat ff_pva_demuxer; +extern AVInputFormat ff_pvf_demuxer; +extern AVInputFormat ff_qcp_demuxer; +extern AVInputFormat ff_r3d_demuxer; +extern AVInputFormat ff_rawvideo_demuxer; +extern AVOutputFormat ff_rawvideo_muxer; +extern AVInputFormat ff_realtext_demuxer; +extern AVInputFormat ff_redspark_demuxer; +extern AVInputFormat ff_rl2_demuxer; +extern AVInputFormat ff_rm_demuxer; +extern AVOutputFormat ff_rm_muxer; +extern AVInputFormat ff_roq_demuxer; +extern AVOutputFormat ff_roq_muxer; +extern AVInputFormat ff_rpl_demuxer; +extern AVInputFormat ff_rsd_demuxer; +extern AVInputFormat ff_rso_demuxer; +extern AVOutputFormat ff_rso_muxer; +extern AVInputFormat ff_rtp_demuxer; +extern AVOutputFormat ff_rtp_muxer; +extern AVOutputFormat ff_rtp_mpegts_muxer; +extern AVInputFormat ff_rtsp_demuxer; +extern AVOutputFormat ff_rtsp_muxer; +extern AVInputFormat ff_s337m_demuxer; +extern AVInputFormat ff_sami_demuxer; +extern AVInputFormat ff_sap_demuxer; +extern AVOutputFormat ff_sap_muxer; +extern AVInputFormat ff_sbc_demuxer; +extern AVOutputFormat ff_sbc_muxer; +extern AVInputFormat ff_sbg_demuxer; +extern AVInputFormat ff_scc_demuxer; +extern AVOutputFormat ff_scc_muxer; +extern AVInputFormat ff_sdp_demuxer; +extern AVInputFormat ff_sdr2_demuxer; +extern AVInputFormat ff_sds_demuxer; +extern AVInputFormat ff_sdx_demuxer; +extern AVInputFormat ff_segafilm_demuxer; +extern AVOutputFormat ff_segafilm_muxer; +extern AVOutputFormat ff_segment_muxer; +extern AVOutputFormat ff_stream_segment_muxer; +extern AVInputFormat ff_shorten_demuxer; +extern AVInputFormat ff_siff_demuxer; +extern AVOutputFormat ff_singlejpeg_muxer; +extern AVInputFormat ff_sln_demuxer; +extern AVInputFormat ff_smacker_demuxer; +extern AVInputFormat ff_smjpeg_demuxer; +extern AVOutputFormat ff_smjpeg_muxer; +extern AVOutputFormat ff_smoothstreaming_muxer; +extern AVInputFormat ff_smush_demuxer; +extern AVInputFormat ff_sol_demuxer; +extern AVInputFormat ff_sox_demuxer; +extern AVOutputFormat ff_sox_muxer; +extern AVOutputFormat ff_spx_muxer; +extern AVInputFormat ff_spdif_demuxer; +extern AVOutputFormat ff_spdif_muxer; +extern AVInputFormat ff_srt_demuxer; +extern AVOutputFormat ff_srt_muxer; +extern AVInputFormat ff_str_demuxer; +extern AVInputFormat ff_stl_demuxer; +extern AVInputFormat ff_subviewer1_demuxer; +extern AVInputFormat ff_subviewer_demuxer; +extern AVInputFormat ff_sup_demuxer; +extern AVOutputFormat ff_sup_muxer; +extern AVInputFormat ff_svag_demuxer; +extern AVInputFormat ff_swf_demuxer; +extern AVOutputFormat ff_swf_muxer; +extern AVInputFormat ff_tak_demuxer; +extern AVOutputFormat ff_tee_muxer; +extern AVInputFormat ff_tedcaptions_demuxer; +extern AVOutputFormat ff_tg2_muxer; +extern AVOutputFormat ff_tgp_muxer; +extern AVInputFormat ff_thp_demuxer; +extern AVInputFormat ff_threedostr_demuxer; +extern AVInputFormat ff_tiertexseq_demuxer; +extern AVOutputFormat ff_mkvtimestamp_v2_muxer; +extern AVInputFormat ff_tmv_demuxer; +extern AVInputFormat ff_truehd_demuxer; +extern AVOutputFormat ff_truehd_muxer; +extern AVInputFormat ff_tta_demuxer; +extern AVOutputFormat ff_tta_muxer; +extern AVInputFormat ff_txd_demuxer; +extern AVInputFormat ff_tty_demuxer; +extern AVInputFormat ff_ty_demuxer; +extern AVOutputFormat ff_uncodedframecrc_muxer; +extern AVInputFormat ff_v210_demuxer; +extern AVInputFormat ff_v210x_demuxer; +extern AVInputFormat ff_vag_demuxer; +extern AVInputFormat ff_vc1_demuxer; +extern AVOutputFormat ff_vc1_muxer; +extern AVInputFormat ff_vc1t_demuxer; +extern AVOutputFormat ff_vc1t_muxer; +extern AVInputFormat ff_vivo_demuxer; +extern AVInputFormat ff_vmd_demuxer; +extern AVInputFormat ff_vobsub_demuxer; +extern AVInputFormat ff_voc_demuxer; +extern AVOutputFormat ff_voc_muxer; +extern AVInputFormat ff_vpk_demuxer; +extern AVInputFormat ff_vplayer_demuxer; +extern AVInputFormat ff_vqf_demuxer; +extern AVInputFormat ff_w64_demuxer; +extern AVOutputFormat ff_w64_muxer; +extern AVInputFormat ff_wav_demuxer; +extern AVOutputFormat ff_wav_muxer; +extern AVInputFormat ff_wc3_demuxer; +extern AVOutputFormat ff_webm_muxer; +extern AVInputFormat ff_webm_dash_manifest_demuxer; +extern AVOutputFormat ff_webm_dash_manifest_muxer; +extern AVOutputFormat ff_webm_chunk_muxer; +extern AVOutputFormat ff_webp_muxer; +extern AVInputFormat ff_webvtt_demuxer; +extern AVOutputFormat ff_webvtt_muxer; +extern AVInputFormat ff_wsaud_demuxer; +extern AVInputFormat ff_wsd_demuxer; +extern AVInputFormat ff_wsvqa_demuxer; +extern AVInputFormat ff_wtv_demuxer; +extern AVOutputFormat ff_wtv_muxer; +extern AVInputFormat ff_wve_demuxer; +extern AVInputFormat ff_wv_demuxer; +extern AVOutputFormat ff_wv_muxer; +extern AVInputFormat ff_xa_demuxer; +extern AVInputFormat ff_xbin_demuxer; +extern AVInputFormat ff_xmv_demuxer; +extern AVInputFormat ff_xvag_demuxer; +extern AVInputFormat ff_xwma_demuxer; +extern AVInputFormat ff_yop_demuxer; +extern AVInputFormat ff_yuv4mpegpipe_demuxer; +extern AVOutputFormat ff_yuv4mpegpipe_muxer; +extern AVInputFormat ff_ijklivehook_demuxer; +extern AVInputFormat ff_ijklas_demuxer; +/* image demuxers */ +extern AVInputFormat ff_image_bmp_pipe_demuxer; +extern AVInputFormat ff_image_dds_pipe_demuxer; +extern AVInputFormat ff_image_dpx_pipe_demuxer; +extern AVInputFormat ff_image_exr_pipe_demuxer; +extern AVInputFormat ff_image_j2k_pipe_demuxer; +extern AVInputFormat ff_image_jpeg_pipe_demuxer; +extern AVInputFormat ff_image_jpegls_pipe_demuxer; +extern AVInputFormat ff_image_pam_pipe_demuxer; +extern AVInputFormat ff_image_pbm_pipe_demuxer; +extern AVInputFormat ff_image_pcx_pipe_demuxer; +extern AVInputFormat ff_image_pgmyuv_pipe_demuxer; +extern AVInputFormat ff_image_pgm_pipe_demuxer; +extern AVInputFormat ff_image_pictor_pipe_demuxer; +extern AVInputFormat ff_image_png_pipe_demuxer; +extern AVInputFormat ff_image_ppm_pipe_demuxer; +extern AVInputFormat ff_image_psd_pipe_demuxer; +extern AVInputFormat ff_image_qdraw_pipe_demuxer; +extern AVInputFormat ff_image_sgi_pipe_demuxer; +extern AVInputFormat ff_image_svg_pipe_demuxer; +extern AVInputFormat ff_image_sunrast_pipe_demuxer; +extern AVInputFormat ff_image_tiff_pipe_demuxer; +extern AVInputFormat ff_image_webp_pipe_demuxer; +extern AVInputFormat ff_image_xpm_pipe_demuxer; + +/* external libraries */ +extern AVOutputFormat ff_chromaprint_muxer; +extern AVInputFormat ff_libgme_demuxer; +extern AVInputFormat ff_libmodplug_demuxer; +extern AVInputFormat ff_libopenmpt_demuxer; + +#include "libavformat/muxer_list.c" +#include "libavformat/demuxer_list.c" + +static const AVInputFormat * const *indev_list = NULL; +static const AVOutputFormat * const *outdev_list = NULL; + +const AVOutputFormat *av_muxer_iterate(void **opaque) +{ + static const uintptr_t size = sizeof(muxer_list)/sizeof(muxer_list[0]) - 1; + uintptr_t i = (uintptr_t)*opaque; + const AVOutputFormat *f = NULL; + + if (i < size) { + f = muxer_list[i]; + } else if (indev_list) { + f = outdev_list[i - size]; } -#define REGISTER_DEMUXER(X, x) \ - { \ - extern AVInputFormat ff_##x##_demuxer; \ - if (CONFIG_##X##_DEMUXER) \ - av_register_input_format(&ff_##x##_demuxer); \ + if (f) + *opaque = (void*)(i + 1); + return f; +} + +const AVInputFormat *av_demuxer_iterate(void **opaque) +{ + static const uintptr_t size = sizeof(demuxer_list)/sizeof(demuxer_list[0]) - 1; + uintptr_t i = (uintptr_t)*opaque; + const AVInputFormat *f = NULL; + + if (i < size) { + f = demuxer_list[i]; + } else if (outdev_list) { + f = indev_list[i - size]; } -#define REGISTER_MUXDEMUX(X, x) REGISTER_MUXER(X, x); REGISTER_DEMUXER(X, x) + if (f) + *opaque = (void*)(i + 1); + return f; +} -static void register_all(void) +static AVMutex avpriv_register_devices_mutex = AV_MUTEX_INITIALIZER; + +#if FF_API_NEXT +FF_DISABLE_DEPRECATION_WARNINGS +static AVOnce av_format_next_init = AV_ONCE_INIT; + +static void av_format_init_next(void) { - avcodec_register_all(); + AVOutputFormat *prevout = NULL, *out; + AVInputFormat *previn = NULL, *in; - /* (de)muxers */ - REGISTER_MUXER (A64, a64); - REGISTER_DEMUXER (AA, aa); - REGISTER_DEMUXER (AAC, aac); - REGISTER_MUXDEMUX(AC3, ac3); - REGISTER_DEMUXER (ACM, acm); - REGISTER_DEMUXER (ACT, act); - REGISTER_DEMUXER (ADF, adf); - REGISTER_DEMUXER (ADP, adp); - REGISTER_DEMUXER (ADS, ads); - REGISTER_MUXER (ADTS, adts); - REGISTER_MUXDEMUX(ADX, adx); - REGISTER_DEMUXER (AEA, aea); - REGISTER_DEMUXER (AFC, afc); - REGISTER_MUXDEMUX(AIFF, aiff); - REGISTER_DEMUXER (AIX, aix); - REGISTER_MUXDEMUX(AMR, amr); - REGISTER_DEMUXER (ANM, anm); - REGISTER_DEMUXER (APC, apc); - REGISTER_DEMUXER (APE, ape); - REGISTER_MUXDEMUX(APNG, apng); - REGISTER_DEMUXER (AQTITLE, aqtitle); - REGISTER_MUXDEMUX(ASF, asf); - REGISTER_DEMUXER (ASF_O, asf_o); - REGISTER_MUXDEMUX(ASS, ass); - REGISTER_MUXDEMUX(AST, ast); - REGISTER_MUXER (ASF_STREAM, asf_stream); - REGISTER_MUXDEMUX(AU, au); - REGISTER_MUXDEMUX(AVI, avi); - REGISTER_DEMUXER (AVISYNTH, avisynth); - REGISTER_MUXER (AVM2, avm2); - REGISTER_DEMUXER (AVR, avr); - REGISTER_DEMUXER (AVS, avs); - REGISTER_DEMUXER (BETHSOFTVID, bethsoftvid); - REGISTER_DEMUXER (BFI, bfi); - REGISTER_DEMUXER (BINTEXT, bintext); - REGISTER_DEMUXER (BINK, bink); - REGISTER_MUXDEMUX(BIT, bit); - REGISTER_DEMUXER (BMV, bmv); - REGISTER_DEMUXER (BFSTM, bfstm); - REGISTER_DEMUXER (BRSTM, brstm); - REGISTER_DEMUXER (BOA, boa); - REGISTER_DEMUXER (C93, c93); - REGISTER_MUXDEMUX(CAF, caf); - REGISTER_MUXDEMUX(CAVSVIDEO, cavsvideo); - REGISTER_DEMUXER (CDG, cdg); - REGISTER_DEMUXER (CDXL, cdxl); - REGISTER_DEMUXER (CINE, cine); - REGISTER_DEMUXER (CONCAT, concat); - REGISTER_MUXER (CRC, crc); - REGISTER_MUXDEMUX(DASH, dash); - REGISTER_MUXDEMUX(DATA, data); - REGISTER_MUXDEMUX(DAUD, daud); - REGISTER_DEMUXER (DCSTR, dcstr); - REGISTER_DEMUXER (DFA, dfa); - REGISTER_MUXDEMUX(DIRAC, dirac); - REGISTER_MUXDEMUX(DNXHD, dnxhd); - REGISTER_DEMUXER (DSF, dsf); - REGISTER_DEMUXER (DSICIN, dsicin); - REGISTER_DEMUXER (DSS, dss); - REGISTER_MUXDEMUX(DTS, dts); - REGISTER_DEMUXER (DTSHD, dtshd); - REGISTER_MUXDEMUX(DV, dv); - REGISTER_DEMUXER (DVBSUB, dvbsub); - REGISTER_DEMUXER (DVBTXT, dvbtxt); - REGISTER_DEMUXER (DXA, dxa); - REGISTER_DEMUXER (EA, ea); - REGISTER_DEMUXER (EA_CDATA, ea_cdata); - REGISTER_MUXDEMUX(EAC3, eac3); - REGISTER_DEMUXER (EPAF, epaf); - REGISTER_MUXER (F4V, f4v); - REGISTER_MUXDEMUX(FFM, ffm); - REGISTER_MUXDEMUX(FFMETADATA, ffmetadata); - REGISTER_MUXER (FIFO, fifo); - REGISTER_MUXDEMUX(FILMSTRIP, filmstrip); - REGISTER_MUXDEMUX(FITS, fits); - REGISTER_MUXDEMUX(FLAC, flac); - REGISTER_DEMUXER (FLIC, flic); - REGISTER_MUXDEMUX(FLV, flv); - REGISTER_DEMUXER (LIVE_FLV, live_flv); - REGISTER_DEMUXER (FOURXM, fourxm); - REGISTER_MUXER (FRAMECRC, framecrc); - REGISTER_MUXER (FRAMEHASH, framehash); - REGISTER_MUXER (FRAMEMD5, framemd5); - REGISTER_DEMUXER (FRM, frm); - REGISTER_DEMUXER (FSB, fsb); - REGISTER_MUXDEMUX(G722, g722); - REGISTER_MUXDEMUX(G723_1, g723_1); - REGISTER_MUXDEMUX(G726, g726); - REGISTER_MUXDEMUX(G726LE, g726le); - REGISTER_DEMUXER (G729, g729); - REGISTER_DEMUXER (GDV, gdv); - REGISTER_DEMUXER (GENH, genh); - REGISTER_MUXDEMUX(GIF, gif); - REGISTER_MUXDEMUX(GSM, gsm); - REGISTER_MUXDEMUX(GXF, gxf); - REGISTER_MUXDEMUX(H261, h261); - REGISTER_MUXDEMUX(H263, h263); - REGISTER_MUXDEMUX(H264, h264); - REGISTER_MUXER (HASH, hash); - REGISTER_MUXER (HDS, hds); - REGISTER_MUXDEMUX(HEVC, hevc); - REGISTER_MUXDEMUX(HLS, hls); - REGISTER_DEMUXER (HNM, hnm); - REGISTER_MUXDEMUX(ICO, ico); - REGISTER_DEMUXER (IDCIN, idcin); - REGISTER_DEMUXER (IDF, idf); - REGISTER_DEMUXER (IFF, iff); - REGISTER_MUXDEMUX(ILBC, ilbc); - REGISTER_MUXDEMUX(IMAGE2, image2); - REGISTER_MUXDEMUX(IMAGE2PIPE, image2pipe); - REGISTER_DEMUXER (IMAGE2_ALIAS_PIX, image2_alias_pix); - REGISTER_DEMUXER (IMAGE2_BRENDER_PIX, image2_brender_pix); - REGISTER_DEMUXER (INGENIENT, ingenient); - REGISTER_DEMUXER (IPMOVIE, ipmovie); - REGISTER_MUXER (IPOD, ipod); - REGISTER_MUXDEMUX(IRCAM, ircam); - REGISTER_MUXER (ISMV, ismv); - REGISTER_DEMUXER (ISS, iss); - REGISTER_DEMUXER (IV8, iv8); - REGISTER_MUXDEMUX(IVF, ivf); - REGISTER_DEMUXER (IVR, ivr); - REGISTER_MUXDEMUX(JACOSUB, jacosub); - REGISTER_DEMUXER (JV, jv); - REGISTER_MUXER (LATM, latm); - REGISTER_DEMUXER (LMLM4, lmlm4); - REGISTER_DEMUXER (LOAS, loas); - REGISTER_MUXDEMUX(LRC, lrc); - REGISTER_DEMUXER (LVF, lvf); - REGISTER_DEMUXER (LXF, lxf); - REGISTER_MUXDEMUX(M4V, m4v); - REGISTER_MUXER (MD5, md5); - REGISTER_MUXDEMUX(MATROSKA, matroska); - REGISTER_MUXER (MATROSKA_AUDIO, matroska_audio); - REGISTER_DEMUXER (MGSTS, mgsts); - REGISTER_MUXDEMUX(MICRODVD, microdvd); - REGISTER_MUXDEMUX(MJPEG, mjpeg); - REGISTER_DEMUXER (MJPEG_2000, mjpeg_2000); - REGISTER_MUXDEMUX(MLP, mlp); - REGISTER_DEMUXER (MLV, mlv); - REGISTER_DEMUXER (MM, mm); - REGISTER_MUXDEMUX(MMF, mmf); - REGISTER_MUXDEMUX(MOV, mov); - REGISTER_MUXER (MP2, mp2); - REGISTER_MUXDEMUX(MP3, mp3); - REGISTER_MUXER (MP4, mp4); - REGISTER_DEMUXER (MPC, mpc); - REGISTER_DEMUXER (MPC8, mpc8); - REGISTER_MUXER (MPEG1SYSTEM, mpeg1system); - REGISTER_MUXER (MPEG1VCD, mpeg1vcd); - REGISTER_MUXER (MPEG1VIDEO, mpeg1video); - REGISTER_MUXER (MPEG2DVD, mpeg2dvd); - REGISTER_MUXER (MPEG2SVCD, mpeg2svcd); - REGISTER_MUXER (MPEG2VIDEO, mpeg2video); - REGISTER_MUXER (MPEG2VOB, mpeg2vob); - REGISTER_DEMUXER (MPEGPS, mpegps); - REGISTER_MUXDEMUX(MPEGTS, mpegts); - REGISTER_DEMUXER (MPEGTSRAW, mpegtsraw); - REGISTER_DEMUXER (MPEGVIDEO, mpegvideo); - REGISTER_MUXDEMUX(MPJPEG, mpjpeg); - REGISTER_DEMUXER (MPL2, mpl2); - REGISTER_DEMUXER (MPSUB, mpsub); - REGISTER_DEMUXER (MSF, msf); - REGISTER_DEMUXER (MSNWC_TCP, msnwc_tcp); - REGISTER_DEMUXER (MTAF, mtaf); - REGISTER_DEMUXER (MTV, mtv); - REGISTER_DEMUXER (MUSX, musx); - REGISTER_DEMUXER (MV, mv); - REGISTER_DEMUXER (MVI, mvi); - REGISTER_MUXDEMUX(MXF, mxf); - REGISTER_MUXER (MXF_D10, mxf_d10); - REGISTER_MUXER (MXF_OPATOM, mxf_opatom); - REGISTER_DEMUXER (MXG, mxg); - REGISTER_DEMUXER (NC, nc); - REGISTER_DEMUXER (NISTSPHERE, nistsphere); - REGISTER_DEMUXER (NSV, nsv); - REGISTER_MUXER (NULL, null); - REGISTER_MUXDEMUX(NUT, nut); - REGISTER_DEMUXER (NUV, nuv); - REGISTER_MUXER (OGA, oga); - REGISTER_MUXDEMUX(OGG, ogg); - REGISTER_MUXER (OGV, ogv); - REGISTER_MUXDEMUX(OMA, oma); - REGISTER_MUXER (OPUS, opus); - REGISTER_DEMUXER (PAF, paf); - REGISTER_MUXDEMUX(PCM_ALAW, pcm_alaw); - REGISTER_MUXDEMUX(PCM_MULAW, pcm_mulaw); - REGISTER_MUXDEMUX(PCM_F64BE, pcm_f64be); - REGISTER_MUXDEMUX(PCM_F64LE, pcm_f64le); - REGISTER_MUXDEMUX(PCM_F32BE, pcm_f32be); - REGISTER_MUXDEMUX(PCM_F32LE, pcm_f32le); - REGISTER_MUXDEMUX(PCM_S32BE, pcm_s32be); - REGISTER_MUXDEMUX(PCM_S32LE, pcm_s32le); - REGISTER_MUXDEMUX(PCM_S24BE, pcm_s24be); - REGISTER_MUXDEMUX(PCM_S24LE, pcm_s24le); - REGISTER_MUXDEMUX(PCM_S16BE, pcm_s16be); - REGISTER_MUXDEMUX(PCM_S16LE, pcm_s16le); - REGISTER_MUXDEMUX(PCM_S8, pcm_s8); - REGISTER_MUXDEMUX(PCM_U32BE, pcm_u32be); - REGISTER_MUXDEMUX(PCM_U32LE, pcm_u32le); - REGISTER_MUXDEMUX(PCM_U24BE, pcm_u24be); - REGISTER_MUXDEMUX(PCM_U24LE, pcm_u24le); - REGISTER_MUXDEMUX(PCM_U16BE, pcm_u16be); - REGISTER_MUXDEMUX(PCM_U16LE, pcm_u16le); - REGISTER_MUXDEMUX(PCM_U8, pcm_u8); - REGISTER_DEMUXER (PJS, pjs); - REGISTER_DEMUXER (PMP, pmp); - REGISTER_MUXER (PSP, psp); - REGISTER_DEMUXER (PVA, pva); - REGISTER_DEMUXER (PVF, pvf); - REGISTER_DEMUXER (QCP, qcp); - REGISTER_DEMUXER (R3D, r3d); - REGISTER_MUXDEMUX(RAWVIDEO, rawvideo); - REGISTER_DEMUXER (REALTEXT, realtext); - REGISTER_DEMUXER (REDSPARK, redspark); - REGISTER_DEMUXER (RL2, rl2); - REGISTER_MUXDEMUX(RM, rm); - REGISTER_MUXDEMUX(ROQ, roq); - REGISTER_DEMUXER (RPL, rpl); - REGISTER_DEMUXER (RSD, rsd); - REGISTER_MUXDEMUX(RSO, rso); - REGISTER_MUXDEMUX(RTP, rtp); - REGISTER_MUXER (RTP_MPEGTS, rtp_mpegts); - REGISTER_MUXDEMUX(RTSP, rtsp); - REGISTER_DEMUXER (S337M, s337m); - REGISTER_DEMUXER (SAMI, sami); - REGISTER_MUXDEMUX(SAP, sap); - REGISTER_DEMUXER (SBG, sbg); - REGISTER_MUXDEMUX(SCC, scc); - REGISTER_DEMUXER (SDP, sdp); - REGISTER_DEMUXER (SDR2, sdr2); - REGISTER_DEMUXER (SDS, sds); - REGISTER_DEMUXER (SDX, sdx); -#if CONFIG_RTPDEC - ff_register_rtp_dynamic_payload_handlers(); - ff_register_rdt_dynamic_payload_handlers(); -#endif - REGISTER_DEMUXER (SEGAFILM, segafilm); - REGISTER_MUXER (SEGMENT, segment); - REGISTER_MUXER (SEGMENT, stream_segment); - REGISTER_DEMUXER (SHORTEN, shorten); - REGISTER_DEMUXER (SIFF, siff); - REGISTER_MUXER (SINGLEJPEG, singlejpeg); - REGISTER_DEMUXER (SLN, sln); - REGISTER_DEMUXER (SMACKER, smacker); - REGISTER_MUXDEMUX(SMJPEG, smjpeg); - REGISTER_MUXER (SMOOTHSTREAMING, smoothstreaming); - REGISTER_DEMUXER (SMUSH, smush); - REGISTER_DEMUXER (SOL, sol); - REGISTER_MUXDEMUX(SOX, sox); - REGISTER_MUXER (SPX, spx); - REGISTER_MUXDEMUX(SPDIF, spdif); - REGISTER_MUXDEMUX(SRT, srt); - REGISTER_DEMUXER (STR, str); - REGISTER_DEMUXER (STL, stl); - REGISTER_DEMUXER (SUBVIEWER1, subviewer1); - REGISTER_DEMUXER (SUBVIEWER, subviewer); - REGISTER_MUXDEMUX(SUP, sup); - REGISTER_DEMUXER (SVAG, svag); - REGISTER_MUXDEMUX(SWF, swf); - REGISTER_DEMUXER (TAK, tak); - REGISTER_MUXER (TEE, tee); - REGISTER_DEMUXER (TEDCAPTIONS, tedcaptions); - REGISTER_MUXER (TG2, tg2); - REGISTER_MUXER (TGP, tgp); - REGISTER_DEMUXER (THP, thp); - REGISTER_DEMUXER (THREEDOSTR, threedostr); - REGISTER_DEMUXER (TIERTEXSEQ, tiertexseq); - REGISTER_MUXER (MKVTIMESTAMP_V2, mkvtimestamp_v2); - REGISTER_DEMUXER (TMV, tmv); - REGISTER_MUXDEMUX(TRUEHD, truehd); - REGISTER_MUXDEMUX(TTA, tta); - REGISTER_DEMUXER (TXD, txd); - REGISTER_DEMUXER (TTY, tty); - REGISTER_MUXER (UNCODEDFRAMECRC, uncodedframecrc); - REGISTER_DEMUXER (V210, v210); - REGISTER_DEMUXER (V210X, v210x); - REGISTER_DEMUXER (VAG, vag); - REGISTER_MUXDEMUX(VC1, vc1); - REGISTER_MUXDEMUX(VC1T, vc1t); - REGISTER_DEMUXER (VIVO, vivo); - REGISTER_DEMUXER (VMD, vmd); - REGISTER_DEMUXER (VOBSUB, vobsub); - REGISTER_MUXDEMUX(VOC, voc); - REGISTER_DEMUXER (VPK, vpk); - REGISTER_DEMUXER (VPLAYER, vplayer); - REGISTER_DEMUXER (VQF, vqf); - REGISTER_MUXDEMUX(W64, w64); - REGISTER_MUXDEMUX(WAV, wav); - REGISTER_DEMUXER (WC3, wc3); - REGISTER_MUXER (WEBM, webm); - REGISTER_MUXDEMUX(WEBM_DASH_MANIFEST, webm_dash_manifest); - REGISTER_MUXER (WEBM_CHUNK, webm_chunk); - REGISTER_MUXER (WEBP, webp); - REGISTER_MUXDEMUX(WEBVTT, webvtt); - REGISTER_DEMUXER (WSAUD, wsaud); - REGISTER_DEMUXER (WSD, wsd); - REGISTER_DEMUXER (WSVQA, wsvqa); - REGISTER_MUXDEMUX(WTV, wtv); - REGISTER_DEMUXER (WVE, wve); - REGISTER_MUXDEMUX(WV, wv); - REGISTER_DEMUXER (XA, xa); - REGISTER_DEMUXER (XBIN, xbin); - REGISTER_DEMUXER (XMV, xmv); - REGISTER_DEMUXER (XVAG, xvag); - REGISTER_DEMUXER (XWMA, xwma); - REGISTER_DEMUXER (YOP, yop); - REGISTER_MUXDEMUX(YUV4MPEGPIPE, yuv4mpegpipe); + ff_mutex_lock(&avpriv_register_devices_mutex); + + for (int i = 0; (out = (AVOutputFormat*)muxer_list[i]); i++) { + if (prevout) + prevout->next = out; + prevout = out; + } - /* image demuxers */ - REGISTER_DEMUXER (IMAGE_BMP_PIPE, image_bmp_pipe); - REGISTER_DEMUXER (IMAGE_DDS_PIPE, image_dds_pipe); - REGISTER_DEMUXER (IMAGE_DPX_PIPE, image_dpx_pipe); - REGISTER_DEMUXER (IMAGE_EXR_PIPE, image_exr_pipe); - REGISTER_DEMUXER (IMAGE_J2K_PIPE, image_j2k_pipe); - REGISTER_DEMUXER (IMAGE_JPEG_PIPE, image_jpeg_pipe); - REGISTER_DEMUXER (IMAGE_JPEGLS_PIPE, image_jpegls_pipe); - REGISTER_DEMUXER (IMAGE_PAM_PIPE, image_pam_pipe); - REGISTER_DEMUXER (IMAGE_PBM_PIPE, image_pbm_pipe); - REGISTER_DEMUXER (IMAGE_PCX_PIPE, image_pcx_pipe); - REGISTER_DEMUXER (IMAGE_PGMYUV_PIPE, image_pgmyuv_pipe); - REGISTER_DEMUXER (IMAGE_PGM_PIPE, image_pgm_pipe); - REGISTER_DEMUXER (IMAGE_PICTOR_PIPE, image_pictor_pipe); - REGISTER_DEMUXER (IMAGE_PNG_PIPE, image_png_pipe); - REGISTER_DEMUXER (IMAGE_PPM_PIPE, image_ppm_pipe); - REGISTER_DEMUXER (IMAGE_PSD_PIPE, image_psd_pipe); - REGISTER_DEMUXER (IMAGE_QDRAW_PIPE, image_qdraw_pipe); - REGISTER_DEMUXER (IMAGE_SGI_PIPE, image_sgi_pipe); - REGISTER_DEMUXER (IMAGE_SVG_PIPE, image_svg_pipe); - REGISTER_DEMUXER (IMAGE_SUNRAST_PIPE, image_sunrast_pipe); - REGISTER_DEMUXER (IMAGE_TIFF_PIPE, image_tiff_pipe); - REGISTER_DEMUXER (IMAGE_WEBP_PIPE, image_webp_pipe); - REGISTER_DEMUXER (IMAGE_XPM_PIPE, image_xpm_pipe); + if (outdev_list) { + for (int i = 0; (out = (AVOutputFormat*)outdev_list[i]); i++) { + if (prevout) + prevout->next = out; + prevout = out; + } + } + + for (int i = 0; (in = (AVInputFormat*)demuxer_list[i]); i++) { + if (previn) + previn->next = in; + previn = in; + } + + if (indev_list) { + for (int i = 0; (in = (AVInputFormat*)indev_list[i]); i++) { + if (previn) + previn->next = in; + previn = in; + } + } - /* external libraries */ - REGISTER_MUXER (CHROMAPRINT, chromaprint); - REGISTER_DEMUXER (LIBGME, libgme); - REGISTER_DEMUXER (LIBMODPLUG, libmodplug); - REGISTER_DEMUXER (LIBOPENMPT, libopenmpt); + ff_mutex_unlock(&avpriv_register_devices_mutex); +} + +AVInputFormat *av_iformat_next(const AVInputFormat *f) +{ + ff_thread_once(&av_format_next_init, av_format_init_next); + + if (f) + return f->next; + else { + void *opaque = NULL; + return (AVInputFormat *)av_demuxer_iterate(&opaque); + } +} + +AVOutputFormat *av_oformat_next(const AVOutputFormat *f) +{ + ff_thread_once(&av_format_next_init, av_format_init_next); + + if (f) + return f->next; + else { + void *opaque = NULL; + return (AVOutputFormat *)av_muxer_iterate(&opaque); + } } void av_register_all(void) { - static AVOnce control = AV_ONCE_INIT; + ff_thread_once(&av_format_next_init, av_format_init_next); +} + +void av_register_input_format(AVInputFormat *format) +{ + ff_thread_once(&av_format_next_init, av_format_init_next); +} + +void av_register_output_format(AVOutputFormat *format) +{ + ff_thread_once(&av_format_next_init, av_format_init_next); +} +FF_ENABLE_DEPRECATION_WARNINGS +#endif - ff_thread_once(&control, register_all); +void avpriv_register_devices(const AVOutputFormat * const o[], const AVInputFormat * const i[]) +{ + ff_mutex_lock(&avpriv_register_devices_mutex); + outdev_list = o; + indev_list = i; + ff_mutex_unlock(&avpriv_register_devices_mutex); +#if FF_API_NEXT + av_format_init_next(); +#endif } diff --git a/libavformat/amr.c b/libavformat/amr.c index b5194a2d9e3a7..f954803d4615a 100644 --- a/libavformat/amr.c +++ b/libavformat/amr.c @@ -38,6 +38,13 @@ typedef struct { static const char AMR_header[] = "#!AMR\n"; static const char AMRWB_header[] = "#!AMR-WB\n"; +static const uint8_t amrnb_packed_size[16] = { + 13, 14, 16, 18, 20, 21, 27, 32, 6, 1, 1, 1, 1, 1, 1, 1 +}; +static const uint8_t amrwb_packed_size[16] = { + 18, 24, 33, 37, 41, 47, 51, 59, 61, 6, 1, 1, 1, 1, 1, 1 +}; + #if CONFIG_AMR_MUXER static int amr_write_header(AVFormatContext *s) { @@ -126,17 +133,9 @@ static int amr_read_packet(AVFormatContext *s, AVPacket *pkt) mode = (toc >> 3) & 0x0F; if (par->codec_id == AV_CODEC_ID_AMR_NB) { - static const uint8_t packed_size[16] = { - 12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0 - }; - - size = packed_size[mode] + 1; + size = amrnb_packed_size[mode]; } else if (par->codec_id == AV_CODEC_ID_AMR_WB) { - static const uint8_t packed_size[16] = { - 18, 24, 33, 37, 41, 47, 51, 59, 61, 6, 6, 0, 0, 0, 1, 1 - }; - - size = packed_size[mode]; + size = amrwb_packed_size[mode]; } if (!size || av_new_packet(pkt, size)) @@ -176,6 +175,120 @@ AVInputFormat ff_amr_demuxer = { }; #endif +#if CONFIG_AMRNB_DEMUXER +static int amrnb_probe(AVProbeData *p) +{ + int mode, i = 0, valid = 0, invalid = 0; + const uint8_t *b = p->buf; + + while (i < p->buf_size) { + mode = b[i] >> 3 & 0x0F; + if (mode < 9 && (b[i] & 0x4) == 0x4) { + int last = mode; + int size = amrnb_packed_size[mode]; + while (size--) { + if (b[++i] != last) + break; + last = b[i]; + } + if (size > 0) { + valid++; + i += size; + } + } else { + valid = 0; + invalid++; + i++; + } + } + if (valid > 100 && valid > invalid) + return AVPROBE_SCORE_EXTENSION / 2 + 1; + return 0; +} + +static int amrnb_read_header(AVFormatContext *s) +{ + AVStream *st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + st->codecpar->codec_id = AV_CODEC_ID_AMR_NB; + st->codecpar->sample_rate = 8000; + st->codecpar->channels = 1; + st->codecpar->channel_layout = AV_CH_LAYOUT_MONO; + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + avpriv_set_pts_info(st, 64, 1, 8000); + + return 0; +} + +AVInputFormat ff_amrnb_demuxer = { + .name = "amrnb", + .long_name = NULL_IF_CONFIG_SMALL("raw AMR-NB"), + .priv_data_size = sizeof(AMRContext), + .read_probe = amrnb_probe, + .read_header = amrnb_read_header, + .read_packet = amr_read_packet, + .flags = AVFMT_GENERIC_INDEX, +}; +#endif + +#if CONFIG_AMRWB_DEMUXER +static int amrwb_probe(AVProbeData *p) +{ + int mode, i = 0, valid = 0, invalid = 0; + const uint8_t *b = p->buf; + + while (i < p->buf_size) { + mode = b[i] >> 3 & 0x0F; + if (mode < 10 && (b[i] & 0x4) == 0x4) { + int last = mode; + int size = amrwb_packed_size[mode]; + while (size--) { + if (b[++i] != last) + break; + last = b[i]; + } + if (size > 0) { + valid++; + i += size; + } + } else { + valid = 0; + invalid++; + i++; + } + } + if (valid > 100 && valid > invalid) + return AVPROBE_SCORE_EXTENSION / 2 - 1; + return 0; +} + +static int amrwb_read_header(AVFormatContext *s) +{ + AVStream *st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + st->codecpar->codec_id = AV_CODEC_ID_AMR_WB; + st->codecpar->sample_rate = 16000; + st->codecpar->channels = 1; + st->codecpar->channel_layout = AV_CH_LAYOUT_MONO; + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + avpriv_set_pts_info(st, 64, 1, 16000); + + return 0; +} + +AVInputFormat ff_amrwb_demuxer = { + .name = "amrwb", + .long_name = NULL_IF_CONFIG_SMALL("raw AMR-WB"), + .priv_data_size = sizeof(AMRContext), + .read_probe = amrwb_probe, + .read_header = amrwb_read_header, + .read_packet = amr_read_packet, + .flags = AVFMT_GENERIC_INDEX, +}; +#endif + #if CONFIG_AMR_MUXER AVOutputFormat ff_amr_muxer = { .name = "amr", diff --git a/libavformat/aptxdec.c b/libavformat/aptxdec.c new file mode 100644 index 0000000000000..a262cd9ebea40 --- /dev/null +++ b/libavformat/aptxdec.c @@ -0,0 +1,128 @@ +/* + * RAW aptX demuxer + * + * Copyright (C) 2017 Aurelien Jacobs + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avformat.h" +#include "rawdec.h" + +#define APTX_BLOCK_SIZE 4 +#define APTX_PACKET_SIZE (256*APTX_BLOCK_SIZE) + +#define APTX_HD_BLOCK_SIZE 6 +#define APTX_HD_PACKET_SIZE (256*APTX_HD_BLOCK_SIZE) + +typedef struct AptXDemuxerContext { + AVClass *class; + int sample_rate; +} AptXDemuxerContext; + +static AVStream *aptx_read_header_common(AVFormatContext *s) +{ + AptXDemuxerContext *s1 = s->priv_data; + AVStream *st = avformat_new_stream(s, NULL); + if (!st) + return NULL; + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + st->codecpar->format = AV_SAMPLE_FMT_S32P; + st->codecpar->channels = 2; + st->codecpar->sample_rate = s1->sample_rate; + st->start_time = 0; + return st; +} + +static int aptx_read_header(AVFormatContext *s) +{ + AVStream *st = aptx_read_header_common(s); + if (!st) + return AVERROR(ENOMEM); + st->codecpar->codec_id = AV_CODEC_ID_APTX; + st->codecpar->bits_per_coded_sample = 4; + st->codecpar->block_align = APTX_BLOCK_SIZE; + st->codecpar->frame_size = APTX_PACKET_SIZE; + return 0; +} + +static int aptx_hd_read_header(AVFormatContext *s) +{ + AVStream *st = aptx_read_header_common(s); + if (!st) + return AVERROR(ENOMEM); + st->codecpar->codec_id = AV_CODEC_ID_APTX_HD; + st->codecpar->bits_per_coded_sample = 6; + st->codecpar->block_align = APTX_HD_BLOCK_SIZE; + st->codecpar->frame_size = APTX_HD_PACKET_SIZE; + return 0; +} + +static int aptx_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + return av_get_packet(s->pb, pkt, APTX_PACKET_SIZE); +} + +static int aptx_hd_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + return av_get_packet(s->pb, pkt, APTX_HD_PACKET_SIZE); +} + +static const AVOption aptx_options[] = { + { "sample_rate", "", offsetof(AptXDemuxerContext, sample_rate), AV_OPT_TYPE_INT, {.i64 = 48000}, 0, INT_MAX, AV_OPT_FLAG_DECODING_PARAM }, + { NULL }, +}; + +#if CONFIG_APTX_DEMUXER +static const AVClass aptx_demuxer_class = { + .class_name = "aptx demuxer", + .item_name = av_default_item_name, + .option = aptx_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVInputFormat ff_aptx_demuxer = { + .name = "aptx", + .long_name = NULL_IF_CONFIG_SMALL("raw aptX"), + .extensions = "aptx", + .priv_data_size = sizeof(AptXDemuxerContext), + .read_header = aptx_read_header, + .read_packet = aptx_read_packet, + .flags = AVFMT_GENERIC_INDEX, + .priv_class = &aptx_demuxer_class, +}; +#endif + +#if CONFIG_APTX_HD_DEMUXER +static const AVClass aptx_hd_demuxer_class = { + .class_name = "aptx hd demuxer", + .item_name = av_default_item_name, + .option = aptx_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVInputFormat ff_aptx_hd_demuxer = { + .name = "aptx_hd", + .long_name = NULL_IF_CONFIG_SMALL("raw aptX HD"), + .extensions = "aptxhd", + .priv_data_size = sizeof(AptXDemuxerContext), + .read_header = aptx_hd_read_header, + .read_packet = aptx_hd_read_packet, + .flags = AVFMT_GENERIC_INDEX, + .priv_class = &aptx_hd_demuxer_class, +}; +#endif diff --git a/libavformat/async.c b/libavformat/async.c index 54dbd2312a24c..bdbb42fa2b426 100644 --- a/libavformat/async.c +++ b/libavformat/async.c @@ -479,7 +479,7 @@ static const AVClass async_context_class = { .version = LIBAVUTIL_VERSION_INT, }; -const URLProtocol ff_async_protocol = { +URLProtocol ff_async_protocol = { .name = "async", .url_open2 = async_open, .url_read = async_read, diff --git a/libavformat/avc.c b/libavformat/avc.c index 094a95821f396..ec50033a0420e 100644 --- a/libavformat/avc.c +++ b/libavformat/avc.c @@ -20,6 +20,7 @@ */ #include "libavutil/intreadwrite.h" +#include "libavcodec/h264.h" #include "avformat.h" #include "avio.h" #include "avc.h" @@ -105,60 +106,92 @@ int ff_avc_parse_nal_units_buf(const uint8_t *buf_in, uint8_t **buf, int *size) int ff_isom_write_avcc(AVIOContext *pb, const uint8_t *data, int len) { - if (len > 6) { - /* check for H.264 start code */ - if (AV_RB32(data) == 0x00000001 || - AV_RB24(data) == 0x000001) { - uint8_t *buf=NULL, *end, *start; - uint32_t sps_size=0, pps_size=0; - uint8_t *sps=0, *pps=0; - - int ret = ff_avc_parse_nal_units_buf(data, &buf, &len); - if (ret < 0) - return ret; - start = buf; - end = buf + len; - - /* look for sps and pps */ - while (end - buf > 4) { - uint32_t size; - uint8_t nal_type; - size = FFMIN(AV_RB32(buf), end - buf - 4); - buf += 4; - nal_type = buf[0] & 0x1f; - - if (nal_type == 7) { /* SPS */ - sps = buf; - sps_size = size; - } else if (nal_type == 8) { /* PPS */ - pps = buf; - pps_size = size; - } - - buf += size; - } + AVIOContext *sps_pb = NULL, *pps_pb = NULL; + uint8_t *buf = NULL, *end, *start = NULL; + uint8_t *sps = NULL, *pps = NULL; + uint32_t sps_size = 0, pps_size = 0; + int ret, nb_sps = 0, nb_pps = 0; + + if (len <= 6) + return AVERROR_INVALIDDATA; - if (!sps || !pps || sps_size < 4 || sps_size > UINT16_MAX || pps_size > UINT16_MAX) - return AVERROR_INVALIDDATA; - - avio_w8(pb, 1); /* version */ - avio_w8(pb, sps[1]); /* profile */ - avio_w8(pb, sps[2]); /* profile compat */ - avio_w8(pb, sps[3]); /* level */ - avio_w8(pb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */ - avio_w8(pb, 0xe1); /* 3 bits reserved (111) + 5 bits number of sps (00001) */ - - avio_wb16(pb, sps_size); - avio_write(pb, sps, sps_size); - avio_w8(pb, 1); /* number of pps */ - avio_wb16(pb, pps_size); - avio_write(pb, pps, pps_size); - av_free(start); - } else { - avio_write(pb, data, len); + /* check for H.264 start code */ + if (AV_RB32(data) != 0x00000001 && + AV_RB24(data) != 0x000001) { + avio_write(pb, data, len); + return 0; + } + + ret = ff_avc_parse_nal_units_buf(data, &buf, &len); + if (ret < 0) + return ret; + start = buf; + end = buf + len; + + ret = avio_open_dyn_buf(&sps_pb); + if (ret < 0) + goto fail; + ret = avio_open_dyn_buf(&pps_pb); + if (ret < 0) + goto fail; + + /* look for sps and pps */ + while (end - buf > 4) { + uint32_t size; + uint8_t nal_type; + size = FFMIN(AV_RB32(buf), end - buf - 4); + buf += 4; + nal_type = buf[0] & 0x1f; + + if (nal_type == 7) { /* SPS */ + nb_sps++; + if (size > UINT16_MAX || nb_sps >= H264_MAX_SPS_COUNT) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + avio_wb16(sps_pb, size); + avio_write(sps_pb, buf, size); + } else if (nal_type == 8) { /* PPS */ + nb_pps++; + if (size > UINT16_MAX || nb_pps >= H264_MAX_PPS_COUNT) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + avio_wb16(pps_pb, size); + avio_write(pps_pb, buf, size); } + + buf += size; } - return 0; + sps_size = avio_close_dyn_buf(sps_pb, &sps); + pps_size = avio_close_dyn_buf(pps_pb, &pps); + + if (sps_size < 6 || !pps_size) { + ret = AVERROR_INVALIDDATA; + goto fail; + } + + avio_w8(pb, 1); /* version */ + avio_w8(pb, sps[3]); /* profile */ + avio_w8(pb, sps[4]); /* profile compat */ + avio_w8(pb, sps[5]); /* level */ + avio_w8(pb, 0xff); /* 6 bits reserved (111111) + 2 bits nal size length - 1 (11) */ + avio_w8(pb, 0xe0 | nb_sps); /* 3 bits reserved (111) + 5 bits number of sps */ + + avio_write(pb, sps, sps_size); + avio_w8(pb, nb_pps); /* number of pps */ + avio_write(pb, pps, pps_size); + +fail: + if (!sps) + avio_close_dyn_buf(sps_pb, &sps); + if (!pps) + avio_close_dyn_buf(pps_pb, &pps); + av_free(sps); + av_free(pps); + av_free(start); + + return ret; } int ff_avc_write_annexb_extradata(const uint8_t *in, uint8_t **buf, int *size) diff --git a/libavformat/avformat.h b/libavformat/avformat.h index b0de66ac1450a..fe7dc5adf5b01 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -437,19 +437,6 @@ int av_get_packet(AVIOContext *s, AVPacket *pkt, int size); */ int av_append_packet(AVIOContext *s, AVPacket *pkt, int size); -#if FF_API_LAVF_FRAC -/*************************************************/ -/* fractional numbers for exact pts handling */ - -/** - * The exact value of the fractional number is: 'val + num / den'. - * num is assumed to be 0 <= num < den. - */ -typedef struct AVFrac { - int64_t val, num, den; -} AVFrac; -#endif - /*************************************************/ /* input/output formats */ @@ -478,10 +465,6 @@ typedef struct AVProbeData { #define AVFMT_NOFILE 0x0001 #define AVFMT_NEEDNUMBER 0x0002 /**< Needs '%d' in filename. */ #define AVFMT_SHOW_IDS 0x0008 /**< Show format stream IDs numbers. */ -#if FF_API_LAVF_FMT_RAWPICTURE -#define AVFMT_RAWPICTURE 0x0020 /**< Format wants AVPicture structure for - raw picture data. @deprecated Not used anymore */ -#endif #define AVFMT_GLOBALHEADER 0x0040 /**< Format wants global header. */ #define AVFMT_NOTIMESTAMPS 0x0080 /**< Format does not need / have any timestamps. */ #define AVFMT_GENERIC_INDEX 0x0100 /**< Use generic index building code. */ @@ -719,6 +702,11 @@ typedef struct AVInputFormat { */ int (*read_header)(struct AVFormatContext *); + /** + * Used by format which open further nested input. + */ + int (*read_header2)(struct AVFormatContext *, AVDictionary **options); + /** * Read one packet and put it in 'pkt'. pts and flags are also * set. 'avformat_new_stream' can be called only if the flag @@ -802,9 +790,9 @@ enum AVStreamParseType { AVSTREAM_PARSE_HEADERS, /**< Only parse headers, do not repack. */ AVSTREAM_PARSE_TIMESTAMPS, /**< full parsing and interpolation of timestamps for frames not starting on a packet boundary */ AVSTREAM_PARSE_FULL_ONCE, /**< full parsing and repack of the first frame only, only implemented for H.264 currently */ - AVSTREAM_PARSE_FULL_RAW=MKTAG(0,'R','A','W'), /**< full parsing and repack with timestamp and position generation by parser for raw - this assumes that each packet in the file contains no demuxer level headers and - just codec level data, otherwise position generation would fail */ + AVSTREAM_PARSE_FULL_RAW, /**< full parsing and repack with timestamp and position generation by parser for raw + this assumes that each packet in the file contains no demuxer level headers and + just codec level data, otherwise position generation would fail */ }; typedef struct AVIndexEntry { @@ -862,6 +850,7 @@ typedef struct AVStreamInternal AVStreamInternal; #define AV_DISPOSITION_CAPTIONS 0x10000 #define AV_DISPOSITION_DESCRIPTIONS 0x20000 #define AV_DISPOSITION_METADATA 0x40000 +#define AV_DISPOSITION_DEPENDENT 0x80000 ///< dependent audio stream (mix_type=0 in mpegts) /** * Options for behavior on timestamp wrap detection. @@ -894,14 +883,6 @@ typedef struct AVStream { #endif void *priv_data; -#if FF_API_LAVF_FRAC - /** - * @deprecated this field is unused - */ - attribute_deprecated - struct AVFrac pts; -#endif - /** * This is the fundamental unit of time (in seconds) in terms * of which frame timestamps are represented. @@ -1001,6 +982,39 @@ typedef struct AVStream { int event_flags; #define AVSTREAM_EVENT_FLAG_METADATA_UPDATED 0x0001 ///< The call resulted in updated metadata. + /** + * Real base framerate of the stream. + * This is the lowest framerate with which all timestamps can be + * represented accurately (it is the least common multiple of all + * framerates in the stream). Note, this value is just a guess! + * For example, if the time base is 1/90000 and all frames have either + * approximately 3600 or 1800 timer ticks, then r_frame_rate will be 50/1. + */ + AVRational r_frame_rate; + +#if FF_API_LAVF_FFSERVER + /** + * String containing pairs of key and values describing recommended encoder configuration. + * Pairs are separated by ','. + * Keys are separated from values by '='. + * + * @deprecated unused + */ + attribute_deprecated + char *recommended_encoder_configuration; +#endif + + /** + * Codec parameters associated with this stream. Allocated and freed by + * libavformat in avformat_new_stream() and avformat_free_context() + * respectively. + * + * - demuxing: filled by libavformat on stream creation or in + * avformat_find_stream_info() + * - muxing: filled by the caller before avformat_write_header() + */ + AVCodecParameters *codecpar; + /***************************************************************** * All fields below this line are not part of the public API. They * may not be used outside of libavformat and can be changed and @@ -1011,10 +1025,10 @@ typedef struct AVStream { ***************************************************************** */ +#define MAX_STD_TIMEBASES (30*12+30+3+6) /** * Stream information used internally by avformat_find_stream_info() */ -#define MAX_STD_TIMEBASES (30*12+30+3+6) struct { int64_t last_dts; int64_t duration_gcd; @@ -1023,6 +1037,7 @@ typedef struct AVStream { double (*duration_error)[2][MAX_STD_TIMEBASES]; int64_t codec_info_duration; int64_t codec_info_duration_fields; + int frame_delay_evidence; /** * 0 -> decoder has not been searched for yet. @@ -1085,19 +1100,6 @@ typedef struct AVStream { int nb_index_entries; unsigned int index_entries_allocated_size; - /** - * Real base framerate of the stream. - * This is the lowest framerate with which all timestamps can be - * represented accurately (it is the least common multiple of all - * framerates in the stream). Note, this value is just a guess! - * For example, if the time base is 1/90000 and all frames have either - * approximately 3600 or 1800 timer ticks, then r_frame_rate will be 50/1. - * - * Code outside avformat should access this field using: - * av_stream_get/set_r_frame_rate(stream) - */ - AVRational r_frame_rate; - /** * Stream Identifier * This is the MPEG-TS stream identifier +1 @@ -1203,19 +1205,6 @@ typedef struct AVStream { */ int inject_global_side_data; - /***************************************************************** - * All fields above this line are not part of the public API. - * Fields below are part of the public API and ABI again. - ***************************************************************** - */ - - /** - * String containing paris of key and values describing recommended encoder configuration. - * Paris are separated by ','. - * Keys are separated from values by '='. - */ - char *recommended_encoder_configuration; - /** * display aspect ratio (0 if unknown) * - encoding: unused @@ -1223,31 +1212,31 @@ typedef struct AVStream { */ AVRational display_aspect_ratio; - struct FFFrac *priv_pts; - /** * An opaque field for libavformat internal usage. * Must not be accessed in any way by callers. */ AVStreamInternal *internal; - - /* - * Codec parameters associated with this stream. Allocated and freed by - * libavformat in avformat_new_stream() and avformat_free_context() - * respectively. - * - * - demuxing: filled by libavformat on stream creation or in - * avformat_find_stream_info() - * - muxing: filled by the caller before avformat_write_header() - */ - AVCodecParameters *codecpar; } AVStream; +#if FF_API_FORMAT_GET_SET +/** + * Accessors for some AVStream fields. These used to be provided for ABI + * compatibility, and do not need to be used anymore. + */ +attribute_deprecated AVRational av_stream_get_r_frame_rate(const AVStream *s); +attribute_deprecated void av_stream_set_r_frame_rate(AVStream *s, AVRational r); -struct AVCodecParserContext *av_stream_get_parser(const AVStream *s); +#if FF_API_LAVF_FFSERVER +attribute_deprecated char* av_stream_get_recommended_encoder_configuration(const AVStream *s); +attribute_deprecated void av_stream_set_recommended_encoder_configuration(AVStream *s, char *configuration); +#endif +#endif + +struct AVCodecParserContext *av_stream_get_parser(const AVStream *s); /** * Returns the pts of the last muxed packet + its duration @@ -1292,6 +1281,11 @@ typedef struct AVProgram { #define AVFMTCTX_NOHEADER 0x0001 /**< signal that no header is present (streams are added dynamically) */ +#define AVFMTCTX_UNSEEKABLE 0x0002 /**< signal that the stream is definitely + not seekable, and attempts to call the + seek function will fail. For some + network protocols (e.g. HLS), this can + change dynamically at runtime. */ typedef struct AVChapter { int id; ///< unique ID to identify the chapter @@ -1406,13 +1400,33 @@ typedef struct AVFormatContext { */ AVStream **streams; +#if FF_API_FORMAT_FILENAME /** * input or output filename * * - demuxing: set by avformat_open_input() * - muxing: may be set by the caller before avformat_write_header() + * + * @deprecated Use url instead. */ + attribute_deprecated char filename[1024]; +#endif + + /** + * input or output URL. Unlike the old filename field, this field has no + * length restriction. + * + * - demuxing: set by avformat_open_input(), initialized to an empty + * string if url parameter was NULL in avformat_open_input(). + * - muxing: may be set by the caller before calling avformat_write_header() + * (or avformat_init_output() if that is called first) to a string + * which is freeable by av_free(). Set to an empty string if it + * was NULL in avformat_init_output(). + * + * Freed by libavformat in avformat_free_context(). + */ + char *url; /** * Position of the first frame of the component, in @@ -1469,11 +1483,11 @@ typedef struct AVFormatContext { #define AVFMT_FLAG_SORT_DTS 0x10000 ///< try to interleave outputted packets by dts (using this flag can slow demuxing down) #define AVFMT_FLAG_PRIV_OPT 0x20000 ///< Enable use of private options by delaying codec open (this could be made default once all code is converted) #if FF_API_LAVF_KEEPSIDE_FLAG -#define AVFMT_FLAG_KEEP_SIDE_DATA 0x40000 ///< Don't merge side data but keep it separate. Deprecated, will be the default. +#define AVFMT_FLAG_KEEP_SIDE_DATA 0x40000 ///< Deprecated, does nothing. #endif #define AVFMT_FLAG_FAST_SEEK 0x80000 ///< Enable fast, but inaccurate seeks for some formats #define AVFMT_FLAG_SHORTEST 0x100000 ///< Stop muxing when the shortest stream stops. -#define AVFMT_FLAG_AUTO_BSF 0x200000 ///< Wait for packet data before writing a header, and add bitstream filters as requested by the muxer +#define AVFMT_FLAG_AUTO_BSF 0x200000 ///< Add bitstream filters as requested by the muxer /** * Maximum size of the data read from input for determining @@ -1876,7 +1890,7 @@ typedef struct AVFormatContext { */ char *protocol_whitelist; - /* + /** * A callback for opening new IO streams. * * Whenever a muxer or a demuxer needs to open an IO stream (typically from @@ -1919,29 +1933,46 @@ typedef struct AVFormatContext { int max_streams; } AVFormatContext; +#if FF_API_FORMAT_GET_SET /** * Accessors for some AVFormatContext fields. These used to be provided for ABI * compatibility, and do not need to be used anymore. */ +attribute_deprecated int av_format_get_probe_score(const AVFormatContext *s); +attribute_deprecated AVCodec * av_format_get_video_codec(const AVFormatContext *s); +attribute_deprecated void av_format_set_video_codec(AVFormatContext *s, AVCodec *c); +attribute_deprecated AVCodec * av_format_get_audio_codec(const AVFormatContext *s); +attribute_deprecated void av_format_set_audio_codec(AVFormatContext *s, AVCodec *c); +attribute_deprecated AVCodec * av_format_get_subtitle_codec(const AVFormatContext *s); +attribute_deprecated void av_format_set_subtitle_codec(AVFormatContext *s, AVCodec *c); +attribute_deprecated AVCodec * av_format_get_data_codec(const AVFormatContext *s); +attribute_deprecated void av_format_set_data_codec(AVFormatContext *s, AVCodec *c); +attribute_deprecated int av_format_get_metadata_header_padding(const AVFormatContext *s); +attribute_deprecated void av_format_set_metadata_header_padding(AVFormatContext *s, int c); +attribute_deprecated void * av_format_get_opaque(const AVFormatContext *s); +attribute_deprecated void av_format_set_opaque(AVFormatContext *s, void *opaque); +attribute_deprecated av_format_control_message av_format_get_control_message_cb(const AVFormatContext *s); +attribute_deprecated void av_format_set_control_message_cb(AVFormatContext *s, av_format_control_message callback); #if FF_API_OLD_OPEN_CALLBACKS attribute_deprecated AVOpenCallback av_format_get_open_cb(const AVFormatContext *s); attribute_deprecated void av_format_set_open_cb(AVFormatContext *s, AVOpenCallback callback); #endif +#endif /** * This function will cause global side data to be injected in the next packet @@ -1986,6 +2017,7 @@ const char *avformat_configuration(void); */ const char *avformat_license(void); +#if FF_API_NEXT /** * Initialize libavformat and register all the muxers, demuxers and * protocols. If you do not call this function, then you can select @@ -1994,31 +2026,44 @@ const char *avformat_license(void); * @see av_register_input_format() * @see av_register_output_format() */ +attribute_deprecated void av_register_all(void); +attribute_deprecated void av_register_input_format(AVInputFormat *format); +attribute_deprecated void av_register_output_format(AVOutputFormat *format); +#endif /** - * Do global initialization of network components. This is optional, - * but recommended, since it avoids the overhead of implicitly - * doing the setup for each session. + * Do global initialization of network libraries. This is optional, + * and not recommended anymore. * - * Calling this function will become mandatory if using network - * protocols at some major version bump. + * This functions only exists to work around thread-safety issues + * with older GnuTLS or OpenSSL libraries. If libavformat is linked + * to newer versions of those libraries, or if you do not use them, + * calling this function is unnecessary. Otherwise, you need to call + * this function before any other threads using them are started. + * + * This function will be deprecated once support for older GnuTLS and + * OpenSSL libraries is removed, and this function has no purpose + * anymore. */ int avformat_network_init(void); /** - * Undo the initialization done by avformat_network_init. + * Undo the initialization done by avformat_network_init. Call it only + * once for each time you called avformat_network_init. */ int avformat_network_deinit(void); +#if FF_API_NEXT /** * If f is NULL, returns the first registered input format, * if f is non-NULL, returns the next registered input format after f * or NULL if f is the last one. */ +attribute_deprecated AVInputFormat *av_iformat_next(const AVInputFormat *f); /** @@ -2026,7 +2071,31 @@ AVInputFormat *av_iformat_next(const AVInputFormat *f); * if f is non-NULL, returns the next registered output format after f * or NULL if f is the last one. */ +attribute_deprecated AVOutputFormat *av_oformat_next(const AVOutputFormat *f); +#endif + +/** + * Iterate over all registered muxers. + * + * @param opaque a pointer where libavformat will store the iteration state. Must + * point to NULL to start the iteration. + * + * @return the next registered muxer or NULL when the iteration is + * finished + */ +const AVOutputFormat *av_muxer_iterate(void **opaque); + +/** + * Iterate over all registered demuxers. + * + * @param opaque a pointer where libavformat will store the iteration state. Must + * point to NULL to start the iteration. + * + * @return the next registered demuxer or NULL when the iteration is + * finished + */ +const AVInputFormat *av_demuxer_iterate(void **opaque); /** * Allocate an AVFormatContext. @@ -2103,13 +2172,8 @@ uint8_t *av_stream_new_side_data(AVStream *stream, * @param size pointer for side information size to store (optional) * @return pointer to data if present or NULL otherwise */ -#if FF_API_NOCONST_GET_SIDE_DATA -uint8_t *av_stream_get_side_data(AVStream *stream, - enum AVPacketSideDataType type, int *size); -#else uint8_t *av_stream_get_side_data(const AVStream *stream, enum AVPacketSideDataType type, int *size); -#endif AVProgram *av_new_program(AVFormatContext *s, int id); diff --git a/libavformat/avidec.c b/libavformat/avidec.c index b8a31dcff2875..bafe1dc8da0c4 100644 --- a/libavformat/avidec.c +++ b/libavformat/avidec.c @@ -401,10 +401,10 @@ static int avi_extract_stream_metadata(AVFormatContext *s, AVStream *st) // skip 4 byte padding bytestream2_skip(&gb, 4); offset = bytestream2_tell(&gb); - bytestream2_init(&gb, data + offset, data_size - offset); // decode EXIF tags from IFD, AVI is always little-endian - return avpriv_exif_decode_ifd(s, &gb, 1, 0, &st->metadata); + return avpriv_exif_decode_ifd(s, data + offset, data_size - offset, + 1, 0, &st->metadata); break; case MKTAG('C', 'A', 'S', 'I'): avpriv_request_sample(s, "RIFF stream data tag type CASI (%u)", tag); @@ -670,7 +670,7 @@ FF_ENABLE_DEPRECATION_WARNINGS st->start_time = 0; avio_rl32(pb); /* buffer size */ avio_rl32(pb); /* quality */ - if (ast->cum_len*ast->scale/ast->rate > 3600) { + if (ast->cum_len > 3600LL * ast->rate / ast->scale) { av_log(s, AV_LOG_ERROR, "crazy start time, iam scared, giving up\n"); ast->cum_len = 0; } diff --git a/libavformat/avienc.c b/libavformat/avienc.c index 483f5b54b1464..ac0f04c3547fd 100644 --- a/libavformat/avienc.c +++ b/libavformat/avienc.c @@ -501,8 +501,14 @@ static int avi_write_header(AVFormatContext *s) AVRational dar = av_mul_q(st->sample_aspect_ratio, (AVRational) { par->width, par->height }); - int num, den; + int num, den, fields, i; av_reduce(&num, &den, dar.num, dar.den, 0xFFFF); + if (par->field_order == AV_FIELD_TT || par->field_order == AV_FIELD_BB || + par->field_order == AV_FIELD_TB || par->field_order == AV_FIELD_BT) { + fields = 2; // interlaced + } else { + fields = 1; // progressive + } avio_wl32(pb, 0); // video format = unknown avio_wl32(pb, 0); // video standard = unknown @@ -514,17 +520,30 @@ static int avi_write_header(AVFormatContext *s) avio_wl16(pb, num); avio_wl32(pb, par->width); avio_wl32(pb, par->height); - avio_wl32(pb, 1); // progressive FIXME - - avio_wl32(pb, par->height); - avio_wl32(pb, par->width); - avio_wl32(pb, par->height); - avio_wl32(pb, par->width); - avio_wl32(pb, 0); - avio_wl32(pb, 0); + avio_wl32(pb, fields); // fields per frame + + for (i = 0; i < fields; i++) { + int start_line; + // OpenDML v1.02 is not very specific on what value to use for + // start_line when frame data is not coming from a capturing device, + // so just use 0/1 depending on the field order for interlaced frames + if (par->field_order == AV_FIELD_TT || par->field_order == AV_FIELD_TB) { + start_line = (i == 0) ? 0 : 1; + } else if (par->field_order == AV_FIELD_BB || par->field_order == AV_FIELD_BT) { + start_line = (i == 0) ? 1 : 0; + } else { + start_line = 0; + } - avio_wl32(pb, 0); - avio_wl32(pb, 0); + avio_wl32(pb, par->height / fields); // compressed bitmap height + avio_wl32(pb, par->width); // compressed bitmap width + avio_wl32(pb, par->height / fields); // valid bitmap height + avio_wl32(pb, par->width); // valid bitmap width + avio_wl32(pb, 0); // valid bitmap X offset + avio_wl32(pb, 0); // valid bitmap Y offset + avio_wl32(pb, 0); // valid X offset in T + avio_wl32(pb, start_line); // valid Y start line + } ff_end_tag(pb, vprp); } diff --git a/libavformat/avio.c b/libavformat/avio.c index 64248e098b9e3..eff98e9ef40a5 100644 --- a/libavformat/avio.c +++ b/libavformat/avio.c @@ -297,7 +297,7 @@ int ffurl_alloc(URLContext **puc, const char *filename, int flags, return url_alloc_for_protocol(puc, p, filename, flags, int_cb); *puc = NULL; - if (av_strstart(filename, "https:", NULL)) + if (av_strstart(filename, "https:", NULL) || av_strstart(filename, "tls:", NULL)) av_log(NULL, AV_LOG_WARNING, "https protocol not found, recompile FFmpeg with " "openssl, gnutls " "or securetransport enabled.\n"); @@ -623,13 +623,15 @@ int64_t ffurl_size(URLContext *h) int ffurl_get_file_handle(URLContext *h) { - if (!h->prot->url_get_file_handle) + if (!h || !h->prot || !h->prot->url_get_file_handle) return -1; return h->prot->url_get_file_handle(h); } int ffurl_get_multi_file_handle(URLContext *h, int **handles, int *numhandles) { + if (!h || !h->prot) + return AVERROR(ENOSYS); if (!h->prot->url_get_multi_file_handle) { if (!h->prot->url_get_file_handle) return AVERROR(ENOSYS); @@ -645,15 +647,15 @@ int ffurl_get_multi_file_handle(URLContext *h, int **handles, int *numhandles) int ffurl_get_short_seek(URLContext *h) { - if (!h->prot->url_get_short_seek) + if (!h || !h->prot || !h->prot->url_get_short_seek) return AVERROR(ENOSYS); return h->prot->url_get_short_seek(h); } int ffurl_shutdown(URLContext *h, int flags) { - if (!h->prot->url_shutdown) - return AVERROR(EINVAL); + if (!h || !h->prot || !h->prot->url_shutdown) + return AVERROR(ENOSYS); return h->prot->url_shutdown(h, flags); } diff --git a/libavformat/avio.h b/libavformat/avio.h index f9c5972adae65..75912ce6bed97 100644 --- a/libavformat/avio.h +++ b/libavformat/avio.h @@ -236,7 +236,6 @@ typedef struct AVIOContext { int (*write_packet)(void *opaque, uint8_t *buf, int buf_size); int64_t (*seek)(void *opaque, int64_t offset, int whence); int64_t pos; /**< position in the file of the current buffer */ - int must_flush; /**< unused */ int eof_reached; /**< true if eof reached */ int write_flag; /**< true if open for writing */ int max_packet_size; @@ -452,6 +451,8 @@ void avio_free_directory_entry(AVIODirEntry **entry); * @param write_flag Set to 1 if the buffer should be writable, 0 otherwise. * @param opaque An opaque pointer to user-specific data. * @param read_packet A function for refilling the buffer, may be NULL. + * For stream protocols, must never return 0 but rather + * a proper AVERROR code. * @param write_packet A function for writing the buffer contents, may be NULL. * The function may not change the input buffers content. * @param seek A function for seeking to specified byte position, may be NULL. @@ -569,13 +570,6 @@ int64_t avio_size(AVIOContext *s); * @return non zero if and only if end of file */ int avio_feof(AVIOContext *s); -#if FF_API_URL_FEOF -/** - * @deprecated use avio_feof() - */ -attribute_deprecated -int url_feof(AVIOContext *s); -#endif /** @warning Writes up to 4 KiB per call */ int avio_printf(AVIOContext *s, const char *fmt, ...) av_printf_format(2, 3); diff --git a/libavformat/avio_internal.h b/libavformat/avio_internal.h index c01835df96fc1..04c1ad5157bf1 100644 --- a/libavformat/avio_internal.h +++ b/libavformat/avio_internal.h @@ -132,6 +132,14 @@ int ffio_open_dyn_packet_buf(AVIOContext **s, int max_packet_size); */ int ffio_fdopen(AVIOContext **s, URLContext *h); +/** + * Return the URLContext associated with the AVIOContext + * + * @param s IO context + * @return pointer to URLContext or NULL. + */ +URLContext *ffio_geturlcontext(AVIOContext *s); + /** * Open a write-only fake memory stream. The written data is not stored * anywhere - this is only used for measuring the amount of data diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c index 636cb46161ad0..52620c1a92c3d 100644 --- a/libavformat/aviobuf.c +++ b/libavformat/aviobuf.c @@ -87,6 +87,8 @@ int ffio_init_context(AVIOContext *s, int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), int64_t (*seek)(void *opaque, int64_t offset, int whence)) { + memset(s, 0, sizeof(AVIOContext)); + s->buffer = buffer; s->orig_buffer_size = s->buffer_size = buffer_size; @@ -135,7 +137,7 @@ AVIOContext *avio_alloc_context( int (*write_packet)(void *opaque, uint8_t *buf, int buf_size), int64_t (*seek)(void *opaque, int64_t offset, int whence)) { - AVIOContext *s = av_mallocz(sizeof(AVIOContext)); + AVIOContext *s = av_malloc(sizeof(AVIOContext)); if (!s) return NULL; ffio_init_context(s, buffer, buffer_size, write_flag, opaque, @@ -357,20 +359,9 @@ int avio_feof(AVIOContext *s) { if(!s) return 0; - if(s->eof_reached){ - s->eof_reached=0; - fill_buffer(s); - } return s->eof_reached; } -#if FF_API_URL_FEOF -int url_feof(AVIOContext *s) -{ - return avio_feof(s); -} -#endif - void avio_wl32(AVIOContext *s, unsigned int val) { avio_w8(s, (uint8_t) val ); @@ -531,6 +522,24 @@ void avio_write_marker(AVIOContext *s, int64_t time, enum AVIODataMarkerType typ s->last_time = time; } +static int read_packet_wrapper(AVIOContext *s, uint8_t *buf, int size) +{ + int ret; + + if (!s->read_packet) + return AVERROR(EINVAL); + ret = s->read_packet(s->opaque, buf, size); +#if FF_API_OLD_AVIO_EOF_0 + if (!ret && !s->max_packet_size) { + av_log(NULL, AV_LOG_WARNING, "Invalid return value 0 for stream protocol\n"); + ret = AVERROR_EOF; + } +#else + av_assert2(ret || s->max_packet_size); +#endif + return ret; +} + /* Input stream */ static void fill_buffer(AVIOContext *s) @@ -711,7 +720,7 @@ int avio_read_partial(AVIOContext *s, unsigned char *buf, int size) return -1; if (s->read_packet && s->write_flag) { - len = s->read_packet(s->opaque, buf, size); + len = read_packet_wrapper(s, buf, size); if (len > 0) s->pos += len; return len; @@ -812,6 +821,60 @@ int ff_get_line(AVIOContext *s, char *buf, int maxlen) return i; } +int ff_get_chomp_line(AVIOContext *s, char *buf, int maxlen) +{ + int len = ff_get_line(s, buf, maxlen); + while (len > 0 && av_isspace(buf[len - 1])) + buf[--len] = '\0'; + return len; +} + +int64_t ff_read_line_to_bprint(AVIOContext *s, AVBPrint *bp) +{ + int len, end; + int64_t read = 0; + char tmp[1024]; + char c; + + do { + len = 0; + do { + c = avio_r8(s); + end = (c == '\r' || c == '\n' || c == '\0'); + if (!end) + tmp[len++] = c; + } while (!end && len < sizeof(tmp)); + av_bprint_append_data(bp, tmp, len); + read += len; + } while (!end); + + if (c == '\r' && avio_r8(s) != '\n' && !avio_feof(s)) + avio_skip(s, -1); + + if (!c && s->error) + return s->error; + + if (!c && !read && avio_feof(s)) + return AVERROR_EOF; + + return read; +} + +int64_t ff_read_line_to_bprint_overwrite(AVIOContext *s, AVBPrint *bp) +{ + int64_t ret; + + av_bprint_clear(bp); + ret = ff_read_line_to_bprint(s, bp); + if (ret < 0) + return ret; + + if (!av_bprint_is_complete(bp)) + return AVERROR(ENOMEM); + + return bp->len; +} + int avio_get_str(AVIOContext *s, int maxlen, char *buf, int buflen) { int i; @@ -971,6 +1034,19 @@ int ffio_fdopen(AVIOContext **s, URLContext *h) return AVERROR(ENOMEM); } +URLContext* ffio_geturlcontext(AVIOContext *s) +{ + AVIOInternal *internal; + if (!s) + return NULL; + + internal = s->opaque; + if (internal && s->read_packet == io_read_packet) + return internal->h; + else + return NULL; +} + int ffio_ensure_seekback(AVIOContext *s, int64_t buf_size) { uint8_t *buffer; diff --git a/libavformat/avisynth.c b/libavformat/avisynth.c index 56700288f77be..250a489321edc 100644 --- a/libavformat/avisynth.c +++ b/libavformat/avisynth.c @@ -774,15 +774,15 @@ static av_cold int avisynth_read_header(AVFormatContext *s) int ret; // Calling library must implement a lock for thread-safe opens. - if (ret = avpriv_lock_avformat()) + if (ret = ff_lock_avformat()) return ret; if (ret = avisynth_open_file(s)) { - avpriv_unlock_avformat(); + ff_unlock_avformat(); return ret; } - avpriv_unlock_avformat(); + ff_unlock_avformat(); return 0; } @@ -818,11 +818,11 @@ static int avisynth_read_packet(AVFormatContext *s, AVPacket *pkt) static av_cold int avisynth_read_close(AVFormatContext *s) { - if (avpriv_lock_avformat()) + if (ff_lock_avformat()) return AVERROR_UNKNOWN; avisynth_context_destroy(s->priv_data); - avpriv_unlock_avformat(); + ff_unlock_avformat(); return 0; } diff --git a/libavformat/bintext.c b/libavformat/bintext.c index 12e3bfde4deb5..f1c0b3e8925b7 100644 --- a/libavformat/bintext.c +++ b/libavformat/bintext.c @@ -126,6 +126,53 @@ static void predict_width(AVCodecParameters *par, uint64_t fsize, int got_width) par->width = fsize > 4000 ? (160<<3) : (80<<3); } +static int bin_probe(AVProbeData *p) +{ + const uint8_t *d = p->buf; + int magic = 0, sauce = 0; + int invisible = 0; + int i; + + if (p->buf_size > 256) + magic = !memcmp(d + p->buf_size - 256, next_magic, sizeof(next_magic)); + if (p->buf_size > 128) + sauce = !memcmp(d + p->buf_size - 128, "SAUCE00", 7); + + if (magic) + return AVPROBE_SCORE_EXTENSION + 1; + + if (av_match_ext(p->filename, "bin")) { + AVCodecParameters par; + int got_width = 0; + par.width = par.height = 0; + if (sauce) + return AVPROBE_SCORE_EXTENSION + 1; + + predict_width(&par, p->buf_size, got_width); + if (par.width <= 0) + return 0; + calculate_height(&par, p->buf_size); + if (par.height <= 0) + return 0; + + for (i = 0; i < p->buf_size - 256; i+=2) { + if ((d[i+1] & 15) == (d[i+1] >> 4) && d[i] && d[i] != 0xFF && d[i] != ' ') { + invisible ++; + } + } + + if (par.width * par.height * 2 / (8*16) == p->buf_size) + return AVPROBE_SCORE_MAX / 2; + return 1; + } + + if (sauce) + return 1; + + return 0; +} + + static int bintext_read_header(AVFormatContext *s) { BinDemuxContext *bin = s->priv_data; @@ -343,9 +390,9 @@ AVInputFormat ff_bintext_demuxer = { .name = "bin", .long_name = NULL_IF_CONFIG_SMALL("Binary text"), .priv_data_size = sizeof(BinDemuxContext), + .read_probe = bin_probe, .read_header = bintext_read_header, .read_packet = read_packet, - .extensions = "bin", .priv_class = CLASS("Binary text demuxer"), }; #endif diff --git a/libavformat/cafenc.c b/libavformat/cafenc.c index f550cd965a3c8..0f7c4ebbb32c4 100644 --- a/libavformat/cafenc.c +++ b/libavformat/cafenc.c @@ -81,6 +81,8 @@ static uint32_t samples_per_packet(enum AVCodecID codec_id, int channels, int bl return 320; case AV_CODEC_ID_MP1: return 384; + case AV_CODEC_ID_OPUS: + return 960; case AV_CODEC_ID_MP2: case AV_CODEC_ID_MP3: return 1152; @@ -117,11 +119,15 @@ static int caf_write_header(AVFormatContext *s) switch (par->codec_id) { case AV_CODEC_ID_AAC: - case AV_CODEC_ID_OPUS: av_log(s, AV_LOG_ERROR, "muxing codec currently unsupported\n"); return AVERROR_PATCHWELCOME; } + if (par->codec_id == AV_CODEC_ID_OPUS && par->channels > 2) { + av_log(s, AV_LOG_ERROR, "Only mono and stereo are supported for Opus\n"); + return AVERROR_INVALIDDATA; + } + if (!codec_tag) { av_log(s, AV_LOG_ERROR, "unsupported codec\n"); return AVERROR_INVALIDDATA; diff --git a/libavformat/chromaprint.c b/libavformat/chromaprint.c index 4da02bef7622e..f39c09ddb92b9 100644 --- a/libavformat/chromaprint.c +++ b/libavformat/chromaprint.c @@ -20,6 +20,7 @@ */ #include "avformat.h" +#include "internal.h" #include "libavutil/opt.h" #include "libavcodec/internal.h" #include @@ -49,9 +50,9 @@ typedef struct ChromaprintMuxContext { static void cleanup(ChromaprintMuxContext *cpr) { if (cpr->ctx) { - avpriv_lock_avformat(); + ff_lock_avformat(); chromaprint_free(cpr->ctx); - avpriv_unlock_avformat(); + ff_unlock_avformat(); } } @@ -60,9 +61,9 @@ static int write_header(AVFormatContext *s) ChromaprintMuxContext *cpr = s->priv_data; AVStream *st; - avpriv_lock_avformat(); + ff_lock_avformat(); cpr->ctx = chromaprint_new(cpr->algorithm); - avpriv_unlock_avformat(); + ff_unlock_avformat(); if (!cpr->ctx) { av_log(s, AV_LOG_ERROR, "Failed to create chromaprint context.\n"); diff --git a/libavformat/codec2.c b/libavformat/codec2.c new file mode 100644 index 0000000000000..28dbbd8176f44 --- /dev/null +++ b/libavformat/codec2.c @@ -0,0 +1,285 @@ +/* + * codec2 muxer and demuxers + * Copyright (c) 2017 Tomas Härdin + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "libavcodec/codec2utils.h" +#include "libavutil/intreadwrite.h" +#include "avio_internal.h" +#include "avformat.h" +#include "internal.h" +#include "rawdec.h" +#include "rawenc.h" +#include "pcm.h" + +#define AVPRIV_CODEC2_HEADER_SIZE 7 +#define AVPRIV_CODEC2_MAGIC 0xC0DEC2 + +//the lowest version we should ever run across is 0.8 +//we may run across later versions as the format evolves +#define EXPECTED_CODEC2_MAJOR_VERSION 0 +#define EXPECTED_CODEC2_MINOR_VERSION 8 + +typedef struct { + const AVClass *class; + int mode; + int frames_per_packet; +} Codec2Context; + +static int codec2_probe(AVProbeData *p) +{ + //must start wih C0 DE C2 + if (AV_RB24(p->buf) != AVPRIV_CODEC2_MAGIC) { + return 0; + } + + //no .c2 files prior to 0.8 + //be strict about major version while we're at it + if (p->buf[3] != EXPECTED_CODEC2_MAJOR_VERSION || + p->buf[4] < EXPECTED_CODEC2_MINOR_VERSION) { + return 0; + } + + //32 bits of identification -> low score + return AVPROBE_SCORE_EXTENSION + 1; +} + +static int codec2_read_header_common(AVFormatContext *s, AVStream *st) +{ + int mode = avpriv_codec2_mode_from_extradata(st->codecpar->extradata); + + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + st->codecpar->codec_id = AV_CODEC_ID_CODEC2; + st->codecpar->sample_rate = 8000; + st->codecpar->channels = 1; + st->codecpar->format = AV_SAMPLE_FMT_S16; + st->codecpar->channel_layout = AV_CH_LAYOUT_MONO; + st->codecpar->bit_rate = avpriv_codec2_mode_bit_rate(s, mode); + st->codecpar->frame_size = avpriv_codec2_mode_frame_size(s, mode); + st->codecpar->block_align = avpriv_codec2_mode_block_align(s, mode); + + if (st->codecpar->bit_rate <= 0 || + st->codecpar->frame_size <= 0 || + st->codecpar->block_align <= 0) { + return AVERROR_INVALIDDATA; + } + + avpriv_set_pts_info(st, 64, 1, st->codecpar->sample_rate); + + return 0; +} + +static int codec2_read_header(AVFormatContext *s) +{ + AVStream *st = avformat_new_stream(s, NULL); + int ret, version; + + if (!st) { + return AVERROR(ENOMEM); + } + + if (avio_rb24(s->pb) != AVPRIV_CODEC2_MAGIC) { + av_log(s, AV_LOG_ERROR, "not a .c2 file\n"); + return AVERROR_INVALIDDATA; + } + + ret = ff_alloc_extradata(st->codecpar, AVPRIV_CODEC2_EXTRADATA_SIZE); + if (ret) { + return ret; + } + + ret = ffio_read_size(s->pb, st->codecpar->extradata, AVPRIV_CODEC2_EXTRADATA_SIZE); + if (ret < 0) { + return ret; + } + + version = avpriv_codec2_version_from_extradata(st->codecpar->extradata); + if ((version >> 8) != EXPECTED_CODEC2_MAJOR_VERSION) { + avpriv_report_missing_feature(s, "Major version %i", version >> 8); + return AVERROR_PATCHWELCOME; + } + + s->internal->data_offset = AVPRIV_CODEC2_HEADER_SIZE; + + return codec2_read_header_common(s, st); +} + +static int codec2_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + Codec2Context *c2 = s->priv_data; + AVStream *st = s->streams[0]; + int ret, size, n, block_align, frame_size; + + block_align = st->codecpar->block_align; + frame_size = st->codecpar->frame_size; + + if (block_align <= 0 || frame_size <= 0 || c2->frames_per_packet <= 0) { + return AVERROR(EINVAL); + } + + //try to read desired number of frames, compute n from to actual number of bytes read + size = c2->frames_per_packet * block_align; + ret = av_get_packet(s->pb, pkt, size); + if (ret < 0) { + return ret; + } + + //only set duration - compute_pkt_fields() and ff_pcm_read_seek() takes care of everything else + //tested by spamming the seek functionality in ffplay + n = ret / block_align; + pkt->duration = n * frame_size; + + return ret; +} + +static int codec2_write_header(AVFormatContext *s) +{ + AVStream *st; + + if (s->nb_streams != 1 || s->streams[0]->codecpar->codec_id != AV_CODEC_ID_CODEC2) { + av_log(s, AV_LOG_ERROR, ".c2 files must have exactly one codec2 stream\n"); + return AVERROR(EINVAL); + } + + st = s->streams[0]; + + if (st->codecpar->extradata_size != AVPRIV_CODEC2_EXTRADATA_SIZE) { + av_log(s, AV_LOG_ERROR, ".c2 files require exactly %i bytes of extradata (got %i)\n", + AVPRIV_CODEC2_EXTRADATA_SIZE, st->codecpar->extradata_size); + return AVERROR(EINVAL); + } + + avio_wb24(s->pb, AVPRIV_CODEC2_MAGIC); + avio_write(s->pb, st->codecpar->extradata, AVPRIV_CODEC2_EXTRADATA_SIZE); + + return 0; +} + +static int codec2raw_read_header(AVFormatContext *s) +{ + Codec2Context *c2 = s->priv_data; + AVStream *st; + int ret; + + if (c2->mode < 0) { + //FIXME: using a default value of -1 for mandatory options is an incredibly ugly hack + av_log(s, AV_LOG_ERROR, "-mode must be set in order to make sense of raw codec2 files\n"); + return AVERROR(EINVAL); + } + + st = avformat_new_stream(s, NULL); + if (!st) { + return AVERROR(ENOMEM); + } + + ret = ff_alloc_extradata(st->codecpar, AVPRIV_CODEC2_EXTRADATA_SIZE); + if (ret) { + return ret; + } + + s->internal->data_offset = 0; + avpriv_codec2_make_extradata(st->codecpar->extradata, c2->mode); + + return codec2_read_header_common(s, st); +} + +//transcoding report2074.c2 to wav went from 7.391s to 5.322s with -frames_per_packet 1000 compared to default, same sha1sum +#define FRAMES_PER_PACKET \ + { "frames_per_packet", "Number of frames to read at a time. Higher = faster decoding, lower granularity", \ + offsetof(Codec2Context, frames_per_packet), AV_OPT_TYPE_INT, {.i64 = 1}, 1, INT_MAX, AV_OPT_FLAG_DECODING_PARAM} + +static const AVOption codec2_options[] = { + FRAMES_PER_PACKET, + { NULL }, +}; + +static const AVOption codec2raw_options[] = { + AVPRIV_CODEC2_AVOPTIONS("codec2 mode [mandatory]", Codec2Context, -1, -1, AV_OPT_FLAG_DECODING_PARAM), + FRAMES_PER_PACKET, + { NULL }, +}; + +static const AVClass codec2_mux_class = { + .class_name = "codec2 muxer", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, + .category = AV_CLASS_CATEGORY_DEMUXER, +}; + +static const AVClass codec2_demux_class = { + .class_name = "codec2 demuxer", + .item_name = av_default_item_name, + .option = codec2_options, + .version = LIBAVUTIL_VERSION_INT, + .category = AV_CLASS_CATEGORY_DEMUXER, +}; + +static const AVClass codec2raw_demux_class = { + .class_name = "codec2raw demuxer", + .item_name = av_default_item_name, + .option = codec2raw_options, + .version = LIBAVUTIL_VERSION_INT, + .category = AV_CLASS_CATEGORY_DEMUXER, +}; + +#if CONFIG_CODEC2_DEMUXER +AVInputFormat ff_codec2_demuxer = { + .name = "codec2", + .long_name = NULL_IF_CONFIG_SMALL("codec2 .c2 demuxer"), + .priv_data_size = sizeof(Codec2Context), + .extensions = "c2", + .read_probe = codec2_probe, + .read_header = codec2_read_header, + .read_packet = codec2_read_packet, + .read_seek = ff_pcm_read_seek, + .flags = AVFMT_GENERIC_INDEX, + .raw_codec_id = AV_CODEC_ID_CODEC2, + .priv_class = &codec2_demux_class, +}; +#endif + +#if CONFIG_CODEC2_MUXER +AVOutputFormat ff_codec2_muxer = { + .name = "codec2", + .long_name = NULL_IF_CONFIG_SMALL("codec2 .c2 muxer"), + .priv_data_size = sizeof(Codec2Context), + .extensions = "c2", + .audio_codec = AV_CODEC_ID_CODEC2, + .video_codec = AV_CODEC_ID_NONE, + .write_header = codec2_write_header, + .write_packet = ff_raw_write_packet, + .flags = AVFMT_NOTIMESTAMPS, + .priv_class = &codec2_mux_class, +}; +#endif + +#if CONFIG_CODEC2RAW_DEMUXER +AVInputFormat ff_codec2raw_demuxer = { + .name = "codec2raw", + .long_name = NULL_IF_CONFIG_SMALL("raw codec2 demuxer"), + .priv_data_size = sizeof(Codec2Context), + .read_header = codec2raw_read_header, + .read_packet = codec2_read_packet, + .read_seek = ff_pcm_read_seek, + .flags = AVFMT_GENERIC_INDEX, + .raw_codec_id = AV_CODEC_ID_CODEC2, + .priv_class = &codec2raw_demux_class, +}; +#endif diff --git a/libavformat/concatdec.c b/libavformat/concatdec.c index 0e189012adf27..f05e935cb0691 100644 --- a/libavformat/concatdec.c +++ b/libavformat/concatdec.c @@ -20,6 +20,7 @@ #include "libavutil/avassert.h" #include "libavutil/avstring.h" +#include "libavutil/bprint.h" #include "libavutil/intreadwrite.h" #include "libavutil/opt.h" #include "libavutil/parseutils.h" @@ -64,6 +65,8 @@ typedef struct { ConcatMatchMode stream_match_mode; unsigned auto_convert; int segment_time_metadata; + AVDictionary *options; + int error; } ConcatContext; static int concat_probe(AVProbeData *probe) @@ -126,10 +129,10 @@ static int add_file(AVFormatContext *avf, char *filename, ConcatFile **rfile, url = filename; filename = NULL; } else { - url_len = strlen(avf->filename) + strlen(filename) + 16; + url_len = strlen(avf->url) + strlen(filename) + 16; if (!(url = av_malloc(url_len))) FAIL(AVERROR(ENOMEM)); - ff_make_absolute_url(url, url_len, avf->filename, filename); + ff_make_absolute_url(url, url_len, avf->url, filename); av_freep(&filename); } @@ -185,8 +188,8 @@ static int copy_stream_props(AVStream *st, AVStream *source_st) return ret; st->r_frame_rate = source_st->r_frame_rate; st->avg_frame_rate = source_st->avg_frame_rate; - st->time_base = source_st->time_base; st->sample_aspect_ratio = source_st->sample_aspect_ratio; + avpriv_set_pts_info(st, 64, source_st->time_base.num, source_st->time_base.den); av_dict_copy(&st->metadata, source_st->metadata, 0); return 0; @@ -317,27 +320,67 @@ static int open_file(AVFormatContext *avf, unsigned fileno) { ConcatContext *cat = avf->priv_data; ConcatFile *file = &cat->files[fileno]; + AVFormatContext *new_avf = NULL; int ret; + AVDictionary *tmp = NULL; + AVDictionaryEntry *t = NULL; + int fps_flag = 0; - if (cat->avf) - avformat_close_input(&cat->avf); - - cat->avf = avformat_alloc_context(); - if (!cat->avf) + new_avf = avformat_alloc_context(); + if (!new_avf) return AVERROR(ENOMEM); - cat->avf->flags |= avf->flags & ~AVFMT_FLAG_CUSTOM_IO; - cat->avf->interrupt_callback = avf->interrupt_callback; + new_avf->flags |= avf->flags & ~AVFMT_FLAG_CUSTOM_IO; + +#ifdef FF_API_LAVF_KEEPSIDE_FLAG + if (avf->flags & AVFMT_FLAG_KEEP_SIDE_DATA) { + new_avf->flags |= AVFMT_FLAG_KEEP_SIDE_DATA; + } +#endif + new_avf->interrupt_callback = avf->interrupt_callback; - if ((ret = ff_copy_whiteblacklists(cat->avf, avf)) < 0) + if ((ret = ff_copy_whiteblacklists(new_avf, avf)) < 0) return ret; - if ((ret = avformat_open_input(&cat->avf, file->url, NULL, NULL)) < 0 || - (ret = avformat_find_stream_info(cat->avf, NULL)) < 0) { + if (cat->options) + av_dict_copy(&tmp, cat->options, 0); + + av_dict_set_int(&tmp, "cur_file_no", fileno, 0); + + t = av_dict_get(tmp, "skip-calc-frame-rate", NULL, AV_DICT_MATCH_CASE); + if (t) { + fps_flag = (int) strtol(t->value, NULL, 10); + if (fps_flag > 0) { + av_dict_set_int(&new_avf->metadata, "skip-calc-frame-rate", fps_flag, 0); + } + } + + t = av_dict_get(tmp, "nb-streams", NULL, AV_DICT_MATCH_CASE); + if (t) { + int nb_streams = (int) strtol(t->value, NULL, 10); + if (nb_streams > 0) { + av_dict_set_int(&new_avf->metadata, "nb-streams", nb_streams, 0); + av_dict_set_int(&cat->options, "nb-streams", 0, 0); + } + } + + ret = avformat_open_input(&new_avf, file->url, NULL, &tmp); + av_dict_free(&tmp); + if (ret < 0 || + (ret = avformat_find_stream_info(new_avf, NULL)) < 0) { av_log(avf, AV_LOG_ERROR, "Impossible to open '%s'\n", file->url); - avformat_close_input(&cat->avf); + avformat_close_input(&new_avf); return ret; } + + if (!new_avf) + return 0; + + if (cat->avf) + avformat_close_input(&cat->avf); + + avf->bit_rate = new_avf->bit_rate; + cat->avf = new_avf; cat->cur_file = file; if (file->start_time == AV_NOPTS_VALUE) file->start_time = !fileno ? 0 : @@ -379,25 +422,29 @@ static int concat_read_close(AVFormatContext *avf) } if (cat->avf) avformat_close_input(&cat->avf); + av_dict_free(&cat->options); av_freep(&cat->files); return 0; } -static int concat_read_header(AVFormatContext *avf) +static int concat_read_header(AVFormatContext *avf, AVDictionary **options) { ConcatContext *cat = avf->priv_data; - uint8_t buf[4096]; + AVBPrint bp; uint8_t *cursor, *keyword; - int ret, line = 0, i; + int line = 0, i; unsigned nb_files_alloc = 0; ConcatFile *file = NULL; - int64_t time = 0; + int64_t ret, time = 0; - while (1) { - if ((ret = ff_get_line(avf->pb, buf, sizeof(buf))) <= 0) - break; + if (options && *options) + av_dict_copy(&cat->options, *options, 0); + + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); + + while ((ret = ff_read_line_to_bprint_overwrite(avf->pb, &bp)) >= 0) { line++; - cursor = buf; + cursor = bp.str; keyword = get_keyword(&cursor); if (!*keyword || *keyword == '#') continue; @@ -473,7 +520,7 @@ static int concat_read_header(AVFormatContext *avf) FAIL(AVERROR_INVALIDDATA); } } - if (ret < 0) + if (ret != AVERROR_EOF && ret < 0) goto fail; if (!cat->nb_files) FAIL(AVERROR_INVALIDDATA); @@ -499,9 +546,11 @@ static int concat_read_header(AVFormatContext *avf) MATCH_ONE_TO_ONE; if ((ret = open_file(avf, 0)) < 0) goto fail; + av_bprint_finalize(&bp, NULL); return 0; fail: + av_bprint_finalize(&bp, NULL); concat_read_close(avf); return ret; } @@ -562,6 +611,7 @@ static int packet_after_outpoint(ConcatContext *cat, AVPacket *pkt) return 0; } +#define CONCAT_MAX_OPEN_TRY 3 static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt) { ConcatContext *cat = avf->priv_data; @@ -569,6 +619,13 @@ static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt) int64_t delta; ConcatStream *cs; AVStream *st; + int try_counter = 0; + int is_new_st = 0; + + if (cat->error) { + ret = cat->error; + return ret; + } if (cat->eof) return AVERROR_EOF; @@ -579,12 +636,20 @@ static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt) while (1) { ret = av_read_frame(cat->avf, pkt); if (ret == AVERROR_EOF) { + is_new_st = 1; if ((ret = open_next_file(avf)) < 0) - return ret; + goto open_fail; continue; } - if (ret < 0) + if (ret < 0) { + if (avf->pb && cat->avf->pb) + avf->pb->error = cat->avf->pb->error; return ret; + } + if (is_new_st) { + pkt->flags |= AV_PKT_FLAG_NEW_SEG; + is_new_st = 0; + } if ((ret = match_streams(avf)) < 0) { av_packet_unref(pkt); return ret; @@ -592,7 +657,7 @@ static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt) if (packet_after_outpoint(cat, pkt)) { av_packet_unref(pkt); if ((ret = open_next_file(avf)) < 0) - return ret; + goto open_fail; continue; } cs = &cat->cur_file->streams[pkt->stream_index]; @@ -600,8 +665,17 @@ static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt) av_packet_unref(pkt); continue; } - pkt->stream_index = cs->out_stream_index; break; +open_fail: + ++try_counter; + if (try_counter > CONCAT_MAX_OPEN_TRY) { + cat->error = ret; + if (avf->pb && ret != AVERROR_EOF) + avf->pb->error = ret; + return AVERROR_EOF; + } + + av_log(avf, AV_LOG_WARNING, "open_next_file() failed (%d)\n", try_counter); } if ((ret = filter_packet(avf, cs, pkt))) return ret; @@ -643,6 +717,7 @@ static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt) } } + pkt->stream_index = cs->out_stream_index; return ret; } @@ -725,6 +800,9 @@ static int concat_seek(AVFormatContext *avf, int stream, AVFormatContext *cur_avf_saved = cat->avf; int ret; + /* reset error/complete state */ + cat->error = 0; + if (!cat->seekable) return AVERROR(ESPIPE); /* XXX: can we use it? */ if (flags & (AVSEEK_FLAG_BYTE | AVSEEK_FLAG_FRAME)) @@ -772,7 +850,7 @@ AVInputFormat ff_concat_demuxer = { .long_name = NULL_IF_CONFIG_SMALL("Virtual concatenation script"), .priv_data_size = sizeof(ConcatContext), .read_probe = concat_probe, - .read_header = concat_read_header, + .read_header2 = concat_read_header, .read_packet = concat_read_packet, .read_close = concat_read_close, .read_seek2 = concat_seek, diff --git a/libavformat/dashdec.c b/libavformat/dashdec.c index f63f1fffbd33f..8bfde4dbce3a9 100644 --- a/libavformat/dashdec.c +++ b/libavformat/dashdec.c @@ -84,6 +84,10 @@ struct representation { int stream_index; enum AVMediaType type; + char id[20]; + int bandwidth; + AVRational framerate; + AVStream *assoc_stream; /* demuxer stream associated with this representation */ int n_fragments; struct fragment **fragments; /* VOD list of fragment for profile */ @@ -118,8 +122,11 @@ struct representation { typedef struct DASHContext { const AVClass *class; char *base_url; - struct representation *cur_video; - struct representation *cur_audio; + + int n_videos; + struct representation **videos; + int n_audios; + struct representation **audios; /* MediaPresentationDescription Attribute */ uint64_t media_presentation_duration; @@ -141,8 +148,20 @@ typedef struct DASHContext { char *headers; ///< holds HTTP headers set as an AVOption to the HTTP protocol context char *allowed_extensions; AVDictionary *avio_opts; + int max_url_size; } DASHContext; +static int ishttp(char *url) +{ + const char *proto_name = avio_find_protocol_name(url); + return av_strstart(proto_name, "http", NULL); +} + +static int aligned(int val) +{ + return ((val + 0x3F) >> 6) << 6; +} + static uint64_t get_current_time_in_sec(void) { return av_gettime() / 1000000; @@ -328,17 +347,39 @@ static void free_representation(struct representation *pls) } av_freep(&pls->url_template); - av_freep(pls); + av_freep(&pls); +} + +static void free_video_list(DASHContext *c) +{ + int i; + for (i = 0; i < c->n_videos; i++) { + struct representation *pls = c->videos[i]; + free_representation(pls); + } + av_freep(&c->videos); + c->n_videos = 0; } -static void set_httpheader_options(DASHContext *c, AVDictionary *opts) +static void free_audio_list(DASHContext *c) +{ + int i; + for (i = 0; i < c->n_audios; i++) { + struct representation *pls = c->audios[i]; + free_representation(pls); + } + av_freep(&c->audios); + c->n_audios = 0; +} + +static void set_httpheader_options(DASHContext *c, AVDictionary **opts) { // broker prior HTTP options that should be consistent across requests - av_dict_set(&opts, "user-agent", c->user_agent, 0); - av_dict_set(&opts, "cookies", c->cookies, 0); - av_dict_set(&opts, "headers", c->headers, 0); + av_dict_set(opts, "user-agent", c->user_agent, 0); + av_dict_set(opts, "cookies", c->cookies, 0); + av_dict_set(opts, "headers", c->headers, 0); if (c->is_live) { - av_dict_set(&opts, "seekable", "0", 0); + av_dict_set(opts, "seekable", "0", 0); } } static void update_options(char **dest, const char *name, void *src) @@ -392,7 +433,8 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, else if (strcmp(proto_name, "file") || !strncmp(url, "file,", 5)) return AVERROR_INVALIDDATA; - ret = s->io_open(s, pb, url, AVIO_FLAG_READ, &tmp); + av_freep(pb); + ret = avio_open2(pb, url, AVIO_FLAG_READ, c->interrupt_callback, &tmp); if (ret >= 0) { // update cookies on http response with setcookies. char *new_cookies = NULL; @@ -418,6 +460,7 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, static char *get_content_url(xmlNodePtr *baseurl_nodes, int n_baseurl_nodes, + int max_url_size, char *rep_id_val, char *rep_bandwidth_val, char *val) @@ -425,10 +468,12 @@ static char *get_content_url(xmlNodePtr *baseurl_nodes, int i; char *text; char *url = NULL; - char tmp_str[MAX_URL_SIZE]; - char tmp_str_2[MAX_URL_SIZE]; + char *tmp_str = av_mallocz(max_url_size); + char *tmp_str_2 = av_mallocz(max_url_size); - memset(tmp_str, 0, sizeof(tmp_str)); + if (!tmp_str || !tmp_str_2) { + return NULL; + } for (i = 0; i < n_baseurl_nodes; ++i) { if (baseurl_nodes[i] && @@ -436,32 +481,36 @@ static char *get_content_url(xmlNodePtr *baseurl_nodes, baseurl_nodes[i]->children->type == XML_TEXT_NODE) { text = xmlNodeGetContent(baseurl_nodes[i]->children); if (text) { - memset(tmp_str, 0, sizeof(tmp_str)); - memset(tmp_str_2, 0, sizeof(tmp_str_2)); - ff_make_absolute_url(tmp_str_2, MAX_URL_SIZE, tmp_str, text); - av_strlcpy(tmp_str, tmp_str_2, sizeof(tmp_str)); + memset(tmp_str, 0, max_url_size); + memset(tmp_str_2, 0, max_url_size); + ff_make_absolute_url(tmp_str_2, max_url_size, tmp_str, text); + av_strlcpy(tmp_str, tmp_str_2, max_url_size); xmlFree(text); } } } if (val) - av_strlcat(tmp_str, (const char*)val, sizeof(tmp_str)); + av_strlcat(tmp_str, (const char*)val, max_url_size); if (rep_id_val) { url = av_strireplace(tmp_str, "$RepresentationID$", (const char*)rep_id_val); if (!url) { - return NULL; + goto end; } - av_strlcpy(tmp_str, url, sizeof(tmp_str)); - av_free(url); + av_strlcpy(tmp_str, url, max_url_size); } if (rep_bandwidth_val && tmp_str[0] != '\0') { + // free any previously assigned url before reassigning + av_free(url); url = av_strireplace(tmp_str, "$Bandwidth$", (const char*)rep_bandwidth_val); if (!url) { - return NULL; + goto end; } } +end: + av_free(tmp_str); + av_free(tmp_str_2); return url; } @@ -522,55 +571,85 @@ static enum AVMediaType get_content_type(xmlNodePtr node) return type; } +static struct fragment * get_Fragment(char *range) +{ + struct fragment * seg = av_mallocz(sizeof(struct fragment)); + + if (!seg) + return NULL; + + seg->size = -1; + if (range) { + char *str_end_offset; + char *str_offset = av_strtok(range, "-", &str_end_offset); + seg->url_offset = strtoll(str_offset, NULL, 10); + seg->size = strtoll(str_end_offset, NULL, 10) - seg->url_offset; + } + + return seg; +} + static int parse_manifest_segmenturlnode(AVFormatContext *s, struct representation *rep, xmlNodePtr fragmenturl_node, xmlNodePtr *baseurl_nodes, char *rep_id_val, char *rep_bandwidth_val) { + DASHContext *c = s->priv_data; char *initialization_val = NULL; char *media_val = NULL; + char *range_val = NULL; + int max_url_size = c ? c->max_url_size: MAX_URL_SIZE; if (!av_strcasecmp(fragmenturl_node->name, (const char *)"Initialization")) { initialization_val = xmlGetProp(fragmenturl_node, "sourceURL"); - if (initialization_val) { - rep->init_section = av_mallocz(sizeof(struct fragment)); + range_val = xmlGetProp(fragmenturl_node, "range"); + if (initialization_val || range_val) { + rep->init_section = get_Fragment(range_val); if (!rep->init_section) { xmlFree(initialization_val); + xmlFree(range_val); return AVERROR(ENOMEM); } rep->init_section->url = get_content_url(baseurl_nodes, 4, + max_url_size, rep_id_val, rep_bandwidth_val, initialization_val); + if (!rep->init_section->url) { av_free(rep->init_section); xmlFree(initialization_val); + xmlFree(range_val); return AVERROR(ENOMEM); } - rep->init_section->size = -1; xmlFree(initialization_val); + xmlFree(range_val); } } else if (!av_strcasecmp(fragmenturl_node->name, (const char *)"SegmentURL")) { media_val = xmlGetProp(fragmenturl_node, "media"); - if (media_val) { - struct fragment *seg = av_mallocz(sizeof(struct fragment)); + range_val = xmlGetProp(fragmenturl_node, "mediaRange"); + if (media_val || range_val) { + struct fragment *seg = get_Fragment(range_val); if (!seg) { xmlFree(media_val); + xmlFree(range_val); return AVERROR(ENOMEM); } seg->url = get_content_url(baseurl_nodes, 4, + max_url_size, rep_id_val, rep_bandwidth_val, media_val); if (!seg->url) { av_free(seg); xmlFree(media_val); + xmlFree(range_val); return AVERROR(ENOMEM); } - seg->size = -1; dynarray_add(&rep->fragments, &rep->n_fragments, seg); xmlFree(media_val); + xmlFree(range_val); } } @@ -613,14 +692,121 @@ static int parse_manifest_segmenttimeline(AVFormatContext *s, struct representat return 0; } +static int resolve_content_path(AVFormatContext *s, const char *url, int *max_url_size, xmlNodePtr *baseurl_nodes, int n_baseurl_nodes) { + + char *tmp_str = NULL; + char *path = NULL; + char *mpdName = NULL; + xmlNodePtr node = NULL; + char *baseurl = NULL; + char *root_url = NULL; + char *text = NULL; + + int isRootHttp = 0; + char token ='/'; + int start = 0; + int rootId = 0; + int updated = 0; + int size = 0; + int i; + int tmp_max_url_size = strlen(url); + + for (i = n_baseurl_nodes-1; i >= 0 ; i--) { + text = xmlNodeGetContent(baseurl_nodes[i]); + if (!text) + continue; + tmp_max_url_size += strlen(text); + if (ishttp(text)) { + xmlFree(text); + break; + } + xmlFree(text); + } + + tmp_max_url_size = aligned(tmp_max_url_size); + text = av_mallocz(tmp_max_url_size); + if (!text) { + updated = AVERROR(ENOMEM); + goto end; + } + av_strlcpy(text, url, strlen(url)+1); + while (mpdName = av_strtok(text, "/", &text)) { + size = strlen(mpdName); + } + + path = av_mallocz(tmp_max_url_size); + tmp_str = av_mallocz(tmp_max_url_size); + if (!tmp_str || !path) { + updated = AVERROR(ENOMEM); + goto end; + } + + av_strlcpy (path, url, strlen(url) - size + 1); + for (rootId = n_baseurl_nodes - 1; rootId > 0; rootId --) { + if (!(node = baseurl_nodes[rootId])) { + continue; + } + if (ishttp(xmlNodeGetContent(node))) { + break; + } + } + + node = baseurl_nodes[rootId]; + baseurl = xmlNodeGetContent(node); + root_url = (av_strcasecmp(baseurl, "")) ? baseurl : path; + if (node) { + xmlNodeSetContent(node, root_url); + updated = 1; + } + + size = strlen(root_url); + isRootHttp = ishttp(root_url); + + if (root_url[size - 1] != token) { + av_strlcat(root_url, "/", size + 2); + size += 2; + } + + for (i = 0; i < n_baseurl_nodes; ++i) { + if (i == rootId) { + continue; + } + text = xmlNodeGetContent(baseurl_nodes[i]); + if (text) { + memset(tmp_str, 0, strlen(tmp_str)); + if (!ishttp(text) && isRootHttp) { + av_strlcpy(tmp_str, root_url, size + 1); + } + start = (text[0] == token); + av_strlcat(tmp_str, text + start, tmp_max_url_size); + xmlNodeSetContent(baseurl_nodes[i], tmp_str); + updated = 1; + xmlFree(text); + } + } + +end: + if (tmp_max_url_size > *max_url_size) { + *max_url_size = tmp_max_url_size; + } + av_free(path); + av_free(tmp_str); + return updated; + +} + static int parse_manifest_representation(AVFormatContext *s, const char *url, xmlNodePtr node, xmlNodePtr adaptionset_node, xmlNodePtr mpd_baseurl_node, xmlNodePtr period_baseurl_node, + xmlNodePtr period_segmenttemplate_node, + xmlNodePtr period_segmentlist_node, xmlNodePtr fragment_template_node, xmlNodePtr content_component_node, - xmlNodePtr adaptionset_baseurl_node) + xmlNodePtr adaptionset_baseurl_node, + xmlNodePtr adaptionset_segmentlist_node, + xmlNodePtr adaptionset_supplementalproperty_node) { int32_t ret = 0; int32_t audio_rep_idx = 0; @@ -631,18 +817,21 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, xmlNodePtr representation_segmenttemplate_node = NULL; xmlNodePtr representation_baseurl_node = NULL; xmlNodePtr representation_segmentlist_node = NULL; + xmlNodePtr segmentlists_tab[2]; xmlNodePtr fragment_timeline_node = NULL; - xmlNodePtr fragment_templates_tab[2]; + xmlNodePtr fragment_templates_tab[5]; char *duration_val = NULL; char *presentation_timeoffset_val = NULL; char *startnumber_val = NULL; char *timescale_val = NULL; char *initialization_val = NULL; char *media_val = NULL; + char *val = NULL; xmlNodePtr baseurl_nodes[4]; xmlNodePtr representation_node = node; char *rep_id_val = xmlGetProp(representation_node, "id"); char *rep_bandwidth_val = xmlGetProp(representation_node, "bandwidth"); + char *rep_framerate_val = xmlGetProp(representation_node, "frameRate"); enum AVMediaType type = AVMEDIA_TYPE_UNKNOWN; // try get information from representation @@ -656,7 +845,7 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, type = get_content_type(adaptionset_node); if (type == AVMEDIA_TYPE_UNKNOWN) { av_log(s, AV_LOG_VERBOSE, "Parsing '%s' - skipp not supported representation type\n", url); - } else if ((type == AVMEDIA_TYPE_VIDEO && !c->cur_video) || (type == AVMEDIA_TYPE_AUDIO && !c->cur_audio)) { + } else if (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO) { // convert selected representation to our internal struct rep = av_mallocz(sizeof(struct representation)); if (!rep) { @@ -672,17 +861,25 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, baseurl_nodes[2] = adaptionset_baseurl_node; baseurl_nodes[3] = representation_baseurl_node; - if (representation_segmenttemplate_node || fragment_template_node) { + ret = resolve_content_path(s, url, &c->max_url_size, baseurl_nodes, 4); + c->max_url_size = aligned(c->max_url_size + strlen(rep_id_val) + strlen(rep_bandwidth_val)); + if (ret == AVERROR(ENOMEM) || ret == 0) { + goto end; + } + if (representation_segmenttemplate_node || fragment_template_node || period_segmenttemplate_node) { fragment_timeline_node = NULL; fragment_templates_tab[0] = representation_segmenttemplate_node; - fragment_templates_tab[1] = fragment_template_node; - - presentation_timeoffset_val = get_val_from_nodes_tab(fragment_templates_tab, 2, "presentationTimeOffset"); - duration_val = get_val_from_nodes_tab(fragment_templates_tab, 2, "duration"); - startnumber_val = get_val_from_nodes_tab(fragment_templates_tab, 2, "startNumber"); - timescale_val = get_val_from_nodes_tab(fragment_templates_tab, 2, "timescale"); - initialization_val = get_val_from_nodes_tab(fragment_templates_tab, 2, "initialization"); - media_val = get_val_from_nodes_tab(fragment_templates_tab, 2, "media"); + fragment_templates_tab[1] = adaptionset_segmentlist_node; + fragment_templates_tab[2] = fragment_template_node; + fragment_templates_tab[3] = period_segmenttemplate_node; + fragment_templates_tab[4] = period_segmentlist_node; + + presentation_timeoffset_val = get_val_from_nodes_tab(fragment_templates_tab, 4, "presentationTimeOffset"); + duration_val = get_val_from_nodes_tab(fragment_templates_tab, 4, "duration"); + startnumber_val = get_val_from_nodes_tab(fragment_templates_tab, 4, "startNumber"); + timescale_val = get_val_from_nodes_tab(fragment_templates_tab, 4, "timescale"); + initialization_val = get_val_from_nodes_tab(fragment_templates_tab, 4, "initialization"); + media_val = get_val_from_nodes_tab(fragment_templates_tab, 4, "media"); if (initialization_val) { rep->init_section = av_mallocz(sizeof(struct fragment)); @@ -691,7 +888,8 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, ret = AVERROR(ENOMEM); goto end; } - rep->init_section->url = get_content_url(baseurl_nodes, 4, rep_id_val, rep_bandwidth_val, initialization_val); + c->max_url_size = aligned(c->max_url_size + strlen(initialization_val)); + rep->init_section->url = get_content_url(baseurl_nodes, 4, c->max_url_size, rep_id_val, rep_bandwidth_val, initialization_val); if (!rep->init_section->url) { av_free(rep->init_section); av_free(rep); @@ -703,7 +901,8 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, } if (media_val) { - rep->url_template = get_content_url(baseurl_nodes, 4, rep_id_val, rep_bandwidth_val, media_val); + c->max_url_size = aligned(c->max_url_size + strlen(media_val)); + rep->url_template = get_content_url(baseurl_nodes, 4, c->max_url_size, rep_id_val, rep_bandwidth_val, media_val); xmlFree(media_val); } @@ -723,11 +922,26 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, rep->first_seq_no = (int64_t) strtoll(startnumber_val, NULL, 10); xmlFree(startnumber_val); } + if (adaptionset_supplementalproperty_node) { + if (!av_strcasecmp(xmlGetProp(adaptionset_supplementalproperty_node,"schemeIdUri"), "http://dashif.org/guidelines/last-segment-number")) { + val = xmlGetProp(adaptionset_supplementalproperty_node,"value"); + if (!val) { + av_log(s, AV_LOG_ERROR, "Missing value attribute in adaptionset_supplementalproperty_node\n"); + } else { + rep->last_seq_no =(int64_t) strtoll(val, NULL, 10) - 1; + xmlFree(val); + } + } + } fragment_timeline_node = find_child_node_by_name(representation_segmenttemplate_node, "SegmentTimeline"); if (!fragment_timeline_node) fragment_timeline_node = find_child_node_by_name(fragment_template_node, "SegmentTimeline"); + if (!fragment_timeline_node) + fragment_timeline_node = find_child_node_by_name(adaptionset_segmentlist_node, "SegmentTimeline"); + if (!fragment_timeline_node) + fragment_timeline_node = find_child_node_by_name(period_segmentlist_node, "SegmentTimeline"); if (fragment_timeline_node) { fragment_timeline_node = xmlFirstElementChild(fragment_timeline_node); while (fragment_timeline_node) { @@ -744,7 +958,7 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, ret = AVERROR(ENOMEM); goto end; } - seg->url = get_content_url(baseurl_nodes, 4, rep_id_val, rep_bandwidth_val, NULL); + seg->url = get_content_url(baseurl_nodes, 4, c->max_url_size, rep_id_val, rep_bandwidth_val, NULL); if (!seg->url) { av_free(seg); ret = AVERROR(ENOMEM); @@ -756,8 +970,11 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, // TODO: https://www.brendanlong.com/the-structure-of-an-mpeg-dash-mpd.html // http://www-itec.uni-klu.ac.at/dash/ddash/mpdGenerator.php?fragmentlength=15&type=full xmlNodePtr fragmenturl_node = NULL; - duration_val = xmlGetProp(representation_segmentlist_node, "duration"); - timescale_val = xmlGetProp(representation_segmentlist_node, "timescale"); + segmentlists_tab[0] = representation_segmentlist_node; + segmentlists_tab[1] = adaptionset_segmentlist_node; + + duration_val = get_val_from_nodes_tab(segmentlists_tab, 2, "duration"); + timescale_val = get_val_from_nodes_tab(segmentlists_tab, 2, "timescale"); if (duration_val) { rep->fragment_duration = (int64_t) strtoll(duration_val, NULL, 10); xmlFree(duration_val); @@ -782,6 +999,10 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, if (!fragment_timeline_node) fragment_timeline_node = find_child_node_by_name(fragment_template_node, "SegmentTimeline"); + if (!fragment_timeline_node) + fragment_timeline_node = find_child_node_by_name(adaptionset_segmentlist_node, "SegmentTimeline"); + if (!fragment_timeline_node) + fragment_timeline_node = find_child_node_by_name(period_segmentlist_node, "SegmentTimeline"); if (fragment_timeline_node) { fragment_timeline_node = xmlFirstElementChild(fragment_timeline_node); while (fragment_timeline_node) { @@ -801,12 +1022,21 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, if (rep) { if (rep->fragment_duration > 0 && !rep->fragment_timescale) rep->fragment_timescale = 1; + rep->bandwidth = rep_bandwidth_val ? atoi(rep_bandwidth_val) : 0; + strncpy(rep->id, rep_id_val ? rep_id_val : "", sizeof(rep->id)); + rep->framerate = av_make_q(0, 0); + if (type == AVMEDIA_TYPE_VIDEO && rep_framerate_val) { + ret = av_parse_video_rate(&rep->framerate, rep_framerate_val); + if (ret < 0) + av_log(s, AV_LOG_VERBOSE, "Ignoring invalid frame rate '%s'\n", rep_framerate_val); + } + if (type == AVMEDIA_TYPE_VIDEO) { rep->rep_idx = video_rep_idx; - c->cur_video = rep; + dynarray_add(&c->videos, &c->n_videos, rep); } else { rep->rep_idx = audio_rep_idx; - c->cur_audio = rep; + dynarray_add(&c->audios, &c->n_audios, rep); } } } @@ -819,6 +1049,8 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, xmlFree(rep_id_val); if (rep_bandwidth_val) xmlFree(rep_bandwidth_val); + if (rep_framerate_val) + xmlFree(rep_framerate_val); return ret; } @@ -826,12 +1058,16 @@ static int parse_manifest_representation(AVFormatContext *s, const char *url, static int parse_manifest_adaptationset(AVFormatContext *s, const char *url, xmlNodePtr adaptionset_node, xmlNodePtr mpd_baseurl_node, - xmlNodePtr period_baseurl_node) + xmlNodePtr period_baseurl_node, + xmlNodePtr period_segmenttemplate_node, + xmlNodePtr period_segmentlist_node) { int ret = 0; xmlNodePtr fragment_template_node = NULL; xmlNodePtr content_component_node = NULL; xmlNodePtr adaptionset_baseurl_node = NULL; + xmlNodePtr adaptionset_segmentlist_node = NULL; + xmlNodePtr adaptionset_supplementalproperty_node = NULL; xmlNodePtr node = NULL; node = xmlFirstElementChild(adaptionset_node); @@ -842,14 +1078,22 @@ static int parse_manifest_adaptationset(AVFormatContext *s, const char *url, content_component_node = node; } else if (!av_strcasecmp(node->name, (const char *)"BaseURL")) { adaptionset_baseurl_node = node; + } else if (!av_strcasecmp(node->name, (const char *)"SegmentList")) { + adaptionset_segmentlist_node = node; + } else if (!av_strcasecmp(node->name, (const char *)"SupplementalProperty")) { + adaptionset_supplementalproperty_node = node; } else if (!av_strcasecmp(node->name, (const char *)"Representation")) { ret = parse_manifest_representation(s, url, node, adaptionset_node, mpd_baseurl_node, period_baseurl_node, + period_segmenttemplate_node, + period_segmentlist_node, fragment_template_node, content_component_node, - adaptionset_baseurl_node); + adaptionset_baseurl_node, + adaptionset_segmentlist_node, + adaptionset_supplementalproperty_node); if (ret < 0) { return ret; } @@ -874,18 +1118,18 @@ static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in) xmlNodePtr period_node = NULL; xmlNodePtr mpd_baseurl_node = NULL; xmlNodePtr period_baseurl_node = NULL; + xmlNodePtr period_segmenttemplate_node = NULL; + xmlNodePtr period_segmentlist_node = NULL; xmlNodePtr adaptionset_node = NULL; xmlAttrPtr attr = NULL; char *val = NULL; - uint32_t perdiod_duration_sec = 0; - uint32_t perdiod_start_sec = 0; - int32_t audio_rep_idx = 0; - int32_t video_rep_idx = 0; + uint32_t period_duration_sec = 0; + uint32_t period_start_sec = 0; if (!in) { close_in = 1; - set_httpheader_options(c, opts); + set_httpheader_options(c, &opts); ret = avio_open2(&in, url, AVIO_FLAG_READ, c->interrupt_callback, &opts); av_dict_free(&opts); if (ret < 0) @@ -967,28 +1211,31 @@ static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in) } mpd_baseurl_node = find_child_node_by_name(node, "BaseURL"); + if (!mpd_baseurl_node) { + mpd_baseurl_node = xmlNewNode(NULL, "BaseURL"); + } // at now we can handle only one period, with the longest duration node = xmlFirstElementChild(node); while (node) { if (!av_strcasecmp(node->name, (const char *)"Period")) { - perdiod_duration_sec = 0; - perdiod_start_sec = 0; + period_duration_sec = 0; + period_start_sec = 0; attr = node->properties; while (attr) { val = xmlGetProp(node, attr->name); if (!av_strcasecmp(attr->name, (const char *)"duration")) { - perdiod_duration_sec = get_duration_insec(s, (const char *)val); + period_duration_sec = get_duration_insec(s, (const char *)val); } else if (!av_strcasecmp(attr->name, (const char *)"start")) { - perdiod_start_sec = get_duration_insec(s, (const char *)val); + period_start_sec = get_duration_insec(s, (const char *)val); } attr = attr->next; xmlFree(val); } - if ((perdiod_duration_sec) >= (c->period_duration)) { + if ((period_duration_sec) >= (c->period_duration)) { period_node = node; - c->period_duration = perdiod_duration_sec; - c->period_start = perdiod_start_sec; + c->period_duration = period_duration_sec; + c->period_start = period_start_sec; if (c->period_start > 0) c->media_presentation_duration = c->period_duration; } @@ -1005,19 +1252,15 @@ static int parse_manifest(AVFormatContext *s, const char *url, AVIOContext *in) while (adaptionset_node) { if (!av_strcasecmp(adaptionset_node->name, (const char *)"BaseURL")) { period_baseurl_node = adaptionset_node; + } else if (!av_strcasecmp(adaptionset_node->name, (const char *)"SegmentTemplate")) { + period_segmenttemplate_node = adaptionset_node; + } else if (!av_strcasecmp(adaptionset_node->name, (const char *)"SegmentList")) { + period_segmentlist_node = adaptionset_node; } else if (!av_strcasecmp(adaptionset_node->name, (const char *)"AdaptationSet")) { - parse_manifest_adaptationset(s, url, adaptionset_node, mpd_baseurl_node, period_baseurl_node); + parse_manifest_adaptationset(s, url, adaptionset_node, mpd_baseurl_node, period_baseurl_node, period_segmenttemplate_node, period_segmentlist_node); } adaptionset_node = xmlNextElementSibling(adaptionset_node); } - if (c->cur_video) { - c->cur_video->rep_count = video_rep_idx; - av_log(s, AV_LOG_VERBOSE, "rep_idx[%d]\n", (int)c->cur_video->rep_idx); - av_log(s, AV_LOG_VERBOSE, "rep_count[%d]\n", (int)video_rep_idx); - } - if (c->cur_audio) { - c->cur_audio->rep_count = audio_rep_idx; - } cleanup: /*free the document */ xmlFreeDoc(doc); @@ -1042,15 +1285,12 @@ static int64_t calc_cur_seg_no(AVFormatContext *s, struct representation *pls) if (pls->n_fragments) { num = pls->first_seq_no; } else if (pls->n_timelines) { - start_time_offset = get_segment_start_time_based_on_timeline(pls, 0xFFFFFFFF) - pls->timelines[pls->first_seq_no]->starttime; // total duration of playlist - if (start_time_offset < 60 * pls->fragment_timescale) - start_time_offset = 0; - else - start_time_offset = start_time_offset - 60 * pls->fragment_timescale; - - num = calc_next_seg_no_from_timelines(pls, pls->timelines[pls->first_seq_no]->starttime + start_time_offset); + start_time_offset = get_segment_start_time_based_on_timeline(pls, 0xFFFFFFFF) - 60 * pls->fragment_timescale; // 60 seconds before end + num = calc_next_seg_no_from_timelines(pls, start_time_offset); if (num == -1) num = pls->first_seq_no; + else + num += pls->first_seq_no; } else if (pls->fragment_duration){ if (pls->presentation_timeoffset) { num = pls->presentation_timeoffset * pls->fragment_timescale / pls->fragment_duration; @@ -1079,9 +1319,8 @@ static int64_t calc_min_seg_no(AVFormatContext *s, struct representation *pls) return num; } -static int64_t calc_max_seg_no(struct representation *pls) +static int64_t calc_max_seg_no(struct representation *pls, DASHContext *c) { - DASHContext *c = pls->parent->priv_data; int64_t num = 0; if (pls->n_fragments) { @@ -1101,21 +1340,21 @@ static int64_t calc_max_seg_no(struct representation *pls) return num; } -static void move_timelines(struct representation *rep_src, struct representation *rep_dest) +static void move_timelines(struct representation *rep_src, struct representation *rep_dest, DASHContext *c) { if (rep_dest && rep_src ) { free_timelines_list(rep_dest); rep_dest->timelines = rep_src->timelines; rep_dest->n_timelines = rep_src->n_timelines; rep_dest->first_seq_no = rep_src->first_seq_no; - rep_dest->last_seq_no = calc_max_seg_no(rep_dest); + rep_dest->last_seq_no = calc_max_seg_no(rep_dest, c); rep_src->timelines = NULL; rep_src->n_timelines = 0; rep_dest->cur_seq_no = rep_src->cur_seq_no; } } -static void move_segments(struct representation *rep_src, struct representation *rep_dest) +static void move_segments(struct representation *rep_src, struct representation *rep_dest, DASHContext *c) { if (rep_dest && rep_src ) { free_fragment_list(rep_dest); @@ -1126,7 +1365,7 @@ static void move_segments(struct representation *rep_src, struct representation rep_dest->fragments = rep_src->fragments; rep_dest->n_fragments = rep_src->n_fragments; rep_dest->parent = rep_src->parent; - rep_dest->last_seq_no = calc_max_seg_no(rep_dest); + rep_dest->last_seq_no = calc_max_seg_no(rep_dest, c); rep_src->fragments = NULL; rep_src->n_fragments = 0; } @@ -1136,48 +1375,69 @@ static void move_segments(struct representation *rep_src, struct representation static int refresh_manifest(AVFormatContext *s) { - int ret = 0; + int ret = 0, i; DASHContext *c = s->priv_data; // save current context - struct representation *cur_video = c->cur_video; - struct representation *cur_audio = c->cur_audio; + int n_videos = c->n_videos; + struct representation **videos = c->videos; + int n_audios = c->n_audios; + struct representation **audios = c->audios; char *base_url = c->base_url; c->base_url = NULL; - c->cur_video = NULL; - c->cur_audio = NULL; + c->n_videos = 0; + c->videos = NULL; + c->n_audios = 0; + c->audios = NULL; ret = parse_manifest(s, s->filename, NULL); if (ret) goto finish; - if (cur_video && cur_video->timelines || cur_audio && cur_audio->timelines) { - // calc current time - int64_t currentVideoTime = 0; - int64_t currentAudioTime = 0; - if (cur_video && cur_video->timelines) - currentVideoTime = get_segment_start_time_based_on_timeline(cur_video, cur_video->cur_seq_no) / cur_video->fragment_timescale; - if (cur_audio && cur_audio->timelines) - currentAudioTime = get_segment_start_time_based_on_timeline(cur_audio, cur_audio->cur_seq_no) / cur_audio->fragment_timescale; - // update segments - if (cur_video && cur_video->timelines) { - c->cur_video->cur_seq_no = calc_next_seg_no_from_timelines(c->cur_video, currentVideoTime * cur_video->fragment_timescale - 1); - if (c->cur_video->cur_seq_no >= 0) { - move_timelines(c->cur_video, cur_video); + if (c->n_videos != n_videos) { + av_log(c, AV_LOG_ERROR, + "new manifest has mismatched no. of video representations, %d -> %d\n", + n_videos, c->n_videos); + return AVERROR_INVALIDDATA; + } + if (c->n_audios != n_audios) { + av_log(c, AV_LOG_ERROR, + "new manifest has mismatched no. of audio representations, %d -> %d\n", + n_audios, c->n_audios); + return AVERROR_INVALIDDATA; + } + + for (i = 0; i < n_videos; i++) { + struct representation *cur_video = videos[i]; + struct representation *ccur_video = c->videos[i]; + if (cur_video->timelines) { + // calc current time + int64_t currentTime = get_segment_start_time_based_on_timeline(cur_video, cur_video->cur_seq_no) / cur_video->fragment_timescale; + // update segments + ccur_video->cur_seq_no = calc_next_seg_no_from_timelines(ccur_video, currentTime * cur_video->fragment_timescale - 1); + if (ccur_video->cur_seq_no >= 0) { + move_timelines(ccur_video, cur_video, c); } } - if (cur_audio && cur_audio->timelines) { - c->cur_audio->cur_seq_no = calc_next_seg_no_from_timelines(c->cur_audio, currentAudioTime * cur_audio->fragment_timescale - 1); - if (c->cur_audio->cur_seq_no >= 0) { - move_timelines(c->cur_audio, cur_audio); - } + if (cur_video->fragments) { + move_segments(ccur_video, cur_video, c); } } - if (cur_video && cur_video->fragments) { - move_segments(c->cur_video, cur_video); - } - if (cur_audio && cur_audio->fragments) { - move_segments(c->cur_audio, cur_audio); + for (i = 0; i < n_audios; i++) { + struct representation *cur_audio = audios[i]; + struct representation *ccur_audio = c->audios[i]; + if (cur_audio->timelines) { + // calc current time + int64_t currentTime = get_segment_start_time_based_on_timeline(cur_audio, cur_audio->cur_seq_no) / cur_audio->fragment_timescale; + // update segments + ccur_audio->cur_seq_no = calc_next_seg_no_from_timelines(ccur_audio, currentTime * cur_audio->fragment_timescale - 1); + if (ccur_audio->cur_seq_no >= 0) { + move_timelines(ccur_audio, cur_audio, c); + } + } + if (cur_audio->fragments) { + move_segments(ccur_audio, cur_audio, c); + } } finish: @@ -1186,12 +1446,14 @@ static int refresh_manifest(AVFormatContext *s) av_free(base_url); else c->base_url = base_url; - if (c->cur_audio) - free_representation(c->cur_audio); - if (c->cur_video) - free_representation(c->cur_video); - c->cur_audio = cur_audio; - c->cur_video = cur_video; + if (c->audios) + free_audio_list(c); + if (c->videos) + free_video_list(c); + c->n_audios = n_audios; + c->audios = audios; + c->n_videos = n_videos; + c->videos = videos; return ret; } @@ -1226,7 +1488,7 @@ static struct fragment *get_current_fragment(struct representation *pls) } if (c->is_live) { min_seq_no = calc_min_seg_no(pls->parent, pls); - max_seq_no = calc_max_seg_no(pls); + max_seq_no = calc_max_seg_no(pls, c); if (pls->timelines || pls->fragments) { refresh_manifest(pls->parent); @@ -1248,19 +1510,22 @@ static struct fragment *get_current_fragment(struct representation *pls) } } if (seg) { - char tmpfilename[MAX_URL_SIZE]; - - ff_dash_fill_tmpl_params(tmpfilename, sizeof(tmpfilename), pls->url_template, 0, pls->cur_seq_no, 0, get_segment_start_time_based_on_timeline(pls, pls->cur_seq_no)); + char *tmpfilename= av_mallocz(c->max_url_size); + if (!tmpfilename) { + return NULL; + } + ff_dash_fill_tmpl_params(tmpfilename, c->max_url_size, pls->url_template, 0, pls->cur_seq_no, 0, get_segment_start_time_based_on_timeline(pls, pls->cur_seq_no)); seg->url = av_strireplace(pls->url_template, pls->url_template, tmpfilename); if (!seg->url) { av_log(pls->parent, AV_LOG_WARNING, "Unable to resolve template url '%s', try to use origin template\n", pls->url_template); seg->url = av_strdup(pls->url_template); if (!seg->url) { av_log(pls->parent, AV_LOG_ERROR, "Cannot resolve template url '%s'\n", pls->url_template); + av_free(tmpfilename); return NULL; } } - + av_free(tmpfilename); seg->size = -1; } @@ -1299,10 +1564,14 @@ static int read_from_url(struct representation *pls, struct fragment *seg, static int open_input(DASHContext *c, struct representation *pls, struct fragment *seg) { AVDictionary *opts = NULL; - char url[MAX_URL_SIZE]; - int ret; + char *url = NULL; + int ret = 0; - set_httpheader_options(c, opts); + url = av_mallocz(c->max_url_size); + if (!url) { + goto cleanup; + } + set_httpheader_options(c, &opts); if (seg->size >= 0) { /* try to restrict the HTTP request to the part we want * (if this is in fact a HTTP request) */ @@ -1310,7 +1579,7 @@ static int open_input(DASHContext *c, struct representation *pls, struct fragmen av_dict_set_int(&opts, "end_offset", seg->url_offset + seg->size, 0); } - ff_make_absolute_url(url, MAX_URL_SIZE, c->base_url, seg->url); + ff_make_absolute_url(url, c->max_url_size, c->base_url, seg->url); av_log(pls->parent, AV_LOG_VERBOSE, "DASH request for url '%s', offset %"PRId64", playlist %d\n", url, seg->url_offset, pls->rep_idx); ret = open_url(pls->parent, &pls->input, url, c->avio_opts, opts, NULL); @@ -1318,19 +1587,8 @@ static int open_input(DASHContext *c, struct representation *pls, struct fragmen goto cleanup; } - /* Seek to the requested position. If this was a HTTP request, the offset - * should already be where want it to, but this allows e.g. local testing - * without a HTTP server. */ - if (!ret && seg->url_offset) { - int64_t seekret = avio_seek(pls->input, seg->url_offset, SEEK_SET); - if (seekret < 0) { - av_log(pls->parent, AV_LOG_ERROR, "Unable to seek to offset %"PRId64" of DASH fragment '%s'\n", seg->url_offset, seg->url); - ret = (int) seekret; - ff_format_io_close(pls->parent, &pls->input); - } - } - cleanup: + av_free(url); av_dict_free(&opts); pls->cur_seg_offset = 0; pls->cur_seg_size = seg->size; @@ -1447,9 +1705,11 @@ static int read_data(void *opaque, uint8_t *buf, int buf_size) if (ret > 0) goto end; - if (!v->is_restart_needed) - v->cur_seq_no++; - v->is_restart_needed = 1; + if (c->is_live || v->cur_seq_no < v->last_seq_no) { + if (!v->is_restart_needed) + v->cur_seq_no++; + v->is_restart_needed = 1; + } end: return ret; @@ -1466,8 +1726,12 @@ static int save_avio_options(AVFormatContext *s) if (av_opt_get(s->pb, *opt, AV_OPT_SEARCH_CHILDREN, &buf) >= 0) { if (buf[0] != '\0') { ret = av_dict_set(&c->avio_opts, *opt, buf, AV_DICT_DONT_STRDUP_VAL); - if (ret < 0) + if (ret < 0) { + av_freep(&buf); return ret; + } + } else { + av_freep(&buf); } } opt++; @@ -1486,21 +1750,26 @@ static int nested_io_open(AVFormatContext *s, AVIOContext **pb, const char *url, return AVERROR(EPERM); } +static void close_demux_for_component(struct representation *pls) +{ + /* note: the internal buffer could have changed */ + av_freep(&pls->pb.buffer); + memset(&pls->pb, 0x00, sizeof(AVIOContext)); + pls->ctx->pb = NULL; + avformat_close_input(&pls->ctx); + pls->ctx = NULL; +} + static int reopen_demux_for_component(AVFormatContext *s, struct representation *pls) { DASHContext *c = s->priv_data; AVInputFormat *in_fmt = NULL; AVDictionary *in_fmt_opts = NULL; uint8_t *avio_ctx_buffer = NULL; - int ret = 0; + int ret = 0, i; if (pls->ctx) { - /* note: the internal buffer could have changed, and be != avio_ctx_buffer */ - av_freep(&pls->pb.buffer); - memset(&pls->pb, 0x00, sizeof(AVIOContext)); - pls->ctx->pb = NULL; - avformat_close_input(&pls->ctx); - pls->ctx = NULL; + close_demux_for_component(pls); } if (!(pls->ctx = avformat_alloc_context())) { ret = AVERROR(ENOMEM); @@ -1544,6 +1813,13 @@ static int reopen_demux_for_component(AVFormatContext *s, struct representation if (ret < 0) goto fail; if (pls->n_fragments) { +#if FF_API_R_FRAME_RATE + if (pls->framerate.den) { + for (i = 0; i < pls->ctx->nb_streams; i++) + pls->ctx->streams[i]->r_frame_rate = pls->framerate; + } +#endif + ret = avformat_find_stream_info(pls->ctx, NULL); if (ret < 0) goto fail; @@ -1560,7 +1836,10 @@ static int open_demux_for_component(AVFormatContext *s, struct representation *p pls->parent = s; pls->cur_seq_no = calc_cur_seg_no(s, pls); - pls->last_seq_no = calc_max_seg_no(pls); + + if (!pls->last_seq_no) { + pls->last_seq_no = calc_max_seg_no(pls, s->priv_data); + } ret = reopen_demux_for_component(s, pls); if (ret < 0) { @@ -1589,6 +1868,7 @@ static int dash_read_header(AVFormatContext *s) DASHContext *c = s->priv_data; int ret = 0; int stream_index = 0; + int i; c->interrupt_callback = &s->interrupt_callback; // if the URL context is good, read important options we must broker later @@ -1610,27 +1890,23 @@ static int dash_read_header(AVFormatContext *s) s->duration = (int64_t) c->media_presentation_duration * AV_TIME_BASE; } - /* Open the demuxer for curent video and current audio components if available */ - if (!ret && c->cur_video) { - ret = open_demux_for_component(s, c->cur_video); - if (!ret) { - c->cur_video->stream_index = stream_index; - ++stream_index; - } else { - free_representation(c->cur_video); - c->cur_video = NULL; - } + /* Open the demuxer for video and audio components if available */ + for (i = 0; i < c->n_videos; i++) { + struct representation *cur_video = c->videos[i]; + ret = open_demux_for_component(s, cur_video); + if (ret) + goto fail; + cur_video->stream_index = stream_index; + ++stream_index; } - if (!ret && c->cur_audio) { - ret = open_demux_for_component(s, c->cur_audio); - if (!ret) { - c->cur_audio->stream_index = stream_index; - ++stream_index; - } else { - free_representation(c->cur_audio); - c->cur_audio = NULL; - } + for (i = 0; i < c->n_audios; i++) { + struct representation *cur_audio = c->audios[i]; + ret = open_demux_for_component(s, cur_audio); + if (ret) + goto fail; + cur_audio->stream_index = stream_index; + ++stream_index; } if (!stream_index) { @@ -1646,11 +1922,25 @@ static int dash_read_header(AVFormatContext *s) goto fail; } - if (c->cur_video) { - av_program_add_stream_index(s, 0, c->cur_video->stream_index); - } - if (c->cur_audio) { - av_program_add_stream_index(s, 0, c->cur_audio->stream_index); + for (i = 0; i < c->n_videos; i++) { + struct representation *pls = c->videos[i]; + + av_program_add_stream_index(s, 0, pls->stream_index); + pls->assoc_stream = s->streams[pls->stream_index]; + if (pls->bandwidth > 0) + av_dict_set_int(&pls->assoc_stream->metadata, "variant_bitrate", pls->bandwidth, 0); + if (pls->id[0]) + av_dict_set(&pls->assoc_stream->metadata, "id", pls->id, 0); + } + for (i = 0; i < c->n_audios; i++) { + struct representation *pls = c->audios[i]; + + av_program_add_stream_index(s, 0, pls->stream_index); + pls->assoc_stream = s->streams[pls->stream_index]; + if (pls->bandwidth > 0) + av_dict_set_int(&pls->assoc_stream->metadata, "variant_bitrate", pls->bandwidth, 0); + if (pls->id[0]) + av_dict_set(&pls->assoc_stream->metadata, "id", pls->id, 0); } } @@ -1659,43 +1949,79 @@ static int dash_read_header(AVFormatContext *s) return ret; } +static void recheck_discard_flags(AVFormatContext *s, struct representation **p, int n) +{ + int i, j; + + for (i = 0; i < n; i++) { + struct representation *pls = p[i]; + + int needed = !pls->assoc_stream || pls->assoc_stream->discard < AVDISCARD_ALL; + if (needed && !pls->ctx) { + pls->cur_seg_offset = 0; + pls->init_sec_buf_read_offset = 0; + /* Catch up */ + for (j = 0; j < n; j++) { + pls->cur_seq_no = FFMAX(pls->cur_seq_no, p[j]->cur_seq_no); + } + reopen_demux_for_component(s, pls); + av_log(s, AV_LOG_INFO, "Now receiving stream_index %d\n", pls->stream_index); + } else if (!needed && pls->ctx) { + close_demux_for_component(pls); + if (pls->input) + ff_format_io_close(pls->parent, &pls->input); + av_log(s, AV_LOG_INFO, "No longer receiving stream_index %d\n", pls->stream_index); + } + } +} + static int dash_read_packet(AVFormatContext *s, AVPacket *pkt) { DASHContext *c = s->priv_data; - int ret = 0; + int ret = 0, i; + int64_t mints = 0; struct representation *cur = NULL; - if (!c->cur_audio && !c->cur_video ) { - return AVERROR_INVALIDDATA; + recheck_discard_flags(s, c->videos, c->n_videos); + recheck_discard_flags(s, c->audios, c->n_audios); + + for (i = 0; i < c->n_videos; i++) { + struct representation *pls = c->videos[i]; + if (!pls->ctx) + continue; + if (!cur || pls->cur_timestamp < mints) { + cur = pls; + mints = pls->cur_timestamp; + } } - if (c->cur_audio && !c->cur_video) { - cur = c->cur_audio; - } else if (!c->cur_audio && c->cur_video) { - cur = c->cur_video; - } else if (c->cur_video->cur_timestamp < c->cur_audio->cur_timestamp) { - cur = c->cur_video; - } else { - cur = c->cur_audio; + for (i = 0; i < c->n_audios; i++) { + struct representation *pls = c->audios[i]; + if (!pls->ctx) + continue; + if (!cur || pls->cur_timestamp < mints) { + cur = pls; + mints = pls->cur_timestamp; + } } - if (cur->ctx) { - while (!ff_check_interrupt(c->interrupt_callback) && !ret) { - ret = av_read_frame(cur->ctx, pkt); - if (ret >= 0) { - /* If we got a packet, return it */ - cur->cur_timestamp = av_rescale(pkt->pts, (int64_t)cur->ctx->streams[0]->time_base.num * 90000, cur->ctx->streams[0]->time_base.den); - pkt->stream_index = cur->stream_index; - return 0; - } - if (cur->is_restart_needed) { - cur->cur_seg_offset = 0; - cur->init_sec_buf_read_offset = 0; - if (cur->input) - ff_format_io_close(cur->parent, &cur->input); - ret = reopen_demux_for_component(s, cur); - cur->is_restart_needed = 0; - } - + if (!cur) { + return AVERROR_INVALIDDATA; + } + while (!ff_check_interrupt(c->interrupt_callback) && !ret) { + ret = av_read_frame(cur->ctx, pkt); + if (ret >= 0) { + /* If we got a packet, return it */ + cur->cur_timestamp = av_rescale(pkt->pts, (int64_t)cur->ctx->streams[0]->time_base.num * 90000, cur->ctx->streams[0]->time_base.den); + pkt->stream_index = cur->stream_index; + return 0; + } + if (cur->is_restart_needed) { + cur->cur_seg_offset = 0; + cur->init_sec_buf_read_offset = 0; + if (cur->input) + ff_format_io_close(cur->parent, &cur->input); + ret = reopen_demux_for_component(s, cur); + cur->is_restart_needed = 0; } } return AVERROR_EOF; @@ -1704,12 +2030,8 @@ static int dash_read_packet(AVFormatContext *s, AVPacket *pkt) static int dash_close(AVFormatContext *s) { DASHContext *c = s->priv_data; - if (c->cur_audio) { - free_representation(c->cur_audio); - } - if (c->cur_video) { - free_representation(c->cur_video); - } + free_audio_list(c); + free_video_list(c); av_freep(&c->cookies); av_freep(&c->user_agent); @@ -1718,19 +2040,22 @@ static int dash_close(AVFormatContext *s) return 0; } -static int dash_seek(AVFormatContext *s, struct representation *pls, int64_t seek_pos_msec, int flags) +static int dash_seek(AVFormatContext *s, struct representation *pls, int64_t seek_pos_msec, int flags, int dry_run) { int ret = 0; int i = 0; int j = 0; int64_t duration = 0; - av_log(pls->parent, AV_LOG_VERBOSE, "DASH seek pos[%"PRId64"ms], playlist %d\n", seek_pos_msec, pls->rep_idx); + av_log(pls->parent, AV_LOG_VERBOSE, "DASH seek pos[%"PRId64"ms], playlist %d%s\n", + seek_pos_msec, pls->rep_idx, dry_run ? " (dry)" : ""); // single fragment mode if (pls->n_fragments == 1) { pls->cur_timestamp = 0; pls->cur_seg_offset = 0; + if (dry_run) + return 0; ff_read_frame_flush(pls->ctx); return av_seek_frame(pls->ctx, -1, seek_pos_msec * 1000, flags); } @@ -1769,20 +2094,20 @@ static int dash_seek(AVFormatContext *s, struct representation *pls, int64_t see } else if (pls->fragment_duration > 0) { pls->cur_seq_no = pls->first_seq_no + ((seek_pos_msec * pls->fragment_timescale) / pls->fragment_duration) / 1000; } else { - av_log(pls->parent, AV_LOG_ERROR, "dash_seek missing fragment_duration\n"); + av_log(pls->parent, AV_LOG_ERROR, "dash_seek missing timeline or fragment_duration\n"); pls->cur_seq_no = pls->first_seq_no; } pls->cur_timestamp = 0; pls->cur_seg_offset = 0; pls->init_sec_buf_read_offset = 0; - ret = reopen_demux_for_component(s, pls); + ret = dry_run ? 0 : reopen_demux_for_component(s, pls); return ret; } static int dash_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags) { - int ret = 0; + int ret = 0, i; DASHContext *c = s->priv_data; int64_t seek_pos_msec = av_rescale_rnd(timestamp, 1000, s->streams[stream_index]->time_base.den, @@ -1790,12 +2115,17 @@ static int dash_read_seek(AVFormatContext *s, int stream_index, int64_t timestam AV_ROUND_DOWN : AV_ROUND_UP); if ((flags & AVSEEK_FLAG_BYTE) || c->is_live) return AVERROR(ENOSYS); - if (c->cur_audio) { - ret = dash_seek(s, c->cur_audio, seek_pos_msec, flags); + + /* Seek in discarded streams with dry_run=1 to avoid reopening them */ + for (i = 0; i < c->n_videos; i++) { + if (!ret) + ret = dash_seek(s, c->videos[i], seek_pos_msec, flags, !c->videos[i]->ctx); } - if (!ret && c->cur_video) { - ret = dash_seek(s, c->cur_video, seek_pos_msec, flags); + for (i = 0; i < c->n_audios; i++) { + if (!ret) + ret = dash_seek(s, c->audios[i], seek_pos_msec, flags, !c->audios[i]->ctx); } + return ret; } diff --git a/libavformat/dashenc.c b/libavformat/dashenc.c index 240ff41380569..bdf8c8d5601e8 100644 --- a/libavformat/dashenc.c +++ b/libavformat/dashenc.c @@ -1,6 +1,7 @@ /* * MPEG-DASH ISO BMFF segmenter * Copyright (c) 2014 Martin Storsjo + * Copyright (c) 2018 Akamai Technologies, Inc. * * This file is part of FFmpeg. * @@ -36,6 +37,10 @@ #include "avc.h" #include "avformat.h" #include "avio_internal.h" +#include "hlsplaylist.h" +#if CONFIG_HTTP_PROTOCOL +#include "http.h" +#endif #include "internal.h" #include "isom.h" #include "os_support.h" @@ -55,6 +60,8 @@ typedef struct AdaptationSet { char id[10]; enum AVMediaType media_type; AVDictionary *metadata; + AVRational min_frame_rate, max_frame_rate; + int ambiguous_frame_rate; } AdaptationSet; typedef struct OutputStream { @@ -74,6 +81,10 @@ typedef struct OutputStream { char bandwidth_str[64]; char codec_str[100]; + int written_len; + char filename[1024]; + char full_path[1024]; + char temp_path[1024]; } OutputStream; typedef struct DASHContext { @@ -97,9 +108,16 @@ typedef struct DASHContext { const char *single_file_name; const char *init_seg_name; const char *media_seg_name; - AVRational min_frame_rate, max_frame_rate; - int ambiguous_frame_rate; const char *utc_timing_url; + const char *method; + const char *user_agent; + int hls_playlist; + int http_persistent; + int master_playlist_created; + AVIOContext *mpd_out; + AVIOContext *m3u8_out; + int streaming; + int64_t timeout; } DASHContext; static struct codec_string { @@ -113,6 +131,39 @@ static struct codec_string { { 0, NULL } }; +static int dashenc_io_open(AVFormatContext *s, AVIOContext **pb, char *filename, + AVDictionary **options) { + DASHContext *c = s->priv_data; + int http_base_proto = filename ? ff_is_http_proto(filename) : 0; + int err = AVERROR_MUXER_NOT_FOUND; + if (!*pb || !http_base_proto || !c->http_persistent) { + err = s->io_open(s, pb, filename, AVIO_FLAG_WRITE, options); +#if CONFIG_HTTP_PROTOCOL + } else { + URLContext *http_url_context = ffio_geturlcontext(*pb); + av_assert0(http_url_context); + err = ff_http_do_new_request(http_url_context, filename); +#endif + } + return err; +} + +static void dashenc_io_close(AVFormatContext *s, AVIOContext **pb, char *filename) { + DASHContext *c = s->priv_data; + int http_base_proto = filename ? ff_is_http_proto(filename) : 0; + + if (!http_base_proto || !c->http_persistent) { + ff_format_io_close(s, pb); +#if CONFIG_HTTP_PROTOCOL + } else { + URLContext *http_url_context = ffio_geturlcontext(*pb); + av_assert0(http_url_context); + avio_flush(*pb); + ffurl_shutdown(http_url_context, AVIO_FLAG_WRITE); +#endif + } +} + static void set_codec_str(AVFormatContext *s, AVCodecParameters *par, char *str, int size) { @@ -203,13 +254,34 @@ static int flush_dynbuf(OutputStream *os, int *range_length) // write out to file *range_length = avio_close_dyn_buf(os->ctx->pb, &buffer); os->ctx->pb = NULL; - avio_write(os->out, buffer, *range_length); + avio_write(os->out, buffer + os->written_len, *range_length - os->written_len); + os->written_len = 0; av_free(buffer); // re-open buffer return avio_open_dyn_buf(&os->ctx->pb); } +static void set_http_options(AVDictionary **options, DASHContext *c) +{ + if (c->method) + av_dict_set(options, "method", c->method, 0); + if (c->user_agent) + av_dict_set(options, "user_agent", c->user_agent, 0); + if (c->http_persistent) + av_dict_set_int(options, "multiple_requests", 1, 0); + if (c->timeout >= 0) + av_dict_set_int(options, "timeout", c->timeout, 0); +} + +static void get_hls_playlist_name(char *playlist_name, int string_size, + const char *base_url, int id) { + if (base_url) + snprintf(playlist_name, string_size, "%smedia_%d.m3u8", base_url, id); + else + snprintf(playlist_name, string_size, "media_%d.m3u8", id); +} + static int flush_init_segment(AVFormatContext *s, OutputStream *os) { DASHContext *c = s->priv_data; @@ -253,10 +325,15 @@ static void dash_free(AVFormatContext *s) av_free(os->segments); } av_freep(&c->streams); + + ff_format_io_close(s, &c->mpd_out); + ff_format_io_close(s, &c->m3u8_out); } -static void output_segment_list(OutputStream *os, AVIOContext *out, DASHContext *c) +static void output_segment_list(OutputStream *os, AVIOContext *out, AVFormatContext *s, + int representation_id, int final) { + DASHContext *c = s->priv_data; int i, start_index = 0, start_number = 1; if (c->window_size) { start_index = FFMAX(os->nb_segments - c->window_size, 0); @@ -315,6 +392,61 @@ static void output_segment_list(OutputStream *os, AVIOContext *out, DASHContext } avio_printf(out, "\t\t\t\t\n"); } + if (c->hls_playlist && start_index < os->nb_segments) + { + int timescale = os->ctx->streams[0]->time_base.den; + char temp_filename_hls[1024]; + char filename_hls[1024]; + AVDictionary *http_opts = NULL; + int target_duration = 0; + int ret = 0; + const char *proto = avio_find_protocol_name(c->dirname); + int use_rename = proto && !strcmp(proto, "file"); + + get_hls_playlist_name(filename_hls, sizeof(filename_hls), + c->dirname, representation_id); + + snprintf(temp_filename_hls, sizeof(temp_filename_hls), use_rename ? "%s.tmp" : "%s", filename_hls); + + set_http_options(&http_opts, c); + dashenc_io_open(s, &c->m3u8_out, temp_filename_hls, &http_opts); + av_dict_free(&http_opts); + for (i = start_index; i < os->nb_segments; i++) { + Segment *seg = os->segments[i]; + double duration = (double) seg->duration / timescale; + if (target_duration <= duration) + target_duration = lrint(duration); + } + + ff_hls_write_playlist_header(c->m3u8_out, 6, -1, target_duration, + start_number, PLAYLIST_TYPE_NONE); + + ff_hls_write_init_file(c->m3u8_out, os->initfile, c->single_file, + os->init_range_length, os->init_start_pos); + + for (i = start_index; i < os->nb_segments; i++) { + Segment *seg = os->segments[i]; + ret = ff_hls_write_file_entry(c->m3u8_out, 0, c->single_file, + (double) seg->duration / timescale, 0, + seg->range_length, seg->start_pos, NULL, + c->single_file ? os->initfile : seg->file, + NULL); + if (ret < 0) { + av_log(os->ctx, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n"); + } + } + + if (final) + ff_hls_write_end_list(c->m3u8_out); + + dashenc_io_close(s, &c->m3u8_out, temp_filename_hls); + + if (use_rename) + if (avpriv_io_move(temp_filename_hls, filename_hls) < 0) { + av_log(os->ctx, AV_LOG_WARNING, "renaming file %s to %s failed\n\n", temp_filename_hls, filename_hls); + } + } + } static char *xmlescape(const char *str) { @@ -384,7 +516,8 @@ static void format_date_now(char *buf, int size) } } -static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_index) +static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_index, + int final) { DASHContext *c = s->priv_data; AdaptationSet *as = &c->as[as_index]; @@ -393,8 +526,8 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind avio_printf(out, "\t\tid, as->media_type == AVMEDIA_TYPE_VIDEO ? "video" : "audio"); - if (as->media_type == AVMEDIA_TYPE_VIDEO && c->max_frame_rate.num && !c->ambiguous_frame_rate) - avio_printf(out, " %s=\"%d/%d\"", (av_cmp_q(c->min_frame_rate, c->max_frame_rate) < 0) ? "maxFrameRate" : "frameRate", c->max_frame_rate.num, c->max_frame_rate.den); + if (as->media_type == AVMEDIA_TYPE_VIDEO && as->max_frame_rate.num && !as->ambiguous_frame_rate && av_cmp_q(as->min_frame_rate, as->max_frame_rate) < 0) + avio_printf(out, " maxFrameRate=\"%d/%d\"", as->max_frame_rate.num, as->max_frame_rate.den); lang = av_dict_get(as->metadata, "language", NULL, 0); if (lang) avio_printf(out, " lang=\"%s\"", lang->value); @@ -423,7 +556,7 @@ static int write_adaptation_set(AVFormatContext *s, AVIOContext *out, int as_ind avio_printf(out, "\t\t\t\t\n", s->streams[i]->codecpar->channels); } - output_segment_list(os, out, c); + output_segment_list(os, out, s, i, final); avio_printf(out, "\t\t\t\n"); } avio_printf(out, "\t\t\n"); @@ -571,20 +704,24 @@ static int write_manifest(AVFormatContext *s, int final) AVIOContext *out; char temp_filename[1024]; int ret, i; - const char *proto = avio_find_protocol_name(s->filename); + const char *proto = avio_find_protocol_name(s->url); int use_rename = proto && !strcmp(proto, "file"); static unsigned int warned_non_file = 0; AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0); + AVDictionary *opts = NULL; if (!use_rename && !warned_non_file++) av_log(s, AV_LOG_ERROR, "Cannot use rename on non file protocol, this may lead to races and temporary partial files\n"); - snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", s->filename); - ret = s->io_open(s, &out, temp_filename, AVIO_FLAG_WRITE, NULL); + snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", s->url); + set_http_options(&opts, c); + ret = dashenc_io_open(s, &c->mpd_out, temp_filename, &opts); if (ret < 0) { av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename); return ret; } + out = c->mpd_out; + av_dict_free(&opts); avio_printf(out, "\n"); avio_printf(out, "\n"); - if (c->utc_timing_url) - avio_printf(out, "\t\n", c->utc_timing_url); if (c->window_size && s->nb_streams > 0 && c->streams[0].nb_segments > 0 && !c->use_template) { OutputStream *os = &c->streams[0]; @@ -642,16 +777,76 @@ static int write_manifest(AVFormatContext *s, int final) } for (i = 0; i < c->nb_as; i++) { - if ((ret = write_adaptation_set(s, out, i)) < 0) + if ((ret = write_adaptation_set(s, out, i, final)) < 0) return ret; } avio_printf(out, "\t\n"); + + if (c->utc_timing_url) + avio_printf(out, "\t\n", c->utc_timing_url); + avio_printf(out, "\n"); avio_flush(out); - ff_format_io_close(s, &out); + dashenc_io_close(s, &c->mpd_out, temp_filename); + + if (use_rename) { + if ((ret = avpriv_io_move(temp_filename, s->url)) < 0) + return ret; + } - if (use_rename) - return avpriv_io_move(temp_filename, s->filename); + if (c->hls_playlist && !c->master_playlist_created) { + char filename_hls[1024]; + const char *audio_group = "A1"; + int is_default = 1; + int max_audio_bitrate = 0; + + if (*c->dirname) + snprintf(filename_hls, sizeof(filename_hls), "%s/master.m3u8", c->dirname); + else + snprintf(filename_hls, sizeof(filename_hls), "master.m3u8"); + + snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", filename_hls); + + set_http_options(&opts, c); + ret = avio_open2(&out, temp_filename, AVIO_FLAG_WRITE, NULL, &opts); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename); + return ret; + } + av_dict_free(&opts); + + ff_hls_write_playlist_version(out, 6); + + for (i = 0; i < s->nb_streams; i++) { + char playlist_file[64]; + AVStream *st = s->streams[i]; + if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO) + continue; + get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, i); + ff_hls_write_audio_rendition(out, (char *)audio_group, + playlist_file, i, is_default); + max_audio_bitrate = FFMAX(st->codecpar->bit_rate, max_audio_bitrate); + is_default = 0; + } + + for (i = 0; i < s->nb_streams; i++) { + char playlist_file[64]; + AVStream *st = s->streams[i]; + char *agroup = NULL; + int stream_bitrate = st->codecpar->bit_rate; + if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && max_audio_bitrate) { + agroup = (char *)audio_group; + stream_bitrate += max_audio_bitrate; + } + get_hls_playlist_name(playlist_file, sizeof(playlist_file), NULL, i); + ff_hls_write_stream_info(st, out, stream_bitrate, playlist_file, agroup, NULL, NULL); + } + avio_close(out); + if (use_rename) + if ((ret = avpriv_io_move(temp_filename, filename_hls)) < 0) + return ret; + c->master_playlist_created = 1; + } return 0; } @@ -664,14 +859,6 @@ static int dict_copy_entry(AVDictionary **dst, const AVDictionary *src, const ch return 0; } -static int dict_set_int(AVDictionary **pm, const char *key, int64_t value, int flags) -{ - char valuestr[22]; - snprintf(valuestr, sizeof(valuestr), "%"PRId64, value); - flags &= ~AV_DICT_DONT_STRDUP_VAL; - return av_dict_set(pm, key, valuestr, flags); -} - static int dash_init(AVFormatContext *s) { DASHContext *c = s->priv_data; @@ -683,16 +870,15 @@ static int dash_init(AVFormatContext *s) c->single_file = 1; if (c->single_file) c->use_template = 0; - c->ambiguous_frame_rate = 0; - av_strlcpy(c->dirname, s->filename, sizeof(c->dirname)); + av_strlcpy(c->dirname, s->url, sizeof(c->dirname)); ptr = strrchr(c->dirname, '/'); if (ptr) { av_strlcpy(basename, &ptr[1], sizeof(basename)); ptr[1] = '\0'; } else { c->dirname[0] = '\0'; - av_strlcpy(basename, s->filename, sizeof(basename)); + av_strlcpy(basename, s->url, sizeof(basename)); } ptr = strrchr(basename, '.'); @@ -759,6 +945,7 @@ static int dash_init(AVFormatContext *s) avcodec_parameters_copy(st->codecpar, s->streams[i]->codecpar); st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio; st->time_base = s->streams[i]->time_base; + st->avg_frame_rate = s->streams[i]->avg_frame_rate; ctx->avoid_negative_ts = s->avoid_negative_ts; ctx->flags = s->flags; @@ -774,18 +961,26 @@ static int dash_init(AVFormatContext *s) ff_dash_fill_tmpl_params(os->initfile, sizeof(os->initfile), c->init_seg_name, i, 0, os->bit_rate, 0); } snprintf(filename, sizeof(filename), "%s%s", c->dirname, os->initfile); - ret = s->io_open(s, &os->out, filename, AVIO_FLAG_WRITE, NULL); + set_http_options(&opts, c); + ret = s->io_open(s, &os->out, filename, AVIO_FLAG_WRITE, &opts); if (ret < 0) return ret; + av_dict_free(&opts); os->init_start_pos = 0; if (!strcmp(os->format_name, "mp4")) { - av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); + if (c->streaming) + av_dict_set(&opts, "movflags", "frag_every_frame+dash+delay_moov", 0); + else + av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0); } else { - dict_set_int(&opts, "cluster_time_limit", c->min_seg_duration / 1000, 0); - dict_set_int(&opts, "cluster_size_limit", 5 * 1024 * 1024, 0); // set a large cluster size limit + av_dict_set_int(&opts, "cluster_time_limit", c->min_seg_duration / 1000, 0); + av_dict_set_int(&opts, "cluster_size_limit", 5 * 1024 * 1024, 0); // set a large cluster size limit + av_dict_set_int(&opts, "dash", 1, 0); + av_dict_set_int(&opts, "dash_track_number", i + 1, 0); + av_dict_set_int(&opts, "live", 1, 0); } - if ((ret = avformat_write_header(ctx, &opts)) < 0) + if ((ret = avformat_init_output(ctx, &opts)) < 0) return ret; os->ctx_inited = 1; avio_flush(ctx->pb); @@ -808,12 +1003,12 @@ static int dash_init(AVFormatContext *s) if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { AVRational avg_frame_rate = s->streams[i]->avg_frame_rate; if (avg_frame_rate.num > 0) { - if (av_cmp_q(avg_frame_rate, c->min_frame_rate) < 0) - c->min_frame_rate = avg_frame_rate; - if (av_cmp_q(c->max_frame_rate, avg_frame_rate) < 0) - c->max_frame_rate = avg_frame_rate; + if (av_cmp_q(avg_frame_rate, as->min_frame_rate) < 0) + as->min_frame_rate = avg_frame_rate; + if (av_cmp_q(as->max_frame_rate, avg_frame_rate) < 0) + as->max_frame_rate = avg_frame_rate; } else { - c->ambiguous_frame_rate = 1; + as->ambiguous_frame_rate = 1; } c->has_video = 1; } @@ -838,14 +1033,12 @@ static int dash_write_header(AVFormatContext *s) int i, ret; for (i = 0; i < s->nb_streams; i++) { OutputStream *os = &c->streams[i]; - if ((ret = avformat_write_header(os->ctx, NULL)) < 0) { - dash_free(s); + if ((ret = avformat_write_header(os->ctx, NULL)) < 0) return ret; - } } ret = write_manifest(s, 0); if (!ret) - av_log(s, AV_LOG_VERBOSE, "Manifest written to: %s\n", s->filename); + av_log(s, AV_LOG_VERBOSE, "Manifest written to: %s\n", s->url); return ret; } @@ -939,12 +1132,34 @@ static int update_stream_extradata(AVFormatContext *s, OutputStream *os, return 0; } +static void dashenc_delete_file(AVFormatContext *s, char *filename) { + DASHContext *c = s->priv_data; + int http_base_proto = ff_is_http_proto(filename); + + if (http_base_proto) { + AVIOContext *out = NULL; + AVDictionary *http_opts = NULL; + + set_http_options(&http_opts, c); + av_dict_set(&http_opts, "method", "DELETE", 0); + + if (dashenc_io_open(s, &out, filename, &http_opts) < 0) { + av_log(s, AV_LOG_ERROR, "failed to delete %s\n", filename); + } + + av_dict_free(&http_opts); + dashenc_io_close(s, &out, filename); + } else if (unlink(filename) < 0) { + av_log(s, AV_LOG_ERROR, "failed to delete %s: %s\n", filename, strerror(errno)); + } +} + static int dash_flush(AVFormatContext *s, int final, int stream) { DASHContext *c = s->priv_data; int i, ret = 0; - const char *proto = avio_find_protocol_name(s->filename); + const char *proto = avio_find_protocol_name(s->url); int use_rename = proto && !strcmp(proto, "file"); int cur_flush_segment_index = 0; @@ -953,7 +1168,7 @@ static int dash_flush(AVFormatContext *s, int final, int stream) for (i = 0; i < s->nb_streams; i++) { OutputStream *os = &c->streams[i]; - char filename[1024] = "", full_path[1024], temp_path[1024]; + AVStream *st = s->streams[i]; int range_length, index_length = 0; if (!os->packets_written) @@ -971,21 +1186,11 @@ static int dash_flush(AVFormatContext *s, int final, int stream) continue; } - if (!os->init_range_length) { - flush_init_segment(s, os); - } - if (!c->single_file) { - ff_dash_fill_tmpl_params(filename, sizeof(filename), c->media_seg_name, i, os->segment_index, os->bit_rate, os->start_pts); - snprintf(full_path, sizeof(full_path), "%s%s", c->dirname, filename); - snprintf(temp_path, sizeof(temp_path), use_rename ? "%s.tmp" : "%s", full_path); - ret = s->io_open(s, &os->out, temp_path, AVIO_FLAG_WRITE, NULL); - if (ret < 0) - break; - if (!strcmp(os->format_name, "mp4")) + if (!strcmp(os->format_name, "mp4") && !os->written_len) write_styp(os->ctx->pb); } else { - snprintf(full_path, sizeof(full_path), "%s%s", c->dirname, os->initfile); + snprintf(os->full_path, sizeof(os->full_path), "%s%s", c->dirname, os->initfile); } ret = flush_dynbuf(os, &range_length); @@ -994,12 +1199,12 @@ static int dash_flush(AVFormatContext *s, int final, int stream) os->packets_written = 0; if (c->single_file) { - find_index_range(s, full_path, os->pos, &index_length); + find_index_range(s, os->full_path, os->pos, &index_length); } else { - ff_format_io_close(s, &os->out); + dashenc_io_close(s, &os->out, os->temp_path); if (use_rename) { - ret = avpriv_io_move(temp_path, full_path); + ret = avpriv_io_move(os->temp_path, os->full_path); if (ret < 0) break; } @@ -1007,15 +1212,17 @@ static int dash_flush(AVFormatContext *s, int final, int stream) if (!os->bit_rate) { // calculate average bitrate of first segment - int64_t bitrate = (int64_t) range_length * 8 * AV_TIME_BASE / (os->max_pts - os->start_pts); + int64_t bitrate = (int64_t) range_length * 8 * AV_TIME_BASE / av_rescale_q(os->max_pts - os->start_pts, + st->time_base, + AV_TIME_BASE_Q); if (bitrate >= 0) { os->bit_rate = bitrate; snprintf(os->bandwidth_str, sizeof(os->bandwidth_str), " bandwidth=\"%d\"", os->bit_rate); } } - add_segment(os, filename, os->start_pts, os->max_pts - os->start_pts, os->pos, range_length, index_length); - av_log(s, AV_LOG_VERBOSE, "Representation %d media segment %d written to: %s\n", i, os->segment_index, full_path); + add_segment(os, os->filename, os->start_pts, os->max_pts - os->start_pts, os->pos, range_length, index_length); + av_log(s, AV_LOG_VERBOSE, "Representation %d media segment %d written to: %s\n", i, os->segment_index, os->full_path); os->pos += range_length; } @@ -1031,7 +1238,7 @@ static int dash_flush(AVFormatContext *s, int final, int stream) for (j = 0; j < remove; j++) { char filename[1024]; snprintf(filename, sizeof(filename), "%s%s", c->dirname, os->segments[j]->file); - unlink(filename); + dashenc_delete_file(s, filename); av_free(os->segments[j]); } os->nb_segments -= remove; @@ -1117,7 +1324,46 @@ static int dash_write_packet(AVFormatContext *s, AVPacket *pkt) else os->max_pts = FFMAX(os->max_pts, pkt->pts + pkt->duration); os->packets_written++; - return ff_write_chained(os->ctx, 0, pkt, s, 0); + if ((ret = ff_write_chained(os->ctx, 0, pkt, s, 0)) < 0) + return ret; + + if (!os->init_range_length) + flush_init_segment(s, os); + + //open the output context when the first frame of a segment is ready + if (!c->single_file && os->packets_written == 1) { + AVDictionary *opts = NULL; + const char *proto = avio_find_protocol_name(s->url); + int use_rename = proto && !strcmp(proto, "file"); + os->filename[0] = os->full_path[0] = os->temp_path[0] = '\0'; + ff_dash_fill_tmpl_params(os->filename, sizeof(os->filename), + c->media_seg_name, pkt->stream_index, + os->segment_index, os->bit_rate, os->start_pts); + snprintf(os->full_path, sizeof(os->full_path), "%s%s", c->dirname, + os->filename); + snprintf(os->temp_path, sizeof(os->temp_path), + use_rename ? "%s.tmp" : "%s", os->full_path); + set_http_options(&opts, c); + ret = dashenc_io_open(s, &os->out, os->temp_path, &opts); + if (ret < 0) + return ret; + av_dict_free(&opts); + } + + //write out the data immediately in streaming mode + if (c->streaming && !strcmp(os->format_name, "mp4")) { + int len = 0; + uint8_t *buf = NULL; + if (!os->written_len) + write_styp(os->ctx->pb); + avio_flush(os->ctx->pb); + len = avio_get_dyn_buf (os->ctx->pb, &buf); + avio_write(os->out, buf + os->written_len, len - os->written_len); + os->written_len = len; + avio_flush(os->out); + } + + return ret; } static int dash_write_trailer(AVFormatContext *s) @@ -1144,9 +1390,9 @@ static int dash_write_trailer(AVFormatContext *s) for (i = 0; i < s->nb_streams; i++) { OutputStream *os = &c->streams[i]; snprintf(filename, sizeof(filename), "%s%s", c->dirname, os->initfile); - unlink(filename); + dashenc_delete_file(s, filename); } - unlink(s->filename); + dashenc_delete_file(s, s->url); } return 0; @@ -1181,7 +1427,7 @@ static const AVOption options[] = { { "adaptation_sets", "Adaptation sets. Syntax: id=0,streams=0,1,2 id=1,streams=3,4 and so on", OFFSET(adaptation_sets), AV_OPT_TYPE_STRING, { 0 }, 0, 0, AV_OPT_FLAG_ENCODING_PARAM }, { "window_size", "number of segments kept in the manifest", OFFSET(window_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, E }, { "extra_window_size", "number of segments kept outside of the manifest before removing from disk", OFFSET(extra_window_size), AV_OPT_TYPE_INT, { .i64 = 5 }, 0, INT_MAX, E }, - { "min_seg_duration", "minimum segment duration (in microseconds)", OFFSET(min_seg_duration), AV_OPT_TYPE_INT64, { .i64 = 5000000 }, 0, INT_MAX, E }, + { "min_seg_duration", "minimum segment duration (in microseconds)", OFFSET(min_seg_duration), AV_OPT_TYPE_INT, { .i64 = 5000000 }, 0, INT_MAX, E }, { "remove_at_exit", "remove all segments when finished", OFFSET(remove_at_exit), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, { "use_template", "Use SegmentTemplate instead of SegmentList", OFFSET(use_template), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E }, { "use_timeline", "Use SegmentTimeline in SegmentTemplate", OFFSET(use_timeline), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, E }, @@ -1190,6 +1436,12 @@ static const AVOption options[] = { { "init_seg_name", "DASH-templated name to used for the initialization segment", OFFSET(init_seg_name), AV_OPT_TYPE_STRING, {.str = "init-stream$RepresentationID$.m4s"}, 0, 0, E }, { "media_seg_name", "DASH-templated name to used for the media segments", OFFSET(media_seg_name), AV_OPT_TYPE_STRING, {.str = "chunk-stream$RepresentationID$-$Number%05d$.m4s"}, 0, 0, E }, { "utc_timing_url", "URL of the page that will return the UTC timestamp in ISO format", OFFSET(utc_timing_url), AV_OPT_TYPE_STRING, { 0 }, 0, 0, E }, + { "method", "set the HTTP method", OFFSET(method), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E }, + { "http_user_agent", "override User-Agent field in HTTP header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, + { "http_persistent", "Use persistent HTTP connections", OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, + { "hls_playlist", "Generate HLS playlist files(master.m3u8, media_%d.m3u8)", OFFSET(hls_playlist), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, + { "streaming", "Enable/Disable streaming mode of output. Each frame will be moof fragment", OFFSET(streaming), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, E }, + { "timeout", "set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT_MAX, .flags = E }, { NULL }, }; @@ -1203,6 +1455,7 @@ static const AVClass dash_class = { AVOutputFormat ff_dash_muxer = { .name = "dash", .long_name = NULL_IF_CONFIG_SMALL("DASH Muxer"), + .extensions = "mpd", .priv_data_size = sizeof(DASHContext), .audio_codec = AV_CODEC_ID_AAC, .video_codec = AV_CODEC_ID_H264, diff --git a/libavformat/dump.c b/libavformat/dump.c index 77043e3fdbff4..942e62a581946 100644 --- a/libavformat/dump.c +++ b/libavformat/dump.c @@ -372,7 +372,9 @@ static void dump_spherical(void *ctx, AVCodecParameters *par, AVPacketSideData * size_t l, t, r, b; av_spherical_tile_bounds(spherical, par->width, par->height, &l, &t, &r, &b); - av_log(ctx, AV_LOG_INFO, "[%zu, %zu, %zu, %zu] ", l, t, r, b); + av_log(ctx, AV_LOG_INFO, + "[%"SIZE_SPECIFIER", %"SIZE_SPECIFIER", %"SIZE_SPECIFIER", %"SIZE_SPECIFIER"] ", + l, t, r, b); } else if (spherical->projection == AV_SPHERICAL_CUBEMAP) { av_log(ctx, AV_LOG_INFO, "[pad %"PRIu32"] ", spherical->padding); } @@ -545,6 +547,10 @@ static void dump_stream_format(AVFormatContext *ic, int i, av_log(NULL, AV_LOG_INFO, " (visual impaired)"); if (st->disposition & AV_DISPOSITION_CLEAN_EFFECTS) av_log(NULL, AV_LOG_INFO, " (clean effects)"); + if (st->disposition & AV_DISPOSITION_DESCRIPTIONS) + av_log(NULL, AV_LOG_INFO, " (descriptions)"); + if (st->disposition & AV_DISPOSITION_DEPENDENT) + av_log(NULL, AV_LOG_INFO, " (dependent)"); av_log(NULL, AV_LOG_INFO, "\n"); dump_metadata(NULL, st->metadata, " "); diff --git a/libavformat/ffm.h b/libavformat/ffm.h deleted file mode 100644 index c445f472f7362..0000000000000 --- a/libavformat/ffm.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * FFM (ffserver live feed) common header - * Copyright (c) 2001 Fabrice Bellard - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVFORMAT_FFM_H -#define AVFORMAT_FFM_H - -#include -#include "avformat.h" -#include "avio.h" - -/* The FFM file is made of blocks of fixed size */ -#define FFM_HEADER_SIZE 14 -#define FFM_PACKET_SIZE 4096 -#define PACKET_ID 0x666d - -/* each packet contains frames (which can span several packets */ -#define FRAME_HEADER_SIZE 16 -#define FLAG_KEY_FRAME 0x01 -#define FLAG_DTS 0x02 - -enum { - READ_HEADER, - READ_DATA, -}; - -typedef struct FFMContext { - const AVClass *class; - /* only reading mode */ - int64_t write_index, file_size; - int read_state; - uint8_t header[FRAME_HEADER_SIZE+4]; - - /* read and write */ - int first_packet; /* true if first packet, needed to set the discontinuity tag */ - int packet_size; - int frame_offset; - int64_t dts; - uint8_t *packet_ptr, *packet_end; - uint8_t packet[FFM_PACKET_SIZE]; - int64_t start_time; - int server_attached; -} FFMContext; - -#endif /* AVFORMAT_FFM_H */ diff --git a/libavformat/ffmdec.c b/libavformat/ffmdec.c deleted file mode 100644 index de6ac272523d9..0000000000000 --- a/libavformat/ffmdec.c +++ /dev/null @@ -1,878 +0,0 @@ -/* - * FFM (ffserver live feed) demuxer - * Copyright (c) 2001 Fabrice Bellard - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include - -#include "libavutil/imgutils.h" -#include "libavutil/internal.h" -#include "libavutil/intreadwrite.h" -#include "libavutil/intfloat.h" -#include "libavutil/opt.h" -#include "libavutil/avassert.h" -#include "libavutil/avstring.h" -#include "libavutil/pixdesc.h" -#include "libavcodec/internal.h" -#include "avformat.h" -#include "internal.h" -#include "ffm.h" -#include "avio_internal.h" - -static int ffm_is_avail_data(AVFormatContext *s, int size) -{ - FFMContext *ffm = s->priv_data; - int64_t pos, avail_size; - ptrdiff_t len; - - len = ffm->packet_end - ffm->packet_ptr; - if (size <= len) - return 1; - pos = avio_tell(s->pb); - if (!ffm->write_index) { - if (pos == ffm->file_size) - return AVERROR_EOF; - avail_size = ffm->file_size - pos; - } else { - if (pos == ffm->write_index) { - /* exactly at the end of stream */ - if (ffm->server_attached) - return AVERROR(EAGAIN); - else - return AVERROR_INVALIDDATA; - } else if (pos < ffm->write_index) { - avail_size = ffm->write_index - pos; - } else { - avail_size = (ffm->file_size - pos) + (ffm->write_index - FFM_PACKET_SIZE); - } - } - avail_size = (avail_size / ffm->packet_size) * (ffm->packet_size - FFM_HEADER_SIZE) + len; - if (size <= avail_size) - return 1; - else if (ffm->server_attached) - return AVERROR(EAGAIN); - else - return AVERROR_INVALIDDATA; -} - -static int ffm_resync(AVFormatContext *s, uint32_t state) -{ - av_log(s, AV_LOG_ERROR, "resyncing\n"); - while (state != PACKET_ID) { - if (avio_feof(s->pb)) { - av_log(s, AV_LOG_ERROR, "cannot find FFM syncword\n"); - return -1; - } - state = (state << 8) | avio_r8(s->pb); - } - return 0; -} - -/* first is true if we read the frame header */ -static int ffm_read_data(AVFormatContext *s, - uint8_t *buf, int size, int header) -{ - FFMContext *ffm = s->priv_data; - AVIOContext *pb = s->pb; - int fill_size, size1, frame_offset; - uint32_t id; - ptrdiff_t len; - int64_t last_pos = -1; - - size1 = size; - while (size > 0) { - redo: - len = ffm->packet_end - ffm->packet_ptr; - if (len < 0) - return -1; - if (len > size) - len = size; - if (len == 0) { - if (avio_tell(pb) == ffm->file_size) { - if (ffm->server_attached) { - avio_seek(pb, ffm->packet_size, SEEK_SET); - } else - return AVERROR_EOF; - } - retry_read: - if (pb->buffer_size != ffm->packet_size) { - int64_t tell = avio_tell(pb); - int ret = ffio_set_buf_size(pb, ffm->packet_size); - if (ret < 0) - return ret; - avio_seek(pb, tell, SEEK_SET); - } - id = avio_rb16(pb); /* PACKET_ID */ - if (id != PACKET_ID) { - if (ffm_resync(s, id) < 0) - return -1; - last_pos = avio_tell(pb); - } - fill_size = avio_rb16(pb); - ffm->dts = avio_rb64(pb); - frame_offset = avio_rb16(pb); - avio_read(pb, ffm->packet, ffm->packet_size - FFM_HEADER_SIZE); - if (ffm->packet_size < FFM_HEADER_SIZE + fill_size || frame_offset < 0) { - return -1; - } - ffm->packet_end = ffm->packet + (ffm->packet_size - FFM_HEADER_SIZE - fill_size); - /* if first packet or resynchronization packet, we must - handle it specifically */ - if (ffm->first_packet || (frame_offset & 0x8000)) { - if (!frame_offset) { - /* This packet has no frame headers in it */ - if (avio_tell(pb) >= ffm->packet_size * 3LL) { - int64_t seekback = FFMIN(ffm->packet_size * 2LL, avio_tell(pb) - last_pos); - seekback = FFMAX(seekback, 0); - avio_seek(pb, -seekback, SEEK_CUR); - goto retry_read; - } - /* This is bad, we cannot find a valid frame header */ - return 0; - } - ffm->first_packet = 0; - if ((frame_offset & 0x7fff) < FFM_HEADER_SIZE) { - ffm->packet_end = ffm->packet_ptr; - return -1; - } - ffm->packet_ptr = ffm->packet + (frame_offset & 0x7fff) - FFM_HEADER_SIZE; - if (!header) - break; - } else { - ffm->packet_ptr = ffm->packet; - } - goto redo; - } - memcpy(buf, ffm->packet_ptr, len); - buf += len; - ffm->packet_ptr += len; - size -= len; - header = 0; - } - return size1 - size; -} - -/* ensure that actual seeking happens between FFM_PACKET_SIZE - and file_size - FFM_PACKET_SIZE */ -static int64_t ffm_seek1(AVFormatContext *s, int64_t pos1) -{ - FFMContext *ffm = s->priv_data; - AVIOContext *pb = s->pb; - int64_t pos; - - pos = FFMIN(pos1, ffm->file_size - FFM_PACKET_SIZE); - pos = FFMAX(pos, FFM_PACKET_SIZE); - ff_dlog(s, "seek to %"PRIx64" -> %"PRIx64"\n", pos1, pos); - return avio_seek(pb, pos, SEEK_SET); -} - -static int64_t get_dts(AVFormatContext *s, int64_t pos) -{ - AVIOContext *pb = s->pb; - int64_t dts; - - ffm_seek1(s, pos); - avio_skip(pb, 4); - dts = avio_rb64(pb); - ff_dlog(s, "dts=%0.6f\n", dts / 1000000.0); - return dts; -} - -static void adjust_write_index(AVFormatContext *s) -{ - FFMContext *ffm = s->priv_data; - AVIOContext *pb = s->pb; - int64_t pts; - //int64_t orig_write_index = ffm->write_index; - int64_t pos_min, pos_max; - int64_t pts_start; - int64_t ptr = avio_tell(pb); - - - pos_min = 0; - pos_max = ffm->file_size - 2 * FFM_PACKET_SIZE; - - pts_start = get_dts(s, pos_min); - - pts = get_dts(s, pos_max); - - if (pts - 100000 > pts_start) - goto end; - - ffm->write_index = FFM_PACKET_SIZE; - - pts_start = get_dts(s, pos_min); - - pts = get_dts(s, pos_max); - - if (pts - 100000 <= pts_start) { - while (1) { - int64_t newpos; - int64_t newpts; - - newpos = ((pos_max + pos_min) / (2 * FFM_PACKET_SIZE)) * FFM_PACKET_SIZE; - - if (newpos == pos_min) - break; - - newpts = get_dts(s, newpos); - - if (newpts - 100000 <= pts) { - pos_max = newpos; - pts = newpts; - } else { - pos_min = newpos; - } - } - ffm->write_index += pos_max; - } - - end: - avio_seek(pb, ptr, SEEK_SET); -} - - -static int ffm_append_recommended_configuration(AVStream *st, char **conf) -{ - int ret; - size_t newsize; - av_assert0(conf && st); - if (!*conf) - return 0; - if (!st->recommended_encoder_configuration) { - st->recommended_encoder_configuration = *conf; - *conf = 0; - return 0; - } - newsize = strlen(*conf) + strlen(st->recommended_encoder_configuration) + 2; - if ((ret = av_reallocp(&st->recommended_encoder_configuration, newsize)) < 0) - return ret; - av_strlcat(st->recommended_encoder_configuration, ",", newsize); - av_strlcat(st->recommended_encoder_configuration, *conf, newsize); - av_freep(conf); - return 0; -} - -#define VALIDATE_PARAMETER(parameter, name, check) { \ - if (check) { \ - av_log(s, AV_LOG_ERROR, "Invalid " name " %d\n", codecpar->parameter); \ - ret = AVERROR_INVALIDDATA; \ - goto fail; \ - } \ -} - -static int ffm2_read_header(AVFormatContext *s) -{ - FFMContext *ffm = s->priv_data; - AVStream *st = NULL; - AVIOContext *pb = s->pb; - AVCodecContext *dummy_codec = NULL; - AVCodecParameters *codecpar = NULL; - const AVCodecDescriptor *codec_desc; - int ret; - int f_main = 0, f_cprv = -1, f_stvi = -1, f_stau = -1; - AVCodec *enc; - char *buffer; - - ffm->packet_size = avio_rb32(pb); - if (ffm->packet_size != FFM_PACKET_SIZE) { - av_log(s, AV_LOG_ERROR, "Invalid packet size %d, expected size was %d\n", - ffm->packet_size, FFM_PACKET_SIZE); - ret = AVERROR_INVALIDDATA; - goto fail; - } - - ffm->write_index = avio_rb64(pb); - /* get also filesize */ - if (pb->seekable & AVIO_SEEKABLE_NORMAL) { - ffm->file_size = avio_size(pb); - if (ffm->write_index && 0) - adjust_write_index(s); - } else { - ffm->file_size = (UINT64_C(1) << 63) - 1; - } - dummy_codec = avcodec_alloc_context3(NULL); - - while(!avio_feof(pb)) { - unsigned id = avio_rb32(pb); - unsigned size = avio_rb32(pb); - int64_t next = avio_tell(pb) + size; - char rc_eq_buf[128]; - int flags; - - if(!id) - break; - - switch(id) { - case MKBETAG('M', 'A', 'I', 'N'): - if (f_main++) { - ret = AVERROR(EINVAL); - goto fail; - } - avio_rb32(pb); /* nb_streams */ - avio_rb32(pb); /* total bitrate */ - break; - case MKBETAG('C', 'O', 'M', 'M'): - f_cprv = f_stvi = f_stau = 0; - st = avformat_new_stream(s, NULL); - if (!st) { - ret = AVERROR(ENOMEM); - goto fail; - } - - avpriv_set_pts_info(st, 64, 1, 1000000); - - codecpar = st->codecpar; - /* generic info */ - codecpar->codec_id = avio_rb32(pb); - codec_desc = avcodec_descriptor_get(codecpar->codec_id); - if (!codec_desc) { - av_log(s, AV_LOG_ERROR, "Invalid codec id: %d\n", codecpar->codec_id); - codecpar->codec_id = AV_CODEC_ID_NONE; - ret = AVERROR_INVALIDDATA; - goto fail; - } - codecpar->codec_type = avio_r8(pb); - if (codecpar->codec_type != codec_desc->type) { - av_log(s, AV_LOG_ERROR, "Codec type mismatch: expected %d, found %d\n", - codec_desc->type, codecpar->codec_type); - codecpar->codec_id = AV_CODEC_ID_NONE; - codecpar->codec_type = AVMEDIA_TYPE_UNKNOWN; - ret = AVERROR_INVALIDDATA; - goto fail; - } - codecpar->bit_rate = avio_rb32(pb); - if (codecpar->bit_rate < 0) { - av_log(s, AV_LOG_ERROR, "Invalid bit rate %"PRId64"\n", codecpar->bit_rate); - ret = AVERROR_INVALIDDATA; - goto fail; - } - flags = avio_rb32(pb); -#if FF_API_LAVF_AVCTX -FF_DISABLE_DEPRECATION_WARNINGS - st->codec->flags = flags; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - avio_rb32(pb); // flags2 - avio_rb32(pb); // debug - if (flags & AV_CODEC_FLAG_GLOBAL_HEADER) { - int size = avio_rb32(pb); - if (size < 0 || size >= FF_MAX_EXTRADATA_SIZE) { - av_log(s, AV_LOG_ERROR, "Invalid extradata size %d\n", size); - ret = AVERROR_INVALIDDATA; - goto fail; - } - codecpar->extradata = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!codecpar->extradata) { - ret = AVERROR(ENOMEM); - goto fail; - } - codecpar->extradata_size = size; - avio_read(pb, codecpar->extradata, size); - } - break; - case MKBETAG('S', 'T', 'V', 'I'): - if (f_stvi++ || codecpar->codec_type != AVMEDIA_TYPE_VIDEO) { - ret = AVERROR(EINVAL); - goto fail; - } - avio_rb32(pb); // time_base.num - avio_rb32(pb); // time_base.den - codecpar->width = avio_rb16(pb); - codecpar->height = avio_rb16(pb); - ret = av_image_check_size(codecpar->width, codecpar->height, 0, s); - if (ret < 0) - goto fail; - avio_rb16(pb); // gop_size - codecpar->format = avio_rb32(pb); - if (!av_pix_fmt_desc_get(codecpar->format)) { - av_log(s, AV_LOG_ERROR, "Invalid pix fmt id: %d\n", codecpar->format); - codecpar->format = AV_PIX_FMT_NONE; - ret = AVERROR_INVALIDDATA; - goto fail; - } - avio_r8(pb); // qmin - avio_r8(pb); // qmax - avio_r8(pb); // max_qdiff - avio_rb16(pb); // qcompress / 10000.0 - avio_rb16(pb); // qblur / 10000.0 - avio_rb32(pb); // bit_rate_tolerance - avio_get_str(pb, INT_MAX, rc_eq_buf, sizeof(rc_eq_buf)); - - avio_rb32(pb); // rc_max_rate - avio_rb32(pb); // rc_min_rate - avio_rb32(pb); // rc_buffer_size - avio_rb64(pb); // i_quant_factor - avio_rb64(pb); // b_quant_factor - avio_rb64(pb); // i_quant_offset - avio_rb64(pb); // b_quant_offset - avio_rb32(pb); // dct_algo - avio_rb32(pb); // strict_std_compliance - avio_rb32(pb); // max_b_frames - avio_rb32(pb); // mpeg_quant - avio_rb32(pb); // intra_dc_precision - avio_rb32(pb); // me_method - avio_rb32(pb); // mb_decision - avio_rb32(pb); // nsse_weight - avio_rb32(pb); // frame_skip_cmp - avio_rb64(pb); // rc_buffer_aggressivity - codecpar->codec_tag = avio_rb32(pb); - avio_r8(pb); // thread_count - avio_rb32(pb); // coder_type - avio_rb32(pb); // me_cmp - avio_rb32(pb); // me_subpel_quality - avio_rb32(pb); // me_range - avio_rb32(pb); // keyint_min - avio_rb32(pb); // scenechange_threshold - avio_rb32(pb); // b_frame_strategy - avio_rb64(pb); // qcompress - avio_rb64(pb); // qblur - avio_rb32(pb); // max_qdiff - avio_rb32(pb); // refs - break; - case MKBETAG('S', 'T', 'A', 'U'): - if (f_stau++ || codecpar->codec_type != AVMEDIA_TYPE_AUDIO) { - ret = AVERROR(EINVAL); - goto fail; - } - codecpar->sample_rate = avio_rb32(pb); - VALIDATE_PARAMETER(sample_rate, "sample rate", codecpar->sample_rate < 0) - codecpar->channels = avio_rl16(pb); - VALIDATE_PARAMETER(channels, "number of channels", codecpar->channels < 0) - codecpar->frame_size = avio_rl16(pb); - VALIDATE_PARAMETER(frame_size, "frame size", codecpar->frame_size < 0) - break; - case MKBETAG('C', 'P', 'R', 'V'): - if (f_cprv++) { - ret = AVERROR(EINVAL); - goto fail; - } - enc = avcodec_find_encoder(codecpar->codec_id); - if (enc && enc->priv_data_size && enc->priv_class) { - buffer = av_malloc(size + 1); - if (!buffer) { - ret = AVERROR(ENOMEM); - goto fail; - } - avio_get_str(pb, size, buffer, size + 1); - if ((ret = ffm_append_recommended_configuration(st, &buffer)) < 0) - goto fail; - } - break; - case MKBETAG('S', '2', 'V', 'I'): - if (f_stvi++ || !size || codecpar->codec_type != AVMEDIA_TYPE_VIDEO) { - ret = AVERROR(EINVAL); - goto fail; - } - buffer = av_malloc(size); - if (!buffer) { - ret = AVERROR(ENOMEM); - goto fail; - } - avio_get_str(pb, INT_MAX, buffer, size); - // The lack of AVOptions support in AVCodecParameters makes this back and forth copying needed - avcodec_parameters_to_context(dummy_codec, codecpar); - av_set_options_string(dummy_codec, buffer, "=", ","); - avcodec_parameters_from_context(codecpar, dummy_codec); - if ((ret = ffm_append_recommended_configuration(st, &buffer)) < 0) - goto fail; - break; - case MKBETAG('S', '2', 'A', 'U'): - if (f_stau++ || !size || codecpar->codec_type != AVMEDIA_TYPE_AUDIO) { - ret = AVERROR(EINVAL); - goto fail; - } - buffer = av_malloc(size); - if (!buffer) { - ret = AVERROR(ENOMEM); - goto fail; - } - avio_get_str(pb, INT_MAX, buffer, size); - // The lack of AVOptions support in AVCodecParameters makes this back and forth copying needed - avcodec_parameters_to_context(dummy_codec, codecpar); - av_set_options_string(dummy_codec, buffer, "=", ","); - avcodec_parameters_from_context(codecpar, dummy_codec); - if ((ret = ffm_append_recommended_configuration(st, &buffer)) < 0) - goto fail; - break; - } - avio_seek(pb, next, SEEK_SET); - } - - /* get until end of block reached */ - while ((avio_tell(pb) % ffm->packet_size) != 0 && !pb->eof_reached) - avio_r8(pb); - - /* init packet demux */ - ffm->packet_ptr = ffm->packet; - ffm->packet_end = ffm->packet; - ffm->frame_offset = 0; - ffm->dts = 0; - ffm->read_state = READ_HEADER; - ffm->first_packet = 1; - avcodec_free_context(&dummy_codec); - return 0; - fail: - avcodec_free_context(&dummy_codec); - return ret; -} - -static int ffm_read_header(AVFormatContext *s) -{ - FFMContext *ffm = s->priv_data; - AVStream *st; - AVIOContext *pb = s->pb; - AVCodecContext *dummy_codec = NULL; - AVCodecParameters *codecpar; - const AVCodecDescriptor *codec_desc; - int i, nb_streams, ret; - uint32_t tag; - - /* header */ - tag = avio_rl32(pb); - if (tag == MKTAG('F', 'F', 'M', '2')) - return ffm2_read_header(s); - if (tag != MKTAG('F', 'F', 'M', '1')) { - ret = AVERROR_INVALIDDATA; - goto fail; - } - ffm->packet_size = avio_rb32(pb); - if (ffm->packet_size != FFM_PACKET_SIZE) { - ret = AVERROR_INVALIDDATA; - goto fail; - } - ffm->write_index = avio_rb64(pb); - /* get also filesize */ - if (pb->seekable & AVIO_SEEKABLE_NORMAL) { - ffm->file_size = avio_size(pb); - if (ffm->write_index && 0) - adjust_write_index(s); - } else { - ffm->file_size = (UINT64_C(1) << 63) - 1; - } - dummy_codec = avcodec_alloc_context3(NULL); - - nb_streams = avio_rb32(pb); - avio_rb32(pb); /* total bitrate */ - /* read each stream */ - for(i=0;icodecpar; - /* generic info */ - codecpar->codec_id = avio_rb32(pb); - codec_desc = avcodec_descriptor_get(codecpar->codec_id); - if (!codec_desc) { - av_log(s, AV_LOG_ERROR, "Invalid codec id: %d\n", codecpar->codec_id); - codecpar->codec_id = AV_CODEC_ID_NONE; - ret = AVERROR_INVALIDDATA; - goto fail; - } - codecpar->codec_type = avio_r8(pb); /* codec_type */ - if (codecpar->codec_type != codec_desc->type) { - av_log(s, AV_LOG_ERROR, "Codec type mismatch: expected %d, found %d\n", - codec_desc->type, codecpar->codec_type); - codecpar->codec_id = AV_CODEC_ID_NONE; - codecpar->codec_type = AVMEDIA_TYPE_UNKNOWN; - ret = AVERROR_INVALIDDATA; - goto fail; - } - codecpar->bit_rate = avio_rb32(pb); - if (codecpar->bit_rate < 0) { - av_log(s, AV_LOG_WARNING, "Invalid bit rate %"PRId64"\n", codecpar->bit_rate); - ret = AVERROR_INVALIDDATA; - goto fail; - } - flags = avio_rb32(pb); -#if FF_API_LAVF_AVCTX -FF_DISABLE_DEPRECATION_WARNINGS - st->codec->flags = flags; -FF_ENABLE_DEPRECATION_WARNINGS -#endif - avio_rb32(pb); // flags2 - avio_rb32(pb); // debug - /* specific info */ - switch(codecpar->codec_type) { - case AVMEDIA_TYPE_VIDEO: - avio_rb32(pb); // time_base.num - avio_rb32(pb); // time_base.den - codecpar->width = avio_rb16(pb); - codecpar->height = avio_rb16(pb); - if ((ret = av_image_check_size(codecpar->width, codecpar->height, 0, s)) < 0) - goto fail; - avio_rb16(pb); // gop_size - codecpar->format = avio_rb32(pb); - if (!av_pix_fmt_desc_get(codecpar->format)) { - av_log(s, AV_LOG_ERROR, "Invalid pix fmt id: %d\n", codecpar->format); - codecpar->format = AV_PIX_FMT_NONE; - ret = AVERROR_INVALIDDATA; - goto fail; - } - avio_r8(pb); // qmin - avio_r8(pb); // qmax - avio_r8(pb); // max_qdiff - avio_rb16(pb); // qcompress / 10000.0 - avio_rb16(pb); // qblur / 10000.0 - avio_rb32(pb); // bit_rate_tolerance - avio_get_str(pb, INT_MAX, rc_eq_buf, sizeof(rc_eq_buf)); - - avio_rb32(pb); // rc_max_rate - avio_rb32(pb); // rc_min_rate - avio_rb32(pb); // rc_buffer_size - avio_rb64(pb); // i_quant_factor - avio_rb64(pb); // b_quant_factor - avio_rb64(pb); // i_quant_offset - avio_rb64(pb); // b_quant_offset - avio_rb32(pb); // dct_algo - avio_rb32(pb); // strict_std_compliance - avio_rb32(pb); // max_b_frames - avio_rb32(pb); // mpeg_quant - avio_rb32(pb); // intra_dc_precision - avio_rb32(pb); // me_method - avio_rb32(pb); // mb_decision - avio_rb32(pb); // nsse_weight - avio_rb32(pb); // frame_skip_cmp - avio_rb64(pb); // rc_buffer_aggressivity - codecpar->codec_tag = avio_rb32(pb); - avio_r8(pb); // thread_count - avio_rb32(pb); // coder_type - avio_rb32(pb); // me_cmp - avio_rb32(pb); // me_subpel_quality - avio_rb32(pb); // me_range - avio_rb32(pb); // keyint_min - avio_rb32(pb); // scenechange_threshold - avio_rb32(pb); // b_frame_strategy - avio_rb64(pb); // qcompress - avio_rb64(pb); // qblur - avio_rb32(pb); // max_qdiff - avio_rb32(pb); // refs - break; - case AVMEDIA_TYPE_AUDIO: - codecpar->sample_rate = avio_rb32(pb); - VALIDATE_PARAMETER(sample_rate, "sample rate", codecpar->sample_rate < 0) - codecpar->channels = avio_rl16(pb); - VALIDATE_PARAMETER(channels, "number of channels", codecpar->channels < 0) - codecpar->frame_size = avio_rl16(pb); - VALIDATE_PARAMETER(frame_size, "frame size", codecpar->frame_size < 0) - break; - default: - ret = AVERROR_INVALIDDATA; - goto fail; - } - if (flags & AV_CODEC_FLAG_GLOBAL_HEADER) { - int size = avio_rb32(pb); - if (size < 0 || size >= FF_MAX_EXTRADATA_SIZE) { - av_log(s, AV_LOG_ERROR, "Invalid extradata size %d\n", size); - ret = AVERROR_INVALIDDATA; - goto fail; - } - codecpar->extradata = av_mallocz(size + AV_INPUT_BUFFER_PADDING_SIZE); - if (!codecpar->extradata) { - ret = AVERROR(ENOMEM); - goto fail; - } - codecpar->extradata_size = size; - avio_read(pb, codecpar->extradata, size); - } - } - - /* get until end of block reached */ - while ((avio_tell(pb) % ffm->packet_size) != 0 && !pb->eof_reached) - avio_r8(pb); - - /* init packet demux */ - ffm->packet_ptr = ffm->packet; - ffm->packet_end = ffm->packet; - ffm->frame_offset = 0; - ffm->dts = 0; - ffm->read_state = READ_HEADER; - ffm->first_packet = 1; - avcodec_free_context(&dummy_codec); - return 0; - fail: - avcodec_free_context(&dummy_codec); - return ret; -} - -/* return < 0 if eof */ -static int ffm_read_packet(AVFormatContext *s, AVPacket *pkt) -{ - int size; - FFMContext *ffm = s->priv_data; - int duration, ret; - - switch(ffm->read_state) { - case READ_HEADER: - if ((ret = ffm_is_avail_data(s, FRAME_HEADER_SIZE+4)) < 0) - return ret; - - ff_dlog(s, "pos=%08"PRIx64" spos=%"PRIx64", write_index=%"PRIx64" size=%"PRIx64"\n", - avio_tell(s->pb), s->pb->pos, ffm->write_index, ffm->file_size); - if (ffm_read_data(s, ffm->header, FRAME_HEADER_SIZE, 1) != - FRAME_HEADER_SIZE) - return -1; - if (ffm->header[1] & FLAG_DTS) - if (ffm_read_data(s, ffm->header+16, 4, 1) != 4) - return -1; - ffm->read_state = READ_DATA; - /* fall through */ - case READ_DATA: - size = AV_RB24(ffm->header + 2); - if ((ret = ffm_is_avail_data(s, size)) < 0) - return ret; - - duration = AV_RB24(ffm->header + 5); - - if (av_new_packet(pkt, size) < 0) { - return AVERROR(ENOMEM); - } - pkt->stream_index = ffm->header[0]; - if ((unsigned)pkt->stream_index >= s->nb_streams) { - av_log(s, AV_LOG_ERROR, "invalid stream index %d\n", pkt->stream_index); - av_packet_unref(pkt); - ffm->read_state = READ_HEADER; - return -1; - } - pkt->pos = avio_tell(s->pb); - if (ffm->header[1] & FLAG_KEY_FRAME) - pkt->flags |= AV_PKT_FLAG_KEY; - - ffm->read_state = READ_HEADER; - if (ffm_read_data(s, pkt->data, size, 0) != size) { - /* bad case: desynchronized packet. we cancel all the packet loading */ - av_packet_unref(pkt); - return -1; - } - pkt->pts = AV_RB64(ffm->header+8); - if (ffm->header[1] & FLAG_DTS) - pkt->dts = pkt->pts - AV_RB32(ffm->header+16); - else - pkt->dts = pkt->pts; - pkt->duration = duration; - break; - } - return 0; -} - -/* seek to a given time in the file. The file read pointer is - positioned at or before pts. XXX: the following code is quite - approximative */ -static int ffm_seek(AVFormatContext *s, int stream_index, int64_t wanted_pts, int flags) -{ - FFMContext *ffm = s->priv_data; - int64_t pos_min, pos_max, pos; - int64_t pts_min, pts_max, pts; - double pos1; - - ff_dlog(s, "wanted_pts=%0.6f\n", wanted_pts / 1000000.0); - /* find the position using linear interpolation (better than - dichotomy in typical cases) */ - if (ffm->write_index && ffm->write_index < ffm->file_size) { - if (get_dts(s, FFM_PACKET_SIZE) < wanted_pts) { - pos_min = FFM_PACKET_SIZE; - pos_max = ffm->write_index - FFM_PACKET_SIZE; - } else { - pos_min = ffm->write_index; - pos_max = ffm->file_size - FFM_PACKET_SIZE; - } - } else { - pos_min = FFM_PACKET_SIZE; - pos_max = ffm->file_size - FFM_PACKET_SIZE; - } - while (pos_min <= pos_max) { - pts_min = get_dts(s, pos_min); - pts_max = get_dts(s, pos_max); - if (pts_min > wanted_pts || pts_max <= wanted_pts) { - pos = pts_min > wanted_pts ? pos_min : pos_max; - goto found; - } - /* linear interpolation */ - pos1 = (double)(pos_max - pos_min) * (double)(wanted_pts - pts_min) / - (double)(pts_max - pts_min); - pos = (((int64_t)pos1) / FFM_PACKET_SIZE) * FFM_PACKET_SIZE; - if (pos <= pos_min) - pos = pos_min; - else if (pos >= pos_max) - pos = pos_max; - pts = get_dts(s, pos); - /* check if we are lucky */ - if (pts == wanted_pts) { - goto found; - } else if (pts > wanted_pts) { - pos_max = pos - FFM_PACKET_SIZE; - } else { - pos_min = pos + FFM_PACKET_SIZE; - } - } - pos = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max; - - found: - if (ffm_seek1(s, pos) < 0) - return -1; - - /* reset read state */ - ffm->read_state = READ_HEADER; - ffm->packet_ptr = ffm->packet; - ffm->packet_end = ffm->packet; - ffm->first_packet = 1; - - return 0; -} - -static int ffm_probe(AVProbeData *p) -{ - if ( - p->buf[0] == 'F' && p->buf[1] == 'F' && p->buf[2] == 'M' && - (p->buf[3] == '1' || p->buf[3] == '2')) - return AVPROBE_SCORE_MAX + 1; - return 0; -} - -static const AVOption options[] = { - {"server_attached", NULL, offsetof(FFMContext, server_attached), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_EXPORT }, - {"ffm_write_index", NULL, offsetof(FFMContext, write_index), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, AV_OPT_FLAG_EXPORT }, - {"ffm_file_size", NULL, offsetof(FFMContext, file_size), AV_OPT_TYPE_INT64, {.i64 = 0}, 0, INT64_MAX, AV_OPT_FLAG_EXPORT }, - { NULL }, -}; - -static const AVClass ffm_class = { - .class_name = "ffm demuxer", - .item_name = av_default_item_name, - .option = options, - .version = LIBAVUTIL_VERSION_INT, -}; -AVInputFormat ff_ffm_demuxer = { - .name = "ffm", - .long_name = NULL_IF_CONFIG_SMALL("FFM (FFserver live feed)"), - .priv_data_size = sizeof(FFMContext), - .read_probe = ffm_probe, - .read_header = ffm_read_header, - .read_packet = ffm_read_packet, - .read_seek = ffm_seek, - .priv_class = &ffm_class, -}; diff --git a/libavformat/ffmenc.c b/libavformat/ffmenc.c deleted file mode 100644 index ef7dc3a03113a..0000000000000 --- a/libavformat/ffmenc.c +++ /dev/null @@ -1,362 +0,0 @@ -/* - * FFM (ffserver live feed) muxer - * Copyright (c) 2001 Fabrice Bellard - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "libavutil/intreadwrite.h" -#include "libavutil/intfloat.h" -#include "libavutil/avassert.h" -#include "libavutil/parseutils.h" -#include "libavutil/opt.h" -#include "avformat.h" -#include "avio_internal.h" -#include "internal.h" -#include "ffm.h" - -static void flush_packet(AVFormatContext *s) -{ - FFMContext *ffm = s->priv_data; - int fill_size, h; - AVIOContext *pb = s->pb; - - fill_size = ffm->packet_end - ffm->packet_ptr; - memset(ffm->packet_ptr, 0, fill_size); - - av_assert1(avio_tell(pb) % ffm->packet_size == 0); - - /* put header */ - avio_wb16(pb, PACKET_ID); - avio_wb16(pb, fill_size); - avio_wb64(pb, ffm->dts); - h = ffm->frame_offset; - if (ffm->first_packet) - h |= 0x8000; - avio_wb16(pb, h); - avio_write(pb, ffm->packet, ffm->packet_end - ffm->packet); - avio_flush(pb); - - /* prepare next packet */ - ffm->frame_offset = 0; /* no key frame */ - ffm->packet_ptr = ffm->packet; - ffm->first_packet = 0; -} - -/* 'first' is true if first data of a frame */ -static void ffm_write_data(AVFormatContext *s, - const uint8_t *buf, int size, - int64_t dts, int header) -{ - FFMContext *ffm = s->priv_data; - int len; - - if (header && ffm->frame_offset == 0) { - ffm->frame_offset = ffm->packet_ptr - ffm->packet + FFM_HEADER_SIZE; - ffm->dts = dts; - } - - /* write as many packets as needed */ - while (size > 0) { - len = ffm->packet_end - ffm->packet_ptr; - if (len > size) - len = size; - memcpy(ffm->packet_ptr, buf, len); - - ffm->packet_ptr += len; - buf += len; - size -= len; - if (ffm->packet_ptr >= ffm->packet_end) - flush_packet(s); - } -} - -static void write_header_chunk(AVIOContext *pb, AVIOContext *dpb, unsigned id) -{ - uint8_t *dyn_buf; - int dyn_size= avio_close_dyn_buf(dpb, &dyn_buf); - avio_wb32(pb, id); - avio_wb32(pb, dyn_size); - avio_write(pb, dyn_buf, dyn_size); - av_free(dyn_buf); -} - -static int ffm_write_header_codec_ctx(AVIOContext *pb, AVCodecParameters *ctxpar, unsigned tag, int type) -{ - AVIOContext *tmp; - char *buf = NULL; - int ret, need_coma = 0; - AVCodecContext *ctx = NULL; - -#define SKIP_DEFAULTS AV_OPT_SERIALIZE_SKIP_DEFAULTS -#define OPT_FLAGS_EXACT AV_OPT_SERIALIZE_OPT_FLAGS_EXACT -#define ENC AV_OPT_FLAG_ENCODING_PARAM - - if (avio_open_dyn_buf(&tmp) < 0) - return AVERROR(ENOMEM); - - // AVCodecParameters does not suport AVOptions, we thus must copy it over to a context that does - // otherwise it could be used directly and this would be much simpler - ctx = avcodec_alloc_context3(NULL); - if (!ctx) { - ret = AVERROR(ENOMEM); - goto fail; - } - avcodec_parameters_to_context(ctx, ctxpar); - - if ((ret = av_opt_serialize(ctx, ENC | type, SKIP_DEFAULTS, &buf, '=', ',')) < 0) - goto fail; - if (buf && strlen(buf)) { - avio_write(tmp, buf, strlen(buf)); - av_freep(&buf); - need_coma = 1; - } - if ((ret = av_opt_serialize(ctx, 0, SKIP_DEFAULTS | OPT_FLAGS_EXACT, &buf, '=', ',')) < 0) - goto fail; - if (buf && strlen(buf)) { - if (need_coma) - avio_w8(tmp, ','); - avio_write(tmp, buf, strlen(buf)); - } - av_freep(&buf); - avio_w8(tmp, 0); - write_header_chunk(pb, tmp, tag); - avcodec_free_context(&ctx); - return 0; - fail: - av_free(buf); - ffio_free_dyn_buf(&tmp); - avcodec_free_context(&ctx); - return ret; - -#undef SKIP_DEFAULTS -#undef OPT_FLAGS_EXACT -#undef ENC -} - -static int ffm_write_recommended_config(AVIOContext *pb, AVCodecParameters *codecpar, unsigned tag, - const char *configuration) -{ - int ret; - const AVCodec *enc = avcodec_find_encoder(codecpar->codec_id); - AVIOContext *tmp; - AVDictionaryEntry *t = NULL; - AVDictionary *all = NULL, *comm = NULL, *prv = NULL; - char *buf = NULL; - - if (!enc || !enc->priv_class || !enc->priv_data_size) { - /* codec is not known/has no private options, so save everything as common options */ - if (avio_open_dyn_buf(&tmp) < 0) - return AVERROR(ENOMEM); - avio_put_str(tmp, configuration); - write_header_chunk(pb, tmp, tag); - return 0; - } - - if ((ret = av_dict_parse_string(&all, configuration, "=", ",", 0)) < 0) - return ret; - - while ((t = av_dict_get(all, "", t, AV_DICT_IGNORE_SUFFIX))) { - if (av_opt_find((void *)&enc->priv_class, t->key, NULL, 0, AV_OPT_SEARCH_FAKE_OBJ)) { - if ((ret = av_dict_set(&prv, t->key, t->value, 0)) < 0) - goto fail; - } else if ((ret = av_dict_set(&comm, t->key, t->value, 0)) < 0) - goto fail; - } - - if (comm) { - if ((ret = av_dict_get_string(comm, &buf, '=', ',')) < 0 || - (ret = avio_open_dyn_buf(&tmp)) < 0) - goto fail; - avio_put_str(tmp, buf); - av_freep(&buf); - write_header_chunk(pb, tmp, tag); - } - if (prv) { - if ((ret = av_dict_get_string(prv, &buf, '=', ',')) < 0 || - (ret = avio_open_dyn_buf(&tmp)) < 0) - goto fail; - avio_put_str(tmp, buf); - write_header_chunk(pb, tmp, MKBETAG('C', 'P', 'R', 'V')); - } - - fail: - av_free(buf); - av_dict_free(&all); - av_dict_free(&comm); - av_dict_free(&prv); - return ret; -} - -static int ffm_write_header(AVFormatContext *s) -{ - FFMContext *ffm = s->priv_data; - AVStream *st; - AVIOContext *pb = s->pb; - AVCodecParameters *codecpar; - int bit_rate, i, ret; - - if ((ret = ff_parse_creation_time_metadata(s, &ffm->start_time, 0)) < 0) - return ret; - - ffm->packet_size = FFM_PACKET_SIZE; - - /* header */ - avio_wl32(pb, MKTAG('F', 'F', 'M', '2')); - avio_wb32(pb, ffm->packet_size); - avio_wb64(pb, 0); /* current write position */ - - if(avio_open_dyn_buf(&pb) < 0) - return AVERROR(ENOMEM); - - avio_wb32(pb, s->nb_streams); - bit_rate = 0; - for(i=0;inb_streams;i++) { - st = s->streams[i]; - bit_rate += st->codecpar->bit_rate; - } - avio_wb32(pb, bit_rate); - - write_header_chunk(s->pb, pb, MKBETAG('M', 'A', 'I', 'N')); - - /* list of streams */ - for(i=0;inb_streams;i++) { - int flags = 0; - st = s->streams[i]; - avpriv_set_pts_info(st, 64, 1, 1000000); - if(avio_open_dyn_buf(&pb) < 0) - return AVERROR(ENOMEM); - - codecpar = st->codecpar; - /* generic info */ - avio_wb32(pb, codecpar->codec_id); - avio_w8(pb, codecpar->codec_type); - avio_wb32(pb, codecpar->bit_rate); - if (codecpar->extradata_size) - flags |= AV_CODEC_FLAG_GLOBAL_HEADER; - - // If the user is not providing us with a configuration we have to fill it in as we cannot access the encoder - if (!st->recommended_encoder_configuration) { - if (s->flags & AVFMT_FLAG_BITEXACT) - flags |= AV_CODEC_FLAG_BITEXACT; - } - - avio_wb32(pb, flags); - avio_wb32(pb, 0); // flags2 - avio_wb32(pb, 0); // debug - if (codecpar->extradata_size) { - avio_wb32(pb, codecpar->extradata_size); - avio_write(pb, codecpar->extradata, codecpar->extradata_size); - } - write_header_chunk(s->pb, pb, MKBETAG('C', 'O', 'M', 'M')); - /* specific info */ - switch(codecpar->codec_type) { - case AVMEDIA_TYPE_VIDEO: - if (st->recommended_encoder_configuration) { - av_log(NULL, AV_LOG_DEBUG, "writing recommended configuration: %s\n", - st->recommended_encoder_configuration); - if ((ret = ffm_write_recommended_config(s->pb, codecpar, MKBETAG('S', '2', 'V', 'I'), - st->recommended_encoder_configuration)) < 0) - return ret; - } else if ((ret = ffm_write_header_codec_ctx(s->pb, codecpar, MKBETAG('S', '2', 'V', 'I'), AV_OPT_FLAG_VIDEO_PARAM)) < 0) - return ret; - break; - case AVMEDIA_TYPE_AUDIO: - if (st->recommended_encoder_configuration) { - av_log(NULL, AV_LOG_DEBUG, "writing recommended configuration: %s\n", - st->recommended_encoder_configuration); - if ((ret = ffm_write_recommended_config(s->pb, codecpar, MKBETAG('S', '2', 'A', 'U'), - st->recommended_encoder_configuration)) < 0) - return ret; - } else if ((ret = ffm_write_header_codec_ctx(s->pb, codecpar, MKBETAG('S', '2', 'A', 'U'), AV_OPT_FLAG_AUDIO_PARAM)) < 0) - return ret; - break; - default: - return -1; - } - } - pb = s->pb; - - avio_wb64(pb, 0); // end of header - - /* flush until end of block reached */ - while ((avio_tell(pb) % ffm->packet_size) != 0) - avio_w8(pb, 0); - - avio_flush(pb); - - /* init packet mux */ - ffm->packet_ptr = ffm->packet; - ffm->packet_end = ffm->packet + ffm->packet_size - FFM_HEADER_SIZE; - av_assert0(ffm->packet_end >= ffm->packet); - ffm->frame_offset = 0; - ffm->dts = 0; - ffm->first_packet = 1; - - return 0; -} - -static int ffm_write_packet(AVFormatContext *s, AVPacket *pkt) -{ - FFMContext *ffm = s->priv_data; - int64_t dts; - uint8_t header[FRAME_HEADER_SIZE+4]; - int header_size = FRAME_HEADER_SIZE; - - dts = ffm->start_time + pkt->dts; - /* packet size & key_frame */ - header[0] = pkt->stream_index; - header[1] = 0; - if (pkt->flags & AV_PKT_FLAG_KEY) - header[1] |= FLAG_KEY_FRAME; - AV_WB24(header+2, pkt->size); - AV_WB24(header+5, pkt->duration); - AV_WB64(header+8, ffm->start_time + pkt->pts); - if (pkt->pts != pkt->dts) { - header[1] |= FLAG_DTS; - AV_WB32(header+16, pkt->pts - pkt->dts); - header_size += 4; - } - ffm_write_data(s, header, header_size, dts, 1); - ffm_write_data(s, pkt->data, pkt->size, dts, 0); - - return 0; -} - -static int ffm_write_trailer(AVFormatContext *s) -{ - FFMContext *ffm = s->priv_data; - - /* flush packets */ - if (ffm->packet_ptr > ffm->packet) - flush_packet(s); - - return 0; -} - -AVOutputFormat ff_ffm_muxer = { - .name = "ffm", - .long_name = NULL_IF_CONFIG_SMALL("FFM (FFserver live feed)"), - .extensions = "ffm", - .priv_data_size = sizeof(FFMContext), - .audio_codec = AV_CODEC_ID_MP2, - .video_codec = AV_CODEC_ID_MPEG1VIDEO, - .write_header = ffm_write_header, - .write_packet = ffm_write_packet, - .write_trailer = ffm_write_trailer, - .flags = AVFMT_TS_NEGATIVE, -}; diff --git a/libavformat/fifo.c b/libavformat/fifo.c index c881f31e94f24..145e2e266047e 100644 --- a/libavformat/fifo.c +++ b/libavformat/fifo.c @@ -124,9 +124,9 @@ static int fifo_thread_write_header(FifoThreadContext *ctx) if (ret < 0) return ret; - ret = ff_format_output_open(avf2, avf->filename, &format_options); + ret = ff_format_output_open(avf2, avf->url, &format_options); if (ret < 0) { - av_log(avf, AV_LOG_ERROR, "Error opening %s: %s\n", avf->filename, + av_log(avf, AV_LOG_ERROR, "Error opening %s: %s\n", avf->url, av_err2str(ret)); goto end; } @@ -500,13 +500,13 @@ static int fifo_init(AVFormatContext *avf) } } - oformat = av_guess_format(fifo->format, avf->filename, NULL); + oformat = av_guess_format(fifo->format, avf->url, NULL); if (!oformat) { ret = AVERROR_MUXER_NOT_FOUND; return ret; } - ret = fifo_mux_init(avf, oformat, avf->filename); + ret = fifo_mux_init(avf, oformat, avf->url); if (ret < 0) return ret; diff --git a/libavformat/fifo_test.c b/libavformat/fifo_test.c new file mode 100644 index 0000000000000..02ec215cbbb8b --- /dev/null +++ b/libavformat/fifo_test.c @@ -0,0 +1,152 @@ +/* + * FIFO test pseudo-muxer + * Copyright (c) 2016 Jan Sebechlebsky + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with FFmpeg; if not, write to the Free Software * Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/opt.h" +#include "libavutil/time.h" +#include "libavutil/avassert.h" + +#include "avformat.h" +#include "url.h" + +/* Implementation of mock muxer to simulate real muxer failures */ + +#define MAX_TST_PACKETS 128 +#define SLEEPTIME_50_MS 50000 +#define SLEEPTIME_10_MS 10000 + +/* Implementation of mock muxer to simulate real muxer failures */ + +/* This is structure of data sent in packets to + * failing muxer */ +typedef struct FailingMuxerPacketData { + int ret; /* return value of write_packet call*/ + int recover_after; /* set ret to zero after this number of recovery attempts */ + unsigned sleep_time; /* sleep for this long in write_packet to simulate long I/O operation */ +} FailingMuxerPacketData; + + +typedef struct FailingMuxerContext { + AVClass *class; + int write_header_ret; + int write_trailer_ret; + /* If non-zero, summary of processed packets will be printed in deinit */ + int print_deinit_summary; + + int flush_count; + int pts_written[MAX_TST_PACKETS]; + int pts_written_nr; +} FailingMuxerContext; + +static int failing_write_header(AVFormatContext *avf) +{ + FailingMuxerContext *ctx = avf->priv_data; + return ctx->write_header_ret; +} + +static int failing_write_packet(AVFormatContext *avf, AVPacket *pkt) +{ + FailingMuxerContext *ctx = avf->priv_data; + int ret = 0; + if (!pkt) { + ctx->flush_count++; + } else { + FailingMuxerPacketData *data = (FailingMuxerPacketData*) pkt->data; + + if (!data->recover_after) { + data->ret = 0; + } else { + data->recover_after--; + } + + ret = data->ret; + + if (data->sleep_time) { + int64_t slept = 0; + while (slept < data->sleep_time) { + if (ff_check_interrupt(&avf->interrupt_callback)) + return AVERROR_EXIT; + av_usleep(SLEEPTIME_10_MS); + slept += SLEEPTIME_10_MS; + } + } + + if (!ret) { + ctx->pts_written[ctx->pts_written_nr++] = pkt->pts; + av_packet_unref(pkt); + } + } + return ret; +} + +static int failing_write_trailer(AVFormatContext *avf) +{ + FailingMuxerContext *ctx = avf->priv_data; + return ctx->write_trailer_ret; +} + +static void failing_deinit(AVFormatContext *avf) +{ + int i; + FailingMuxerContext *ctx = avf->priv_data; + + if (!ctx->print_deinit_summary) + return; + + printf("flush count: %d\n", ctx->flush_count); + printf("pts seen nr: %d\n", ctx->pts_written_nr); + printf("pts seen: "); + for (i = 0; i < ctx->pts_written_nr; ++i ) { + printf(i ? ",%d" : "%d", ctx->pts_written[i]); + } + printf("\n"); +} +#define OFFSET(x) offsetof(FailingMuxerContext, x) +static const AVOption options[] = { + {"write_header_ret", "write_header() return value", OFFSET(write_header_ret), + AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM}, + {"write_trailer_ret", "write_trailer() return value", OFFSET(write_trailer_ret), + AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM}, + {"print_deinit_summary", "print summary when deinitializing muxer", OFFSET(print_deinit_summary), + AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM}, + {NULL} + }; + +static const AVClass failing_muxer_class = { + .class_name = "Fifo test muxer", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVOutputFormat ff_fifo_test_muxer = { + .name = "fifo_test", + .long_name = NULL_IF_CONFIG_SMALL("Fifo test muxer"), + .priv_data_size = sizeof(FailingMuxerContext), + .write_header = failing_write_header, + .write_packet = failing_write_packet, + .write_trailer = failing_write_trailer, + .deinit = failing_deinit, + .priv_class = &failing_muxer_class, + .flags = AVFMT_NOFILE | AVFMT_ALLOW_FLUSH, +}; + diff --git a/libavformat/file.c b/libavformat/file.c index 1d321c42050e3..dabecf59ca7e1 100644 --- a/libavformat/file.c +++ b/libavformat/file.c @@ -386,7 +386,7 @@ static int pipe_open(URLContext *h, const char *filename, int flags) setmode(fd, O_BINARY); #endif c->fd = fd; - h->is_streamed = 1; + h->is_streamed = 0; return 0; } @@ -395,6 +395,7 @@ const URLProtocol ff_pipe_protocol = { .url_open = pipe_open, .url_read = file_read, .url_write = file_write, + .url_seek = file_seek, .url_get_file_handle = file_get_handle, .url_check = file_check, .priv_data_size = sizeof(FileContext), diff --git a/libavformat/fitsenc.c b/libavformat/fitsenc.c index 7cb171596c4e2..cc3999aa8a0c7 100644 --- a/libavformat/fitsenc.c +++ b/libavformat/fitsenc.c @@ -106,6 +106,8 @@ static int write_image_header(AVFormatContext *s) } bzero = 32768; break; + default: + return AVERROR(EINVAL); } if (fitsctx->first_image) { @@ -166,7 +168,9 @@ static int write_image_header(AVFormatContext *s) static int fits_write_packet(AVFormatContext *s, AVPacket *pkt) { - write_image_header(s); + int ret = write_image_header(s); + if (ret < 0) + return ret; avio_write(s->pb, pkt->data, pkt->size); return 0; } diff --git a/libavformat/flacenc.c b/libavformat/flacenc.c index b894f9ef614cb..617bccdc84a88 100644 --- a/libavformat/flacenc.c +++ b/libavformat/flacenc.c @@ -21,10 +21,13 @@ #include "libavutil/channel_layout.h" #include "libavutil/opt.h" +#include "libavutil/pixdesc.h" #include "libavcodec/flac.h" #include "avformat.h" #include "avio_internal.h" #include "flacenc.h" +#include "id3v2.h" +#include "internal.h" #include "vorbiscomment.h" #include "libavcodec/bytestream.h" @@ -33,8 +36,15 @@ typedef struct FlacMuxerContext { const AVClass *class; int write_header; + int audio_stream_idx; + int waiting_pics; + /* audio packets are queued here until we get all the attached pictures */ + AVPacketList *queue, *queue_end; + /* updated streaminfo sent by the encoder at the end */ uint8_t *streaminfo; + + unsigned attached_types; } FlacMuxerContext; static int flac_write_block_padding(AVIOContext *pb, unsigned int n_padding_bytes, @@ -74,36 +84,160 @@ static int flac_write_block_comment(AVIOContext *pb, AVDictionary **m, return 0; } -static int flac_write_header(struct AVFormatContext *s) +static int flac_write_picture(struct AVFormatContext *s, AVPacket *pkt) { - int ret; - int padding = s->metadata_header_padding; - AVCodecParameters *par = s->streams[0]->codecpar; - FlacMuxerContext *c = s->priv_data; - - if (!c->write_header) + FlacMuxerContext *c = s->priv_data; + AVIOContext *pb = s->pb; + const AVPixFmtDescriptor *pixdesc; + const CodecMime *mime = ff_id3v2_mime_tags; + AVDictionaryEntry *e; + const char *mimetype = NULL, *desc = ""; + const AVStream *st = s->streams[pkt->stream_index]; + int i, mimelen, desclen, type = 0; + + if (!pkt->data) return 0; - if (s->nb_streams > 1) { - av_log(s, AV_LOG_ERROR, "only one stream is supported\n"); + while (mime->id != AV_CODEC_ID_NONE) { + if (mime->id == st->codecpar->codec_id) { + mimetype = mime->str; + break; + } + mime++; + } + if (!mimetype) { + av_log(s, AV_LOG_ERROR, "No mimetype is known for stream %d, cannot " + "write an attached picture.\n", st->index); + return AVERROR(EINVAL); + } + mimelen = strlen(mimetype); + + /* get the picture type */ + e = av_dict_get(st->metadata, "comment", NULL, 0); + for (i = 0; e && i < FF_ARRAY_ELEMS(ff_id3v2_picture_types); i++) { + if (!av_strcasecmp(e->value, ff_id3v2_picture_types[i])) { + type = i; + break; + } + } + + if ((c->attached_types & (1 << type)) & 0x6) { + av_log(s, AV_LOG_ERROR, "Duplicate attachment for type '%s'\n", ff_id3v2_picture_types[type]); return AVERROR(EINVAL); } - if (par->codec_id != AV_CODEC_ID_FLAC) { - av_log(s, AV_LOG_ERROR, "unsupported codec\n"); + + if (type == 1 && (st->codecpar->codec_id != AV_CODEC_ID_PNG || + st->codecpar->width != 32 || + st->codecpar->height != 32)) { + av_log(s, AV_LOG_ERROR, "File icon attachment must be a 32x32 PNG"); return AVERROR(EINVAL); } + c->attached_types |= (1 << type); + + /* get the description */ + if ((e = av_dict_get(st->metadata, "title", NULL, 0))) + desc = e->value; + desclen = strlen(desc); + + avio_w8(pb, 0x06); + avio_wb24(pb, 4 + 4 + mimelen + 4 + desclen + 4 + 4 + 4 + 4 + 4 + pkt->size); + + avio_wb32(pb, type); + + avio_wb32(pb, mimelen); + avio_write(pb, mimetype, mimelen); + + avio_wb32(pb, desclen); + avio_write(pb, desc, desclen); + + avio_wb32(pb, st->codecpar->width); + avio_wb32(pb, st->codecpar->height); + if ((pixdesc = av_pix_fmt_desc_get(st->codecpar->format))) + avio_wb32(pb, av_get_bits_per_pixel(pixdesc)); + else + avio_wb32(pb, 0); + avio_wb32(pb, 0); + + avio_wb32(pb, pkt->size); + avio_write(pb, pkt->data, pkt->size); + return 0; +} + +static int flac_finish_header(struct AVFormatContext *s) +{ + int i, ret, padding = s->metadata_header_padding; if (padding < 0) padding = 8192; /* The FLAC specification states that 24 bits are used to represent the * size of a metadata block so we must clip this value to 2^24-1. */ padding = av_clip_uintp2(padding, 24); - ret = ff_flac_write_header(s->pb, par->extradata, - par->extradata_size, 0); + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + AVPacket *pkt = st->priv_data; + if (!pkt) + continue; + ret = flac_write_picture(s, pkt); + av_packet_unref(pkt); + if (ret < 0 && (s->error_recognition & AV_EF_EXPLODE)) + return ret; + } + + ret = flac_write_block_comment(s->pb, &s->metadata, !padding, + s->flags & AVFMT_FLAG_BITEXACT); if (ret) return ret; + /* The command line flac encoder defaults to placing a seekpoint + * every 10s. So one might add padding to allow that later + * but there seems to be no simple way to get the duration here. + * So just add the amount requested by the user. */ + if (padding) + flac_write_block_padding(s->pb, padding, 1); + + return 0; +} + +static int flac_init(struct AVFormatContext *s) +{ + AVCodecParameters *par; + FlacMuxerContext *c = s->priv_data; + int i; + + c->audio_stream_idx = -1; + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { + if (c->audio_stream_idx >= 0 || st->codecpar->codec_id != AV_CODEC_ID_FLAC) { + av_log(s, AV_LOG_ERROR, "Invalid audio stream. Exactly one FLAC " + "audio stream is required.\n"); + return AVERROR(EINVAL); + } + par = s->streams[i]->codecpar; + c->audio_stream_idx = i; + } else if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + if (!(st->disposition & AV_DISPOSITION_ATTACHED_PIC)) { + av_log(s, AV_LOG_WARNING, "Video stream #%d is not an attached picture. Ignoring\n", i); + continue; + } else if (st->codecpar->codec_id == AV_CODEC_ID_GIF) { + av_log(s, AV_LOG_ERROR, "GIF image support is not implemented.\n"); + return AVERROR_PATCHWELCOME; + } else if (!c->write_header) { + av_log(s, AV_LOG_ERROR, "Can't write attached pictures without a header.\n"); + return AVERROR(EINVAL); + } + c->waiting_pics++; + } else { + av_log(s, AV_LOG_ERROR, "Only audio streams and pictures are allowed in FLAC.\n"); + return AVERROR(EINVAL); + } + } + if (c->audio_stream_idx < 0) { + av_log(s, AV_LOG_ERROR, "No audio stream present.\n"); + return AVERROR(EINVAL); + } + /* add the channel layout tag */ if (par->channel_layout && !(par->channel_layout & ~0x3ffffULL) && @@ -121,18 +255,68 @@ static int flac_write_header(struct AVFormatContext *s) } } - ret = flac_write_block_comment(s->pb, &s->metadata, !padding, - s->flags & AVFMT_FLAG_BITEXACT); - if (ret) + return 0; +} + +static int flac_write_header(struct AVFormatContext *s) +{ + FlacMuxerContext *c = s->priv_data; + AVCodecParameters *par = s->streams[c->audio_stream_idx]->codecpar; + int ret; + + if (!c->write_header) + return 0; + + ret = ff_flac_write_header(s->pb, par->extradata, + par->extradata_size, 0); + if (ret < 0) return ret; - /* The command line flac encoder defaults to placing a seekpoint - * every 10s. So one might add padding to allow that later - * but there seems to be no simple way to get the duration here. - * So just add the amount requested by the user. */ - if (padding) - flac_write_block_padding(s->pb, padding, 1); + if (!c->waiting_pics) + ret = flac_finish_header(s); + + return ret; +} + +static int flac_write_audio_packet(struct AVFormatContext *s, AVPacket *pkt) +{ + FlacMuxerContext *c = s->priv_data; + uint8_t *streaminfo; + int streaminfo_size; + + /* check for updated streaminfo */ + streaminfo = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, + &streaminfo_size); + if (streaminfo && streaminfo_size == FLAC_STREAMINFO_SIZE) { + av_freep(&c->streaminfo); + + c->streaminfo = av_malloc(FLAC_STREAMINFO_SIZE); + if (!c->streaminfo) + return AVERROR(ENOMEM); + memcpy(c->streaminfo, streaminfo, FLAC_STREAMINFO_SIZE); + } + + if (pkt->size) + avio_write(s->pb, pkt->data, pkt->size); + return 0; +} +static int flac_queue_flush(AVFormatContext *s) +{ + FlacMuxerContext *c = s->priv_data; + AVPacket pkt; + int ret, write = 1; + + ret = flac_finish_header(s); + if (ret < 0) + write = 0; + + while (c->queue) { + ff_packet_list_get(&c->queue, &c->queue_end, &pkt); + if (write && (ret = flac_write_audio_packet(s, &pkt)) < 0) + write = 0; + av_packet_unref(&pkt); + } return ret; } @@ -142,7 +326,13 @@ static int flac_write_trailer(struct AVFormatContext *s) int64_t file_size; FlacMuxerContext *c = s->priv_data; uint8_t *streaminfo = c->streaminfo ? c->streaminfo : - s->streams[0]->codecpar->extradata; + s->streams[c->audio_stream_idx]->codecpar->extradata; + + if (c->waiting_pics) { + av_log(s, AV_LOG_WARNING, "No packets were sent for some of the " + "attached pictures.\n"); + flac_queue_flush(s); + } if (!c->write_header || !streaminfo) return 0; @@ -166,23 +356,48 @@ static int flac_write_trailer(struct AVFormatContext *s) static int flac_write_packet(struct AVFormatContext *s, AVPacket *pkt) { FlacMuxerContext *c = s->priv_data; - uint8_t *streaminfo; - int streaminfo_size; + int ret; - /* check for updated streaminfo */ - streaminfo = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, - &streaminfo_size); - if (streaminfo && streaminfo_size == FLAC_STREAMINFO_SIZE) { - av_freep(&c->streaminfo); + if (pkt->stream_index == c->audio_stream_idx) { + if (c->waiting_pics) { + /* buffer audio packets until we get all the pictures */ + ret = ff_packet_list_put(&c->queue, &c->queue_end, pkt, FF_PACKETLIST_FLAG_REF_PACKET); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Out of memory in packet queue; skipping attached pictures\n"); + c->waiting_pics = 0; + ret = flac_queue_flush(s); + if (ret < 0) + return ret; + return flac_write_audio_packet(s, pkt); + } + } else + return flac_write_audio_packet(s, pkt); + } else { + AVStream *st = s->streams[pkt->stream_index]; - c->streaminfo = av_malloc(FLAC_STREAMINFO_SIZE); - if (!c->streaminfo) - return AVERROR(ENOMEM); - memcpy(c->streaminfo, streaminfo, FLAC_STREAMINFO_SIZE); + if (!c->waiting_pics || + !(st->disposition & AV_DISPOSITION_ATTACHED_PIC)) + return 0; + + /* warn only once for each stream */ + if (st->nb_frames == 1) { + av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d," + " ignoring.\n", pkt->stream_index); + } + if (st->nb_frames >= 1) + return 0; + + st->priv_data = av_packet_clone(pkt); + if (!st->priv_data) + av_log(s, AV_LOG_ERROR, "Out of memory queueing an attached picture; skipping\n"); + c->waiting_pics--; + + /* flush the buffered audio packets */ + if (!c->waiting_pics && + (ret = flac_queue_flush(s)) < 0) + return ret; } - if (pkt->size) - avio_write(s->pb, pkt->data, pkt->size); return 0; } @@ -205,7 +420,8 @@ AVOutputFormat ff_flac_muxer = { .mime_type = "audio/x-flac", .extensions = "flac", .audio_codec = AV_CODEC_ID_FLAC, - .video_codec = AV_CODEC_ID_NONE, + .video_codec = AV_CODEC_ID_PNG, + .init = flac_init, .write_header = flac_write_header, .write_packet = flac_write_packet, .write_trailer = flac_write_trailer, diff --git a/libavformat/flv.h b/libavformat/flv.h index df5ce3d17f8c7..97324cca46d5a 100644 --- a/libavformat/flv.h +++ b/libavformat/flv.h @@ -109,6 +109,7 @@ enum { FLV_CODECID_H264 = 7, FLV_CODECID_REALH263= 8, FLV_CODECID_MPEG4 = 9, + FLV_CODECID_HEVC = 12, }; enum { diff --git a/libavformat/flvdec.c b/libavformat/flvdec.c index 2d89bef15f25b..10c16e9c93fc6 100644 --- a/libavformat/flvdec.c +++ b/libavformat/flvdec.c @@ -291,6 +291,8 @@ static int flv_same_video_codec(AVCodecParameters *vpar, int flags) return vpar->codec_id == AV_CODEC_ID_VP6A; case FLV_CODECID_H264: return vpar->codec_id == AV_CODEC_ID_H264; + case FLV_CODECID_HEVC: + return vpar->codec_id == AV_CODEC_ID_HEVC; default: return vpar->codec_tag == flv_codecid; } @@ -331,6 +333,11 @@ static int flv_set_video_codec(AVFormatContext *s, AVStream *vstream, } ret = 1; // 1 byte body size adjustment for flv_read_packet() break; + case FLV_CODECID_HEVC: + par->codec_id = AV_CODEC_ID_HEVC; + vstream->need_parsing = AVSTREAM_PARSE_NONE; + ret = 3; // not 4, reading packet type will consume one byte + break; case FLV_CODECID_H264: par->codec_id = AV_CODEC_ID_H264; vstream->need_parsing = AVSTREAM_PARSE_HEADERS; @@ -598,8 +605,10 @@ static int amf_parse_object(AVFormatContext *s, AVStream *astream, if (version > 0 && version <= 655) flv->broken_sizes = 1; } - } else if (!strcmp(key, "metadatacreator") && !strcmp(str_val, "MEGA")) { - flv->broken_sizes = 1; + } else if (!strcmp(key, "metadatacreator")) { + if ( !strcmp (str_val, "MEGA") + || !strncmp(str_val, "FlixEngine", 10)) + flv->broken_sizes = 1; } } } @@ -1149,10 +1158,17 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) if (st->codecpar->codec_id == AV_CODEC_ID_AAC || st->codecpar->codec_id == AV_CODEC_ID_H264 || - st->codecpar->codec_id == AV_CODEC_ID_MPEG4) { + st->codecpar->codec_id == AV_CODEC_ID_MPEG4 || + st->codecpar->codec_id == AV_CODEC_ID_HEVC) { int type = avio_r8(s->pb); size--; - if (st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_MPEG4) { + + if (size < 0) { + ret = AVERROR_INVALIDDATA; + goto leave; + } + + if (st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_MPEG4 || st->codecpar->codec_id == AV_CODEC_ID_HEVC) { // sign extension int32_t cts = (avio_rb24(s->pb) + 0xff800000) ^ 0xff800000; pts = dts + cts; @@ -1168,7 +1184,7 @@ static int flv_read_packet(AVFormatContext *s, AVPacket *pkt) } } if (type == 0 && (!st->codecpar->extradata || st->codecpar->codec_id == AV_CODEC_ID_AAC || - st->codecpar->codec_id == AV_CODEC_ID_H264)) { + st->codecpar->codec_id == AV_CODEC_ID_H264 || st->codecpar->codec_id == AV_CODEC_ID_HEVC)) { AVDictionaryEntry *t; if (st->codecpar->extradata) { diff --git a/libavformat/flvenc.c b/libavformat/flvenc.c index 899b07ea7bef8..e8af48cb6415a 100644 --- a/libavformat/flvenc.c +++ b/libavformat/flvenc.c @@ -610,10 +610,10 @@ static int shift_data(AVFormatContext *s) * writing, so we re-open the same output, but for reading. It also avoids * a read/seek/write/seek back and forth. */ avio_flush(s->pb); - ret = s->io_open(s, &read_pb, s->filename, AVIO_FLAG_READ, NULL); + ret = s->io_open(s, &read_pb, s->url, AVIO_FLAG_READ, NULL); if (ret < 0) { av_log(s, AV_LOG_ERROR, "Unable to re-open %s output file for " - "the second pass (add_keyframe_index)\n", s->filename); + "the second pass (add_keyframe_index)\n", s->url); goto end; } diff --git a/libavformat/format.c b/libavformat/format.c index 38ca2a3465aff..1c66afb7e6d55 100644 --- a/libavformat/format.c +++ b/libavformat/format.c @@ -19,10 +19,10 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/atomic.h" #include "libavutil/avstring.h" #include "libavutil/bprint.h" #include "libavutil/opt.h" +#include "libavutil/thread.h" #include "avio_internal.h" #include "avformat.h" @@ -34,53 +34,6 @@ * @file * Format register and lookup */ -/** head of registered input format linked list */ -static AVInputFormat *first_iformat = NULL; -/** head of registered output format linked list */ -static AVOutputFormat *first_oformat = NULL; - -static AVInputFormat **last_iformat = &first_iformat; -static AVOutputFormat **last_oformat = &first_oformat; - -AVInputFormat *av_iformat_next(const AVInputFormat *f) -{ - if (f) - return f->next; - else - return first_iformat; -} - -AVOutputFormat *av_oformat_next(const AVOutputFormat *f) -{ - if (f) - return f->next; - else - return first_oformat; -} - -void av_register_input_format(AVInputFormat *format) -{ - AVInputFormat **p = last_iformat; - - // Note, format could be added after the first 2 checks but that implies that *p is no longer NULL - while(p != &format->next && !format->next && avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format)) - p = &(*p)->next; - - if (!format->next) - last_iformat = &format->next; -} - -void av_register_output_format(AVOutputFormat *format) -{ - AVOutputFormat **p = last_oformat; - - // Note, format could be added after the first 2 checks but that implies that *p is no longer NULL - while(p != &format->next && !format->next && avpriv_atomic_ptr_cas((void * volatile *)p, NULL, format)) - p = &(*p)->next; - - if (!format->next) - last_oformat = &format->next; -} int av_match_ext(const char *filename, const char *extensions) { @@ -98,7 +51,9 @@ int av_match_ext(const char *filename, const char *extensions) AVOutputFormat *av_guess_format(const char *short_name, const char *filename, const char *mime_type) { - AVOutputFormat *fmt = NULL, *fmt_found; + const AVOutputFormat *fmt = NULL; + AVOutputFormat *fmt_found = NULL; + void *i = 0; int score_max, score; /* specific test for image sequences */ @@ -110,9 +65,8 @@ AVOutputFormat *av_guess_format(const char *short_name, const char *filename, } #endif /* Find the proper file type. */ - fmt_found = NULL; score_max = 0; - while ((fmt = av_oformat_next(fmt))) { + while ((fmt = av_muxer_iterate(&i))) { score = 0; if (fmt->name && short_name && av_match_name(short_name, fmt->name)) score += 100; @@ -124,7 +78,7 @@ AVOutputFormat *av_guess_format(const char *short_name, const char *filename, } if (score > score_max) { score_max = score; - fmt_found = fmt; + fmt_found = (AVOutputFormat*)fmt; } } return fmt_found; @@ -163,10 +117,11 @@ enum AVCodecID av_guess_codec(AVOutputFormat *fmt, const char *short_name, AVInputFormat *av_find_input_format(const char *short_name) { - AVInputFormat *fmt = NULL; - while ((fmt = av_iformat_next(fmt))) + const AVInputFormat *fmt = NULL; + void *i = 0; + while ((fmt = av_demuxer_iterate(&i))) if (av_match_name(short_name, fmt->name)) - return fmt; + return (AVInputFormat*)fmt; return NULL; } @@ -174,8 +129,10 @@ AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, int *score_ret) { AVProbeData lpd = *pd; - AVInputFormat *fmt1 = NULL, *fmt; + const AVInputFormat *fmt1 = NULL; + AVInputFormat *fmt = NULL; int score, score_max = 0; + void *i = 0; const static uint8_t zerobuffer[AVPROBE_PADDING_SIZE]; enum nodat { NO_ID3, @@ -200,8 +157,7 @@ AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, nodat = ID3_GREATER_PROBE; } - fmt = NULL; - while ((fmt1 = av_iformat_next(fmt1))) { + while ((fmt1 = av_demuxer_iterate(&i))) { if (!is_opened == !(fmt1->flags & AVFMT_NOFILE) && strcmp(fmt1->name, "image2")) continue; score = 0; @@ -235,7 +191,7 @@ AVInputFormat *av_probe_input_format3(AVProbeData *pd, int is_opened, } if (score > score_max) { score_max = score; - fmt = fmt1; + fmt = (AVInputFormat*)fmt1; } else if (score == score_max) fmt = NULL; } diff --git a/libavformat/gxfenc.c b/libavformat/gxfenc.c index 0e0772b744157..3507c00b40122 100644 --- a/libavformat/gxfenc.c +++ b/libavformat/gxfenc.c @@ -311,7 +311,7 @@ static int gxf_write_material_data_section(AVFormatContext *s) AVIOContext *pb = s->pb; int64_t pos; int len; - const char *filename = strrchr(s->filename, '/'); + const char *filename = strrchr(s->url, '/'); pos = avio_tell(pb); avio_wb16(pb, 0); /* size */ @@ -320,7 +320,7 @@ static int gxf_write_material_data_section(AVFormatContext *s) if (filename) filename++; else - filename = s->filename; + filename = s->url; len = strlen(filename); avio_w8(pb, MAT_NAME); diff --git a/libavformat/hdsenc.c b/libavformat/hdsenc.c index 72829f7257a28..d82aee17b98e2 100644 --- a/libavformat/hdsenc.c +++ b/libavformat/hdsenc.c @@ -169,8 +169,8 @@ static int write_manifest(AVFormatContext *s, int final) if (c->nb_streams > 0) duration = c->streams[0].last_ts * av_q2d(s->streams[0]->time_base); - snprintf(filename, sizeof(filename), "%s/index.f4m", s->filename); - snprintf(temp_filename, sizeof(temp_filename), "%s/index.f4m.tmp", s->filename); + snprintf(filename, sizeof(filename), "%s/index.f4m", s->url); + snprintf(temp_filename, sizeof(temp_filename), "%s/index.f4m.tmp", s->url); ret = s->io_open(s, &out, temp_filename, AVIO_FLAG_WRITE, NULL); if (ret < 0) { av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename); @@ -178,7 +178,7 @@ static int write_manifest(AVFormatContext *s, int final) } avio_printf(out, "\n"); avio_printf(out, "\n"); - avio_printf(out, "\t%s\n", av_basename(s->filename)); + avio_printf(out, "\t%s\n", av_basename(s->url)); avio_printf(out, "\t%s\n", final ? "recorded" : "live"); avio_printf(out, "\tstreaming\n"); @@ -236,9 +236,9 @@ static int write_abst(AVFormatContext *s, OutputStream *os, int final) cur_media_time = os->fragments[os->nb_fragments - 1]->start_time; snprintf(filename, sizeof(filename), - "%s/stream%d.abst", s->filename, index); + "%s/stream%d.abst", s->url, index); snprintf(temp_filename, sizeof(temp_filename), - "%s/stream%d.abst.tmp", s->filename, index); + "%s/stream%d.abst.tmp", s->url, index); ret = s->io_open(s, &out, temp_filename, AVIO_FLAG_WRITE, NULL); if (ret < 0) { av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename); @@ -317,9 +317,9 @@ static int hds_write_header(AVFormatContext *s) int ret = 0, i; AVOutputFormat *oformat; - if (mkdir(s->filename, 0777) == -1 && errno != EEXIST) { + if (mkdir(s->url, 0777) == -1 && errno != EEXIST) { ret = AVERROR(errno); - av_log(s, AV_LOG_ERROR , "Failed to create directory %s\n", s->filename); + av_log(s, AV_LOG_ERROR , "Failed to create directory %s\n", s->url); goto fail; } @@ -412,7 +412,7 @@ static int hds_write_header(AVFormatContext *s) s->streams[os->first_stream + j]->time_base = os->ctx->streams[j]->time_base; snprintf(os->temp_filename, sizeof(os->temp_filename), - "%s/stream%d_temp", s->filename, i); + "%s/stream%d_temp", s->url, i); ret = init_file(s, os, 0); if (ret < 0) goto fail; @@ -476,7 +476,7 @@ static int hds_flush(AVFormatContext *s, OutputStream *os, int final, close_file(s, os); snprintf(target_filename, sizeof(target_filename), - "%s/stream%dSeg1-Frag%d", s->filename, index, os->fragment_index); + "%s/stream%dSeg1-Frag%d", s->url, index, os->fragment_index); ret = ff_rename(os->temp_filename, target_filename, s); if (ret < 0) return ret; @@ -549,13 +549,13 @@ static int hds_write_trailer(AVFormatContext *s) if (c->remove_at_exit) { char filename[1024]; - snprintf(filename, sizeof(filename), "%s/index.f4m", s->filename); + snprintf(filename, sizeof(filename), "%s/index.f4m", s->url); unlink(filename); for (i = 0; i < c->nb_streams; i++) { - snprintf(filename, sizeof(filename), "%s/stream%d.abst", s->filename, i); + snprintf(filename, sizeof(filename), "%s/stream%d.abst", s->url, i); unlink(filename); } - rmdir(s->filename); + rmdir(s->url); } hds_free(s); diff --git a/libavformat/hevc.c b/libavformat/hevc.c index 1a2d6cdd2b258..3628d5a0282b7 100644 --- a/libavformat/hevc.c +++ b/libavformat/hevc.c @@ -417,7 +417,7 @@ static void skip_scaling_list_data(GetBitContext *gb) static int parse_rps(GetBitContext *gb, unsigned int rps_idx, unsigned int num_rps, - unsigned int num_delta_pocs[HEVC_MAX_SHORT_TERM_RPS_COUNT]) + unsigned int num_delta_pocs[HEVC_MAX_SHORT_TERM_REF_PIC_SETS]) { unsigned int i; @@ -486,7 +486,7 @@ static int hvcc_parse_sps(GetBitContext *gb, HEVCDecoderConfigurationRecord *hvcc) { unsigned int i, sps_max_sub_layers_minus1, log2_max_pic_order_cnt_lsb_minus4; - unsigned int num_short_term_ref_pic_sets, num_delta_pocs[HEVC_MAX_SHORT_TERM_RPS_COUNT]; + unsigned int num_short_term_ref_pic_sets, num_delta_pocs[HEVC_MAX_SHORT_TERM_REF_PIC_SETS]; skip_bits(gb, 4); // sps_video_parameter_set_id @@ -556,7 +556,7 @@ static int hvcc_parse_sps(GetBitContext *gb, } num_short_term_ref_pic_sets = get_ue_golomb_long(gb); - if (num_short_term_ref_pic_sets > HEVC_MAX_SHORT_TERM_RPS_COUNT) + if (num_short_term_ref_pic_sets > HEVC_MAX_SHORT_TERM_REF_PIC_SETS) return AVERROR_INVALIDDATA; for (i = 0; i < num_short_term_ref_pic_sets; i++) { @@ -669,6 +669,8 @@ static uint8_t *nal_unit_extract_rbsp(const uint8_t *src, uint32_t src_len, while (i < src_len) dst[len++] = src[i++]; + memset(dst + len, 0, AV_INPUT_BUFFER_PADDING_SIZE); + *dst_len = len; return dst; } diff --git a/libavformat/hls.c b/libavformat/hls.c index 786934af032f3..db40420bddafe 100644 --- a/libavformat/hls.c +++ b/libavformat/hls.c @@ -2,6 +2,7 @@ * Apple HTTP Live Streaming demuxer * Copyright (c) 2010 Martin Storsjo * Copyright (c) 2013 Anssi Hannula + * Copyright (c) 2011 Cedirc Fung (wolfplanet@gmail.com) * * This file is part of FFmpeg. * @@ -26,6 +27,7 @@ * http://tools.ietf.org/html/draft-pantos-http-live-streaming */ +#include "libavformat/http.h" #include "libavutil/avstring.h" #include "libavutil/avassert.h" #include "libavutil/intreadwrite.h" @@ -65,7 +67,9 @@ enum KeyType { }; struct segment { + int64_t previous_duration; int64_t duration; + int64_t start_time; int64_t url_offset; int64_t size; char *url; @@ -94,6 +98,9 @@ struct playlist { AVIOContext pb; uint8_t* read_buffer; AVIOContext *input; + int input_read_done; + AVIOContext *input_next; + int input_next_requested; AVFormatContext *parent; int index; AVFormatContext *ctx; @@ -111,7 +118,7 @@ struct playlist { int start_seq_no; int n_segments; struct segment **segments; - int needed, cur_needed; + int needed; int cur_seq_no; int64_t cur_seg_offset; int64_t last_load_time; @@ -198,6 +205,7 @@ typedef struct HLSContext { int64_t first_timestamp; int64_t cur_timestamp; AVIOInterruptCB *interrupt_callback; + char *referer; ///< holds HTTP referer set as an AVOption to the HTTP protocol context char *user_agent; ///< holds HTTP user agent set as an AVOption to the HTTP protocol context char *cookies; ///< holds HTTP cookie values set in either the initial response or as an AVOption to the HTTP protocol context char *headers; ///< holds HTTP headers set as an AVOption to the HTTP protocol context @@ -206,16 +214,13 @@ typedef struct HLSContext { int strict_std_compliance; char *allowed_extensions; int max_reload; + int http_persistent; + int http_multiple; + AVIOContext *playlist_pb; + int hls_io_protocol_enable; + char * hls_io_protocol; } HLSContext; -static int read_chomp_line(AVIOContext *s, char *buf, int maxlen) -{ - int len = ff_get_line(s, buf, maxlen); - while (len > 0 && av_isspace(buf[len - 1])) - buf[--len] = '\0'; - return len; -} - static void free_segment_list(struct playlist *pls) { int i; @@ -256,6 +261,10 @@ static void free_playlist_list(HLSContext *c) av_freep(&pls->pb.buffer); if (pls->input) ff_format_io_close(c->ctx, &pls->input); + pls->input_read_done = 0; + if (pls->input_next) + ff_format_io_close(c->ctx, &pls->input_next); + pls->input_next_requested = 0; if (pls->ctx) { pls->ctx->pb = NULL; avformat_close_input(&pls->ctx); @@ -597,16 +606,36 @@ static void update_options(char **dest, const char *name, void *src) av_freep(dest); } +static int open_url_keepalive(AVFormatContext *s, AVIOContext **pb, + const char *url) +{ +#if !CONFIG_HTTP_PROTOCOL + return AVERROR_PROTOCOL_NOT_FOUND; +#else + int ret; + URLContext *uc = ffio_geturlcontext(*pb); + av_assert0(uc); + (*pb)->eof_reached = 0; + ret = ff_http_do_new_request(uc, url); + if (ret < 0) { + ff_format_io_close(s, pb); + } + return ret; +#endif +} + static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, - AVDictionary *opts, AVDictionary *opts2, int *is_http) + AVDictionary *opts, AVDictionary *opts2, int *is_http_out) { HLSContext *c = s->priv_data; AVDictionary *tmp = NULL; const char *proto_name = NULL; int ret; + int is_http = 0; av_dict_copy(&tmp, opts, 0); av_dict_copy(&tmp, opts2, 0); + av_dict_set(&tmp, "seekable", "1", 0); if (av_strstart(url, "crypto", NULL)) { if (url[6] == '+' || url[6] == ':') @@ -629,6 +658,8 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, return AVERROR_INVALIDDATA; } } else if (av_strstart(proto_name, "http", NULL)) { + is_http = 1; + } else if (c->hls_io_protocol_enable) { ; } else return AVERROR_INVALIDDATA; @@ -640,7 +671,20 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, else if (strcmp(proto_name, "file") || !strncmp(url, "file,", 5)) return AVERROR_INVALIDDATA; - ret = s->io_open(s, pb, url, AVIO_FLAG_READ, &tmp); + if (is_http && c->http_persistent && *pb) { + ret = open_url_keepalive(c->ctx, pb, url); + if (ret == AVERROR_EXIT) { + return ret; + } else if (ret < 0) { + if (ret != AVERROR_EOF) + av_log(s, AV_LOG_WARNING, + "keepalive request failed for '%s', retrying with new connection: %s\n", + url, av_err2str(ret)); + ret = s->io_open(s, pb, url, AVIO_FLAG_READ, &tmp); + } + } else { + ret = s->io_open(s, pb, url, AVIO_FLAG_READ, &tmp); + } if (ret >= 0) { // update cookies on http response with setcookies. char *new_cookies = NULL; @@ -658,8 +702,8 @@ static int open_url(AVFormatContext *s, AVIOContext **pb, const char *url, av_dict_free(&tmp); - if (is_http) - *is_http = av_strstart(proto_name, "http", NULL); + if (is_http_out) + *is_http_out = is_http; return ret; } @@ -668,12 +712,13 @@ static int parse_playlist(HLSContext *c, const char *url, struct playlist *pls, AVIOContext *in) { int ret = 0, is_segment = 0, is_variant = 0; - int64_t duration = 0; + int64_t duration = 0, previous_duration1 = 0, previous_duration = 0, total_duration = 0; enum KeyType key_type = KEY_NONE; uint8_t iv[16] = ""; int has_iv = 0; char key[MAX_URL_SIZE] = ""; char line[MAX_URL_SIZE]; + char io_url[MAX_URL_SIZE] = ""; const char *ptr; int close_in = 0; int64_t seg_offset = 0; @@ -682,11 +727,28 @@ static int parse_playlist(HLSContext *c, const char *url, struct variant_info variant_info; char tmp_str[MAX_URL_SIZE]; struct segment *cur_init_section = NULL; + int is_http = av_strstart(url, "http", NULL); + + if (is_http && !in && c->http_persistent && c->playlist_pb) { + in = c->playlist_pb; + ret = open_url_keepalive(c->ctx, &c->playlist_pb, url); + if (ret == AVERROR_EXIT) { + return ret; + } else if (ret < 0) { + if (ret != AVERROR_EOF) + av_log(c->ctx, AV_LOG_WARNING, + "keepalive request failed for '%s', retrying with new connection: %s\n", + url, av_err2str(ret)); + in = NULL; + } + } + int start_seq_no = -1; if (!in) { -#if 1 AVDictionary *opts = NULL; - close_in = 1; + + av_dict_copy(&opts, c->avio_opts, 0); + /* Some HLS servers don't like being sent the range header */ av_dict_set(&opts, "seekable", "0", 0); @@ -696,22 +758,24 @@ static int parse_playlist(HLSContext *c, const char *url, av_dict_set(&opts, "headers", c->headers, 0); av_dict_set(&opts, "http_proxy", c->http_proxy, 0); + if (c->http_persistent) + av_dict_set(&opts, "multiple_requests", "1", 0); + ret = c->ctx->io_open(c->ctx, &in, url, AVIO_FLAG_READ, &opts); av_dict_free(&opts); if (ret < 0) return ret; -#else - ret = open_in(c, &in, url); - if (ret < 0) - return ret; - close_in = 1; -#endif + + if (is_http && c->http_persistent) + c->playlist_pb = in; + else + close_in = 1; } if (av_opt_get(in, "location", AV_OPT_SEARCH_CHILDREN, &new_url) >= 0) url = new_url; - read_chomp_line(in, line, sizeof(line)); + ff_get_chomp_line(in, line, sizeof(line)); if (strcmp(line, "#EXTM3U")) { ret = AVERROR_INVALIDDATA; goto fail; @@ -723,7 +787,7 @@ static int parse_playlist(HLSContext *c, const char *url, pls->type = PLS_TYPE_UNSPECIFIED; } while (!avio_feof(in)) { - read_chomp_line(in, line, sizeof(line)); + ff_get_chomp_line(in, line, sizeof(line)); if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) { is_variant = 1; memset(&variant_info, 0, sizeof(variant_info)); @@ -758,7 +822,11 @@ static int parse_playlist(HLSContext *c, const char *url, ret = ensure_playlist(c, &pls, url); if (ret < 0) goto fail; - pls->start_seq_no = atoi(ptr); + /* Some buggy HLS servers write #EXT-X-MEDIA-SEQUENCE more than once */ + if (start_seq_no < 0) { + start_seq_no = atoi(ptr); + pls->start_seq_no = start_seq_no; + } } else if (av_strstart(line, "#EXT-X-PLAYLIST-TYPE:", &ptr)) { ret = ensure_playlist(c, &pls, url); if (ret < 0) @@ -778,6 +846,8 @@ static int parse_playlist(HLSContext *c, const char *url, } else if (av_strstart(line, "#EXT-X-ENDLIST", &ptr)) { if (pls) pls->finished = 1; + } else if (av_strstart(line, "#EXT-X-DISCONTINUITY", &ptr)) { + previous_duration = previous_duration1; } else if (av_strstart(line, "#EXTINF:", &ptr)) { is_segment = 1; duration = atof(ptr) * AV_TIME_BASE; @@ -810,6 +880,10 @@ static int parse_playlist(HLSContext *c, const char *url, ret = AVERROR(ENOMEM); goto fail; } + previous_duration1 += duration; + seg->previous_duration = previous_duration; + seg->start_time = total_duration; + total_duration += duration; seg->duration = duration; seg->key_type = key_type; if (has_iv) { @@ -833,7 +907,22 @@ static int parse_playlist(HLSContext *c, const char *url, } ff_make_absolute_url(tmp_str, sizeof(tmp_str), url, line); - seg->url = av_strdup(tmp_str); + + if (c->hls_io_protocol_enable) { + char * url_start = NULL; + if (c->hls_io_protocol) { + strcpy(io_url, c->hls_io_protocol); + } else if ((url_start = strstr(url,"http://")) || + (url_start = strstr(url,"https://"))) { + strncpy(io_url, url, url_start - url); + } + av_strlcat(io_url, tmp_str, sizeof(io_url)); + seg->url = av_strdup(io_url); + memset(io_url, 0, sizeof(io_url)); + } else { + seg->url = av_strdup(tmp_str); + } + if (!seg->url) { av_free(seg->key); av_free(seg); @@ -865,6 +954,11 @@ static int parse_playlist(HLSContext *c, const char *url, av_free(new_url); if (close_in) ff_format_io_close(c->ctx, &in); + c->ctx->ctx_flags = c->ctx->ctx_flags & ~(unsigned)AVFMTCTX_UNSEEKABLE; + if (!c->n_variants || !c->variants[0]->n_playlists || + !(c->variants[0]->playlists[0]->finished || + c->variants[0]->playlists[0]->type == PLS_TYPE_EVENT)) + c->ctx->ctx_flags |= AVFMTCTX_UNSEEKABLE; return ret; } @@ -873,6 +967,14 @@ static struct segment *current_segment(struct playlist *pls) return pls->segments[pls->cur_seq_no - pls->start_seq_no]; } +static struct segment *next_segment(struct playlist *pls) +{ + int n = pls->cur_seq_no - pls->start_seq_no + 1; + if (n >= pls->n_segments) + return NULL; + return pls->segments[n]; +} + enum ReadFromURLMode { READ_NORMAL, READ_COMPLETE, @@ -983,6 +1085,7 @@ static void handle_id3(AVIOContext *pb, struct playlist *pls) /* demuxer not yet opened, defer picture attachment */ pls->id3_deferred_extra = extra_meta; + ff_id3v2_parse_priv_dict(&metadata, &extra_meta); av_dict_copy(&pls->ctx->metadata, metadata, 0); pls->id3_initial = metadata; @@ -1098,7 +1201,7 @@ static void intercept_id3(struct playlist *pls, uint8_t *buf, pls->is_id3_timestamped = (pls->id3_mpegts_timestamp != AV_NOPTS_VALUE); } -static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg) +static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg, AVIOContext **in) { AVDictionary *opts = NULL; int ret; @@ -1106,11 +1209,15 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg) // broker prior HTTP options that should be consistent across requests av_dict_set(&opts, "user_agent", c->user_agent, 0); + av_dict_set(&opts, "referer", c->referer, 0); av_dict_set(&opts, "cookies", c->cookies, 0); av_dict_set(&opts, "headers", c->headers, 0); av_dict_set(&opts, "http_proxy", c->http_proxy, 0); av_dict_set(&opts, "seekable", "0", 0); + if (c->http_persistent) + av_dict_set(&opts, "multiple_requests", "1", 0); + if (seg->size >= 0) { /* try to restrict the HTTP request to the part we want * (if this is in fact a HTTP request) */ @@ -1122,12 +1229,12 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg) seg->url, seg->url_offset, pls->index); if (seg->key_type == KEY_NONE) { - ret = open_url(pls->parent, &pls->input, seg->url, c->avio_opts, opts, &is_http); + ret = open_url(pls->parent, in, seg->url, c->avio_opts, opts, &is_http); } else if (seg->key_type == KEY_AES_128) { AVDictionary *opts2 = NULL; char iv[33], key[33], url[MAX_URL_SIZE]; if (strcmp(seg->key, pls->key_url)) { - AVIOContext *pb; + AVIOContext *pb = NULL; if (open_url(pls->parent, &pb, seg->key, c->avio_opts, opts, NULL) == 0) { ret = avio_read(pb, pls->key, sizeof(pls->key)); if (ret != sizeof(pls->key)) { @@ -1153,7 +1260,7 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg) av_dict_set(&opts2, "key", key, 0); av_dict_set(&opts2, "iv", iv, 0); - ret = open_url(pls->parent, &pls->input, url, opts2, opts, &is_http); + ret = open_url(pls->parent, in, url, opts2, opts, &is_http); av_dict_free(&opts2); @@ -1180,11 +1287,11 @@ static int open_input(HLSContext *c, struct playlist *pls, struct segment *seg) * noticed without the call, though. */ if (ret == 0 && !is_http && seg->key_type == KEY_NONE && seg->url_offset) { - int64_t seekret = avio_seek(pls->input, seg->url_offset, SEEK_SET); + int64_t seekret = avio_seek(*in, seg->url_offset, SEEK_SET); if (seekret < 0) { av_log(pls->parent, AV_LOG_ERROR, "Unable to seek to offset %"PRId64" of HLS segment '%s'\n", seg->url_offset, seg->url); ret = seekret; - ff_format_io_close(pls->parent, &pls->input); + ff_format_io_close(pls->parent, in); } } @@ -1210,7 +1317,7 @@ static int update_init_section(struct playlist *pls, struct segment *seg) if (!seg->init_section) return 0; - ret = open_input(c, pls, seg->init_section); + ret = open_input(c, pls, seg->init_section, &pls->input); if (ret < 0) { av_log(pls->parent, AV_LOG_WARNING, "Failed to open an initialization section in playlist %d\n", @@ -1258,33 +1365,72 @@ static int64_t default_reload_interval(struct playlist *pls) pls->target_duration; } +static int playlist_needed(struct playlist *pls) +{ + AVFormatContext *s = pls->parent; + int i, j; + int stream_needed = 0; + int first_st; + + /* If there is no context or streams yet, the playlist is needed */ + if (!pls->ctx || !pls->n_main_streams) + return 1; + + /* check if any of the streams in the playlist are needed */ + for (i = 0; i < pls->n_main_streams; i++) { + if (pls->main_streams[i]->discard < AVDISCARD_ALL) { + stream_needed = 1; + break; + } + } + + /* If all streams in the playlist were discarded, the playlist is not + * needed (regardless of whether whole programs are discarded or not). */ + if (!stream_needed) + return 0; + + /* Otherwise, check if all the programs (variants) this playlist is in are + * discarded. Since all streams in the playlist are part of the same programs + * we can just check the programs of the first stream. */ + + first_st = pls->main_streams[0]->index; + + for (i = 0; i < s->nb_programs; i++) { + AVProgram *program = s->programs[i]; + if (program->discard < AVDISCARD_ALL) { + for (j = 0; j < program->nb_stream_indexes; j++) { + if (program->stream_index[j] == first_st) { + /* playlist is in an undiscarded program */ + return 1; + } + } + } + } + + /* some streams were not discarded but all the programs were */ + return 0; +} + static int read_data(void *opaque, uint8_t *buf, int buf_size) { struct playlist *v = opaque; HLSContext *c = v->parent->priv_data; - int ret, i; + int ret; int just_opened = 0; int reload_count = 0; + struct segment *seg; restart: if (!v->needed) return AVERROR_EOF; - if (!v->input) { + if (!v->input || (c->http_persistent && v->input_read_done)) { int64_t reload_interval; - struct segment *seg; /* Check that the playlist is still needed before opening a new * segment. */ - if (v->ctx && v->ctx->nb_streams) { - v->needed = 0; - for (i = 0; i < v->n_main_streams; i++) { - if (v->main_streams[i]->discard < AVDISCARD_ALL) { - v->needed = 1; - break; - } - } - } + v->needed = playlist_needed(v); + if (!v->needed) { av_log(v->parent, AV_LOG_INFO, "No longer receiving playlist %d\n", v->index); @@ -1302,8 +1448,9 @@ static int read_data(void *opaque, uint8_t *buf, int buf_size) if (!v->finished && av_gettime_relative() - v->last_load_time >= reload_interval) { if ((ret = parse_playlist(c, v->url, v, NULL)) < 0) { - av_log(v->parent, AV_LOG_WARNING, "Failed to reload playlist %d\n", - v->index); + if (ret != AVERROR_EXIT) + av_log(v->parent, AV_LOG_WARNING, "Failed to reload playlist %d\n", + v->index); return ret; } /* If we need to reload the playlist again below (if @@ -1329,6 +1476,7 @@ static int read_data(void *opaque, uint8_t *buf, int buf_size) goto reload; } + v->input_read_done = 0; seg = current_segment(v); /* load/update Media Initialization Section, if any */ @@ -1336,18 +1484,55 @@ static int read_data(void *opaque, uint8_t *buf, int buf_size) if (ret) return ret; - ret = open_input(c, v, seg); + if (c->http_multiple == 1 && v->input_next_requested) { + FFSWAP(AVIOContext *, v->input, v->input_next); + v->input_next_requested = 0; + ret = 0; + } else { + ret = open_input(c, v, seg, &v->input); + } if (ret < 0) { if (ff_check_interrupt(c->interrupt_callback)) return AVERROR_EXIT; - av_log(v->parent, AV_LOG_WARNING, "Failed to open segment of playlist %d\n", + av_log(v->parent, AV_LOG_WARNING, "Failed to open segment %d of playlist %d\n", + v->cur_seq_no, v->index); - v->cur_seq_no += 1; + + if (c->hls_io_protocol_enable && (parse_playlist(c, v->url, v, NULL)) < 0) { + av_log(NULL, AV_LOG_INFO, "Failed to reload playlist %d\n", + v->index); + } else { + v->cur_seq_no += 1; + } goto reload; } just_opened = 1; } + if (c->http_multiple == -1) { + uint8_t *http_version_opt = NULL; + int r = av_opt_get(v->input, "http_version", AV_OPT_SEARCH_CHILDREN, &http_version_opt); + if (r >= 0) { + c->http_multiple = strncmp((const char *)http_version_opt, "1.1", 3) == 0; + av_freep(&http_version_opt); + } + } + + seg = next_segment(v); + if (c->http_multiple == 1 && !v->input_next_requested && + seg && seg->key_type == KEY_NONE && av_strstart(seg->url, "http", NULL)) { + ret = open_input(c, v, seg, &v->input_next); + if (ret < 0) { + if (ff_check_interrupt(c->interrupt_callback)) + return AVERROR_EXIT; + av_log(v->parent, AV_LOG_WARNING, "Failed to open segment %d of playlist %d\n", + v->cur_seq_no + 1, + v->index); + } else { + v->input_next_requested = 1; + } + } + if (v->init_sec_buf_read_offset < v->init_sec_data_len) { /* Push init section out first before first actual segment */ int copy_size = FFMIN(v->init_sec_data_len - v->init_sec_buf_read_offset, buf_size); @@ -1356,7 +1541,8 @@ static int read_data(void *opaque, uint8_t *buf, int buf_size) return copy_size; } - ret = read_from_url(v, current_segment(v), buf, buf_size, READ_NORMAL); + seg = current_segment(v); + ret = read_from_url(v, seg, buf, buf_size, READ_NORMAL); if (ret > 0) { if (just_opened && v->is_id3_timestamped != 0) { /* Intercept ID3 tags here, elementary audio streams are required @@ -1366,7 +1552,12 @@ static int read_data(void *opaque, uint8_t *buf, int buf_size) return ret; } - ff_format_io_close(v->parent, &v->input); + if (c->http_persistent && + seg->key_type == KEY_NONE && av_strstart(seg->url, "http", NULL)) { + v->input_read_done = 1; + } else { + ff_format_io_close(v->parent, &v->input); + } v->cur_seq_no++; c->cur_seq_no = v->cur_seq_no; @@ -1499,7 +1690,7 @@ static int save_avio_options(AVFormatContext *s) { HLSContext *c = s->priv_data; static const char * const opts[] = { - "headers", "http_proxy", "user_agent", "user-agent", "cookies", NULL }; + "headers", "http_proxy", "user_agent", "user-agent", "cookies", "referer", NULL }; const char * const * opt = opts; uint8_t *buf; int ret = 0; @@ -1523,7 +1714,7 @@ static int nested_io_open(AVFormatContext *s, AVIOContext **pb, const char *url, av_log(s, AV_LOG_ERROR, "A HLS playlist item '%s' referred to an external file '%s'. " "Opening this file was forbidden for security reasons\n", - s->filename, url); + s->url, url); return AVERROR(EPERM); } @@ -1627,11 +1818,12 @@ static int hls_close(AVFormatContext *s) free_rendition_list(c); av_dict_free(&c->avio_opts); + ff_format_io_close(c->ctx, &c->playlist_pb); return 0; } -static int hls_read_header(AVFormatContext *s) +static int hls_read_header(AVFormatContext *s, AVDictionary **options) { void *u = (s->flags & AVFMT_FLAG_CUSTOM_IO) ? NULL : s->pb; HLSContext *c = s->priv_data; @@ -1646,6 +1838,9 @@ static int hls_read_header(AVFormatContext *s) c->first_timestamp = AV_NOPTS_VALUE; c->cur_timestamp = AV_NOPTS_VALUE; + if (options && *options) + av_dict_copy(&c->avio_opts, *options, 0); + if (u) { // get the previous user agent & set back to null if string size is zero update_options(&c->user_agent, "user_agent", u); @@ -1660,7 +1855,7 @@ static int hls_read_header(AVFormatContext *s) update_options(&c->http_proxy, "http_proxy", u); } - if ((ret = parse_playlist(c, s->filename, NULL, s->pb)) < 0) + if ((ret = parse_playlist(c, s->url, NULL, s->pb)) < 0) goto fail; if ((ret = save_avio_options(s)) < 0) @@ -1798,6 +1993,7 @@ static int hls_read_header(AVFormatContext *s) if (pls->id3_deferred_extra && pls->ctx->nb_streams == 1) { ff_id3v2_parse_apic(pls->ctx, &pls->id3_deferred_extra); avformat_queue_attached_pictures(pls->ctx); + ff_id3v2_parse_priv(pls->ctx, &pls->id3_deferred_extra); ff_id3v2_free_extra_meta(&pls->id3_deferred_extra); pls->id3_deferred_extra = NULL; } @@ -1824,6 +2020,13 @@ static int hls_read_header(AVFormatContext *s) if (ret < 0) goto fail; + /* + * Copy any metadata from playlist to main streams, but do not set + * event flags. + */ + if (pls->n_main_streams) + av_dict_copy(&pls->main_streams[0]->metadata, pls->ctx->metadata, 0); + add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_AUDIO); add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_VIDEO); add_metadata_from_renditions(s, pls, AVMEDIA_TYPE_SUBTITLE); @@ -1841,20 +2044,15 @@ static int recheck_discard_flags(AVFormatContext *s, int first) { HLSContext *c = s->priv_data; int i, changed = 0; + int cur_needed; /* Check if any new streams are needed */ - for (i = 0; i < c->n_playlists; i++) - c->playlists[i]->cur_needed = 0; - - for (i = 0; i < s->nb_streams; i++) { - AVStream *st = s->streams[i]; - struct playlist *pls = c->playlists[s->streams[i]->id]; - if (st->discard < AVDISCARD_ALL) - pls->cur_needed = 1; - } for (i = 0; i < c->n_playlists; i++) { struct playlist *pls = c->playlists[i]; - if (pls->cur_needed && !pls->needed) { + + cur_needed = playlist_needed(c->playlists[i]); + + if (cur_needed && !pls->needed) { pls->needed = 1; changed = 1; pls->cur_seq_no = select_cur_seq_no(c, pls); @@ -1866,9 +2064,13 @@ static int recheck_discard_flags(AVFormatContext *s, int first) pls->seek_stream_index = -1; } av_log(s, AV_LOG_INFO, "Now receiving playlist %d, segment %d\n", i, pls->cur_seq_no); - } else if (first && !pls->cur_needed && pls->needed) { + } else if (first && !cur_needed && pls->needed) { if (pls->input) ff_format_io_close(pls->parent, &pls->input); + pls->input_read_done = 0; + if (pls->input_next) + ff_format_io_close(pls->parent, &pls->input_next); + pls->input_next_requested = 0; pls->needed = 0; changed = 1; av_log(s, AV_LOG_INFO, "No longer receiving playlist %d\n", i); @@ -1933,12 +2135,20 @@ static int hls_read_packet(AVFormatContext *s, AVPacket *pkt) * stream */ if (pls->needed && !pls->pkt.data) { while (1) { + int64_t pkt_ts; int64_t ts_diff; AVRational tb; ret = av_read_frame(pls->ctx, &pls->pkt); if (ret < 0) { - if (!avio_feof(&pls->pb) && ret != AVERROR_EOF) + //when error occur try to renew m3u8 + if (c->hls_io_protocol_enable && (parse_playlist(c, pls->url, pls, NULL)) < 0) { + av_log(NULL, AV_LOG_INFO, "Failed to reload playlist %d\n", + pls->index); + } + + if (!avio_feof(&pls->pb) && ret != AVERROR_EOF) { return ret; + } reset_packet(&pls->pkt); break; } else { @@ -1948,10 +2158,16 @@ static int hls_read_packet(AVFormatContext *s, AVPacket *pkt) fill_timing_for_id3_timestamped_stream(pls); } - if (c->first_timestamp == AV_NOPTS_VALUE && - pls->pkt.dts != AV_NOPTS_VALUE) - c->first_timestamp = av_rescale_q(pls->pkt.dts, - get_timebase(pls), AV_TIME_BASE_Q); + if (pls->pkt.pts != AV_NOPTS_VALUE) + pkt_ts = pls->pkt.pts; + else if (pls->pkt.dts != AV_NOPTS_VALUE) + pkt_ts = pls->pkt.dts; + else + pkt_ts = AV_NOPTS_VALUE; + + + c->first_timestamp = s->start_time != AV_NOPTS_VALUE ? s->start_time : 0; + } if (pls->seek_timestamp == AV_NOPTS_VALUE) @@ -1960,15 +2176,16 @@ static int hls_read_packet(AVFormatContext *s, AVPacket *pkt) if (pls->seek_stream_index < 0 || pls->seek_stream_index == pls->pkt.stream_index) { - if (pls->pkt.dts == AV_NOPTS_VALUE) { + if (pkt_ts == AV_NOPTS_VALUE) { pls->seek_timestamp = AV_NOPTS_VALUE; break; } tb = get_timebase(pls); - ts_diff = av_rescale_rnd(pls->pkt.dts, AV_TIME_BASE, + ts_diff = av_rescale_rnd(pkt_ts, AV_TIME_BASE, tb.den, AV_ROUND_DOWN) - pls->seek_timestamp; + if (ts_diff >= 0 && (pls->seek_flags & AVSEEK_FLAG_ANY || pls->pkt.flags & AV_PKT_FLAG_KEY)) { pls->seek_timestamp = AV_NOPTS_VALUE; @@ -2009,6 +2226,17 @@ static int hls_read_packet(AVFormatContext *s, AVPacket *pkt) return ret; } + // If sub-demuxer reports updated metadata, copy it to the first stream + // and set its AVSTREAM_EVENT_FLAG_METADATA_UPDATED flag. + if (pls->ctx->event_flags & AVFMT_EVENT_FLAG_METADATA_UPDATED) { + if (pls->n_main_streams) { + st = pls->main_streams[0]; + av_dict_copy(&st->metadata, pls->ctx->metadata, 0); + st->event_flags |= AVSTREAM_EVENT_FLAG_METADATA_UPDATED; + } + pls->ctx->event_flags &= ~AVFMT_EVENT_FLAG_METADATA_UPDATED; + } + /* check if noheader flag has been cleared by the subdemuxer */ if (pls->has_noheader_flag && !(pls->ctx->ctx_flags & AVFMTCTX_NOHEADER)) { pls->has_noheader_flag = 0; @@ -2045,6 +2273,28 @@ static int hls_read_packet(AVFormatContext *s, AVPacket *pkt) } } + if (c->playlists[minplaylist]->finished) { + struct playlist *pls = c->playlists[minplaylist]; + int seq_no = pls->cur_seq_no - pls->start_seq_no; + if (seq_no < pls->n_segments && s->streams[pkt->stream_index]) { + struct segment *seg = pls->segments[seq_no]; + int64_t pred = av_rescale_q(seg->previous_duration, + AV_TIME_BASE_Q, + s->streams[pkt->stream_index]->time_base); + int64_t max_ts = av_rescale_q(seg->start_time + seg->duration, + AV_TIME_BASE_Q, + s->streams[pkt->stream_index]->time_base); + /* EXTINF duration is not precise enough */ + max_ts += 2 * AV_TIME_BASE; + if (s->start_time > 0) { + max_ts += av_rescale_q(s->start_time, + AV_TIME_BASE_Q, + s->streams[pkt->stream_index]->time_base); + } + if (pkt->dts != AV_NOPTS_VALUE && pkt->dts + pred < max_ts) pkt->dts += pred; + if (pkt->pts != AV_NOPTS_VALUE && pkt->pts + pred < max_ts) pkt->pts += pred; + } + } return 0; } return AVERROR_EOF; @@ -2060,8 +2310,7 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, int stream_subdemuxer_index; int64_t first_timestamp, seek_timestamp, duration; - if ((flags & AVSEEK_FLAG_BYTE) || - !(c->variants[0]->playlists[0]->finished || c->variants[0]->playlists[0]->type == PLS_TYPE_EVENT)) + if ((flags & AVSEEK_FLAG_BYTE) || (c->ctx->ctx_flags & AVFMTCTX_UNSEEKABLE)) return AVERROR(ENOSYS); first_timestamp = c->first_timestamp == AV_NOPTS_VALUE ? @@ -2103,6 +2352,10 @@ static int hls_read_seek(AVFormatContext *s, int stream_index, struct playlist *pls = c->playlists[i]; if (pls->input) ff_format_io_close(pls->parent, &pls->input); + pls->input_read_done = 0; + if (pls->input_next) + ff_format_io_close(pls->parent, &pls->input_next); + pls->input_next_requested = 0; av_packet_unref(&pls->pkt); reset_packet(&pls->pkt); pls->pb.eof_reached = 0; @@ -2157,6 +2410,14 @@ static const AVOption hls_options[] = { INT_MIN, INT_MAX, FLAGS}, {"max_reload", "Maximum number of times a insufficient list is attempted to be reloaded", OFFSET(max_reload), AV_OPT_TYPE_INT, {.i64 = 1000}, 0, INT_MAX, FLAGS}, + {"http_persistent", "Use persistent HTTP connections", + OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, FLAGS }, + {"http_multiple", "Use multiple HTTP connections for fetching segments", + OFFSET(http_multiple), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, FLAGS}, + {"hls_io_protocol", "force segment io protocol", + OFFSET(hls_io_protocol), AV_OPT_TYPE_STRING, {.str= NULL}, 0, 0, FLAGS}, + {"hls_io_protocol_enable", "enable auto copy segment io protocol from playlist", + OFFSET(hls_io_protocol_enable), AV_OPT_TYPE_BOOL, {.i64= 0}, 0, 1, FLAGS}, {NULL} }; @@ -2172,8 +2433,9 @@ AVInputFormat ff_hls_demuxer = { .long_name = NULL_IF_CONFIG_SMALL("Apple HTTP Live Streaming"), .priv_class = &hls_class, .priv_data_size = sizeof(HLSContext), + .flags = AVFMT_NOGENSEARCH, .read_probe = hls_probe, - .read_header = hls_read_header, + .read_header2 = hls_read_header, .read_packet = hls_read_packet, .read_close = hls_close, .read_seek = hls_read_seek, diff --git a/libavformat/hlsenc.c b/libavformat/hlsenc.c index 418f153c6f99f..c27a66ea795b0 100644 --- a/libavformat/hlsenc.c +++ b/libavformat/hlsenc.c @@ -1,6 +1,7 @@ /* * Apple HTTP Live Streaming segmenter * Copyright (c) 2012, Luca Barbato + * Copyright (c) 2017 Akamai Technologies, Inc. * * This file is part of FFmpeg. * @@ -44,6 +45,10 @@ #include "avformat.h" #include "avio_internal.h" +#if CONFIG_HTTP_PROTOCOL +#include "http.h" +#endif +#include "hlsplaylist.h" #include "internal.h" #include "os_support.h" @@ -53,9 +58,15 @@ typedef enum { HLS_START_SEQUENCE_AS_FORMATTED_DATETIME = 2, // YYYYMMDDhhmmss } StartSequenceSourceType; +typedef enum { + CODEC_ATTRIBUTE_WRITTEN = 0, + CODEC_ATTRIBUTE_WILL_NOT_BE_WRITTEN, +} CodecAttributeStatus; + #define KEYSIZE 16 #define LINE_BUFFER_SIZE 1024 #define HLS_MICROSECOND_UNIT 1000000 +#define POSTFIX_PATTERN "_%d" typedef struct HLSSegment { char filename[1024]; @@ -64,6 +75,7 @@ typedef struct HLSSegment { int discont; int64_t pos; int64_t size; + unsigned var_stream_idx; char key_uri[LINE_BUFFER_SIZE + 1]; char iv_string[KEYSIZE*2 + 1]; @@ -86,6 +98,7 @@ typedef enum HLSFlags { HLS_SECOND_LEVEL_SEGMENT_SIZE = (1 << 10), // include segment size (bytes) in segment filenames when use_localtime e.g.: %%014s HLS_TEMP_FILE = (1 << 11), HLS_PERIODIC_REKEY = (1 << 12), + HLS_INDEPENDENT_SEGMENTS = (1 << 13), } HLSFlags; typedef enum { @@ -93,42 +106,19 @@ typedef enum { SEGMENT_TYPE_FMP4, } SegmentType; -typedef enum { - PLAYLIST_TYPE_NONE, - PLAYLIST_TYPE_EVENT, - PLAYLIST_TYPE_VOD, - PLAYLIST_TYPE_NB, -} PlaylistType; - -typedef struct HLSContext { - const AVClass *class; // Class for private options. +typedef struct VariantStream { + unsigned var_stream_idx; unsigned number; int64_t sequence; - int64_t start_sequence; - uint32_t start_sequence_source_type; // enum StartSequenceSourceType AVOutputFormat *oformat; AVOutputFormat *vtt_oformat; + AVIOContext *out; + int packets_written; + int init_range_length; AVFormatContext *avf; AVFormatContext *vtt_avf; - float time; // Set by a private option. - float init_time; // Set by a private option. - int max_nb_segments; // Set by a private option. -#if FF_API_HLS_WRAP - int wrap; // Set by a private option. -#endif - uint32_t flags; // enum HLSFlags - uint32_t pl_type; // enum PlaylistType - char *segment_filename; - char *fmp4_init_filename; - int segment_type; - int fmp4_init_mode; - - int use_localtime; ///< flag to expand filename with localtime - int use_localtime_mkdir;///< flag to mkdir dirname in timebased filename - int allowcache; - int64_t recording_time; int has_video; int has_subtitle; int new_start; @@ -138,19 +128,67 @@ typedef struct HLSContext { double duration; // last segment duration computed so far, in seconds int64_t start_pos; // last segment starting position int64_t size; // last segment size - int64_t max_seg_size; // every segment file max size int nb_entries; int discontinuity_set; int discontinuity; + int reference_stream_index; HLSSegment *segments; HLSSegment *last_segment; HLSSegment *old_segments; char *basename; - char *base_output_dirname; char *vtt_basename; char *vtt_m3u8_name; + char *m3u8_name; + + double initial_prog_date_time; + char current_segment_final_filename_fmt[1024]; // when renaming segments + + char *fmp4_init_filename; + char *base_output_dirname; + int fmp4_init_mode; + + AVStream **streams; + char codec_attr[128]; + CodecAttributeStatus attr_status; + unsigned int nb_streams; + int m3u8_created; /* status of media play-list creation */ + char *agroup; /* audio group name */ + char *ccgroup; /* closed caption group name */ + char *baseurl; +} VariantStream; + +typedef struct ClosedCaptionsStream { + char *ccgroup; /* closed caption group name */ + char *instreamid; /* closed captions INSTREAM-ID */ + char *language; /* closed captions langauge */ +} ClosedCaptionsStream; + +typedef struct HLSContext { + const AVClass *class; // Class for private options. + int64_t start_sequence; + uint32_t start_sequence_source_type; // enum StartSequenceSourceType + + float time; // Set by a private option. + float init_time; // Set by a private option. + int max_nb_segments; // Set by a private option. + int hls_delete_threshold; // Set by a private option. +#if FF_API_HLS_WRAP + int wrap; // Set by a private option. +#endif + uint32_t flags; // enum HLSFlags + uint32_t pl_type; // enum PlaylistType + char *segment_filename; + char *fmp4_init_filename; + int segment_type; + + int use_localtime; ///< flag to expand filename with localtime + int use_localtime_mkdir;///< flag to mkdir dirname in timebased filename + int allowcache; + int64_t recording_time; + int64_t max_seg_size; // every segment file max size + char *baseurl; char *format_options_str; char *vtt_format_options_str; @@ -162,6 +200,7 @@ typedef struct HLSContext { char *key_url; char *iv; char *key_basename; + int encrypt_started; char *key_info_file; char key_file[LINE_BUFFER_SIZE + 1]; @@ -171,16 +210,25 @@ typedef struct HLSContext { AVDictionary *vtt_format_options; char *method; - - double initial_prog_date_time; - char current_segment_final_filename_fmt[1024]; // when renaming segments char *user_agent; -} HLSContext; -static int get_int_from_double(double val) -{ - return (int)((val - (int)val) >= 0.001) ? (int)(val + 1) : (int)val; -} + VariantStream *var_streams; + unsigned int nb_varstreams; + ClosedCaptionsStream *cc_streams; + unsigned int nb_ccstreams; + + int master_m3u8_created; /* status of master play-list creation */ + char *master_m3u8_url; /* URL of the master m3u8 file */ + int version; /* HLS version */ + char *var_stream_map; /* user specified variant stream map string */ + char *cc_stream_map; /* user specified closed caption streams map string */ + char *master_pl_name; + unsigned int master_publish_rate; + int http_persistent; + AVIOContext *m3u8_out; + AVIOContext *sub_m3u8_out; + int64_t timeout; +} HLSContext; static int mkdir_p(const char *path) { int ret = 0; @@ -215,10 +263,41 @@ static int mkdir_p(const char *path) { return ret; } +static int hlsenc_io_open(AVFormatContext *s, AVIOContext **pb, char *filename, + AVDictionary **options) { + HLSContext *hls = s->priv_data; + int http_base_proto = filename ? ff_is_http_proto(filename) : 0; + int err = AVERROR_MUXER_NOT_FOUND; + if (!*pb || !http_base_proto || !hls->http_persistent) { + err = s->io_open(s, pb, filename, AVIO_FLAG_WRITE, options); +#if CONFIG_HTTP_PROTOCOL + } else { + URLContext *http_url_context = ffio_geturlcontext(*pb); + av_assert0(http_url_context); + err = ff_http_do_new_request(http_url_context, filename); +#endif + } + return err; +} + +static void hlsenc_io_close(AVFormatContext *s, AVIOContext **pb, char *filename) { + HLSContext *hls = s->priv_data; + int http_base_proto = filename ? ff_is_http_proto(filename) : 0; + if (!http_base_proto || !hls->http_persistent || hls->key_info_file || hls->encrypt) { + ff_format_io_close(s, pb); +#if CONFIG_HTTP_PROTOCOL + } else { + URLContext *http_url_context = ffio_geturlcontext(*pb); + av_assert0(http_url_context); + avio_flush(*pb); + ffurl_shutdown(http_url_context, AVIO_FLAG_WRITE); +#endif + } +} + static void set_http_options(AVFormatContext *s, AVDictionary **options, HLSContext *c) { - const char *proto = avio_find_protocol_name(s->filename); - int http_base_proto = proto ? (!av_strcasecmp(proto, "http") || !av_strcasecmp(proto, "https")) : 0; + int http_base_proto = ff_is_http_proto(s->url); if (c->method) { av_dict_set(options, "method", c->method, 0); @@ -228,17 +307,68 @@ static void set_http_options(AVFormatContext *s, AVDictionary **options, HLSCont } if (c->user_agent) av_dict_set(options, "user_agent", c->user_agent, 0); + if (c->http_persistent) + av_dict_set_int(options, "multiple_requests", 1, 0); + if (c->timeout >= 0) + av_dict_set_int(options, "timeout", c->timeout, 0); +} + +static void write_codec_attr(AVStream *st, VariantStream *vs) { + int codec_strlen = strlen(vs->codec_attr); + char attr[32]; + + if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) + return; + if (vs->attr_status == CODEC_ATTRIBUTE_WILL_NOT_BE_WRITTEN) + return; + + if (st->codecpar->codec_id == AV_CODEC_ID_H264) { + uint8_t *data = st->codecpar->extradata; + if (data && (data[0] | data[1] | data[2]) == 0 && data[3] == 1 && (data[4] & 0x1F) == 7) { + snprintf(attr, sizeof(attr), + "avc1.%02x%02x%02x", data[5], data[6], data[7]); + } else { + goto fail; + } + } else if (st->codecpar->codec_id == AV_CODEC_ID_MP2) { + snprintf(attr, sizeof(attr), "mp4a.40.33"); + } else if (st->codecpar->codec_id == AV_CODEC_ID_MP3) { + snprintf(attr, sizeof(attr), "mp4a.40.34"); + } else if (st->codecpar->codec_id == AV_CODEC_ID_AAC) { + /* TODO : For HE-AAC, HE-AACv2, the last digit needs to be set to 5 and 29 respectively */ + snprintf(attr, sizeof(attr), "mp4a.40.2"); + } else if (st->codecpar->codec_id == AV_CODEC_ID_AC3) { + snprintf(attr, sizeof(attr), "ac-3"); + } else if (st->codecpar->codec_id == AV_CODEC_ID_EAC3) { + snprintf(attr, sizeof(attr), "ec-3"); + } else { + goto fail; + } + // Don't write the same attribute multiple times + if (!av_stristr(vs->codec_attr, attr)) { + snprintf(vs->codec_attr + codec_strlen, + sizeof(vs->codec_attr) - codec_strlen, + "%s%s", codec_strlen ? "," : "", attr); + } + return; +fail: + vs->codec_attr[0] = '\0'; + vs->attr_status = CODEC_ATTRIBUTE_WILL_NOT_BE_WRITTEN; + return; } -static int replace_int_data_in_filename(char *buf, int buf_size, const char *filename, char placeholder, int64_t number) +static int replace_int_data_in_filename(char **s, const char *filename, char placeholder, int64_t number) { const char *p; - char *q, buf1[20], c; - int nd, len, addchar_count; + char *new_filename; + char c; + int nd, addchar_count; int found_count = 0; + AVBPrint buf; + + av_bprint_init(&buf, 0, AV_BPRINT_SIZE_UNLIMITED); - q = buf; p = filename; for (;;) { c = *p; @@ -255,13 +385,7 @@ static int replace_int_data_in_filename(char *buf, int buf_size, const char *fil } if (*(p + addchar_count) == placeholder) { - len = snprintf(buf1, sizeof(buf1), "%0*"PRId64, (number < 0) ? nd : nd++, number); - if (len < 1) // returned error or empty buf1 - goto fail; - if ((q - buf + len) > buf_size - 1) - goto fail; - memcpy(q, buf1, len); - q += len; + av_bprintf(&buf, "%0*"PRId64, (number < 0) ? nd : nd++, number); p += (addchar_count + 1); addchar_count = 0; found_count++; @@ -270,17 +394,17 @@ static int replace_int_data_in_filename(char *buf, int buf_size, const char *fil } else addchar_count = 1; - while (addchar_count--) - if ((q - buf) < buf_size - 1) - *q++ = *p++; - else - goto fail; + av_bprint_append_data(&buf, p, addchar_count); + p += addchar_count; + } + if (!av_bprint_is_complete(&buf)) { + av_bprint_finalize(&buf, NULL); + return -1; } - *q = '\0'; + if (av_bprint_finalize(&buf, &new_filename) < 0 || !new_filename) + return -1; + *s = new_filename; return found_count; -fail: - *q = '\0'; - return -1; } static void write_styp(AVIOContext *pb) @@ -293,39 +417,70 @@ static void write_styp(AVIOContext *pb) ffio_wfourcc(pb, "msix"); } -static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls) { +static int flush_dynbuf(VariantStream *vs, int *range_length) +{ + AVFormatContext *ctx = vs->avf; + uint8_t *buffer; + + if (!ctx->pb) { + return AVERROR(EINVAL); + } + + // flush + av_write_frame(ctx, NULL); + avio_flush(ctx->pb); + + // write out to file + *range_length = avio_close_dyn_buf(ctx->pb, &buffer); + ctx->pb = NULL; + avio_write(vs->out, buffer, *range_length); + av_free(buffer); + + // re-open buffer + return avio_open_dyn_buf(&ctx->pb); +} + +static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls, + VariantStream *vs) { HLSSegment *segment, *previous_segment = NULL; float playlist_duration = 0.0f; int ret = 0, path_size, sub_path_size; + int segment_cnt = 0; char *dirname = NULL, *p, *sub_path; char *path = NULL; AVDictionary *options = NULL; AVIOContext *out = NULL; const char *proto = NULL; - segment = hls->segments; + segment = vs->segments; while (segment) { playlist_duration += segment->duration; segment = segment->next; } - segment = hls->old_segments; + segment = vs->old_segments; + segment_cnt = 0; while (segment) { playlist_duration -= segment->duration; previous_segment = segment; segment = previous_segment->next; + segment_cnt++; if (playlist_duration <= -previous_segment->duration) { previous_segment->next = NULL; break; } + if (segment_cnt >= hls->hls_delete_threshold) { + previous_segment->next = NULL; + break; + } } if (segment && !hls->use_localtime_mkdir) { if (hls->segment_filename) { dirname = av_strdup(hls->segment_filename); } else { - dirname = av_strdup(hls->avf->filename); + dirname = av_strdup(vs->avf->url); } if (!dirname) { ret = AVERROR(ENOMEM); @@ -333,9 +488,23 @@ static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls) { } p = (char *)av_basename(dirname); *p = '\0'; + } while (segment) { + char * r_dirname = dirname; + + /* if %v is present in the file's directory */ + if (av_stristr(dirname, "%v")) { + + if (replace_int_data_in_filename(&r_dirname, dirname, 'v', segment->var_stream_idx) < 1) { + ret = AVERROR(EINVAL); + goto fail; + } + av_free(dirname); + dirname = r_dirname; + } + av_log(hls, AV_LOG_DEBUG, "deleting old segment %s\n", segment->filename); path_size = (hls->use_localtime_mkdir ? 0 : strlen(dirname)) + strlen(segment->filename) + 1; @@ -352,12 +521,12 @@ static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls) { av_strlcat(path, segment->filename, path_size); } - proto = avio_find_protocol_name(s->filename); + proto = avio_find_protocol_name(s->url); if (hls->method || (proto && !av_strcasecmp(proto, "http"))) { av_dict_set(&options, "method", "DELETE", 0); - if ((ret = hls->avf->io_open(hls->avf, &out, path, AVIO_FLAG_WRITE, &options)) < 0) + if ((ret = vs->avf->io_open(vs->avf, &out, path, AVIO_FLAG_WRITE, &options)) < 0) goto fail; - ff_format_io_close(hls->avf, &out); + ff_format_io_close(vs->avf, &out); } else if (unlink(path) < 0) { av_log(hls, AV_LOG_ERROR, "failed to delete old segment %s: %s\n", path, strerror(errno)); @@ -376,11 +545,11 @@ static int hls_delete_old_segments(AVFormatContext *s, HLSContext *hls) { if (hls->method || (proto && !av_strcasecmp(proto, "http"))) { av_dict_set(&options, "method", "DELETE", 0); - if ((ret = hls->avf->io_open(hls->avf, &out, sub_path, AVIO_FLAG_WRITE, &options)) < 0) { + if ((ret = vs->avf->io_open(vs->avf, &out, sub_path, AVIO_FLAG_WRITE, &options)) < 0) { av_free(sub_path); goto fail; } - ff_format_io_close(hls->avf, &out); + ff_format_io_close(vs->avf, &out); } else if (unlink(sub_path) < 0) { av_log(hls, AV_LOG_ERROR, "failed to delete old segment %s: %s\n", sub_path, strerror(errno)); @@ -414,7 +583,7 @@ static int randomize(uint8_t *buf, int len) return AVERROR(EINVAL); } -static int do_encrypt(AVFormatContext *s) +static int do_encrypt(AVFormatContext *s, VariantStream *vs) { HLSContext *hls = s->priv_data; int ret; @@ -422,12 +591,12 @@ static int do_encrypt(AVFormatContext *s) AVIOContext *pb; uint8_t key[KEYSIZE]; - len = strlen(hls->basename) + 4 + 1; + len = strlen(s->url) + 4 + 1; hls->key_basename = av_mallocz(len); if (!hls->key_basename) return AVERROR(ENOMEM); - av_strlcpy(hls->key_basename, s->filename, len); + av_strlcpy(hls->key_basename, s->url, len); av_strlcat(hls->key_basename, ".key", len); if (hls->key_url) { @@ -443,7 +612,7 @@ static int do_encrypt(AVFormatContext *s) char buf[33]; if (!hls->iv) { - AV_WB64(iv + 8, hls->sequence); + AV_WB64(iv + 8, vs->sequence); } else { memcpy(iv, hls->iv, sizeof(iv)); } @@ -535,15 +704,7 @@ static int hls_encryption_start(AVFormatContext *s) return 0; } -static int read_chomp_line(AVIOContext *s, char *buf, int maxlen) -{ - int len = ff_get_line(s, buf, maxlen); - while (len > 0 && av_isspace(buf[len - 1])) - buf[--len] = '\0'; - return len; -} - -static int hls_mux_init(AVFormatContext *s) +static int hls_mux_init(AVFormatContext *s, VariantStream *vs) { AVDictionary *options = NULL; HLSContext *hls = s->priv_data; @@ -552,13 +713,16 @@ static int hls_mux_init(AVFormatContext *s) int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0); int i, ret; - ret = avformat_alloc_output_context2(&hls->avf, hls->oformat, NULL, NULL); + ret = avformat_alloc_output_context2(&vs->avf, vs->oformat, NULL, NULL); if (ret < 0) return ret; - oc = hls->avf; + oc = vs->avf; + + oc->url = av_strdup(""); + if (!oc->url) + return AVERROR(ENOMEM); - oc->filename[0] = '\0'; - oc->oformat = hls->oformat; + oc->oformat = vs->oformat; oc->interrupt_callback = s->interrupt_callback; oc->max_delay = s->max_delay; oc->opaque = s->opaque; @@ -566,51 +730,65 @@ static int hls_mux_init(AVFormatContext *s) oc->io_close = s->io_close; av_dict_copy(&oc->metadata, s->metadata, 0); - if(hls->vtt_oformat) { - ret = avformat_alloc_output_context2(&hls->vtt_avf, hls->vtt_oformat, NULL, NULL); + if(vs->vtt_oformat) { + ret = avformat_alloc_output_context2(&vs->vtt_avf, vs->vtt_oformat, NULL, NULL); if (ret < 0) return ret; - vtt_oc = hls->vtt_avf; - vtt_oc->oformat = hls->vtt_oformat; + vtt_oc = vs->vtt_avf; + vtt_oc->oformat = vs->vtt_oformat; av_dict_copy(&vtt_oc->metadata, s->metadata, 0); } - for (i = 0; i < s->nb_streams; i++) { + for (i = 0; i < vs->nb_streams; i++) { AVStream *st; AVFormatContext *loc; - if (s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) + if (vs->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) loc = vtt_oc; else loc = oc; if (!(st = avformat_new_stream(loc, NULL))) return AVERROR(ENOMEM); - avcodec_parameters_copy(st->codecpar, s->streams[i]->codecpar); + avcodec_parameters_copy(st->codecpar, vs->streams[i]->codecpar); if (!oc->oformat->codec_tag || - av_codec_get_id (oc->oformat->codec_tag, s->streams[i]->codecpar->codec_tag) == st->codecpar->codec_id || - av_codec_get_tag(oc->oformat->codec_tag, s->streams[i]->codecpar->codec_id) <= 0) { - st->codecpar->codec_tag = s->streams[i]->codecpar->codec_tag; + av_codec_get_id (oc->oformat->codec_tag, vs->streams[i]->codecpar->codec_tag) == st->codecpar->codec_id || + av_codec_get_tag(oc->oformat->codec_tag, vs->streams[i]->codecpar->codec_id) <= 0) { + st->codecpar->codec_tag = vs->streams[i]->codecpar->codec_tag; } else { st->codecpar->codec_tag = 0; } - st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio; - st->time_base = s->streams[i]->time_base; - av_dict_copy(&st->metadata, s->streams[i]->metadata, 0); + st->sample_aspect_ratio = vs->streams[i]->sample_aspect_ratio; + st->time_base = vs->streams[i]->time_base; + av_dict_copy(&st->metadata, vs->streams[i]->metadata, 0); } - hls->start_pos = 0; - hls->new_start = 1; - hls->fmp4_init_mode = 0; + + vs->packets_written = 1; + vs->start_pos = 0; + vs->new_start = 1; + vs->fmp4_init_mode = 0; if (hls->segment_type == SEGMENT_TYPE_FMP4) { if (hls->max_seg_size > 0) { av_log(s, AV_LOG_WARNING, "Multi-file byterange mode is currently unsupported in the HLS muxer.\n"); return AVERROR_PATCHWELCOME; } - hls->fmp4_init_mode = !byterange_mode; + + vs->packets_written = 0; + vs->init_range_length = 0; + vs->fmp4_init_mode = !byterange_mode; set_http_options(s, &options, hls); - if ((ret = s->io_open(s, &oc->pb, hls->base_output_dirname, AVIO_FLAG_WRITE, &options)) < 0) { - av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", hls->fmp4_init_filename); + if ((ret = avio_open_dyn_buf(&oc->pb)) < 0) + return ret; + + if (byterange_mode) { + ret = hlsenc_io_open(s, &vs->out, vs->basename, &options); + } else { + ret = hlsenc_io_open(s, &vs->out, vs->base_output_dirname, &options); + } + av_dict_free(&options); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", vs->fmp4_init_filename); return ret; } @@ -634,6 +812,7 @@ static int hls_mux_init(AVFormatContext *s) av_dict_free(&options); return AVERROR(EINVAL); } + avio_flush(oc->pb); av_dict_free(&options); } return 0; @@ -649,47 +828,44 @@ static HLSSegment *find_segment_by_filename(HLSSegment *segment, const char *fil return (HLSSegment *) NULL; } -static int sls_flags_filename_process(struct AVFormatContext *s, HLSContext *hls, HLSSegment *en, double duration, - int64_t pos, int64_t size) +static int sls_flags_filename_process(struct AVFormatContext *s, HLSContext *hls, + VariantStream *vs, HLSSegment *en, + double duration, int64_t pos, int64_t size) { if ((hls->flags & (HLS_SECOND_LEVEL_SEGMENT_SIZE | HLS_SECOND_LEVEL_SEGMENT_DURATION)) && - strlen(hls->current_segment_final_filename_fmt)) { - av_strlcpy(hls->avf->filename, hls->current_segment_final_filename_fmt, sizeof(hls->avf->filename)); + strlen(vs->current_segment_final_filename_fmt)) { + char * new_url = av_strdup(vs->current_segment_final_filename_fmt); + if (!new_url) { + av_free(en); + return AVERROR(ENOMEM); + } + ff_format_set_url(vs->avf, new_url); if (hls->flags & HLS_SECOND_LEVEL_SEGMENT_SIZE) { - char * filename = av_strdup(hls->avf->filename); // %%s will be %s after strftime - if (!filename) { - av_free(en); - return AVERROR(ENOMEM); - } - if (replace_int_data_in_filename(hls->avf->filename, sizeof(hls->avf->filename), - filename, 's', pos + size) < 1) { + char *filename = NULL; + if (replace_int_data_in_filename(&filename, vs->avf->url, 's', pos + size) < 1) { av_log(hls, AV_LOG_ERROR, "Invalid second level segment filename template '%s', " "you can try to remove second_level_segment_size flag\n", - filename); + vs->avf->url); av_free(filename); av_free(en); return AVERROR(EINVAL); } - av_free(filename); + ff_format_set_url(vs->avf, filename); } if (hls->flags & HLS_SECOND_LEVEL_SEGMENT_DURATION) { - char * filename = av_strdup(hls->avf->filename); // %%t will be %t after strftime - if (!filename) { - av_free(en); - return AVERROR(ENOMEM); - } - if (replace_int_data_in_filename(hls->avf->filename, sizeof(hls->avf->filename), - filename, 't', (int64_t)round(duration * HLS_MICROSECOND_UNIT)) < 1) { + char *filename = NULL; + if (replace_int_data_in_filename(&filename, vs->avf->url, + 't', (int64_t)round(duration * HLS_MICROSECOND_UNIT)) < 1) { av_log(hls, AV_LOG_ERROR, "Invalid second level segment filename template '%s', " "you can try to remove second_level_segment_time flag\n", - filename); + vs->avf->url); av_free(filename); av_free(en); return AVERROR(EINVAL); } - av_free(filename); + ff_format_set_url(vs->avf, filename); } } return 0; @@ -718,9 +894,9 @@ static int sls_flag_check_duration_size_index(HLSContext *hls) return ret; } -static int sls_flag_check_duration_size(HLSContext *hls) +static int sls_flag_check_duration_size(HLSContext *hls, VariantStream *vs) { - const char *proto = avio_find_protocol_name(hls->basename); + const char *proto = avio_find_protocol_name(vs->basename); int segment_renaming_ok = proto && !strcmp(proto, "file"); int ret = 0; @@ -738,69 +914,64 @@ static int sls_flag_check_duration_size(HLSContext *hls) return ret; } -static void sls_flag_file_rename(HLSContext *hls, char *old_filename) { +static void sls_flag_file_rename(HLSContext *hls, VariantStream *vs, char *old_filename) { if ((hls->flags & (HLS_SECOND_LEVEL_SEGMENT_SIZE | HLS_SECOND_LEVEL_SEGMENT_DURATION)) && - strlen(hls->current_segment_final_filename_fmt)) { - ff_rename(old_filename, hls->avf->filename, hls); + strlen(vs->current_segment_final_filename_fmt)) { + ff_rename(old_filename, vs->avf->url, hls); } } -static int sls_flag_use_localtime_filename(AVFormatContext *oc, HLSContext *c) +static int sls_flag_use_localtime_filename(AVFormatContext *oc, HLSContext *c, VariantStream *vs) { if (c->flags & HLS_SECOND_LEVEL_SEGMENT_INDEX) { - char * filename = av_strdup(oc->filename); // %%d will be %d after strftime - if (!filename) - return AVERROR(ENOMEM); - if (replace_int_data_in_filename(oc->filename, sizeof(oc->filename), + char *filename = NULL; + if (replace_int_data_in_filename(&filename, #if FF_API_HLS_WRAP - filename, 'd', c->wrap ? c->sequence % c->wrap : c->sequence) < 1) { + oc->url, 'd', c->wrap ? vs->sequence % c->wrap : vs->sequence) < 1) { #else - filename, 'd', c->sequence) < 1) { + oc->url, 'd', vs->sequence) < 1) { #endif av_log(c, AV_LOG_ERROR, "Invalid second level segment filename template '%s', " "you can try to remove second_level_segment_index flag\n", - filename); + oc->url); av_free(filename); return AVERROR(EINVAL); } - av_free(filename); + ff_format_set_url(oc, filename); } if (c->flags & (HLS_SECOND_LEVEL_SEGMENT_SIZE | HLS_SECOND_LEVEL_SEGMENT_DURATION)) { - av_strlcpy(c->current_segment_final_filename_fmt, oc->filename, - sizeof(c->current_segment_final_filename_fmt)); + av_strlcpy(vs->current_segment_final_filename_fmt, oc->url, + sizeof(vs->current_segment_final_filename_fmt)); if (c->flags & HLS_SECOND_LEVEL_SEGMENT_SIZE) { - char * filename = av_strdup(oc->filename); // %%s will be %s after strftime - if (!filename) - return AVERROR(ENOMEM); - if (replace_int_data_in_filename(oc->filename, sizeof(oc->filename), filename, 's', 0) < 1) { + char *filename = NULL; + if (replace_int_data_in_filename(&filename, oc->url, 's', 0) < 1) { av_log(c, AV_LOG_ERROR, "Invalid second level segment filename template '%s', " "you can try to remove second_level_segment_size flag\n", - filename); + oc->url); av_free(filename); return AVERROR(EINVAL); } - av_free(filename); + ff_format_set_url(oc, filename); } if (c->flags & HLS_SECOND_LEVEL_SEGMENT_DURATION) { - char * filename = av_strdup(oc->filename); // %%t will be %t after strftime - if (!filename) - return AVERROR(ENOMEM); - if (replace_int_data_in_filename(oc->filename, sizeof(oc->filename), filename, 't', 0) < 1) { + char *filename = NULL; + if (replace_int_data_in_filename(&filename, oc->url, 't', 0) < 1) { av_log(c, AV_LOG_ERROR, "Invalid second level segment filename template '%s', " "you can try to remove second_level_segment_time flag\n", - filename); + oc->url); av_free(filename); return AVERROR(EINVAL); } - av_free(filename); + ff_format_set_url(oc, filename); } } return 0; } /* Create a new segment and append it to the segment list */ -static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, double duration, - int64_t pos, int64_t size) +static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, + VariantStream *vs, double duration, int64_t pos, + int64_t size) { HLSSegment *en = av_malloc(sizeof(*en)); const char *filename; @@ -810,24 +981,25 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, double if (!en) return AVERROR(ENOMEM); - ret = sls_flags_filename_process(s, hls, en, duration, pos, size); + en->var_stream_idx = vs->var_stream_idx; + ret = sls_flags_filename_process(s, hls, vs, en, duration, pos, size); if (ret < 0) { return ret; } - filename = av_basename(hls->avf->filename); + filename = av_basename(vs->avf->url); if (hls->use_localtime_mkdir) { - filename = hls->avf->filename; + filename = vs->avf->url; } - if ((find_segment_by_filename(hls->segments, filename) || find_segment_by_filename(hls->old_segments, filename)) + if ((find_segment_by_filename(vs->segments, filename) || find_segment_by_filename(vs->old_segments, filename)) && !byterange_mode) { av_log(hls, AV_LOG_WARNING, "Duplicated segment filename detected: %s\n", filename); } av_strlcpy(en->filename, filename, sizeof(en->filename)); - if(hls->has_subtitle) - av_strlcpy(en->sub_filename, av_basename(hls->vtt_avf->filename), sizeof(en->sub_filename)); + if(vs->has_subtitle) + av_strlcpy(en->sub_filename, av_basename(vs->vtt_avf->url), sizeof(en->sub_filename)); else en->sub_filename[0] = '\0'; @@ -837,9 +1009,9 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, double en->next = NULL; en->discont = 0; - if (hls->discontinuity) { + if (vs->discontinuity) { en->discont = 1; - hls->discontinuity = 0; + vs->discontinuity = 0; } if (hls->key_info_file || hls->encrypt) { @@ -847,45 +1019,45 @@ static int hls_append_segment(struct AVFormatContext *s, HLSContext *hls, double av_strlcpy(en->iv_string, hls->iv_string, sizeof(en->iv_string)); } - if (!hls->segments) - hls->segments = en; + if (!vs->segments) + vs->segments = en; else - hls->last_segment->next = en; + vs->last_segment->next = en; - hls->last_segment = en; + vs->last_segment = en; // EVENT or VOD playlists imply sliding window cannot be used if (hls->pl_type != PLAYLIST_TYPE_NONE) hls->max_nb_segments = 0; - if (hls->max_nb_segments && hls->nb_entries >= hls->max_nb_segments) { - en = hls->segments; - hls->initial_prog_date_time += en->duration; - hls->segments = en->next; + if (hls->max_nb_segments && vs->nb_entries >= hls->max_nb_segments) { + en = vs->segments; + vs->initial_prog_date_time += en->duration; + vs->segments = en->next; if (en && hls->flags & HLS_DELETE_SEGMENTS && #if FF_API_HLS_WRAP !(hls->flags & HLS_SINGLE_FILE || hls->wrap)) { #else !(hls->flags & HLS_SINGLE_FILE)) { #endif - en->next = hls->old_segments; - hls->old_segments = en; - if ((ret = hls_delete_old_segments(s, hls)) < 0) + en->next = vs->old_segments; + vs->old_segments = en; + if ((ret = hls_delete_old_segments(s, hls, vs)) < 0) return ret; } else av_free(en); } else - hls->nb_entries++; + vs->nb_entries++; if (hls->max_seg_size > 0) { return 0; } - hls->sequence++; + vs->sequence++; return 0; } -static int parse_playlist(AVFormatContext *s, const char *url) +static int parse_playlist(AVFormatContext *s, const char *url, VariantStream *vs) { HLSContext *hls = s->priv_data; AVIOContext *in; @@ -900,32 +1072,32 @@ static int parse_playlist(AVFormatContext *s, const char *url) s->protocol_whitelist, s->protocol_blacklist)) < 0) return ret; - read_chomp_line(in, line, sizeof(line)); + ff_get_chomp_line(in, line, sizeof(line)); if (strcmp(line, "#EXTM3U")) { ret = AVERROR_INVALIDDATA; goto fail; } - hls->discontinuity = 0; + vs->discontinuity = 0; while (!avio_feof(in)) { - read_chomp_line(in, line, sizeof(line)); + ff_get_chomp_line(in, line, sizeof(line)); if (av_strstart(line, "#EXT-X-MEDIA-SEQUENCE:", &ptr)) { int64_t tmp_sequence = strtoll(ptr, NULL, 10); - if (tmp_sequence < hls->sequence) + if (tmp_sequence < vs->sequence) av_log(hls, AV_LOG_VERBOSE, "Found playlist sequence number was smaller """ "than specified start sequence number: %"PRId64" < %"PRId64", " "omitting\n", tmp_sequence, hls->start_sequence); else { av_log(hls, AV_LOG_DEBUG, "Found playlist sequence number: %"PRId64"\n", tmp_sequence); - hls->sequence = tmp_sequence; + vs->sequence = tmp_sequence; } } else if (av_strstart(line, "#EXT-X-DISCONTINUITY", &ptr)) { is_segment = 1; - hls->discontinuity = 1; + vs->discontinuity = 1; } else if (av_strstart(line, "#EXTINF:", &ptr)) { is_segment = 1; - hls->duration = atof(ptr); + vs->duration = atof(ptr); } else if (av_stristart(line, "#EXT-X-KEY:", &ptr)) { ptr = av_stristr(line, "URI=\""); if (ptr) { @@ -953,14 +1125,19 @@ static int parse_playlist(AVFormatContext *s, const char *url) continue; } else if (line[0]) { if (is_segment) { + char *new_file = av_strdup(line); + if (!new_file) { + ret = AVERROR(ENOMEM); + goto fail; + } + ff_format_set_url(vs->avf, new_file); is_segment = 0; - new_start_pos = avio_tell(hls->avf->pb); - hls->size = new_start_pos - hls->start_pos; - av_strlcpy(hls->avf->filename, line, sizeof(line)); - ret = hls_append_segment(s, hls, hls->duration, hls->start_pos, hls->size); + new_start_pos = avio_tell(vs->avf->pb); + vs->size = new_start_pos - vs->start_pos; + ret = hls_append_segment(s, hls, vs, vs->duration, vs->start_pos, vs->size); if (ret < 0) goto fail; - hls->start_pos = new_start_pos; + vs->start_pos = new_start_pos; } } } @@ -981,221 +1158,387 @@ static void hls_free_segments(HLSSegment *p) } } -static void write_m3u8_head_block(HLSContext *hls, AVIOContext *out, int version, - int target_duration, int64_t sequence) +static int hls_rename_temp_file(AVFormatContext *s, AVFormatContext *oc) +{ + size_t len = strlen(oc->url); + char *final_filename = av_strdup(oc->url); + int ret; + + if (!final_filename) + return AVERROR(ENOMEM); + final_filename[len-4] = '\0'; + ret = ff_rename(oc->url, final_filename, s); + oc->url[len-4] = '\0'; + av_freep(&final_filename); + return ret; +} + +static int get_relative_url(const char *master_url, const char *media_url, + char *rel_url, int rel_url_buf_size) { - avio_printf(out, "#EXTM3U\n"); - avio_printf(out, "#EXT-X-VERSION:%d\n", version); - if (hls->allowcache == 0 || hls->allowcache == 1) { - avio_printf(out, "#EXT-X-ALLOW-CACHE:%s\n", hls->allowcache == 0 ? "NO" : "YES"); - } - avio_printf(out, "#EXT-X-TARGETDURATION:%d\n", target_duration); - avio_printf(out, "#EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence); - av_log(hls, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence); + char *p = NULL; + int base_len = -1; + p = strrchr(master_url, '/') ? strrchr(master_url, '/') :\ + strrchr(master_url, '\\'); + if (p) { + base_len = FFABS(p - master_url); + if (av_strncasecmp(master_url, media_url, base_len)) { + av_log(NULL, AV_LOG_WARNING, "Unable to find relative url\n"); + return AVERROR(EINVAL); + } + } + av_strlcpy(rel_url, &(media_url[base_len + 1]), rel_url_buf_size); + return 0; +} + +static int64_t get_stream_bit_rate(AVStream *stream) { + AVCPBProperties *props = (AVCPBProperties*)av_stream_get_side_data( + stream, + AV_PKT_DATA_CPB_PROPERTIES, + NULL + ); + + if (stream->codecpar->bit_rate) + return stream->codecpar->bit_rate; + else if (props) + return props->max_bitrate; + + return 0; } -static void hls_rename_temp_file(AVFormatContext *s, AVFormatContext *oc) +static int create_master_playlist(AVFormatContext *s, + VariantStream * const input_vs) { - size_t len = strlen(oc->filename); - char final_filename[sizeof(oc->filename)]; + HLSContext *hls = s->priv_data; + VariantStream *vs, *temp_vs; + AVStream *vid_st, *aud_st; + AVDictionary *options = NULL; + unsigned int i, j; + int m3u8_name_size, ret, bandwidth; + char *m3u8_rel_name, *ccgroup; + ClosedCaptionsStream *ccs; + + input_vs->m3u8_created = 1; + if (!hls->master_m3u8_created) { + /* For the first time, wait until all the media playlists are created */ + for (i = 0; i < hls->nb_varstreams; i++) + if (!hls->var_streams[i].m3u8_created) + return 0; + } else { + /* Keep publishing the master playlist at the configured rate */ + if (&hls->var_streams[0] != input_vs || !hls->master_publish_rate || + input_vs->number % hls->master_publish_rate) + return 0; + } - av_strlcpy(final_filename, oc->filename, len); - final_filename[len-4] = '\0'; - ff_rename(oc->filename, final_filename, s); - oc->filename[len-4] = '\0'; + set_http_options(s, &options, hls); + + ret = hlsenc_io_open(s, &hls->m3u8_out, hls->master_m3u8_url, &options); + av_dict_free(&options); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Failed to open master play list file '%s'\n", + hls->master_m3u8_url); + goto fail; + } + + ff_hls_write_playlist_version(hls->m3u8_out, hls->version); + + for (i = 0; i < hls->nb_ccstreams; i++) { + ccs = &(hls->cc_streams[i]); + avio_printf(hls->m3u8_out, "#EXT-X-MEDIA:TYPE=CLOSED-CAPTIONS"); + avio_printf(hls->m3u8_out, ",GROUP-ID=\"%s\"", ccs->ccgroup); + avio_printf(hls->m3u8_out, ",NAME=\"%s\"", ccs->instreamid); + if (ccs->language) + avio_printf(hls->m3u8_out, ",LANGUAGE=\"%s\"", ccs->language); + avio_printf(hls->m3u8_out, ",INSTREAM-ID=\"%s\"\n", ccs->instreamid); + } + + /* For audio only variant streams add #EXT-X-MEDIA tag with attributes*/ + for (i = 0; i < hls->nb_varstreams; i++) { + vs = &(hls->var_streams[i]); + + if (vs->has_video || vs->has_subtitle || !vs->agroup) + continue; + + m3u8_name_size = strlen(vs->m3u8_name) + 1; + m3u8_rel_name = av_malloc(m3u8_name_size); + if (!m3u8_rel_name) { + ret = AVERROR(ENOMEM); + goto fail; + } + av_strlcpy(m3u8_rel_name, vs->m3u8_name, m3u8_name_size); + ret = get_relative_url(hls->master_m3u8_url, vs->m3u8_name, + m3u8_rel_name, m3u8_name_size); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Unable to find relative URL\n"); + goto fail; + } + + ff_hls_write_audio_rendition(hls->m3u8_out, vs->agroup, m3u8_rel_name, 0, 1); + + av_freep(&m3u8_rel_name); + } + + /* For variant streams with video add #EXT-X-STREAM-INF tag with attributes*/ + for (i = 0; i < hls->nb_varstreams; i++) { + vs = &(hls->var_streams[i]); + + m3u8_name_size = strlen(vs->m3u8_name) + 1; + m3u8_rel_name = av_malloc(m3u8_name_size); + if (!m3u8_rel_name) { + ret = AVERROR(ENOMEM); + goto fail; + } + av_strlcpy(m3u8_rel_name, vs->m3u8_name, m3u8_name_size); + ret = get_relative_url(hls->master_m3u8_url, vs->m3u8_name, + m3u8_rel_name, m3u8_name_size); + if (ret < 0) { + av_log(NULL, AV_LOG_ERROR, "Unable to find relative URL\n"); + goto fail; + } + + vid_st = NULL; + aud_st = NULL; + for (j = 0; j < vs->nb_streams; j++) { + if (vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) + vid_st = vs->streams[j]; + else if (vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) + aud_st = vs->streams[j]; + } + + if (!vid_st && !aud_st) { + av_log(NULL, AV_LOG_WARNING, "Media stream not found\n"); + continue; + } + + /** + * Traverse through the list of audio only rendition streams and find + * the rendition which has highest bitrate in the same audio group + */ + if (vs->agroup) { + for (j = 0; j < hls->nb_varstreams; j++) { + temp_vs = &(hls->var_streams[j]); + if (!temp_vs->has_video && !temp_vs->has_subtitle && + temp_vs->agroup && + !av_strcasecmp(temp_vs->agroup, vs->agroup)) { + if (!aud_st) + aud_st = temp_vs->streams[0]; + if (temp_vs->streams[0]->codecpar->bit_rate > + aud_st->codecpar->bit_rate) + aud_st = temp_vs->streams[0]; + } + } + } + + bandwidth = 0; + if (vid_st) + bandwidth += get_stream_bit_rate(vid_st); + if (aud_st) + bandwidth += get_stream_bit_rate(aud_st); + bandwidth += bandwidth / 10; + + ccgroup = NULL; + if (vid_st && vs->ccgroup) { + /* check if this group name is available in the cc map string */ + for (j = 0; j < hls->nb_ccstreams; j++) { + ccs = &(hls->cc_streams[j]); + if (!av_strcasecmp(ccs->ccgroup, vs->ccgroup)) { + ccgroup = vs->ccgroup; + break; + } + } + if (j == hls->nb_ccstreams) + av_log(NULL, AV_LOG_WARNING, "mapping ccgroup %s not found\n", + vs->ccgroup); + } + + ff_hls_write_stream_info(vid_st, hls->m3u8_out, bandwidth, m3u8_rel_name, + aud_st ? vs->agroup : NULL, vs->codec_attr, ccgroup); + + av_freep(&m3u8_rel_name); + } +fail: + if(ret >=0) + hls->master_m3u8_created = 1; + av_freep(&m3u8_rel_name); + hlsenc_io_close(s, &hls->m3u8_out, hls->master_m3u8_url); + return ret; } -static int hls_window(AVFormatContext *s, int last) +static int hls_window(AVFormatContext *s, int last, VariantStream *vs) { HLSContext *hls = s->priv_data; HLSSegment *en; int target_duration = 0; int ret = 0; - AVIOContext *out = NULL; - AVIOContext *sub_out = NULL; char temp_filename[1024]; - int64_t sequence = FFMAX(hls->start_sequence, hls->sequence - hls->nb_entries); - int version = 3; - const char *proto = avio_find_protocol_name(s->filename); + int64_t sequence = FFMAX(hls->start_sequence, vs->sequence - vs->nb_entries); + const char *proto = avio_find_protocol_name(s->url); int use_rename = proto && !strcmp(proto, "file"); static unsigned warned_non_file; char *key_uri = NULL; char *iv_string = NULL; AVDictionary *options = NULL; - double prog_date_time = hls->initial_prog_date_time; + double prog_date_time = vs->initial_prog_date_time; + double *prog_date_time_p = (hls->flags & HLS_PROGRAM_DATE_TIME) ? &prog_date_time : NULL; int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0); + hls->version = 3; if (byterange_mode) { - version = 4; + hls->version = 4; sequence = 0; } + if (hls->flags & HLS_INDEPENDENT_SEGMENTS) { + hls->version = 6; + } + if (hls->segment_type == SEGMENT_TYPE_FMP4) { - version = 7; + hls->version = 7; } if (!use_rename && !warned_non_file++) av_log(s, AV_LOG_ERROR, "Cannot use rename on non file protocol, this may lead to races and temporary partial files\n"); set_http_options(s, &options, hls); - snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", s->filename); - if ((ret = s->io_open(s, &out, temp_filename, AVIO_FLAG_WRITE, &options)) < 0) + snprintf(temp_filename, sizeof(temp_filename), use_rename ? "%s.tmp" : "%s", vs->m3u8_name); + if ((ret = hlsenc_io_open(s, &hls->m3u8_out, temp_filename, &options)) < 0) goto fail; - for (en = hls->segments; en; en = en->next) { + for (en = vs->segments; en; en = en->next) { if (target_duration <= en->duration) - target_duration = get_int_from_double(en->duration); + target_duration = lrint(en->duration); } - hls->discontinuity_set = 0; - write_m3u8_head_block(hls, out, version, target_duration, sequence); - if (hls->pl_type == PLAYLIST_TYPE_EVENT) { - avio_printf(out, "#EXT-X-PLAYLIST-TYPE:EVENT\n"); - } else if (hls->pl_type == PLAYLIST_TYPE_VOD) { - avio_printf(out, "#EXT-X-PLAYLIST-TYPE:VOD\n"); - } + vs->discontinuity_set = 0; + ff_hls_write_playlist_header(hls->m3u8_out, hls->version, hls->allowcache, + target_duration, sequence, hls->pl_type); - if((hls->flags & HLS_DISCONT_START) && sequence==hls->start_sequence && hls->discontinuity_set==0 ){ - avio_printf(out, "#EXT-X-DISCONTINUITY\n"); - hls->discontinuity_set = 1; + if((hls->flags & HLS_DISCONT_START) && sequence==hls->start_sequence && vs->discontinuity_set==0 ){ + avio_printf(hls->m3u8_out, "#EXT-X-DISCONTINUITY\n"); + vs->discontinuity_set = 1; + } + if (vs->has_video && (hls->flags & HLS_INDEPENDENT_SEGMENTS)) { + avio_printf(hls->m3u8_out, "#EXT-X-INDEPENDENT-SEGMENTS\n"); } - for (en = hls->segments; en; en = en->next) { + for (en = vs->segments; en; en = en->next) { if ((hls->encrypt || hls->key_info_file) && (!key_uri || strcmp(en->key_uri, key_uri) || av_strcasecmp(en->iv_string, iv_string))) { - avio_printf(out, "#EXT-X-KEY:METHOD=AES-128,URI=\"%s\"", en->key_uri); + avio_printf(hls->m3u8_out, "#EXT-X-KEY:METHOD=AES-128,URI=\"%s\"", en->key_uri); if (*en->iv_string) - avio_printf(out, ",IV=0x%s", en->iv_string); - avio_printf(out, "\n"); + avio_printf(hls->m3u8_out, ",IV=0x%s", en->iv_string); + avio_printf(hls->m3u8_out, "\n"); key_uri = en->key_uri; iv_string = en->iv_string; } - if (en->discont) { - avio_printf(out, "#EXT-X-DISCONTINUITY\n"); + if ((hls->segment_type == SEGMENT_TYPE_FMP4) && (en == vs->segments)) { + ff_hls_write_init_file(hls->m3u8_out, (hls->flags & HLS_SINGLE_FILE) ? en->filename : vs->fmp4_init_filename, + hls->flags & HLS_SINGLE_FILE, vs->init_range_length, 0); } - if ((hls->segment_type == SEGMENT_TYPE_FMP4) && (en == hls->segments)) { - avio_printf(out, "#EXT-X-MAP:URI=\"%s\"", hls->fmp4_init_filename); - if (hls->flags & HLS_SINGLE_FILE) { - avio_printf(out, ",BYTERANGE=\"%"PRId64"@%"PRId64"\"", en->size, en->pos); - } - avio_printf(out, "\n"); - } else { - if (hls->flags & HLS_ROUND_DURATIONS) - avio_printf(out, "#EXTINF:%ld,\n", lrint(en->duration)); - else - avio_printf(out, "#EXTINF:%f,\n", en->duration); - if (byterange_mode) - avio_printf(out, "#EXT-X-BYTERANGE:%"PRId64"@%"PRId64"\n", - en->size, en->pos); - } - if (hls->flags & HLS_PROGRAM_DATE_TIME) { - time_t tt, wrongsecs; - int milli; - struct tm *tm, tmpbuf; - char buf0[128], buf1[128]; - tt = (int64_t)prog_date_time; - milli = av_clip(lrint(1000*(prog_date_time - tt)), 0, 999); - tm = localtime_r(&tt, &tmpbuf); - strftime(buf0, sizeof(buf0), "%Y-%m-%dT%H:%M:%S", tm); - if (!strftime(buf1, sizeof(buf1), "%z", tm) || buf1[1]<'0' ||buf1[1]>'2') { - int tz_min, dst = tm->tm_isdst; - tm = gmtime_r(&tt, &tmpbuf); - tm->tm_isdst = dst; - wrongsecs = mktime(tm); - tz_min = (abs(wrongsecs - tt) + 30) / 60; - snprintf(buf1, sizeof(buf1), - "%c%02d%02d", - wrongsecs <= tt ? '+' : '-', - tz_min / 60, - tz_min % 60); - } - avio_printf(out, "#EXT-X-PROGRAM-DATE-TIME:%s.%03d%s\n", buf0, milli, buf1); - prog_date_time += en->duration; - } - if (!((hls->segment_type == SEGMENT_TYPE_FMP4) && (en == hls->segments))) { - if (hls->baseurl) - avio_printf(out, "%s", hls->baseurl); - avio_printf(out, "%s\n", en->filename); + ret = ff_hls_write_file_entry(hls->m3u8_out, en->discont, byterange_mode, + en->duration, hls->flags & HLS_ROUND_DURATIONS, + en->size, en->pos, vs->baseurl, + en->filename, prog_date_time_p); + if (ret < 0) { + av_log(s, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n"); } } if (last && (hls->flags & HLS_OMIT_ENDLIST)==0) - avio_printf(out, "#EXT-X-ENDLIST\n"); + ff_hls_write_end_list(hls->m3u8_out); - if( hls->vtt_m3u8_name ) { - if ((ret = s->io_open(s, &sub_out, hls->vtt_m3u8_name, AVIO_FLAG_WRITE, &options)) < 0) + if( vs->vtt_m3u8_name ) { + if ((ret = hlsenc_io_open(s, &hls->sub_m3u8_out, vs->vtt_m3u8_name, &options)) < 0) goto fail; - write_m3u8_head_block(hls, sub_out, version, target_duration, sequence); - - for (en = hls->segments; en; en = en->next) { - avio_printf(sub_out, "#EXTINF:%f,\n", en->duration); - if (byterange_mode) - avio_printf(sub_out, "#EXT-X-BYTERANGE:%"PRIi64"@%"PRIi64"\n", - en->size, en->pos); - if (hls->baseurl) - avio_printf(sub_out, "%s", hls->baseurl); - avio_printf(sub_out, "%s\n", en->sub_filename); + ff_hls_write_playlist_header(hls->sub_m3u8_out, hls->version, hls->allowcache, + target_duration, sequence, PLAYLIST_TYPE_NONE); + for (en = vs->segments; en; en = en->next) { + ret = ff_hls_write_file_entry(hls->sub_m3u8_out, 0, byterange_mode, + en->duration, 0, en->size, en->pos, + vs->baseurl, en->sub_filename, NULL); + if (ret < 0) { + av_log(s, AV_LOG_WARNING, "ff_hls_write_file_entry get error\n"); + } } if (last) - avio_printf(sub_out, "#EXT-X-ENDLIST\n"); + ff_hls_write_end_list(hls->sub_m3u8_out); } fail: av_dict_free(&options); - ff_format_io_close(s, &out); - ff_format_io_close(s, &sub_out); + hlsenc_io_close(s, &hls->m3u8_out, temp_filename); + hlsenc_io_close(s, &hls->sub_m3u8_out, vs->vtt_m3u8_name); if (ret >= 0 && use_rename) - ff_rename(temp_filename, s->filename, s); + ff_rename(temp_filename, vs->m3u8_name, s); + + if (ret >= 0 && hls->master_pl_name) + if (create_master_playlist(s, vs) < 0) + av_log(s, AV_LOG_WARNING, "Master playlist creation failed\n"); + return ret; } -static int hls_start(AVFormatContext *s) +static int hls_start(AVFormatContext *s, VariantStream *vs) { HLSContext *c = s->priv_data; - AVFormatContext *oc = c->avf; - AVFormatContext *vtt_oc = c->vtt_avf; + AVFormatContext *oc = vs->avf; + AVFormatContext *vtt_oc = vs->vtt_avf; AVDictionary *options = NULL; char *filename, iv_string[KEYSIZE*2 + 1]; int err = 0; if (c->flags & HLS_SINGLE_FILE) { - av_strlcpy(oc->filename, c->basename, - sizeof(oc->filename)); - if (c->vtt_basename) - av_strlcpy(vtt_oc->filename, c->vtt_basename, - sizeof(vtt_oc->filename)); + char *new_name = av_strdup(vs->basename); + if (!new_name) + return AVERROR(ENOMEM); + ff_format_set_url(oc, new_name); + if (vs->vtt_basename) { + new_name = av_strdup(vs->vtt_basename); + if (!new_name) + return AVERROR(ENOMEM); + ff_format_set_url(vtt_oc, new_name); + } } else if (c->max_seg_size > 0) { - if (replace_int_data_in_filename(oc->filename, sizeof(oc->filename), + char *filename = NULL; + if (replace_int_data_in_filename(&filename, #if FF_API_HLS_WRAP - c->basename, 'd', c->wrap ? c->sequence % c->wrap : c->sequence) < 1) { + vs->basename, 'd', c->wrap ? vs->sequence % c->wrap : vs->sequence) < 1) { #else - c->basename, 'd', c->sequence) < 1) { + vs->basename, 'd', vs->sequence) < 1) { #endif - av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s', you can try to use -use_localtime 1 with it\n", c->basename); + av_free(filename); + av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s', you can try to use -use_localtime 1 with it\n", vs->basename); return AVERROR(EINVAL); } + ff_format_set_url(oc, filename); } else { if (c->use_localtime) { time_t now0; struct tm *tm, tmpbuf; + int bufsize = strlen(vs->basename) + 1024; + char *buf = av_mallocz(bufsize); + if (!buf) + return AVERROR(ENOMEM); time(&now0); tm = localtime_r(&now0, &tmpbuf); - if (!strftime(oc->filename, sizeof(oc->filename), c->basename, tm)) { + ff_format_set_url(oc, buf); + if (!strftime(oc->url, bufsize, vs->basename, tm)) { av_log(oc, AV_LOG_ERROR, "Could not get segment filename with use_localtime\n"); return AVERROR(EINVAL); } - err = sls_flag_use_localtime_filename(oc, c); + err = sls_flag_use_localtime_filename(oc, c, vs); if (err < 0) { return AVERROR(ENOMEM); } if (c->use_localtime_mkdir) { const char *dir; - char *fn_copy = av_strdup(oc->filename); + char *fn_copy = av_strdup(oc->url); if (!fn_copy) { return AVERROR(ENOMEM); } @@ -1207,82 +1550,98 @@ static int hls_start(AVFormatContext *s) } av_free(fn_copy); } - } else if (replace_int_data_in_filename(oc->filename, sizeof(oc->filename), + } else { + char *filename = NULL; + if (replace_int_data_in_filename(&filename, #if FF_API_HLS_WRAP - c->basename, 'd', c->wrap ? c->sequence % c->wrap : c->sequence) < 1) { + vs->basename, 'd', c->wrap ? vs->sequence % c->wrap : vs->sequence) < 1) { #else - c->basename, 'd', c->sequence) < 1) { + vs->basename, 'd', vs->sequence) < 1) { #endif - av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s' you can try to use -use_localtime 1 with it\n", c->basename); - return AVERROR(EINVAL); + av_free(filename); + av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s' you can try to use -use_localtime 1 with it\n", vs->basename); + return AVERROR(EINVAL); + } + ff_format_set_url(oc, filename); } - if( c->vtt_basename) { - if (replace_int_data_in_filename(vtt_oc->filename, sizeof(vtt_oc->filename), + if( vs->vtt_basename) { + char *filename = NULL; + if (replace_int_data_in_filename(&filename, #if FF_API_HLS_WRAP - c->vtt_basename, 'd', c->wrap ? c->sequence % c->wrap : c->sequence) < 1) { + vs->vtt_basename, 'd', c->wrap ? vs->sequence % c->wrap : vs->sequence) < 1) { #else - c->vtt_basename, 'd', c->sequence) < 1) { + vs->vtt_basename, 'd', vs->sequence) < 1) { #endif - av_log(vtt_oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", c->vtt_basename); + av_free(filename); + av_log(vtt_oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", vs->vtt_basename); return AVERROR(EINVAL); } + ff_format_set_url(vtt_oc, filename); } } - c->number++; + vs->number++; set_http_options(s, &options, c); if (c->flags & HLS_TEMP_FILE) { - av_strlcat(oc->filename, ".tmp", sizeof(oc->filename)); + char *new_name = av_asprintf("%s.tmp", oc->url); + if (!new_name) + return AVERROR(ENOMEM); + ff_format_set_url(oc, new_name); } if (c->key_info_file || c->encrypt) { + if (c->segment_type == SEGMENT_TYPE_FMP4) { + av_log(s, AV_LOG_ERROR, "Encrypted fmp4 not yet supported\n"); + return AVERROR_PATCHWELCOME; + } + if (c->key_info_file && c->encrypt) { av_log(s, AV_LOG_WARNING, "Cannot use both -hls_key_info_file and -hls_enc," - " will use -hls_key_info_file priority\n"); + " ignoring -hls_enc\n"); } - if (c->number <= 1 || (c->flags & HLS_PERIODIC_REKEY)) { + if (!c->encrypt_started || (c->flags & HLS_PERIODIC_REKEY)) { if (c->key_info_file) { if ((err = hls_encryption_start(s)) < 0) goto fail; } else { - if ((err = do_encrypt(s)) < 0) + if ((err = do_encrypt(s, vs)) < 0) goto fail; } + c->encrypt_started = 1; } if ((err = av_dict_set(&options, "encryption_key", c->key_string, 0)) < 0) goto fail; err = av_strlcpy(iv_string, c->iv_string, sizeof(iv_string)); if (!err) - snprintf(iv_string, sizeof(iv_string), "%032"PRIx64, c->sequence); + snprintf(iv_string, sizeof(iv_string), "%032"PRIx64, vs->sequence); if ((err = av_dict_set(&options, "encryption_iv", iv_string, 0)) < 0) goto fail; - filename = av_asprintf("crypto:%s", oc->filename); + filename = av_asprintf("crypto:%s", oc->url); if (!filename) { err = AVERROR(ENOMEM); goto fail; } - err = s->io_open(s, &oc->pb, filename, AVIO_FLAG_WRITE, &options); + err = hlsenc_io_open(s, &oc->pb, filename, &options); av_free(filename); av_dict_free(&options); if (err < 0) return err; - } else - if ((err = s->io_open(s, &oc->pb, oc->filename, AVIO_FLAG_WRITE, &options)) < 0) + } else if (c->segment_type != SEGMENT_TYPE_FMP4) { + if ((err = hlsenc_io_open(s, &oc->pb, oc->url, &options)) < 0) goto fail; - if (c->vtt_basename) { + } + if (vs->vtt_basename) { set_http_options(s, &options, c); - if ((err = s->io_open(s, &vtt_oc->pb, vtt_oc->filename, AVIO_FLAG_WRITE, &options)) < 0) + if ((err = hlsenc_io_open(s, &vtt_oc->pb, vtt_oc->url, &options)) < 0) goto fail; } av_dict_free(&options); - if (c->segment_type == SEGMENT_TYPE_FMP4 && !(c->flags & HLS_SINGLE_FILE)) { - write_styp(oc->pb); - } else { + if (c->segment_type != SEGMENT_TYPE_FMP4) { /* We only require one PAT/PMT per segment. */ if (oc->oformat->priv_class && oc->priv_data) { char period[21]; @@ -1295,7 +1654,7 @@ static int hls_start(AVFormatContext *s) } } - if (c->vtt_basename) { + if (vs->vtt_basename) { err = avformat_write_header(vtt_oc,NULL); if (err < 0) return err; @@ -1324,264 +1683,455 @@ static const char * get_default_pattern_localtime_fmt(AVFormatContext *s) return (HAVE_LIBC_MSVCRT || !strftime(b, sizeof(b), "%s", p) || !strcmp(b, "%s")) ? "-%Y%m%d%H%M%S.ts" : "-%s.ts"; } -static int hls_write_header(AVFormatContext *s) +static int append_postfix(char *name, int name_buf_len, int i) { - HLSContext *hls = s->priv_data; - int ret, i; - char *p = NULL; - const char *pattern = "%d.ts"; - const char *pattern_localtime_fmt = get_default_pattern_localtime_fmt(s); - const char *vtt_pattern = "%d.vtt"; - AVDictionary *options = NULL; - int basename_size = 0; - int vtt_basename_size = 0; + char *p; + char extension[10] = {'\0'}; - if (hls->segment_type == SEGMENT_TYPE_FMP4) { - pattern = "%d.m4s"; - } - if ((hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH) || - (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_FORMATTED_DATETIME)) { - time_t t = time(NULL); // we will need it in either case - if (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH) { - hls->start_sequence = (int64_t)t; - } else if (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_FORMATTED_DATETIME) { - char b[15]; - struct tm *p, tmbuf; - if (!(p = localtime_r(&t, &tmbuf))) - return AVERROR(ENOMEM); - if (!strftime(b, sizeof(b), "%Y%m%d%H%M%S", p)) - return AVERROR(ENOMEM); - hls->start_sequence = strtoll(b, NULL, 10); - } - av_log(hls, AV_LOG_DEBUG, "start_number evaluated to %"PRId64"\n", hls->start_sequence); + p = strrchr(name, '.'); + if (p) { + av_strlcpy(extension, p, sizeof(extension)); + *p = '\0'; } - hls->sequence = hls->start_sequence; - hls->recording_time = (hls->init_time ? hls->init_time : hls->time) * AV_TIME_BASE; - hls->start_pts = AV_NOPTS_VALUE; - hls->current_segment_final_filename_fmt[0] = '\0'; + snprintf(name + strlen(name), name_buf_len - strlen(name), POSTFIX_PATTERN, i); - if (hls->flags & HLS_PROGRAM_DATE_TIME) { - time_t now0; - time(&now0); - hls->initial_prog_date_time = now0; - } + if (strlen(extension)) + av_strlcat(name, extension, name_buf_len); - if (hls->format_options_str) { - ret = av_dict_parse_string(&hls->format_options, hls->format_options_str, "=", ":", 0); - if (ret < 0) { - av_log(s, AV_LOG_ERROR, "Could not parse format options list '%s'\n", hls->format_options_str); - goto fail; - } + return 0; +} + +static int validate_name(int nb_vs, const char *fn) +{ + const char *filename, *subdir_name; + char *fn_dup = NULL; + int ret = 0; + + if (!fn) { + ret = AVERROR(EINVAL); + goto fail; } - for (i = 0; i < s->nb_streams; i++) { - hls->has_video += - s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO; - hls->has_subtitle += - s->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE; + fn_dup = av_strdup(fn); + if (!fn_dup) { + ret = AVERROR(ENOMEM); + goto fail; } - if (hls->has_video > 1) - av_log(s, AV_LOG_WARNING, - "More than a single video stream present, " - "expect issues decoding it.\n"); + filename = av_basename(fn); + subdir_name = av_dirname(fn_dup); - if (hls->segment_type == SEGMENT_TYPE_FMP4) { - hls->oformat = av_guess_format("mp4", NULL, NULL); - } else { - hls->oformat = av_guess_format("mpegts", NULL, NULL); + if (nb_vs > 1 && !av_stristr(filename, "%v") && !av_stristr(subdir_name, "%v")) { + av_log(NULL, AV_LOG_ERROR, "More than 1 variant streams are present, %%v is expected in the filename %s\n", + fn); + ret = AVERROR(EINVAL); + goto fail; } - if (!hls->oformat) { - ret = AVERROR_MUXER_NOT_FOUND; + if (av_stristr(filename, "%v") && av_stristr(subdir_name, "%v")) { + av_log(NULL, AV_LOG_ERROR, "%%v is expected either in filename or in the sub-directory name of file %s\n", + fn); + ret = AVERROR(EINVAL); goto fail; } - if(hls->has_subtitle) { - hls->vtt_oformat = av_guess_format("webvtt", NULL, NULL); - if (!hls->oformat) { - ret = AVERROR_MUXER_NOT_FOUND; - goto fail; - } - } +fail: + av_freep(&fn_dup); + return ret; +} - if (hls->segment_filename) { - hls->basename = av_strdup(hls->segment_filename); - if (!hls->basename) { - ret = AVERROR(ENOMEM); - goto fail; - } - } else { - if (hls->flags & HLS_SINGLE_FILE) { - if (hls->segment_type == SEGMENT_TYPE_FMP4) { - pattern = ".m4s"; - } else { - pattern = ".ts"; - } - } +static int format_name(char *buf, int buf_len, int index) +{ + const char *proto, *dir; + char *orig_buf_dup = NULL, *mod_buf = NULL, *mod_buf_dup = NULL; + int ret = 0; - if (hls->use_localtime) { - basename_size = strlen(s->filename) + strlen(pattern_localtime_fmt) + 1; - } else { - basename_size = strlen(s->filename) + strlen(pattern) + 1; - } - hls->basename = av_malloc(basename_size); - if (!hls->basename) { - ret = AVERROR(ENOMEM); - goto fail; - } + if (!av_stristr(buf, "%v")) + return ret; - av_strlcpy(hls->basename, s->filename, basename_size); + orig_buf_dup = av_strdup(buf); + if (!orig_buf_dup) { + ret = AVERROR(ENOMEM); + goto fail; + } - p = strrchr(hls->basename, '.'); - if (p) - *p = '\0'; - if (hls->use_localtime) { - av_strlcat(hls->basename, pattern_localtime_fmt, basename_size); - } else { - av_strlcat(hls->basename, pattern, basename_size); - } + if (replace_int_data_in_filename(&mod_buf, orig_buf_dup, 'v', index) < 1) { + ret = AVERROR(EINVAL); + goto fail; } + av_strlcpy(buf, mod_buf, buf_len); - if (av_strcasecmp(hls->fmp4_init_filename, "init.mp4")) { - int fmp4_init_filename_len = strlen(hls->fmp4_init_filename) + 1; - hls->base_output_dirname = av_malloc(fmp4_init_filename_len); - if (!hls->base_output_dirname) { + proto = avio_find_protocol_name(orig_buf_dup); + dir = av_dirname(orig_buf_dup); + + /* if %v is present in the file's directory, create sub-directory */ + if (av_stristr(dir, "%v") && proto && !strcmp(proto, "file")) { + mod_buf_dup = av_strdup(buf); + if (!mod_buf_dup) { ret = AVERROR(ENOMEM); goto fail; } - av_strlcpy(hls->base_output_dirname, hls->fmp4_init_filename, fmp4_init_filename_len); - } else { - hls->base_output_dirname = av_malloc(basename_size); - if (!hls->base_output_dirname) { - ret = AVERROR(ENOMEM); + + dir = av_dirname(mod_buf_dup); + if (mkdir_p(dir) == -1 && errno != EEXIST) { + ret = AVERROR(errno); goto fail; } + } - av_strlcpy(hls->base_output_dirname, s->filename, basename_size); - p = strrchr(hls->base_output_dirname, '/'); - if (p) { - *(p + 1) = '\0'; - av_strlcat(hls->base_output_dirname, hls->fmp4_init_filename, basename_size); - } else { - av_strlcpy(hls->base_output_dirname, hls->fmp4_init_filename, basename_size); - } +fail: + av_freep(&orig_buf_dup); + av_freep(&mod_buf_dup); + av_freep(&mod_buf); + return ret; +} + +static int get_nth_codec_stream_index(AVFormatContext *s, + enum AVMediaType codec_type, + int stream_id) +{ + unsigned int stream_index, cnt; + if (stream_id < 0 || stream_id > s->nb_streams - 1) + return -1; + cnt = 0; + for (stream_index = 0; stream_index < s->nb_streams; stream_index++) { + if (s->streams[stream_index]->codecpar->codec_type != codec_type) + continue; + if (cnt == stream_id) + return stream_index; + cnt++; } + return -1; +} - if (!hls->use_localtime) { - ret = sls_flag_check_duration_size_index(hls); - if (ret < 0) { - goto fail; +static int parse_variant_stream_mapstring(AVFormatContext *s) +{ + HLSContext *hls = s->priv_data; + VariantStream *vs; + int stream_index; + enum AVMediaType codec_type; + int nb_varstreams, nb_streams; + char *p, *q, *saveptr1, *saveptr2, *varstr, *keyval; + const char *val; + + /** + * Expected format for var_stream_map string is as below: + * "a:0,v:0 a:1,v:1" + * "a:0,agroup:a0 a:1,agroup:a1 v:0,agroup:a0 v:1,agroup:a1" + * This string specifies how to group the audio, video and subtitle streams + * into different variant streams. The variant stream groups are separated + * by space. + * + * a:, v:, s: are keys to specify audio, video and subtitle streams + * respectively. Allowed values are 0 to 9 digits (limited just based on + * practical usage) + * + * agroup: is key to specify audio group. A string can be given as value. + */ + p = av_strdup(hls->var_stream_map); + q = p; + while(av_strtok(q, " \t", &saveptr1)) { + q = NULL; + hls->nb_varstreams++; + } + av_freep(&p); + + hls->var_streams = av_mallocz(sizeof(*hls->var_streams) * hls->nb_varstreams); + if (!hls->var_streams) + return AVERROR(ENOMEM); + + p = hls->var_stream_map; + nb_varstreams = 0; + while (varstr = av_strtok(p, " \t", &saveptr1)) { + p = NULL; + + if (nb_varstreams < hls->nb_varstreams) { + vs = &(hls->var_streams[nb_varstreams]); + vs->var_stream_idx = nb_varstreams; + nb_varstreams++; + } else + return AVERROR(EINVAL); + + q = varstr; + while (q < varstr + strlen(varstr)) { + if (!av_strncasecmp(q, "a:", 2) || !av_strncasecmp(q, "v:", 2) || + !av_strncasecmp(q, "s:", 2)) + vs->nb_streams++; + q++; } - } else { - ret = sls_flag_check_duration_size(hls); - if (ret < 0) { - goto fail; + vs->streams = av_mallocz(sizeof(AVStream *) * vs->nb_streams); + if (!vs->streams) + return AVERROR(ENOMEM); + + nb_streams = 0; + while (keyval = av_strtok(varstr, ",", &saveptr2)) { + varstr = NULL; + + if (av_strstart(keyval, "agroup:", &val)) { + vs->agroup = av_strdup(val); + if (!vs->agroup) + return AVERROR(ENOMEM); + continue; + } else if (av_strstart(keyval, "ccgroup:", &val)) { + vs->ccgroup = av_strdup(val); + if (!vs->ccgroup) + return AVERROR(ENOMEM); + continue; + } else if (av_strstart(keyval, "v:", &val)) { + codec_type = AVMEDIA_TYPE_VIDEO; + } else if (av_strstart(keyval, "a:", &val)) { + codec_type = AVMEDIA_TYPE_AUDIO; + } else if (av_strstart(keyval, "s:", &val)) { + codec_type = AVMEDIA_TYPE_SUBTITLE; + } else { + av_log(s, AV_LOG_ERROR, "Invalid keyval %s\n", keyval); + return AVERROR(EINVAL); + } + + stream_index = -1; + if (av_isdigit(*val)) + stream_index = get_nth_codec_stream_index (s, codec_type, + atoi(val)); + + if (stream_index >= 0 && nb_streams < vs->nb_streams) { + vs->streams[nb_streams++] = s->streams[stream_index]; + } else { + av_log(s, AV_LOG_ERROR, "Unable to map stream at %s\n", keyval); + return AVERROR(EINVAL); + } } } - if(hls->has_subtitle) { + av_log(s, AV_LOG_DEBUG, "Number of variant streams %d\n", + hls->nb_varstreams); - if (hls->flags & HLS_SINGLE_FILE) - vtt_pattern = ".vtt"; - vtt_basename_size = strlen(s->filename) + strlen(vtt_pattern) + 1; - hls->vtt_basename = av_malloc(vtt_basename_size); - if (!hls->vtt_basename) { - ret = AVERROR(ENOMEM); - goto fail; + return 0; +} + +static int parse_cc_stream_mapstring(AVFormatContext *s) +{ + HLSContext *hls = s->priv_data; + int nb_ccstreams; + char *p, *q, *ccstr, *keyval; + char *saveptr1 = NULL, *saveptr2 = NULL; + const char *val; + ClosedCaptionsStream *ccs; + + p = av_strdup(hls->cc_stream_map); + q = p; + while(av_strtok(q, " \t", &saveptr1)) { + q = NULL; + hls->nb_ccstreams++; + } + av_freep(&p); + + hls->cc_streams = av_mallocz(sizeof(*hls->cc_streams) * hls->nb_ccstreams); + if (!hls->cc_streams) + return AVERROR(ENOMEM); + + p = hls->cc_stream_map; + nb_ccstreams = 0; + while (ccstr = av_strtok(p, " \t", &saveptr1)) { + p = NULL; + + if (nb_ccstreams < hls->nb_ccstreams) + ccs = &(hls->cc_streams[nb_ccstreams++]); + else + return AVERROR(EINVAL); + + while (keyval = av_strtok(ccstr, ",", &saveptr2)) { + ccstr = NULL; + + if (av_strstart(keyval, "ccgroup:", &val)) { + ccs->ccgroup = av_strdup(val); + if (!ccs->ccgroup) + return AVERROR(ENOMEM); + } else if (av_strstart(keyval, "instreamid:", &val)) { + ccs->instreamid = av_strdup(val); + if (!ccs->instreamid) + return AVERROR(ENOMEM); + } else if (av_strstart(keyval, "language:", &val)) { + ccs->language = av_strdup(val); + if (!ccs->language) + return AVERROR(ENOMEM); + } else { + av_log(s, AV_LOG_ERROR, "Invalid keyval %s\n", keyval); + return AVERROR(EINVAL); + } } - hls->vtt_m3u8_name = av_malloc(vtt_basename_size); - if (!hls->vtt_m3u8_name ) { - ret = AVERROR(ENOMEM); - goto fail; + + if (!ccs->ccgroup || !ccs->instreamid) { + av_log(s, AV_LOG_ERROR, "Insufficient parameters in cc stream map string\n"); + return AVERROR(EINVAL); } - av_strlcpy(hls->vtt_basename, s->filename, vtt_basename_size); - p = strrchr(hls->vtt_basename, '.'); - if (p) - *p = '\0'; - if( hls->subtitle_filename ) { - strcpy(hls->vtt_m3u8_name, hls->subtitle_filename); + if (av_strstart(ccs->instreamid, "CC", &val)) { + if(atoi(val) < 1 || atoi(val) > 4) { + av_log(s, AV_LOG_ERROR, "Invalid instream ID CC index %d in %s, range 1-4\n", + atoi(val), ccs->instreamid); + return AVERROR(EINVAL); + } + } else if (av_strstart(ccs->instreamid, "SERVICE", &val)) { + if(atoi(val) < 1 || atoi(val) > 63) { + av_log(s, AV_LOG_ERROR, "Invalid instream ID SERVICE index %d in %s, range 1-63 \n", + atoi(val), ccs->instreamid); + return AVERROR(EINVAL); + } } else { - strcpy(hls->vtt_m3u8_name, hls->vtt_basename); - av_strlcat(hls->vtt_m3u8_name, "_vtt.m3u8", vtt_basename_size); + av_log(s, AV_LOG_ERROR, "Invalid instream ID %s, supported are CCn or SERIVICEn\n", + ccs->instreamid); + return AVERROR(EINVAL); } - av_strlcat(hls->vtt_basename, vtt_pattern, vtt_basename_size); } - if ((hls->flags & HLS_SINGLE_FILE) && (hls->segment_type == SEGMENT_TYPE_FMP4)) { - hls->fmp4_init_filename = av_strdup(hls->basename); - if (!hls->fmp4_init_filename) { - ret = AVERROR(ENOMEM); - goto fail; - } + return 0; +} + +static int update_variant_stream_info(AVFormatContext *s) { + HLSContext *hls = s->priv_data; + unsigned int i; + int ret = 0; + + if (hls->cc_stream_map) { + ret = parse_cc_stream_mapstring(s); + if (ret < 0) + return ret; } - if ((ret = hls_mux_init(s)) < 0) - goto fail; + if (hls->var_stream_map) { + return parse_variant_stream_mapstring(s); + } else { + //By default, a single variant stream with all the codec streams is created + hls->nb_varstreams = 1; + hls->var_streams = av_mallocz(sizeof(*hls->var_streams) * + hls->nb_varstreams); + if (!hls->var_streams) + return AVERROR(ENOMEM); + + hls->var_streams[0].var_stream_idx = 0; + hls->var_streams[0].nb_streams = s->nb_streams; + hls->var_streams[0].streams = av_mallocz(sizeof(AVStream *) * + hls->var_streams[0].nb_streams); + if (!hls->var_streams[0].streams) + return AVERROR(ENOMEM); - if (hls->flags & HLS_APPEND_LIST) { - parse_playlist(s, s->filename); - hls->discontinuity = 1; - if (hls->init_time > 0) { - av_log(s, AV_LOG_WARNING, "append_list mode does not support hls_init_time," - " hls_init_time value will have no effect\n"); - hls->init_time = 0; - hls->recording_time = hls->time * AV_TIME_BASE; + //by default, the first available ccgroup is mapped to the variant stream + if (hls->nb_ccstreams) { + hls->var_streams[0].ccgroup = av_strdup(hls->cc_streams[0].ccgroup); + if (!hls->var_streams[0].ccgroup) + return AVERROR(ENOMEM); } + + for (i = 0; i < s->nb_streams; i++) + hls->var_streams[0].streams[i] = s->streams[i]; } + return 0; +} + +static int update_master_pl_info(AVFormatContext *s) { + HLSContext *hls = s->priv_data; + const char *dir; + char *fn1= NULL, *fn2 = NULL; + int ret = 0; - if (hls->segment_type != SEGMENT_TYPE_FMP4 || hls->flags & HLS_SINGLE_FILE) { - if ((ret = hls_start(s)) < 0) + fn1 = av_strdup(s->url); + if (!fn1) { + ret = AVERROR(ENOMEM); + goto fail; + } + + dir = av_dirname(fn1); + + /** + * if output file's directory has %v, variants are created in sub-directories + * then master is created at the sub-directories level + */ + if (dir && av_stristr(av_basename(dir), "%v")) { + fn2 = av_strdup(dir); + if (!fn2) { + ret = AVERROR(ENOMEM); goto fail; + } + dir = av_dirname(fn2); } - av_dict_copy(&options, hls->format_options, 0); - ret = avformat_write_header(hls->avf, &options); - if (av_dict_count(options)) { - av_log(s, AV_LOG_ERROR, "Some of provided format options in '%s' are not recognized\n", hls->format_options_str); - ret = AVERROR(EINVAL); + if (dir && strcmp(dir, ".")) + hls->master_m3u8_url = av_append_path_component(dir, hls->master_pl_name); + else + hls->master_m3u8_url = av_strdup(hls->master_pl_name); + + if (!hls->master_m3u8_url) { + ret = AVERROR(ENOMEM); goto fail; } - //av_assert0(s->nb_streams == hls->avf->nb_streams); - for (i = 0; i < s->nb_streams; i++) { - AVStream *inner_st; - AVStream *outer_st = s->streams[i]; - if (hls->max_seg_size > 0) { - if ((outer_st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && - (outer_st->codecpar->bit_rate > hls->max_seg_size)) { - av_log(s, AV_LOG_WARNING, "Your video bitrate is bigger than hls_segment_size, " - "(%"PRId64 " > %"PRId64 "), the result maybe not be what you want.", - outer_st->codecpar->bit_rate, hls->max_seg_size); - } +fail: + av_freep(&fn1); + av_freep(&fn2); + + return ret; +} + +static int hls_write_header(AVFormatContext *s) +{ + HLSContext *hls = s->priv_data; + int ret, i, j; + AVDictionary *options = NULL; + VariantStream *vs = NULL; + + for (i = 0; i < hls->nb_varstreams; i++) { + vs = &hls->var_streams[i]; + + av_dict_copy(&options, hls->format_options, 0); + ret = avformat_write_header(vs->avf, &options); + if (av_dict_count(options)) { + av_log(s, AV_LOG_ERROR, "Some of provided format options in '%s' are not recognized\n", hls->format_options_str); + ret = AVERROR(EINVAL); + av_dict_free(&options); + goto fail; } + av_dict_free(&options); + //av_assert0(s->nb_streams == hls->avf->nb_streams); + for (j = 0; j < vs->nb_streams; j++) { + AVStream *inner_st; + AVStream *outer_st = vs->streams[j]; + + if (hls->max_seg_size > 0) { + if ((outer_st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && + (outer_st->codecpar->bit_rate > hls->max_seg_size)) { + av_log(s, AV_LOG_WARNING, "Your video bitrate is bigger than hls_segment_size, " + "(%"PRId64 " > %"PRId64 "), the result maybe not be what you want.", + outer_st->codecpar->bit_rate, hls->max_seg_size); + } + } - if (outer_st->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) - inner_st = hls->avf->streams[i]; - else if (hls->vtt_avf) - inner_st = hls->vtt_avf->streams[0]; - else { - /* We have a subtitle stream, when the user does not want one */ - inner_st = NULL; - continue; + if (outer_st->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) + inner_st = vs->avf->streams[j]; + else if (vs->vtt_avf) + inner_st = vs->vtt_avf->streams[0]; + else { + /* We have a subtitle stream, when the user does not want one */ + inner_st = NULL; + continue; + } + avpriv_set_pts_info(outer_st, inner_st->pts_wrap_bits, inner_st->time_base.num, inner_st->time_base.den); + write_codec_attr(outer_st, vs); + + } + /* Update the Codec Attr string for the mapped audio groups */ + if (vs->has_video && vs->agroup) { + for (j = 0; j < hls->nb_varstreams; j++) { + VariantStream *vs_agroup = &(hls->var_streams[j]); + if (!vs_agroup->has_video && !vs_agroup->has_subtitle && + vs_agroup->agroup && + !av_strcasecmp(vs_agroup->agroup, vs->agroup)) { + write_codec_attr(vs_agroup->streams[0], vs); + } + } } - avpriv_set_pts_info(outer_st, inner_st->pts_wrap_bits, inner_st->time_base.num, inner_st->time_base.den); } fail: - av_dict_free(&options); - if (ret < 0) { - av_freep(&hls->fmp4_init_filename); - av_freep(&hls->basename); - av_freep(&hls->vtt_basename); - av_freep(&hls->key_basename); - if (hls->avf) - avformat_free_context(hls->avf); - if (hls->vtt_avf) - avformat_free_context(hls->vtt_avf); - - } return ret; } @@ -1590,116 +2140,191 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) HLSContext *hls = s->priv_data; AVFormatContext *oc = NULL; AVStream *st = s->streams[pkt->stream_index]; - int64_t end_pts = hls->recording_time * hls->number; + int64_t end_pts = 0; int is_ref_pkt = 1; - int ret = 0, can_split = 1; + int ret = 0, can_split = 1, i, j; int stream_index = 0; + int range_length = 0; + uint8_t *buffer = NULL; + VariantStream *vs = NULL; + + for (i = 0; i < hls->nb_varstreams; i++) { + vs = &hls->var_streams[i]; + for (j = 0; j < vs->nb_streams; j++) { + if (vs->streams[j] == st) { + if( st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE ) { + oc = vs->vtt_avf; + stream_index = 0; + } else { + oc = vs->avf; + stream_index = j; + } + break; + } + } + + if (oc) + break; + } + + if (!oc) { + av_log(s, AV_LOG_ERROR, "Unable to find mapping variant stream\n"); + return AVERROR(ENOMEM); + } + + end_pts = hls->recording_time * vs->number; - if (hls->sequence - hls->nb_entries > hls->start_sequence && hls->init_time > 0) { + if (vs->sequence - vs->nb_entries > hls->start_sequence && hls->init_time > 0) { /* reset end_pts, hls->recording_time at end of the init hls list */ - int init_list_dur = hls->init_time * hls->nb_entries * AV_TIME_BASE; - int after_init_list_dur = (hls->sequence - hls->nb_entries ) * hls->time * AV_TIME_BASE; + int init_list_dur = hls->init_time * vs->nb_entries * AV_TIME_BASE; + int after_init_list_dur = (vs->sequence - vs->nb_entries ) * hls->time * AV_TIME_BASE; hls->recording_time = hls->time * AV_TIME_BASE; end_pts = init_list_dur + after_init_list_dur ; } - if( st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE ) { - oc = hls->vtt_avf; - stream_index = 0; - } else { - oc = hls->avf; - stream_index = pkt->stream_index; - } - if (hls->start_pts == AV_NOPTS_VALUE) { - hls->start_pts = pkt->pts; - hls->end_pts = pkt->pts; + if (vs->start_pts == AV_NOPTS_VALUE) { + vs->start_pts = pkt->pts; } - if (hls->has_video) { + if (vs->has_video) { can_split = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && ((pkt->flags & AV_PKT_FLAG_KEY) || (hls->flags & HLS_SPLIT_BY_TIME)); - is_ref_pkt = st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO; + is_ref_pkt = (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && (pkt->stream_index == vs->reference_stream_index); } if (pkt->pts == AV_NOPTS_VALUE) is_ref_pkt = can_split = 0; if (is_ref_pkt) { - if (hls->new_start) { - hls->new_start = 0; - hls->duration = (double)(pkt->pts - hls->end_pts) + if (vs->end_pts == AV_NOPTS_VALUE) + vs->end_pts = pkt->pts; + if (vs->new_start) { + vs->new_start = 0; + vs->duration = (double)(pkt->pts - vs->end_pts) * st->time_base.num / st->time_base.den; - hls->dpp = (double)(pkt->duration) * st->time_base.num / st->time_base.den; + vs->dpp = (double)(pkt->duration) * st->time_base.num / st->time_base.den; } else { if (pkt->duration) { - hls->duration += (double)(pkt->duration) * st->time_base.num / st->time_base.den; + vs->duration += (double)(pkt->duration) * st->time_base.num / st->time_base.den; } else { av_log(s, AV_LOG_WARNING, "pkt->duration = 0, maybe the hls segment duration will not precise\n"); - hls->duration = (double)(pkt->pts - hls->end_pts) * st->time_base.num / st->time_base.den; + vs->duration = (double)(pkt->pts - vs->end_pts) * st->time_base.num / st->time_base.den; } } } - if (hls->fmp4_init_mode || can_split && av_compare_ts(pkt->pts - hls->start_pts, st->time_base, - end_pts, AV_TIME_BASE_Q) >= 0) { + + if (vs->packets_written && can_split && av_compare_ts(pkt->pts - vs->start_pts, st->time_base, + end_pts, AV_TIME_BASE_Q) >= 0) { int64_t new_start_pos; - char *old_filename = av_strdup(hls->avf->filename); + char *old_filename = NULL; int byterange_mode = (hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size > 0); - if (!old_filename) { - return AVERROR(ENOMEM); - } - - av_write_frame(hls->avf, NULL); /* Flush any buffered data */ + av_write_frame(vs->avf, NULL); /* Flush any buffered data */ - new_start_pos = avio_tell(hls->avf->pb); - hls->size = new_start_pos - hls->start_pos; + new_start_pos = avio_tell(vs->avf->pb); + if (hls->segment_type != SEGMENT_TYPE_FMP4) { + vs->size = new_start_pos - vs->start_pos; + } else { + vs->size = new_start_pos; + } + if (hls->segment_type == SEGMENT_TYPE_FMP4) { + if (!vs->init_range_length) { + avio_flush(oc->pb); + range_length = avio_close_dyn_buf(oc->pb, &buffer); + avio_write(vs->out, buffer, range_length); + vs->init_range_length = range_length; + avio_open_dyn_buf(&oc->pb); + vs->packets_written = 0; + vs->start_pos = range_length; + if (!byterange_mode) { + ff_format_io_close(s, &vs->out); + hlsenc_io_close(s, &vs->out, vs->base_output_dirname); + } + } + } else { + if (!byterange_mode) { + hlsenc_io_close(s, &oc->pb, oc->url); + } + } if (!byterange_mode) { - ff_format_io_close(s, &oc->pb); - if (hls->vtt_avf) { - ff_format_io_close(s, &hls->vtt_avf->pb); + if (vs->vtt_avf) { + hlsenc_io_close(s, &vs->vtt_avf->pb, vs->vtt_avf->url); } } - if ((hls->flags & HLS_TEMP_FILE) && oc->filename[0]) { + if ((hls->flags & HLS_TEMP_FILE) && oc->url[0]) { if (!(hls->flags & HLS_SINGLE_FILE) || (hls->max_seg_size <= 0)) - if ((hls->avf->oformat->priv_class && hls->avf->priv_data) && hls->segment_type != SEGMENT_TYPE_FMP4) - av_opt_set(hls->avf->priv_data, "mpegts_flags", "resend_headers", 0); + if ((vs->avf->oformat->priv_class && vs->avf->priv_data) && hls->segment_type != SEGMENT_TYPE_FMP4) + av_opt_set(vs->avf->priv_data, "mpegts_flags", "resend_headers", 0); hls_rename_temp_file(s, oc); } - if (hls->fmp4_init_mode) { - hls->number--; + if (vs->fmp4_init_mode) { + vs->number--; + } + + if (hls->segment_type == SEGMENT_TYPE_FMP4) { + if (hls->flags & HLS_SINGLE_FILE) { + ret = flush_dynbuf(vs, &range_length); + if (ret < 0) { + av_free(old_filename); + return ret; + } + vs->size = range_length; + } else { + ret = hlsenc_io_open(s, &vs->out, vs->avf->url, NULL); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Failed to open file '%s'\n", + vs->avf->url); + return ret; + } + write_styp(vs->out); + ret = flush_dynbuf(vs, &range_length); + if (ret < 0) { + return ret; + } + ff_format_io_close(s, &vs->out); + } } - if (!hls->fmp4_init_mode || byterange_mode) - ret = hls_append_segment(s, hls, hls->duration, hls->start_pos, hls->size); + old_filename = av_strdup(vs->avf->url); + if (!old_filename) { + return AVERROR(ENOMEM); + } - hls->start_pos = new_start_pos; - if (ret < 0) { - av_free(old_filename); - return ret; + if (vs->start_pos || hls->segment_type != SEGMENT_TYPE_FMP4) { + ret = hls_append_segment(s, hls, vs, vs->duration, vs->start_pos, vs->size); + vs->end_pts = pkt->pts; + vs->duration = 0; + if (ret < 0) { + av_free(old_filename); + return ret; + } } - hls->end_pts = pkt->pts; - hls->duration = 0; + if (hls->segment_type != SEGMENT_TYPE_FMP4) { + vs->start_pos = new_start_pos; + } else { + vs->start_pos += vs->size; + } - hls->fmp4_init_mode = 0; + vs->fmp4_init_mode = 0; if (hls->flags & HLS_SINGLE_FILE) { - hls->number++; + vs->number++; } else if (hls->max_seg_size > 0) { - if (hls->start_pos >= hls->max_seg_size) { - hls->sequence++; - sls_flag_file_rename(hls, old_filename); - ret = hls_start(s); - hls->start_pos = 0; + if (vs->start_pos >= hls->max_seg_size) { + vs->sequence++; + sls_flag_file_rename(hls, vs, old_filename); + ret = hls_start(s, vs); + vs->start_pos = 0; /* When split segment by byte, the duration is short than hls_time, * so it is not enough one segment duration as hls_time, */ - hls->number--; + vs->number--; } - hls->number++; + vs->number++; } else { - sls_flag_file_rename(hls, old_filename); - ret = hls_start(s); + sls_flag_file_rename(hls, vs, old_filename); + ret = hls_start(s, vs); } av_free(old_filename); @@ -1707,12 +2332,13 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) return ret; } - if (!hls->fmp4_init_mode || byterange_mode) - if ((ret = hls_window(s, 0)) < 0) { + if (!vs->fmp4_init_mode || byterange_mode) + if ((ret = hls_window(s, 0, vs)) < 0) { return ret; } } + vs->packets_written++; ret = ff_write_chained(oc, stream_index, pkt, s, 0); return ret; @@ -1721,55 +2347,454 @@ static int hls_write_packet(AVFormatContext *s, AVPacket *pkt) static int hls_write_trailer(struct AVFormatContext *s) { HLSContext *hls = s->priv_data; - AVFormatContext *oc = hls->avf; - AVFormatContext *vtt_oc = hls->vtt_avf; - char *old_filename = av_strdup(hls->avf->filename); + AVFormatContext *oc = NULL; + AVFormatContext *vtt_oc = NULL; + char *old_filename = NULL; + int i; + int ret = 0; + VariantStream *vs = NULL; - if (!old_filename) { - return AVERROR(ENOMEM); - } + for (i = 0; i < hls->nb_varstreams; i++) { + vs = &hls->var_streams[i]; + oc = vs->avf; + vtt_oc = vs->vtt_avf; + old_filename = av_strdup(vs->avf->url); - av_write_trailer(oc); - if (oc->pb) { - hls->size = avio_tell(hls->avf->pb) - hls->start_pos; - ff_format_io_close(s, &oc->pb); + if (!old_filename) { + return AVERROR(ENOMEM); + } + if ( hls->segment_type == SEGMENT_TYPE_FMP4) { + int range_length = 0; + if (!(hls->flags & HLS_SINGLE_FILE)) { + ret = hlsenc_io_open(s, &vs->out, vs->avf->url, NULL); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Failed to open file '%s'\n", vs->avf->url); + goto failed; + } + write_styp(vs->out); + } + ret = flush_dynbuf(vs, &range_length); + if (ret < 0) { + goto failed; + } + ff_format_io_close(s, &vs->out); + } - if ((hls->flags & HLS_TEMP_FILE) && oc->filename[0]) { - hls_rename_temp_file(s, oc); +failed: + av_write_trailer(oc); + if (oc->pb) { + if (hls->segment_type != SEGMENT_TYPE_FMP4) { + vs->size = avio_tell(vs->avf->pb) - vs->start_pos; + } else { + vs->size = avio_tell(vs->avf->pb); + } + if (hls->segment_type != SEGMENT_TYPE_FMP4) + ff_format_io_close(s, &oc->pb); + + if ((hls->flags & HLS_TEMP_FILE) && oc->url[0]) { + hls_rename_temp_file(s, oc); + av_free(old_filename); + old_filename = av_strdup(vs->avf->url); + + if (!old_filename) { + return AVERROR(ENOMEM); + } + } + + /* after av_write_trailer, then duration + 1 duration per packet */ + hls_append_segment(s, hls, vs, vs->duration + vs->dpp, vs->start_pos, vs->size); } - /* after av_write_trailer, then duration + 1 duration per packet */ - hls_append_segment(s, hls, hls->duration + hls->dpp, hls->start_pos, hls->size); - } + sls_flag_file_rename(hls, vs, old_filename); + + if (vtt_oc) { + if (vtt_oc->pb) + av_write_trailer(vtt_oc); + vs->size = avio_tell(vs->vtt_avf->pb) - vs->start_pos; + ff_format_io_close(s, &vtt_oc->pb); + } + av_freep(&vs->basename); + av_freep(&vs->base_output_dirname); + avformat_free_context(oc); + + vs->avf = NULL; + hls_window(s, 1, vs); + + av_freep(&vs->fmp4_init_filename); + if (vtt_oc) { + av_freep(&vs->vtt_basename); + av_freep(&vs->vtt_m3u8_name); + avformat_free_context(vtt_oc); + } - sls_flag_file_rename(hls, old_filename); + hls_free_segments(vs->segments); + hls_free_segments(vs->old_segments); + av_free(old_filename); + av_freep(&vs->m3u8_name); + av_freep(&vs->streams); + av_freep(&vs->agroup); + av_freep(&vs->ccgroup); + av_freep(&vs->baseurl); + } - if (vtt_oc) { - if (vtt_oc->pb) - av_write_trailer(vtt_oc); - hls->size = avio_tell(hls->vtt_avf->pb) - hls->start_pos; - ff_format_io_close(s, &vtt_oc->pb); + for (i = 0; i < hls->nb_ccstreams; i++) { + ClosedCaptionsStream *ccs = &hls->cc_streams[i]; + av_freep(&ccs->ccgroup); + av_freep(&ccs->instreamid); + av_freep(&ccs->language); } - av_freep(&hls->basename); - av_freep(&hls->base_output_dirname); + + ff_format_io_close(s, &hls->m3u8_out); + ff_format_io_close(s, &hls->sub_m3u8_out); av_freep(&hls->key_basename); - avformat_free_context(oc); + av_freep(&hls->var_streams); + av_freep(&hls->cc_streams); + av_freep(&hls->master_m3u8_url); + return 0; +} - hls->avf = NULL; - hls_window(s, 1); - av_freep(&hls->fmp4_init_filename); - if (vtt_oc) { - av_freep(&hls->vtt_basename); - av_freep(&hls->vtt_m3u8_name); - avformat_free_context(vtt_oc); +static int hls_init(AVFormatContext *s) +{ + int ret = 0; + int i = 0; + int j = 0; + HLSContext *hls = s->priv_data; + const char *pattern = "%d.ts"; + VariantStream *vs = NULL; + int basename_size = 0; + const char *pattern_localtime_fmt = get_default_pattern_localtime_fmt(s); + const char *vtt_pattern = "%d.vtt"; + char *p = NULL; + int vtt_basename_size = 0; + int fmp4_init_filename_len = strlen(hls->fmp4_init_filename) + 1; + + ret = update_variant_stream_info(s); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Variant stream info update failed with status %x\n", + ret); + goto fail; + } + //TODO: Updates needed to encryption functionality with periodic re-key when more than one variant streams are present + if (hls->nb_varstreams > 1 && hls->flags & HLS_PERIODIC_REKEY) { + ret = AVERROR(EINVAL); + av_log(s, AV_LOG_ERROR, "Periodic re-key not supported when more than one variant streams are present\n"); + goto fail; } - hls_free_segments(hls->segments); - hls_free_segments(hls->old_segments); - av_free(old_filename); - return 0; + ret = validate_name(hls->nb_varstreams, s->url); + if (ret < 0) + goto fail; + + if (hls->segment_filename) { + ret = validate_name(hls->nb_varstreams, hls->segment_filename); + if (ret < 0) + goto fail; + } + + if (av_strcasecmp(hls->fmp4_init_filename, "init.mp4")) { + ret = validate_name(hls->nb_varstreams, hls->fmp4_init_filename); + if (ret < 0) + goto fail; + } + + if (hls->subtitle_filename) { + ret = validate_name(hls->nb_varstreams, hls->subtitle_filename); + if (ret < 0) + goto fail; + } + + if (hls->master_pl_name) { + ret = update_master_pl_info(s); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Master stream info update failed with status %x\n", + ret); + goto fail; + } + } + + if (hls->segment_type == SEGMENT_TYPE_FMP4) { + pattern = "%d.m4s"; + } + if ((hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH) || + (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_FORMATTED_DATETIME)) { + time_t t = time(NULL); // we will need it in either case + if (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH) { + hls->start_sequence = (int64_t)t; + } else if (hls->start_sequence_source_type == HLS_START_SEQUENCE_AS_FORMATTED_DATETIME) { + char b[15]; + struct tm *p, tmbuf; + if (!(p = localtime_r(&t, &tmbuf))) + return AVERROR(ENOMEM); + if (!strftime(b, sizeof(b), "%Y%m%d%H%M%S", p)) + return AVERROR(ENOMEM); + hls->start_sequence = strtoll(b, NULL, 10); + } + av_log(hls, AV_LOG_DEBUG, "start_number evaluated to %"PRId64"\n", hls->start_sequence); + } + + hls->recording_time = (hls->init_time ? hls->init_time : hls->time) * AV_TIME_BASE; + for (i = 0; i < hls->nb_varstreams; i++) { + vs = &hls->var_streams[i]; + + vs->m3u8_name = av_strdup(s->url); + if (!vs->m3u8_name ) { + ret = AVERROR(ENOMEM); + goto fail; + } + ret = format_name(vs->m3u8_name, strlen(s->url) + 1, i); + if (ret < 0) + goto fail; + + vs->sequence = hls->start_sequence; + vs->start_pts = AV_NOPTS_VALUE; + vs->end_pts = AV_NOPTS_VALUE; + vs->current_segment_final_filename_fmt[0] = '\0'; + + if (hls->flags & HLS_SPLIT_BY_TIME && hls->flags & HLS_INDEPENDENT_SEGMENTS) { + // Independent segments cannot be guaranteed when splitting by time + hls->flags &= ~HLS_INDEPENDENT_SEGMENTS; + av_log(s, AV_LOG_WARNING, + "'split_by_time' and 'independent_segments' cannot be enabled together. " + "Disabling 'independent_segments' flag\n"); + } + + if (hls->flags & HLS_PROGRAM_DATE_TIME) { + time_t now0; + time(&now0); + vs->initial_prog_date_time = now0; + } + if (hls->format_options_str) { + ret = av_dict_parse_string(&hls->format_options, hls->format_options_str, "=", ":", 0); + if (ret < 0) { + av_log(s, AV_LOG_ERROR, "Could not parse format options list '%s'\n", hls->format_options_str); + goto fail; + } + } + + for (j = 0; j < vs->nb_streams; j++) { + vs->has_video += vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO; + /* Get one video stream to reference for split segments + * so use the first video stream index. */ + if ((vs->has_video == 1) && (vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)) { + vs->reference_stream_index = vs->streams[j]->index; + } + vs->has_subtitle += vs->streams[j]->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE; + } + + if (vs->has_video > 1) + av_log(s, AV_LOG_WARNING, "More than a single video stream present, expect issues decoding it.\n"); + if (hls->segment_type == SEGMENT_TYPE_FMP4) { + vs->oformat = av_guess_format("mp4", NULL, NULL); + } else { + vs->oformat = av_guess_format("mpegts", NULL, NULL); + } + + if (!vs->oformat) { + ret = AVERROR_MUXER_NOT_FOUND; + goto fail; + } + + if (vs->has_subtitle) { + vs->vtt_oformat = av_guess_format("webvtt", NULL, NULL); + if (!vs->oformat) { + ret = AVERROR_MUXER_NOT_FOUND; + goto fail; + } + } + if (hls->segment_filename) { + basename_size = strlen(hls->segment_filename) + 1; + vs->basename = av_malloc(basename_size); + if (!vs->basename) { + ret = AVERROR(ENOMEM); + goto fail; + } + + av_strlcpy(vs->basename, hls->segment_filename, basename_size); + ret = format_name(vs->basename, basename_size, i); + if (ret < 0) + goto fail; + } else { + if (hls->flags & HLS_SINGLE_FILE) { + if (hls->segment_type == SEGMENT_TYPE_FMP4) { + pattern = ".m4s"; + } else { + pattern = ".ts"; + } + } + + if (hls->use_localtime) { + basename_size = strlen(vs->m3u8_name) + strlen(pattern_localtime_fmt) + 1; + } else { + basename_size = strlen(vs->m3u8_name) + strlen(pattern) + 1; + } + + vs->basename = av_malloc(basename_size); + if (!vs->basename) { + ret = AVERROR(ENOMEM); + goto fail; + } + + av_strlcpy(vs->basename, vs->m3u8_name, basename_size); + + p = strrchr(vs->basename, '.'); + if (p) + *p = '\0'; + if (hls->use_localtime) { + av_strlcat(vs->basename, pattern_localtime_fmt, basename_size); + } else { + av_strlcat(vs->basename, pattern, basename_size); + } + } + + if (hls->segment_type == SEGMENT_TYPE_FMP4) { + if (hls->nb_varstreams > 1) + fmp4_init_filename_len += strlen(POSTFIX_PATTERN); + if (hls->flags & HLS_SINGLE_FILE) { + vs->fmp4_init_filename = av_strdup(vs->basename); + if (!vs->fmp4_init_filename) { + ret = AVERROR(ENOMEM); + goto fail; + } + } else { + vs->fmp4_init_filename = av_malloc(fmp4_init_filename_len); + if (!vs->fmp4_init_filename ) { + ret = AVERROR(ENOMEM); + goto fail; + } + av_strlcpy(vs->fmp4_init_filename, hls->fmp4_init_filename, + fmp4_init_filename_len); + if (hls->nb_varstreams > 1) { + ret = append_postfix(vs->fmp4_init_filename, fmp4_init_filename_len, i); + if (ret < 0) + goto fail; + } + + fmp4_init_filename_len = strlen(vs->m3u8_name) + + strlen(vs->fmp4_init_filename) + 1; + + vs->base_output_dirname = av_malloc(fmp4_init_filename_len); + if (!vs->base_output_dirname) { + ret = AVERROR(ENOMEM); + goto fail; + } + + av_strlcpy(vs->base_output_dirname, vs->m3u8_name, + fmp4_init_filename_len); + p = strrchr(vs->base_output_dirname, '/'); + if (p) { + *(p + 1) = '\0'; + av_strlcat(vs->base_output_dirname, vs->fmp4_init_filename, + fmp4_init_filename_len); + } else { + av_strlcpy(vs->base_output_dirname, vs->fmp4_init_filename, + fmp4_init_filename_len); + } + } + } + + if (!hls->use_localtime) { + ret = sls_flag_check_duration_size_index(hls); + if (ret < 0) { + goto fail; + } + } else { + ret = sls_flag_check_duration_size(hls, vs); + if (ret < 0) { + goto fail; + } + } + if (vs->has_subtitle) { + + if (hls->flags & HLS_SINGLE_FILE) + vtt_pattern = ".vtt"; + vtt_basename_size = strlen(vs->m3u8_name) + strlen(vtt_pattern) + 1; + + vs->vtt_basename = av_malloc(vtt_basename_size); + if (!vs->vtt_basename) { + ret = AVERROR(ENOMEM); + goto fail; + } + vs->vtt_m3u8_name = av_malloc(vtt_basename_size); + if (!vs->vtt_m3u8_name ) { + ret = AVERROR(ENOMEM); + goto fail; + } + av_strlcpy(vs->vtt_basename, vs->m3u8_name, vtt_basename_size); + p = strrchr(vs->vtt_basename, '.'); + if (p) + *p = '\0'; + + if ( hls->subtitle_filename ) { + strcpy(vs->vtt_m3u8_name, hls->subtitle_filename); + ret = format_name(vs->vtt_m3u8_name, vtt_basename_size, i); + if (ret < 0) + goto fail; + } else { + strcpy(vs->vtt_m3u8_name, vs->vtt_basename); + av_strlcat(vs->vtt_m3u8_name, "_vtt.m3u8", vtt_basename_size); + } + av_strlcat(vs->vtt_basename, vtt_pattern, vtt_basename_size); + } + + if (hls->baseurl) { + vs->baseurl = av_strdup(hls->baseurl); + if (!vs->baseurl) { + ret = AVERROR(ENOMEM); + goto fail; + } + } + + if ((ret = hls_mux_init(s, vs)) < 0) + goto fail; + + if (hls->flags & HLS_APPEND_LIST) { + parse_playlist(s, vs->m3u8_name, vs); + vs->discontinuity = 1; + if (hls->init_time > 0) { + av_log(s, AV_LOG_WARNING, "append_list mode does not support hls_init_time," + " hls_init_time value will have no effect\n"); + hls->init_time = 0; + hls->recording_time = hls->time * AV_TIME_BASE; + } + } + + if ((ret = hls_start(s, vs)) < 0) + goto fail; + } + +fail: + if (ret < 0) { + av_freep(&hls->key_basename); + for (i = 0; i < hls->nb_varstreams && hls->var_streams; i++) { + vs = &hls->var_streams[i]; + av_freep(&vs->basename); + av_freep(&vs->vtt_basename); + av_freep(&vs->fmp4_init_filename); + av_freep(&vs->m3u8_name); + av_freep(&vs->vtt_m3u8_name); + av_freep(&vs->streams); + av_freep(&vs->agroup); + av_freep(&vs->ccgroup); + av_freep(&vs->baseurl); + if (vs->avf) + avformat_free_context(vs->avf); + if (vs->vtt_avf) + avformat_free_context(vs->vtt_avf); + } + for (i = 0; i < hls->nb_ccstreams; i++) { + ClosedCaptionsStream *ccs = &hls->cc_streams[i]; + av_freep(&ccs->ccgroup); + av_freep(&ccs->instreamid); + av_freep(&ccs->language); + } + av_freep(&hls->var_streams); + av_freep(&hls->cc_streams); + av_freep(&hls->master_m3u8_url); + } + + return ret; } #define OFFSET(x) offsetof(HLSContext, x) @@ -1779,6 +2804,7 @@ static const AVOption options[] = { {"hls_time", "set segment length in seconds", OFFSET(time), AV_OPT_TYPE_FLOAT, {.dbl = 2}, 0, FLT_MAX, E}, {"hls_init_time", "set segment length in seconds at init list", OFFSET(init_time), AV_OPT_TYPE_FLOAT, {.dbl = 0}, 0, FLT_MAX, E}, {"hls_list_size", "set maximum number of playlist entries", OFFSET(max_nb_segments), AV_OPT_TYPE_INT, {.i64 = 5}, 0, INT_MAX, E}, + {"hls_delete_threshold", "set number of unreferenced segments to keep before deleting", OFFSET(hls_delete_threshold), AV_OPT_TYPE_INT, {.i64 = 1}, 1, INT_MAX, E}, {"hls_ts_options","set hls mpegts list of options for the container format used for hls", OFFSET(format_options_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, {"hls_vtt_options","set hls vtt list of options for the container format used for hls", OFFSET(vtt_format_options_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, #if FF_API_HLS_WRAP @@ -1812,6 +2838,7 @@ static const AVOption options[] = { {"second_level_segment_duration", "include segment duration in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SECOND_LEVEL_SEGMENT_DURATION }, 0, UINT_MAX, E, "flags"}, {"second_level_segment_size", "include segment size in segment filenames when use_localtime", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_SECOND_LEVEL_SEGMENT_SIZE }, 0, UINT_MAX, E, "flags"}, {"periodic_rekey", "reload keyinfo file periodically for re-keying", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_PERIODIC_REKEY }, 0, UINT_MAX, E, "flags"}, + {"independent_segments", "add EXT-X-INDEPENDENT-SEGMENTS, whenever applicable", 0, AV_OPT_TYPE_CONST, { .i64 = HLS_INDEPENDENT_SEGMENTS }, 0, UINT_MAX, E, "flags"}, {"use_localtime", "set filename expansion with strftime at segment creation", OFFSET(use_localtime), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, {"use_localtime_mkdir", "create last directory component in strftime-generated filename", OFFSET(use_localtime_mkdir), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, {"hls_playlist_type", "set the HLS playlist type", OFFSET(pl_type), AV_OPT_TYPE_INT, {.i64 = PLAYLIST_TYPE_NONE }, 0, PLAYLIST_TYPE_NB-1, E, "pl_type" }, @@ -1823,6 +2850,12 @@ static const AVOption options[] = { {"epoch", "seconds since epoch", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_START_SEQUENCE_AS_SECONDS_SINCE_EPOCH }, INT_MIN, INT_MAX, E, "start_sequence_source_type" }, {"datetime", "current datetime as YYYYMMDDhhmmss", 0, AV_OPT_TYPE_CONST, {.i64 = HLS_START_SEQUENCE_AS_FORMATTED_DATETIME }, INT_MIN, INT_MAX, E, "start_sequence_source_type" }, {"http_user_agent", "override User-Agent field in HTTP header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, + {"var_stream_map", "Variant stream map string", OFFSET(var_stream_map), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, + {"cc_stream_map", "Closed captions stream map string", OFFSET(cc_stream_map), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, + {"master_pl_name", "Create HLS master playlist with this name", OFFSET(master_pl_name), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, E}, + {"master_pl_publish_rate", "Publish master play list every after this many segment intervals", OFFSET(master_publish_rate), AV_OPT_TYPE_INT, {.i64 = 0}, 0, UINT_MAX, E}, + {"http_persistent", "Use persistent HTTP connections", OFFSET(http_persistent), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, E }, + {"timeout", "set timeout for socket I/O operations", OFFSET(timeout), AV_OPT_TYPE_DURATION, { .i64 = -1 }, -1, INT_MAX, .flags = E }, { NULL }, }; @@ -1843,6 +2876,7 @@ AVOutputFormat ff_hls_muxer = { .video_codec = AV_CODEC_ID_H264, .subtitle_codec = AV_CODEC_ID_WEBVTT, .flags = AVFMT_NOFILE | AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH, + .init = hls_init, .write_header = hls_write_header, .write_packet = hls_write_packet, .write_trailer = hls_write_trailer, diff --git a/libavformat/hlsplaylist.c b/libavformat/hlsplaylist.c new file mode 100644 index 0000000000000..efcbff0009db7 --- /dev/null +++ b/libavformat/hlsplaylist.c @@ -0,0 +1,161 @@ +/* + * Apple HTTP Live Streaming segmenter + * Copyright (c) 2012, Luca Barbato + * Copyright (c) 2017 Akamai Technologies, Inc. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" +#include + +#include "libavutil/time_internal.h" + +#include "avformat.h" +#include "hlsplaylist.h" + +void ff_hls_write_playlist_version(AVIOContext *out, int version) { + if (!out) + return; + avio_printf(out, "#EXTM3U\n"); + avio_printf(out, "#EXT-X-VERSION:%d\n", version); +} + +void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup, + char *filename, int name_id, int is_default) { + if (!out || !agroup || !filename) + return; + + avio_printf(out, "#EXT-X-MEDIA:TYPE=AUDIO,GROUP-ID=\"group_%s\"", agroup); + avio_printf(out, ",NAME=\"audio_%d\",DEFAULT=%s,URI=\"%s\"\n", name_id, + is_default ? "YES" : "NO", filename); +} + +void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, + int bandwidth, char *filename, char *agroup, + char *codecs, char *ccgroup) { + + if (!out || !filename) + return; + + if (!bandwidth) { + av_log(NULL, AV_LOG_WARNING, + "Bandwidth info not available, set audio and video bitrates\n"); + return; + } + + avio_printf(out, "#EXT-X-STREAM-INF:BANDWIDTH=%d", bandwidth); + if (st && st->codecpar->width > 0 && st->codecpar->height > 0) + avio_printf(out, ",RESOLUTION=%dx%d", st->codecpar->width, + st->codecpar->height); + if (codecs && strlen(codecs) > 0) + avio_printf(out, ",CODECS=\"%s\"", codecs); + if (agroup && strlen(agroup) > 0) + avio_printf(out, ",AUDIO=\"group_%s\"", agroup); + if (ccgroup && strlen(ccgroup) > 0) + avio_printf(out, ",CLOSED-CAPTIONS=\"%s\"", ccgroup); + avio_printf(out, "\n%s\n\n", filename); +} + +void ff_hls_write_playlist_header(AVIOContext *out, int version, int allowcache, + int target_duration, int64_t sequence, + uint32_t playlist_type) { + if (!out) + return; + ff_hls_write_playlist_version(out, version); + if (allowcache == 0 || allowcache == 1) { + avio_printf(out, "#EXT-X-ALLOW-CACHE:%s\n", allowcache == 0 ? "NO" : "YES"); + } + avio_printf(out, "#EXT-X-TARGETDURATION:%d\n", target_duration); + avio_printf(out, "#EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence); + av_log(NULL, AV_LOG_VERBOSE, "EXT-X-MEDIA-SEQUENCE:%"PRId64"\n", sequence); + + if (playlist_type == PLAYLIST_TYPE_EVENT) { + avio_printf(out, "#EXT-X-PLAYLIST-TYPE:EVENT\n"); + } else if (playlist_type == PLAYLIST_TYPE_VOD) { + avio_printf(out, "#EXT-X-PLAYLIST-TYPE:VOD\n"); + } +} + +void ff_hls_write_init_file(AVIOContext *out, char *filename, + int byterange_mode, int64_t size, int64_t pos) { + avio_printf(out, "#EXT-X-MAP:URI=\"%s\"", filename); + if (byterange_mode) { + avio_printf(out, ",BYTERANGE=\"%"PRId64"@%"PRId64"\"", size, pos); + } + avio_printf(out, "\n"); +} + +int ff_hls_write_file_entry(AVIOContext *out, int insert_discont, + int byterange_mode, + double duration, int round_duration, + int64_t size, int64_t pos, //Used only if HLS_SINGLE_FILE flag is set + char *baseurl, //Ignored if NULL + char *filename, double *prog_date_time) { + if (!out || !filename) + return AVERROR(EINVAL); + + if (insert_discont) { + avio_printf(out, "#EXT-X-DISCONTINUITY\n"); + } + if (round_duration) + avio_printf(out, "#EXTINF:%ld,\n", lrint(duration)); + else + avio_printf(out, "#EXTINF:%f,\n", duration); + if (byterange_mode) + avio_printf(out, "#EXT-X-BYTERANGE:%"PRId64"@%"PRId64"\n", size, pos); + + if (prog_date_time) { + time_t tt, wrongsecs; + int milli; + struct tm *tm, tmpbuf; + char buf0[128], buf1[128]; + tt = (int64_t)*prog_date_time; + milli = av_clip(lrint(1000*(*prog_date_time - tt)), 0, 999); + tm = localtime_r(&tt, &tmpbuf); + if (!strftime(buf0, sizeof(buf0), "%Y-%m-%dT%H:%M:%S", tm)) { + av_log(NULL, AV_LOG_DEBUG, "strftime error in ff_hls_write_file_entry\n"); + return AVERROR_UNKNOWN; + } + if (!strftime(buf1, sizeof(buf1), "%z", tm) || buf1[1]<'0' ||buf1[1]>'2') { + int tz_min, dst = tm->tm_isdst; + tm = gmtime_r(&tt, &tmpbuf); + tm->tm_isdst = dst; + wrongsecs = mktime(tm); + tz_min = (FFABS(wrongsecs - tt) + 30) / 60; + snprintf(buf1, sizeof(buf1), + "%c%02d%02d", + wrongsecs <= tt ? '+' : '-', + tz_min / 60, + tz_min % 60); + } + avio_printf(out, "#EXT-X-PROGRAM-DATE-TIME:%s.%03d%s\n", buf0, milli, buf1); + *prog_date_time += duration; + } + if (baseurl) + avio_printf(out, "%s", baseurl); + avio_printf(out, "%s\n", filename); + + return 0; +} + +void ff_hls_write_end_list (AVIOContext *out) { + if (!out) + return; + avio_printf(out, "#EXT-X-ENDLIST\n"); +} + diff --git a/libavformat/hlsplaylist.h b/libavformat/hlsplaylist.h new file mode 100644 index 0000000000000..5054b01c8fc53 --- /dev/null +++ b/libavformat/hlsplaylist.h @@ -0,0 +1,58 @@ +/* + * Apple HTTP Live Streaming segmenter + * Copyright (c) 2012, Luca Barbato + * Copyright (c) 2017 Akamai Technologies, Inc. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVFORMAT_HLSPLAYLIST_H +#define AVFORMAT_HLSPLAYLIST_H + +#include + +#include "libavutil/common.h" +#include "avformat.h" +#include "avio.h" + +typedef enum { + PLAYLIST_TYPE_NONE, + PLAYLIST_TYPE_EVENT, + PLAYLIST_TYPE_VOD, + PLAYLIST_TYPE_NB, +} PlaylistType; + +void ff_hls_write_playlist_version(AVIOContext *out, int version); +void ff_hls_write_audio_rendition(AVIOContext *out, char *agroup, + char *filename, int name_id, int is_default); +void ff_hls_write_stream_info(AVStream *st, AVIOContext *out, + int bandwidth, char *filename, char *agroup, + char *codecs, char *ccgroup); +void ff_hls_write_playlist_header(AVIOContext *out, int version, int allowcache, + int target_duration, int64_t sequence, + uint32_t playlist_type); +void ff_hls_write_init_file(AVIOContext *out, char *filename, + int byterange_mode, int64_t size, int64_t pos); +int ff_hls_write_file_entry(AVIOContext *out, int insert_discont, + int byterange_mode, + double duration, int round_duration, + int64_t size, int64_t pos, //Used only if HLS_SINGLE_FILE flag is set + char *baseurl, //Ignored if NULL + char *filename, double *prog_date_time); +void ff_hls_write_end_list (AVIOContext *out); + +#endif /* AVFORMAT_HLSPLAYLIST_H_ */ diff --git a/libavformat/hlsproto.c b/libavformat/hlsproto.c index 2b19ed0cf67a8..e7ef2d88ea8d0 100644 --- a/libavformat/hlsproto.c +++ b/libavformat/hlsproto.c @@ -69,14 +69,6 @@ typedef struct HLSContext { int64_t last_load_time; } HLSContext; -static int read_chomp_line(AVIOContext *s, char *buf, int maxlen) -{ - int len = ff_get_line(s, buf, maxlen); - while (len > 0 && av_isspace(buf[len - 1])) - buf[--len] = '\0'; - return len; -} - static void free_segment_list(HLSContext *s) { int i; @@ -122,7 +114,7 @@ static int parse_playlist(URLContext *h, const char *url) h->protocol_whitelist, h->protocol_blacklist)) < 0) return ret; - read_chomp_line(in, line, sizeof(line)); + ff_get_chomp_line(in, line, sizeof(line)); if (strcmp(line, "#EXTM3U")) { ret = AVERROR_INVALIDDATA; goto fail; @@ -131,7 +123,7 @@ static int parse_playlist(URLContext *h, const char *url) free_segment_list(s); s->finished = 0; while (!avio_feof(in)) { - read_chomp_line(in, line, sizeof(line)); + ff_get_chomp_line(in, line, sizeof(line)); if (av_strstart(line, "#EXT-X-STREAM-INF:", &ptr)) { struct variant_info info = {{0}}; is_variant = 1; diff --git a/libavformat/http.c b/libavformat/http.c index 668cd51986680..01535169db245 100644 --- a/libavformat/http.c +++ b/libavformat/http.c @@ -30,6 +30,7 @@ #include "libavutil/opt.h" #include "libavutil/time.h" #include "libavutil/parseutils.h" +#include "libavutil/application.h" #include "avformat.h" #include "http.h" @@ -66,6 +67,7 @@ typedef struct HTTPContext { int http_code; /* Used if "Transfer-Encoding: chunked" otherwise -1. */ uint64_t chunksize; + int chunkend; uint64_t off, end_off, filesize; char *location; HTTPAuthState auth_state; @@ -73,7 +75,9 @@ typedef struct HTTPContext { char *http_proxy; char *headers; char *mime_type; + char *http_version; char *user_agent; + char *referer; #if FF_API_HTTP_USER_AGENT char *user_agent_deprecated; #endif @@ -115,7 +119,6 @@ typedef struct HTTPContext { int reconnect; int reconnect_at_eof; int reconnect_streamed; - int reconnect_delay; int reconnect_delay_max; int listen; char *resource; @@ -123,6 +126,9 @@ typedef struct HTTPContext { int is_multi_client; HandshakeState handshake_step; int is_connected_server; + char *tcp_hook; + int64_t app_ctx_intptr; + AVApplicationContext *app_ctx; } HTTPContext; #define OFFSET(x) offsetof(HTTPContext, x) @@ -137,12 +143,14 @@ static const AVOption options[] = { { "headers", "set custom HTTP headers, can override built in default headers", OFFSET(headers), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E }, { "content_type", "set a specific content type for the POST messages", OFFSET(content_type), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D | E }, { "user_agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, { .str = DEFAULT_USER_AGENT }, 0, 0, D }, + { "referer", "override referer header", OFFSET(referer), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D }, #if FF_API_HTTP_USER_AGENT { "user-agent", "override User-Agent header", OFFSET(user_agent_deprecated), AV_OPT_TYPE_STRING, { .str = DEFAULT_USER_AGENT }, 0, 0, D }, #endif { "multiple_requests", "use persistent connections", OFFSET(multiple_requests), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, D | E }, { "post_data", "set custom HTTP post data", OFFSET(post_data), AV_OPT_TYPE_BINARY, .flags = D | E }, { "mime_type", "export the MIME type", OFFSET(mime_type), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY }, + { "http_version", "export the http response version", OFFSET(http_version), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_EXPORT | AV_OPT_FLAG_READONLY }, { "cookies", "set cookies to be sent in applicable future requests, use newline delimited Set-Cookie HTTP field value syntax", OFFSET(cookies), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, D }, { "icy", "request ICY metadata", OFFSET(icy), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, D }, { "icy_metadata_headers", "return ICY metadata headers", OFFSET(icy_metadata_headers), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, AV_OPT_FLAG_EXPORT }, @@ -163,6 +171,8 @@ static const AVOption options[] = { { "listen", "listen on HTTP", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, D | E }, { "resource", "The resource requested by a client", OFFSET(resource), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, E }, { "reply_code", "The http status code to return to a client", OFFSET(reply_code), AV_OPT_TYPE_INT, { .i64 = 200}, INT_MIN, 599, E}, + { "http-tcp-hook", "hook protocol on tcp", OFFSET(tcp_hook), AV_OPT_TYPE_STRING, { .str = "tcp" }, 0, 0, D | E }, + { "ijkapplication", "AVApplicationContext", OFFSET(app_ctx_intptr), AV_OPT_TYPE_INT64, { .i64 = 0 }, INT64_MIN, INT64_MAX, .flags = D }, { NULL } }; @@ -170,6 +180,7 @@ static int http_connect(URLContext *h, const char *path, const char *local_path, const char *hoststr, const char *auth, const char *proxyauth, int *new_location); static int http_read_header(URLContext *h, int *new_location); +static int http_shutdown(URLContext *h, int flags); void ff_http_init_auth_state(URLContext *dest, const URLContext *src) { @@ -189,8 +200,11 @@ static int http_open_cnx_internal(URLContext *h, AVDictionary **options) char path1[MAX_URL_SIZE]; char buf[1024], urlbuf[MAX_URL_SIZE]; int port, use_proxy, err, location_changed = 0; + char prev_location[4096]; HTTPContext *s = h->priv_data; + lower_proto = s->tcp_hook; + av_url_split(proto, sizeof(proto), auth, sizeof(auth), hostname, sizeof(hostname), &port, path1, sizeof(path1), s->location); @@ -201,6 +215,7 @@ static int http_open_cnx_internal(URLContext *h, AVDictionary **options) proxy_path && av_strstart(proxy_path, "http://", NULL); if (!strcmp(proto, "https")) { + av_dict_set_int(options, "fastopen", 0, 0); lower_proto = "tls"; use_proxy = 0; if (port < 0) @@ -227,6 +242,7 @@ static int http_open_cnx_internal(URLContext *h, AVDictionary **options) ff_url_join(buf, sizeof(buf), lower_proto, NULL, hostname, port, NULL); if (!s->hd) { + av_dict_set_int(options, "ijkapplication", (int64_t)(intptr_t)s->app_ctx, 0); err = ffurl_open_whitelist(&s->hd, buf, AVIO_FLAG_READ_WRITE, &h->interrupt_callback, options, h->protocol_whitelist, h->protocol_blacklist, h); @@ -234,6 +250,7 @@ static int http_open_cnx_internal(URLContext *h, AVDictionary **options) return err; } + av_strlcpy(prev_location, s->location, sizeof(prev_location)); err = http_connect(h, path, local_path, hoststr, auth, proxyauth, &location_changed); if (err < 0) @@ -304,7 +321,39 @@ int ff_http_do_new_request(URLContext *h, const char *uri) HTTPContext *s = h->priv_data; AVDictionary *options = NULL; int ret; + char hostname1[1024], hostname2[1024], proto1[10], proto2[10]; + int port1, port2; + + if (!h->prot || + !(!strcmp(h->prot->name, "http") || + !strcmp(h->prot->name, "https"))) + return AVERROR(EINVAL); + + av_url_split(proto1, sizeof(proto1), NULL, 0, + hostname1, sizeof(hostname1), &port1, + NULL, 0, s->location); + av_url_split(proto2, sizeof(proto2), NULL, 0, + hostname2, sizeof(hostname2), &port2, + NULL, 0, uri); + if (port1 != port2 || strncmp(hostname1, hostname2, sizeof(hostname2)) != 0) { + av_log(h, AV_LOG_ERROR, "Cannot reuse HTTP connection for different host: %s:%d != %s:%d\n", + hostname1, port1, + hostname2, port2 + ); + return AVERROR(EINVAL); + } + + if (!s->end_chunked_post) { + ret = http_shutdown(h, h->flags); + if (ret < 0) + return ret; + } + + if (s->willclose) + return AVERROR_EOF; + s->end_chunked_post = 0; + s->chunkend = 0; s->off = 0; s->icy_data_read = 0; av_free(s->location); @@ -312,6 +361,7 @@ int ff_http_do_new_request(URLContext *h, const char *uri) if (!s->location) return AVERROR(ENOMEM); + av_log(s, AV_LOG_INFO, "Opening \'%s\' for %s\n", uri, h->flags & AVIO_FLAG_WRITE ? "writing" : "reading"); ret = http_open_cnx(h, &options); av_dict_free(&options); return ret; @@ -487,6 +537,8 @@ static int http_open(URLContext *h, const char *uri, int flags, HTTPContext *s = h->priv_data; int ret; + s->app_ctx = (AVApplicationContext *)(intptr_t)s->app_ctx_intptr; + if( s->seekable == 1 ) h->is_streamed = 0; else @@ -516,7 +568,9 @@ static int http_open(URLContext *h, const char *uri, int flags, if (s->listen) { return http_listen(h, uri, flags, options); } + av_application_will_http_open(s->app_ctx, (void*)h, uri); ret = http_open_cnx(h, options); + av_application_did_http_open(s->app_ctx, (void*)h, uri, ret, s->http_code, s->filesize); if (ret < 0) av_dict_free(&s->chained_options); return ret; @@ -538,7 +592,11 @@ static int http_accept(URLContext *s, URLContext **c) goto fail; cc->hd = cl; cc->is_multi_client = 1; + return 0; fail: + if (c) { + ffurl_closep(c); + } return ret; } @@ -712,6 +770,9 @@ static int parse_set_cookie(const char *set_cookie, AVDictionary **dict) { char *param, *next_param, *cstr, *back; + if (!set_cookie[0]) + return 0; + if (!(cstr = av_strdup(set_cookie))) return AVERROR(EINVAL); @@ -719,6 +780,8 @@ static int parse_set_cookie(const char *set_cookie, AVDictionary **dict) back = &cstr[strlen(cstr)-1]; while (strchr(WHITESPACES, *back)) { *back='\0'; + if (back == cstr) + break; back--; } @@ -764,7 +827,7 @@ static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies) // if the cookie has already expired ignore it if (av_timegm(&new_tm) < av_gettime() / 1000000) { av_dict_free(&new_params); - return -1; + return 0; } // only replace an older cookie with the same name @@ -788,6 +851,7 @@ static int parse_cookie(HTTPContext *s, const char *p, AVDictionary **cookies) } } } + av_dict_free(&new_params); // duplicate the cookie name (dict will dupe the value) if (!(eql = strchr(p, '='))) return AVERROR(EINVAL); @@ -887,6 +951,14 @@ static int process_line(URLContext *h, char *line, int line_count, } av_log(h, AV_LOG_TRACE, "HTTP version string: %s\n", version); } else { + if (av_strncasecmp(p, "HTTP/1.0", 8) == 0) + s->willclose = 1; + while (*p != '/' && *p != '\0') + p++; + while (*p == '/') + p++; + av_freep(&s->http_version); + s->http_version = av_strndup(p, 3); while (!av_isspace(*p) && *p != '\0') p++; while (av_isspace(*p)) @@ -1107,6 +1179,7 @@ static int http_connect(URLContext *h, const char *path, const char *local_path, char headers[HTTP_HEADERS_SIZE] = ""; char *authstr = NULL, *proxyauthstr = NULL; uint64_t off = s->off; + uint64_t filesize = s->filesize; int len = 0; const char *method; int send_expect_100 = 0; @@ -1153,6 +1226,12 @@ static int http_connect(URLContext *h, const char *path, const char *local_path, if (!has_header(s->headers, "\r\nUser-Agent: ")) len += av_strlcatf(headers + len, sizeof(headers) - len, "User-Agent: %s\r\n", s->user_agent); + if (s->referer) { + /* set default headers if needed */ + if (!has_header(s->headers, "\r\nReferer: ")) + len += av_strlcatf(headers + len, sizeof(headers) - len, + "Referer: %s\r\n", s->referer); + } if (!has_header(s->headers, "\r\nAccept: ")) len += av_strlcpy(headers + len, "Accept: */*\r\n", sizeof(headers) - len); @@ -1268,6 +1347,15 @@ static int http_connect(URLContext *h, const char *path, const char *local_path, if (*new_location) s->off = off; + /* Some buggy servers may missing 'Content-Range' header for range request */ + if (off > 0 && s->off <= 0 && (off + s->filesize == filesize)) { + av_log(NULL, AV_LOG_WARNING, + "try to fix missing 'Content-Range' at server side (%"PRId64",%"PRId64") => (%"PRId64",%"PRId64")", + s->off, s->filesize, off, filesize); + s->off = off; + s->filesize = filesize; + } + err = (off == s->off) ? 0 : -1; done: av_freep(&authstr); @@ -1281,6 +1369,9 @@ static int http_buf_read(URLContext *h, uint8_t *buf, int size) int len; if (s->chunksize != UINT64_MAX) { + if (s->chunkend) { + return AVERROR_EOF; + } if (!s->chunksize) { char line[32]; int err; @@ -1293,7 +1384,7 @@ static int http_buf_read(URLContext *h, uint8_t *buf, int size) s->chunksize = strtoull(line, NULL, 16); av_log(h, AV_LOG_TRACE, - "Chunked encoding data size: %"PRIu64"'\n", + "Chunked encoding data size: %"PRIu64"\n", s->chunksize); if (!s->chunksize) @@ -1318,7 +1409,15 @@ static int http_buf_read(URLContext *h, uint8_t *buf, int size) uint64_t target_end = s->end_off ? s->end_off : s->filesize; if ((!s->willclose || s->chunksize == UINT64_MAX) && s->off >= target_end) return AVERROR_EOF; - len = ffurl_read(s->hd, buf, size); + + len = size; + if (s->filesize > 0 && s->filesize != UINT64_MAX && s->filesize != 2147483647) { + int64_t unread = s->filesize - s->off; + if (len > unread) + len = (int)unread; + } + if (len > 0) + len = ffurl_read(s->hd, buf, len); if (!len && (!s->willclose || s->chunksize == UINT64_MAX) && s->off < target_end) { av_log(h, AV_LOG_ERROR, "Stream ends prematurely at %"PRIu64", should be %"PRIu64"\n", @@ -1377,6 +1476,7 @@ static int http_read_stream(URLContext *h, uint8_t *buf, int size) HTTPContext *s = h->priv_data; int err, new_location, read_ret; int64_t seek_ret; + int reconnect_delay = 0; if (!s->hd) return AVERROR_EOF; @@ -1392,25 +1492,35 @@ static int http_read_stream(URLContext *h, uint8_t *buf, int size) return http_buf_read_compressed(h, buf, size); #endif /* CONFIG_ZLIB */ read_ret = http_buf_read(h, buf, size); - if ( (read_ret < 0 && s->reconnect && (!h->is_streamed || s->reconnect_streamed) && s->filesize > 0 && s->off < s->filesize) - || (read_ret == 0 && s->reconnect_at_eof && (!h->is_streamed || s->reconnect_streamed))) { + while (read_ret < 0) { uint64_t target = h->is_streamed ? 0 : s->off; - if (s->reconnect_delay > s->reconnect_delay_max) + if (read_ret == AVERROR_EXIT) + break; + + if (h->is_streamed && !s->reconnect_streamed) + break; + + if (!(s->reconnect && s->filesize > 0 && s->off < s->filesize) && + !(s->reconnect_at_eof && read_ret == AVERROR_EOF)) + break; + + if (reconnect_delay > s->reconnect_delay_max) return AVERROR(EIO); - av_log(h, AV_LOG_INFO, "Will reconnect at %"PRIu64" error=%s.\n", s->off, av_err2str(read_ret)); - av_usleep(1000U*1000*s->reconnect_delay); - s->reconnect_delay = 1 + 2*s->reconnect_delay; + av_log(h, AV_LOG_WARNING, "Will reconnect at %"PRIu64" in %d second(s), error=%s.\n", s->off, reconnect_delay, av_err2str(read_ret)); + err = ff_network_sleep_interruptible(1000U*1000*reconnect_delay, &h->interrupt_callback); + if (err != AVERROR(ETIMEDOUT)) + return err; + reconnect_delay = 1 + 2*reconnect_delay; seek_ret = http_seek_internal(h, target, SEEK_SET, 1); - if (seek_ret != target) { + if (seek_ret >= 0 && seek_ret != target) { av_log(h, AV_LOG_ERROR, "Failed to reconnect at %"PRIu64".\n", target); return read_ret; } read_ret = http_buf_read(h, buf, size); - } else - s->reconnect_delay = 0; + } return read_ret; } @@ -1610,7 +1720,9 @@ static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int fo s->hd = NULL; /* if it fails, continue on old connection */ + av_application_will_http_seek(s->app_ctx, (void*)h, s->location, off); if ((ret = http_open_cnx(h, &options)) < 0) { + av_application_did_http_seek(s->app_ctx, (void*)h, s->location, off, ret, s->http_code); av_dict_free(&options); memcpy(s->buffer, old_buf, old_buf_size); s->buf_ptr = s->buffer; @@ -1619,6 +1731,7 @@ static int64_t http_seek_internal(URLContext *h, int64_t off, int whence, int fo s->off = old_off; return ret; } + av_application_did_http_seek(s->app_ctx, (void*)h, s->location, off, ret, s->http_code); av_dict_free(&options); ffurl_close(old_hd); return off; @@ -1711,6 +1824,8 @@ static int http_proxy_open(URLContext *h, const char *uri, int flags) char *authstr; int new_loc; + s->app_ctx = (AVApplicationContext *)(intptr_t)s->app_ctx_intptr; + if( s->seekable == 1 ) h->is_streamed = 0; else @@ -1723,7 +1838,7 @@ static int http_proxy_open(URLContext *h, const char *uri, int flags) if (*path == '/') path++; - ff_url_join(lower_url, sizeof(lower_url), "tcp", NULL, hostname, port, + ff_url_join(lower_url, sizeof(lower_url), s->tcp_hook, NULL, hostname, port, NULL); redo: ret = ffurl_open_whitelist(&s->hd, lower_url, AVIO_FLAG_READ_WRITE, diff --git a/libavformat/id3v2.c b/libavformat/id3v2.c index 6c216ba7a251a..f7de26a1d8e54 100644 --- a/libavformat/id3v2.c +++ b/libavformat/id3v2.c @@ -33,6 +33,7 @@ #endif #include "libavutil/avstring.h" +#include "libavutil/bprint.h" #include "libavutil/dict.h" #include "libavutil/intreadwrite.h" #include "avio_internal.h" @@ -975,19 +976,21 @@ static void id3v2_parse(AVIOContext *pb, AVDictionary **metadata, } } if (unsync || tunsync) { - int64_t end = avio_tell(pb) + tlen; - uint8_t *b; - - b = buffer; - while (avio_tell(pb) < end && b - buffer < tlen && !pb->eof_reached) { - *b++ = avio_r8(pb); - if (*(b - 1) == 0xff && avio_tell(pb) < end - 1 && - b - buffer < tlen && - !pb->eof_reached ) { - uint8_t val = avio_r8(pb); - *b++ = val ? val : avio_r8(pb); - } + uint8_t *b = buffer; + uint8_t *t = buffer; + uint8_t *end = t + tlen; + + if (avio_read(pb, buffer, tlen) != tlen) { + av_log(s, AV_LOG_ERROR, "Failed to read tag data\n"); + goto seek; } + + while (t != end) { + *b++ = *t++; + if (t != end && t[-1] == 0xff && !t[0]) + t++; + } + ffio_init_context(&pb_local, buffer, b - buffer, 0, NULL, NULL, NULL, NULL); tlen = b - buffer; @@ -1224,3 +1227,50 @@ int ff_id3v2_parse_chapters(AVFormatContext *s, ID3v2ExtraMeta **extra_meta) av_freep(&chapters); return ret; } + +int ff_id3v2_parse_priv_dict(AVDictionary **metadata, ID3v2ExtraMeta **extra_meta) +{ + ID3v2ExtraMeta *cur; + int dict_flags = AV_DICT_DONT_OVERWRITE | AV_DICT_DONT_STRDUP_KEY | AV_DICT_DONT_STRDUP_VAL; + + for (cur = *extra_meta; cur; cur = cur->next) { + if (!strcmp(cur->tag, "PRIV")) { + ID3v2ExtraMetaPRIV *priv = cur->data; + AVBPrint bprint; + char *escaped, *key; + int i, ret; + + if ((key = av_asprintf(ID3v2_PRIV_METADATA_PREFIX "%s", priv->owner)) == NULL) { + return AVERROR(ENOMEM); + } + + av_bprint_init(&bprint, priv->datasize + 1, AV_BPRINT_SIZE_UNLIMITED); + + for (i = 0; i < priv->datasize; i++) { + if (priv->data[i] < 32 || priv->data[i] > 126 || priv->data[i] == '\\') { + av_bprintf(&bprint, "\\x%02x", priv->data[i]); + } else { + av_bprint_chars(&bprint, priv->data[i], 1); + } + } + + if ((ret = av_bprint_finalize(&bprint, &escaped)) < 0) { + av_free(key); + return ret; + } + + if ((ret = av_dict_set(metadata, key, escaped, dict_flags)) < 0) { + av_free(key); + av_free(escaped); + return ret; + } + } + } + + return 0; +} + +int ff_id3v2_parse_priv(AVFormatContext *s, ID3v2ExtraMeta **extra_meta) +{ + return ff_id3v2_parse_priv_dict(&s->metadata, extra_meta); +} diff --git a/libavformat/id3v2.h b/libavformat/id3v2.h index 5e64ead096a82..9de0bee374380 100644 --- a/libavformat/id3v2.h +++ b/libavformat/id3v2.h @@ -39,6 +39,8 @@ #define ID3v2_FLAG_ENCRYPTION 0x0004 #define ID3v2_FLAG_COMPRESSION 0x0008 +#define ID3v2_PRIV_METADATA_PREFIX "id3v2_priv." + enum ID3v2Encoding { ID3v2_ENCODING_ISO8859 = 0, ID3v2_ENCODING_UTF16BOM = 1, @@ -167,6 +169,19 @@ int ff_id3v2_parse_apic(AVFormatContext *s, ID3v2ExtraMeta **extra_meta); */ int ff_id3v2_parse_chapters(AVFormatContext *s, ID3v2ExtraMeta **extra_meta); +/** + * Parse PRIV tags into a dictionary. The PRIV owner is the metadata key. The + * PRIV data is the value, with non-printable characters escaped. + */ +int ff_id3v2_parse_priv_dict(AVDictionary **d, ID3v2ExtraMeta **extra_meta); + +/** + * Add metadata for all PRIV tags in the ID3v2 header. The PRIV owner is the + * metadata key. The PRIV data is the value, with non-printable characters + * escaped. + */ +int ff_id3v2_parse_priv(AVFormatContext *s, ID3v2ExtraMeta **extra_meta); + extern const AVMetadataConv ff_id3v2_34_metadata_conv[]; extern const AVMetadataConv ff_id3v2_4_metadata_conv[]; diff --git a/libavformat/id3v2enc.c b/libavformat/id3v2enc.c index 14de76ac06d4b..ffe358f019865 100644 --- a/libavformat/id3v2enc.c +++ b/libavformat/id3v2enc.c @@ -96,6 +96,59 @@ static int id3v2_put_ttag(ID3v2EncContext *id3, AVIOContext *avioc, const char * return len + ID3v2_HEADER_SIZE; } +/** + * Write a priv frame with owner and data. 'key' is the owner prepended with + * ID3v2_PRIV_METADATA_PREFIX. 'data' is provided as a string. Any \xXX + * (where 'X' is a valid hex digit) will be unescaped to the byte value. + */ +static int id3v2_put_priv(ID3v2EncContext *id3, AVIOContext *avioc, const char *key, const char *data) +{ + int len; + uint8_t *pb; + AVIOContext *dyn_buf; + + if (!av_strstart(key, ID3v2_PRIV_METADATA_PREFIX, &key)) { + return 0; + } + + if (avio_open_dyn_buf(&dyn_buf) < 0) + return AVERROR(ENOMEM); + + // owner + null byte. + avio_write(dyn_buf, key, strlen(key) + 1); + + while (*data) { + if (av_strstart(data, "\\x", &data)) { + if (data[0] && data[1] && av_isxdigit(data[0]) && av_isxdigit(data[1])) { + char digits[] = {data[0], data[1], 0}; + avio_w8(dyn_buf, strtol(digits, NULL, 16)); + data += 2; + } else { + ffio_free_dyn_buf(&dyn_buf); + av_log(avioc, AV_LOG_ERROR, "Invalid escape '\\x%.2s' in metadata tag '" + ID3v2_PRIV_METADATA_PREFIX "%s'.\n", data, key); + return AVERROR(EINVAL); + } + } else { + avio_write(dyn_buf, data++, 1); + } + } + + len = avio_close_dyn_buf(dyn_buf, &pb); + + avio_wb32(avioc, MKBETAG('P', 'R', 'I', 'V')); + if (id3->version == 3) + avio_wb32(avioc, len); + else + id3v2_put_size(avioc, len); + avio_wb16(avioc, 0); + avio_write(avioc, pb, len); + + av_free(pb); + + return len + ID3v2_HEADER_SIZE; +} + static int id3v2_check_write_tag(ID3v2EncContext *id3, AVIOContext *pb, AVDictionaryEntry *t, const char table[][4], enum ID3v2Encoding enc) { @@ -186,6 +239,13 @@ static int write_metadata(AVIOContext *pb, AVDictionary **metadata, continue; } + if ((ret = id3v2_put_priv(id3, pb, t->key, t->value)) > 0) { + id3->len += ret; + continue; + } else if (ret < 0) { + return ret; + } + /* unknown tag, write as TXXX frame */ if ((ret = id3v2_put_ttag(id3, pb, t->key, t->value, MKBETAG('T', 'X', 'X', 'X'), enc)) < 0) return ret; diff --git a/libavformat/ijkutils.c b/libavformat/ijkutils.c new file mode 100644 index 0000000000000..c6d013486d2e1 --- /dev/null +++ b/libavformat/ijkutils.c @@ -0,0 +1,98 @@ +/* + * utils.c + * + * Copyright (c) 2003 Fabrice Bellard + * Copyright (c) 2013 Zhang Rui + * + * This file is part of ijkPlayer. + * + * ijkPlayer is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * ijkPlayer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with ijkPlayer; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "url.h" +#include "avformat.h" + + +#define IJK_FF_PROTOCOL(x) \ +extern URLProtocol ff_##x##_protocol; \ +int ijkav_register_##x##_protocol(URLProtocol *protocol, int protocol_size); \ +int ijkav_register_##x##_protocol(URLProtocol *protocol, int protocol_size) \ +{ \ + if (protocol_size != sizeof(URLProtocol)) { \ + av_log(NULL, AV_LOG_ERROR, "ijkav_register_##x##_protocol: ABI mismatch.\n"); \ + return -1; \ + } \ + memcpy(&ff_##x##_protocol, protocol, protocol_size); \ + return 0; \ +} + +#define IJK_DUMMY_PROTOCOL(x) \ +IJK_FF_PROTOCOL(x); \ +static const AVClass ijk_##x##_context_class = { \ + .class_name = #x, \ + .item_name = av_default_item_name, \ + .version = LIBAVUTIL_VERSION_INT, \ + }; \ + \ +URLProtocol ff_##x##_protocol = { \ + .name = #x, \ + .url_open2 = ijkdummy_open, \ + .priv_data_size = 1, \ + .priv_data_class = &ijk_##x##_context_class, \ +}; + +static int ijkdummy_open(URLContext *h, const char *arg, int flags, AVDictionary **options) +{ + return -1; +} + +IJK_FF_PROTOCOL(async); +IJK_DUMMY_PROTOCOL(ijkmediadatasource); +IJK_DUMMY_PROTOCOL(ijkhttphook); +IJK_DUMMY_PROTOCOL(ijklongurl); +IJK_DUMMY_PROTOCOL(ijksegment); +IJK_DUMMY_PROTOCOL(ijktcphook); +IJK_DUMMY_PROTOCOL(ijkio); + +#define IJK_FF_DEMUXER(x) \ +extern AVInputFormat ff_##x##_demuxer; \ +int ijkav_register_##x##_demuxer(AVInputFormat *demuxer, int demuxer_size); \ +int ijkav_register_##x##_demuxer(AVInputFormat *demuxer, int demuxer_size) \ +{ \ + if (demuxer_size != sizeof(AVInputFormat)) { \ + av_log(NULL, AV_LOG_ERROR, "ijkav_register_##x##_demuxer: ABI mismatch.\n"); \ + return -1; \ + } \ + memcpy(&ff_##x##_demuxer, demuxer, demuxer_size); \ + return 0; \ +} + +#define IJK_DUMMY_DEMUXER(x) \ +IJK_FF_DEMUXER(x); \ +static const AVClass ijk_##x##_demuxer_class = { \ + .class_name = #x, \ + .item_name = av_default_item_name, \ + .version = LIBAVUTIL_VERSION_INT, \ + }; \ + \ +AVInputFormat ff_##x##_demuxer = { \ + .name = #x, \ + .priv_data_size = 1, \ + .priv_class = &ijk_##x##_demuxer_class, \ +}; + +IJK_DUMMY_DEMUXER(ijklivehook); +IJK_DUMMY_DEMUXER(ijklas); diff --git a/libavformat/img2dec.c b/libavformat/img2dec.c index ecf64eaffaed2..ffbc9a66d8231 100644 --- a/libavformat/img2dec.c +++ b/libavformat/img2dec.c @@ -198,7 +198,7 @@ int ff_img_read_header(AVFormatContext *s1) return AVERROR(EINVAL); } - av_strlcpy(s->path, s1->filename, sizeof(s->path)); + av_strlcpy(s->path, s1->url, sizeof(s->path)); s->img_number = 0; s->img_count = 0; @@ -323,7 +323,8 @@ int ff_img_read_header(AVFormatContext *s1) if (s1->pb) { int probe_buffer_size = 2048; uint8_t *probe_buffer = av_realloc(NULL, probe_buffer_size + AVPROBE_PADDING_SIZE); - AVInputFormat *fmt = NULL; + const AVInputFormat *fmt = NULL; + void *fmt_iter = NULL; AVProbeData pd = { 0 }; if (!probe_buffer) @@ -338,9 +339,9 @@ int ff_img_read_header(AVFormatContext *s1) pd.buf = probe_buffer; pd.buf_size = probe_buffer_size; - pd.filename = s1->filename; + pd.filename = s1->url; - while ((fmt = av_iformat_next(fmt))) { + while ((fmt = av_demuxer_iterate(&fmt_iter))) { if (fmt->read_header != ff_img_read_header || !fmt->read_probe || (fmt->flags & AVFMT_NOFILE) || @@ -878,10 +879,14 @@ static int svg_probe(AVProbeData *p) { const uint8_t *b = p->buf; const uint8_t *end = p->buf + p->buf_size; + if (memcmp(p->buf, "= end - 4) return 0; if (!memcmp(b, "streams[0]; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(st->codecpar->format); - av_strlcpy(img->path, s->filename, sizeof(img->path)); + av_strlcpy(img->path, s->url, sizeof(img->path)); /* find format */ if (s->oformat->flags & AVFMT_NOFILE) @@ -99,12 +100,17 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) av_log(s, AV_LOG_ERROR, "Could not get frame filename with strftime\n"); return AVERROR(EINVAL); } + } else if (img->frame_pts) { + if (av_get_frame_filename2(filename, sizeof(filename), img->path, pkt->pts, AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0) { + av_log(s, AV_LOG_ERROR, "Cannot write filename by pts of the frames."); + return AVERROR(EINVAL); + } } else if (av_get_frame_filename2(filename, sizeof(filename), img->path, img->img_number, AV_FRAME_FILENAME_FLAGS_MULTIPLE) < 0 && img->img_number > 1) { av_log(s, AV_LOG_ERROR, - "Could not get frame filename number %d from pattern '%s' (either set updatefirst or use a pattern like %%03d within the filename pattern)\n", + "Could not get frame filename number %d from pattern '%s' (either set update or use a pattern like %%03d within the filename pattern)\n", img->img_number, img->path); return AVERROR(EINVAL); } @@ -150,7 +156,7 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) av_assert0(!img->split_planes); - ret = avformat_alloc_output_context2(&fmt, NULL, img->muxer, s->filename); + ret = avformat_alloc_output_context2(&fmt, NULL, img->muxer, s->url); if (ret < 0) return ret; st = avformat_new_stream(fmt, NULL); @@ -203,10 +209,10 @@ static int query_codec(enum AVCodecID id, int std_compliance) #define OFFSET(x) offsetof(VideoMuxData, x) #define ENC AV_OPT_FLAG_ENCODING_PARAM static const AVOption muxoptions[] = { - { "updatefirst", "continuously overwrite one file", OFFSET(update), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC }, { "update", "continuously overwrite one file", OFFSET(update), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC }, { "start_number", "set first number in the sequence", OFFSET(img_number), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, INT_MAX, ENC }, { "strftime", "use strftime for filename", OFFSET(use_strftime), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC }, + { "frame_pts", "use current frame pts for filename", OFFSET(frame_pts), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC }, { "atomic_writing", "write files atomically (using temporary files and renames)", OFFSET(use_rename), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, ENC }, { NULL }, }; diff --git a/libavformat/internal.h b/libavformat/internal.h index d136c79bdd42a..3582682925023 100644 --- a/libavformat/internal.h +++ b/libavformat/internal.h @@ -120,12 +120,6 @@ struct AVFormatInternal { int avoid_negative_ts_use_pts; - /** - * Whether or not a header has already been written - */ - int header_written; - int write_header_ret; - /** * Timestamp of the end of the shortest stream. */ @@ -196,6 +190,8 @@ struct AVStreamInternal { * Whether the internal avctx needs to be updated from codecpar (after a late change to codecpar) */ int need_context_update; + + FFFrac *priv_pts; }; #ifdef __GNUC__ @@ -303,6 +299,42 @@ void ff_put_v(AVIOContext *bc, uint64_t val); */ int ff_get_line(AVIOContext *s, char *buf, int maxlen); +/** + * Same as ff_get_line but strip the white-space characters in the text tail + * + * @param s the read-only AVIOContext + * @param buf buffer to store the read line + * @param maxlen size of the buffer + * @return the length of the string written in the buffer + */ +int ff_get_chomp_line(AVIOContext *s, char *buf, int maxlen); + +/** + * Read a whole line of text from AVIOContext to an AVBPrint buffer. Stop + * reading after reaching a \\r, a \\n, a \\r\\n, a \\0 or EOF. The line + * ending characters are NOT included in the buffer, but they are skipped on + * the input. + * + * @param s the read-only AVIOContext + * @param bp the AVBPrint buffer + * @return the length of the read line, not including the line endings, + * negative on error. + */ +int64_t ff_read_line_to_bprint(AVIOContext *s, AVBPrint *bp); + +/** + * Read a whole line of text from AVIOContext to an AVBPrint buffer overwriting + * its contents. Stop reading after reaching a \\r, a \\n, a \\r\\n, a \\0 or + * EOF. The line ending characters are NOT included in the buffer, but they + * are skipped on the input. + * + * @param s the read-only AVIOContext + * @param bp the AVBPrint buffer + * @return the length of the read line not including the line endings, + * negative on error, or if the buffer becomes truncated. + */ +int64_t ff_read_line_to_bprint_overwrite(AVIOContext *s, AVBPrint *bp); + #define SPACE_CHARS " \t\r\n" /** @@ -545,8 +577,11 @@ static inline int ff_rename(const char *oldpath, const char *newpath, void *logc int ret = 0; if (rename(oldpath, newpath) == -1) { ret = AVERROR(errno); - if (logctx) - av_log(logctx, AV_LOG_ERROR, "failed to rename file %s to %s\n", oldpath, newpath); + if (logctx) { + char err[AV_ERROR_MAX_STRING_SIZE] = {0}; + av_make_error_string(err, AV_ERROR_MAX_STRING_SIZE, ret); + av_log(logctx, AV_LOG_ERROR, "failed to rename file %s to %s: %s\n", oldpath, newpath, err); + } } return ret; } @@ -555,6 +590,8 @@ static inline int ff_rename(const char *oldpath, const char *newpath, void *logc * Allocate extradata with additional AV_INPUT_BUFFER_PADDING_SIZE at end * which is always set to 0. * + * Previously allocated extradata in par will be freed. + * * @param size size of extradata * @return 0 if OK, AVERROR_xxx on error */ @@ -622,6 +659,14 @@ int ff_format_output_open(AVFormatContext *s, const char *url, AVDictionary **op */ void ff_format_io_close(AVFormatContext *s, AVIOContext **pb); +/** + * Utility function to check if the file uses http or https protocol + * + * @param s AVFormatContext + * @param filename URL or file name to open for writing + */ +int ff_is_http_proto(char *filename); + /** * Parse creation_time in AVFormatContext metadata if exists and warn if the * parsing fails. @@ -685,4 +730,55 @@ int ff_bprint_to_codecpar_extradata(AVCodecParameters *par, struct AVBPrint *buf int ff_interleaved_peek(AVFormatContext *s, int stream, AVPacket *pkt, int add_offset); + +int ff_lock_avformat(void); +int ff_unlock_avformat(void); + +/** + * Set AVFormatContext url field to the provided pointer. The pointer must + * point to a valid string. The existing url field is freed if necessary. Also + * set the legacy filename field to the same string which was provided in url. + */ +void ff_format_set_url(AVFormatContext *s, char *url); + +#define FF_PACKETLIST_FLAG_REF_PACKET (1 << 0) /**< Create a new reference for the packet instead of + transferring the ownership of the existing one to the + list. */ + +/** + * Append an AVPacket to the list. + * + * @param head List head element + * @param tail List tail element + * @param pkt The packet being appended + * @param flags Any combination of FF_PACKETLIST_FLAG_* flags + * @return 0 on success, negative AVERROR value on failure. On failure, + the list is unchanged + */ +int ff_packet_list_put(AVPacketList **head, AVPacketList **tail, + AVPacket *pkt, int flags); + +/** + * Remove the oldest AVPacket in the list and return it. + * + * @note The pkt will be overwritten completely. The caller owns the + * packet and must unref it by itself. + * + * @param head List head element + * @param tail List tail element + * @param pkt Pointer to an initialized AVPacket struct + */ +int ff_packet_list_get(AVPacketList **head, AVPacketList **tail, + AVPacket *pkt); + +/** + * Wipe the list and unref all the packets in it. + * + * @param head List head element + * @param tail List tail element + */ +void ff_packet_list_free(AVPacketList **head, AVPacketList **tail); + +void avpriv_register_devices(const AVOutputFormat * const o[], const AVInputFormat * const i[]); + #endif /* AVFORMAT_INTERNAL_H */ diff --git a/libavformat/isom.c b/libavformat/isom.c index 77983c5eaabbf..2792371c2503a 100644 --- a/libavformat/isom.c +++ b/libavformat/isom.c @@ -186,6 +186,7 @@ const AVCodecTag ff_codec_movvideo_tags[] = { { AV_CODEC_ID_H264, MKTAG('x', 'a', 'l', 'g') }, /* XAVC-L HD422 produced by FCP */ { AV_CODEC_ID_H264, MKTAG('a', 'v', 'l', 'g') }, /* Panasonic P2 AVC-LongG */ + { AV_CODEC_ID_VP8, MKTAG('v', 'p', '0', '8') }, /* VP8 */ { AV_CODEC_ID_VP9, MKTAG('v', 'p', '0', '9') }, /* VP9 */ { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', '1', 'v', ' ') }, @@ -524,8 +525,7 @@ FF_ENABLE_DEPRECATION_WARNINGS if (tag == MP4DecSpecificDescrTag) { av_log(fc, AV_LOG_TRACE, "Specific MPEG-4 header len=%d\n", len); if (!len || (uint64_t)len > (1<<30)) - return -1; - av_free(st->codecpar->extradata); + return AVERROR_INVALIDDATA; if ((ret = ff_get_extradata(fc, st->codecpar, pb, len)) < 0) return ret; if (st->codecpar->codec_id == AV_CODEC_ID_AAC) { diff --git a/libavformat/isom.h b/libavformat/isom.h index b9380e9dcc3e9..bff5622dfb3b8 100644 --- a/libavformat/isom.h +++ b/libavformat/isom.h @@ -93,7 +93,6 @@ typedef struct MOVFragment { unsigned duration; unsigned size; unsigned flags; - int64_t time; } MOVFragment; typedef struct MOVTrackExt { @@ -109,17 +108,28 @@ typedef struct MOVSbgp { unsigned int index; } MOVSbgp; +typedef struct MOVFragmentStreamInfo { + int id; + int64_t sidx_pts; + int64_t first_tfra_pts; + int64_t tfdt_dts; + int index_entry; +} MOVFragmentStreamInfo; + typedef struct MOVFragmentIndexItem { int64_t moof_offset; - int64_t time; int headers_read; + int current; + int nb_stream_info; + MOVFragmentStreamInfo * stream_info; } MOVFragmentIndexItem; typedef struct MOVFragmentIndex { - unsigned track_id; - unsigned item_count; - unsigned current_item; - MOVFragmentIndexItem *items; + int allocated_size; + int complete; + int current; + int nb_items; + MOVFragmentIndexItem * item; } MOVFragmentIndex; typedef struct MOVIndexRange { @@ -158,6 +168,7 @@ typedef struct MOVStreamContext { int *keyframes; int time_scale; int64_t time_offset; ///< time offset of the edit list entries + int64_t min_corrected_pts; ///< minimum Composition time shown by the edits excluding empty edits. int current_sample; int64_t current_index; MOVIndexRange* index_ranges; @@ -250,9 +261,7 @@ typedef struct MOVContext { int moov_retry; int use_mfra_for; int has_looked_for_mfra; - MOVFragmentIndex** fragment_index_data; - unsigned fragment_index_count; - int fragment_index_complete; + MOVFragmentIndex frag_index; int atom_depth; unsigned int aax_mode; ///< 'aax' file has been detected uint8_t file_key[20]; @@ -265,6 +274,8 @@ typedef struct MOVContext { uint8_t *decryption_key; int decryption_key_len; int enable_drefs; + int allow_multi_extradata; + int has_extradata; int32_t movie_display_matrix[3][3]; ///< display matrix from mvhd } MOVContext; @@ -310,6 +321,11 @@ void ff_mp4_parse_es_descr(AVIOContext *pb, int *es_id); #define MOV_TKHD_FLAG_IN_PREVIEW 0x0004 #define MOV_TKHD_FLAG_IN_POSTER 0x0008 +#define MOV_SAMPLE_DEPENDENCY_UNKNOWN 0x0 +#define MOV_SAMPLE_DEPENDENCY_YES 0x1 +#define MOV_SAMPLE_DEPENDENCY_NO 0x2 + + #define TAG_IS_AVCI(tag) \ ((tag) == MKTAG('a', 'i', '5', 'p') || \ (tag) == MKTAG('a', 'i', '5', 'q') || \ @@ -328,7 +344,6 @@ void ff_mp4_parse_es_descr(AVIOContext *pb, int *es_id); int ff_mov_read_esds(AVFormatContext *fc, AVIOContext *pb); -enum AVCodecID ff_mov_get_lpcm_codec_id(int bps, int flags); int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries); void ff_mov_write_chan(AVIOContext *pb, int64_t channel_layout); @@ -337,4 +352,18 @@ void ff_mov_write_chan(AVIOContext *pb, int64_t channel_layout); #define FF_MOV_FLAG_MFRA_DTS 1 #define FF_MOV_FLAG_MFRA_PTS 2 +/** + * Compute codec id for 'lpcm' tag. + * See CoreAudioTypes and AudioStreamBasicDescription at Apple. + */ +static inline enum AVCodecID ff_mov_get_lpcm_codec_id(int bps, int flags) +{ + /* lpcm flags: + * 0x1 = float + * 0x2 = big-endian + * 0x4 = signed + */ + return ff_get_pcm_codec_id(bps, flags & 1, flags & 2, flags & 4 ? -1 : 0); +} + #endif /* AVFORMAT_ISOM_H */ diff --git a/libavformat/ivfenc.c b/libavformat/ivfenc.c index fdc0ee03e1640..af803d59ee80c 100644 --- a/libavformat/ivfenc.c +++ b/libavformat/ivfenc.c @@ -37,14 +37,18 @@ static int ivf_write_header(AVFormatContext *s) } par = s->streams[0]->codecpar; if (par->codec_type != AVMEDIA_TYPE_VIDEO || - !(par->codec_id == AV_CODEC_ID_VP8 || par->codec_id == AV_CODEC_ID_VP9)) { - av_log(s, AV_LOG_ERROR, "Currently only VP8 and VP9 are supported!\n"); + !(par->codec_id == AV_CODEC_ID_AV1 || + par->codec_id == AV_CODEC_ID_VP8 || + par->codec_id == AV_CODEC_ID_VP9)) { + av_log(s, AV_LOG_ERROR, "Currently only VP8, VP9 and AV1 are supported!\n"); return AVERROR(EINVAL); } avio_write(pb, "DKIF", 4); avio_wl16(pb, 0); // version avio_wl16(pb, 32); // header length - avio_wl32(pb, par->codec_tag ? par->codec_tag : par->codec_id == AV_CODEC_ID_VP9 ? AV_RL32("VP90") : AV_RL32("VP80")); + avio_wl32(pb, par->codec_tag ? par->codec_tag : + par->codec_id == AV_CODEC_ID_VP9 ? AV_RL32("VP90") : + par->codec_id == AV_CODEC_ID_VP8 ? AV_RL32("VP80") : AV_RL32("AV01")); avio_wl16(pb, par->width); avio_wl16(pb, par->height); avio_wl32(pb, s->streams[0]->time_base.den); @@ -100,6 +104,7 @@ static int ivf_check_bitstream(struct AVFormatContext *s, const AVPacket *pkt) static const AVCodecTag codec_ivf_tags[] = { { AV_CODEC_ID_VP8, MKTAG('V', 'P', '8', '0') }, { AV_CODEC_ID_VP9, MKTAG('V', 'P', '9', '0') }, + { AV_CODEC_ID_AV1, MKTAG('A', 'V', '0', '1') }, { AV_CODEC_ID_NONE, 0 } }; diff --git a/libavformat/latmenc.c b/libavformat/latmenc.c index c919976d49d8c..273197bb547c9 100644 --- a/libavformat/latmenc.c +++ b/libavformat/latmenc.c @@ -128,7 +128,7 @@ static void latm_write_frame_header(AVFormatContext *s, PutBitContext *bs) int ret = init_get_bits8(&gb, par->extradata, par->extradata_size); av_assert0(ret >= 0); // extradata size has been checked already, so this should not fail skip_bits_long(&gb, ctx->off + 3); - avpriv_copy_pce_data(bs, &gb); + ff_copy_pce_data(bs, &gb); } } diff --git a/libavformat/libavformat.v b/libavformat/libavformat.v index c961cd8f19ccd..47d5ddcdb13e3 100644 --- a/libavformat/libavformat.v +++ b/libavformat/libavformat.v @@ -1,19 +1,6 @@ LIBAVFORMAT_MAJOR { global: av*; - #FIXME those are for ffserver - ff_inet_aton; - ff_socket_nonblock; - ff_rtsp_parse_line; - ff_rtp_get_local_rtp_port; - ff_rtp_get_local_rtcp_port; - ffio_open_dyn_packet_buf; - ffio_set_buf_size; - ffurl_close; - ffurl_open; - ffurl_write; - #those are deprecated, remove on next bump - url_feof; local: *; }; diff --git a/libavformat/libopenmpt.c b/libavformat/libopenmpt.c index af6eb1ac4a028..0fff702a36f46 100644 --- a/libavformat/libopenmpt.c +++ b/libavformat/libopenmpt.c @@ -21,6 +21,14 @@ #include #include +#include +/* Shims to support libopenmpt < 0.3.0 (as documented by libopenmpt) */ +#if !defined(OPENMPT_API_VERSION_MAKE) +#define OPENMPT_API_VERSION_MAKE(major, minor, patch) (((major)<<24)|((minor)<<16)|((patch)<<0)) +#endif +#if !defined(OPENMPT_API_VERSION_AT_LEAST) +#define OPENMPT_API_VERSION_AT_LEAST(major, minor, patch) (OPENMPT_API_VERSION >= OPENMPT_API_VERSION_MAKE((major), (minor), (patch))) +#endif #include "libavutil/avstring.h" #include "libavutil/opt.h" @@ -72,13 +80,17 @@ static int read_header_openmpt(AVFormatContext *s) { AVStream *st; OpenMPTContext *openmpt = s->priv_data; - int64_t size = avio_size(s->pb); - if (size <= 0) - return AVERROR_INVALIDDATA; - char *buf = av_malloc(size); + int64_t size; + char *buf; +#if OPENMPT_API_VERSION_AT_LEAST(0,3,0) + int error; +#endif int ret; - + size = avio_size(s->pb); + if (size <= 0) + return AVERROR_INVALIDDATA; + buf = av_malloc(size); if (!buf) return AVERROR(ENOMEM); size = avio_read(s->pb, buf, size); @@ -88,10 +100,24 @@ static int read_header_openmpt(AVFormatContext *s) return size; } +#if OPENMPT_API_VERSION_AT_LEAST(0,3,0) + error = OPENMPT_ERROR_OK; + openmpt->module = openmpt_module_create_from_memory2(buf, size, openmpt_logfunc, s, NULL, NULL, &error, NULL, NULL); + av_freep(&buf); + if (!openmpt->module) { + if (error == OPENMPT_ERROR_OUT_OF_MEMORY) + return AVERROR(ENOMEM); + else if (error >= OPENMPT_ERROR_GENERAL) + return AVERROR_INVALIDDATA; + else + return AVERROR_UNKNOWN; + } +#else openmpt->module = openmpt_module_create_from_memory(buf, size, openmpt_logfunc, s, NULL); av_freep(&buf); if (!openmpt->module) return AVERROR_INVALIDDATA; +#endif openmpt->channels = av_get_channel_layout_nb_channels(openmpt->layout); @@ -192,6 +218,62 @@ static int read_seek_openmpt(AVFormatContext *s, int stream_idx, int64_t ts, int return 0; } +static int probe_openmpt_extension(AVProbeData *p) +{ + const char *ext; + if (p->filename) { + ext = strrchr(p->filename, '.'); + if (ext && strlen(ext + 1) > 0) { + ext++; /* skip '.' */ + if (openmpt_is_extension_supported(ext) == 1) + return AVPROBE_SCORE_EXTENSION; + } + } + return 0; +} + +static int read_probe_openmpt(AVProbeData *p) +{ +#if OPENMPT_API_VERSION_AT_LEAST(0,3,0) + int probe_result; + if (p->buf && p->buf_size > 0) { + probe_result = openmpt_probe_file_header_without_filesize( + OPENMPT_PROBE_FILE_HEADER_FLAGS_DEFAULT, + p->buf, p->buf_size, + &openmpt_logfunc, NULL, NULL, NULL, NULL, NULL); + if (probe_result == OPENMPT_PROBE_FILE_HEADER_RESULT_SUCCESS) { + /* As probing here relies on code external to FFmpeg, do not return + * AVPROBE_SCORE_MAX in order to reduce the impact in the rare + * cases of false positives. + */ + return AVPROBE_SCORE_MIME + 1; + } else if (probe_result == OPENMPT_PROBE_FILE_HEADER_RESULT_WANTMOREDATA) { + if (probe_openmpt_extension(p) > 0) { + return AVPROBE_SCORE_RETRY; + } else { + if (p->buf_size >= openmpt_probe_file_header_get_recommended_size()) { + /* We have already received the recommended amount of data + * and still cannot decide. Return a rather low score. + */ + return AVPROBE_SCORE_RETRY / 2; + } else { + /* The file extension is unknown and we have very few data + * bytes available. libopenmpt cannot decide anything here, + * and returning any score > 0 would result in successfull + * probing of random data. + */ + return 0; + } + } + } else if (probe_result == OPENMPT_PROBE_FILE_HEADER_RESULT_FAILURE) { + return 0; + } + } +#endif + /* for older libopenmpt, fall back to file extension probing */ + return probe_openmpt_extension(p); +} + static const AVClass class_openmpt = { .class_name = "libopenmpt", .item_name = av_default_item_name, @@ -203,10 +285,15 @@ AVInputFormat ff_libopenmpt_demuxer = { .name = "libopenmpt", .long_name = NULL_IF_CONFIG_SMALL("Tracker formats (libopenmpt)"), .priv_data_size = sizeof(OpenMPTContext), + .read_probe = read_probe_openmpt, .read_header = read_header_openmpt, .read_packet = read_packet_openmpt, .read_close = read_close_openmpt, .read_seek = read_seek_openmpt, .priv_class = &class_openmpt, - .extensions = "669,amf,ams,dbm,digi,dmf,dsm,far,gdm,imf,it,j2b,m15,mdl,med,mmcmp,mms,mo3,mod,mptm,mt2,mtm,nst,okt,plm,ppm,psm,pt36,ptm,s3m,sfx,sfx2,stk,stm,ult,umx,wow,xm,xpk", +#if OPENMPT_API_VERSION_AT_LEAST(0,3,0) + .extensions = "669,amf,ams,dbm,digi,dmf,dsm,dtm,far,gdm,ice,imf,it,j2b,m15,mdl,med,mmcmp,mms,mo3,mod,mptm,mt2,mtm,nst,okt,plm,ppm,psm,pt36,ptm,s3m,sfx,sfx2,st26,stk,stm,stp,ult,umx,wow,xm,xpk", +#else + .extensions = "669,amf,ams,dbm,digi,dmf,dsm,far,gdm,ice,imf,it,j2b,m15,mdl,med,mmcmp,mms,mo3,mod,mptm,mt2,mtm,nst,okt,plm,ppm,psm,pt36,ptm,s3m,sfx,sfx2,st26,stk,stm,ult,umx,wow,xm,xpk", +#endif }; diff --git a/libavformat/libsrt.c b/libavformat/libsrt.c new file mode 100644 index 0000000000000..0f9529d263a1c --- /dev/null +++ b/libavformat/libsrt.c @@ -0,0 +1,546 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Haivision Open SRT (Secure Reliable Transport) protocol + */ + +#include + +#include "libavutil/avassert.h" +#include "libavutil/opt.h" +#include "libavutil/parseutils.h" +#include "libavutil/time.h" + +#include "avformat.h" +#include "internal.h" +#include "network.h" +#include "os_support.h" +#include "url.h" + +enum SRTMode { + SRT_MODE_CALLER = 0, + SRT_MODE_LISTENER = 1, + SRT_MODE_RENDEZVOUS = 2 +}; + +typedef struct SRTContext { + const AVClass *class; + int fd; + int eid; + int64_t rw_timeout; + int64_t listen_timeout; + int recv_buffer_size; + int send_buffer_size; + + int64_t maxbw; + int pbkeylen; + char *passphrase; + int mss; + int ffs; + int ipttl; + int iptos; + int64_t inputbw; + int oheadbw; + int64_t tsbpddelay; + int tlpktdrop; + int nakreport; + int64_t connect_timeout; + enum SRTMode mode; +} SRTContext; + +#define D AV_OPT_FLAG_DECODING_PARAM +#define E AV_OPT_FLAG_ENCODING_PARAM +#define OFFSET(x) offsetof(SRTContext, x) +static const AVOption libsrt_options[] = { + { "rw_timeout", "Timeout of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, + { "listen_timeout", "Connection awaiting timeout", OFFSET(listen_timeout), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, + { "send_buffer_size", "Socket send buffer size (in bytes)", OFFSET(send_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, + { "recv_buffer_size", "Socket receive buffer size (in bytes)", OFFSET(recv_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, + { "maxbw", "Maximum bandwidth (bytes per second) that the connection can use", OFFSET(maxbw), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, + { "pbkeylen", "Crypto key len in bytes {16,24,32} Default: 16 (128-bit)", OFFSET(pbkeylen), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 32, .flags = D|E }, + { "passphrase", "Crypto PBKDF2 Passphrase size[0,10..64] 0:disable crypto", OFFSET(passphrase), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = D|E }, + { "mss", "The Maximum Segment Size", OFFSET(mss), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1500, .flags = D|E }, + { "ffs", "Flight flag size (window size) (in bytes)", OFFSET(ffs), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, + { "ipttl", "IP Time To Live", OFFSET(ipttl), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, .flags = D|E }, + { "iptos", "IP Type of Service", OFFSET(iptos), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 255, .flags = D|E }, + { "inputbw", "Estimated input stream rate", OFFSET(inputbw), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, + { "oheadbw", "MaxBW ceiling based on % over input stream rate", OFFSET(oheadbw), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 100, .flags = D|E }, + { "tsbpddelay", "TsbPd receiver delay to absorb burst of missed packet retransmission", OFFSET(tsbpddelay), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, + { "tlpktdrop", "Enable receiver pkt drop", OFFSET(tlpktdrop), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, .flags = D|E }, + { "nakreport", "Enable receiver to send periodic NAK reports", OFFSET(nakreport), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 1, .flags = D|E }, + { "connect_timeout", "Connect timeout. Caller default: 3000, rendezvous (x 10)", OFFSET(connect_timeout), AV_OPT_TYPE_INT64, { .i64 = -1 }, -1, INT64_MAX, .flags = D|E }, + { "mode", "Connection mode (caller, listener, rendezvous)", OFFSET(mode), AV_OPT_TYPE_INT, { .i64 = SRT_MODE_CALLER }, SRT_MODE_CALLER, SRT_MODE_RENDEZVOUS, .flags = D|E, "mode" }, + { "caller", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_MODE_CALLER }, INT_MIN, INT_MAX, .flags = D|E, "mode" }, + { "listener", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_MODE_LISTENER }, INT_MIN, INT_MAX, .flags = D|E, "mode" }, + { "rendezvous", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = SRT_MODE_RENDEZVOUS }, INT_MIN, INT_MAX, .flags = D|E, "mode" }, + { NULL } +}; + +static int libsrt_neterrno(URLContext *h) +{ + int err = srt_getlasterror(NULL); + av_log(h, AV_LOG_ERROR, "%s\n", srt_getlasterror_str()); + if (err == SRT_EASYNCRCV) + return AVERROR(EAGAIN); + return AVERROR_UNKNOWN; +} + +static int libsrt_socket_nonblock(int socket, int enable) +{ + int ret = srt_setsockopt(socket, 0, SRTO_SNDSYN, &enable, sizeof(enable)); + if (ret < 0) + return ret; + return srt_setsockopt(socket, 0, SRTO_RCVSYN, &enable, sizeof(enable)); +} + +static int libsrt_network_wait_fd(URLContext *h, int eid, int fd, int write) +{ + int ret, len = 1; + int modes = write ? SRT_EPOLL_OUT : SRT_EPOLL_IN; + SRTSOCKET ready[1]; + + if (srt_epoll_add_usock(eid, fd, &modes) < 0) + return libsrt_neterrno(h); + if (write) { + ret = srt_epoll_wait(eid, 0, 0, ready, &len, POLLING_TIME, 0, 0, 0, 0); + } else { + ret = srt_epoll_wait(eid, ready, &len, 0, 0, POLLING_TIME, 0, 0, 0, 0); + } + if (ret < 0) { + if (srt_getlasterror(NULL) == SRT_ETIMEOUT) + ret = AVERROR(EAGAIN); + else + ret = libsrt_neterrno(h); + } else { + ret = 0; + } + if (srt_epoll_remove_usock(eid, fd) < 0) + return libsrt_neterrno(h); + return ret; +} + +/* TODO de-duplicate code from ff_network_wait_fd_timeout() */ + +static int libsrt_network_wait_fd_timeout(URLContext *h, int eid, int fd, int write, int64_t timeout, AVIOInterruptCB *int_cb) +{ + int ret; + int64_t wait_start = 0; + + while (1) { + if (ff_check_interrupt(int_cb)) + return AVERROR_EXIT; + ret = libsrt_network_wait_fd(h, eid, fd, write); + if (ret != AVERROR(EAGAIN)) + return ret; + if (timeout > 0) { + if (!wait_start) + wait_start = av_gettime_relative(); + else if (av_gettime_relative() - wait_start > timeout) + return AVERROR(ETIMEDOUT); + } + } +} + +static int libsrt_listen(int eid, int fd, const struct sockaddr *addr, socklen_t addrlen, URLContext *h, int timeout) +{ + int ret; + int reuse = 1; + if (srt_setsockopt(fd, SOL_SOCKET, SRTO_REUSEADDR, &reuse, sizeof(reuse))) { + av_log(h, AV_LOG_WARNING, "setsockopt(SRTO_REUSEADDR) failed\n"); + } + ret = srt_bind(fd, addr, addrlen); + if (ret) + return libsrt_neterrno(h); + + ret = srt_listen(fd, 1); + if (ret) + return libsrt_neterrno(h); + + while ((ret = libsrt_network_wait_fd_timeout(h, eid, fd, 1, timeout, &h->interrupt_callback))) { + switch (ret) { + case AVERROR(ETIMEDOUT): + continue; + default: + return ret; + } + } + + ret = srt_accept(fd, NULL, NULL); + if (ret < 0) + return libsrt_neterrno(h); + if (libsrt_socket_nonblock(ret, 1) < 0) + av_log(h, AV_LOG_DEBUG, "libsrt_socket_nonblock failed\n"); + + return ret; +} + +static int libsrt_listen_connect(int eid, int fd, const struct sockaddr *addr, socklen_t addrlen, int timeout, URLContext *h, int will_try_next) +{ + int ret; + + if (libsrt_socket_nonblock(fd, 1) < 0) + av_log(h, AV_LOG_DEBUG, "ff_socket_nonblock failed\n"); + + while ((ret = srt_connect(fd, addr, addrlen))) { + ret = libsrt_neterrno(h); + switch (ret) { + case AVERROR(EINTR): + if (ff_check_interrupt(&h->interrupt_callback)) + return AVERROR_EXIT; + continue; + case AVERROR(EINPROGRESS): + case AVERROR(EAGAIN): + ret = libsrt_network_wait_fd_timeout(h, eid, fd, 1, timeout, &h->interrupt_callback); + if (ret < 0) + return ret; + ret = srt_getlasterror(NULL); + srt_clearlasterror(); + if (ret != 0) { + char buf[128]; + ret = AVERROR(ret); + av_strerror(ret, buf, sizeof(buf)); + if (will_try_next) + av_log(h, AV_LOG_WARNING, + "Connection to %s failed (%s), trying next address\n", + h->filename, buf); + else + av_log(h, AV_LOG_ERROR, "Connection to %s failed: %s\n", + h->filename, buf); + } + default: + return ret; + } + } + return ret; +} + +static int libsrt_setsockopt(URLContext *h, int fd, SRT_SOCKOPT optname, const char * optnamestr, const void * optval, int optlen) +{ + if (srt_setsockopt(fd, 0, optname, optval, optlen) < 0) { + av_log(h, AV_LOG_ERROR, "failed to set option %s on socket: %s\n", optnamestr, srt_getlasterror_str()); + return AVERROR(EIO); + } + return 0; +} + +/* - The "POST" options can be altered any time on a connected socket. + They MAY have also some meaning when set prior to connecting; such + option is SRTO_RCVSYN, which makes connect/accept call asynchronous. + Because of that this option is treated special way in this app. */ +static int libsrt_set_options_post(URLContext *h, int fd) +{ + SRTContext *s = h->priv_data; + + if ((s->inputbw >= 0 && libsrt_setsockopt(h, fd, SRTO_INPUTBW, "SRTO_INPUTBW", &s->inputbw, sizeof(s->inputbw)) < 0) || + (s->oheadbw >= 0 && libsrt_setsockopt(h, fd, SRTO_OHEADBW, "SRTO_OHEADBW", &s->oheadbw, sizeof(s->oheadbw)) < 0)) { + return AVERROR(EIO); + } + return 0; +} + +/* - The "PRE" options must be set prior to connecting and can't be altered + on a connected socket, however if set on a listening socket, they are + derived by accept-ed socket. */ +static int libsrt_set_options_pre(URLContext *h, int fd) +{ + SRTContext *s = h->priv_data; + int yes = 1; + int tsbpddelay = s->tsbpddelay / 1000; + int connect_timeout = s->connect_timeout; + + if ((s->mode == SRT_MODE_RENDEZVOUS && libsrt_setsockopt(h, fd, SRTO_RENDEZVOUS, "SRTO_RENDEZVOUS", &yes, sizeof(yes)) < 0) || + (s->maxbw >= 0 && libsrt_setsockopt(h, fd, SRTO_MAXBW, "SRTO_MAXBW", &s->maxbw, sizeof(s->maxbw)) < 0) || + (s->pbkeylen >= 0 && libsrt_setsockopt(h, fd, SRTO_PBKEYLEN, "SRTO_PBKEYLEN", &s->pbkeylen, sizeof(s->pbkeylen)) < 0) || + (s->passphrase && libsrt_setsockopt(h, fd, SRTO_PASSPHRASE, "SRTO_PASSPHRASE", &s->passphrase, sizeof(s->passphrase)) < 0) || + (s->mss >= 0 && libsrt_setsockopt(h, fd, SRTO_MSS, "SRTO_MMS", &s->mss, sizeof(s->mss)) < 0) || + (s->ffs >= 0 && libsrt_setsockopt(h, fd, SRTO_FC, "SRTO_FC", &s->ffs, sizeof(s->ffs)) < 0) || + (s->ipttl >= 0 && libsrt_setsockopt(h, fd, SRTO_IPTTL, "SRTO_UPTTL", &s->ipttl, sizeof(s->ipttl)) < 0) || + (s->iptos >= 0 && libsrt_setsockopt(h, fd, SRTO_IPTOS, "SRTO_IPTOS", &s->iptos, sizeof(s->iptos)) < 0) || + (tsbpddelay >= 0 && libsrt_setsockopt(h, fd, SRTO_TSBPDDELAY, "SRTO_TSBPDELAY", &tsbpddelay, sizeof(tsbpddelay)) < 0) || + (s->tlpktdrop >= 0 && libsrt_setsockopt(h, fd, SRTO_TLPKTDROP, "SRTO_TLPKDROP", &s->tlpktdrop, sizeof(s->tlpktdrop)) < 0) || + (s->nakreport >= 0 && libsrt_setsockopt(h, fd, SRTO_NAKREPORT, "SRTO_NAKREPORT", &s->nakreport, sizeof(s->nakreport)) < 0) || + (connect_timeout >= 0 && libsrt_setsockopt(h, fd, SRTO_CONNTIMEO, "SRTO_CONNTIMEO", &connect_timeout, sizeof(connect_timeout)) <0 )) { + return AVERROR(EIO); + } + return 0; +} + + +static int libsrt_setup(URLContext *h, const char *uri, int flags) +{ + struct addrinfo hints = { 0 }, *ai, *cur_ai; + int port, fd = -1; + SRTContext *s = h->priv_data; + const char *p; + char buf[256]; + int ret; + char hostname[1024],proto[1024],path[1024]; + char portstr[10]; + int open_timeout = 5000000; + int eid; + + eid = srt_epoll_create(); + if (eid < 0) + return libsrt_neterrno(h); + s->eid = eid; + + av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), + &port, path, sizeof(path), uri); + if (strcmp(proto, "srt")) + return AVERROR(EINVAL); + if (port <= 0 || port >= 65536) { + av_log(h, AV_LOG_ERROR, "Port missing in uri\n"); + return AVERROR(EINVAL); + } + p = strchr(uri, '?'); + if (p) { + if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) { + s->rw_timeout = strtol(buf, NULL, 10); + } + if (av_find_info_tag(buf, sizeof(buf), "listen_timeout", p)) { + s->listen_timeout = strtol(buf, NULL, 10); + } + } + if (s->rw_timeout >= 0) { + open_timeout = h->rw_timeout = s->rw_timeout; + } + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + snprintf(portstr, sizeof(portstr), "%d", port); + if (s->mode == SRT_MODE_LISTENER) + hints.ai_flags |= AI_PASSIVE; + ret = getaddrinfo(hostname[0] ? hostname : NULL, portstr, &hints, &ai); + if (ret) { + av_log(h, AV_LOG_ERROR, + "Failed to resolve hostname %s: %s\n", + hostname, gai_strerror(ret)); + return AVERROR(EIO); + } + + cur_ai = ai; + + restart: + + fd = srt_socket(cur_ai->ai_family, cur_ai->ai_socktype, 0); + if (fd < 0) { + ret = libsrt_neterrno(h); + goto fail; + } + + if ((ret = libsrt_set_options_pre(h, fd)) < 0) { + goto fail; + } + + /* Set the socket's send or receive buffer sizes, if specified. + If unspecified or setting fails, system default is used. */ + if (s->recv_buffer_size > 0) { + srt_setsockopt(fd, SOL_SOCKET, SRTO_UDP_RCVBUF, &s->recv_buffer_size, sizeof (s->recv_buffer_size)); + } + if (s->send_buffer_size > 0) { + srt_setsockopt(fd, SOL_SOCKET, SRTO_UDP_SNDBUF, &s->send_buffer_size, sizeof (s->send_buffer_size)); + } + if (s->mode == SRT_MODE_LISTENER) { + // multi-client + if ((ret = libsrt_listen(s->eid, fd, cur_ai->ai_addr, cur_ai->ai_addrlen, h, open_timeout / 1000)) < 0) + goto fail1; + fd = ret; + } else { + if (s->mode == SRT_MODE_RENDEZVOUS) { + ret = srt_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen); + if (ret) + goto fail1; + } + + if ((ret = libsrt_listen_connect(s->eid, fd, cur_ai->ai_addr, cur_ai->ai_addrlen, + open_timeout / 1000, h, !!cur_ai->ai_next)) < 0) { + if (ret == AVERROR_EXIT) + goto fail1; + else + goto fail; + } + } + if ((ret = libsrt_set_options_post(h, fd)) < 0) { + goto fail; + } + + h->is_streamed = 1; + s->fd = fd; + + freeaddrinfo(ai); + return 0; + + fail: + if (cur_ai->ai_next) { + /* Retry with the next sockaddr */ + cur_ai = cur_ai->ai_next; + if (fd >= 0) + srt_close(fd); + ret = 0; + goto restart; + } + fail1: + if (fd >= 0) + srt_close(fd); + freeaddrinfo(ai); + return ret; +} + +static int libsrt_open(URLContext *h, const char *uri, int flags) +{ + SRTContext *s = h->priv_data; + const char * p; + char buf[256]; + + if (srt_startup() < 0) { + return AVERROR_UNKNOWN; + } + + /* SRT options (srt/srt.h) */ + p = strchr(uri, '?'); + if (p) { + if (av_find_info_tag(buf, sizeof(buf), "maxbw", p)) { + s->maxbw = strtoll(buf, NULL, 0); + } + if (av_find_info_tag(buf, sizeof(buf), "pbkeylen", p)) { + s->pbkeylen = strtol(buf, NULL, 10); + } + if (av_find_info_tag(buf, sizeof(buf), "passphrase", p)) { + s->passphrase = av_strndup(buf, strlen(buf)); + } + if (av_find_info_tag(buf, sizeof(buf), "mss", p)) { + s->mss = strtol(buf, NULL, 10); + } + if (av_find_info_tag(buf, sizeof(buf), "ffs", p)) { + s->ffs = strtol(buf, NULL, 10); + } + if (av_find_info_tag(buf, sizeof(buf), "ipttl", p)) { + s->ipttl = strtol(buf, NULL, 10); + } + if (av_find_info_tag(buf, sizeof(buf), "iptos", p)) { + s->iptos = strtol(buf, NULL, 10); + } + if (av_find_info_tag(buf, sizeof(buf), "inputbw", p)) { + s->inputbw = strtoll(buf, NULL, 10); + } + if (av_find_info_tag(buf, sizeof(buf), "oheadbw", p)) { + s->oheadbw = strtoll(buf, NULL, 10); + } + if (av_find_info_tag(buf, sizeof(buf), "tsbpddelay", p)) { + s->tsbpddelay = strtol(buf, NULL, 10); + } + if (av_find_info_tag(buf, sizeof(buf), "tlpktdrop", p)) { + s->tlpktdrop = strtol(buf, NULL, 10); + } + if (av_find_info_tag(buf, sizeof(buf), "nakreport", p)) { + s->nakreport = strtol(buf, NULL, 10); + } + if (av_find_info_tag(buf, sizeof(buf), "connect_timeout", p)) { + s->connect_timeout = strtol(buf, NULL, 10); + } + if (av_find_info_tag(buf, sizeof(buf), "mode", p)) { + if (!strcmp(buf, "caller")) { + s->mode = SRT_MODE_CALLER; + } else if (!strcmp(buf, "listener")) { + s->mode = SRT_MODE_LISTENER; + } else if (!strcmp(buf, "rendezvous")) { + s->mode = SRT_MODE_RENDEZVOUS; + } else { + return AVERROR(EIO); + } + } + } + return libsrt_setup(h, uri, flags); +} + +static int libsrt_read(URLContext *h, uint8_t *buf, int size) +{ + SRTContext *s = h->priv_data; + int ret; + + if (!(h->flags & AVIO_FLAG_NONBLOCK)) { + ret = libsrt_network_wait_fd_timeout(h, s->eid, s->fd, 0, h->rw_timeout, &h->interrupt_callback); + if (ret) + return ret; + } + + ret = srt_recvmsg(s->fd, buf, size); + if (ret < 0) { + ret = libsrt_neterrno(h); + } + + return ret; +} + +static int libsrt_write(URLContext *h, const uint8_t *buf, int size) +{ + SRTContext *s = h->priv_data; + int ret; + + if (!(h->flags & AVIO_FLAG_NONBLOCK)) { + ret = libsrt_network_wait_fd_timeout(h, s->eid, s->fd, 1, h->rw_timeout, &h->interrupt_callback); + if (ret) + return ret; + } + + ret = srt_sendmsg(s->fd, buf, size, -1, 0); + if (ret < 0) { + ret = libsrt_neterrno(h); + } + + return ret; +} + +static int libsrt_close(URLContext *h) +{ + SRTContext *s = h->priv_data; + + srt_close(s->fd); + + srt_epoll_release(s->eid); + + srt_cleanup(); + + return 0; +} + +static int libsrt_get_file_handle(URLContext *h) +{ + SRTContext *s = h->priv_data; + return s->fd; +} + +static const AVClass libsrt_class = { + .class_name = "libsrt", + .item_name = av_default_item_name, + .option = libsrt_options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const URLProtocol ff_libsrt_protocol = { + .name = "srt", + .url_open = libsrt_open, + .url_read = libsrt_read, + .url_write = libsrt_write, + .url_close = libsrt_close, + .url_get_file_handle = libsrt_get_file_handle, + .priv_data_size = sizeof(SRTContext), + .flags = URL_PROTOCOL_FLAG_NETWORK, + .priv_data_class = &libsrt_class, +}; diff --git a/libavformat/lrcdec.c b/libavformat/lrcdec.c index 12f74b22a08ef..f4e9a4efa9118 100644 --- a/libavformat/lrcdec.c +++ b/libavformat/lrcdec.c @@ -212,6 +212,7 @@ static int lrc_read_header(AVFormatContext *s) } ff_subtitles_queue_finalize(s, &lrc->q); ff_metadata_conv_ctx(s, NULL, ff_lrc_metadata_conv); + av_bprint_finalize(&line, NULL); return 0; } diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index 94a56ebfa7a7e..1ded431b801cb 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -104,6 +104,7 @@ typedef struct EbmlList { typedef struct EbmlBin { int size; + AVBufferRef *buf; uint8_t *data; int64_t pos; } EbmlBin; @@ -338,9 +339,8 @@ typedef struct MatroskaDemuxContext { int64_t segment_start; /* the packet queue */ - AVPacket **packets; - int num_packets; - AVPacket *prev_pkt; + AVPacketList *queue; + AVPacketList *queue_end; int done; @@ -963,14 +963,19 @@ static int ebml_read_ascii(AVIOContext *pb, int size, char **str) */ static int ebml_read_binary(AVIOContext *pb, int length, EbmlBin *bin) { - av_fast_padded_malloc(&bin->data, &bin->size, length); - if (!bin->data) - return AVERROR(ENOMEM); + int ret; + + ret = av_buffer_realloc(&bin->buf, length + AV_INPUT_BUFFER_PADDING_SIZE); + if (ret < 0) + return ret; + memset(bin->buf->data + length, 0, AV_INPUT_BUFFER_PADDING_SIZE); + bin->data = bin->buf->data; bin->size = length; bin->pos = avio_tell(pb); if (avio_read(pb, bin->data, length) != length) { - av_freep(&bin->data); + av_buffer_unref(&bin->buf); + bin->data = NULL; bin->size = 0; return AVERROR(EIO); } @@ -1253,7 +1258,7 @@ static void ebml_free(EbmlSyntax *syntax, void *data) av_freep(data_off); break; case EBML_BIN: - av_freep(&((EbmlBin *) data_off)->data); + av_buffer_unref(&((EbmlBin *) data_off)->buf); break; case EBML_LEVEL1: case EBML_NEST: @@ -1362,7 +1367,7 @@ static int matroska_decode_buffer(uint8_t **buf, int *buf_size, return 0; pkt_size = isize + header_size; - pkt_data = av_malloc(pkt_size); + pkt_data = av_malloc(pkt_size + AV_INPUT_BUFFER_PADDING_SIZE); if (!pkt_data) return AVERROR(ENOMEM); @@ -1374,7 +1379,8 @@ static int matroska_decode_buffer(uint8_t **buf, int *buf_size, case MATROSKA_TRACK_ENCODING_COMP_LZO: do { olen = pkt_size *= 3; - newpktdata = av_realloc(pkt_data, pkt_size + AV_LZO_OUTPUT_PADDING); + newpktdata = av_realloc(pkt_data, pkt_size + AV_LZO_OUTPUT_PADDING + + AV_INPUT_BUFFER_PADDING_SIZE); if (!newpktdata) { result = AVERROR(ENOMEM); goto failed; @@ -1399,7 +1405,7 @@ static int matroska_decode_buffer(uint8_t **buf, int *buf_size, zstream.avail_in = isize; do { pkt_size *= 3; - newpktdata = av_realloc(pkt_data, pkt_size); + newpktdata = av_realloc(pkt_data, pkt_size + AV_INPUT_BUFFER_PADDING_SIZE); if (!newpktdata) { inflateEnd(&zstream); result = AVERROR(ENOMEM); @@ -1432,7 +1438,7 @@ static int matroska_decode_buffer(uint8_t **buf, int *buf_size, bzstream.avail_in = isize; do { pkt_size *= 3; - newpktdata = av_realloc(pkt_data, pkt_size); + newpktdata = av_realloc(pkt_data, pkt_size + AV_INPUT_BUFFER_PADDING_SIZE); if (!newpktdata) { BZ2_bzDecompressEnd(&bzstream); result = AVERROR(ENOMEM); @@ -1459,6 +1465,8 @@ static int matroska_decode_buffer(uint8_t **buf, int *buf_size, return AVERROR_INVALIDDATA; } + memset(pkt_data + pkt_size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + *buf = pkt_data; *buf_size = pkt_size; return 0; @@ -1989,18 +1997,25 @@ static int mkv_parse_video_projection(AVStream *st, const MatroskaTrack *track) return AVERROR_INVALIDDATA; } break; + case MATROSKA_VIDEO_PROJECTION_TYPE_RECTANGULAR: + /* No Spherical metadata */ + return 0; default: + av_log(NULL, AV_LOG_WARNING, + "Unknown spherical metadata type %"PRIu64"\n", + track->video.projection.type); return 0; } spherical = av_spherical_alloc(&spherical_size); if (!spherical) return AVERROR(ENOMEM); + spherical->projection = projection; - spherical->yaw = (int32_t)(track->video.projection.yaw * (1 << 16)); - spherical->pitch = (int32_t)(track->video.projection.pitch * (1 << 16)); - spherical->roll = (int32_t)(track->video.projection.roll * (1 << 16)); + spherical->yaw = (int32_t) (track->video.projection.yaw * (1 << 16)); + spherical->pitch = (int32_t) (track->video.projection.pitch * (1 << 16)); + spherical->roll = (int32_t) (track->video.projection.roll * (1 << 16)); spherical->padding = padding; @@ -2030,12 +2045,13 @@ static int get_qt_codec(MatroskaTrack *track, uint32_t *fourcc, enum AVCodecID * * by expanding/shifting the data by 4 bytes and storing the data * size at the start. */ if (ff_codec_get_id(codec_tags, AV_RL32(track->codec_priv.data))) { - uint8_t *p = av_realloc(track->codec_priv.data, - track->codec_priv.size + 4); - if (!p) - return AVERROR(ENOMEM); - memmove(p + 4, p, track->codec_priv.size); - track->codec_priv.data = p; + int ret = av_buffer_realloc(&track->codec_priv.buf, + track->codec_priv.size + 4 + AV_INPUT_BUFFER_PADDING_SIZE); + if (ret < 0) + return ret; + + track->codec_priv.data = track->codec_priv.buf->data; + memmove(track->codec_priv.data + 4, track->codec_priv.data, track->codec_priv.size); track->codec_priv.size += 4; AV_WB32(track->codec_priv.data, track->codec_priv.size); } @@ -2089,8 +2105,16 @@ static int matroska_parse_tracks(AVFormatContext *s) } if (track->type == MATROSKA_TRACK_TYPE_VIDEO) { - if (!track->default_duration && track->video.frame_rate > 0) - track->default_duration = 1000000000 / track->video.frame_rate; + if (!track->default_duration && track->video.frame_rate > 0) { + double default_duration = 1000000000 / track->video.frame_rate; + if (default_duration > UINT64_MAX || default_duration < 0) { + av_log(matroska->ctx, AV_LOG_WARNING, + "Invalid frame rate %e. Cannot calculate default duration.\n", + track->video.frame_rate); + } else { + track->default_duration = default_duration; + } + } if (track->video.display_width == -1) track->video.display_width = track->video.pixel_width; if (track->video.display_height == -1) @@ -2148,8 +2172,19 @@ static int matroska_parse_tracks(AVFormatContext *s) "Failed to decode codec private data\n"); } - if (codec_priv != track->codec_priv.data) - av_free(codec_priv); + if (codec_priv != track->codec_priv.data) { + av_buffer_unref(&track->codec_priv.buf); + if (track->codec_priv.data) { + track->codec_priv.buf = av_buffer_create(track->codec_priv.data, + track->codec_priv.size + AV_INPUT_BUFFER_PADDING_SIZE, + NULL, NULL, 0); + if (!track->codec_priv.buf) { + av_freep(&track->codec_priv.data); + track->codec_priv.size = 0; + return AVERROR(ENOMEM); + } + } + } } } @@ -2382,6 +2417,10 @@ static int matroska_parse_tracks(AVFormatContext *s) return ret; } else if (codec_id == AV_CODEC_ID_PRORES && track->codec_priv.size == 4) { fourcc = AV_RL32(track->codec_priv.data); + } else if (codec_id == AV_CODEC_ID_VP9 && track->codec_priv.size) { + /* we don't need any value stored in CodecPrivate. + make sure that it's not exported as extradata. */ + track->codec_priv.size = 0; } track->codec_priv.size -= extradata_offset; @@ -2506,7 +2545,9 @@ static int matroska_parse_tracks(AVFormatContext *s) st->codecpar->channels = track->audio.channels; if (!st->codecpar->bits_per_coded_sample) st->codecpar->bits_per_coded_sample = track->audio.bitdepth; - if (st->codecpar->codec_id == AV_CODEC_ID_MP3) + if (st->codecpar->codec_id == AV_CODEC_ID_MP3 || + st->codecpar->codec_id == AV_CODEC_ID_MLP || + st->codecpar->codec_id == AV_CODEC_ID_TRUEHD) st->need_parsing = AVSTREAM_PARSE_FULL; else if (st->codecpar->codec_id != AV_CODEC_ID_AAC) st->need_parsing = AVSTREAM_PARSE_HEADERS; @@ -2701,11 +2742,11 @@ static int matroska_read_header(AVFormatContext *s) static int matroska_deliver_packet(MatroskaDemuxContext *matroska, AVPacket *pkt) { - if (matroska->num_packets > 0) { + if (matroska->queue) { MatroskaTrack *tracks = matroska->tracks.elem; MatroskaTrack *track; - memcpy(pkt, matroska->packets[0], sizeof(AVPacket)); - av_freep(&matroska->packets[0]); + + ff_packet_list_get(&matroska->queue, &matroska->queue_end, pkt); track = &tracks[pkt->stream_index]; if (track->has_palette) { uint8_t *pal = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE); @@ -2716,20 +2757,6 @@ static int matroska_deliver_packet(MatroskaDemuxContext *matroska, } track->has_palette = 0; } - if (matroska->num_packets > 1) { - void *newpackets; - memmove(&matroska->packets[0], &matroska->packets[1], - (matroska->num_packets - 1) * sizeof(AVPacket *)); - newpackets = av_realloc(matroska->packets, - (matroska->num_packets - 1) * - sizeof(AVPacket *)); - if (newpackets) - matroska->packets = newpackets; - } else { - av_freep(&matroska->packets); - matroska->prev_pkt = NULL; - } - matroska->num_packets--; return 0; } @@ -2741,16 +2768,7 @@ static int matroska_deliver_packet(MatroskaDemuxContext *matroska, */ static void matroska_clear_queue(MatroskaDemuxContext *matroska) { - matroska->prev_pkt = NULL; - if (matroska->packets) { - int n; - for (n = 0; n < matroska->num_packets; n++) { - av_packet_unref(matroska->packets[n]); - av_freep(&matroska->packets[n]); - } - av_freep(&matroska->packets); - matroska->num_packets = 0; - } + ff_packet_list_free(&matroska->queue, &matroska->queue_end); } static int matroska_parse_laces(MatroskaDemuxContext *matroska, uint8_t **buf, @@ -2916,13 +2934,10 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska, while (track->audio.pkt_cnt) { int ret; - AVPacket *pkt = av_mallocz(sizeof(AVPacket)); - if (!pkt) - return AVERROR(ENOMEM); + AVPacket pktl, *pkt = &pktl; ret = av_new_packet(pkt, a); if (ret < 0) { - av_free(pkt); return ret; } memcpy(pkt->data, @@ -2932,7 +2947,11 @@ static int matroska_parse_rm_audio(MatroskaDemuxContext *matroska, track->audio.buf_timecode = AV_NOPTS_VALUE; pkt->pos = pos; pkt->stream_index = st->index; - dynarray_add(&matroska->packets, &matroska->num_packets, pkt); + ret = ff_packet_list_put(&matroska->queue, &matroska->queue_end, pkt, 0); + if (ret < 0) { + av_packet_unref(pkt); + return AVERROR(ENOMEM); + } } return 0; @@ -2985,7 +3004,7 @@ static int matroska_parse_wavpack(MatroskaTrack *track, uint8_t *src, goto fail; } - tmp = av_realloc(dst, dstlen + blocksize + 32); + tmp = av_realloc(dst, dstlen + blocksize + 32 + AV_INPUT_BUFFER_PADDING_SIZE); if (!tmp) { ret = AVERROR(ENOMEM); goto fail; @@ -3009,6 +3028,8 @@ static int matroska_parse_wavpack(MatroskaTrack *track, uint8_t *src, offset += blocksize + 32; } + memset(dst + dstlen, 0, AV_INPUT_BUFFER_PADDING_SIZE); + *pdst = dst; *size = dstlen; @@ -3019,6 +3040,30 @@ static int matroska_parse_wavpack(MatroskaTrack *track, uint8_t *src, return ret; } +static int matroska_parse_prores(MatroskaTrack *track, uint8_t *src, + uint8_t **pdst, int *size) +{ + uint8_t *dst = src; + int dstlen = *size; + + if (AV_RB32(&src[4]) != MKBETAG('i', 'c', 'p', 'f')) { + dst = av_malloc(dstlen + 8 + AV_INPUT_BUFFER_PADDING_SIZE); + if (!dst) + return AVERROR(ENOMEM); + + AV_WB32(dst, dstlen); + AV_WB32(dst + 4, MKBETAG('i', 'c', 'p', 'f')); + memcpy(dst + 8, src, dstlen); + memset(dst + 8 + dstlen, 0, AV_INPUT_BUFFER_PADDING_SIZE); + dstlen += 8; + } + + *pdst = dst; + *size = dstlen; + + return 0; +} + static int matroska_parse_webvtt(MatroskaDemuxContext *matroska, MatroskaTrack *track, AVStream *st, @@ -3027,7 +3072,7 @@ static int matroska_parse_webvtt(MatroskaDemuxContext *matroska, uint64_t duration, int64_t pos) { - AVPacket *pkt; + AVPacket pktl, *pkt = &pktl; uint8_t *id, *settings, *text, *buf; int id_len, settings_len, text_len; uint8_t *p, *q; @@ -3084,13 +3129,9 @@ static int matroska_parse_webvtt(MatroskaDemuxContext *matroska, if (text_len <= 0) return AVERROR_INVALIDDATA; - pkt = av_mallocz(sizeof(*pkt)); - if (!pkt) - return AVERROR(ENOMEM); err = av_new_packet(pkt, text_len); if (err < 0) { - av_free(pkt); - return AVERROR(err); + return err; } memcpy(pkt->data, text, text_len); @@ -3100,7 +3141,7 @@ static int matroska_parse_webvtt(MatroskaDemuxContext *matroska, AV_PKT_DATA_WEBVTT_IDENTIFIER, id_len); if (!buf) { - av_free(pkt); + av_packet_unref(pkt); return AVERROR(ENOMEM); } memcpy(buf, id, id_len); @@ -3111,7 +3152,7 @@ static int matroska_parse_webvtt(MatroskaDemuxContext *matroska, AV_PKT_DATA_WEBVTT_SETTINGS, settings_len); if (!buf) { - av_free(pkt); + av_packet_unref(pkt); return AVERROR(ENOMEM); } memcpy(buf, settings, settings_len); @@ -3129,15 +3170,18 @@ static int matroska_parse_webvtt(MatroskaDemuxContext *matroska, pkt->duration = duration; pkt->pos = pos; - dynarray_add(&matroska->packets, &matroska->num_packets, pkt); - matroska->prev_pkt = pkt; + err = ff_packet_list_put(&matroska->queue, &matroska->queue_end, pkt, 0); + if (err < 0) { + av_packet_unref(pkt); + return AVERROR(ENOMEM); + } return 0; } static int matroska_parse_frame(MatroskaDemuxContext *matroska, MatroskaTrack *track, AVStream *st, - uint8_t *data, int pkt_size, + AVBufferRef *buf, uint8_t *data, int pkt_size, uint64_t timecode, uint64_t lace_duration, int64_t pos, int is_keyframe, uint8_t *additional, uint64_t additional_id, int additional_size, @@ -3145,8 +3189,8 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, { MatroskaTrackEncoding *encodings = track->encodings.elem; uint8_t *pkt_data = data; - int offset = 0, res; - AVPacket *pkt; + int res; + AVPacket pktl, *pkt = &pktl; if (encodings && !encodings->type && encodings->scope & 1) { res = matroska_decode_buffer(&pkt_data, &pkt_size, track); @@ -3167,34 +3211,33 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, pkt_data = wv_data; } - if (st->codecpar->codec_id == AV_CODEC_ID_PRORES && - AV_RB32(&data[4]) != MKBETAG('i', 'c', 'p', 'f')) - offset = 8; - - pkt = av_mallocz(sizeof(AVPacket)); - if (!pkt) { + if (st->codecpar->codec_id == AV_CODEC_ID_PRORES) { + uint8_t *pr_data; + res = matroska_parse_prores(track, pkt_data, &pr_data, &pkt_size); + if (res < 0) { + av_log(matroska->ctx, AV_LOG_ERROR, + "Error parsing a prores block.\n"); + goto fail; + } if (pkt_data != data) av_freep(&pkt_data); - return AVERROR(ENOMEM); + pkt_data = pr_data; } - /* XXX: prevent data copy... */ - if (av_new_packet(pkt, pkt_size + offset) < 0) { - av_free(pkt); + + av_init_packet(pkt); + if (pkt_data != data) + pkt->buf = av_buffer_create(pkt_data, pkt_size + AV_INPUT_BUFFER_PADDING_SIZE, + NULL, NULL, 0); + else + pkt->buf = av_buffer_ref(buf); + + if (!pkt->buf) { res = AVERROR(ENOMEM); goto fail; } - if (st->codecpar->codec_id == AV_CODEC_ID_PRORES && offset == 8) { - uint8_t *buf = pkt->data; - bytestream_put_be32(&buf, pkt_size); - bytestream_put_be32(&buf, MKBETAG('i', 'c', 'p', 'f')); - } - - memcpy(pkt->data + offset, pkt_data, pkt_size); - - if (pkt_data != data) - av_freep(&pkt_data); - + pkt->data = pkt_data; + pkt->size = pkt_size; pkt->flags = is_keyframe; pkt->stream_index = st->index; @@ -3204,7 +3247,6 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, additional_size + 8); if (!side_data) { av_packet_unref(pkt); - av_free(pkt); return AVERROR(ENOMEM); } AV_WB64(side_data, additional_id); @@ -3217,7 +3259,6 @@ static int matroska_parse_frame(MatroskaDemuxContext *matroska, 10); if (!side_data) { av_packet_unref(pkt); - av_free(pkt); return AVERROR(ENOMEM); } discard_padding = av_rescale_q(discard_padding, @@ -3245,8 +3286,11 @@ FF_DISABLE_DEPRECATION_WARNINGS FF_ENABLE_DEPRECATION_WARNINGS #endif - dynarray_add(&matroska->packets, &matroska->num_packets, pkt); - matroska->prev_pkt = pkt; + res = ff_packet_list_put(&matroska->queue, &matroska->queue_end, pkt, 0); + if (res < 0) { + av_packet_unref(pkt); + return AVERROR(ENOMEM); + } return 0; @@ -3256,7 +3300,7 @@ FF_ENABLE_DEPRECATION_WARNINGS return res; } -static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, +static int matroska_parse_block(MatroskaDemuxContext *matroska, AVBufferRef *buf, uint8_t *data, int size, int64_t pos, uint64_t cluster_time, uint64_t block_duration, int is_keyframe, uint8_t *additional, uint64_t additional_id, int additional_size, @@ -3374,7 +3418,7 @@ static int matroska_parse_block(MatroskaDemuxContext *matroska, uint8_t *data, if (res) goto end; } else { - res = matroska_parse_frame(matroska, track, st, data, lace_size[n], + res = matroska_parse_frame(matroska, track, st, buf, data, lace_size[n], timecode, lace_duration, pos, !n ? is_keyframe : 0, additional, additional_id, additional_size, @@ -3410,7 +3454,6 @@ static int matroska_parse_cluster_incremental(MatroskaDemuxContext *matroska) memset(&matroska->current_cluster, 0, sizeof(MatroskaCluster)); matroska->current_cluster_num_blocks = 0; matroska->current_cluster_pos = avio_tell(matroska->ctx->pb); - matroska->prev_pkt = NULL; /* sizeof the ID which was already read */ if (matroska->current_id) matroska->current_cluster_pos -= 4; @@ -3438,7 +3481,7 @@ static int matroska_parse_cluster_incremental(MatroskaDemuxContext *matroska) blocks[i].additional.data : NULL; if (!blocks[i].non_simple) blocks[i].duration = 0; - res = matroska_parse_block(matroska, blocks[i].bin.data, + res = matroska_parse_block(matroska, blocks[i].bin.buf, blocks[i].bin.data, blocks[i].bin.size, blocks[i].bin.pos, matroska->current_cluster.timecode, blocks[i].duration, is_keyframe, @@ -3463,7 +3506,6 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska) if (!matroska->contains_ssa) return matroska_parse_cluster_incremental(matroska); pos = avio_tell(matroska->ctx->pb); - matroska->prev_pkt = NULL; if (matroska->current_id) pos -= 4; /* sizeof the ID which was already read */ res = ebml_parse(matroska, matroska_clusters, &cluster); @@ -3472,7 +3514,7 @@ static int matroska_parse_cluster(MatroskaDemuxContext *matroska) for (i = 0; i < blocks_list->nb_elem; i++) if (blocks[i].bin.size > 0 && blocks[i].bin.data) { int is_keyframe = blocks[i].non_simple ? blocks[i].reference == INT64_MIN : -1; - res = matroska_parse_block(matroska, blocks[i].bin.data, + res = matroska_parse_block(matroska, blocks[i].bin.buf, blocks[i].bin.data, blocks[i].bin.size, blocks[i].bin.pos, cluster.timecode, blocks[i].duration, is_keyframe, NULL, 0, 0, pos, @@ -3648,10 +3690,10 @@ static int webm_clusters_start_with_keyframe(AVFormatContext *s) matroska->current_id = 0; matroska_clear_queue(matroska); if (matroska_parse_cluster(matroska) < 0 || - matroska->num_packets <= 0) { + !matroska->queue) { break; } - pkt = matroska->packets[0]; + pkt = &matroska->queue->pkt; cluster_pos += cluster_length + 12; // 12 is the offset of the cluster id and length. if (!(pkt->flags & AV_PKT_FLAG_KEY)) { rv = 0; @@ -3938,8 +3980,8 @@ static int webm_dash_manifest_read_header(AVFormatContext *s) } // basename of the file - buf = strrchr(s->filename, '/'); - av_dict_set(&s->streams[0]->metadata, FILENAME, buf ? ++buf : s->filename, 0); + buf = strrchr(s->url, '/'); + av_dict_set(&s->streams[0]->metadata, FILENAME, buf ? ++buf : s->url, 0); // track number tracks = matroska->tracks.elem; diff --git a/libavformat/matroskaenc.c b/libavformat/matroskaenc.c index 6f094c458c8d2..5950b4de4436f 100644 --- a/libavformat/matroskaenc.c +++ b/libavformat/matroskaenc.c @@ -953,78 +953,79 @@ static int mkv_write_video_color(AVIOContext *pb, AVCodecParameters *par, AVStre return 0; } -static int mkv_write_video_projection(AVFormatContext *s, AVIOContext *pb, AVStream *st) +static int mkv_write_video_projection(AVFormatContext *s, AVIOContext *pb, + AVStream *st) { + AVIOContext b; + AVIOContext *dyn_cp; int side_data_size = 0; + int ret, projection_size; + uint8_t *projection_ptr; + uint8_t private[20]; + const AVSphericalMapping *spherical = - (const AVSphericalMapping*) av_stream_get_side_data(st, AV_PKT_DATA_SPHERICAL, + (const AVSphericalMapping *)av_stream_get_side_data(st, AV_PKT_DATA_SPHERICAL, &side_data_size); - if (side_data_size) { - AVIOContext *dyn_cp; - uint8_t *projection_ptr; - int ret, projection_size; + if (!side_data_size) + return 0; - ret = avio_open_dyn_buf(&dyn_cp); - if (ret < 0) - return ret; + ret = avio_open_dyn_buf(&dyn_cp); + if (ret < 0) + return ret; - switch (spherical->projection) { - case AV_SPHERICAL_EQUIRECTANGULAR: - put_ebml_uint(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONTYPE, - MATROSKA_VIDEO_PROJECTION_TYPE_EQUIRECTANGULAR); - break; - case AV_SPHERICAL_EQUIRECTANGULAR_TILE: - { - AVIOContext b; - uint8_t private[20]; - ffio_init_context(&b, private, sizeof(private), - 1, NULL, NULL, NULL, NULL); - put_ebml_uint(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONTYPE, - MATROSKA_VIDEO_PROJECTION_TYPE_EQUIRECTANGULAR); - avio_wb32(&b, 0); // version + flags - avio_wb32(&b, spherical->bound_top); - avio_wb32(&b, spherical->bound_bottom); - avio_wb32(&b, spherical->bound_left); - avio_wb32(&b, spherical->bound_right); - put_ebml_binary(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONPRIVATE, private, sizeof(private)); - break; - } - case AV_SPHERICAL_CUBEMAP: - { - AVIOContext b; - uint8_t private[12]; - ffio_init_context(&b, private, sizeof(private), - 1, NULL, NULL, NULL, NULL); - put_ebml_uint(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONTYPE, - MATROSKA_VIDEO_PROJECTION_TYPE_CUBEMAP); - avio_wb32(&b, 0); // version + flags - avio_wb32(&b, 0); // layout - avio_wb32(&b, spherical->padding); - put_ebml_binary(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONPRIVATE, private, sizeof(private)); - break; - } - default: - av_log(s, AV_LOG_WARNING, "Unknown projection type\n"); - goto end; - } + switch (spherical->projection) { + case AV_SPHERICAL_EQUIRECTANGULAR: + put_ebml_uint(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONTYPE, + MATROSKA_VIDEO_PROJECTION_TYPE_EQUIRECTANGULAR); + break; + case AV_SPHERICAL_EQUIRECTANGULAR_TILE: + ffio_init_context(&b, private, 20, 1, NULL, NULL, NULL, NULL); + put_ebml_uint(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONTYPE, + MATROSKA_VIDEO_PROJECTION_TYPE_EQUIRECTANGULAR); + avio_wb32(&b, 0); // version + flags + avio_wb32(&b, spherical->bound_top); + avio_wb32(&b, spherical->bound_bottom); + avio_wb32(&b, spherical->bound_left); + avio_wb32(&b, spherical->bound_right); + put_ebml_binary(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONPRIVATE, + private, avio_tell(&b)); + break; + case AV_SPHERICAL_CUBEMAP: + ffio_init_context(&b, private, 12, 1, NULL, NULL, NULL, NULL); + put_ebml_uint(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONTYPE, + MATROSKA_VIDEO_PROJECTION_TYPE_CUBEMAP); + avio_wb32(&b, 0); // version + flags + avio_wb32(&b, 0); // layout + avio_wb32(&b, spherical->padding); + put_ebml_binary(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONPRIVATE, + private, avio_tell(&b)); + break; + default: + av_log(s, AV_LOG_WARNING, "Unknown projection type\n"); + goto end; + } - if (spherical->yaw) - put_ebml_float(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONPOSEYAW, (double)spherical->yaw / (1 << 16)); - if (spherical->pitch) - put_ebml_float(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONPOSEPITCH, (double)spherical->pitch / (1 << 16)); - if (spherical->roll) - put_ebml_float(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONPOSEROLL, (double)spherical->roll / (1 << 16)); + if (spherical->yaw) + put_ebml_float(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONPOSEYAW, + (double) spherical->yaw / (1 << 16)); + if (spherical->pitch) + put_ebml_float(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONPOSEPITCH, + (double) spherical->pitch / (1 << 16)); + if (spherical->roll) + put_ebml_float(dyn_cp, MATROSKA_ID_VIDEOPROJECTIONPOSEROLL, + (double) spherical->roll / (1 << 16)); end: - projection_size = avio_close_dyn_buf(dyn_cp, &projection_ptr); - if (projection_size) { - ebml_master projection = start_ebml_master(pb, MATROSKA_ID_VIDEOPROJECTION, projection_size); - avio_write(pb, projection_ptr, projection_size); - end_ebml_master(pb, projection); - } - av_freep(&projection_ptr); + projection_size = avio_close_dyn_buf(dyn_cp, &projection_ptr); + if (projection_size) { + ebml_master projection = start_ebml_master(pb, + MATROSKA_ID_VIDEOPROJECTION, + projection_size); + avio_write(pb, projection_ptr, projection_size); + end_ebml_master(pb, projection); } + av_freep(&projection_ptr); return 0; } @@ -1859,17 +1860,6 @@ static int mkv_write_header(AVFormatContext *s) version = 4; for (i = 0; i < s->nb_streams; i++) { - if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_ATRAC3 || - s->streams[i]->codecpar->codec_id == AV_CODEC_ID_COOK || - s->streams[i]->codecpar->codec_id == AV_CODEC_ID_RA_288 || - s->streams[i]->codecpar->codec_id == AV_CODEC_ID_SIPR || - s->streams[i]->codecpar->codec_id == AV_CODEC_ID_RV10 || - s->streams[i]->codecpar->codec_id == AV_CODEC_ID_RV20) { - av_log(s, AV_LOG_ERROR, - "The Matroska muxer does not yet support muxing %s\n", - avcodec_get_name(s->streams[i]->codecpar->codec_id)); - return AVERROR_PATCHWELCOME; - } if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_OPUS || av_dict_get(s->streams[i]->metadata, "stereo_mode", NULL, 0) || av_dict_get(s->streams[i]->metadata, "alpha_mode", NULL, 0)) @@ -1975,6 +1965,10 @@ static int mkv_write_header(AVFormatContext *s) // initialize stream_duration fields mkv->stream_durations = av_mallocz(s->nb_streams * sizeof(int64_t)); mkv->stream_duration_offsets = av_mallocz(s->nb_streams * sizeof(int64_t)); + if (!mkv->stream_durations || !mkv->stream_duration_offsets) { + ret = AVERROR(ENOMEM); + goto fail; + } ret = mkv_write_tracks(s); if (ret < 0) @@ -2007,6 +2001,8 @@ static int mkv_write_header(AVFormatContext *s) } if ((pb->seekable & AVIO_SEEKABLE_NORMAL) && mkv->reserve_cues_space) { mkv->cues_pos = avio_tell(pb); + if (mkv->reserve_cues_space == 1) + mkv->reserve_cues_space++; put_ebml_void(pb, mkv->reserve_cues_space); } @@ -2648,6 +2644,27 @@ static int mkv_init(struct AVFormatContext *s) { int i; + if (s->nb_streams > MAX_TRACKS) { + av_log(s, AV_LOG_ERROR, + "At most %d streams are supported for muxing in Matroska\n", + MAX_TRACKS); + return AVERROR(EINVAL); + } + + for (i = 0; i < s->nb_streams; i++) { + if (s->streams[i]->codecpar->codec_id == AV_CODEC_ID_ATRAC3 || + s->streams[i]->codecpar->codec_id == AV_CODEC_ID_COOK || + s->streams[i]->codecpar->codec_id == AV_CODEC_ID_RA_288 || + s->streams[i]->codecpar->codec_id == AV_CODEC_ID_SIPR || + s->streams[i]->codecpar->codec_id == AV_CODEC_ID_RV10 || + s->streams[i]->codecpar->codec_id == AV_CODEC_ID_RV20) { + av_log(s, AV_LOG_ERROR, + "The Matroska muxer does not yet support muxing %s\n", + avcodec_get_name(s->streams[i]->codecpar->codec_id)); + return AVERROR_PATCHWELCOME; + } + } + if (s->avoid_negative_ts < 0) { s->avoid_negative_ts = 1; s->internal->avoid_negative_ts_use_pts = 1; diff --git a/libavformat/mlvdec.c b/libavformat/mlvdec.c index 319cd26de4f00..d387c871ee953 100644 --- a/libavformat/mlvdec.c +++ b/libavformat/mlvdec.c @@ -342,9 +342,9 @@ static int read_header(AVFormatContext *avctx) return ret; /* scan secondary files */ - if (strlen(avctx->filename) > 2) { + if (strlen(avctx->url) > 2) { int i; - char *filename = av_strdup(avctx->filename); + char *filename = av_strdup(avctx->url); if (!filename) return AVERROR(ENOMEM); diff --git a/libavformat/mov.c b/libavformat/mov.c index 899690d920d47..01b315ce8cdcf 100644 --- a/libavformat/mov.c +++ b/libavformat/mov.c @@ -336,6 +336,8 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom) case MKTAG( 'l','d','e','s'): key = "synopsis"; break; case MKTAG( 'l','o','c','i'): return mov_metadata_loci(c, pb, atom.size); + case MKTAG( 'm','a','n','u'): key = "make"; break; + case MKTAG( 'm','o','d','l'): key = "model"; break; case MKTAG( 'p','c','s','t'): key = "podcast"; parse = mov_metadata_int8_no_padding; break; case MKTAG( 'p','g','a','p'): key = "gapless_playback"; @@ -410,7 +412,11 @@ static int mov_read_udta_string(MOVContext *c, AVIOContext *pb, MOVAtom atom) int ret = mov_read_covr(c, pb, data_type, str_size); if (ret < 0) { av_log(c->fc, AV_LOG_ERROR, "Error parsing cover art.\n"); + return ret; } + atom.size -= str_size; + if (atom.size > 8) + goto retry; return ret; } else if (!key && c->found_hdlr_mdta && c->meta_keys) { uint32_t index = AV_RB32(&atom.type); @@ -767,28 +773,6 @@ static int mov_read_hdlr(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } -int ff_mov_read_esds(AVFormatContext *fc, AVIOContext *pb) -{ - AVStream *st; - int tag; - - if (fc->nb_streams < 1) - return 0; - st = fc->streams[fc->nb_streams-1]; - - avio_rb32(pb); /* version + flags */ - ff_mp4_read_descr(fc, pb, &tag); - if (tag == MP4ESDescrTag) { - ff_mp4_parse_es_descr(pb, NULL); - } else - avio_rb16(pb); /* ID */ - - ff_mp4_read_descr(fc, pb, &tag); - if (tag == MP4DecConfigDescrTag) - ff_mp4_read_dec_config_descr(fc, st, pb); - return 0; -} - static int mov_read_esds(MOVContext *c, AVIOContext *pb, MOVAtom atom) { return ff_mov_read_esds(c->fc, pb); @@ -1168,6 +1152,216 @@ static int mov_read_moov(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; /* now go for mdat */ } +static MOVFragmentStreamInfo * get_frag_stream_info( + MOVFragmentIndex *frag_index, + int index, + int id) +{ + int i; + MOVFragmentIndexItem * item; + + if (index < 0 || index >= frag_index->nb_items) + return NULL; + item = &frag_index->item[index]; + for (i = 0; i < item->nb_stream_info; i++) + if (item->stream_info[i].id == id) + return &item->stream_info[i]; + + // This shouldn't happen + return NULL; +} + +static void set_frag_stream(MOVFragmentIndex *frag_index, int id) +{ + int i; + MOVFragmentIndexItem * item; + + if (frag_index->current < 0 || + frag_index->current >= frag_index->nb_items) + return; + + item = &frag_index->item[frag_index->current]; + for (i = 0; i < item->nb_stream_info; i++) + if (item->stream_info[i].id == id) { + item->current = i; + return; + } + + // id not found. This shouldn't happen. + item->current = -1; +} + +static MOVFragmentStreamInfo * get_current_frag_stream_info( + MOVFragmentIndex *frag_index) +{ + MOVFragmentIndexItem *item; + if (frag_index->current < 0 || + frag_index->current >= frag_index->nb_items) + return NULL; + + item = &frag_index->item[frag_index->current]; + if (item->current >= 0 && item->current < item->nb_stream_info) + return &item->stream_info[item->current]; + + // This shouldn't happen + return NULL; +} + +static int search_frag_moof_offset(MOVFragmentIndex *frag_index, int64_t offset) +{ + int a, b, m; + int64_t moof_offset; + + // Optimize for appending new entries + if (!frag_index->nb_items || + frag_index->item[frag_index->nb_items - 1].moof_offset < offset) + return frag_index->nb_items; + + a = -1; + b = frag_index->nb_items; + + while (b - a > 1) { + m = (a + b) >> 1; + moof_offset = frag_index->item[m].moof_offset; + if (moof_offset >= offset) + b = m; + if (moof_offset <= offset) + a = m; + } + return b; +} + +static int64_t get_stream_info_time(MOVFragmentStreamInfo * frag_stream_info) +{ + + if (frag_stream_info) { + if (frag_stream_info->sidx_pts != AV_NOPTS_VALUE) + return frag_stream_info->sidx_pts; + if (frag_stream_info->first_tfra_pts != AV_NOPTS_VALUE) + return frag_stream_info->first_tfra_pts; + if (frag_stream_info->tfdt_dts != AV_NOPTS_VALUE) + return frag_stream_info->tfdt_dts; + } + return AV_NOPTS_VALUE; +} + +static int64_t get_frag_time(MOVFragmentIndex *frag_index, + int index, int track_id) +{ + MOVFragmentStreamInfo * frag_stream_info; + int64_t timestamp; + int i; + + if (track_id >= 0) { + frag_stream_info = get_frag_stream_info(frag_index, index, track_id); + return frag_stream_info->sidx_pts; + } + + for (i = 0; i < frag_index->item[index].nb_stream_info; i++) { + frag_stream_info = &frag_index->item[index].stream_info[i]; + timestamp = get_stream_info_time(frag_stream_info); + if (timestamp != AV_NOPTS_VALUE) + return timestamp; + } + return AV_NOPTS_VALUE; +} + +static int search_frag_timestamp(MOVFragmentIndex *frag_index, + AVStream *st, int64_t timestamp) +{ + int a, b, m; + int64_t frag_time; + int id = -1; + + if (st) { + // If the stream is referenced by any sidx, limit the search + // to fragments that referenced this stream in the sidx + MOVStreamContext *sc = st->priv_data; + if (sc->has_sidx) + id = st->id; + } + + a = -1; + b = frag_index->nb_items; + + while (b - a > 1) { + m = (a + b) >> 1; + frag_time = get_frag_time(frag_index, m, id); + if (frag_time != AV_NOPTS_VALUE) { + if (frag_time >= timestamp) + b = m; + if (frag_time <= timestamp) + a = m; + } + } + return a; +} + +static int update_frag_index(MOVContext *c, int64_t offset) +{ + int index, i; + MOVFragmentIndexItem * item; + MOVFragmentStreamInfo * frag_stream_info; + + // If moof_offset already exists in frag_index, return index to it + index = search_frag_moof_offset(&c->frag_index, offset); + if (index < c->frag_index.nb_items && + c->frag_index.item[index].moof_offset == offset) + return index; + + // offset is not yet in frag index. + // Insert new item at index (sorted by moof offset) + item = av_fast_realloc(c->frag_index.item, + &c->frag_index.allocated_size, + (c->frag_index.nb_items + 1) * + sizeof(*c->frag_index.item)); + if(!item) + return -1; + c->frag_index.item = item; + + frag_stream_info = av_realloc_array(NULL, c->fc->nb_streams, + sizeof(*item->stream_info)); + if (!frag_stream_info) + return -1; + + for (i = 0; i < c->fc->nb_streams; i++) { + frag_stream_info[i].id = c->fc->streams[i]->id; + frag_stream_info[i].sidx_pts = AV_NOPTS_VALUE; + frag_stream_info[i].tfdt_dts = AV_NOPTS_VALUE; + frag_stream_info[i].first_tfra_pts = AV_NOPTS_VALUE; + frag_stream_info[i].index_entry = -1; + } + + if (index < c->frag_index.nb_items) + memmove(c->frag_index.item + index + 1, c->frag_index.item + index, + (c->frag_index.nb_items - index) * sizeof(*c->frag_index.item)); + + item = &c->frag_index.item[index]; + item->headers_read = 0; + item->current = 0; + item->nb_stream_info = c->fc->nb_streams; + item->moof_offset = offset; + item->stream_info = frag_stream_info; + c->frag_index.nb_items++; + + return index; +} + +static void fix_frag_index_entries(MOVFragmentIndex *frag_index, int index, + int id, int entries) +{ + int i; + MOVFragmentStreamInfo * frag_stream_info; + + if (index < 0) + return; + for (i = index; i < frag_index->nb_items; i++) { + frag_stream_info = get_frag_stream_info(frag_index, i, id); + if (frag_stream_info && frag_stream_info->index_entry >= 0) + frag_stream_info->index_entry += entries; + } +} + static int mov_read_moof(MOVContext *c, AVIOContext *pb, MOVAtom atom) { if (!c->has_looked_for_mfra && c->use_mfra_for > 0) { @@ -1187,6 +1381,7 @@ static int mov_read_moof(MOVContext *c, AVIOContext *pb, MOVAtom atom) } c->fragment.moof_offset = c->fragment.implicit_offset = avio_tell(pb) - 8; av_log(c->fc, AV_LOG_TRACE, "moof offset %"PRIx64"\n", c->fragment.moof_offset); + c->frag_index.current = update_frag_index(c, c->fragment.moof_offset); return mov_read_default(c, pb, atom); } @@ -1544,6 +1739,7 @@ static int mov_read_ares(MOVContext *c, AVIOContext *pb, MOVAtom atom) par->width = 1440; return 0; } else if ((par->codec_tag == MKTAG('A', 'V', 'd', '1') || + par->codec_tag == MKTAG('A', 'V', 'j', '2') || par->codec_tag == MKTAG('A', 'V', 'd', 'n')) && atom.size >= 24) { int num, den; @@ -1696,8 +1892,14 @@ static int mov_read_glbl(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (type == MKTAG('f','i','e','l') && size == atom.size) return mov_read_default(c, pb, atom); } + c->has_extradata = 1; if (st->codecpar->extradata_size > 1 && st->codecpar->extradata) { - av_log(c, AV_LOG_WARNING, "ignoring multiple glbl\n"); + if (c->allow_multi_extradata) { + av_log(c, AV_LOG_WARNING, "found multiple glbl\n"); + } else { + av_log(c, AV_LOG_WARNING, "ignoring multiple glbl\n"); + return 0; + } return 0; } av_freep(&st->codecpar->extradata); @@ -1801,26 +2003,14 @@ static int mov_read_stco(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->chunk_count = i; - if (pb->eof_reached) + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted STCO atom\n"); return AVERROR_EOF; + } return 0; } -/** - * Compute codec id for 'lpcm' tag. - * See CoreAudioTypes and AudioStreamBasicDescription at Apple. - */ -enum AVCodecID ff_mov_get_lpcm_codec_id(int bps, int flags) -{ - /* lpcm flags: - * 0x1 = float - * 0x2 = big-endian - * 0x4 = signed - */ - return ff_get_pcm_codec_id(bps, flags & 1, flags & 2, flags & 4 ? -1 : 0); -} - static int mov_codec_id(AVStream *st, uint32_t format) { int id = ff_codec_get_id(ff_codec_movaudio_tags, format); @@ -2219,6 +2409,7 @@ static int mov_finalize_stsd_codec(MOVContext *c, AVIOContext *pb, case AV_CODEC_ID_EAC3: case AV_CODEC_ID_MPEG1VIDEO: case AV_CODEC_ID_VC1: + case AV_CODEC_ID_VP8: case AV_CODEC_ID_VP9: st->need_parsing = AVSTREAM_PARSE_FULL; break; @@ -2262,8 +2453,7 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) MOVStreamContext *sc; int pseudo_stream_id; - if (c->fc->nb_streams < 1) - return 0; + av_assert0 (c->fc->nb_streams >= 1); st = c->fc->streams[c->fc->nb_streams-1]; sc = st->priv_data; @@ -2289,8 +2479,10 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) } if (mov_skip_multiple_stsd(c, pb, st->codecpar->codec_tag, format, - size - (avio_tell(pb) - start_pos))) + size - (avio_tell(pb) - start_pos))) { + sc->stsd_count++; continue; + } sc->pseudo_stream_id = st->codecpar->codec_tag ? -1 : pseudo_stream_id; sc->dref_id= dref_id; @@ -2342,10 +2534,13 @@ int ff_mov_read_stsd_entries(MOVContext *c, AVIOContext *pb, int entries) av_freep(&st->codecpar->extradata); st->codecpar->extradata_size = 0; } + sc->stsd_count++; } - if (pb->eof_reached) + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted STSD atom\n"); return AVERROR_EOF; + } return 0; } @@ -2378,17 +2573,18 @@ static int mov_read_stsd(MOVContext *c, AVIOContext *pb, MOVAtom atom) /* Prepare space for hosting multiple extradata. */ sc->extradata = av_mallocz_array(entries, sizeof(*sc->extradata)); + if (!sc->extradata) + return AVERROR(ENOMEM); + sc->extradata_size = av_mallocz_array(entries, sizeof(*sc->extradata_size)); - if (!sc->extradata_size || !sc->extradata) { + if (!sc->extradata_size) { ret = AVERROR(ENOMEM); goto fail; } ret = ff_mov_read_stsd_entries(c, pb, entries); if (ret < 0) - return ret; - - sc->stsd_count = entries; + goto fail; /* Restore back the primary extradata. */ av_freep(&st->codecpar->extradata); @@ -2402,6 +2598,12 @@ static int mov_read_stsd(MOVContext *c, AVIOContext *pb, MOVAtom atom) return mov_finalize_stsd_codec(c, pb, st, sc); fail: + if (sc->extradata) { + int j; + for (j = 0; j < sc->stsd_count; j++) + av_freep(&sc->extradata[j]); + } + av_freep(&sc->extradata); av_freep(&sc->extradata_size); return ret; @@ -2422,6 +2624,8 @@ static int mov_read_stsc(MOVContext *c, AVIOContext *pb, MOVAtom atom) avio_rb24(pb); /* flags */ entries = avio_rb32(pb); + if ((uint64_t)entries * 12 + 4 > atom.size) + return AVERROR_INVALIDDATA; av_log(c->fc, AV_LOG_TRACE, "track[%u].stsc.entries = %u\n", c->fc->nb_streams - 1, entries); @@ -2442,9 +2646,26 @@ static int mov_read_stsc(MOVContext *c, AVIOContext *pb, MOVAtom atom) } sc->stsc_count = i; + for (i = sc->stsc_count - 1; i < UINT_MAX; i--) { + if ((i+1 < sc->stsc_count && sc->stsc_data[i].first >= sc->stsc_data[i+1].first) || + (i > 0 && sc->stsc_data[i].first <= sc->stsc_data[i-1].first) || + sc->stsc_data[i].first < 1 || + sc->stsc_data[i].count < 1 || + sc->stsc_data[i].id < 1) { + av_log(c->fc, AV_LOG_WARNING, "STSC entry %d is invalid (first=%d count=%d id=%d)\n", i, sc->stsc_data[i].first, sc->stsc_data[i].count, sc->stsc_data[i].id); + if (i+1 >= sc->stsc_count || sc->stsc_data[i+1].first < 2) + return AVERROR_INVALIDDATA; + // We replace this entry by the next valid + sc->stsc_data[i].first = sc->stsc_data[i+1].first - 1; + sc->stsc_data[i].count = sc->stsc_data[i+1].count; + sc->stsc_data[i].id = sc->stsc_data[i+1].id; + } + } - if (pb->eof_reached) + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted STSC atom\n"); return AVERROR_EOF; + } return 0; } @@ -2455,7 +2676,7 @@ static inline int mov_stsc_index_valid(unsigned int index, unsigned int count) } /* Compute the samples value for the stsc entry at the given index. */ -static inline int mov_get_stsc_samples(MOVStreamContext *sc, unsigned int index) +static inline int64_t mov_get_stsc_samples(MOVStreamContext *sc, unsigned int index) { int chunk_count; @@ -2464,7 +2685,7 @@ static inline int mov_get_stsc_samples(MOVStreamContext *sc, unsigned int index) else chunk_count = sc->chunk_count - (sc->stsc_data[index].first - 1); - return sc->stsc_data[index].count * chunk_count; + return sc->stsc_data[index].count * (int64_t)chunk_count; } static int mov_read_stps(MOVContext *c, AVIOContext *pb, MOVAtom atom) @@ -2495,8 +2716,10 @@ static int mov_read_stps(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->stps_count = i; - if (pb->eof_reached) + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted STPS atom\n"); return AVERROR_EOF; + } return 0; } @@ -2542,8 +2765,10 @@ static int mov_read_stss(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->keyframe_count = i; - if (pb->eof_reached) + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted STSS atom\n"); return AVERROR_EOF; + } return 0; } @@ -2627,8 +2852,10 @@ static int mov_read_stsz(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_free(buf); - if (pb->eof_reached) + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted STSZ atom\n"); return AVERROR_EOF; + } return 0; } @@ -2637,7 +2864,7 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; MOVStreamContext *sc; - unsigned int i, entries; + unsigned int i, entries, alloc_size = 0; int64_t duration=0; int64_t total_sample_count=0; @@ -2655,15 +2882,24 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (sc->stts_data) av_log(c->fc, AV_LOG_WARNING, "Duplicated STTS atom\n"); - av_free(sc->stts_data); + av_freep(&sc->stts_data); sc->stts_count = 0; - sc->stts_data = av_malloc_array(entries, sizeof(*sc->stts_data)); - if (!sc->stts_data) + if (entries >= INT_MAX / sizeof(*sc->stts_data)) return AVERROR(ENOMEM); for (i = 0; i < entries && !pb->eof_reached; i++) { int sample_duration; unsigned int sample_count; + unsigned int min_entries = FFMIN(FFMAX(i + 1, 1024 * 1024), entries); + MOVStts *stts_data = av_fast_realloc(sc->stts_data, &alloc_size, + min_entries * sizeof(*sc->stts_data)); + if (!stts_data) { + av_freep(&sc->stts_data); + sc->stts_count = 0; + return AVERROR(ENOMEM); + } + sc->stts_count = min_entries; + sc->stts_data = stts_data; sample_count=avio_rb32(pb); sample_duration = avio_rb32(pb); @@ -2680,17 +2916,24 @@ static int mov_read_stts(MOVContext *c, AVIOContext *pb, MOVAtom atom) && total_sample_count > 100 && sample_duration/10 > duration / total_sample_count) sample_duration = duration / total_sample_count; - duration+=(int64_t)sample_duration*sample_count; + duration+=(int64_t)sample_duration*(uint64_t)sample_count; total_sample_count+=sample_count; } sc->stts_count = i; - sc->duration_for_fps += duration; - sc->nb_frames_for_fps += total_sample_count; + if (duration > 0 && + duration <= INT64_MAX - sc->duration_for_fps && + total_sample_count <= INT64_MAX - sc->nb_frames_for_fps + ) { + sc->duration_for_fps += duration; + sc->nb_frames_for_fps += total_sample_count; + } - if (pb->eof_reached) + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted STTS atom\n"); return AVERROR_EOF; + } st->nb_frames= total_sample_count; if (duration) @@ -2714,7 +2957,7 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; MOVStreamContext *sc; - unsigned int i, j, entries, ctts_count = 0; + unsigned int i, entries, ctts_count = 0; if (c->fc->nb_streams < 1) return 0; @@ -2747,9 +2990,8 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom) continue; } - /* Expand entries such that we have a 1-1 mapping with samples. */ - for (j = 0; j < count; j++) - add_ctts_entry(&sc->ctts_data, &ctts_count, &sc->ctts_allocated_size, 1, duration); + add_ctts_entry(&sc->ctts_data, &ctts_count, &sc->ctts_allocated_size, + count, duration); av_log(c->fc, AV_LOG_TRACE, "count=%d, duration=%d\n", count, duration); @@ -2767,8 +3009,10 @@ static int mov_read_ctts(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->ctts_count = ctts_count; - if (pb->eof_reached) + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted CTTS atom\n"); return AVERROR_EOF; + } av_log(c->fc, AV_LOG_TRACE, "dts shift %d\n", sc->dts_shift); @@ -2814,7 +3058,12 @@ static int mov_read_sbgp(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc->rap_group_count = i; - return pb->eof_reached ? AVERROR_EOF : 0; + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted SBGP atom\n"); + return AVERROR_EOF; + } + + return 0; } /** @@ -2844,34 +3093,99 @@ static int get_edit_list_entry(MOVContext *mov, } /** - * Find the closest previous frame to the timestamp, in e_old index + * Find the closest previous frame to the timestamp_pts, in e_old index * entries. Searching for just any frame / just key frames can be controlled by * last argument 'flag'. - * Returns the index of the entry in st->index_entries if successful, - * else returns -1. + * Note that if ctts_data is not NULL, we will always search for a key frame + * irrespective of the value of 'flag'. If we don't find any keyframe, we will + * return the first frame of the video. + * + * Here the timestamp_pts is considered to be a presentation timestamp and + * the timestamp of index entries are considered to be decoding timestamps. + * + * Returns 0 if successful in finding a frame, else returns -1. + * Places the found index corresponding output arg. + * + * If ctts_old is not NULL, then refines the searched entry by searching + * backwards from the found timestamp, to find the frame with correct PTS. + * + * Places the found ctts_index and ctts_sample in corresponding output args. */ -static int64_t find_prev_closest_index(AVStream *st, - AVIndexEntry *e_old, - int nb_old, - int64_t timestamp, - int flag) +static int find_prev_closest_index(AVStream *st, + AVIndexEntry *e_old, + int nb_old, + MOVStts* ctts_data, + int64_t ctts_count, + int64_t timestamp_pts, + int flag, + int64_t* index, + int64_t* ctts_index, + int64_t* ctts_sample) { + MOVStreamContext *msc = st->priv_data; AVIndexEntry *e_keep = st->index_entries; int nb_keep = st->nb_index_entries; - int64_t found = -1; int64_t i = 0; + int64_t index_ctts_count; + + av_assert0(index); + + // If dts_shift > 0, then all the index timestamps will have to be offset by + // at least dts_shift amount to obtain PTS. + // Hence we decrement the searched timestamp_pts by dts_shift to find the closest index element. + if (msc->dts_shift > 0) { + timestamp_pts -= msc->dts_shift; + } st->index_entries = e_old; st->nb_index_entries = nb_old; - found = av_index_search_timestamp(st, timestamp, flag | AVSEEK_FLAG_BACKWARD); + *index = av_index_search_timestamp(st, timestamp_pts, flag | AVSEEK_FLAG_BACKWARD); // Keep going backwards in the index entries until the timestamp is the same. - if (found >= 0) { - for (i = found; i > 0 && e_old[i].timestamp == e_old[i - 1].timestamp; + if (*index >= 0) { + for (i = *index; i > 0 && e_old[i].timestamp == e_old[i - 1].timestamp; i--) { if ((flag & AVSEEK_FLAG_ANY) || (e_old[i - 1].flags & AVINDEX_KEYFRAME)) { - found = i - 1; + *index = i - 1; + } + } + } + + // If we have CTTS then refine the search, by searching backwards over PTS + // computed by adding corresponding CTTS durations to index timestamps. + if (ctts_data && *index >= 0) { + av_assert0(ctts_index); + av_assert0(ctts_sample); + // Find out the ctts_index for the found frame. + *ctts_index = 0; + *ctts_sample = 0; + for (index_ctts_count = 0; index_ctts_count < *index; index_ctts_count++) { + if (*ctts_index < ctts_count) { + (*ctts_sample)++; + if (ctts_data[*ctts_index].count == *ctts_sample) { + (*ctts_index)++; + *ctts_sample = 0; + } + } + } + + while (*index >= 0 && (*ctts_index) >= 0 && (*ctts_index) < ctts_count) { + // Find a "key frame" with PTS <= timestamp_pts (So that we can decode B-frames correctly). + // No need to add dts_shift to the timestamp here becase timestamp_pts has already been + // compensated by dts_shift above. + if ((e_old[*index].timestamp + ctts_data[*ctts_index].duration) <= timestamp_pts && + (e_old[*index].flags & AVINDEX_KEYFRAME)) { + break; + } + + (*index)--; + if (*ctts_sample == 0) { + (*ctts_index)--; + if (*ctts_index >= 0) + *ctts_sample = ctts_data[*ctts_index].count - 1; + } else { + (*ctts_sample)--; } } } @@ -2879,7 +3193,7 @@ static int64_t find_prev_closest_index(AVStream *st, /* restore AVStream state*/ st->index_entries = e_keep; st->nb_index_entries = nb_keep; - return found; + return *index >= 0 ? 0 : -1; } /** @@ -2958,7 +3272,7 @@ static int64_t add_ctts_entry(MOVStts** ctts_data, unsigned int* ctts_count, uns FFMAX(min_size_needed, 2 * (*allocated_size)) : min_size_needed; - if((unsigned)(*ctts_count) + 1 >= UINT_MAX / sizeof(MOVStts)) + if((unsigned)(*ctts_count) >= UINT_MAX / sizeof(MOVStts) - 1) return -1; ctts_buf_new = av_fast_realloc(*ctts_data, allocated_size, requested_size); @@ -2975,6 +3289,60 @@ static int64_t add_ctts_entry(MOVStts** ctts_data, unsigned int* ctts_count, uns return *ctts_count; } +#define MAX_REORDER_DELAY 16 +static void mov_estimate_video_delay(MOVContext *c, AVStream* st) { + MOVStreamContext *msc = st->priv_data; + int ind; + int ctts_ind = 0; + int ctts_sample = 0; + int64_t pts_buf[MAX_REORDER_DELAY + 1]; // Circular buffer to sort pts. + int buf_start = 0; + int buf_size = 0; + int j, r, num_swaps; + + if (st->codecpar->video_delay <= 0 && msc->ctts_data && + st->codecpar->codec_id == AV_CODEC_ID_H264) { + st->codecpar->video_delay = 0; + for(ind = 0; ind < st->nb_index_entries && ctts_ind < msc->ctts_count; ++ind) { + if (buf_size == (MAX_REORDER_DELAY + 1)) { + // If circular buffer is full, then move the first element forward. + buf_start = (buf_start + 1) % buf_size; + } else { + ++buf_size; + } + + // Point j to the last elem of the buffer and insert the current pts there. + j = (buf_start + buf_size - 1) % buf_size; + pts_buf[j] = st->index_entries[ind].timestamp + msc->ctts_data[ctts_ind].duration; + + // The timestamps that are already in the sorted buffer, and are greater than the + // current pts, are exactly the timestamps that need to be buffered to output PTS + // in correct sorted order. + // Hence the video delay (which is the buffer size used to sort DTS and output PTS), + // can be computed as the maximum no. of swaps any particular timestamp needs to + // go through, to keep this buffer in sorted order. + num_swaps = 0; + while (j != buf_start) { + r = (j - 1 + buf_size) % buf_size; + if (pts_buf[j] < pts_buf[r]) { + FFSWAP(int64_t, pts_buf[j], pts_buf[r]); + ++num_swaps; + } + j = r; + } + st->codecpar->video_delay = FFMAX(st->codecpar->video_delay, num_swaps); + + ctts_sample++; + if (ctts_sample == msc->ctts_data[ctts_ind].count) { + ctts_ind++; + ctts_sample = 0; + } + } + av_log(c->fc, AV_LOG_DEBUG, "Setting codecpar->delay to %d for stream st: %d\n", + st->codecpar->video_delay, st->index); + } +} + static void mov_current_sample_inc(MOVStreamContext *sc) { sc->current_sample++; @@ -3046,14 +3414,11 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) int64_t edit_list_start_ctts_sample = 0; int64_t curr_cts; int64_t curr_ctts = 0; - int64_t min_corrected_pts = -1; int64_t empty_edits_sum_duration = 0; int64_t edit_list_index = 0; int64_t index; - int64_t index_ctts_count; int flags; int64_t start_dts = 0; - int64_t edit_list_media_time_dts = 0; int64_t edit_list_start_encountered = 0; int64_t search_timestamp = 0; int64_t* frame_duration_buffer = NULL; @@ -3062,6 +3427,7 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) int packet_skip_samples = 0; MOVIndexRange *current_index_range; int i; + int found_keyframe_after_edit = 0; if (!msc->elst_data || msc->elst_count <= 0 || nb_old <= 0) { return; @@ -3088,6 +3454,9 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) msc->ctts_sample = 0; msc->ctts_allocated_size = 0; + // Reinitialize min_corrected_pts so that it can be computed again. + msc->min_corrected_pts = -1; + // If the dts_shift is positive (in case of negative ctts values in mov), // then negate the DTS by dts_shift if (msc->dts_shift > 0) { @@ -3123,17 +3492,11 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) st->skip_samples = msc->start_pad = 0; } - //find closest previous key frame - edit_list_media_time_dts = edit_list_media_time; - if (msc->dts_shift > 0) { - edit_list_media_time_dts -= msc->dts_shift; - } - // While reordering frame index according to edit list we must handle properly // the scenario when edit list entry starts from none key frame. // We find closest previous key frame and preserve it and consequent frames in index. // All frames which are outside edit list entry time boundaries will be dropped after decoding. - search_timestamp = edit_list_media_time_dts; + search_timestamp = edit_list_media_time; if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { // Audio decoders like AAC need need a decoder delay samples previous to the current sample, // to correctly decode this frame. Hence for audio we seek to a frame 1 sec. before the @@ -3141,42 +3504,27 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) search_timestamp = FFMAX(search_timestamp - msc->time_scale, e_old[0].timestamp); } - index = find_prev_closest_index(st, e_old, nb_old, search_timestamp, 0); - if (index == -1) { + if (find_prev_closest_index(st, e_old, nb_old, ctts_data_old, ctts_count_old, search_timestamp, 0, + &index, &ctts_index_old, &ctts_sample_old) < 0) { av_log(mov->fc, AV_LOG_WARNING, "st: %d edit list: %"PRId64" Missing key frame while searching for timestamp: %"PRId64"\n", st->index, edit_list_index, search_timestamp); - index = find_prev_closest_index(st, e_old, nb_old, search_timestamp, AVSEEK_FLAG_ANY); - - if (index == -1) { + if (find_prev_closest_index(st, e_old, nb_old, ctts_data_old, ctts_count_old, search_timestamp, AVSEEK_FLAG_ANY, + &index, &ctts_index_old, &ctts_sample_old) < 0) { av_log(mov->fc, AV_LOG_WARNING, - "st: %d edit list %"PRId64" Cannot find an index entry before timestamp: %"PRId64".\n" - "Rounding edit list media time to zero.\n", + "st: %d edit list %"PRId64" Cannot find an index entry before timestamp: %"PRId64".\n", st->index, edit_list_index, search_timestamp); index = 0; - edit_list_media_time = 0; + ctts_index_old = 0; + ctts_sample_old = 0; } } current = e_old + index; - - ctts_index_old = 0; - ctts_sample_old = 0; - - // set ctts_index properly for the found key frame - for (index_ctts_count = 0; index_ctts_count < index; index_ctts_count++) { - if (ctts_data_old && ctts_index_old < ctts_count_old) { - ctts_sample_old++; - if (ctts_data_old[ctts_index_old].count == ctts_sample_old) { - ctts_index_old++; - ctts_sample_old = 0; - } - } - } - edit_list_start_ctts_sample = ctts_sample_old; // Iterate over index and arrange it according to edit list edit_list_start_encountered = 0; + found_keyframe_after_edit = 0; for (; current < e_old_end; current++, index++) { // check if frame outside edit list mark it for discard frame_duration = (current + 1 < e_old_end) ? @@ -3249,15 +3597,14 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) // Increment skip_samples for the first non-zero audio edit list if (first_non_zero_audio_edit > 0 && st->codecpar->codec_id != AV_CODEC_ID_VORBIS) { st->skip_samples += frame_duration; - msc->start_pad = st->skip_samples; } } } } else { - if (min_corrected_pts < 0) { - min_corrected_pts = edit_list_dts_counter + curr_ctts + msc->dts_shift; + if (msc->min_corrected_pts < 0) { + msc->min_corrected_pts = edit_list_dts_counter + curr_ctts + msc->dts_shift; } else { - min_corrected_pts = FFMIN(min_corrected_pts, edit_list_dts_counter + curr_ctts + msc->dts_shift); + msc->min_corrected_pts = FFMIN(msc->min_corrected_pts, edit_list_dts_counter + curr_ctts + msc->dts_shift); } if (edit_list_start_encountered == 0) { edit_list_start_encountered = 1; @@ -3290,43 +3637,53 @@ static void mov_fix_index(MOVContext *mov, AVStream *st) } // Break when found first key frame after edit entry completion - if (((curr_cts + frame_duration) >= (edit_list_duration + edit_list_media_time)) && + if ((curr_cts + frame_duration >= (edit_list_duration + edit_list_media_time)) && ((flags & AVINDEX_KEYFRAME) || ((st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)))) { - - if (ctts_data_old && ctts_sample_old != 0) { - if (add_ctts_entry(&msc->ctts_data, &msc->ctts_count, - &msc->ctts_allocated_size, - ctts_sample_old - edit_list_start_ctts_sample, - ctts_data_old[ctts_index_old].duration) == -1) { - av_log(mov->fc, AV_LOG_ERROR, "Cannot add CTTS entry %"PRId64" - {%"PRId64", %d}\n", - ctts_index_old, ctts_sample_old - edit_list_start_ctts_sample, - ctts_data_old[ctts_index_old].duration); - break; + if (ctts_data_old) { + // If we have CTTS and this is the first keyframe after edit elist, + // wait for one more, because there might be trailing B-frames after this I-frame + // that do belong to the edit. + if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO && found_keyframe_after_edit == 0) { + found_keyframe_after_edit = 1; + continue; + } + if (ctts_sample_old != 0) { + if (add_ctts_entry(&msc->ctts_data, &msc->ctts_count, + &msc->ctts_allocated_size, + ctts_sample_old - edit_list_start_ctts_sample, + ctts_data_old[ctts_index_old].duration) == -1) { + av_log(mov->fc, AV_LOG_ERROR, "Cannot add CTTS entry %"PRId64" - {%"PRId64", %d}\n", + ctts_index_old, ctts_sample_old - edit_list_start_ctts_sample, + ctts_data_old[ctts_index_old].duration); + break; + } } } break; } } } - // If there are empty edits, then min_corrected_pts might be positive intentionally. So we subtract the - // sum duration of emtpy edits here. - min_corrected_pts -= empty_edits_sum_duration; + // If there are empty edits, then msc->min_corrected_pts might be positive + // intentionally. So we subtract the sum duration of emtpy edits here. + msc->min_corrected_pts -= empty_edits_sum_duration; // If the minimum pts turns out to be greater than zero after fixing the index, then we subtract the // dts by that amount to make the first pts zero. - if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && min_corrected_pts > 0) { - av_log(mov->fc, AV_LOG_DEBUG, "Offset DTS by %"PRId64" to make first pts zero.\n", min_corrected_pts); + if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && msc->min_corrected_pts > 0) { + av_log(mov->fc, AV_LOG_DEBUG, "Offset DTS by %"PRId64" to make first pts zero.\n", msc->min_corrected_pts); for (i = 0; i < st->nb_index_entries; ++i) { - st->index_entries[i].timestamp -= min_corrected_pts; + st->index_entries[i].timestamp -= msc->min_corrected_pts; } } // Update av stream length st->duration = edit_list_dts_entry_end - start_dts; + msc->start_pad = st->skip_samples; // Free the old index and the old CTTS structures av_free(e_old); av_free(ctts_data_old); + av_freep(&frame_duration_buffer); // Null terminate the index ranges array current_index_range++; @@ -3346,6 +3703,8 @@ static void mov_build_index(MOVContext *mov, AVStream *st) unsigned int stps_index = 0; unsigned int i, j; uint64_t stream_size = 0; + MOVStts *ctts_data_old = sc->ctts_data; + unsigned int ctts_count_old = sc->ctts_count; if (sc->elst_count) { int i, edit_start_index = 0, multiple_edits = 0; @@ -3376,6 +3735,7 @@ static void mov_build_index(MOVContext *mov, AVStream *st) if (empty_duration) empty_duration = av_rescale(empty_duration, sc->time_scale, mov->time_scale); sc->time_offset = start_time - empty_duration; + sc->min_corrected_pts = start_time; if (!mov->advanced_editlist) current_dts = -sc->time_offset; } @@ -3414,6 +3774,31 @@ static void mov_build_index(MOVContext *mov, AVStream *st) } st->index_entries_allocated_size = (st->nb_index_entries + sc->sample_count) * sizeof(*st->index_entries); + if (ctts_data_old) { + // Expand ctts entries such that we have a 1-1 mapping with samples + if (sc->sample_count >= UINT_MAX / sizeof(*sc->ctts_data)) + return; + sc->ctts_count = 0; + sc->ctts_allocated_size = 0; + sc->ctts_data = av_fast_realloc(NULL, &sc->ctts_allocated_size, + sc->sample_count * sizeof(*sc->ctts_data)); + if (!sc->ctts_data) { + av_free(ctts_data_old); + return; + } + + memset((uint8_t*)(sc->ctts_data), 0, sc->ctts_allocated_size); + + for (i = 0; i < ctts_count_old && + sc->ctts_count < sc->sample_count; i++) + for (j = 0; j < ctts_data_old[i].count && + sc->ctts_count < sc->sample_count; j++) + add_ctts_entry(&sc->ctts_data, &sc->ctts_count, + &sc->ctts_allocated_size, 1, + ctts_data_old[i].duration); + av_free(ctts_data_old); + } + for (i = 0; i < sc->chunk_count; i++) { int64_t next_offset = i+1 < sc->chunk_count ? sc->chunk_offsets[i+1] : INT64_MAX; current_offset = sc->chunk_offsets[i]; @@ -3620,6 +4005,8 @@ static void mov_build_index(MOVContext *mov, AVStream *st) // Fix index according to edit lists. mov_fix_index(mov, st); } + + mov_estimate_video_delay(mov, st); } static int test_same_origin(const char *src, const char *ref) { @@ -3763,6 +4150,11 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom) st->index); return 0; } + if (sc->stsc_count && sc->stsc_data[ sc->stsc_count - 1 ].first > sc->chunk_count) { + av_log(c->fc, AV_LOG_ERROR, "stream %d, contradictionary STSC and STCO\n", + st->index); + return AVERROR_INVALIDDATA; + } fix_timescale(c, sc); @@ -3773,7 +4165,7 @@ static int mov_read_trak(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (sc->dref_id-1 < sc->drefs_count && sc->drefs[sc->dref_id-1].path) { MOVDref *dref = &sc->drefs[sc->dref_id - 1]; if (c->enable_drefs) { - if (mov_open_dref(c, &sc->pb, c->fc->filename, dref) < 0) + if (mov_open_dref(c, &sc->pb, c->fc->url, dref) < 0) av_log(c->fc, AV_LOG_ERROR, "stream %d, error opening alias: path='%s', dir='%s', " "filename='%s', volume='%s', nlvl_from=%d, nlvl_to=%d\n", @@ -3943,8 +4335,10 @@ static int mov_read_custom(MOVContext *c, AVIOContext *pb, MOVAtom atom) break; *p = av_malloc(len + 1); - if (!*p) + if (!*p) { + ret = AVERROR(ENOMEM); break; + } ret = ffio_read_size(pb, *p, len); if (ret < 0) { av_freep(p); @@ -4118,8 +4512,7 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) { MOVFragment *frag = &c->fragment; MOVTrackExt *trex = NULL; - MOVFragmentIndex* index = NULL; - int flags, track_id, i, found = 0; + int flags, track_id, i; avio_r8(pb); /* version */ flags = avio_rb24(pb); @@ -4128,6 +4521,7 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (!track_id) return AVERROR_INVALIDDATA; frag->track_id = track_id; + set_frag_stream(&c->frag_index, track_id); for (i = 0; i < c->trex_count; i++) if (c->trex_data[i].track_id == frag->track_id) { trex = &c->trex_data[i]; @@ -4149,35 +4543,8 @@ static int mov_read_tfhd(MOVContext *c, AVIOContext *pb, MOVAtom atom) avio_rb32(pb) : trex->size; frag->flags = flags & MOV_TFHD_DEFAULT_FLAGS ? avio_rb32(pb) : trex->flags; - frag->time = AV_NOPTS_VALUE; - for (i = 0; i < c->fragment_index_count; i++) { - int j; - MOVFragmentIndex* candidate = c->fragment_index_data[i]; - if (candidate->track_id == frag->track_id) { - av_log(c->fc, AV_LOG_DEBUG, - "found fragment index for track %u\n", frag->track_id); - index = candidate; - for (j = index->current_item; j < index->item_count; j++) { - if (frag->implicit_offset == index->items[j].moof_offset) { - av_log(c->fc, AV_LOG_DEBUG, "found fragment index entry " - "for track %u and moof_offset %"PRId64"\n", - frag->track_id, index->items[j].moof_offset); - frag->time = index->items[j].time; - index->current_item = j + 1; - found = 1; - break; - } - } - if (found) - break; - } - } - if (index && !found) { - av_log(c->fc, AV_LOG_DEBUG, "track %u has a fragment index but " - "it doesn't have an (in-order) entry for moof_offset " - "%"PRId64"\n", frag->track_id, frag->implicit_offset); - } av_log(c->fc, AV_LOG_TRACE, "frag flags 0x%x\n", frag->flags); + return 0; } @@ -4232,6 +4599,8 @@ static int mov_read_tfdt(MOVContext *c, AVIOContext *pb, MOVAtom atom) AVStream *st = NULL; MOVStreamContext *sc; int version, i; + MOVFragmentStreamInfo * frag_stream_info; + int64_t base_media_decode_time; for (i = 0; i < c->fc->nb_streams; i++) { if (c->fc->streams[i]->id == frag->track_id) { @@ -4244,15 +4613,21 @@ static int mov_read_tfdt(MOVContext *c, AVIOContext *pb, MOVAtom atom) return AVERROR_INVALIDDATA; } sc = st->priv_data; - if (sc->pseudo_stream_id + 1 != frag->stsd_id) + if (sc->pseudo_stream_id + 1 != frag->stsd_id && sc->pseudo_stream_id != -1) return 0; version = avio_r8(pb); avio_rb24(pb); /* flags */ if (version) { - sc->track_end = avio_rb64(pb); + base_media_decode_time = avio_rb64(pb); } else { - sc->track_end = avio_rb32(pb); + base_media_decode_time = avio_rb32(pb); } + + frag_stream_info = get_current_frag_stream_info(&c->frag_index); + if (frag_stream_info) + frag_stream_info->tfdt_dts = base_media_decode_time; + sc->track_end = base_media_decode_time; + return 0; } @@ -4263,10 +4638,16 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) MOVStreamContext *sc; MOVStts *ctts_data; uint64_t offset; - int64_t dts; + int64_t dts, pts = AV_NOPTS_VALUE; int data_offset = 0; unsigned entries, first_sample_flags = frag->flags; int flags, distance, i; + int64_t prev_dts = AV_NOPTS_VALUE; + int next_frag_index = -1, index_entry_pos; + size_t requested_size; + size_t old_ctts_allocated_size; + AVIndexEntry *new_entries; + MOVFragmentStreamInfo * frag_stream_info; for (i = 0; i < c->fc->nb_streams; i++) { if (c->fc->streams[i]->id == frag->track_id) { @@ -4281,6 +4662,23 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) sc = st->priv_data; if (sc->pseudo_stream_id+1 != frag->stsd_id && sc->pseudo_stream_id != -1) return 0; + + // Find the next frag_index index that has a valid index_entry for + // the current track_id. + // + // A valid index_entry means the trun for the fragment was read + // and it's samples are in index_entries at the given position. + // New index entries will be inserted before the index_entry found. + index_entry_pos = st->nb_index_entries; + for (i = c->frag_index.current + 1; i < c->frag_index.nb_items; i++) { + frag_stream_info = get_frag_stream_info(&c->frag_index, i, frag->track_id); + if (frag_stream_info && frag_stream_info->index_entry >= 0) { + next_frag_index = i; + index_entry_pos = frag_stream_info->index_entry; + break; + } + } + avio_r8(pb); /* version */ flags = avio_rb24(pb); entries = avio_rb32(pb); @@ -4290,18 +4688,100 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) return AVERROR_INVALIDDATA; if (flags & MOV_TRUN_DATA_OFFSET) data_offset = avio_rb32(pb); if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS) first_sample_flags = avio_rb32(pb); - dts = sc->track_end - sc->time_offset; - offset = frag->base_data_offset + data_offset; + + frag_stream_info = get_current_frag_stream_info(&c->frag_index); + if (frag_stream_info) + { + if (frag_stream_info->first_tfra_pts != AV_NOPTS_VALUE && + c->use_mfra_for == FF_MOV_FLAG_MFRA_PTS) { + pts = frag_stream_info->first_tfra_pts; + av_log(c->fc, AV_LOG_DEBUG, "found mfra time %"PRId64 + ", using it for pts\n", pts); + } else if (frag_stream_info->sidx_pts != AV_NOPTS_VALUE) { + // FIXME: sidx earliest_presentation_time is *PTS*, s.b. + // pts = frag_stream_info->sidx_pts; + dts = frag_stream_info->sidx_pts - sc->time_offset; + av_log(c->fc, AV_LOG_DEBUG, "found sidx time %"PRId64 + ", using it for pts\n", pts); + } else if (frag_stream_info->tfdt_dts != AV_NOPTS_VALUE) { + dts = frag_stream_info->tfdt_dts - sc->time_offset; + av_log(c->fc, AV_LOG_DEBUG, "found tfdt time %"PRId64 + ", using it for dts\n", dts); + } else { + dts = sc->track_end - sc->time_offset; + av_log(c->fc, AV_LOG_DEBUG, "found track end time %"PRId64 + ", using it for dts\n", dts); + } + } else { + dts = sc->track_end - sc->time_offset; + av_log(c->fc, AV_LOG_DEBUG, "found track end time %"PRId64 + ", using it for dts\n", dts); + } + offset = frag->base_data_offset + data_offset; distance = 0; av_log(c->fc, AV_LOG_TRACE, "first sample flags 0x%x\n", first_sample_flags); + + // realloc space for new index entries + if((unsigned)st->nb_index_entries + entries >= UINT_MAX / sizeof(AVIndexEntry)) { + entries = UINT_MAX / sizeof(AVIndexEntry) - st->nb_index_entries; + av_log(c->fc, AV_LOG_ERROR, "Failed to add index entry\n"); + } + if (entries <= 0) + return -1; + + requested_size = (st->nb_index_entries + entries) * sizeof(AVIndexEntry); + new_entries = av_fast_realloc(st->index_entries, + &st->index_entries_allocated_size, + requested_size); + if(!new_entries) + return AVERROR(ENOMEM); + st->index_entries= new_entries; + + requested_size = (st->nb_index_entries + entries) * sizeof(*sc->ctts_data); + old_ctts_allocated_size = sc->ctts_allocated_size; + ctts_data = av_fast_realloc(sc->ctts_data, &sc->ctts_allocated_size, + requested_size); + if (!ctts_data) + return AVERROR(ENOMEM); + sc->ctts_data = ctts_data; + + // In case there were samples without ctts entries, ensure they get + // zero valued entries. This ensures clips which mix boxes with and + // without ctts entries don't pickup uninitialized data. + memset((uint8_t*)(sc->ctts_data) + old_ctts_allocated_size, 0, + sc->ctts_allocated_size - old_ctts_allocated_size); + + if (index_entry_pos < st->nb_index_entries) { + // Make hole in index_entries and ctts_data for new samples + memmove(st->index_entries + index_entry_pos + entries, + st->index_entries + index_entry_pos, + sizeof(*st->index_entries) * + (st->nb_index_entries - index_entry_pos)); + memmove(sc->ctts_data + index_entry_pos + entries, + sc->ctts_data + index_entry_pos, + sizeof(*sc->ctts_data) * (sc->ctts_count - index_entry_pos)); + if (index_entry_pos < sc->current_sample) { + sc->current_sample += entries; + } + } + + st->nb_index_entries += entries; + sc->ctts_count = st->nb_index_entries; + + // Record the index_entry position in frag_index of this fragment + if (frag_stream_info) + frag_stream_info->index_entry = index_entry_pos; + + if (index_entry_pos > 0) + prev_dts = st->index_entries[index_entry_pos-1].timestamp; + for (i = 0; i < entries && !pb->eof_reached; i++) { unsigned sample_size = frag->size; int sample_flags = i ? frag->flags : first_sample_flags; unsigned sample_duration = frag->duration; unsigned ctts_duration = 0; int keyframe = 0; - int ctts_index = 0; - int old_nb_index_entries = st->nb_index_entries; + int index_entry_flags = 0; if (flags & MOV_TRUN_SAMPLE_DURATION) sample_duration = avio_rb32(pb); if (flags & MOV_TRUN_SAMPLE_SIZE) sample_size = avio_rb32(pb); @@ -4309,27 +4789,22 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (flags & MOV_TRUN_SAMPLE_CTS) ctts_duration = avio_rb32(pb); mov_update_dts_shift(sc, ctts_duration); - if (frag->time != AV_NOPTS_VALUE) { - if (c->use_mfra_for == FF_MOV_FLAG_MFRA_PTS) { - int64_t pts = frag->time; - av_log(c->fc, AV_LOG_DEBUG, "found frag time %"PRId64 - " sc->dts_shift %d ctts.duration %d" - " sc->time_offset %"PRId64" flags & MOV_TRUN_SAMPLE_CTS %d\n", pts, - sc->dts_shift, ctts_duration, - sc->time_offset, flags & MOV_TRUN_SAMPLE_CTS); - dts = pts - sc->dts_shift; - if (flags & MOV_TRUN_SAMPLE_CTS) { - dts -= ctts_duration; - } else { - dts -= sc->time_offset; - } - av_log(c->fc, AV_LOG_DEBUG, "calculated into dts %"PRId64"\n", dts); + if (pts != AV_NOPTS_VALUE) { + dts = pts - sc->dts_shift; + if (flags & MOV_TRUN_SAMPLE_CTS) { + dts -= ctts_duration; } else { - dts = frag->time - sc->time_offset; - av_log(c->fc, AV_LOG_DEBUG, "found frag time %"PRId64 - ", using it for dts\n", dts); + dts -= sc->time_offset; } - frag->time = AV_NOPTS_VALUE; + av_log(c->fc, AV_LOG_DEBUG, + "pts %"PRId64" calculated dts %"PRId64 + " sc->dts_shift %d ctts.duration %d" + " sc->time_offset %"PRId64 + " flags & MOV_TRUN_SAMPLE_CTS %d\n", + pts, dts, + sc->dts_shift, ctts_duration, + sc->time_offset, flags & MOV_TRUN_SAMPLE_CTS); + pts = AV_NOPTS_VALUE; } if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) @@ -4338,57 +4813,83 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) keyframe = !(sample_flags & (MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC | MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES)); - if (keyframe) + if (keyframe) { distance = 0; - ctts_index = av_add_index_entry(st, offset, dts, sample_size, distance, - keyframe ? AVINDEX_KEYFRAME : 0); - if (ctts_index >= 0 && old_nb_index_entries < st->nb_index_entries) { - unsigned int size_needed = st->nb_index_entries * sizeof(*sc->ctts_data); - unsigned int request_size = size_needed > sc->ctts_allocated_size ? - FFMAX(size_needed, 2 * sc->ctts_allocated_size) : size_needed; - unsigned int old_ctts_size = sc->ctts_allocated_size; - ctts_data = av_fast_realloc(sc->ctts_data, &sc->ctts_allocated_size, request_size); - if (!ctts_data) { - av_freep(&sc->ctts_data); - return AVERROR(ENOMEM); - } - sc->ctts_data = ctts_data; - - // In case there were samples without ctts entries, ensure they get - // zero valued entries. This ensures clips which mix boxes with and - // without ctts entries don't pickup uninitialized data. - memset((uint8_t*)(sc->ctts_data) + old_ctts_size, 0, sc->ctts_allocated_size - old_ctts_size); - - if (ctts_index != old_nb_index_entries) { - memmove(sc->ctts_data + ctts_index + 1, sc->ctts_data + ctts_index, - sizeof(*sc->ctts_data) * (sc->ctts_count - ctts_index)); - if (ctts_index <= sc->current_sample) { - // if we inserted a new item before the current sample, move the - // counter ahead so it is still pointing to the same sample. - sc->current_sample++; - } - } - - sc->ctts_data[ctts_index].count = 1; - sc->ctts_data[ctts_index].duration = ctts_duration; - sc->ctts_count++; - } else { - av_log(c->fc, AV_LOG_ERROR, "Failed to add index entry\n"); + index_entry_flags |= AVINDEX_KEYFRAME; } + // Fragments can overlap in time. Discard overlapping frames after + // decoding. + if (prev_dts >= dts) + index_entry_flags |= AVINDEX_DISCARD_FRAME; + + st->index_entries[index_entry_pos].pos = offset; + st->index_entries[index_entry_pos].timestamp = dts; + st->index_entries[index_entry_pos].size= sample_size; + st->index_entries[index_entry_pos].min_distance= distance; + st->index_entries[index_entry_pos].flags = index_entry_flags; + + sc->ctts_data[index_entry_pos].count = 1; + sc->ctts_data[index_entry_pos].duration = ctts_duration; + index_entry_pos++; av_log(c->fc, AV_LOG_TRACE, "AVIndex stream %d, sample %d, offset %"PRIx64", dts %"PRId64", " - "size %u, distance %d, keyframe %d\n", st->index, ctts_index, - offset, dts, sample_size, distance, keyframe); + "size %u, distance %d, keyframe %d\n", st->index, + index_entry_pos, offset, dts, sample_size, distance, keyframe); distance++; dts += sample_duration; offset += sample_size; sc->data_size += sample_size; - sc->duration_for_fps += sample_duration; - sc->nb_frames_for_fps ++; + + if (sample_duration <= INT64_MAX - sc->duration_for_fps && + 1 <= INT64_MAX - sc->nb_frames_for_fps + ) { + sc->duration_for_fps += sample_duration; + sc->nb_frames_for_fps ++; + } + } + if (i < entries) { + // EOF found before reading all entries. Fix the hole this would + // leave in index_entries and ctts_data + int gap = entries - i; + memmove(st->index_entries + index_entry_pos, + st->index_entries + index_entry_pos + gap, + sizeof(*st->index_entries) * + (st->nb_index_entries - (index_entry_pos + gap))); + memmove(sc->ctts_data + index_entry_pos, + sc->ctts_data + index_entry_pos + gap, + sizeof(*sc->ctts_data) * + (sc->ctts_count - (index_entry_pos + gap))); + + st->nb_index_entries -= gap; + sc->ctts_count -= gap; + if (index_entry_pos < sc->current_sample) { + sc->current_sample -= gap; + } + entries = i; + } + + // The end of this new fragment may overlap in time with the start + // of the next fragment in index_entries. Mark the samples in the next + // fragment that overlap with AVINDEX_DISCARD_FRAME + prev_dts = AV_NOPTS_VALUE; + if (index_entry_pos > 0) + prev_dts = st->index_entries[index_entry_pos-1].timestamp; + for (i = index_entry_pos; i < st->nb_index_entries; i++) { + if (prev_dts < st->index_entries[i].timestamp) + break; + st->index_entries[i].flags |= AVINDEX_DISCARD_FRAME; } - if (pb->eof_reached) + // If a hole was created to insert the new index_entries into, + // the index_entry recorded for all subsequent moof must + // be incremented by the number of entries inserted. + fix_frag_index_entries(&c->frag_index, next_frag_index, + frag->track_id, entries); + + if (pb->eof_reached) { + av_log(c->fc, AV_LOG_WARNING, "reached eof, corrupted TRUN atom\n"); return AVERROR_EOF; + } frag->implicit_offset = offset; @@ -4401,14 +4902,12 @@ static int mov_read_trun(MOVContext *c, AVIOContext *pb, MOVAtom atom) static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom) { - int64_t offset = avio_tell(pb) + atom.size, pts; + int64_t offset = avio_tell(pb) + atom.size, pts, timestamp; uint8_t version; - unsigned i, track_id; + unsigned i, j, track_id, item_count; AVStream *st = NULL; AVStream *ref_st = NULL; MOVStreamContext *sc, *ref_sc = NULL; - MOVFragmentIndex *index = NULL; - MOVFragmentIndex **tmp; AVRational timescale; version = avio_r8(pb); @@ -4450,57 +4949,46 @@ static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom) avio_rb16(pb); // reserved - index = av_mallocz(sizeof(MOVFragmentIndex)); - if (!index) - return AVERROR(ENOMEM); - - index->track_id = track_id; - - index->item_count = avio_rb16(pb); - index->items = av_mallocz_array(index->item_count, sizeof(MOVFragmentIndexItem)); - - if (!index->items) { - av_freep(&index); - return AVERROR(ENOMEM); - } + item_count = avio_rb16(pb); - for (i = 0; i < index->item_count; i++) { + for (i = 0; i < item_count; i++) { + int index; + MOVFragmentStreamInfo * frag_stream_info; uint32_t size = avio_rb32(pb); uint32_t duration = avio_rb32(pb); if (size & 0x80000000) { avpriv_request_sample(c->fc, "sidx reference_type 1"); - av_freep(&index->items); - av_freep(&index); return AVERROR_PATCHWELCOME; } avio_rb32(pb); // sap_flags - index->items[i].moof_offset = offset; - index->items[i].time = av_rescale_q(pts, st->time_base, timescale); + timestamp = av_rescale_q(pts, st->time_base, timescale); + + index = update_frag_index(c, offset); + frag_stream_info = get_frag_stream_info(&c->frag_index, index, track_id); + if (frag_stream_info) + frag_stream_info->sidx_pts = timestamp; + offset += size; pts += duration; } st->duration = sc->track_end = pts; - tmp = av_realloc_array(c->fragment_index_data, - c->fragment_index_count + 1, - sizeof(MOVFragmentIndex*)); - if (!tmp) { - av_freep(&index->items); - av_freep(&index); - return AVERROR(ENOMEM); - } - - c->fragment_index_data = tmp; - c->fragment_index_data[c->fragment_index_count++] = index; sc->has_sidx = 1; if (offset == avio_size(pb)) { - for (i = 0; i < c->fc->nb_streams; i++) { - if (c->fc->streams[i]->id == c->fragment_index_data[0]->track_id) { - ref_st = c->fc->streams[i]; - ref_sc = ref_st->priv_data; - break; + // Find first entry in fragment index that came from an sidx. + // This will pretty much always be the first entry. + for (i = 0; i < c->frag_index.nb_items; i++) { + MOVFragmentIndexItem * item = &c->frag_index.item[i]; + for (j = 0; ref_st == NULL && j < item->nb_stream_info; j++) { + MOVFragmentStreamInfo * si; + si = &item->stream_info[j]; + if (si->sidx_pts != AV_NOPTS_VALUE) { + ref_st = c->fc->streams[j]; + ref_sc = ref_st->priv_data; + break; + } } } for (i = 0; i < c->fc->nb_streams; i++) { @@ -4511,7 +4999,7 @@ static int mov_read_sidx(MOVContext *c, AVIOContext *pb, MOVAtom atom) } } - c->fragment_index_complete = 1; + c->frag_index.complete = 1; } return 0; @@ -4574,6 +5062,7 @@ static int mov_read_cmov(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (ret < 0) goto free_and_return; + ret = AVERROR_INVALIDDATA; if (uncompress (moov_data, (uLongf *) &moov_len, (const Bytef *)cmov_data, cmov_len) != Z_OK) goto free_and_return; if (ffio_init_context(&ctx, moov_data, moov_len, 0, NULL, NULL, NULL, NULL) != 0) @@ -4597,6 +5086,7 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom) { MOVStreamContext *sc; int i, edit_count, version; + int64_t elst_entry_size; if (c->fc->nb_streams < 1 || c->ignore_editlist) return 0; @@ -4605,6 +5095,21 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom) version = avio_r8(pb); /* version */ avio_rb24(pb); /* flags */ edit_count = avio_rb32(pb); /* entries */ + atom.size -= 8; + + elst_entry_size = version == 1 ? 20 : 12; + if (atom.size != edit_count * elst_entry_size) { + if (c->fc->strict_std_compliance >= FF_COMPLIANCE_STRICT) { + av_log(c->fc, AV_LOG_ERROR, "Invalid edit list entry_count: %d for elst atom of size: %"PRId64" bytes.\n", + edit_count, atom.size + 8); + return AVERROR_INVALIDDATA; + } else { + edit_count = atom.size / elst_entry_size; + if (edit_count * elst_entry_size != atom.size) { + av_log(c->fc, AV_LOG_WARNING, "ELST atom of %"PRId64" bytes, bigger than %d entries.", atom.size, edit_count); + } + } + } if (!edit_count) return 0; @@ -4617,17 +5122,20 @@ static int mov_read_elst(MOVContext *c, AVIOContext *pb, MOVAtom atom) return AVERROR(ENOMEM); av_log(c->fc, AV_LOG_TRACE, "track[%u].edit_count = %i\n", c->fc->nb_streams - 1, edit_count); - for (i = 0; i < edit_count && !pb->eof_reached; i++) { + for (i = 0; i < edit_count && atom.size > 0 && !pb->eof_reached; i++) { MOVElst *e = &sc->elst_data[i]; if (version == 1) { e->duration = avio_rb64(pb); e->time = avio_rb64(pb); + atom.size -= 16; } else { e->duration = avio_rb32(pb); /* segment duration */ e->time = (int32_t)avio_rb32(pb); /* media time */ + atom.size -= 8; } e->rate = avio_rb32(pb) / 65536.0; + atom.size -= 4; av_log(c->fc, AV_LOG_TRACE, "duration=%"PRId64" time=%"PRId64" rate=%f\n", e->duration, e->time, e->rate); @@ -4744,6 +5252,45 @@ static int mov_read_smdm(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } +static int mov_read_mdcv(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + MOVStreamContext *sc; + const int mapping[3] = {1, 2, 0}; + const int chroma_den = 50000; + const int luma_den = 10000; + int i; + + if (c->fc->nb_streams < 1) + return AVERROR_INVALIDDATA; + + sc = c->fc->streams[c->fc->nb_streams - 1]->priv_data; + + if (atom.size < 24) { + av_log(c->fc, AV_LOG_ERROR, "Invalid Mastering Display Color Volume box\n"); + return AVERROR_INVALIDDATA; + } + + sc->mastering = av_mastering_display_metadata_alloc(); + if (!sc->mastering) + return AVERROR(ENOMEM); + + for (i = 0; i < 3; i++) { + const int j = mapping[i]; + sc->mastering->display_primaries[j][0] = av_make_q(avio_rb16(pb), chroma_den); + sc->mastering->display_primaries[j][1] = av_make_q(avio_rb16(pb), chroma_den); + } + sc->mastering->white_point[0] = av_make_q(avio_rb16(pb), chroma_den); + sc->mastering->white_point[1] = av_make_q(avio_rb16(pb), chroma_den); + + sc->mastering->max_luminance = av_make_q(avio_rb32(pb), luma_den); + sc->mastering->min_luminance = av_make_q(avio_rb32(pb), luma_den); + + sc->mastering->has_luminance = 1; + sc->mastering->has_primaries = 1; + + return 0; +} + static int mov_read_coll(MOVContext *c, AVIOContext *pb, MOVAtom atom) { MOVStreamContext *sc; @@ -4776,6 +5323,30 @@ static int mov_read_coll(MOVContext *c, AVIOContext *pb, MOVAtom atom) return 0; } +static int mov_read_clli(MOVContext *c, AVIOContext *pb, MOVAtom atom) +{ + MOVStreamContext *sc; + + if (c->fc->nb_streams < 1) + return AVERROR_INVALIDDATA; + + sc = c->fc->streams[c->fc->nb_streams - 1]->priv_data; + + if (atom.size < 4) { + av_log(c->fc, AV_LOG_ERROR, "Empty Content Light Level Info box\n"); + return AVERROR_INVALIDDATA; + } + + sc->coll = av_content_light_metadata_alloc(&sc->coll_size); + if (!sc->coll) + return AVERROR(ENOMEM); + + sc->coll->MaxCLL = avio_rb16(pb); + sc->coll->MaxFALL = avio_rb16(pb); + + return 0; +} + static int mov_read_st3d(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; @@ -4823,7 +5394,7 @@ static int mov_read_sv3d(MOVContext *c, AVIOContext *pb, MOVAtom atom) { AVStream *st; MOVStreamContext *sc; - int size, layout; + int size, version, layout; int32_t yaw, pitch, roll; uint32_t l = 0, t = 0, r = 0, b = 0; uint32_t tag, padding = 0; @@ -4849,7 +5420,13 @@ static int mov_read_sv3d(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_log(c->fc, AV_LOG_ERROR, "Missing spherical video header\n"); return 0; } - avio_skip(pb, 4); /* version + flags */ + version = avio_r8(pb); + if (version != 0) { + av_log(c->fc, AV_LOG_WARNING, "Unknown spherical version %d\n", + version); + return 0; + } + avio_skip(pb, 3); /* flags */ avio_skip(pb, size - 12); /* metadata_source */ size = avio_rb32(pb); @@ -4871,7 +5448,13 @@ static int mov_read_sv3d(MOVContext *c, AVIOContext *pb, MOVAtom atom) av_log(c->fc, AV_LOG_ERROR, "Missing projection header box\n"); return 0; } - avio_skip(pb, 4); /* version + flags */ + version = avio_r8(pb); + if (version != 0) { + av_log(c->fc, AV_LOG_WARNING, "Unknown spherical version %d\n", + version); + return 0; + } + avio_skip(pb, 3); /* flags */ /* 16.16 fixed point */ yaw = avio_rb32(pb); @@ -4883,7 +5466,13 @@ static int mov_read_sv3d(MOVContext *c, AVIOContext *pb, MOVAtom atom) return AVERROR_INVALIDDATA; tag = avio_rl32(pb); - avio_skip(pb, 4); /* version + flags */ + version = avio_r8(pb); + if (version != 0) { + av_log(c->fc, AV_LOG_WARNING, "Unknown spherical version %d\n", + version); + return 0; + } + avio_skip(pb, 3); /* flags */ switch (tag) { case MKTAG('c','b','m','p'): layout = avio_rb32(pb); @@ -4914,7 +5503,7 @@ static int mov_read_sv3d(MOVContext *c, AVIOContext *pb, MOVAtom atom) projection = AV_SPHERICAL_EQUIRECTANGULAR; break; default: - av_log(c->fc, AV_LOG_ERROR, "Unknown projection type\n"); + av_log(c->fc, AV_LOG_ERROR, "Unknown projection type: %s\n", av_fourcc2str(tag)); return 0; } @@ -4953,7 +5542,8 @@ static int mov_parse_uuid_spherical(MOVStreamContext *sc, AVIOContext *pb, size_ goto out; /* Check for mandatory keys and values, try to support XML as best-effort */ - if (av_stristr(buffer, "") && + if (!sc->spherical && + av_stristr(buffer, "") && (val = av_stristr(buffer, "")) && av_stristr(val, "true") && (val = av_stristr(buffer, "")) && @@ -4966,7 +5556,7 @@ static int mov_parse_uuid_spherical(MOVStreamContext *sc, AVIOContext *pb, size_ sc->spherical->projection = AV_SPHERICAL_EQUIRECTANGULAR; - if (av_stristr(buffer, "")) { + if (av_stristr(buffer, "") && !sc->stereo3d) { enum AVStereo3DType mode; if (av_stristr(buffer, "left-right")) @@ -5108,7 +5698,8 @@ static int mov_read_uuid(MOVContext *c, AVIOContext *pb, MOVAtom atom) if (ret < 0) return ret; if (!sc->spherical) - av_log(c->fc, AV_LOG_WARNING, "Invalid spherical metadata found\n"); } + av_log(c->fc, AV_LOG_WARNING, "Invalid spherical metadata found\n"); + } return 0; } @@ -5565,6 +6156,8 @@ static const MOVParseTableEntry mov_default_parse_table[] = { { MKTAG('S','m','D','m'), mov_read_smdm }, { MKTAG('C','o','L','L'), mov_read_coll }, { MKTAG('v','p','c','C'), mov_read_vpcc }, +{ MKTAG('m','d','c','v'), mov_read_mdcv }, +{ MKTAG('c','l','l','i'), mov_read_clli }, { 0, NULL } }; @@ -5661,9 +6254,9 @@ static int mov_read_default(MOVContext *c, AVIOContext *pb, MOVAtom atom) return err; } if (c->found_moov && c->found_mdat && - ((!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX || c->fragment_index_complete) || + ((!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX || c->frag_index.complete) || start_pos + a.size == avio_size(pb))) { - if (!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX || c->fragment_index_complete) + if (!(pb->seekable & AVIO_SEEKABLE_NORMAL) || c->fc->flags & AVFMT_FLAG_IGNIDX || c->frag_index.complete) c->next_root_atom = start_pos + a.size; c->atom_depth --; return 0; @@ -6008,12 +6601,10 @@ static int mov_read_close(AVFormatContext *s) av_freep(&mov->trex_data); av_freep(&mov->bitrates); - for (i = 0; i < mov->fragment_index_count; i++) { - MOVFragmentIndex* index = mov->fragment_index_data[i]; - av_freep(&index->items); - av_freep(&mov->fragment_index_data[i]); + for (i = 0; i < mov->frag_index.nb_items; i++) { + av_freep(&mov->frag_index.item[i].stream_info); } - av_freep(&mov->fragment_index_data); + av_freep(&mov->frag_index.item); av_freep(&mov->aes_decrypt); av_freep(&mov->chapter_tracks); @@ -6057,48 +6648,27 @@ static void export_orphan_timecode(AVFormatContext *s) static int read_tfra(MOVContext *mov, AVIOContext *f) { - MOVFragmentIndex* index = NULL; int version, fieldlength, i, j; int64_t pos = avio_tell(f); uint32_t size = avio_rb32(f); - void *tmp; + unsigned track_id, item_count; if (avio_rb32(f) != MKBETAG('t', 'f', 'r', 'a')) { return 1; } av_log(mov->fc, AV_LOG_VERBOSE, "found tfra\n"); - index = av_mallocz(sizeof(MOVFragmentIndex)); - if (!index) { - return AVERROR(ENOMEM); - } - - tmp = av_realloc_array(mov->fragment_index_data, - mov->fragment_index_count + 1, - sizeof(MOVFragmentIndex*)); - if (!tmp) { - av_freep(&index); - return AVERROR(ENOMEM); - } - mov->fragment_index_data = tmp; - mov->fragment_index_data[mov->fragment_index_count++] = index; version = avio_r8(f); avio_rb24(f); - index->track_id = avio_rb32(f); + track_id = avio_rb32(f); fieldlength = avio_rb32(f); - index->item_count = avio_rb32(f); - index->items = av_mallocz_array( - index->item_count, sizeof(MOVFragmentIndexItem)); - if (!index->items) { - index->item_count = 0; - return AVERROR(ENOMEM); - } - for (i = 0; i < index->item_count; i++) { + item_count = avio_rb32(f); + for (i = 0; i < item_count; i++) { int64_t time, offset; + int index; + MOVFragmentStreamInfo * frag_stream_info; if (avio_feof(f)) { - index->item_count = 0; - av_freep(&index->items); return AVERROR_INVALIDDATA; } @@ -6109,8 +6679,16 @@ static int read_tfra(MOVContext *mov, AVIOContext *f) time = avio_rb32(f); offset = avio_rb32(f); } - index->items[i].time = time; - index->items[i].moof_offset = offset; + + // The first sample of each stream in a fragment is always a random + // access sample. So it's entry in the tfra can be used as the + // initial PTS of the fragment. + index = update_frag_index(mov, offset); + frag_stream_info = get_frag_stream_info(&mov->frag_index, index, track_id); + if (frag_stream_info && + frag_stream_info->first_tfra_pts == AV_NOPTS_VALUE) + frag_stream_info->first_tfra_pts = time; + for (j = 0; j < ((fieldlength >> 4) & 3) + 1; j++) avio_r8(f); for (j = 0; j < ((fieldlength >> 2) & 3) + 1; j++) @@ -6192,13 +6770,13 @@ static int mov_read_header(AVFormatContext *s) /* check MOV header */ do { - if (mov->moov_retry) - avio_seek(pb, 0, SEEK_SET); - if ((err = mov_read_default(mov, pb, atom)) < 0) { - av_log(s, AV_LOG_ERROR, "error reading header\n"); - mov_read_close(s); - return err; - } + if (mov->moov_retry) + avio_seek(pb, 0, SEEK_SET); + if ((err = mov_read_default(mov, pb, atom)) < 0) { + av_log(s, AV_LOG_ERROR, "error reading header\n"); + mov_read_close(s); + return err; + } } while ((pb->seekable & AVIO_SEEKABLE_NORMAL) && !mov->found_moov && !mov->moov_retry++); if (!mov->found_moov) { av_log(s, AV_LOG_ERROR, "moov atom not found\n"); @@ -6371,12 +6949,9 @@ static int mov_read_header(AVFormatContext *s) } ff_configure_buffers_for_index(s, AV_TIME_BASE); - for (i = 0; i < mov->fragment_index_count; i++) { - MOVFragmentIndex *idx = mov->fragment_index_data[i]; - for (j = 0; j < idx->item_count; j++) - if (idx->items[j].moof_offset <= mov->fragment.moof_offset) - idx->items[j].headers_read = 1; - } + for (i = 0; i < mov->frag_index.nb_items; i++) + if (mov->frag_index.item[i].moof_offset <= mov->fragment.moof_offset) + mov->frag_index.item[i].headers_read = 1; return 0; } @@ -6384,8 +6959,13 @@ static int mov_read_header(AVFormatContext *s) static AVIndexEntry *mov_find_next_sample(AVFormatContext *s, AVStream **st) { AVIndexEntry *sample = NULL; + AVIndexEntry *best_dts_sample = NULL; + AVIndexEntry *best_pos_sample = NULL; + AVStream *best_dts_stream = NULL; + AVStream *best_pos_stream = NULL; int64_t best_dts = INT64_MAX; int i; + int64_t pos = avio_tell(s->pb); for (i = 0; i < s->nb_streams; i++) { AVStream *avst = s->streams[i]; MOVStreamContext *msc = avst->priv_data; @@ -6393,17 +6973,36 @@ static AVIndexEntry *mov_find_next_sample(AVFormatContext *s, AVStream **st) AVIndexEntry *current_sample = &avst->index_entries[msc->current_sample]; int64_t dts = av_rescale(current_sample->timestamp, AV_TIME_BASE, msc->time_scale); av_log(s, AV_LOG_TRACE, "stream %d, sample %d, dts %"PRId64"\n", i, msc->current_sample, dts); - if (!sample || (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) && current_sample->pos < sample->pos) || + if (!best_dts_sample || (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) && current_sample->pos < best_dts_sample->pos) || ((s->pb->seekable & AVIO_SEEKABLE_NORMAL) && ((msc->pb != s->pb && dts < best_dts) || (msc->pb == s->pb && - ((FFABS(best_dts - dts) <= AV_TIME_BASE && current_sample->pos < sample->pos) || + ((FFABS(best_dts - dts) <= AV_TIME_BASE && current_sample->pos < best_dts_sample->pos) || (FFABS(best_dts - dts) > AV_TIME_BASE && dts < best_dts)))))) { - sample = current_sample; + /* find best dts sample */ + best_dts_sample = current_sample; best_dts = dts; - *st = avst; + best_dts_stream = avst; + } + if (current_sample->pos >= pos && + (!best_pos_sample || current_sample->pos < best_pos_sample->pos)) { + /* find nearest sample to avoid seek around */ + best_pos_sample = current_sample; + best_pos_stream = avst; } } } + + if (best_dts_sample && best_dts_sample != best_pos_sample && + (!best_pos_sample || + best_dts_sample->pos < pos || + best_dts_sample->pos > pos + 1024 * 1024)) { + sample = best_dts_sample; + *st = best_dts_stream; + } else { + sample = best_pos_sample; + *st = best_pos_stream; + } + return sample; } @@ -6414,46 +7013,35 @@ static int should_retry(AVIOContext *pb, int error_code) { return 1; } -static int mov_switch_root(AVFormatContext *s, int64_t target) +static int mov_switch_root(AVFormatContext *s, int64_t target, int index) { + int ret; MOVContext *mov = s->priv_data; - int i, j; - int already_read = 0; + if (index >= 0 && index < mov->frag_index.nb_items) + target = mov->frag_index.item[index].moof_offset; if (avio_seek(s->pb, target, SEEK_SET) != target) { av_log(mov->fc, AV_LOG_ERROR, "root atom offset 0x%"PRIx64": partial file\n", target); return AVERROR_INVALIDDATA; } mov->next_root_atom = 0; - - for (i = 0; i < mov->fragment_index_count; i++) { - MOVFragmentIndex *index = mov->fragment_index_data[i]; - int found = 0; - for (j = 0; j < index->item_count; j++) { - MOVFragmentIndexItem *item = &index->items[j]; - if (found) { - mov->next_root_atom = item->moof_offset; - break; // Advance to next index in outer loop - } else if (item->moof_offset == target) { - index->current_item = FFMIN(j, index->current_item); - if (item->headers_read) - already_read = 1; - item->headers_read = 1; - found = 1; - } - } - if (!found) - index->current_item = 0; + if (index < 0 || index >= mov->frag_index.nb_items) + index = search_frag_moof_offset(&mov->frag_index, target); + if (index < mov->frag_index.nb_items) { + if (index + 1 < mov->frag_index.nb_items) + mov->next_root_atom = mov->frag_index.item[index + 1].moof_offset; + if (mov->frag_index.item[index].headers_read) + return 0; + mov->frag_index.item[index].headers_read = 1; } - if (already_read) - return 0; - mov->found_mdat = 0; - if (mov_read_default(mov, s->pb, (MOVAtom){ AV_RL32("root"), INT64_MAX }) < 0 || - avio_feof(s->pb)) + ret = mov_read_default(mov, s->pb, (MOVAtom){ AV_RL32("root"), INT64_MAX }); + if (ret < 0) + return ret; + if (avio_feof(s->pb)) return AVERROR_EOF; av_log(s, AV_LOG_TRACE, "read fragments, offset 0x%"PRIx64"\n", avio_tell(s->pb)); @@ -6497,7 +7085,7 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) if (!sample || (mov->next_root_atom && sample->pos > mov->next_root_atom)) { if (!mov->next_root_atom) return AVERROR_EOF; - if ((ret = mov_switch_root(s, mov->next_root_atom)) < 0) + if ((ret = mov_switch_root(s, mov->next_root_atom, -1)) < 0) return ret; goto retry; } @@ -6604,6 +7192,12 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) return ret; } } + if (mov->allow_multi_extradata && mov->has_extradata) { + mov->has_extradata = 0; + ret = mov_change_extradata(sc, pkt); + if (ret < 0) + return ret; + } if (mov->aax_mode) aax_filter(pkt->data, pkt->size, mov); @@ -6621,25 +7215,18 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt) static int mov_seek_fragment(AVFormatContext *s, AVStream *st, int64_t timestamp) { MOVContext *mov = s->priv_data; - MOVStreamContext *sc = st->priv_data; - int i, j; + int index; - if (!mov->fragment_index_complete) + if (!mov->frag_index.complete) return 0; - for (i = 0; i < mov->fragment_index_count; i++) { - if (mov->fragment_index_data[i]->track_id == st->id || !sc->has_sidx) { - MOVFragmentIndex *index = mov->fragment_index_data[i]; - for (j = index->item_count - 1; j >= 0; j--) { - if (index->items[j].time <= timestamp) { - if (index->items[j].headers_read) - return 0; - - return mov_switch_root(s, index->items[j].moof_offset); - } - } - } - } + index = search_frag_timestamp(&mov->frag_index, st, timestamp); + if (index < 0) + index = 0; + if (!mov->frag_index.item[index].headers_read) + return mov_switch_root(s, -1, index); + if (index + 1 < mov->frag_index.nb_items) + mov->next_root_atom = mov->frag_index.item[index + 1].moof_offset; return 0; } @@ -6647,10 +7234,14 @@ static int mov_seek_fragment(AVFormatContext *s, AVStream *st, int64_t timestamp static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp, int flags) { MOVStreamContext *sc = st->priv_data; - int sample, time_sample; + int sample, time_sample, ret; unsigned int i; - int ret = mov_seek_fragment(s, st, timestamp); + // Here we consider timestamp to be PTS, hence try to offset it so that we + // can search over the DTS timeline. + timestamp -= (sc->min_corrected_pts + sc->dts_shift); + + ret = mov_seek_fragment(s, st, timestamp); if (ret < 0) return ret; @@ -6679,12 +7270,13 @@ static int mov_seek_stream(AVFormatContext *s, AVStream *st, int64_t timestamp, /* adjust stsd index */ time_sample = 0; for (i = 0; i < sc->stsc_count; i++) { - int next = time_sample + mov_get_stsc_samples(sc, i); + int64_t next = time_sample + mov_get_stsc_samples(sc, i); if (next > sc->current_sample) { sc->stsc_index = i; sc->stsc_sample = sc->current_sample - time_sample; break; } + av_assert0(next == (int)next); time_sample = next; } @@ -6787,6 +7379,8 @@ static const AVOption mov_options[] = { { "enable_drefs", "Enable external track support.", OFFSET(enable_drefs), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS }, + {"allow_multi_extradata", "", OFFSET(allow_multi_extradata), AV_OPT_TYPE_BOOL, {.i64 = 0}, + 0, 1, FLAGS}, { NULL }, }; diff --git a/libavutil/tests/atomic.c b/libavformat/mov_esds.c similarity index 56% rename from libavutil/tests/atomic.c rename to libavformat/mov_esds.c index e41bf5a2b94cd..a444d969c65e4 100644 --- a/libavutil/tests/atomic.c +++ b/libavformat/mov_esds.c @@ -16,23 +16,29 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "libavutil/atomic.h" -#include "libavutil/avassert.h" +#include "avformat.h" +#include "avio.h" +#include "isom.h" -int main(void) +int ff_mov_read_esds(AVFormatContext *fc, AVIOContext *pb) { - volatile int val = 1; - void *tmp1 = (int *)&val; - void * volatile *tmp2 = &tmp1; - int res; + AVStream *st; + int tag, ret = 0; - res = avpriv_atomic_int_add_and_fetch(&val, 1); - av_assert0(res == 2); - avpriv_atomic_int_set(&val, 3); - res = avpriv_atomic_int_get(&val); - av_assert0(res == 3); - avpriv_atomic_ptr_cas(tmp2, tmp1, &res); - av_assert0(*tmp2 == &res); + if (fc->nb_streams < 1) + return 0; + st = fc->streams[fc->nb_streams-1]; - return 0; + avio_rb32(pb); /* version + flags */ + ff_mp4_read_descr(fc, pb, &tag); + if (tag == MP4ESDescrTag) { + ff_mp4_parse_es_descr(pb, NULL); + } else + avio_rb16(pb); /* ID */ + + ff_mp4_read_descr(fc, pb, &tag); + if (tag == MP4DecConfigDescrTag) + ret = ff_mp4_read_dec_config_descr(fc, st, pb); + + return ret; } diff --git a/libavformat/movenc.c b/libavformat/movenc.c index 2838286141842..0b44fd66ea1f3 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -31,7 +31,7 @@ #include "avio.h" #include "isom.h" #include "avc.h" -#include "libavcodec/ac3_parser.h" +#include "libavcodec/ac3_parser_internal.h" #include "libavcodec/dnxhddata.h" #include "libavcodec/flac.h" #include "libavcodec/get_bits.h" @@ -62,6 +62,7 @@ static const AVOption options[] = { { "moov_size", "maximum moov size so it can be placed at the begin", offsetof(MOVMuxContext, reserved_moov_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, 0 }, { "empty_moov", "Make the initial moov atom empty", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_EMPTY_MOOV}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, { "frag_keyframe", "Fragment at video keyframes", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_KEYFRAME}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, + { "frag_every_frame", "Fragment at every frame", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_EVERY_FRAME}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, { "separate_moof", "Write separate moof/mdat atoms for each track", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SEPARATE_MOOF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, { "frag_custom", "Flush fragments on caller requests", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_CUSTOM}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, { "isml", "Create a live smooth streaming feed (for pushing to a publishing point)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_ISML}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, "movflags" }, @@ -139,6 +140,15 @@ static int co64_required(const MOVTrack *track) return 0; } +static int rtp_hinting_needed(const AVStream *st) +{ + /* Add hint tracks for each real audio and video stream */ + if (st->disposition & AV_DISPOSITION_ATTACHED_PIC) + return 0; + return st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO || + st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO; +} + /* Chunk offset atom */ static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track) { @@ -252,6 +262,30 @@ static int mov_write_stss_tag(AVIOContext *pb, MOVTrack *track, uint32_t flag) return update_size(pb, pos); } +/* Sample dependency atom */ +static int mov_write_sdtp_tag(AVIOContext *pb, MOVTrack *track) +{ + int i; + uint8_t leading, dependent, reference, redundancy; + int64_t pos = avio_tell(pb); + avio_wb32(pb, 0); // size + ffio_wfourcc(pb, "sdtp"); + avio_wb32(pb, 0); // version & flags + for (i = 0; i < track->entry; i++) { + dependent = MOV_SAMPLE_DEPENDENCY_YES; + leading = reference = redundancy = MOV_SAMPLE_DEPENDENCY_UNKNOWN; + if (track->cluster[i].flags & MOV_DISPOSABLE_SAMPLE) { + reference = MOV_SAMPLE_DEPENDENCY_NO; + } + if (track->cluster[i].flags & MOV_SYNC_SAMPLE) { + dependent = MOV_SAMPLE_DEPENDENCY_NO; + } + avio_w8(pb, (leading << 6) | (dependent << 4) | + (reference << 2) | redundancy); + } + return update_size(pb, pos); +} + static int mov_write_amr_tag(AVIOContext *pb, MOVTrack *track) { avio_wb32(pb, 0x11); /* size */ @@ -345,23 +379,22 @@ struct eac3_info { #if CONFIG_AC3_PARSER static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track) { - GetBitContext gbc; - AC3HeaderInfo tmp, *hdr = &tmp; + AC3HeaderInfo *hdr = NULL; struct eac3_info *info; - int num_blocks; + int num_blocks, ret; if (!track->eac3_priv && !(track->eac3_priv = av_mallocz(sizeof(*info)))) return AVERROR(ENOMEM); info = track->eac3_priv; - init_get_bits(&gbc, pkt->data, pkt->size * 8); - if (avpriv_ac3_parse_header(&gbc, &hdr) < 0) { + if (avpriv_ac3_parse_header(&hdr, pkt->data, pkt->size) < 0) { /* drop the packets until we see a good one */ if (!track->entry) { av_log(mov, AV_LOG_WARNING, "Dropping invalid packet from start of the stream\n"); - return 0; - } - return AVERROR_INVALIDDATA; + ret = 0; + } else + ret = AVERROR_INVALIDDATA; + goto end; } info->data_rate = FFMAX(info->data_rate, hdr->bit_rate / 1000); @@ -369,20 +402,25 @@ static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track) if (!info->ec3_done) { /* AC-3 substream must be the first one */ - if (hdr->bitstream_id <= 10 && hdr->substreamid != 0) - return AVERROR(EINVAL); + if (hdr->bitstream_id <= 10 && hdr->substreamid != 0) { + ret = AVERROR(EINVAL); + goto end; + } /* this should always be the case, given that our AC-3 parser * concatenates dependent frames to their independent parent */ if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT) { /* substream ids must be incremental */ - if (hdr->substreamid > info->num_ind_sub + 1) - return AVERROR(EINVAL); + if (hdr->substreamid > info->num_ind_sub + 1) { + ret = AVERROR(EINVAL); + goto end; + } if (hdr->substreamid == info->num_ind_sub + 1) { //info->num_ind_sub++; avpriv_request_sample(track->par, "Multiple independent substreams"); - return AVERROR_PATCHWELCOME; + ret = AVERROR_PATCHWELCOME; + goto end; } else if (hdr->substreamid < info->num_ind_sub || hdr->substreamid == 0 && info->substream[0].bsid) { info->ec3_done = 1; @@ -403,16 +441,20 @@ static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track) int parent = hdr->substreamid; while (cumul_size != pkt->size) { + GetBitContext gbc; int i; - init_get_bits(&gbc, pkt->data + cumul_size, (pkt->size - cumul_size) * 8); - if (avpriv_ac3_parse_header(&gbc, &hdr) < 0) - return AVERROR_INVALIDDATA; - if (hdr->frame_type != EAC3_FRAME_TYPE_DEPENDENT) - return AVERROR(EINVAL); - cumul_size += hdr->frame_size; + ret = avpriv_ac3_parse_header(&hdr, pkt->data + cumul_size, pkt->size - cumul_size); + if (ret < 0) + goto end; + if (hdr->frame_type != EAC3_FRAME_TYPE_DEPENDENT) { + ret = AVERROR(EINVAL); + goto end; + } info->substream[parent].num_dep_sub++; + ret /= 8; /* header is parsed up to lfeon, but custom channel map may be needed */ + init_get_bits8(&gbc, pkt->data + cumul_size + ret, pkt->size - cumul_size - ret); /* skip bsid */ skip_bits(&gbc, 5); /* skip volume control params */ @@ -427,42 +469,46 @@ static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track) info->substream[parent].chan_loc |= (get_bits(&gbc, 16) >> 5) & 0x1f; else info->substream[parent].chan_loc |= hdr->channel_mode; + cumul_size += hdr->frame_size; } } } concatenate: - if (!info->num_blocks && num_blocks == 6) - return pkt->size; - else if (info->num_blocks + num_blocks > 6) - return AVERROR_INVALIDDATA; + if (!info->num_blocks && num_blocks == 6) { + ret = pkt->size; + goto end; + } + else if (info->num_blocks + num_blocks > 6) { + ret = AVERROR_INVALIDDATA; + goto end; + } if (!info->num_blocks) { - int ret = av_packet_ref(&info->pkt, pkt); - if (ret < 0) - return ret; - info->num_blocks = num_blocks; - return 0; + ret = av_packet_ref(&info->pkt, pkt); + if (!ret) + info->num_blocks = num_blocks; + goto end; } else { - int ret; if ((ret = av_grow_packet(&info->pkt, pkt->size)) < 0) - return ret; + goto end; memcpy(info->pkt.data + info->pkt.size - pkt->size, pkt->data, pkt->size); info->num_blocks += num_blocks; info->pkt.duration += pkt->duration; if ((ret = av_copy_packet_side_data(&info->pkt, pkt)) < 0) - return ret; + goto end; if (info->num_blocks != 6) - return 0; + goto end; av_packet_unref(pkt); - ret = av_packet_ref(pkt, &info->pkt); - if (ret < 0) - return ret; - av_packet_unref(&info->pkt); + av_packet_move_ref(pkt, &info->pkt); info->num_blocks = 0; } + ret = pkt->size; + +end: + av_free(hdr); - return pkt->size; + return ret; } #endif @@ -1517,9 +1563,9 @@ static int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track) else if (track->mode == MODE_ISM) tag = track->par->codec_tag; else if (track->mode == MODE_IPOD) { - if (!av_match_ext(s->filename, "m4a") && - !av_match_ext(s->filename, "m4v") && - !av_match_ext(s->filename, "m4b")) + if (!av_match_ext(s->url, "m4a") && + !av_match_ext(s->url, "m4v") && + !av_match_ext(s->url, "m4b")) av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v " "Quicktime/Ipod might not play the file\n"); tag = track->par->codec_tag; @@ -1671,6 +1717,21 @@ static int mov_write_sv3d_tag(AVFormatContext *s, AVIOContext *pb, AVSphericalMa return update_size(pb, sv3d_pos); } +static int mov_write_clap_tag(AVIOContext *pb, MOVTrack *track) +{ + avio_wb32(pb, 40); + ffio_wfourcc(pb, "clap"); + avio_wb32(pb, track->par->width); /* apertureWidth_N */ + avio_wb32(pb, 1); /* apertureWidth_D (= 1) */ + avio_wb32(pb, track->height); /* apertureHeight_N */ + avio_wb32(pb, 1); /* apertureHeight_D (= 1) */ + avio_wb32(pb, 0); /* horizOff_N (= 0) */ + avio_wb32(pb, 1); /* horizOff_D (= 1) */ + avio_wb32(pb, 0); /* vertOff_N (= 0) */ + avio_wb32(pb, 1); /* vertOff_D (= 1) */ + return 40; +} + static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track) { AVRational sar; @@ -1755,23 +1816,30 @@ static int mov_write_colr_tag(AVIOContext *pb, MOVTrack *track) ffio_wfourcc(pb, "nclc"); switch (track->par->color_primaries) { case AVCOL_PRI_BT709: avio_wb16(pb, 1); break; + case AVCOL_PRI_BT470BG: avio_wb16(pb, 5); break; case AVCOL_PRI_SMPTE170M: case AVCOL_PRI_SMPTE240M: avio_wb16(pb, 6); break; - case AVCOL_PRI_BT470BG: avio_wb16(pb, 5); break; + case AVCOL_PRI_BT2020: avio_wb16(pb, 9); break; + case AVCOL_PRI_SMPTE431: avio_wb16(pb, 11); break; + case AVCOL_PRI_SMPTE432: avio_wb16(pb, 12); break; default: avio_wb16(pb, 2); } switch (track->par->color_trc) { - case AVCOL_TRC_BT709: avio_wb16(pb, 1); break; - case AVCOL_TRC_SMPTE170M: avio_wb16(pb, 1); break; // remapped - case AVCOL_TRC_SMPTE240M: avio_wb16(pb, 7); break; - default: avio_wb16(pb, 2); + case AVCOL_TRC_BT709: avio_wb16(pb, 1); break; + case AVCOL_TRC_SMPTE170M: avio_wb16(pb, 1); break; // remapped + case AVCOL_TRC_SMPTE240M: avio_wb16(pb, 7); break; + case AVCOL_TRC_SMPTEST2084: avio_wb16(pb, 16); break; + case AVCOL_TRC_SMPTE428: avio_wb16(pb, 17); break; + case AVCOL_TRC_ARIB_STD_B67: avio_wb16(pb, 18); break; + default: avio_wb16(pb, 2); } switch (track->par->color_space) { - case AVCOL_SPC_BT709: avio_wb16(pb, 1); break; + case AVCOL_SPC_BT709: avio_wb16(pb, 1); break; case AVCOL_SPC_BT470BG: - case AVCOL_SPC_SMPTE170M: avio_wb16(pb, 6); break; - case AVCOL_SPC_SMPTE240M: avio_wb16(pb, 7); break; - default: avio_wb16(pb, 2); + case AVCOL_SPC_SMPTE170M: avio_wb16(pb, 6); break; + case AVCOL_SPC_SMPTE240M: avio_wb16(pb, 7); break; + case AVCOL_SPC_BT2020_NCL: avio_wb16(pb, 9); break; + default: avio_wb16(pb, 2); } if (track->mode == MODE_MP4) { @@ -1817,6 +1885,13 @@ static int mov_write_video_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *tr char compressor_name[32] = { 0 }; int avid = 0; + int uncompressed_ycbcr = ((track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_UYVY422) + || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_YUYV422) + || track->par->codec_id == AV_CODEC_ID_V308 + || track->par->codec_id == AV_CODEC_ID_V408 + || track->par->codec_id == AV_CODEC_ID_V410 + || track->par->codec_id == AV_CODEC_ID_V210); + avio_wb32(pb, 0); /* size */ if (mov->encryption_scheme != MOV_ENC_NONE) { ffio_wfourcc(pb, "encv"); @@ -1827,11 +1902,15 @@ static int mov_write_video_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *tr avio_wb16(pb, 0); /* Reserved */ avio_wb16(pb, 1); /* Data-reference index */ - avio_wb16(pb, 0); /* Codec stream version */ + if (uncompressed_ycbcr) { + avio_wb16(pb, 2); /* Codec stream version */ + } else { + avio_wb16(pb, 0); /* Codec stream version */ + } avio_wb16(pb, 0); /* Codec stream revision (=0) */ if (track->mode == MODE_MOV) { ffio_wfourcc(pb, "FFMP"); /* Vendor */ - if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO) { + if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO || uncompressed_ycbcr) { avio_wb32(pb, 0); /* Temporal Quality */ avio_wb32(pb, 0x400); /* Spatial Quality = lossless*/ } else { @@ -1855,7 +1934,10 @@ static int mov_write_video_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *tr avio_w8(pb, strlen(compressor_name)); avio_write(pb, compressor_name, 31); - if (track->mode == MODE_MOV && track->par->bits_per_coded_sample) + if (track->mode == MODE_MOV && + (track->par->codec_id == AV_CODEC_ID_V410 || track->par->codec_id == AV_CODEC_ID_V210)) + avio_wb16(pb, 0x18); + else if (track->mode == MODE_MOV && track->par->bits_per_coded_sample) avio_wb16(pb, track->par->bits_per_coded_sample | (track->par->format == AV_PIX_FMT_GRAY8 ? 0x20 : 0)); else @@ -1955,6 +2037,10 @@ static int mov_write_video_tag(AVIOContext *pb, MOVMuxContext *mov, MOVTrack *tr mov_write_pasp_tag(pb, track); } + if (uncompressed_ycbcr){ + mov_write_clap_tag(pb, track); + } + if (mov->encryption_scheme != MOV_ENC_NONE) { ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid); } @@ -2305,6 +2391,8 @@ static int mov_write_stbl_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext track->par->codec_tag == MKTAG('r','t','p',' ')) && track->has_keyframes && track->has_keyframes < track->entry) mov_write_stss_tag(pb, track, MOV_SYNC_SAMPLE); + if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && track->has_disposable) + mov_write_sdtp_tag(pb, track); if (track->mode == MODE_MOV && track->flags & MOV_TRACK_STPS) mov_write_stss_tag(pb, track, MOV_PARTIAL_SYNC_SAMPLE); if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && @@ -2945,7 +3033,7 @@ static int mov_write_track_udta_tag(AVIOContext *pb, MOVMuxContext *mov, if (ret < 0) return ret; - if (mov->mode & MODE_MP4) + if (mov->mode & (MODE_MP4|MODE_MOV)) mov_write_track_metadata(pb_buf, st, "name", "title"); if ((size = avio_close_dyn_buf(pb_buf, &buf)) > 0) { @@ -3334,6 +3422,51 @@ static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb, return size; } +static int mov_write_covr(AVIOContext *pb, AVFormatContext *s) +{ + MOVMuxContext *mov = s->priv_data; + int64_t pos = 0; + int i, type; + + for (i = 0; i < s->nb_streams; i++) { + MOVTrack *trk = &mov->tracks[i]; + AVStream *st = s->streams[i]; + + if (!(st->disposition & AV_DISPOSITION_ATTACHED_PIC) || + trk->cover_image.size <= 0) + continue; + + switch (st->codecpar->codec_id) { + case AV_CODEC_ID_MJPEG: + type = 0xD; + break; + case AV_CODEC_ID_PNG: + type = 0xE; + break; + case AV_CODEC_ID_BMP: + type = 0x1B; + break; + default: + av_log(s, AV_LOG_ERROR, "unsupported codec_id (0x%x) for cover", + st->codecpar->codec_id); + continue; + } + + if (!pos) { + pos = avio_tell(pb); + avio_wb32(pb, 0); + ffio_wfourcc(pb, "covr"); + } + avio_wb32(pb, 16 + trk->cover_image.size); + ffio_wfourcc(pb, "data"); + avio_wb32(pb, type); + avio_wb32(pb , 0); + avio_write(pb, trk->cover_image.data, trk->cover_image.size); + } + + return pos ? update_size(pb, pos) : 0; +} + /* iTunes meta data list */ static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s) @@ -3353,7 +3486,7 @@ static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov, } mov_write_string_metadata(s, pb, "\251cmt", "comment" , 1); mov_write_string_metadata(s, pb, "\251gen", "genre" , 1); - mov_write_string_metadata(s, pb, "\251cpy", "copyright", 1); + mov_write_string_metadata(s, pb, "cprt", "copyright", 1); mov_write_string_metadata(s, pb, "\251grp", "grouping" , 1); mov_write_string_metadata(s, pb, "\251lyr", "lyrics" , 1); mov_write_string_metadata(s, pb, "desc", "description",1); @@ -3368,6 +3501,7 @@ static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov, mov_write_int8_metadata (s, pb, "hdvd", "hd_video", 1); mov_write_int8_metadata (s, pb, "pgap", "gapless_playback",1); mov_write_int8_metadata (s, pb, "cpil", "compilation", 1); + mov_write_covr(pb, s); mov_write_trkn_tag(pb, mov, s, 0); // track number mov_write_trkn_tag(pb, mov, s, 1); // disc number mov_write_tmpo_tag(pb, s); @@ -3865,6 +3999,8 @@ static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov, AVFormat } else { continue; } + if (st->disposition & AV_DISPOSITION_ATTACHED_PIC) + continue; props = (AVCPBProperties*)av_stream_get_side_data(track->st, AV_PKT_DATA_CPB_PROPERTIES, NULL); @@ -4478,6 +4614,8 @@ static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s) for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; + if (st->disposition & AV_DISPOSITION_ATTACHED_PIC) + continue; if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) has_video = 1; if (st->codecpar->codec_id == AV_CODEC_ID_H264) @@ -4626,6 +4764,8 @@ static int mov_write_identification(AVIOContext *pb, AVFormatContext *s) int video_streams_nb = 0, audio_streams_nb = 0, other_streams_nb = 0; for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; + if (st->disposition & AV_DISPOSITION_ATTACHED_PIC) + continue; if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) video_streams_nb++; else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) @@ -4815,7 +4955,8 @@ static int mov_flush_fragment(AVFormatContext *s, int force) int buf_size, moov_size; for (i = 0; i < mov->nb_streams; i++) - if (!mov->tracks[i].entry) + if (!mov->tracks[i].entry && + (i >= s->nb_streams || !(s->streams[i]->disposition & AV_DISPOSITION_ATTACHED_PIC))) break; /* Don't write the initial moov unless all tracks have data */ if (i < mov->nb_streams && !force) @@ -5268,6 +5409,10 @@ int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt) if (trk->cluster[trk->entry].flags & MOV_SYNC_SAMPLE) trk->has_keyframes++; } + if (pkt->flags & AV_PKT_FLAG_DISPOSABLE) { + trk->cluster[trk->entry].flags |= MOV_DISPOSABLE_SAMPLE; + trk->has_disposable++; + } trk->entry++; trk->sample_count += samples_in_chunk; mov->mdat_size += size; @@ -5347,7 +5492,8 @@ static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt) (mov->max_fragment_size && mov->mdat_size + size >= mov->max_fragment_size) || (mov->flags & FF_MOV_FLAG_FRAG_KEYFRAME && par->codec_type == AVMEDIA_TYPE_VIDEO && - trk->entry && pkt->flags & AV_PKT_FLAG_KEY)) { + trk->entry && pkt->flags & AV_PKT_FLAG_KEY) || + (mov->flags & FF_MOV_FLAG_FRAG_EVERY_FRAME)) { if (frag_duration >= mov->min_fragment_duration) { // Set the duration of this track to line up with the next // sample in this track. This avoids relying on AVPacket @@ -5389,13 +5535,34 @@ static int mov_write_subtitle_end_packet(AVFormatContext *s, static int mov_write_packet(AVFormatContext *s, AVPacket *pkt) { + MOVMuxContext *mov = s->priv_data; + MOVTrack *trk; + AVStream *st; + if (!pkt) { mov_flush_fragment(s, 1); return 1; + } + + st = s->streams[pkt->stream_index]; + trk = &mov->tracks[pkt->stream_index]; + + if (st->disposition & AV_DISPOSITION_ATTACHED_PIC) { + int ret; + + if (st->nb_frames >= 1) { + if (st->nb_frames == 1) + av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d," + " ignoring.\n", pkt->stream_index); + return 0; + } + + if ((ret = av_packet_ref(&trk->cover_image, pkt)) < 0) + return ret; + + return 0; } else { int i; - MOVMuxContext *mov = s->priv_data; - MOVTrack *trk = &mov->tracks[pkt->stream_index]; if (!pkt->size) return mov_write_single_packet(s, pkt); /* Passthrough. */ @@ -5642,7 +5809,8 @@ static void enable_tracks(AVFormatContext *s) AVStream *st = s->streams[i]; if (st->codecpar->codec_type <= AVMEDIA_TYPE_UNKNOWN || - st->codecpar->codec_type >= AVMEDIA_TYPE_NB) + st->codecpar->codec_type >= AVMEDIA_TYPE_NB || + st->disposition & AV_DISPOSITION_ATTACHED_PIC) continue; if (first[st->codecpar->codec_type] < 0) @@ -5685,6 +5853,7 @@ static void mov_free(AVFormatContext *s) av_freep(&mov->tracks[i].par); av_freep(&mov->tracks[i].cluster); av_freep(&mov->tracks[i].frag_info); + av_packet_unref(&mov->tracks[i].cover_image); if (mov->tracks[i].vos_len) av_freep(&mov->tracks[i].vos_data); @@ -5789,7 +5958,8 @@ static int mov_init(AVFormatContext *s) if (mov->max_fragment_duration || mov->max_fragment_size || mov->flags & (FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_FRAG_KEYFRAME | - FF_MOV_FLAG_FRAG_CUSTOM)) + FF_MOV_FLAG_FRAG_CUSTOM | + FF_MOV_FLAG_FRAG_EVERY_FRAME)) mov->flags |= FF_MOV_FLAG_FRAGMENT; /* Set other implicit flags immediately */ @@ -5856,14 +6026,9 @@ static int mov_init(AVFormatContext *s) mov->chapter_track = mov->nb_streams++; if (mov->flags & FF_MOV_FLAG_RTP_HINT) { - /* Add hint tracks for each audio and video stream */ - for (i = 0; i < s->nb_streams; i++) { - AVStream *st = s->streams[i]; - if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO || - st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { + for (i = 0; i < s->nb_streams; i++) + if (rtp_hinting_needed(s->streams[i])) mov->nb_streams++; - } - } } if ( mov->write_tmcd == -1 && (mov->mode == MODE_MOV || mov->mode == MODE_MP4) @@ -5994,6 +6159,15 @@ static int mov_init(AVFormatContext *s) av_log(s, AV_LOG_ERROR, "VP9 only supported in MP4.\n"); return AVERROR(EINVAL); } + } else if (track->par->codec_id == AV_CODEC_ID_AV1) { + /* spec is not finished, so forbid for now */ + av_log(s, AV_LOG_ERROR, "AV1 muxing is currently not supported.\n"); + return AVERROR_PATCHWELCOME; + } else if (track->par->codec_id == AV_CODEC_ID_VP8) { + /* altref frames handling is not defined in the spec as of version v1.0, + * so just forbid muxing VP8 streams altogether until a new version does */ + av_log(s, AV_LOG_ERROR, "VP8 muxing is currently not supported.\n"); + return AVERROR_PATCHWELCOME; } } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { track->timescale = st->codecpar->sample_rate; @@ -6081,15 +6255,10 @@ static int mov_write_header(AVFormatContext *s) nb_tracks++; if (mov->flags & FF_MOV_FLAG_RTP_HINT) { - /* Add hint tracks for each audio and video stream */ hint_track = nb_tracks; - for (i = 0; i < s->nb_streams; i++) { - AVStream *st = s->streams[i]; - if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO || - st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { + for (i = 0; i < s->nb_streams; i++) + if (rtp_hinting_needed(s->streams[i])) nb_tracks++; - } - } } if (mov->mode == MODE_MOV || mov->mode == MODE_MP4) @@ -6148,7 +6317,8 @@ static int mov_write_header(AVFormatContext *s) if (mov->flags & FF_MOV_FLAG_FRAGMENT) { /* If no fragmentation options have been set, set a default. */ if (!(mov->flags & (FF_MOV_FLAG_FRAG_KEYFRAME | - FF_MOV_FLAG_FRAG_CUSTOM)) && + FF_MOV_FLAG_FRAG_CUSTOM | + FF_MOV_FLAG_FRAG_EVERY_FRAME)) && !mov->max_fragment_duration && !mov->max_fragment_size) mov->flags |= FF_MOV_FLAG_FRAG_KEYFRAME; } else { @@ -6166,11 +6336,8 @@ static int mov_write_header(AVFormatContext *s) return ret; if (mov->flags & FF_MOV_FLAG_RTP_HINT) { - /* Initialize the hint tracks for each audio and video stream */ for (i = 0; i < s->nb_streams; i++) { - AVStream *st = s->streams[i]; - if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO || - st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { + if (rtp_hinting_needed(s->streams[i])) { if ((ret = ff_mov_init_hinting(s, hint_track, i)) < 0) return ret; hint_track++; @@ -6315,10 +6482,10 @@ static int shift_data(AVFormatContext *s) * writing, so we re-open the same output, but for reading. It also avoids * a read/seek/write/seek back and forth. */ avio_flush(s->pb); - ret = s->io_open(s, &read_pb, s->filename, AVIO_FLAG_READ, NULL); + ret = s->io_open(s, &read_pb, s->url, AVIO_FLAG_READ, NULL); if (ret < 0) { av_log(s, AV_LOG_ERROR, "Unable to re-open %s output file for " - "the second pass (faststart)\n", s->filename); + "the second pass (faststart)\n", s->url); goto end; } @@ -6498,6 +6665,7 @@ static const AVCodecTag codec_3gp_tags[] = { const AVCodecTag codec_mp4_tags[] = { { AV_CODEC_ID_MPEG4 , MKTAG('m', 'p', '4', 'v') }, { AV_CODEC_ID_H264 , MKTAG('a', 'v', 'c', '1') }, + { AV_CODEC_ID_H264 , MKTAG('a', 'v', 'c', '3') }, { AV_CODEC_ID_HEVC , MKTAG('h', 'e', 'v', '1') }, { AV_CODEC_ID_HEVC , MKTAG('h', 'v', 'c', '1') }, { AV_CODEC_ID_MPEG2VIDEO , MKTAG('m', 'p', '4', 'v') }, @@ -6663,7 +6831,7 @@ AVOutputFormat ff_ipod_muxer = { .name = "ipod", .long_name = NULL_IF_CONFIG_SMALL("iPod H.264 MP4 (MPEG-4 Part 14)"), .mime_type = "video/mp4", - .extensions = "m4v,m4a", + .extensions = "m4v,m4a,m4b", .priv_data_size = sizeof(MOVMuxContext), .audio_codec = AV_CODEC_ID_AAC, .video_codec = AV_CODEC_ID_H264, diff --git a/libavformat/movenc.h b/libavformat/movenc.h index cc2a155d79aa4..c9b4072fb9d11 100644 --- a/libavformat/movenc.h +++ b/libavformat/movenc.h @@ -53,6 +53,7 @@ typedef struct MOVIentry { int cts; #define MOV_SYNC_SAMPLE 0x0001 #define MOV_PARTIAL_SYNC_SAMPLE 0x0002 +#define MOV_DISPOSABLE_SAMPLE 0x0004 uint32_t flags; } MOVIentry; @@ -89,6 +90,7 @@ typedef struct MOVTrack { long sample_size; long chunkCount; int has_keyframes; + int has_disposable; #define MOV_TRACK_CTTS 0x0001 #define MOV_TRACK_STPS 0x0002 #define MOV_TRACK_ENABLED 0x0004 @@ -130,6 +132,7 @@ typedef struct MOVTrack { uint32_t default_size; HintSampleQueue sample_queue; + AVPacket cover_image; AVIOContext *mdat_buf; int64_t data_offset; @@ -243,6 +246,7 @@ typedef struct MOVMuxContext { #define FF_MOV_FLAG_USE_MDTA (1 << 17) #define FF_MOV_FLAG_SKIP_TRAILER (1 << 18) #define FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS (1 << 19) +#define FF_MOV_FLAG_FRAG_EVERY_FRAME (1 << 20) int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt); diff --git a/libavformat/mp3dec.c b/libavformat/mp3dec.c index a5c4f2ea12720..a76fe32e5998a 100644 --- a/libavformat/mp3dec.c +++ b/libavformat/mp3dec.c @@ -508,9 +508,9 @@ static int64_t mp3_sync(AVFormatContext *s, int64_t target_pos, int flags) return AVERROR(EINVAL); } } - if ((target_pos - pos)*dir <= 0 && abs(MIN_VALID/2-j) < score) { + if ((target_pos - pos)*dir <= 0 && FFABS(MIN_VALID/2-j) < score) { candidate = pos; - score = abs(MIN_VALID/2-j); + score = FFABS(MIN_VALID/2-j); } pos += ret; } diff --git a/libavformat/mp3enc.c b/libavformat/mp3enc.c index 8479e2485bb33..dd662f5473c8b 100644 --- a/libavformat/mp3enc.c +++ b/libavformat/mp3enc.c @@ -369,20 +369,18 @@ static int mp3_write_audio_packet(AVFormatContext *s, AVPacket *pkt) static int mp3_queue_flush(AVFormatContext *s) { MP3Context *mp3 = s->priv_data; - AVPacketList *pktl; + AVPacket pkt; int ret = 0, write = 1; ff_id3v2_finish(&mp3->id3, s->pb, s->metadata_header_padding); mp3_write_xing(s); - while ((pktl = mp3->queue)) { - if (write && (ret = mp3_write_audio_packet(s, &pktl->pkt)) < 0) + while (mp3->queue) { + ff_packet_list_get(&mp3->queue, &mp3->queue_end, &pkt); + if (write && (ret = mp3_write_audio_packet(s, &pkt)) < 0) write = 0; - av_packet_unref(&pktl->pkt); - mp3->queue = pktl->next; - av_freep(&pktl); + av_packet_unref(&pkt); } - mp3->queue_end = NULL; return ret; } @@ -514,21 +512,14 @@ static int mp3_write_packet(AVFormatContext *s, AVPacket *pkt) if (pkt->stream_index == mp3->audio_stream_idx) { if (mp3->pics_to_write) { /* buffer audio packets until we get all the pictures */ - AVPacketList *pktl = av_mallocz(sizeof(*pktl)); + int ret = ff_packet_list_put(&mp3->queue, &mp3->queue_end, pkt, FF_PACKETLIST_FLAG_REF_PACKET); - if (!pktl || av_packet_ref(&pktl->pkt, pkt) < 0) { - av_freep(&pktl); + if (ret < 0) { av_log(s, AV_LOG_WARNING, "Not enough memory to buffer audio. Skipping picture streams\n"); mp3->pics_to_write = 0; mp3_queue_flush(s); return mp3_write_audio_packet(s, pkt); } - - if (mp3->queue_end) - mp3->queue_end->next = pktl; - else - mp3->queue = pktl; - mp3->queue_end = pktl; } else return mp3_write_audio_packet(s, pkt); } else { diff --git a/libavformat/mpc8.c b/libavformat/mpc8.c index f280faa5ccd0b..79e5f6a9ab648 100644 --- a/libavformat/mpc8.c +++ b/libavformat/mpc8.c @@ -297,7 +297,7 @@ static int mpc8_read_packet(AVFormatContext *s, AVPacket *pkt) return 0; } if(tag == TAG_STREAMEND) - return AVERROR(EIO); + return AVERROR_EOF; mpc8_handle_chunk(s, tag, pos, size); } return AVERROR_EOF; diff --git a/libavformat/mpeg.c b/libavformat/mpeg.c index 50fe7a1a76873..8ae4740920b8a 100644 --- a/libavformat/mpeg.c +++ b/libavformat/mpeg.c @@ -20,6 +20,7 @@ */ #include "avformat.h" +#include "avio_internal.h" #include "internal.h" #include "mpeg.h" @@ -128,6 +129,7 @@ typedef struct MpegDemuxContext { int sofdec; int dvd; int imkh_cctv; + int raw_ac3; #if CONFIG_VOBSUB_DEMUXER AVFormatContext *sub_ctx; FFDemuxSubtitlesQueue q[32]; @@ -442,8 +444,24 @@ static int mpegps_read_pes_header(AVFormatContext *s, } if (startcode == PRIVATE_STREAM_1) { + int ret = ffio_ensure_seekback(s->pb, 2); + + if (ret < 0) + return ret; + startcode = avio_r8(s->pb); - len--; + m->raw_ac3 = 0; + if (startcode == 0x0b) { + if (avio_r8(s->pb) == 0x77) { + startcode = 0x80; + m->raw_ac3 = 1; + avio_skip(s->pb, -2); + } else { + avio_skip(s->pb, -1); + } + } else { + len--; + } } if (len < 0) goto error_redo; @@ -486,14 +504,16 @@ static int mpegps_read_packet(AVFormatContext *s, if (len < 4) goto skip; - /* audio: skip header */ - avio_r8(s->pb); - lpcm_header_len = avio_rb16(s->pb); - len -= 3; - if (startcode >= 0xb0 && startcode <= 0xbf) { - /* MLP/TrueHD audio has a 4-byte header */ + if (!m->raw_ac3) { + /* audio: skip header */ avio_r8(s->pb); - len--; + lpcm_header_len = avio_rb16(s->pb); + len -= 3; + if (startcode >= 0xb0 && startcode <= 0xbf) { + /* MLP/TrueHD audio has a 4-byte header */ + avio_r8(s->pb); + len--; + } } } @@ -568,7 +588,7 @@ static int mpegps_read_packet(AVFormatContext *s, codec_id = AV_CODEC_ID_DTS; } else if (startcode >= 0xa0 && startcode <= 0xaf) { type = AVMEDIA_TYPE_AUDIO; - if (lpcm_header_len == 6 || startcode == 0xa1) { + if (lpcm_header_len >= 6 && startcode == 0xa1) { codec_id = AV_CODEC_ID_MLP; } else { codec_id = AV_CODEC_ID_PCM_DVD; @@ -703,7 +723,7 @@ static int vobsub_read_header(AVFormatContext *s) if (!vobsub->sub_name) { char *ext; - vobsub->sub_name = av_strdup(s->filename); + vobsub->sub_name = av_strdup(s->url); if (!vobsub->sub_name) { ret = AVERROR(ENOMEM); goto end; @@ -718,7 +738,7 @@ static int vobsub_read_header(AVFormatContext *s) goto end; } memcpy(ext, !strncmp(ext, "IDX", 3) ? "SUB" : "sub", 3); - av_log(s, AV_LOG_VERBOSE, "IDX/SUB: %s -> %s\n", s->filename, vobsub->sub_name); + av_log(s, AV_LOG_VERBOSE, "IDX/SUB: %s -> %s\n", s->url, vobsub->sub_name); } if (!(iformat = av_find_input_format("mpeg"))) { diff --git a/libavformat/mpegenc.c b/libavformat/mpegenc.c index c77c3dfe41459..4c6fa67fb83c1 100644 --- a/libavformat/mpegenc.c +++ b/libavformat/mpegenc.c @@ -353,7 +353,8 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx) if (!s->is_mpeg2 && (st->codecpar->codec_id == AV_CODEC_ID_AC3 || st->codecpar->codec_id == AV_CODEC_ID_DTS || - st->codecpar->codec_id == AV_CODEC_ID_PCM_S16BE)) + st->codecpar->codec_id == AV_CODEC_ID_PCM_S16BE || + st->codecpar->codec_id == AV_CODEC_ID_PCM_DVD)) av_log(ctx, AV_LOG_WARNING, "%s in MPEG-1 system streams is not widely supported, " "consider using the vob or the dvd muxer " @@ -363,16 +364,30 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx) stream->id = ac3_id++; } else if (st->codecpar->codec_id == AV_CODEC_ID_DTS) { stream->id = dts_id++; - } else if (st->codecpar->codec_id == AV_CODEC_ID_PCM_S16BE) { + } else if (st->codecpar->codec_id == AV_CODEC_ID_PCM_S16BE || + st->codecpar->codec_id == AV_CODEC_ID_PCM_DVD) { + if (st->codecpar->bits_per_coded_sample != 16) { + av_log(ctx, AV_LOG_ERROR, "Only 16 bit LPCM streams can be muxed.\n"); + goto fail; + } stream->id = lpcm_id++; for (j = 0; j < 4; j++) { if (lpcm_freq_tab[j] == st->codecpar->sample_rate) break; } - if (j == 4) + if (j == 4) { + int sr; + av_log(ctx, AV_LOG_ERROR, "Invalid sampling rate for PCM stream.\n"); + av_log(ctx, AV_LOG_INFO, "Allowed sampling rates:"); + for (sr = 0; sr < 4; sr++) + av_log(ctx, AV_LOG_INFO, " %d", lpcm_freq_tab[sr]); + av_log(ctx, AV_LOG_INFO, "\n"); + goto fail; + } + if (st->codecpar->channels > 8) { + av_log(ctx, AV_LOG_ERROR, "At most 8 channels allowed for LPCM streams.\n"); goto fail; - if (st->codecpar->channels > 8) - return -1; + } stream->lpcm_header[0] = 0x0c; stream->lpcm_header[1] = (st->codecpar->channels - 1) | (j << 4); stream->lpcm_header[2] = 0x80; @@ -397,7 +412,7 @@ static av_cold int mpeg_mux_init(AVFormatContext *ctx) stream->max_buffer_size = 6 * 1024 + props->buffer_size / 8; else { av_log(ctx, AV_LOG_WARNING, - "VBV buffer size not set, using default size of 130KB\n" + "VBV buffer size not set, using default size of 230KB\n" "If you want the mpeg file to be compliant to some specification\n" "Like DVD, VCD or others, make sure you set the correct buffer size\n"); // FIXME: this is probably too small as default @@ -1150,6 +1165,19 @@ static int mpeg_mux_write_packet(AVFormatContext *ctx, AVPacket *pkt) return AVERROR(ENOMEM); pkt_desc->pts = pts; pkt_desc->dts = dts; + + if (st->codecpar->codec_id == AV_CODEC_ID_PCM_DVD) { + if (size < 3) { + av_log(ctx, AV_LOG_ERROR, "Invalid packet size %d\n", size); + return AVERROR(EINVAL); + } + + /* Skip first 3 bytes of packet data, which comprise PCM header + and will be written fresh by this muxer. */ + buf += 3; + size -= 3; + } + pkt_desc->unwritten_size = pkt_desc->size = size; if (!stream->predecode_packet) diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index 53cbcfb543bf3..37a6aa8bffee7 100644 --- a/libavformat/mpegts.c +++ b/libavformat/mpegts.c @@ -1840,7 +1840,9 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type } if (i && language[0]) { language[i - 1] = 0; - av_dict_set(&st->metadata, "language", language, 0); + /* don't overwrite language, as it may already have been set by + * another, more specific descriptor (e.g. supplementary audio) */ + av_dict_set(&st->metadata, "language", language, AV_DICT_DONT_OVERWRITE); } break; case 0x05: /* registration descriptor */ @@ -1895,6 +1897,42 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type st->internal->need_context_update = 1; } } + if (ext_desc_tag == 0x06) { /* supplementary audio descriptor */ + int flags; + + if (desc_len < 1) + return AVERROR_INVALIDDATA; + flags = get8(pp, desc_end); + + if ((flags & 0x80) == 0) /* mix_type */ + st->disposition |= AV_DISPOSITION_DEPENDENT; + + switch ((flags >> 2) & 0x1F) { /* editorial_classification */ + case 0x01: + st->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED; + break; + case 0x02: + st->disposition |= AV_DISPOSITION_HEARING_IMPAIRED; + break; + case 0x03: + st->disposition |= AV_DISPOSITION_VISUAL_IMPAIRED; + break; + } + + if (flags & 0x01) { /* language_code_present */ + if (desc_len < 4) + return AVERROR_INVALIDDATA; + language[0] = get8(pp, desc_end); + language[1] = get8(pp, desc_end); + language[2] = get8(pp, desc_end); + language[3] = 0; + + /* This language always has to override a possible + * ISO 639 language descriptor language */ + if (language[0]) + av_dict_set(&st->metadata, "language", language, 0); + } + } break; default: break; @@ -2296,6 +2334,14 @@ static int handle_packet(MpegTSContext *ts, const uint8_t *packet) } } + if (packet[1] & 0x80) { + av_log(ts->stream, AV_LOG_DEBUG, "Packet had TEI flag set; marking as corrupt\n"); + if (tss->type == MPEGTS_PES) { + PESContext *pc = tss->u.pes_filter.opaque; + pc->flags |= AV_PKT_FLAG_CORRUPT; + } + } + p = packet + 4; if (has_adaptation) { int64_t pcr_h; diff --git a/libavformat/mpegtsenc.c b/libavformat/mpegtsenc.c index fdfa544ee26f4..8b0736ac4e36f 100644 --- a/libavformat/mpegtsenc.c +++ b/libavformat/mpegtsenc.c @@ -1012,7 +1012,7 @@ static int mpegts_init(AVFormatContext *s) ts->sdt_packet_period, ts->pat_packet_period); if (ts->m2ts_mode == -1) { - if (av_match_ext(s->filename, "m2ts")) { + if (av_match_ext(s->url, "m2ts")) { ts->m2ts_mode = 1; } else { ts->m2ts_mode = 0; diff --git a/libavformat/mpjpeg.c b/libavformat/mpjpeg.c index 3904ccb2b43f3..80f83c58719d6 100644 --- a/libavformat/mpjpeg.c +++ b/libavformat/mpjpeg.c @@ -23,7 +23,7 @@ /* Multipart JPEG */ -#define BOUNDARY_TAG "ffserver" +#define BOUNDARY_TAG "ffmpeg" typedef struct MPJPEGContext { AVClass *class; diff --git a/libavformat/mux.c b/libavformat/mux.c index 53ad46df42d2d..a13f0e3a1b8a7 100644 --- a/libavformat/mux.c +++ b/libavformat/mux.c @@ -186,8 +186,16 @@ int avformat_alloc_output_context2(AVFormatContext **avctx, AVOutputFormat *ofor } else s->priv_data = NULL; - if (filename) + if (filename) { +#if FF_API_FORMAT_FILENAME +FF_DISABLE_DEPRECATION_WARNINGS av_strlcpy(s->filename, filename, sizeof(s->filename)); +FF_ENABLE_DEPRECATION_WARNINGS +#endif + if (!(s->url = av_strdup(filename))) + goto nomem; + + } *avctx = s; return 0; nomem: @@ -251,23 +259,25 @@ static int init_muxer(AVFormatContext *s, AVDictionary **options) (ret = av_opt_set_dict2(s->priv_data, &tmp, AV_OPT_SEARCH_CHILDREN)) < 0) goto fail; +#if FF_API_FORMAT_FILENAME +FF_DISABLE_DEPRECATION_WARNINGS + if (!s->url && !(s->url = av_strdup(s->filename))) { +FF_ENABLE_DEPRECATION_WARNINGS +#else + if (!s->url && !(s->url = av_strdup(""))) { +#endif + ret = AVERROR(ENOMEM); + goto fail; + } + #if FF_API_LAVF_AVCTX FF_DISABLE_DEPRECATION_WARNINGS if (s->nb_streams && s->streams[0]->codec->flags & AV_CODEC_FLAG_BITEXACT) { if (!(s->flags & AVFMT_FLAG_BITEXACT)) { -#if FF_API_LAVF_BITEXACT - av_log(s, AV_LOG_WARNING, - "Setting the AVFormatContext to bitexact mode, because " - "the AVCodecContext is in that mode. This behavior will " - "change in the future. To keep the current behavior, set " - "AVFormatContext.flags |= AVFMT_FLAG_BITEXACT.\n"); - s->flags |= AVFMT_FLAG_BITEXACT; -#else av_log(s, AV_LOG_WARNING, "The AVFormatContext is not in set to bitexact mode, only " "the AVCodecContext. If this is not intended, set " "AVFormatContext.flags |= AVFMT_FLAG_BITEXACT.\n"); -#endif } } FF_ENABLE_DEPRECATION_WARNINGS @@ -284,17 +294,6 @@ FF_ENABLE_DEPRECATION_WARNINGS st = s->streams[i]; par = st->codecpar; -#if FF_API_LAVF_CODEC_TB && FF_API_LAVF_AVCTX -FF_DISABLE_DEPRECATION_WARNINGS - if (!st->time_base.num && st->codec->time_base.num) { - av_log(s, AV_LOG_WARNING, "Using AVStream.codec.time_base as a " - "timebase hint to the muxer is deprecated. Set " - "AVStream.time_base instead.\n"); - avpriv_set_pts_info(st, 64, st->codec->time_base.num, st->codec->time_base.den); - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif - #if FF_API_LAVF_AVCTX FF_DISABLE_DEPRECATION_WARNINGS if (st->codecpar->codec_type == AVMEDIA_TYPE_UNKNOWN && @@ -452,19 +451,27 @@ static int init_pts(AVFormatContext *s) break; } - if (!st->priv_pts) - st->priv_pts = av_mallocz(sizeof(*st->priv_pts)); - if (!st->priv_pts) + if (!st->internal->priv_pts) + st->internal->priv_pts = av_mallocz(sizeof(*st->internal->priv_pts)); + if (!st->internal->priv_pts) return AVERROR(ENOMEM); if (den != AV_NOPTS_VALUE) { if (den <= 0) return AVERROR_INVALIDDATA; - frac_init(st->priv_pts, 0, 0, den); + frac_init(st->internal->priv_pts, 0, 0, den); } } + if (s->avoid_negative_ts < 0) { + av_assert2(s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO); + if (s->oformat->flags & (AVFMT_TS_NEGATIVE | AVFMT_NOTIMESTAMPS)) { + s->avoid_negative_ts = 0; + } else + s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_NON_NEGATIVE; + } + return 0; } @@ -478,25 +485,6 @@ static void flush_if_needed(AVFormatContext *s) } } -static int write_header_internal(AVFormatContext *s) -{ - if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb) - avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_HEADER); - if (s->oformat->write_header) { - int ret = s->oformat->write_header(s); - if (ret >= 0 && s->pb && s->pb->error < 0) - ret = s->pb->error; - s->internal->write_header_ret = ret; - if (ret < 0) - return ret; - flush_if_needed(s); - } - s->internal->header_written = 1; - if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb) - avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_UNKNOWN); - return 0; -} - int avformat_init_output(AVFormatContext *s, AVDictionary **options) { int ret = 0; @@ -511,14 +499,6 @@ int avformat_init_output(AVFormatContext *s, AVDictionary **options) if ((ret = init_pts(s)) < 0) return ret; - if (s->avoid_negative_ts < 0) { - av_assert2(s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO); - if (s->oformat->flags & (AVFMT_TS_NEGATIVE | AVFMT_NOTIMESTAMPS)) { - s->avoid_negative_ts = 0; - } else - s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_NON_NEGATIVE; - } - return AVSTREAM_INIT_IN_INIT_OUTPUT; } @@ -535,23 +515,22 @@ int avformat_write_header(AVFormatContext *s, AVDictionary **options) if ((ret = avformat_init_output(s, options)) < 0) return ret; - if (!(s->oformat->check_bitstream && s->flags & AVFMT_FLAG_AUTO_BSF)) { - ret = write_header_internal(s); + if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb) + avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_HEADER); + if (s->oformat->write_header) { + ret = s->oformat->write_header(s); + if (ret >= 0 && s->pb && s->pb->error < 0) + ret = s->pb->error; if (ret < 0) goto fail; + flush_if_needed(s); } + if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb) + avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_UNKNOWN); if (!s->internal->streams_initialized) { if ((ret = init_pts(s)) < 0) goto fail; - - if (s->avoid_negative_ts < 0) { - av_assert2(s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO); - if (s->oformat->flags & (AVFMT_TS_NEGATIVE | AVFMT_NOTIMESTAMPS)) { - s->avoid_negative_ts = 0; - } else - s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_NON_NEGATIVE; - } } return streams_already_initialized; @@ -621,7 +600,7 @@ static int compute_muxer_pkt_fields(AVFormatContext *s, AVStream *st, AVPacket * } pkt->dts = // pkt->pts= st->cur_dts; - pkt->pts = st->priv_pts->val; + pkt->pts = st->internal->priv_pts->val; } //calculate dts from pts @@ -658,7 +637,7 @@ static int compute_muxer_pkt_fields(AVFormatContext *s, AVStream *st, AVPacket * av_ts2str(pkt->pts), av_ts2str(pkt->dts)); st->cur_dts = pkt->dts; - st->priv_pts->val = pkt->dts; + st->internal->priv_pts->val = pkt->dts; /* update pts */ switch (st->codecpar->codec_type) { @@ -670,12 +649,12 @@ static int compute_muxer_pkt_fields(AVFormatContext *s, AVStream *st, AVPacket * /* HACK/FIXME, we skip the initial 0 size packets as they are most * likely equal to the encoder delay, but it would be better if we * had the real timestamps from the encoder */ - if (frame_size >= 0 && (pkt->size || st->priv_pts->num != st->priv_pts->den >> 1 || st->priv_pts->val)) { - frac_add(st->priv_pts, (int64_t)st->time_base.den * frame_size); + if (frame_size >= 0 && (pkt->size || st->internal->priv_pts->num != st->internal->priv_pts->den >> 1 || st->internal->priv_pts->val)) { + frac_add(st->internal->priv_pts, (int64_t)st->time_base.den * frame_size); } break; case AVMEDIA_TYPE_VIDEO: - frac_add(st->priv_pts, (int64_t)st->time_base.den * st->time_base.num); + frac_add(st->internal->priv_pts, (int64_t)st->time_base.den * st->time_base.num); break; } return 0; @@ -694,7 +673,7 @@ FF_ENABLE_DEPRECATION_WARNINGS */ static int write_packet(AVFormatContext *s, AVPacket *pkt) { - int ret, did_split; + int ret; int64_t pts_backup, dts_backup; pts_backup = pkt->pts; @@ -759,18 +738,6 @@ static int write_packet(AVFormatContext *s, AVPacket *pkt) } } -#if FF_API_LAVF_MERGE_SD -FF_DISABLE_DEPRECATION_WARNINGS - did_split = av_packet_split_side_data(pkt); -FF_ENABLE_DEPRECATION_WARNINGS -#endif - - if (!s->internal->header_written) { - ret = s->internal->write_header_ret ? s->internal->write_header_ret : write_header_internal(s); - if (ret < 0) - goto fail; - } - if ((pkt->flags & AV_PKT_FLAG_UNCODED_FRAME)) { AVFrame *frame = (AVFrame *)pkt->data; av_assert0(pkt->size == UNCODED_FRAME_PACKET_SIZE); @@ -786,14 +753,6 @@ FF_ENABLE_DEPRECATION_WARNINGS ret = s->pb->error; } -fail: -#if FF_API_LAVF_MERGE_SD -FF_DISABLE_DEPRECATION_WARNINGS - if (did_split) - av_packet_merge_side_data(pkt); -FF_ENABLE_DEPRECATION_WARNINGS -#endif - if (ret < 0) { pkt->pts = pts_backup; pkt->dts = dts_backup; @@ -889,16 +848,6 @@ static int do_packet_auto_bsf(AVFormatContext *s, AVPacket *pkt) { } } -#if FF_API_LAVF_MERGE_SD -FF_DISABLE_DEPRECATION_WARNINGS - if (st->internal->nb_bsfcs) { - ret = av_packet_split_side_data(pkt); - if (ret < 0) - av_log(s, AV_LOG_WARNING, "Failed to split side data before bitstream filter\n"); - } -FF_ENABLE_DEPRECATION_WARNINGS -#endif - for (i = 0; i < st->internal->nb_bsfcs; i++) { AVBSFContext *ctx = st->internal->bsfcs[i]; // TODO: when any bitstream filter requires flushing at EOF, we'll need to @@ -918,7 +867,9 @@ FF_ENABLE_DEPRECATION_WARNINGS av_log(ctx, AV_LOG_ERROR, "Failed to send packet to filter %s for stream %d\n", ctx->filter->name, pkt->stream_index); - return ret; + if (s->error_recognition & AV_EF_EXPLODE) + return ret; + return 0; } } return 1; @@ -934,11 +885,6 @@ int av_write_frame(AVFormatContext *s, AVPacket *pkt) if (!pkt) { if (s->oformat->flags & AVFMT_ALLOW_FLUSH) { - if (!s->internal->header_written) { - ret = s->internal->write_header_ret ? s->internal->write_header_ret : write_header_internal(s); - if (ret < 0) - return ret; - } ret = s->oformat->write_packet(s, NULL); flush_if_needed(s); if (ret >= 0 && s->pb && s->pb->error < 0) @@ -1322,14 +1268,8 @@ int av_write_trailer(AVFormatContext *s) goto fail; } - if (!s->internal->header_written) { - ret = s->internal->write_header_ret ? s->internal->write_header_ret : write_header_internal(s); - if (ret < 0) - goto fail; - } - fail: - if (s->internal->header_written && s->oformat->write_trailer) { + if (s->oformat->write_trailer) { if (!(s->oformat->flags & AVFMT_NOFILE) && s->pb) avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER); if (ret >= 0) { @@ -1342,7 +1282,6 @@ int av_write_trailer(AVFormatContext *s) if (s->oformat->deinit) s->oformat->deinit(s); - s->internal->header_written = s->internal->initialized = s->internal->streams_initialized = 0; diff --git a/libavformat/mvdec.c b/libavformat/mvdec.c index f7aa4cbaecf86..fa596179ed97a 100644 --- a/libavformat/mvdec.c +++ b/libavformat/mvdec.c @@ -227,7 +227,9 @@ static int read_table(AVFormatContext *avctx, AVStream *st, int (*parse)(AVFormatContext *avctx, AVStream *st, const char *name, int size)) { - int count, i; + unsigned count; + int i; + AVIOContext *pb = avctx->pb; avio_skip(pb, 4); count = avio_rb32(pb); @@ -235,6 +237,10 @@ static int read_table(AVFormatContext *avctx, AVStream *st, for (i = 0; i < count; i++) { char name[17]; int size; + + if (avio_feof(pb)) + return AVERROR_EOF; + avio_read(pb, name, 16); name[sizeof(name) - 1] = 0; size = avio_rb32(pb); diff --git a/libavformat/mxf.c b/libavformat/mxf.c index bfc3218b815a0..a909401f08b98 100644 --- a/libavformat/mxf.c +++ b/libavformat/mxf.c @@ -137,6 +137,7 @@ static const MXFSamplesPerFrame mxf_spf[] = { { { 1001, 60000 }, { 801, 801, 801, 801, 800, 0 } }, // NTSC 59.94 { { 1, 25 }, { 1920, 0, 0, 0, 0, 0 } }, // PAL 25 { { 1, 50 }, { 960, 0, 0, 0, 0, 0 } }, // PAL 50 + { { 1, 60 }, { 800, 0, 0, 0, 0, 0 } }, }; static const AVRational mxf_time_base[] = { @@ -146,6 +147,7 @@ static const AVRational mxf_time_base[] = { { 1001, 60000 }, { 1, 25 }, { 1, 50 }, + { 1, 60 }, { 0, 0} }; @@ -155,7 +157,7 @@ const MXFSamplesPerFrame *ff_mxf_get_samples_per_frame(AVFormatContext *s, int idx = av_find_nearest_q_idx(time_base, mxf_time_base); AVRational diff = av_sub_q(time_base, mxf_time_base[idx]); - diff.num = abs(diff.num); + diff.num = FFABS(diff.num); if (av_cmp_q(diff, (AVRational){1, 1000}) >= 0) return NULL; diff --git a/libavformat/mxf.h b/libavformat/mxf.h index f3db1f939bbd7..ffcc429a8b4d7 100644 --- a/libavformat/mxf.h +++ b/libavformat/mxf.h @@ -45,9 +45,9 @@ enum MXFMetadataSetType { SubDescriptor, IndexTableSegment, EssenceContainerData, - TypeBottom,// add metadata type before this EssenceGroup, TaggedValue, + TapeDescriptor, }; enum MXFFrameLayout { diff --git a/libavformat/mxfdec.c b/libavformat/mxfdec.c index 118e3e40b44cf..7a42555562190 100644 --- a/libavformat/mxfdec.c +++ b/libavformat/mxfdec.c @@ -91,6 +91,7 @@ typedef struct MXFPartition { int64_t index_byte_count; int pack_length; int64_t pack_ofs; ///< absolute offset of pack in file, including run-in + int64_t body_offset; } MXFPartition; typedef struct MXFCryptoContext { @@ -162,6 +163,8 @@ typedef struct { int intra_only; uint64_t sample_count; int64_t original_duration; /* st->duration in SampleRate/EditRate units */ + int index_sid; + int body_sid; } MXFTrack; typedef struct MXFDescriptor { @@ -223,6 +226,15 @@ typedef struct MXFPackage { int comment_count; } MXFPackage; +typedef struct MXFEssenceContainerData { + UID uid; + enum MXFMetadataSetType type; + UID package_uid; + UID package_ul; + int index_sid; + int body_sid; +} MXFEssenceContainerData; + typedef struct MXFMetadataSet { UID uid; enum MXFMetadataSetType type; @@ -247,6 +259,8 @@ typedef struct MXFContext { MXFOP op; UID *packages_refs; int packages_count; + UID *essence_container_data_refs; + int essence_container_data_count; MXFMetadataSet **metadata_sets; int metadata_sets_count; AVFormatContext *fc; @@ -261,7 +275,7 @@ typedef struct MXFContext { int parsing_backward; int64_t last_forward_tell; int last_forward_partition; - int current_edit_unit; + int64_t current_edit_unit; int nb_index_tables; MXFIndexTable *index_tables; int edit_units_per_packet; ///< how many edit units to read at a time (PCM, OPAtom) @@ -289,7 +303,8 @@ static const uint8_t mxf_header_partition_pack_key[] = { 0x06,0x0e,0x2b,0x static const uint8_t mxf_essence_element_key[] = { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0d,0x01,0x03,0x01 }; static const uint8_t mxf_avid_essence_element_key[] = { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x01,0x0e,0x04,0x03,0x01 }; static const uint8_t mxf_canopus_essence_element_key[] = { 0x06,0x0e,0x2b,0x34,0x01,0x02,0x01,0x0a,0x0e,0x0f,0x03,0x01 }; -static const uint8_t mxf_system_item_key[] = { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x03,0x01,0x04 }; +static const uint8_t mxf_system_item_key_cp[] = { 0x06,0x0e,0x2b,0x34,0x02,0x05,0x01,0x01,0x0d,0x01,0x03,0x01,0x04 }; +static const uint8_t mxf_system_item_key_gc[] = { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x03,0x01,0x14 }; static const uint8_t mxf_klv_key[] = { 0x06,0x0e,0x2b,0x34 }; /* complete keys to match */ static const uint8_t mxf_crypto_source_container_ul[] = { 0x06,0x0e,0x2b,0x34,0x01,0x01,0x01,0x09,0x06,0x01,0x01,0x02,0x02,0x00,0x00,0x00 }; @@ -384,20 +399,43 @@ static int klv_read_packet(KLVPacket *klv, AVIOContext *pb) return klv->length == -1 ? -1 : 0; } -static int mxf_get_stream_index(AVFormatContext *s, KLVPacket *klv) +static int mxf_get_stream_index(AVFormatContext *s, KLVPacket *klv, int body_sid) { int i; for (i = 0; i < s->nb_streams; i++) { MXFTrack *track = s->streams[i]->priv_data; /* SMPTE 379M 7.3 */ - if (track && !memcmp(klv->key + sizeof(mxf_essence_element_key), track->track_number, sizeof(track->track_number))) + if (track && (!body_sid || !track->body_sid || track->body_sid == body_sid) && !memcmp(klv->key + sizeof(mxf_essence_element_key), track->track_number, sizeof(track->track_number))) return i; } /* return 0 if only one stream, for OP Atom files with 0 as track number */ return s->nb_streams == 1 ? 0 : -1; } +static int find_body_sid_by_offset(MXFContext *mxf, int64_t offset) +{ + // we look for partition where the offset is placed + int a, b, m; + int64_t this_partition; + + a = -1; + b = mxf->partitions_count; + + while (b - a > 1) { + m = (a + b) >> 1; + this_partition = mxf->partitions[m].this_partition; + if (this_partition <= offset) + a = m; + else + b = m; + } + + if (a == -1) + return 0; + return mxf->partitions[a].body_sid; +} + /* XXX: use AVBitStreamFilter */ static int mxf_get_d10_aes3_packet(AVIOContext *pb, AVStream *st, AVPacket *pkt, int64_t length) { @@ -439,6 +477,7 @@ static int mxf_decrypt_triplet(AVFormatContext *s, AVPacket *pkt, KLVPacket *klv uint8_t ivec[16]; uint8_t tmpbuf[16]; int index; + int body_sid; if (!mxf->aesc && s->key && s->keylen == 16) { mxf->aesc = av_aes_alloc(); @@ -456,7 +495,9 @@ static int mxf_decrypt_triplet(AVFormatContext *s, AVPacket *pkt, KLVPacket *klv avio_read(pb, klv->key, 16); if (!IS_KLV_KEY(klv, mxf_essence_element_key)) return AVERROR_INVALIDDATA; - index = mxf_get_stream_index(s, klv); + + body_sid = find_body_sid_by_offset(mxf, klv->offset); + index = mxf_get_stream_index(s, klv, body_sid); if (index < 0) return AVERROR_INVALIDDATA; // source size @@ -524,6 +565,9 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size uint64_t footer_partition; uint32_t nb_essence_containers; + if (mxf->partitions_count >= INT_MAX / 2) + return AVERROR_INVALIDDATA; + tmp_part = av_realloc_array(mxf->partitions, mxf->partitions_count + 1, sizeof(*mxf->partitions)); if (!tmp_part) return AVERROR(ENOMEM); @@ -572,7 +616,7 @@ static int mxf_read_partition_pack(void *arg, AVIOContext *pb, int tag, int size partition->header_byte_count = avio_rb64(pb); partition->index_byte_count = avio_rb64(pb); partition->index_sid = avio_rb32(pb); - avio_skip(pb, 8); + partition->body_offset = avio_rb64(pb); partition->body_sid = avio_rb32(pb); if (avio_read(pb, op, sizeof(UID)) != sizeof(UID)) { av_log(mxf->fc, AV_LOG_ERROR, "Failed reading UID\n"); @@ -756,6 +800,9 @@ static int mxf_read_content_storage(void *arg, AVIOContext *pb, int tag, int siz av_log(mxf->fc, AV_LOG_VERBOSE, "Multiple packages_refs\n"); av_free(mxf->packages_refs); return mxf_read_strong_ref_array(pb, &mxf->packages_refs, &mxf->packages_count); + case 0x1902: + av_free(mxf->essence_container_data_refs); + return mxf_read_strong_ref_array(pb, &mxf->essence_container_data_refs, &mxf->essence_container_data_count); } return 0; } @@ -892,6 +939,25 @@ static int mxf_read_package(void *arg, AVIOContext *pb, int tag, int size, UID u return 0; } +static int mxf_read_essence_container_data(void *arg, AVIOContext *pb, int tag, int size, UID uid, int64_t klv_offset) +{ + MXFEssenceContainerData *essence_data = arg; + switch(tag) { + case 0x2701: + /* linked package umid UMID */ + avio_read(pb, essence_data->package_ul, 16); + avio_read(pb, essence_data->package_uid, 16); + break; + case 0x3f06: + essence_data->index_sid = avio_rb32(pb); + break; + case 0x3f07: + essence_data->body_sid = avio_rb32(pb); + break; + } + return 0; +} + static int mxf_read_index_entry_array(AVIOContext *pb, MXFIndexTableSegment *segment) { int i, length; @@ -1247,9 +1313,15 @@ static int mxf_get_sorted_table_segments(MXFContext *mxf, int *nb_sorted_segment * We want the smallest values for the keys than what we currently have, unless this is the first such entry this time around. * If we come across an entry with the same IndexStartPosition but larger IndexDuration, then we'll prefer it over the one we currently have. */ - if ((i == 0 || s->body_sid > last_body_sid || s->index_sid > last_index_sid || s->index_start_position > last_index_start) && - (best == -1 || s->body_sid < best_body_sid || s->index_sid < best_index_sid || s->index_start_position < best_index_start || - (s->index_start_position == best_index_start && s->index_duration > best_index_duration))) { + if ((i == 0 || + s->body_sid > last_body_sid || + s->body_sid == last_body_sid && s->index_sid > last_index_sid || + s->body_sid == last_body_sid && s->index_sid == last_index_sid && s->index_start_position > last_index_start) && + (best == -1 || + s->body_sid < best_body_sid || + s->body_sid == best_body_sid && s->index_sid < best_index_sid || + s->body_sid == best_body_sid && s->index_sid == best_index_sid && s->index_start_position < best_index_start || + s->body_sid == best_body_sid && s->index_sid == best_index_sid && s->index_start_position == best_index_start && s->index_duration > best_index_duration)) { best = j; best_body_sid = s->body_sid; best_index_sid = s->index_sid; @@ -1278,26 +1350,38 @@ static int mxf_get_sorted_table_segments(MXFContext *mxf, int *nb_sorted_segment */ static int mxf_absolute_bodysid_offset(MXFContext *mxf, int body_sid, int64_t offset, int64_t *offset_out) { - int x; - int64_t offset_in = offset; /* for logging */ + MXFPartition *last_p = NULL; + int a, b, m, m0; - for (x = 0; x < mxf->partitions_count; x++) { - MXFPartition *p = &mxf->partitions[x]; + if (offset < 0) + return AVERROR(EINVAL); - if (p->body_sid != body_sid) - continue; + a = -1; + b = mxf->partitions_count; - if (offset < p->essence_length || !p->essence_length) { - *offset_out = p->essence_offset + offset; - return 0; - } + while (b - a > 1) { + m0 = m = (a + b) >> 1; + + while (m < b && mxf->partitions[m].body_sid != body_sid) + m++; + + if (m < b && mxf->partitions[m].body_offset <= offset) + a = m; + else + b = m0; + } + + if (a >= 0) + last_p = &mxf->partitions[a]; - offset -= p->essence_length; + if (last_p && (!last_p->essence_length || last_p->essence_length > (offset - last_p->body_offset))) { + *offset_out = last_p->essence_offset + (offset - last_p->body_offset); + return 0; } av_log(mxf->fc, AV_LOG_ERROR, "failed to find absolute offset of %"PRIX64" in BodySID %i - partial file?\n", - offset_in, body_sid); + offset, body_sid); return AVERROR_INVALIDDATA; } @@ -1496,14 +1580,6 @@ static int mxf_compute_index_tables(MXFContext *mxf) { int i, j, k, ret, nb_sorted_segments; MXFIndexTableSegment **sorted_segments = NULL; - AVStream *st = NULL; - - for (i = 0; i < mxf->fc->nb_streams; i++) { - if (mxf->fc->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_DATA) - continue; - st = mxf->fc->streams[i]; - break; - } if ((ret = mxf_get_sorted_table_segments(mxf, &nb_sorted_segments, &sorted_segments)) || nb_sorted_segments <= 0) { @@ -1542,6 +1618,7 @@ static int mxf_compute_index_tables(MXFContext *mxf) for (i = j = 0; j < mxf->nb_index_tables; i += mxf->index_tables[j++].nb_segments) { MXFIndexTable *t = &mxf->index_tables[j]; + MXFTrack *mxf_track = NULL; t->segments = av_mallocz_array(t->nb_segments, sizeof(*t->segments)); @@ -1564,6 +1641,14 @@ static int mxf_compute_index_tables(MXFContext *mxf) if ((ret = mxf_compute_ptses_fake_index(mxf, t)) < 0) goto finish_decoding_index; + for (k = 0; k < mxf->fc->nb_streams; k++) { + MXFTrack *track = mxf->fc->streams[k]->priv_data; + if (track && track->index_sid == t->index_sid) { + mxf_track = track; + break; + } + } + /* fix zero IndexDurations */ for (k = 0; k < t->nb_segments; k++) { if (t->segments[k]->index_duration) @@ -1573,7 +1658,7 @@ static int mxf_compute_index_tables(MXFContext *mxf) av_log(mxf->fc, AV_LOG_WARNING, "IndexSID %i segment %i has zero IndexDuration and there's more than one segment\n", t->index_sid, k); - if (!st) { + if (!mxf_track) { av_log(mxf->fc, AV_LOG_WARNING, "no streams?\n"); break; } @@ -1581,7 +1666,7 @@ static int mxf_compute_index_tables(MXFContext *mxf) /* assume the first stream's duration is reasonable * leave index_duration = 0 on further segments in case we have any (unlikely) */ - t->segments[k]->index_duration = st->duration; + t->segments[k]->index_duration = mxf_track->original_duration; break; } } @@ -1680,7 +1765,7 @@ static MXFTimecodeComponent* mxf_resolve_timecode_component(MXFContext *mxf, UID return NULL; } -static MXFPackage* mxf_resolve_source_package(MXFContext *mxf, UID package_uid) +static MXFPackage* mxf_resolve_source_package(MXFContext *mxf, UID package_ul, UID package_uid) { MXFPackage *package = NULL; int i; @@ -1690,7 +1775,7 @@ static MXFPackage* mxf_resolve_source_package(MXFContext *mxf, UID package_uid) if (!package) continue; - if (!memcmp(package->package_uid, package_uid, 16)) + if (!memcmp(package->package_ul, package_ul, 16) && !memcmp(package->package_uid, package_uid, 16)) return package; } return NULL; @@ -1739,7 +1824,7 @@ static MXFStructuralComponent* mxf_resolve_essence_group_choice(MXFContext *mxf, if (!component) continue; - if (!(package = mxf_resolve_source_package(mxf, component->source_package_uid))) + if (!(package = mxf_resolve_source_package(mxf, component->source_package_ul, component->source_package_uid))) continue; descriptor = mxf_resolve_strong_ref(mxf, &package->descriptor_ref, Descriptor); @@ -1805,7 +1890,7 @@ static int mxf_parse_physical_source_package(MXFContext *mxf, MXFTrack *source_t if (!sourceclip) continue; - if (!(physical_package = mxf_resolve_source_package(mxf, sourceclip->source_package_uid))) + if (!(physical_package = mxf_resolve_source_package(mxf, sourceclip->source_package_ul, sourceclip->source_package_uid))) break; mxf_add_umid_metadata(&st->metadata, "reel_umid", physical_package); @@ -1975,7 +2060,7 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) if (!component) continue; - source_package = mxf_resolve_source_package(mxf, component->source_package_uid); + source_package = mxf_resolve_source_package(mxf, component->source_package_ul, component->source_package_uid); if (!source_package) { av_log(mxf->fc, AV_LOG_TRACE, "material track %d: no corresponding source package found\n", material_track->track_id); continue; @@ -1995,6 +2080,21 @@ static int mxf_parse_structural_metadata(MXFContext *mxf) av_log(mxf->fc, AV_LOG_ERROR, "material track %d: no corresponding source track found\n", material_track->track_id); break; } + + for (k = 0; k < mxf->essence_container_data_count; k++) { + MXFEssenceContainerData *essence_data; + + if (!(essence_data = mxf_resolve_strong_ref(mxf, &mxf->essence_container_data_refs[k], EssenceContainerData))) { + av_log(mxf, AV_LOG_TRACE, "could not resolve essence container data strong ref\n"); + continue; + } + if (!memcmp(component->source_package_ul, essence_data->package_ul, sizeof(UID)) && !memcmp(component->source_package_uid, essence_data->package_uid, sizeof(UID))) { + source_track->body_sid = essence_data->body_sid; + source_track->index_sid = essence_data->index_sid; + break; + } + } + if(source_track && component) break; } @@ -2401,6 +2501,7 @@ static const MXFMetadataReadTableEntry mxf_metadata_read_table[] = { { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x0c,0x00 }, mxf_read_pulldown_component, sizeof(MXFPulldownComponent), PulldownComponent }, { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x04,0x01,0x02,0x02,0x00,0x00 }, mxf_read_cryptographic_context, sizeof(MXFCryptoContext), CryptoContext }, { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x02,0x01,0x01,0x10,0x01,0x00 }, mxf_read_index_table_segment, sizeof(MXFIndexTableSegment), IndexTableSegment }, + { { 0x06,0x0e,0x2b,0x34,0x02,0x53,0x01,0x01,0x0d,0x01,0x01,0x01,0x01,0x01,0x23,0x00 }, mxf_read_essence_container_data, sizeof(MXFEssenceContainerData), EssenceContainerData }, { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, NULL, 0, AnyType }, }; @@ -2694,6 +2795,7 @@ static AVStream* mxf_get_opatom_stream(MXFContext *mxf) static void mxf_handle_small_eubc(AVFormatContext *s) { MXFContext *mxf = s->priv_data; + MXFTrack *track; /* assuming non-OPAtom == frame wrapped * no sane writer would wrap 2 byte PCM packets with 20 byte headers.. */ @@ -2713,7 +2815,8 @@ static void mxf_handle_small_eubc(AVFormatContext *s) /* TODO: We could compute this from the ratio between the audio * and video edit rates for 48 kHz NTSC we could use the * 1802-1802-1802-1802-1801 pattern. */ - mxf->edit_units_per_packet = 1920; + track = st->priv_data; + mxf->edit_units_per_packet = FFMAX(1, track->edit_rate.num / track->edit_rate.den / 25); } /** @@ -2861,7 +2964,8 @@ static int mxf_read_header(AVFormatContext *s) if (IS_KLV_KEY(klv.key, mxf_encrypted_triplet_key) || IS_KLV_KEY(klv.key, mxf_essence_element_key) || IS_KLV_KEY(klv.key, mxf_avid_essence_element_key) || - IS_KLV_KEY(klv.key, mxf_system_item_key)) { + IS_KLV_KEY(klv.key, mxf_system_item_key_cp) || + IS_KLV_KEY(klv.key, mxf_system_item_key_gc)) { if (!mxf->current_partition) { av_log(mxf->fc, AV_LOG_ERROR, "found essence prior to first PartitionPack\n"); @@ -2875,8 +2979,8 @@ static int mxf_read_header(AVFormatContext *s) * for OPAtom we still need the actual essence_offset though (the KL's length can vary) */ int64_t op1a_essence_offset = - round_to_kag(mxf->current_partition->this_partition + - mxf->current_partition->pack_length, mxf->current_partition->kag_size) + + mxf->current_partition->this_partition + + round_to_kag(mxf->current_partition->pack_length, mxf->current_partition->kag_size) + round_to_kag(mxf->current_partition->header_byte_count, mxf->current_partition->kag_size) + round_to_kag(mxf->current_partition->index_byte_count, mxf->current_partition->kag_size); @@ -2888,7 +2992,10 @@ static int mxf_read_header(AVFormatContext *s) mxf->current_partition->essence_length = klv.length; } else { /* NOTE: op1a_essence_offset may be less than to klv.offset (C0023S01.mxf) */ - mxf->current_partition->essence_offset = op1a_essence_offset; + if (IS_KLV_KEY(klv.key, mxf_system_item_key_cp) || IS_KLV_KEY(klv.key, mxf_system_item_key_gc)) + mxf->current_partition->essence_offset = klv.offset; + else + mxf->current_partition->essence_offset = op1a_essence_offset; } } @@ -2959,6 +3066,42 @@ static int mxf_read_header(AVFormatContext *s) return ret; } +static MXFIndexTable *mxf_find_index_table(MXFContext *mxf, int index_sid) +{ + int i; + for (i = 0; i < mxf->nb_index_tables; i++) + if (mxf->index_tables[i].index_sid == index_sid) + return &mxf->index_tables[i]; + return NULL; +} + +/* Get the edit unit of the next packet from current_offset in a track. The returned edit unit can be original_duration as well! */ +static int mxf_get_next_track_edit_unit(MXFContext *mxf, MXFTrack *track, int64_t current_offset, int64_t *edit_unit_out) +{ + int64_t a, b, m, offset; + MXFIndexTable *t = mxf_find_index_table(mxf, track->index_sid); + + if (!t || track->original_duration <= 0) + return -1; + + a = -1; + b = track->original_duration; + + while (b - a > 1) { + m = (a + b) >> 1; + if (mxf_edit_unit_absolute_offset(mxf, t, m, NULL, &offset, 0) < 0) + return -1; + if (offset < current_offset) + a = m; + else + b = m; + } + + *edit_unit_out = b; + + return 0; +} + /** * Sets mxf->current_edit_unit based on what offset we're currently at. * @return next_ofs if OK, <0 on error @@ -2976,7 +3119,7 @@ static int64_t mxf_set_current_edit_unit(MXFContext *mxf, int64_t current_offset /* find mxf->current_edit_unit so that the next edit unit starts ahead of current_offset */ while (mxf->current_edit_unit >= 0) { if (mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit + 1, NULL, &next_ofs, 0) < 0) - return -1; + return -2; if (next_ofs <= last_ofs) { /* large next_ofs didn't change or current_edit_unit wrapped @@ -3065,7 +3208,7 @@ static int mxf_set_pts(MXFContext *mxf, AVStream *st, AVPacket *pkt, int64_t nex AVCodecParameters *par = st->codecpar; MXFTrack *track = st->priv_data; - if (par->codec_type == AVMEDIA_TYPE_VIDEO && next_ofs >= 0) { + if (par->codec_type == AVMEDIA_TYPE_VIDEO && (next_ofs >= 0 || next_ofs == -2 && st->duration == mxf->current_edit_unit + 1)) { /* mxf->current_edit_unit good - see if we have an * index table to derive timestamps from */ MXFIndexTable *t = &mxf->index_tables[0]; @@ -3106,7 +3249,8 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) if (IS_KLV_KEY(klv.key, mxf_essence_element_key) || IS_KLV_KEY(klv.key, mxf_canopus_essence_element_key) || IS_KLV_KEY(klv.key, mxf_avid_essence_element_key)) { - int index = mxf_get_stream_index(s, &klv); + int body_sid = find_body_sid_by_offset(mxf, klv.offset); + int index = mxf_get_stream_index(s, &klv, body_sid); int64_t next_ofs, next_klv; AVStream *st; @@ -3130,7 +3274,7 @@ static int mxf_read_packet_old(AVFormatContext *s, AVPacket *pkt) * truncate the packet since it's probably very large (>2 GiB is common) */ avpriv_request_sample(s, "OPAtom misinterpreted as OP1a? " - "KLV for edit unit %i extending into " + "KLV for edit unit %"PRId64" extending into " "next edit unit", mxf->current_edit_unit); klv.length = next_ofs - avio_tell(s->pb); @@ -3174,6 +3318,7 @@ static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) int64_t ret64, pos, next_pos; AVStream *st; MXFIndexTable *t; + MXFTrack *track; int edit_units; if (mxf->op != OPAtom) @@ -3184,14 +3329,16 @@ static int mxf_read_packet(AVFormatContext *s, AVPacket *pkt) if (!st) return AVERROR_EOF; + track = st->priv_data; + /* OPAtom - clip wrapped demuxing */ /* NOTE: mxf_read_header() makes sure nb_index_tables > 0 for OPAtom */ t = &mxf->index_tables[0]; - if (mxf->current_edit_unit >= st->duration) + if (mxf->current_edit_unit >= track->original_duration) return AVERROR_EOF; - edit_units = FFMIN(mxf->edit_units_per_packet, st->duration - mxf->current_edit_unit); + edit_units = FFMIN(mxf->edit_units_per_packet, track->original_duration - mxf->current_edit_unit); if ((ret = mxf_edit_unit_absolute_offset(mxf, t, mxf->current_edit_unit, NULL, &pos, 1)) < 0) return ret; @@ -3232,6 +3379,7 @@ static int mxf_read_close(AVFormatContext *s) int i; av_freep(&mxf->packages_refs); + av_freep(&mxf->essence_container_data_refs); for (i = 0; i < s->nb_streams; i++) s->streams[i]->priv_data = NULL; @@ -3303,20 +3451,34 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti av_inv_q(source_track->edit_rate)); if (mxf->nb_index_tables <= 0) { - if (!s->bit_rate) - return AVERROR_INVALIDDATA; - if (sample_time < 0) - sample_time = 0; - seconds = av_rescale(sample_time, st->time_base.num, st->time_base.den); + if (!s->bit_rate) + return AVERROR_INVALIDDATA; + if (sample_time < 0) + sample_time = 0; + seconds = av_rescale(sample_time, st->time_base.num, st->time_base.den); - seekpos = avio_seek(s->pb, (s->bit_rate * seconds) >> 3, SEEK_SET); - if (seekpos < 0) - return seekpos; + seekpos = avio_seek(s->pb, (s->bit_rate * seconds) >> 3, SEEK_SET); + if (seekpos < 0) + return seekpos; - ff_update_cur_dts(s, st, sample_time); - mxf->current_edit_unit = sample_time; + ff_update_cur_dts(s, st, sample_time); + mxf->current_edit_unit = sample_time; } else { t = &mxf->index_tables[0]; + if (t->index_sid != source_track->index_sid) { + /* If the first index table does not belong to the stream, then find a stream which does belong to the index table */ + for (i = 0; i < s->nb_streams; i++) { + MXFTrack *new_source_track = s->streams[i]->priv_data; + if (new_source_track && new_source_track->index_sid == t->index_sid) { + sample_time = av_rescale_q(sample_time, new_source_track->edit_rate, source_track->edit_rate); + source_track = new_source_track; + st = s->streams[i]; + break; + } + } + if (i == s->nb_streams) + return AVERROR_INVALIDDATA; + } /* clamp above zero, else ff_index_search_timestamp() returns negative * this also means we allow seeking before the start */ @@ -3356,13 +3518,19 @@ static int mxf_read_seek(AVFormatContext *s, int stream_index, int64_t sample_ti for (i = 0; i < s->nb_streams; i++) { AVStream *cur_st = s->streams[i]; MXFTrack *cur_track = cur_st->priv_data; - uint64_t current_sample_count = 0; if (cur_st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { - ret = mxf_compute_sample_count(mxf, i, ¤t_sample_count); - if (ret < 0) - return ret; - - cur_track->sample_count = current_sample_count; + int64_t track_edit_unit; + if (st != cur_st && mxf_get_next_track_edit_unit(mxf, cur_track, seekpos, &track_edit_unit) >= 0) { + cur_track->sample_count = av_rescale_q(track_edit_unit, + av_inv_q(cur_track->edit_rate), + cur_st->time_base); + } else { + uint64_t current_sample_count = 0; + ret = mxf_compute_sample_count(mxf, i, ¤t_sample_count); + if (ret < 0) + return ret; + cur_track->sample_count = current_sample_count; + } } } return 0; diff --git a/libavformat/mxfenc.c b/libavformat/mxfenc.c index 035e65ed43a0b..3bb70326fe973 100644 --- a/libavformat/mxfenc.c +++ b/libavformat/mxfenc.c @@ -101,6 +101,13 @@ typedef struct MXFContainerEssenceEntry { void (*write_desc)(AVFormatContext *, AVStream *); } MXFContainerEssenceEntry; +typedef struct MXFPackage { + char *name; + enum MXFMetadataSetType type; + int instance; + struct MXFPackage *ref; +} MXFPackage; + enum ULIndex { INDEX_MPEG2 = 0, INDEX_AES3, @@ -380,6 +387,7 @@ typedef struct MXFContext { uint32_t tagged_value_count; AVRational audio_edit_rate; int store_user_comments; + int track_instance_count; // used to generate MXFTrack uuids } MXFContext; static const uint8_t uuid_base[] = { 0xAD,0xAB,0x44,0x24,0x2f,0x25,0x4d,0xc7,0x92,0xff,0x29,0xbd }; @@ -808,13 +816,14 @@ static void mxf_write_identification(AVFormatContext *s) avio_wb64(pb, mxf->timestamp); } -static void mxf_write_content_storage(AVFormatContext *s) +static void mxf_write_content_storage(AVFormatContext *s, MXFPackage *packages, int package_count) { AVIOContext *pb = s->pb; + int i; mxf_write_metadata_key(pb, 0x011800); PRINT_KEY(s, "content storage key", pb->buf_ptr - 16); - klv_encode_ber_length(pb, 92); + klv_encode_ber_length(pb, 60 + (16 * package_count)); // write uid mxf_write_local_tag(pb, 16, 0x3C0A); @@ -822,10 +831,11 @@ static void mxf_write_content_storage(AVFormatContext *s) PRINT_KEY(s, "content storage uid", pb->buf_ptr - 16); // write package reference - mxf_write_local_tag(pb, 16 * 2 + 8, 0x1901); - mxf_write_refs_count(pb, 2); - mxf_write_uuid(pb, MaterialPackage, 0); - mxf_write_uuid(pb, SourcePackage, 0); + mxf_write_local_tag(pb, 16 * package_count + 8, 0x1901); + mxf_write_refs_count(pb, package_count); + for (i = 0; i < package_count; i++) { + mxf_write_uuid(pb, packages[i].type, packages[i].instance); + } // write essence container data mxf_write_local_tag(pb, 8 + 16, 0x1902); @@ -833,7 +843,7 @@ static void mxf_write_content_storage(AVFormatContext *s) mxf_write_uuid(pb, EssenceContainerData, 0); } -static void mxf_write_track(AVFormatContext *s, AVStream *st, enum MXFMetadataSetType type) +static void mxf_write_track(AVFormatContext *s, AVStream *st, MXFPackage *package) { MXFContext *mxf = s->priv_data; AVIOContext *pb = s->pb; @@ -845,7 +855,7 @@ static void mxf_write_track(AVFormatContext *s, AVStream *st, enum MXFMetadataSe // write track uid mxf_write_local_tag(pb, 16, 0x3C0A); - mxf_write_uuid(pb, type == MaterialPackage ? Track : Track + TypeBottom, st->index); + mxf_write_uuid(pb, Track, mxf->track_instance_count); PRINT_KEY(s, "track uid", pb->buf_ptr - 16); // write track id @@ -854,7 +864,7 @@ static void mxf_write_track(AVFormatContext *s, AVStream *st, enum MXFMetadataSe // write track number mxf_write_local_tag(pb, 4, 0x4804); - if (type == MaterialPackage) + if (package->type == MaterialPackage) avio_wb32(pb, 0); // track number of material package is 0 else avio_write(pb, sc->track_essence_element_key + 12, 4); @@ -876,7 +886,7 @@ static void mxf_write_track(AVFormatContext *s, AVStream *st, enum MXFMetadataSe // write sequence refs mxf_write_local_tag(pb, 16, 0x4803); - mxf_write_uuid(pb, type == MaterialPackage ? Sequence: Sequence + TypeBottom, st->index); + mxf_write_uuid(pb, Sequence, mxf->track_instance_count); } static const uint8_t smpte_12m_timecode_track_data_ul[] = { 0x06,0x0E,0x2B,0x34,0x04,0x01,0x01,0x01,0x01,0x03,0x02,0x01,0x01,0x00,0x00,0x00 }; @@ -905,7 +915,7 @@ static void mxf_write_common_fields(AVFormatContext *s, AVStream *st) } } -static void mxf_write_sequence(AVFormatContext *s, AVStream *st, enum MXFMetadataSetType type) +static void mxf_write_sequence(AVFormatContext *s, AVStream *st, MXFPackage *package) { MXFContext *mxf = s->priv_data; AVIOContext *pb = s->pb; @@ -916,7 +926,7 @@ static void mxf_write_sequence(AVFormatContext *s, AVStream *st, enum MXFMetadat klv_encode_ber_length(pb, 80); mxf_write_local_tag(pb, 16, 0x3C0A); - mxf_write_uuid(pb, type == MaterialPackage ? Sequence: Sequence + TypeBottom, st->index); + mxf_write_uuid(pb, Sequence, mxf->track_instance_count); PRINT_KEY(s, "sequence uid", pb->buf_ptr - 16); mxf_write_common_fields(s, st); @@ -928,12 +938,11 @@ static void mxf_write_sequence(AVFormatContext *s, AVStream *st, enum MXFMetadat component = TimecodeComponent; else component = SourceClip; - if (type == SourcePackage) - component += TypeBottom; - mxf_write_uuid(pb, component, st->index); + + mxf_write_uuid(pb, component, mxf->track_instance_count); } -static void mxf_write_timecode_component(AVFormatContext *s, AVStream *st, enum MXFMetadataSetType type) +static void mxf_write_timecode_component(AVFormatContext *s, AVStream *st, MXFPackage *package) { MXFContext *mxf = s->priv_data; AVIOContext *pb = s->pb; @@ -943,8 +952,7 @@ static void mxf_write_timecode_component(AVFormatContext *s, AVStream *st, enum // UID mxf_write_local_tag(pb, 16, 0x3C0A); - mxf_write_uuid(pb, type == MaterialPackage ? TimecodeComponent : - TimecodeComponent + TypeBottom, st->index); + mxf_write_uuid(pb, TimecodeComponent, mxf->track_instance_count); mxf_write_common_fields(s, st); @@ -961,8 +969,9 @@ static void mxf_write_timecode_component(AVFormatContext *s, AVStream *st, enum avio_w8(pb, !!(mxf->tc.flags & AV_TIMECODE_FLAG_DROPFRAME)); } -static void mxf_write_structural_component(AVFormatContext *s, AVStream *st, enum MXFMetadataSetType type) +static void mxf_write_structural_component(AVFormatContext *s, AVStream *st, MXFPackage *package) { + MXFContext *mxf = s->priv_data; AVIOContext *pb = s->pb; int i; @@ -972,7 +981,7 @@ static void mxf_write_structural_component(AVFormatContext *s, AVStream *st, enu // write uid mxf_write_local_tag(pb, 16, 0x3C0A); - mxf_write_uuid(pb, type == MaterialPackage ? SourceClip: SourceClip + TypeBottom, st->index); + mxf_write_uuid(pb, SourceClip, mxf->track_instance_count); PRINT_KEY(s, "structural component uid", pb->buf_ptr - 16); mxf_write_common_fields(s, st); @@ -983,20 +992,33 @@ static void mxf_write_structural_component(AVFormatContext *s, AVStream *st, enu // write source package uid, end of the reference mxf_write_local_tag(pb, 32, 0x1101); - if (type == SourcePackage) { + if (!package->ref) { for (i = 0; i < 4; i++) avio_wb64(pb, 0); } else - mxf_write_umid(s, 1); + mxf_write_umid(s, package->ref->instance); // write source track id mxf_write_local_tag(pb, 4, 0x1102); - if (type == SourcePackage) + if (package->type == SourcePackage && !package->ref) avio_wb32(pb, 0); else avio_wb32(pb, st->index+2); } +static void mxf_write_tape_descriptor(AVFormatContext *s) +{ + AVIOContext *pb = s->pb; + + mxf_write_metadata_key(pb, 0x012e00); + PRINT_KEY(s, "tape descriptor key", pb->buf_ptr - 16); + klv_encode_ber_length(pb, 20); + mxf_write_local_tag(pb, 16, 0x3C0A); + mxf_write_uuid(pb, TapeDescriptor, 0); + PRINT_KEY(s, "tape_desc uid", pb->buf_ptr - 16); +} + + static void mxf_write_multi_descriptor(AVFormatContext *s) { MXFContext *mxf = s->priv_data; @@ -1321,15 +1343,15 @@ static int mxf_write_user_comments(AVFormatContext *s, const AVDictionary *m) return count; } -static void mxf_write_package(AVFormatContext *s, enum MXFMetadataSetType type, const char *package_name) +static void mxf_write_package(AVFormatContext *s, MXFPackage *package) { MXFContext *mxf = s->priv_data; AVIOContext *pb = s->pb; int i, track_count = s->nb_streams+1; - int name_size = mxf_utf16_local_tag_length(package_name); + int name_size = mxf_utf16_local_tag_length(package->name); int user_comment_count = 0; - if (type == MaterialPackage) { + if (package->type == MaterialPackage) { if (mxf->store_user_comments) user_comment_count = mxf_write_user_comments(s, s->metadata); mxf_write_metadata_key(pb, 0x013600); @@ -1343,18 +1365,18 @@ static void mxf_write_package(AVFormatContext *s, enum MXFMetadataSetType type, // write uid mxf_write_local_tag(pb, 16, 0x3C0A); - mxf_write_uuid(pb, type, 0); - av_log(s, AV_LOG_DEBUG, "package type:%d\n", type); + mxf_write_uuid(pb, package->type, package->instance); + av_log(s, AV_LOG_DEBUG, "package type:%d\n", package->type); PRINT_KEY(s, "package uid", pb->buf_ptr - 16); // write package umid mxf_write_local_tag(pb, 32, 0x4401); - mxf_write_umid(s, type == SourcePackage); + mxf_write_umid(s, package->instance); PRINT_KEY(s, "package umid second part", pb->buf_ptr - 16); // package name if (name_size) - mxf_write_local_tag_utf16(pb, 0x4402, package_name); + mxf_write_local_tag_utf16(pb, 0x4402, package->name); // package creation date mxf_write_local_tag(pb, 8, 0x4405); @@ -1367,10 +1389,9 @@ static void mxf_write_package(AVFormatContext *s, enum MXFMetadataSetType type, // write track refs mxf_write_local_tag(pb, track_count*16 + 8, 0x4403); mxf_write_refs_count(pb, track_count); - mxf_write_uuid(pb, type == MaterialPackage ? Track : - Track + TypeBottom, -1); // timecode track - for (i = 0; i < s->nb_streams; i++) - mxf_write_uuid(pb, type == MaterialPackage ? Track : Track + TypeBottom, i); + // these are the uuids of the tracks the will be written in mxf_write_track + for (i = 0; i < track_count; i++) + mxf_write_uuid(pb, Track, mxf->track_instance_count + i); // write user comment refs if (mxf->store_user_comments) { @@ -1381,27 +1402,41 @@ static void mxf_write_package(AVFormatContext *s, enum MXFMetadataSetType type, } // write multiple descriptor reference - if (type == SourcePackage) { + if (package->type == SourcePackage && package->instance == 1) { mxf_write_local_tag(pb, 16, 0x4701); if (s->nb_streams > 1) { mxf_write_uuid(pb, MultipleDescriptor, 0); mxf_write_multi_descriptor(s); } else mxf_write_uuid(pb, SubDescriptor, 0); + } else if (package->type == SourcePackage && package->instance == 2) { + mxf_write_local_tag(pb, 16, 0x4701); + mxf_write_uuid(pb, TapeDescriptor, 0); + mxf_write_tape_descriptor(s); } + /* + * for every 1 track in a package there is 1 sequence and 1 component. + * all 3 of these elements share the same instance number for generating + * there instance uuids. mxf->track_instance_count stores this value. + * mxf->track_instance_count is incremented after a group of all 3 of + * these elements are written. + */ + // write timecode track - mxf_write_track(s, mxf->timecode_track, type); - mxf_write_sequence(s, mxf->timecode_track, type); - mxf_write_timecode_component(s, mxf->timecode_track, type); + mxf_write_track(s, mxf->timecode_track, package); + mxf_write_sequence(s, mxf->timecode_track, package); + mxf_write_timecode_component(s, mxf->timecode_track, package); + mxf->track_instance_count++; for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; - mxf_write_track(s, st, type); - mxf_write_sequence(s, st, type); - mxf_write_structural_component(s, st, type); + mxf_write_track(s, st, package); + mxf_write_sequence(s, st, package); + mxf_write_structural_component(s, st, package); + mxf->track_instance_count++; - if (type == SourcePackage) { + if (package->type == SourcePackage && package->instance == 1) { MXFStreamContext *sc = st->priv_data; mxf_essence_container_uls[sc->index].write_desc(s, st); } @@ -1432,33 +1467,49 @@ static int mxf_write_essence_container_data(AVFormatContext *s) static int mxf_write_header_metadata_sets(AVFormatContext *s) { - const char *material_package_name = NULL; - const char *file_package_name = NULL; + MXFContext *mxf = s->priv_data; AVDictionaryEntry *entry = NULL; AVStream *st = NULL; int i; + MXFPackage packages[3] = {{0}}; + int package_count = 2; + packages[0].type = MaterialPackage; + packages[1].type = SourcePackage; + packages[1].instance = 1; + packages[0].ref = &packages[1]; + if (entry = av_dict_get(s->metadata, "material_package_name", NULL, 0)) - material_package_name = entry->value; + packages[0].name = entry->value; if (entry = av_dict_get(s->metadata, "file_package_name", NULL, 0)) { - file_package_name = entry->value; + packages[1].name = entry->value; } else { /* check if any of the streams contain a file_package_name */ for (i = 0; i < s->nb_streams; i++) { st = s->streams[i]; if (entry = av_dict_get(st->metadata, "file_package_name", NULL, 0)) { - file_package_name = entry->value; + packages[1].name = entry->value; break; } } } + entry = av_dict_get(s->metadata, "reel_name", NULL, 0); + if (entry) { + packages[2].name = entry->value; + packages[2].type = SourcePackage; + packages[2].instance = 2; + packages[1].ref = &packages[2]; + package_count = 3; + } + mxf_write_preface(s); mxf_write_identification(s); - mxf_write_content_storage(s); - mxf_write_package(s, MaterialPackage, material_package_name); - mxf_write_package(s, SourcePackage, file_package_name); + mxf_write_content_storage(s, packages, package_count); + mxf->track_instance_count = 0; + for (i = 0; i < package_count; i++) + mxf_write_package(s, &packages[i]); mxf_write_essence_container_data(s); return 0; } diff --git a/libavformat/mxg.c b/libavformat/mxg.c index 6fbf99cfa31ed..fe5879ecf04f6 100644 --- a/libavformat/mxg.c +++ b/libavformat/mxg.c @@ -169,11 +169,14 @@ static int mxg_read_packet(AVFormatContext *s, AVPacket *pkt) continue; } + size = mxg->buffer_ptr - mxg->soi_ptr; + ret = av_new_packet(pkt, size); + if (ret < 0) + return ret; + memcpy(pkt->data, mxg->soi_ptr, size); + pkt->pts = pkt->dts = mxg->dts; pkt->stream_index = 0; - pkt->buf = NULL; - pkt->size = mxg->buffer_ptr - mxg->soi_ptr; - pkt->data = mxg->soi_ptr; if (mxg->soi_ptr - mxg->buffer > mxg->cache_size) { if (mxg->cache_size > 0) { @@ -206,12 +209,14 @@ static int mxg_read_packet(AVFormatContext *s, AVPacket *pkt) mxg->buffer_ptr += size; if (marker == APP13 && size >= 16) { /* audio data */ + ret = av_new_packet(pkt, size - 14); + if (ret < 0) + return ret; + memcpy(pkt->data, startmarker_ptr + 16, size - 14); + /* time (GMT) of first sample in usec since 1970, little-endian */ pkt->pts = pkt->dts = AV_RL64(startmarker_ptr + 8); pkt->stream_index = 1; - pkt->buf = NULL; - pkt->size = size - 14; - pkt->data = startmarker_ptr + 16; if (startmarker_ptr - mxg->buffer > mxg->cache_size) { if (mxg->cache_size > 0) { diff --git a/libavformat/network.c b/libavformat/network.c index b3987a4d116cf..f44b1245b3289 100644 --- a/libavformat/network.c +++ b/libavformat/network.c @@ -29,41 +29,36 @@ int ff_tls_init(void) { -#if CONFIG_TLS_OPENSSL_PROTOCOL +#if CONFIG_TLS_PROTOCOL +#if CONFIG_OPENSSL int ret; if ((ret = ff_openssl_init()) < 0) return ret; #endif -#if CONFIG_TLS_GNUTLS_PROTOCOL +#if CONFIG_GNUTLS ff_gnutls_init(); +#endif #endif return 0; } void ff_tls_deinit(void) { -#if CONFIG_TLS_OPENSSL_PROTOCOL +#if CONFIG_TLS_PROTOCOL +#if CONFIG_OPENSSL ff_openssl_deinit(); #endif -#if CONFIG_TLS_GNUTLS_PROTOCOL +#if CONFIG_GNUTLS ff_gnutls_deinit(); #endif +#endif } -int ff_network_inited_globally; - int ff_network_init(void) { #if HAVE_WINSOCK2_H WSADATA wsaData; -#endif - if (!ff_network_inited_globally) - av_log(NULL, AV_LOG_WARNING, "Using network protocols without global " - "network initialization. Please use " - "avformat_network_init(), this will " - "become mandatory later.\n"); -#if HAVE_WINSOCK2_H if (WSAStartup(MAKEWORD(1,1), &wsaData)) return 0; #endif @@ -99,6 +94,24 @@ int ff_network_wait_fd_timeout(int fd, int write, int64_t timeout, AVIOInterrupt } } +int ff_network_sleep_interruptible(int64_t timeout, AVIOInterruptCB *int_cb) +{ + int64_t wait_start = av_gettime_relative(); + + while (1) { + int64_t time_left; + + if (ff_check_interrupt(int_cb)) + return AVERROR_EXIT; + + time_left = timeout - (av_gettime_relative() - wait_start); + if (time_left <= 0) + return AVERROR(ETIMEDOUT); + + av_usleep(FFMIN(time_left, POLLING_TIME * 1000)); + } +} + void ff_network_close(void) { #if HAVE_WINSOCK2_H @@ -280,6 +293,52 @@ int ff_listen_connect(int fd, const struct sockaddr *addr, return ret; } +int ff_sendto(int fd, const char *msg, int msg_len, int flag, + const struct sockaddr *addr, + socklen_t addrlen, int timeout, URLContext *h, + int will_try_next) +{ + struct pollfd p = {fd, POLLOUT, 0}; + int ret; + socklen_t optlen; + + if (ff_socket_nonblock(fd, 1) < 0) + av_log(NULL, AV_LOG_INFO, "ff_socket_nonblock failed\n"); + + while ((ret = sendto(fd, msg, msg_len, flag, addr, addrlen)) < 0) { + ret = ff_neterrno(); + switch (ret) { + case AVERROR(EINTR): + if (ff_check_interrupt(&h->interrupt_callback)) + return AVERROR_EXIT; + continue; + case AVERROR(EINPROGRESS): + case AVERROR(EAGAIN): + ret = ff_poll_interrupt(&p, 1, timeout, &h->interrupt_callback); + if (ret < 0) + return ret; + optlen = sizeof(ret); + if (getsockopt (fd, SOL_SOCKET, SO_ERROR, &ret, &optlen)) + ret = AVUNERROR(ff_neterrno()); + if (ret != 0) { + char errbuf[100]; + ret = AVERROR(ret); + av_strerror(ret, errbuf, sizeof(errbuf)); + if (will_try_next) + av_log(h, AV_LOG_WARNING, + "Connection to %s failed (%s), trying next address\n", + h->filename, errbuf); + else + av_log(h, AV_LOG_ERROR, "Connection to %s failed: %s\n", + h->filename, errbuf); + } + default: + return ret; + } + } + return ret; +} + static int match_host_pattern(const char *pattern, const char *hostname) { int len_p, len_h; diff --git a/libavformat/network.h b/libavformat/network.h index f83c796a95a55..a9abd0eed0235 100644 --- a/libavformat/network.h +++ b/libavformat/network.h @@ -59,6 +59,7 @@ int ff_neterrno(void); #include #include #include +#include #include #define ff_neterrno() AVERROR(errno) @@ -74,7 +75,6 @@ int ff_neterrno(void); int ff_socket_nonblock(int socket, int enable); -extern int ff_network_inited_globally; int ff_network_init(void); void ff_network_close(void); @@ -95,7 +95,14 @@ int ff_network_wait_fd(int fd, int write); */ int ff_network_wait_fd_timeout(int fd, int write, int64_t timeout, AVIOInterruptCB *int_cb); -int ff_inet_aton (const char * str, struct in_addr * add); +/** + * Waits for up to 'timeout' microseconds. If the usert's int_cb is set and + * triggered, return before that. + * @timeout Timeout in microseconds. Maybe have lower actual precision. + * @param int_cb Interrupt callback, is checked regularly. + * @return AVERROR(ETIMEDOUT) if timeout expirted, AVERROR_EXIT if interrupted by int_cb + */ +int ff_network_sleep_interruptible(int64_t timeout, AVIOInterruptCB *int_cb); #if !HAVE_STRUCT_SOCKADDR_STORAGE struct sockaddr_storage { @@ -293,6 +300,11 @@ int ff_listen_connect(int fd, const struct sockaddr *addr, socklen_t addrlen, int timeout, URLContext *h, int will_try_next); +int ff_sendto(int fd, const char *msg, int msg_len, int flag, + const struct sockaddr *addr, + socklen_t addrlen, int timeout, URLContext *h, + int will_try_next); + int ff_http_match_no_proxy(const char *no_proxy, const char *hostname); int ff_socket(int domain, int type, int protocol); diff --git a/libavformat/nspdec.c b/libavformat/nspdec.c new file mode 100644 index 0000000000000..34c747b65ea8a --- /dev/null +++ b/libavformat/nspdec.c @@ -0,0 +1,108 @@ +/* + * NSP demuxer + * Copyright (c) 2017 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avstring.h" +#include "libavutil/intreadwrite.h" +#include "avformat.h" +#include "internal.h" +#include "pcm.h" + +static int nsp_probe(AVProbeData *p) +{ + if (AV_RB32(p->buf) == AV_RB32("FORM") && + AV_RB32(p->buf + 4) == AV_RB32("DS16")) + return AVPROBE_SCORE_MAX; + return 0; +} + +static int nsp_read_header(AVFormatContext *s) +{ + int channels = 0, rate = 0; + uint32_t chunk, size; + AVStream *st; + int64_t pos; + + avio_skip(s->pb, 12); + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + while (!avio_feof(s->pb)) { + char value[1024]; + + chunk = avio_rb32(s->pb); + size = avio_rl32(s->pb); + pos = avio_tell(s->pb); + + switch (chunk) { + case MKBETAG('H', 'E', 'D', 'R'): + case MKBETAG('H', 'D', 'R', '8'): + if (size < 32) + return AVERROR_INVALIDDATA; + avio_skip(s->pb, 20); + rate = avio_rl32(s->pb); + avio_skip(s->pb, size - (avio_tell(s->pb) - pos)); + break; + case MKBETAG('N', 'O', 'T', 'E'): + avio_get_str(s->pb, size, value, sizeof(value)); + av_dict_set(&s->metadata, "Comment", value, 0); + avio_skip(s->pb, size & 1); + break; + case MKBETAG('S', 'D', 'A', 'B'): + channels = 2; + break; + case MKBETAG('S', 'D', '_', '2'): + case MKBETAG('S', 'D', '_', '3'): + case MKBETAG('S', 'D', '_', '4'): + case MKBETAG('S', 'D', '_', '5'): + case MKBETAG('S', 'D', '_', '6'): + case MKBETAG('S', 'D', '_', '7'): + case MKBETAG('S', 'D', '_', '8'): + av_log(s, AV_LOG_WARNING, "Unsupported chunk!\n"); + case MKBETAG('S', 'D', 'A', '_'): + case MKBETAG('S', 'D', '_', 'A'): + channels = 1; + break; + } + + if (channels) + break; + } + + st->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + st->codecpar->channels = channels; + st->codecpar->sample_rate = rate; + st->codecpar->codec_id = AV_CODEC_ID_PCM_S16LE; + st->codecpar->block_align = 2 * channels; + + return 0; +} + +AVInputFormat ff_nsp_demuxer = { + .name = "nsp", + .long_name = NULL_IF_CONFIG_SMALL("Computerized Speech Lab NSP"), + .read_probe = nsp_probe, + .read_header = nsp_read_header, + .read_packet = ff_pcm_read_packet, + .read_seek = ff_pcm_read_seek, + .extensions = "nsp", + .flags = AVFMT_GENERIC_INDEX, +}; diff --git a/libavformat/oggdec.c b/libavformat/oggdec.c index 97ad1a27d15ce..27d16a3e4e5c0 100644 --- a/libavformat/oggdec.c +++ b/libavformat/oggdec.c @@ -128,7 +128,10 @@ static int ogg_restore(AVFormatContext *s) ogg->state = ost->next; for (i = 0; i < ogg->nstreams; i++) { - av_freep(&ogg->streams[i].buf); + struct ogg_stream *stream = &ogg->streams[i]; + av_freep(&stream->buf); + av_freep(&stream->new_metadata); + if (i >= ost->nstreams || !ost->streams[i].private) { free_stream(s, i); } @@ -543,7 +546,11 @@ static int ogg_packet(AVFormatContext *s, int *sid, int *dstart, int *dsize, os->incomplete = 0; if (os->header) { - os->header = os->codec->header(s, idx); + if ((ret = os->codec->header(s, idx)) < 0) { + av_log(s, AV_LOG_ERROR, "Header processing failed: %s\n", av_err2str(ret)); + return ret; + } + os->header = ret; if (!os->header) { os->segp = segp; os->psize = psize; @@ -574,8 +581,12 @@ static int ogg_packet(AVFormatContext *s, int *sid, int *dstart, int *dsize, } else { os->pflags = 0; os->pduration = 0; - if (os->codec && os->codec->packet) - os->codec->packet(s, idx); + if (os->codec && os->codec->packet) { + if ((ret = os->codec->packet(s, idx)) < 0) { + av_log(s, AV_LOG_ERROR, "Packet processing failed: %s\n", av_err2str(ret)); + return ret; + } + } if (sid) *sid = idx; if (dstart) @@ -719,8 +730,10 @@ static int ogg_read_header(AVFormatContext *s) "Headers mismatch for stream %d: " "expected %d received %d.\n", i, os->codec->nb_header, os->nb_header); - if (s->error_recognition & AV_EF_EXPLODE) + if (s->error_recognition & AV_EF_EXPLODE) { + ogg_read_close(s); return AVERROR_INVALIDDATA; + } } if (os->start_granule != OGG_NOGRANULE_VALUE) os->lastpts = s->streams[i]->start_time = diff --git a/libavformat/oggparsedaala.c b/libavformat/oggparsedaala.c index a373b41b4cac4..e944470aca38c 100644 --- a/libavformat/oggparsedaala.c +++ b/libavformat/oggparsedaala.c @@ -218,6 +218,7 @@ static int daala_packet(AVFormatContext *s, int idx) int seg, duration = 1; struct ogg *ogg = s->priv_data; struct ogg_stream *os = ogg->streams + idx; + int64_t pts; /* * first packet handling: here we parse the duration of each packet in the @@ -230,7 +231,10 @@ static int daala_packet(AVFormatContext *s, int idx) if (os->segments[seg] < 255) duration++; - os->lastpts = os->lastdts = daala_gptopts(s, idx, os->granule, NULL) - duration; + pts = daala_gptopts(s, idx, os->granule, NULL); + if (pts != AV_NOPTS_VALUE) + pts -= duration; + os->lastpts = os->lastdts = pts; if(s->streams[idx]->start_time == AV_NOPTS_VALUE) { s->streams[idx]->start_time = os->lastpts; if (s->streams[idx]->duration != AV_NOPTS_VALUE) diff --git a/libavformat/oggparseogm.c b/libavformat/oggparseogm.c index e7a501b5a71e2..a07453760b710 100644 --- a/libavformat/oggparseogm.c +++ b/libavformat/oggparseogm.c @@ -24,7 +24,6 @@ #include -#include "libavutil/avassert.h" #include "libavutil/intreadwrite.h" #include "libavcodec/bytestream.h" @@ -106,10 +105,10 @@ ogm_header(AVFormatContext *s, int idx) size -= 4; } if (size > 52) { - av_assert0(AV_INPUT_BUFFER_PADDING_SIZE <= 52); size -= 52; if (bytestream2_get_bytes_left(&p) < size) return AVERROR_INVALIDDATA; + av_freep(&st->codecpar->extradata); if (ff_alloc_extradata(st->codecpar, size) < 0) return AVERROR(ENOMEM); bytestream2_get_buffer(&p, st->codecpar->extradata, st->codecpar->extradata_size); @@ -177,11 +176,14 @@ ogm_packet(AVFormatContext *s, int idx) os->pflags |= AV_PKT_FLAG_KEY; lb = ((*p & 2) << 1) | ((*p >> 6) & 3); + if (os->psize < lb + 1) + return AVERROR_INVALIDDATA; + os->pstart += lb + 1; os->psize -= lb + 1; while (lb--) - os->pduration += p[lb+1] << (lb*8); + os->pduration += (uint64_t)p[lb+1] << (lb*8); return 0; } diff --git a/libavformat/oggparseopus.c b/libavformat/oggparseopus.c index f45ad848744a4..cd34cf23ba62f 100644 --- a/libavformat/oggparseopus.c +++ b/libavformat/oggparseopus.c @@ -62,6 +62,7 @@ static int opus_header(AVFormatContext *avf, int idx) /*gain = AV_RL16(packet + 16);*/ /*channel_map = AV_RL8 (packet + 18);*/ + av_freep(&st->codecpar->extradata); if (ff_alloc_extradata(st->codecpar, os->psize)) return AVERROR(ENOMEM); diff --git a/libavformat/oggparsetheora.c b/libavformat/oggparsetheora.c index b14f9f0669c1a..b0c0edc7a545f 100644 --- a/libavformat/oggparsetheora.c +++ b/libavformat/oggparsetheora.c @@ -181,6 +181,7 @@ static int theora_packet(AVFormatContext *s, int idx) if ((!os->lastpts || os->lastpts == AV_NOPTS_VALUE) && !(os->flags & OGG_FLAG_EOS)) { int seg; + int64_t pts; duration = 1; for (seg = os->segp; seg < os->nsegs; seg++) { @@ -188,7 +189,10 @@ static int theora_packet(AVFormatContext *s, int idx) duration ++; } - os->lastpts = os->lastdts = theora_gptopts(s, idx, os->granule, NULL) - duration; + pts = theora_gptopts(s, idx, os->granule, NULL); + if (pts != AV_NOPTS_VALUE) + pts -= duration; + os->lastpts = os->lastdts = pts; if(s->streams[idx]->start_time == AV_NOPTS_VALUE) { s->streams[idx]->start_time = os->lastpts; if (s->streams[idx]->duration > 0) diff --git a/libavformat/oggparsevorbis.c b/libavformat/oggparsevorbis.c index 65b1998a02d92..bcfd246b8dcf3 100644 --- a/libavformat/oggparsevorbis.c +++ b/libavformat/oggparsevorbis.c @@ -230,6 +230,10 @@ static int fixup_vorbis_headers(AVFormatContext *as, len = priv->len[0] + priv->len[1] + priv->len[2]; buf_len = len + len / 255 + 64; + + if (*buf) + return AVERROR_INVALIDDATA; + ptr = *buf = av_realloc(NULL, buf_len); if (!ptr) return AVERROR(ENOMEM); @@ -317,7 +321,7 @@ static int vorbis_header(AVFormatContext *s, int idx) if (priv->packet[pkt_type >> 1]) return AVERROR_INVALIDDATA; if (pkt_type > 1 && !priv->packet[0] || pkt_type > 3 && !priv->packet[1]) - return AVERROR_INVALIDDATA; + return priv->vp ? 0 : AVERROR_INVALIDDATA; priv->len[pkt_type >> 1] = os->psize; priv->packet[pkt_type >> 1] = av_mallocz(os->psize); diff --git a/libavformat/oggparsevp8.c b/libavformat/oggparsevp8.c index c534ab117d94e..b76ac71cc5075 100644 --- a/libavformat/oggparsevp8.c +++ b/libavformat/oggparsevp8.c @@ -125,7 +125,7 @@ static int vp8_packet(AVFormatContext *s, int idx) os->lastdts = vp8_gptopts(s, idx, os->granule, NULL) - duration; if(s->streams[idx]->start_time == AV_NOPTS_VALUE) { s->streams[idx]->start_time = os->lastpts; - if (s->streams[idx]->duration) + if (s->streams[idx]->duration && s->streams[idx]->duration != AV_NOPTS_VALUE) s->streams[idx]->duration -= s->streams[idx]->start_time; } } diff --git a/libavformat/options.c b/libavformat/options.c index 9371c72667479..c188c23506a20 100644 --- a/libavformat/options.c +++ b/libavformat/options.c @@ -104,7 +104,7 @@ static int io_open_default(AVFormatContext *s, AVIOContext **pb, { int loglevel; - if (!strcmp(url, s->filename) || + if (!strcmp(url, s->url) || s->iformat && !strcmp(s->iformat->name, "image2") || s->oformat && !strcmp(s->oformat->name, "image2") ) { diff --git a/libavformat/options_table.h b/libavformat/options_table.h index 118086df665eb..7c4d84798e1af 100644 --- a/libavformat/options_table.h +++ b/libavformat/options_table.h @@ -49,15 +49,15 @@ static const AVOption avformat_options[] = { {"discardcorrupt", "discard corrupted frames", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_DISCARD_CORRUPT }, INT_MIN, INT_MAX, D, "fflags"}, {"sortdts", "try to interleave outputted packets by dts", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_SORT_DTS }, INT_MIN, INT_MAX, D, "fflags"}, #if FF_API_LAVF_KEEPSIDE_FLAG -{"keepside", "don't merge side data", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_KEEP_SIDE_DATA }, INT_MIN, INT_MAX, D, "fflags"}, +{"keepside", "deprecated, does nothing", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_KEEP_SIDE_DATA }, INT_MIN, INT_MAX, D, "fflags"}, #endif {"fastseek", "fast but inaccurate seeks", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_FAST_SEEK }, INT_MIN, INT_MAX, D, "fflags"}, {"latm", "enable RTP MP4A-LATM payload", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_MP4A_LATM }, INT_MIN, INT_MAX, E, "fflags"}, {"nobuffer", "reduce the latency introduced by optional buffering", 0, AV_OPT_TYPE_CONST, {.i64 = AVFMT_FLAG_NOBUFFER }, 0, INT_MAX, D, "fflags"}, -{"seek2any", "allow seeking to non-keyframes on demuxer level when supported", OFFSET(seek2any), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, D}, {"bitexact", "do not write random/volatile data", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_BITEXACT }, 0, 0, E, "fflags" }, {"shortest", "stop muxing with the shortest stream", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_SHORTEST }, 0, 0, E, "fflags" }, -{"autobsf", "add needed bsfs automatically (delays header until each stream's first packet is written)", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_AUTO_BSF }, 0, 0, E, "fflags" }, +{"autobsf", "add needed bsfs automatically", 0, AV_OPT_TYPE_CONST, { .i64 = AVFMT_FLAG_AUTO_BSF }, 0, 0, E, "fflags" }, +{"seek2any", "allow seeking to non-keyframes on demuxer level when supported", OFFSET(seek2any), AV_OPT_TYPE_BOOL, {.i64 = 0 }, 0, 1, D}, {"analyzeduration", "specify how many microseconds are analyzed to probe the input", OFFSET(max_analyze_duration), AV_OPT_TYPE_INT64, {.i64 = 0 }, 0, INT64_MAX, D}, {"cryptokey", "decryption key", OFFSET(key), AV_OPT_TYPE_BINARY, {.dbl = 0}, 0, 0, D}, {"indexmem", "max memory used for timestamp index (per stream)", OFFSET(max_index_size), AV_OPT_TYPE_INT, {.i64 = 1<<20 }, 0, INT_MAX, D}, diff --git a/libavformat/os_support.c b/libavformat/os_support.c index 86d0b8f306d23..099d7b501f439 100644 --- a/libavformat/os_support.c +++ b/libavformat/os_support.c @@ -46,7 +46,7 @@ #if !HAVE_INET_ATON #include -int ff_inet_aton(const char *str, struct in_addr *add) +static int inet_aton(const char *str, struct in_addr *add) { unsigned int add1 = 0, add2 = 0, add3 = 0, add4 = 0; @@ -60,11 +60,6 @@ int ff_inet_aton(const char *str, struct in_addr *add) return 1; } -#else -int ff_inet_aton(const char *str, struct in_addr *add) -{ - return inet_aton(str, add); -} #endif /* !HAVE_INET_ATON */ #if !HAVE_GETADDRINFO @@ -75,16 +70,6 @@ int ff_getaddrinfo(const char *node, const char *service, struct addrinfo *ai; struct sockaddr_in *sin; -#if HAVE_WINSOCK2_H - int (WSAAPI *win_getaddrinfo)(const char *node, const char *service, - const struct addrinfo *hints, - struct addrinfo **res); - HMODULE ws2mod = GetModuleHandle("ws2_32.dll"); - win_getaddrinfo = GetProcAddress(ws2mod, "getaddrinfo"); - if (win_getaddrinfo) - return win_getaddrinfo(node, service, hints, res); -#endif /* HAVE_WINSOCK2_H */ - *res = NULL; sin = av_mallocz(sizeof(struct sockaddr_in)); if (!sin) @@ -92,7 +77,7 @@ int ff_getaddrinfo(const char *node, const char *service, sin->sin_family = AF_INET; if (node) { - if (!ff_inet_aton(node, &sin->sin_addr)) { + if (!inet_aton(node, &sin->sin_addr)) { if (hints && (hints->ai_flags & AI_NUMERICHOST)) { av_free(sin); return EAI_FAIL; @@ -148,17 +133,6 @@ int ff_getaddrinfo(const char *node, const char *service, void ff_freeaddrinfo(struct addrinfo *res) { -#if HAVE_WINSOCK2_H - void (WSAAPI *win_freeaddrinfo)(struct addrinfo *res); - HMODULE ws2mod = GetModuleHandle("ws2_32.dll"); - win_freeaddrinfo = (void (WSAAPI *)(struct addrinfo *res)) - GetProcAddress(ws2mod, "freeaddrinfo"); - if (win_freeaddrinfo) { - win_freeaddrinfo(res); - return; - } -#endif /* HAVE_WINSOCK2_H */ - av_freep(&res->ai_canonname); av_freep(&res->ai_addr); av_freep(&res); @@ -170,16 +144,6 @@ int ff_getnameinfo(const struct sockaddr *sa, int salen, { const struct sockaddr_in *sin = (const struct sockaddr_in *)sa; -#if HAVE_WINSOCK2_H - int (WSAAPI *win_getnameinfo)(const struct sockaddr *sa, socklen_t salen, - char *host, DWORD hostlen, - char *serv, DWORD servlen, int flags); - HMODULE ws2mod = GetModuleHandle("ws2_32.dll"); - win_getnameinfo = GetProcAddress(ws2mod, "getnameinfo"); - if (win_getnameinfo) - return win_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); -#endif /* HAVE_WINSOCK2_H */ - if (sa->sa_family != AF_INET) return EAI_FAMILY; if (!host && !serv) diff --git a/libavformat/os_support.h b/libavformat/os_support.h index 91220e9716a41..7a56dc9a7c1e2 100644 --- a/libavformat/os_support.h +++ b/libavformat/os_support.h @@ -40,7 +40,7 @@ #endif #endif -#if defined(_WIN32) && !defined(__MINGW32CE__) +#ifdef _WIN32 # include # ifdef lseek # undef lseek @@ -54,7 +54,7 @@ # undef fstat # endif # define fstat(f,s) _fstati64((f), (s)) -#endif /* defined(_WIN32) && !defined(__MINGW32CE__) */ +#endif /* defined(_WIN32) */ #ifdef __ANDROID__ @@ -139,9 +139,7 @@ int ff_poll(struct pollfd *fds, nfds_t numfds, int timeout); #endif /* HAVE_POLL_H */ #endif /* CONFIG_NETWORK */ -#if defined(__MINGW32CE__) -#define mkdir(a, b) _mkdir(a) -#elif defined(_WIN32) +#ifdef _WIN32 #include #include #include "libavutil/wchar_filename.h" @@ -220,7 +218,7 @@ static inline int win32_rename(const char *src_utf8, const char *dest_utf8) fallback: /* filename may be be in CP_ACP */ -#if !HAVE_WINRT +#if !HAVE_UWP ret = MoveFileExA(src_utf8, dest_utf8, MOVEFILE_REPLACE_EXISTING); if (ret) errno = EPERM; diff --git a/libavformat/pcm.c b/libavformat/pcm.c index 806f91b6b135e..767bbd045a994 100644 --- a/libavformat/pcm.c +++ b/libavformat/pcm.c @@ -28,13 +28,20 @@ int ff_pcm_read_packet(AVFormatContext *s, AVPacket *pkt) { + AVCodecParameters *par = s->streams[0]->codecpar; int ret, size; - size= RAW_SAMPLES*s->streams[0]->codecpar->block_align; - if (size <= 0) + if (par->block_align <= 0) return AVERROR(EINVAL); - ret= av_get_packet(s->pb, pkt, size); + /* + * Compute read size to complete a read every 62ms. + * Clamp to RAW_SAMPLES if larger. + */ + size = FFMAX(par->sample_rate/25, 1); + size = FFMIN(size, RAW_SAMPLES) * par->block_align; + + ret = av_get_packet(s->pb, pkt, size); pkt->flags &= ~AV_PKT_FLAG_CORRUPT; pkt->stream_index = 0; diff --git a/libavformat/protocols.c b/libavformat/protocols.c index 8d3555ed5206e..6ea2b38ae98fd 100644 --- a/libavformat/protocols.c +++ b/libavformat/protocols.c @@ -39,6 +39,12 @@ extern const URLProtocol ff_http_protocol; extern const URLProtocol ff_httpproxy_protocol; extern const URLProtocol ff_https_protocol; extern const URLProtocol ff_icecast_protocol; +extern const URLProtocol ff_ijkhttphook_protocol; +extern const URLProtocol ff_ijklongurl_protocol; +extern const URLProtocol ff_ijkmediadatasource_protocol; +extern const URLProtocol ff_ijksegment_protocol; +extern const URLProtocol ff_ijktcphook_protocol; +extern const URLProtocol ff_ijkio_protocol; extern const URLProtocol ff_mmsh_protocol; extern const URLProtocol ff_mmst_protocol; extern const URLProtocol ff_md5_protocol; @@ -56,10 +62,7 @@ extern const URLProtocol ff_srtp_protocol; extern const URLProtocol ff_subfile_protocol; extern const URLProtocol ff_tee_protocol; extern const URLProtocol ff_tcp_protocol; -extern const URLProtocol ff_tls_gnutls_protocol; -extern const URLProtocol ff_tls_schannel_protocol; -extern const URLProtocol ff_tls_securetransport_protocol; -extern const URLProtocol ff_tls_openssl_protocol; +extern const URLProtocol ff_tls_protocol; extern const URLProtocol ff_udp_protocol; extern const URLProtocol ff_udplite_protocol; extern const URLProtocol ff_unix_protocol; @@ -68,6 +71,7 @@ extern const URLProtocol ff_librtmpe_protocol; extern const URLProtocol ff_librtmps_protocol; extern const URLProtocol ff_librtmpt_protocol; extern const URLProtocol ff_librtmpte_protocol; +extern const URLProtocol ff_libsrt_protocol; extern const URLProtocol ff_libssh_protocol; extern const URLProtocol ff_libsmbclient_protocol; diff --git a/libavformat/rawdec.c b/libavformat/rawdec.c index e926549a60332..b38a4b5e5d4ba 100644 --- a/libavformat/rawdec.c +++ b/libavformat/rawdec.c @@ -130,7 +130,7 @@ static int mjpeg_probe(AVProbeData *p) int nb_invalid = 0; int nb_frames = 0; - for (i=0; ibuf_size-2; i++) { + for (i = 0; i < p->buf_size - 1; i++) { int c; if (p->buf[i] != 0xFF) continue; diff --git a/libavformat/rawenc.c b/libavformat/rawenc.c index f640121cb4698..809ca23b1a5d2 100644 --- a/libavformat/rawenc.c +++ b/libavformat/rawenc.c @@ -91,6 +91,32 @@ AVOutputFormat ff_adx_muxer = { }; #endif +#if CONFIG_APTX_MUXER +AVOutputFormat ff_aptx_muxer = { + .name = "aptx", + .long_name = NULL_IF_CONFIG_SMALL("raw aptX (Audio Processing Technology for Bluetooth)"), + .extensions = "aptx", + .audio_codec = AV_CODEC_ID_APTX, + .video_codec = AV_CODEC_ID_NONE, + .write_header = force_one_stream, + .write_packet = ff_raw_write_packet, + .flags = AVFMT_NOTIMESTAMPS, +}; +#endif + +#if CONFIG_APTX_HD_MUXER +AVOutputFormat ff_aptx_hd_muxer = { + .name = "aptx_hd", + .long_name = NULL_IF_CONFIG_SMALL("raw aptX HD (Audio Processing Technology for Bluetooth)"), + .extensions = "aptxhd", + .audio_codec = AV_CODEC_ID_APTX_HD, + .video_codec = AV_CODEC_ID_NONE, + .write_header = force_one_stream, + .write_packet = ff_raw_write_packet, + .flags = AVFMT_NOTIMESTAMPS, +}; +#endif + #if CONFIG_CAVSVIDEO_MUXER AVOutputFormat ff_cavsvideo_muxer = { .name = "cavsvideo", @@ -104,6 +130,19 @@ AVOutputFormat ff_cavsvideo_muxer = { }; #endif +#if CONFIG_CODEC2RAW_MUXER +AVOutputFormat ff_codec2raw_muxer = { + .name = "codec2raw", + .long_name = NULL_IF_CONFIG_SMALL("raw codec2 muxer"), + .audio_codec = AV_CODEC_ID_CODEC2, + .video_codec = AV_CODEC_ID_NONE, + .write_header = force_one_stream, + .write_packet = ff_raw_write_packet, + .flags = AVFMT_NOTIMESTAMPS, +}; +#endif + + #if CONFIG_DATA_MUXER AVOutputFormat ff_data_muxer = { .name = "data", @@ -413,6 +452,19 @@ AVOutputFormat ff_rawvideo_muxer = { }; #endif +#if CONFIG_SBC_MUXER +AVOutputFormat ff_sbc_muxer = { + .name = "sbc", + .long_name = NULL_IF_CONFIG_SMALL("raw SBC"), + .mime_type = "audio/x-sbc", + .extensions = "sbc,msbc", + .audio_codec = AV_CODEC_ID_SBC, + .write_header = force_one_stream, + .write_packet = ff_raw_write_packet, + .flags = AVFMT_NOTIMESTAMPS, +}; +#endif + #if CONFIG_TRUEHD_MUXER AVOutputFormat ff_truehd_muxer = { .name = "truehd", diff --git a/libavformat/rdt.c b/libavformat/rdt.c index b69827fcbfcd6..60c36f09e636e 100644 --- a/libavformat/rdt.c +++ b/libavformat/rdt.c @@ -53,7 +53,7 @@ struct RDTDemuxContext { RDTDemuxContext * ff_rdt_parse_open(AVFormatContext *ic, int first_stream_of_set_idx, - void *priv_data, RTPDynamicProtocolHandler *handler) + void *priv_data, const RTPDynamicProtocolHandler *handler) { RDTDemuxContext *s = av_mallocz(sizeof(RDTDemuxContext)); if (!s) @@ -554,7 +554,7 @@ rdt_close_context (PayloadContext *rdt) } #define RDT_HANDLER(n, s, t) \ -static RTPDynamicProtocolHandler rdt_ ## n ## _handler = { \ +RTPDynamicProtocolHandler ff_rdt_ ## n ## _handler = { \ .enc_name = s, \ .codec_type = t, \ .codec_id = AV_CODEC_ID_NONE, \ @@ -570,10 +570,3 @@ RDT_HANDLER(live_audio, "x-pn-multirate-realaudio-live", AVMEDIA_TYPE_AUDIO); RDT_HANDLER(video, "x-pn-realvideo", AVMEDIA_TYPE_VIDEO); RDT_HANDLER(audio, "x-pn-realaudio", AVMEDIA_TYPE_AUDIO); -void ff_register_rdt_dynamic_payload_handlers(void) -{ - ff_register_dynamic_payload_handler(&rdt_video_handler); - ff_register_dynamic_payload_handler(&rdt_audio_handler); - ff_register_dynamic_payload_handler(&rdt_live_video_handler); - ff_register_dynamic_payload_handler(&rdt_live_audio_handler); -} diff --git a/libavformat/rdt.h b/libavformat/rdt.h index ce6026f49c251..67fb308421df8 100644 --- a/libavformat/rdt.h +++ b/libavformat/rdt.h @@ -41,7 +41,7 @@ typedef struct RDTDemuxContext RDTDemuxContext; RDTDemuxContext *ff_rdt_parse_open(AVFormatContext *ic, int first_stream_of_set_idx, void *priv_data, - RTPDynamicProtocolHandler *handler); + const RTPDynamicProtocolHandler *handler); void ff_rdt_parse_close(RDTDemuxContext *s); /** @@ -59,11 +59,6 @@ void ff_rdt_parse_close(RDTDemuxContext *s); void ff_rdt_calc_response_and_checksum(char response[41], char chksum[9], const char *challenge); -/** - * Register RDT-related dynamic payload handlers with our cache. - */ -void ff_register_rdt_dynamic_payload_handlers(void); - /** * Add subscription information to Subscribe parameter string. * diff --git a/libavformat/riff.c b/libavformat/riff.c index 3f0b390774fc7..89117250d4ef4 100644 --- a/libavformat/riff.c +++ b/libavformat/riff.c @@ -404,6 +404,12 @@ const AVCodecTag ff_codec_bmp_tags[] = { { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'Q', 'Y', '2') }, { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'Q', 'R', 'A') }, { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'Q', 'R', 'G') }, + { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'M', 'Y', '2') }, + { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'M', 'H', '2') }, + { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'M', 'Y', '4') }, + { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'M', 'H', '4') }, + { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'M', 'R', 'A') }, + { AV_CODEC_ID_UTVIDEO, MKTAG('U', 'M', 'R', 'G') }, { AV_CODEC_ID_VBLE, MKTAG('V', 'B', 'L', 'E') }, { AV_CODEC_ID_ESCAPE130, MKTAG('E', '1', '3', '0') }, { AV_CODEC_ID_DXTORY, MKTAG('x', 't', 'o', 'r') }, diff --git a/libavformat/rmdec.c b/libavformat/rmdec.c index d6d7d9cd8414d..ac61723c66acc 100644 --- a/libavformat/rmdec.c +++ b/libavformat/rmdec.c @@ -70,16 +70,10 @@ static int rm_read_close(AVFormatContext *s); static inline void get_strl(AVIOContext *pb, char *buf, int buf_size, int len) { - int i; - char *q, r; + int read = avio_get_str(pb, len, buf, buf_size); - q = buf; - for(i=0;i 0) *q = '\0'; + if (read > 0) + avio_skip(pb, len - read); } static void get_str8(AVIOContext *pb, char *buf, int buf_size) @@ -105,8 +99,10 @@ static void rm_read_metadata(AVFormatContext *s, AVIOContext *pb, int wide) for (i=0; imetadata, ff_rm_metadata[i], buf, 0); + if (len > 0) { + get_strl(pb, buf, sizeof(buf), len); + av_dict_set(&s->metadata, ff_rm_metadata[i], buf, 0); + } } } @@ -950,12 +946,14 @@ ff_rm_parse_packet (AVFormatContext *s, AVIOContext *pb, } else return -1; } else { - if ((ret = av_get_packet(pb, pkt, len)) < 0) + ret = av_get_packet(pb, pkt, len); + if (ret < 0) return ret; rm_ac3_swap_bytes(st, pkt); } } else { - if ((ret = av_get_packet(pb, pkt, len)) < 0) + ret = av_get_packet(pb, pkt, len); + if (ret < 0) return ret; } @@ -973,16 +971,17 @@ ff_rm_retrieve_cache (AVFormatContext *s, AVIOContext *pb, AVStream *st, RMStream *ast, AVPacket *pkt) { RMDemuxContext *rm = s->priv_data; + int ret; av_assert0 (rm->audio_pkt_cnt > 0); if (ast->deint_id == DEINT_ID_VBRF || ast->deint_id == DEINT_ID_VBRS) { - int ret = av_get_packet(pb, pkt, ast->sub_packet_lengths[ast->sub_packet_cnt - rm->audio_pkt_cnt]); + ret = av_get_packet(pb, pkt, ast->sub_packet_lengths[ast->sub_packet_cnt - rm->audio_pkt_cnt]); if (ret < 0) return ret; } else { - int ret = av_new_packet(pkt, st->codecpar->block_align); + ret = av_new_packet(pkt, st->codecpar->block_align); if (ret < 0) return ret; memcpy(pkt->data, ast->pkt.data + st->codecpar->block_align * //FIXME avoid this diff --git a/libavformat/rtmpdigest.c b/libavformat/rtmpdigest.c new file mode 100644 index 0000000000000..a9b1177ed1344 --- /dev/null +++ b/libavformat/rtmpdigest.c @@ -0,0 +1,67 @@ +/* + * RTMP network protocol + * Copyright (c) 2009 Konstantin Shishkov + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * RTMP protocol digest + */ + +#include + +#include "libavutil/error.h" +#include "libavutil/hmac.h" + +#include "rtmp.h" + +int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap, + const uint8_t *key, int keylen, uint8_t *dst) +{ + AVHMAC *hmac; + + hmac = av_hmac_alloc(AV_HMAC_SHA256); + if (!hmac) + return AVERROR(ENOMEM); + + av_hmac_init(hmac, key, keylen); + if (gap <= 0) { + av_hmac_update(hmac, src, len); + } else { //skip 32 bytes used for storing digest + av_hmac_update(hmac, src, gap); + av_hmac_update(hmac, src + gap + 32, len - gap - 32); + } + av_hmac_final(hmac, dst, 32); + + av_hmac_free(hmac); + + return 0; +} + +int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val, + int add_val) +{ + int i, digest_pos = 0; + + for (i = 0; i < 4; i++) + digest_pos += buf[i + off]; + digest_pos = digest_pos % mod_val + add_val; + + return digest_pos; +} diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c index 7320b4f022a42..b741e421af972 100644 --- a/libavformat/rtmpproto.c +++ b/libavformat/rtmpproto.c @@ -27,7 +27,6 @@ #include "libavcodec/bytestream.h" #include "libavutil/avstring.h" #include "libavutil/base64.h" -#include "libavutil/hmac.h" #include "libavutil/intfloat.h" #include "libavutil/lfg.h" #include "libavutil/md5.h" @@ -989,41 +988,6 @@ static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt, return rtmp_send_packet(rt, &pkt, 1); } -int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap, - const uint8_t *key, int keylen, uint8_t *dst) -{ - AVHMAC *hmac; - - hmac = av_hmac_alloc(AV_HMAC_SHA256); - if (!hmac) - return AVERROR(ENOMEM); - - av_hmac_init(hmac, key, keylen); - if (gap <= 0) { - av_hmac_update(hmac, src, len); - } else { //skip 32 bytes used for storing digest - av_hmac_update(hmac, src, gap); - av_hmac_update(hmac, src + gap + 32, len - gap - 32); - } - av_hmac_final(hmac, dst, 32); - - av_hmac_free(hmac); - - return 0; -} - -int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val, - int add_val) -{ - int i, digest_pos = 0; - - for (i = 0; i < 4; i++) - digest_pos += buf[i + off]; - digest_pos = digest_pos % mod_val + add_val; - - return digest_pos; -} - /** * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest * will be stored) into that packet. @@ -2467,8 +2431,10 @@ static int get_packet(URLContext *s, int for_header) rt->bytes_read += ret; if (rt->bytes_read - rt->last_bytes_read > rt->receive_report_size) { av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n"); - if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0) + if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0) { + ff_rtmp_packet_destroy(&rpkt); return ret; + } rt->last_bytes_read = rt->bytes_read; } diff --git a/libavformat/rtpdec.c b/libavformat/rtpdec.c index 4acb1ca629d4b..e75a34cb93330 100644 --- a/libavformat/rtpdec.c +++ b/libavformat/rtpdec.c @@ -69,88 +69,104 @@ static RTPDynamicProtocolHandler t140_dynamic_handler = { /* RFC 4103 */ .codec_id = AV_CODEC_ID_TEXT, }; -static RTPDynamicProtocolHandler *rtp_first_dynamic_payload_handler = NULL; +extern RTPDynamicProtocolHandler ff_rdt_video_handler; +extern RTPDynamicProtocolHandler ff_rdt_audio_handler; +extern RTPDynamicProtocolHandler ff_rdt_live_video_handler; +extern RTPDynamicProtocolHandler ff_rdt_live_audio_handler; + +static const RTPDynamicProtocolHandler *rtp_dynamic_protocol_handler_list[] = { + /* rtp */ + &ff_ac3_dynamic_handler, + &ff_amr_nb_dynamic_handler, + &ff_amr_wb_dynamic_handler, + &ff_dv_dynamic_handler, + &ff_g726_16_dynamic_handler, + &ff_g726_24_dynamic_handler, + &ff_g726_32_dynamic_handler, + &ff_g726_40_dynamic_handler, + &ff_g726le_16_dynamic_handler, + &ff_g726le_24_dynamic_handler, + &ff_g726le_32_dynamic_handler, + &ff_g726le_40_dynamic_handler, + &ff_h261_dynamic_handler, + &ff_h263_1998_dynamic_handler, + &ff_h263_2000_dynamic_handler, + &ff_h263_rfc2190_dynamic_handler, + &ff_h264_dynamic_handler, + &ff_hevc_dynamic_handler, + &ff_ilbc_dynamic_handler, + &ff_jpeg_dynamic_handler, + &ff_mp4a_latm_dynamic_handler, + &ff_mp4v_es_dynamic_handler, + &ff_mpeg_audio_dynamic_handler, + &ff_mpeg_audio_robust_dynamic_handler, + &ff_mpeg_video_dynamic_handler, + &ff_mpeg4_generic_dynamic_handler, + &ff_mpegts_dynamic_handler, + &ff_ms_rtp_asf_pfa_handler, + &ff_ms_rtp_asf_pfv_handler, + &ff_qcelp_dynamic_handler, + &ff_qdm2_dynamic_handler, + &ff_qt_rtp_aud_handler, + &ff_qt_rtp_vid_handler, + &ff_quicktime_rtp_aud_handler, + &ff_quicktime_rtp_vid_handler, + &ff_rfc4175_rtp_handler, + &ff_svq3_dynamic_handler, + &ff_theora_dynamic_handler, + &ff_vc2hq_dynamic_handler, + &ff_vorbis_dynamic_handler, + &ff_vp8_dynamic_handler, + &ff_vp9_dynamic_handler, + &gsm_dynamic_handler, + &l24_dynamic_handler, + &opus_dynamic_handler, + &realmedia_mp3_dynamic_handler, + &speex_dynamic_handler, + &t140_dynamic_handler, + /* rdt */ + &ff_rdt_video_handler, + &ff_rdt_audio_handler, + &ff_rdt_live_video_handler, + &ff_rdt_live_audio_handler, + NULL, +}; -void ff_register_dynamic_payload_handler(RTPDynamicProtocolHandler *handler) +const RTPDynamicProtocolHandler *ff_rtp_handler_iterate(void **opaque) { - handler->next = rtp_first_dynamic_payload_handler; - rtp_first_dynamic_payload_handler = handler; -} + uintptr_t i = (uintptr_t)*opaque; + const RTPDynamicProtocolHandler *r = rtp_dynamic_protocol_handler_list[i]; -void ff_register_rtp_dynamic_payload_handlers(void) -{ - ff_register_dynamic_payload_handler(&ff_ac3_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_amr_nb_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_amr_wb_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_dv_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_g726_16_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_g726_24_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_g726_32_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_g726_40_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_g726le_16_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_g726le_24_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_g726le_32_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_g726le_40_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_h261_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_h263_1998_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_h263_2000_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_h263_rfc2190_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_h264_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_hevc_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_ilbc_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_jpeg_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_mp4a_latm_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_mp4v_es_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_mpeg_audio_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_mpeg_audio_robust_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_mpeg_video_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_mpeg4_generic_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_mpegts_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_ms_rtp_asf_pfa_handler); - ff_register_dynamic_payload_handler(&ff_ms_rtp_asf_pfv_handler); - ff_register_dynamic_payload_handler(&ff_qcelp_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_qdm2_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_qt_rtp_aud_handler); - ff_register_dynamic_payload_handler(&ff_qt_rtp_vid_handler); - ff_register_dynamic_payload_handler(&ff_quicktime_rtp_aud_handler); - ff_register_dynamic_payload_handler(&ff_quicktime_rtp_vid_handler); - ff_register_dynamic_payload_handler(&ff_rfc4175_rtp_handler); - ff_register_dynamic_payload_handler(&ff_svq3_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_theora_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_vc2hq_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_vorbis_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_vp8_dynamic_handler); - ff_register_dynamic_payload_handler(&ff_vp9_dynamic_handler); - ff_register_dynamic_payload_handler(&gsm_dynamic_handler); - ff_register_dynamic_payload_handler(&l24_dynamic_handler); - ff_register_dynamic_payload_handler(&opus_dynamic_handler); - ff_register_dynamic_payload_handler(&realmedia_mp3_dynamic_handler); - ff_register_dynamic_payload_handler(&speex_dynamic_handler); - ff_register_dynamic_payload_handler(&t140_dynamic_handler); + if (r) + *opaque = (void*)(i + 1); + + return r; } -RTPDynamicProtocolHandler *ff_rtp_handler_find_by_name(const char *name, +const RTPDynamicProtocolHandler *ff_rtp_handler_find_by_name(const char *name, enum AVMediaType codec_type) { - RTPDynamicProtocolHandler *handler; - for (handler = rtp_first_dynamic_payload_handler; - handler; handler = handler->next) + void *i = 0; + const RTPDynamicProtocolHandler *handler; + while (handler = ff_rtp_handler_iterate(&i)) { if (handler->enc_name && !av_strcasecmp(name, handler->enc_name) && codec_type == handler->codec_type) return handler; + } return NULL; } -RTPDynamicProtocolHandler *ff_rtp_handler_find_by_id(int id, +const RTPDynamicProtocolHandler *ff_rtp_handler_find_by_id(int id, enum AVMediaType codec_type) { - RTPDynamicProtocolHandler *handler; - for (handler = rtp_first_dynamic_payload_handler; - handler; handler = handler->next) + void *i = 0; + const RTPDynamicProtocolHandler *handler; + while (handler = ff_rtp_handler_iterate(&i)) { if (handler->static_payload_id && handler->static_payload_id == id && codec_type == handler->codec_type) return handler; + } return NULL; } @@ -556,7 +572,7 @@ RTPDemuxContext *ff_rtp_parse_open(AVFormatContext *s1, AVStream *st, } void ff_rtp_parse_set_dynamic_protocol(RTPDemuxContext *s, PayloadContext *ctx, - RTPDynamicProtocolHandler *handler) + const RTPDynamicProtocolHandler *handler) { s->dynamic_protocol_context = ctx; s->handler = handler; diff --git a/libavformat/rtpdec.h b/libavformat/rtpdec.h index 77596b6707444..5a47d6f79d5fb 100644 --- a/libavformat/rtpdec.h +++ b/libavformat/rtpdec.h @@ -43,7 +43,7 @@ typedef struct RTPDemuxContext RTPDemuxContext; RTPDemuxContext *ff_rtp_parse_open(AVFormatContext *s1, AVStream *st, int payload_type, int queue_size); void ff_rtp_parse_set_dynamic_protocol(RTPDemuxContext *s, PayloadContext *ctx, - RTPDynamicProtocolHandler *handler); + const RTPDynamicProtocolHandler *handler); void ff_rtp_parse_set_crypto(RTPDemuxContext *s, const char *suite, const char *params); int ff_rtp_parse_packet(RTPDemuxContext *s, AVPacket *pkt, @@ -192,10 +192,31 @@ struct RTPDemuxContext { PayloadContext *dynamic_protocol_context; }; -void ff_register_dynamic_payload_handler(RTPDynamicProtocolHandler *handler); -RTPDynamicProtocolHandler *ff_rtp_handler_find_by_name(const char *name, +/** + * Iterate over all registered rtp dynamic protocol handlers. + * + * @param opaque a pointer where libavformat will store the iteration state. Must + * point to NULL to start the iteration. + * + * @return the next registered rtp dynamic protocol handler or NULL when the iteration is + * finished + */ +const RTPDynamicProtocolHandler *ff_rtp_handler_iterate(void **opaque); +/** + * Find a registered rtp dynamic protocol handler with the specified name. + * + * @param name name of the requested rtp dynamic protocol handler + * @return A rtp dynamic protocol handler if one was found, NULL otherwise. + */ +const RTPDynamicProtocolHandler *ff_rtp_handler_find_by_name(const char *name, enum AVMediaType codec_type); -RTPDynamicProtocolHandler *ff_rtp_handler_find_by_id(int id, +/** + * Find a registered rtp dynamic protocol handler with a matching codec ID. + * + * @param id AVCodecID of the requested rtp dynamic protocol handler. + * @return A rtp dynamic protocol handler if one was found, NULL otherwise. + */ +const RTPDynamicProtocolHandler *ff_rtp_handler_find_by_id(int id, enum AVMediaType codec_type); /* from rtsp.c, but used by rtp dynamic protocol handlers. */ @@ -209,8 +230,6 @@ int ff_parse_fmtp(AVFormatContext *s, PayloadContext *data, const char *attr, const char *value)); -void ff_register_rtp_dynamic_payload_handlers(void); - /** * Close the dynamic buffer and make a packet from it. */ diff --git a/libavformat/rtpdec_ac3.c b/libavformat/rtpdec_ac3.c index 48b2d9cf98b4b..56a379f86ccc2 100644 --- a/libavformat/rtpdec_ac3.c +++ b/libavformat/rtpdec_ac3.c @@ -122,7 +122,7 @@ static int ac3_handle_packet(AVFormatContext *ctx, PayloadContext *data, return 0; } -RTPDynamicProtocolHandler ff_ac3_dynamic_handler = { +const RTPDynamicProtocolHandler ff_ac3_dynamic_handler = { .enc_name = "ac3", .codec_type = AVMEDIA_TYPE_AUDIO, .codec_id = AV_CODEC_ID_AC3, diff --git a/libavformat/rtpdec_amr.c b/libavformat/rtpdec_amr.c index 8687e654a3c52..35d322281102e 100644 --- a/libavformat/rtpdec_amr.c +++ b/libavformat/rtpdec_amr.c @@ -182,7 +182,7 @@ static int amr_parse_sdp_line(AVFormatContext *s, int st_index, return 0; } -RTPDynamicProtocolHandler ff_amr_nb_dynamic_handler = { +const RTPDynamicProtocolHandler ff_amr_nb_dynamic_handler = { .enc_name = "AMR", .codec_type = AVMEDIA_TYPE_AUDIO, .codec_id = AV_CODEC_ID_AMR_NB, @@ -192,7 +192,7 @@ RTPDynamicProtocolHandler ff_amr_nb_dynamic_handler = { .parse_packet = amr_handle_packet, }; -RTPDynamicProtocolHandler ff_amr_wb_dynamic_handler = { +const RTPDynamicProtocolHandler ff_amr_wb_dynamic_handler = { .enc_name = "AMR-WB", .codec_type = AVMEDIA_TYPE_AUDIO, .codec_id = AV_CODEC_ID_AMR_WB, diff --git a/libavformat/rtpdec_asf.c b/libavformat/rtpdec_asf.c index 2c09fda10b7dc..54ffef68767ef 100644 --- a/libavformat/rtpdec_asf.c +++ b/libavformat/rtpdec_asf.c @@ -139,12 +139,12 @@ int ff_wms_parse_sdp_a_line(AVFormatContext *s, const char *p) ret = avformat_open_input(&rt->asf_ctx, "", iformat, &opts); av_dict_free(&opts); if (ret < 0) { - av_free(buf); + av_free(pb.buffer); return ret; } av_dict_copy(&s->metadata, rt->asf_ctx->metadata, 0); rt->asf_pb_pos = avio_tell(&pb); - av_free(buf); + av_free(pb.buffer); rt->asf_ctx->pb = NULL; } return ret; @@ -300,7 +300,7 @@ static void asfrtp_close_context(PayloadContext *asf) } #define RTP_ASF_HANDLER(n, s, t) \ -RTPDynamicProtocolHandler ff_ms_rtp_ ## n ## _handler = { \ +const RTPDynamicProtocolHandler ff_ms_rtp_ ## n ## _handler = { \ .enc_name = s, \ .codec_type = t, \ .codec_id = AV_CODEC_ID_NONE, \ diff --git a/libavformat/rtpdec_dv.c b/libavformat/rtpdec_dv.c index de99d277950c8..53a5855ad360c 100644 --- a/libavformat/rtpdec_dv.c +++ b/libavformat/rtpdec_dv.c @@ -131,7 +131,7 @@ static int dv_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_dv_ctx, return 0; } -RTPDynamicProtocolHandler ff_dv_dynamic_handler = { +const RTPDynamicProtocolHandler ff_dv_dynamic_handler = { .enc_name = "DV", .codec_type = AVMEDIA_TYPE_VIDEO, .codec_id = AV_CODEC_ID_DVVIDEO, diff --git a/libavformat/rtpdec_formats.h b/libavformat/rtpdec_formats.h index a436c9d62c60d..dad2b8ac1bb05 100644 --- a/libavformat/rtpdec_formats.h +++ b/libavformat/rtpdec_formats.h @@ -47,47 +47,47 @@ int ff_h264_handle_frag_packet(AVPacket *pkt, const uint8_t *buf, int len, int nal_header_len); void ff_h264_parse_framesize(AVCodecParameters *par, const char *p); -extern RTPDynamicProtocolHandler ff_ac3_dynamic_handler; -extern RTPDynamicProtocolHandler ff_amr_nb_dynamic_handler; -extern RTPDynamicProtocolHandler ff_amr_wb_dynamic_handler; -extern RTPDynamicProtocolHandler ff_dv_dynamic_handler; -extern RTPDynamicProtocolHandler ff_g726_16_dynamic_handler; -extern RTPDynamicProtocolHandler ff_g726_24_dynamic_handler; -extern RTPDynamicProtocolHandler ff_g726_32_dynamic_handler; -extern RTPDynamicProtocolHandler ff_g726_40_dynamic_handler; -extern RTPDynamicProtocolHandler ff_g726le_16_dynamic_handler; -extern RTPDynamicProtocolHandler ff_g726le_24_dynamic_handler; -extern RTPDynamicProtocolHandler ff_g726le_32_dynamic_handler; -extern RTPDynamicProtocolHandler ff_g726le_40_dynamic_handler; -extern RTPDynamicProtocolHandler ff_h261_dynamic_handler; -extern RTPDynamicProtocolHandler ff_h263_1998_dynamic_handler; -extern RTPDynamicProtocolHandler ff_h263_2000_dynamic_handler; -extern RTPDynamicProtocolHandler ff_h263_rfc2190_dynamic_handler; -extern RTPDynamicProtocolHandler ff_h264_dynamic_handler; -extern RTPDynamicProtocolHandler ff_hevc_dynamic_handler; -extern RTPDynamicProtocolHandler ff_ilbc_dynamic_handler; -extern RTPDynamicProtocolHandler ff_jpeg_dynamic_handler; -extern RTPDynamicProtocolHandler ff_mp4a_latm_dynamic_handler; -extern RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler; -extern RTPDynamicProtocolHandler ff_mpeg_audio_dynamic_handler; -extern RTPDynamicProtocolHandler ff_mpeg_audio_robust_dynamic_handler; -extern RTPDynamicProtocolHandler ff_mpeg_video_dynamic_handler; -extern RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler; -extern RTPDynamicProtocolHandler ff_mpegts_dynamic_handler; -extern RTPDynamicProtocolHandler ff_ms_rtp_asf_pfa_handler; -extern RTPDynamicProtocolHandler ff_ms_rtp_asf_pfv_handler; -extern RTPDynamicProtocolHandler ff_qcelp_dynamic_handler; -extern RTPDynamicProtocolHandler ff_qdm2_dynamic_handler; -extern RTPDynamicProtocolHandler ff_qt_rtp_aud_handler; -extern RTPDynamicProtocolHandler ff_qt_rtp_vid_handler; -extern RTPDynamicProtocolHandler ff_quicktime_rtp_aud_handler; -extern RTPDynamicProtocolHandler ff_quicktime_rtp_vid_handler; -extern RTPDynamicProtocolHandler ff_rfc4175_rtp_handler; -extern RTPDynamicProtocolHandler ff_svq3_dynamic_handler; -extern RTPDynamicProtocolHandler ff_theora_dynamic_handler; -extern RTPDynamicProtocolHandler ff_vc2hq_dynamic_handler; -extern RTPDynamicProtocolHandler ff_vorbis_dynamic_handler; -extern RTPDynamicProtocolHandler ff_vp8_dynamic_handler; -extern RTPDynamicProtocolHandler ff_vp9_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_ac3_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_amr_nb_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_amr_wb_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_dv_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_g726_16_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_g726_24_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_g726_32_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_g726_40_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_g726le_16_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_g726le_24_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_g726le_32_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_g726le_40_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_h261_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_h263_1998_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_h263_2000_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_h263_rfc2190_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_h264_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_hevc_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_ilbc_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_jpeg_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_mp4a_latm_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_mpeg_audio_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_mpeg_audio_robust_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_mpeg_video_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_mpegts_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_ms_rtp_asf_pfa_handler; +extern const RTPDynamicProtocolHandler ff_ms_rtp_asf_pfv_handler; +extern const RTPDynamicProtocolHandler ff_qcelp_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_qdm2_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_qt_rtp_aud_handler; +extern const RTPDynamicProtocolHandler ff_qt_rtp_vid_handler; +extern const RTPDynamicProtocolHandler ff_quicktime_rtp_aud_handler; +extern const RTPDynamicProtocolHandler ff_quicktime_rtp_vid_handler; +extern const RTPDynamicProtocolHandler ff_rfc4175_rtp_handler; +extern const RTPDynamicProtocolHandler ff_svq3_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_theora_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_vc2hq_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_vorbis_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_vp8_dynamic_handler; +extern const RTPDynamicProtocolHandler ff_vp9_dynamic_handler; #endif /* AVFORMAT_RTPDEC_FORMATS_H */ diff --git a/libavformat/rtpdec_g726.c b/libavformat/rtpdec_g726.c index 2de09ac233450..89afd586c2aec 100644 --- a/libavformat/rtpdec_g726.c +++ b/libavformat/rtpdec_g726.c @@ -35,13 +35,13 @@ static av_cold int g726_ ## bitrate ##_init(AVFormatContext *s, int st_index, \ return 0; \ } \ \ -RTPDynamicProtocolHandler ff_g726_ ## bitrate ## _dynamic_handler = { \ +const RTPDynamicProtocolHandler ff_g726_ ## bitrate ## _dynamic_handler = { \ .enc_name = "AAL2-G726-" #bitrate, \ .codec_type = AVMEDIA_TYPE_AUDIO, \ .codec_id = AV_CODEC_ID_ADPCM_G726, \ .init = g726_ ## bitrate ## _init, \ }; \ -RTPDynamicProtocolHandler ff_g726le_ ## bitrate ## _dynamic_handler = { \ +const RTPDynamicProtocolHandler ff_g726le_ ## bitrate ## _dynamic_handler = { \ .enc_name = "G726-" #bitrate, \ .codec_type = AVMEDIA_TYPE_AUDIO, \ .codec_id = AV_CODEC_ID_ADPCM_G726LE, \ diff --git a/libavformat/rtpdec_h261.c b/libavformat/rtpdec_h261.c index 9729f21d15757..a102909c60dbe 100644 --- a/libavformat/rtpdec_h261.c +++ b/libavformat/rtpdec_h261.c @@ -162,7 +162,7 @@ static int h261_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_h261_ctx return 0; } -RTPDynamicProtocolHandler ff_h261_dynamic_handler = { +const RTPDynamicProtocolHandler ff_h261_dynamic_handler = { .enc_name = "H261", .codec_type = AVMEDIA_TYPE_VIDEO, .codec_id = AV_CODEC_ID_H261, diff --git a/libavformat/rtpdec_h263.c b/libavformat/rtpdec_h263.c index 97aa4add3685c..9b71ed7efe9d7 100644 --- a/libavformat/rtpdec_h263.c +++ b/libavformat/rtpdec_h263.c @@ -89,7 +89,7 @@ int ff_h263_handle_packet(AVFormatContext *ctx, PayloadContext *data, return 0; } -RTPDynamicProtocolHandler ff_h263_1998_dynamic_handler = { +const RTPDynamicProtocolHandler ff_h263_1998_dynamic_handler = { .enc_name = "H263-1998", .codec_type = AVMEDIA_TYPE_VIDEO, .codec_id = AV_CODEC_ID_H263, @@ -97,7 +97,7 @@ RTPDynamicProtocolHandler ff_h263_1998_dynamic_handler = { .parse_packet = ff_h263_handle_packet, }; -RTPDynamicProtocolHandler ff_h263_2000_dynamic_handler = { +const RTPDynamicProtocolHandler ff_h263_2000_dynamic_handler = { .enc_name = "H263-2000", .codec_type = AVMEDIA_TYPE_VIDEO, .codec_id = AV_CODEC_ID_H263, diff --git a/libavformat/rtpdec_h263_rfc2190.c b/libavformat/rtpdec_h263_rfc2190.c index 6ba2814be2268..a0f587f5c34bf 100644 --- a/libavformat/rtpdec_h263_rfc2190.c +++ b/libavformat/rtpdec_h263_rfc2190.c @@ -183,7 +183,7 @@ static int h263_handle_packet(AVFormatContext *ctx, PayloadContext *data, return 0; } -RTPDynamicProtocolHandler ff_h263_rfc2190_dynamic_handler = { +const RTPDynamicProtocolHandler ff_h263_rfc2190_dynamic_handler = { .codec_type = AVMEDIA_TYPE_VIDEO, .codec_id = AV_CODEC_ID_H263, .need_parsing = AVSTREAM_PARSE_FULL, diff --git a/libavformat/rtpdec_h264.c b/libavformat/rtpdec_h264.c index 6f8148ab6d5db..a785120c23097 100644 --- a/libavformat/rtpdec_h264.c +++ b/libavformat/rtpdec_h264.c @@ -408,7 +408,7 @@ static int parse_h264_sdp_line(AVFormatContext *s, int st_index, return 0; } -RTPDynamicProtocolHandler ff_h264_dynamic_handler = { +const RTPDynamicProtocolHandler ff_h264_dynamic_handler = { .enc_name = "H264", .codec_type = AVMEDIA_TYPE_VIDEO, .codec_id = AV_CODEC_ID_H264, diff --git a/libavformat/rtpdec_hevc.c b/libavformat/rtpdec_hevc.c index a0e3a7c2f49cf..5a06b2362cc87 100644 --- a/libavformat/rtpdec_hevc.c +++ b/libavformat/rtpdec_hevc.c @@ -347,7 +347,7 @@ static int hevc_handle_packet(AVFormatContext *ctx, PayloadContext *rtp_hevc_ctx return res; } -RTPDynamicProtocolHandler ff_hevc_dynamic_handler = { +const RTPDynamicProtocolHandler ff_hevc_dynamic_handler = { .enc_name = "H265", .codec_type = AVMEDIA_TYPE_VIDEO, .codec_id = AV_CODEC_ID_HEVC, diff --git a/libavformat/rtpdec_ilbc.c b/libavformat/rtpdec_ilbc.c index cb48f7661da18..9094f2c786fff 100644 --- a/libavformat/rtpdec_ilbc.c +++ b/libavformat/rtpdec_ilbc.c @@ -66,7 +66,7 @@ static int ilbc_parse_sdp_line(AVFormatContext *s, int st_index, return 0; } -RTPDynamicProtocolHandler ff_ilbc_dynamic_handler = { +const RTPDynamicProtocolHandler ff_ilbc_dynamic_handler = { .enc_name = "iLBC", .codec_type = AVMEDIA_TYPE_AUDIO, .codec_id = AV_CODEC_ID_ILBC, diff --git a/libavformat/rtpdec_jpeg.c b/libavformat/rtpdec_jpeg.c index 465d9bc292119..931463cec4090 100644 --- a/libavformat/rtpdec_jpeg.c +++ b/libavformat/rtpdec_jpeg.c @@ -379,7 +379,7 @@ static int jpeg_parse_packet(AVFormatContext *ctx, PayloadContext *jpeg, return AVERROR(EAGAIN); } -RTPDynamicProtocolHandler ff_jpeg_dynamic_handler = { +const RTPDynamicProtocolHandler ff_jpeg_dynamic_handler = { .enc_name = "JPEG", .codec_type = AVMEDIA_TYPE_VIDEO, .codec_id = AV_CODEC_ID_MJPEG, diff --git a/libavformat/rtpdec_latm.c b/libavformat/rtpdec_latm.c index a25c07fe52f4d..9087d6bec540b 100644 --- a/libavformat/rtpdec_latm.c +++ b/libavformat/rtpdec_latm.c @@ -162,7 +162,7 @@ static int latm_parse_sdp_line(AVFormatContext *s, int st_index, return 0; } -RTPDynamicProtocolHandler ff_mp4a_latm_dynamic_handler = { +const RTPDynamicProtocolHandler ff_mp4a_latm_dynamic_handler = { .enc_name = "MP4A-LATM", .codec_type = AVMEDIA_TYPE_AUDIO, .codec_id = AV_CODEC_ID_AAC, diff --git a/libavformat/rtpdec_mpa_robust.c b/libavformat/rtpdec_mpa_robust.c index 86c8958d5cef8..f4716edf747b3 100644 --- a/libavformat/rtpdec_mpa_robust.c +++ b/libavformat/rtpdec_mpa_robust.c @@ -189,7 +189,7 @@ static int mpa_robust_parse_packet(AVFormatContext *ctx, PayloadContext *data, return 0; } -RTPDynamicProtocolHandler ff_mpeg_audio_robust_dynamic_handler = { +const RTPDynamicProtocolHandler ff_mpeg_audio_robust_dynamic_handler = { .enc_name = "mpa-robust", .codec_type = AVMEDIA_TYPE_AUDIO, .codec_id = AV_CODEC_ID_MP3ADU, diff --git a/libavformat/rtpdec_mpeg12.c b/libavformat/rtpdec_mpeg12.c index b93de3d9e4da6..43d9d5854c4a9 100644 --- a/libavformat/rtpdec_mpeg12.c +++ b/libavformat/rtpdec_mpeg12.c @@ -48,7 +48,7 @@ static int mpeg_parse_packet(AVFormatContext *ctx, PayloadContext *data, return 0; } -RTPDynamicProtocolHandler ff_mpeg_audio_dynamic_handler = { +const RTPDynamicProtocolHandler ff_mpeg_audio_dynamic_handler = { .codec_type = AVMEDIA_TYPE_AUDIO, .codec_id = AV_CODEC_ID_MP3, .need_parsing = AVSTREAM_PARSE_FULL, @@ -56,7 +56,7 @@ RTPDynamicProtocolHandler ff_mpeg_audio_dynamic_handler = { .static_payload_id = 14, }; -RTPDynamicProtocolHandler ff_mpeg_video_dynamic_handler = { +const RTPDynamicProtocolHandler ff_mpeg_video_dynamic_handler = { .codec_type = AVMEDIA_TYPE_VIDEO, .codec_id = AV_CODEC_ID_MPEG2VIDEO, .need_parsing = AVSTREAM_PARSE_FULL, diff --git a/libavformat/rtpdec_mpeg4.c b/libavformat/rtpdec_mpeg4.c index 994ab49251769..4f705990845e3 100644 --- a/libavformat/rtpdec_mpeg4.c +++ b/libavformat/rtpdec_mpeg4.c @@ -325,7 +325,7 @@ static int parse_sdp_line(AVFormatContext *s, int st_index, return 0; } -RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler = { +const RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler = { .enc_name = "MP4V-ES", .codec_type = AVMEDIA_TYPE_VIDEO, .codec_id = AV_CODEC_ID_MPEG4, @@ -334,7 +334,7 @@ RTPDynamicProtocolHandler ff_mp4v_es_dynamic_handler = { .parse_sdp_a_line = parse_sdp_line, }; -RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler = { +const RTPDynamicProtocolHandler ff_mpeg4_generic_dynamic_handler = { .enc_name = "mpeg4-generic", .codec_type = AVMEDIA_TYPE_AUDIO, .codec_id = AV_CODEC_ID_AAC, diff --git a/libavformat/rtpdec_mpegts.c b/libavformat/rtpdec_mpegts.c index 5bf0f186dbd07..405271f744aa7 100644 --- a/libavformat/rtpdec_mpegts.c +++ b/libavformat/rtpdec_mpegts.c @@ -89,7 +89,7 @@ static int mpegts_handle_packet(AVFormatContext *ctx, PayloadContext *data, return 0; } -RTPDynamicProtocolHandler ff_mpegts_dynamic_handler = { +const RTPDynamicProtocolHandler ff_mpegts_dynamic_handler = { .codec_type = AVMEDIA_TYPE_DATA, .priv_data_size = sizeof(PayloadContext), .parse_packet = mpegts_handle_packet, diff --git a/libavformat/rtpdec_qcelp.c b/libavformat/rtpdec_qcelp.c index 41cc8263dfc90..3485c27b6858d 100644 --- a/libavformat/rtpdec_qcelp.c +++ b/libavformat/rtpdec_qcelp.c @@ -209,7 +209,7 @@ static int qcelp_parse_packet(AVFormatContext *ctx, PayloadContext *data, return return_stored_frame(ctx, data, st, pkt, timestamp, buf, len); } -RTPDynamicProtocolHandler ff_qcelp_dynamic_handler = { +const RTPDynamicProtocolHandler ff_qcelp_dynamic_handler = { .enc_name = "x-Purevoice", .codec_type = AVMEDIA_TYPE_AUDIO, .codec_id = AV_CODEC_ID_QCELP, diff --git a/libavformat/rtpdec_qdm2.c b/libavformat/rtpdec_qdm2.c index 1f4fd5aace5e6..fa2b1b9302fbd 100644 --- a/libavformat/rtpdec_qdm2.c +++ b/libavformat/rtpdec_qdm2.c @@ -298,7 +298,7 @@ static int qdm2_parse_packet(AVFormatContext *s, PayloadContext *qdm, return (qdm->cache > 0) ? 1 : 0; } -RTPDynamicProtocolHandler ff_qdm2_dynamic_handler = { +const RTPDynamicProtocolHandler ff_qdm2_dynamic_handler = { .enc_name = "X-QDM", .codec_type = AVMEDIA_TYPE_AUDIO, .codec_id = AV_CODEC_ID_NONE, diff --git a/libavformat/rtpdec_rfc4175.c b/libavformat/rtpdec_rfc4175.c index 498381dfd3fb1..e9c62c1389751 100644 --- a/libavformat/rtpdec_rfc4175.c +++ b/libavformat/rtpdec_rfc4175.c @@ -226,7 +226,7 @@ static int rfc4175_handle_packet(AVFormatContext *ctx, PayloadContext *data, return AVERROR(EAGAIN); } -RTPDynamicProtocolHandler ff_rfc4175_rtp_handler = { +const RTPDynamicProtocolHandler ff_rfc4175_rtp_handler = { .enc_name = "raw", .codec_type = AVMEDIA_TYPE_VIDEO, .codec_id = AV_CODEC_ID_BITPACKED, diff --git a/libavformat/rtpdec_svq3.c b/libavformat/rtpdec_svq3.c index 18d79d2e22dad..77164dd6f917e 100644 --- a/libavformat/rtpdec_svq3.c +++ b/libavformat/rtpdec_svq3.c @@ -110,7 +110,7 @@ static void svq3_close_context(PayloadContext *sv) ffio_free_dyn_buf(&sv->pktbuf); } -RTPDynamicProtocolHandler ff_svq3_dynamic_handler = { +const RTPDynamicProtocolHandler ff_svq3_dynamic_handler = { .enc_name = "X-SV3V-ES", .codec_type = AVMEDIA_TYPE_VIDEO, .codec_id = AV_CODEC_ID_NONE, // see if (config_packet) above diff --git a/libavformat/rtpdec_vc2hq.c b/libavformat/rtpdec_vc2hq.c index 8a3996a035aeb..1a11ace9a2836 100644 --- a/libavformat/rtpdec_vc2hq.c +++ b/libavformat/rtpdec_vc2hq.c @@ -216,7 +216,7 @@ static int vc2hq_handle_packet(AVFormatContext *ctx, PayloadContext *pl_ctx, return res; } -RTPDynamicProtocolHandler ff_vc2hq_dynamic_handler = { +const RTPDynamicProtocolHandler ff_vc2hq_dynamic_handler = { .enc_name = "VC2", .codec_type = AVMEDIA_TYPE_VIDEO, .codec_id = AV_CODEC_ID_DIRAC, diff --git a/libavformat/rtpdec_vp8.c b/libavformat/rtpdec_vp8.c index f0e457b70fbb2..360dd5c782a3e 100644 --- a/libavformat/rtpdec_vp8.c +++ b/libavformat/rtpdec_vp8.c @@ -276,7 +276,7 @@ static int vp8_need_keyframe(PayloadContext *vp8) return vp8->sequence_dirty || !vp8->sequence_ok; } -RTPDynamicProtocolHandler ff_vp8_dynamic_handler = { +const RTPDynamicProtocolHandler ff_vp8_dynamic_handler = { .enc_name = "VP8", .codec_type = AVMEDIA_TYPE_VIDEO, .codec_id = AV_CODEC_ID_VP8, diff --git a/libavformat/rtpdec_vp9.c b/libavformat/rtpdec_vp9.c index 4a7f934d6a605..6bbdf4847ad6d 100644 --- a/libavformat/rtpdec_vp9.c +++ b/libavformat/rtpdec_vp9.c @@ -330,7 +330,7 @@ static void vp9_close_context(PayloadContext *vp9) ffio_free_dyn_buf(&vp9->buf); } -RTPDynamicProtocolHandler ff_vp9_dynamic_handler = { +const RTPDynamicProtocolHandler ff_vp9_dynamic_handler = { .enc_name = "VP9", .codec_type = AVMEDIA_TYPE_VIDEO, .codec_id = AV_CODEC_ID_VP9, diff --git a/libavformat/rtpdec_xiph.c b/libavformat/rtpdec_xiph.c index 43de6ce343195..574508affb6ec 100644 --- a/libavformat/rtpdec_xiph.c +++ b/libavformat/rtpdec_xiph.c @@ -365,7 +365,7 @@ static int xiph_parse_sdp_line(AVFormatContext *s, int st_index, return 0; } -RTPDynamicProtocolHandler ff_theora_dynamic_handler = { +const RTPDynamicProtocolHandler ff_theora_dynamic_handler = { .enc_name = "theora", .codec_type = AVMEDIA_TYPE_VIDEO, .codec_id = AV_CODEC_ID_THEORA, @@ -375,7 +375,7 @@ RTPDynamicProtocolHandler ff_theora_dynamic_handler = { .parse_packet = xiph_handle_packet, }; -RTPDynamicProtocolHandler ff_vorbis_dynamic_handler = { +const RTPDynamicProtocolHandler ff_vorbis_dynamic_handler = { .enc_name = "vorbis", .codec_type = AVMEDIA_TYPE_AUDIO, .codec_id = AV_CODEC_ID_VORBIS, diff --git a/libavformat/rtpenc.c b/libavformat/rtpenc.c index 573593fa663fd..63047beccc8d7 100644 --- a/libavformat/rtpenc.c +++ b/libavformat/rtpenc.c @@ -66,6 +66,7 @@ static int is_supported(enum AVCodecID id) case AV_CODEC_ID_PCM_S8: case AV_CODEC_ID_PCM_S16BE: case AV_CODEC_ID_PCM_S16LE: + case AV_CODEC_ID_PCM_S24BE: case AV_CODEC_ID_PCM_U16BE: case AV_CODEC_ID_PCM_U16LE: case AV_CODEC_ID_PCM_U8: @@ -544,6 +545,8 @@ static int rtp_write_packet(AVFormatContext *s1, AVPacket *pkt) case AV_CODEC_ID_PCM_S16BE: case AV_CODEC_ID_PCM_S16LE: return rtp_send_samples(s1, pkt->data, size, 16 * st->codecpar->channels); + case AV_CODEC_ID_PCM_S24BE: + return rtp_send_samples(s1, pkt->data, size, 24 * st->codecpar->channels); case AV_CODEC_ID_ADPCM_G722: /* The actual sample size is half a byte per sample, but since the * stream clock rate is 8000 Hz while the sample rate is 16000 Hz, diff --git a/libavformat/rtpenc_chain.c b/libavformat/rtpenc_chain.c index f768fb002ebcb..e69fdc27cfb7f 100644 --- a/libavformat/rtpenc_chain.c +++ b/libavformat/rtpenc_chain.c @@ -101,7 +101,7 @@ int ff_rtp_chain_mux_open(AVFormatContext **out, AVFormatContext *s, return 0; fail: - av_free(rtpctx); + avformat_free_context(rtpctx); if (handle) ffurl_close(handle); return ret; diff --git a/libavformat/rtpenc_mpegts.c b/libavformat/rtpenc_mpegts.c index 7af02e0d2fba2..5f81e1a14533a 100644 --- a/libavformat/rtpenc_mpegts.c +++ b/libavformat/rtpenc_mpegts.c @@ -85,6 +85,10 @@ static int rtp_mpegts_write_header(AVFormatContext *s) } rtp_ctx->oformat = rtp_format; st = avformat_new_stream(rtp_ctx, NULL); + if (!st) { + ret = AVERROR(ENOMEM); + goto fail; + } st->time_base.num = 1; st->time_base.den = 90000; st->codecpar->codec_id = AV_CODEC_ID_MPEG2TS; diff --git a/libavformat/rtpproto.c b/libavformat/rtpproto.c index 0706cae25f379..c01d9cea183ad 100644 --- a/libavformat/rtpproto.c +++ b/libavformat/rtpproto.c @@ -636,12 +636,6 @@ int ff_rtp_get_local_rtp_port(URLContext *h) * @return the local port number */ -int ff_rtp_get_local_rtcp_port(URLContext *h) -{ - RTPContext *s = h->priv_data; - return ff_udp_get_local_port(s->rtcp_hd); -} - static int rtp_get_file_handle(URLContext *h) { RTPContext *s = h->priv_data; diff --git a/libavformat/rtpproto.h b/libavformat/rtpproto.h index 5b243fb2486b8..131aac5f3c461 100644 --- a/libavformat/rtpproto.h +++ b/libavformat/rtpproto.h @@ -26,6 +26,5 @@ int ff_rtp_set_remote_url(URLContext *h, const char *uri); int ff_rtp_get_local_rtp_port(URLContext *h); -int ff_rtp_get_local_rtcp_port(URLContext *h); #endif /* AVFORMAT_RTPPROTO_H */ diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c index b6da61b95e6c0..ceb770a3a4901 100644 --- a/libavformat/rtsp.c +++ b/libavformat/rtsp.c @@ -93,10 +93,18 @@ const AVOption ff_rtsp_options[] = { RTSP_MEDIATYPE_OPTS("allowed_media_types", "set media types to accept from the server"), { "min_port", "set minimum local UDP port", OFFSET(rtp_port_min), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MIN}, 0, 65535, DEC|ENC }, { "max_port", "set maximum local UDP port", OFFSET(rtp_port_max), AV_OPT_TYPE_INT, {.i64 = RTSP_RTP_PORT_MAX}, 0, 65535, DEC|ENC }, - { "timeout", "set maximum timeout (in seconds) to wait for incoming connections (-1 is infinite, imply flag listen)", OFFSET(initial_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, DEC }, + { "listen_timeout", "set maximum timeout (in seconds) to wait for incoming connections (-1 is infinite, imply flag listen)", OFFSET(initial_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, DEC }, +#if FF_API_OLD_RTSP_OPTIONS + { "timeout", "set maximum timeout (in seconds) to wait for incoming connections (-1 is infinite, imply flag listen) (deprecated, use listen_timeout)", OFFSET(initial_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, DEC }, { "stimeout", "set timeout (in microseconds) of socket TCP I/O operations", OFFSET(stimeout), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC }, +#else + { "timeout", "set timeout (in microseconds) of socket TCP I/O operations", OFFSET(stimeout), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC }, +#endif COMMON_OPTS(), - { "user-agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = LIBAVFORMAT_IDENT}, 0, 0, DEC }, + { "user_agent", "override User-Agent header", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = LIBAVFORMAT_IDENT}, 0, 0, DEC }, +#if FF_API_OLD_RTSP_OPTIONS + { "user-agent", "override User-Agent header (deprecated, use user_agent)", OFFSET(user_agent), AV_OPT_TYPE_STRING, {.str = LIBAVFORMAT_IDENT}, 0, 0, DEC }, +#endif { NULL }, }; @@ -203,7 +211,7 @@ static int get_sockaddr(AVFormatContext *s, } #if CONFIG_RTPDEC -static void init_rtp_handler(RTPDynamicProtocolHandler *handler, +static void init_rtp_handler(const RTPDynamicProtocolHandler *handler, RTSPStream *rtsp_st, AVStream *st) { AVCodecParameters *par = st ? st->codecpar : NULL; @@ -263,7 +271,7 @@ static int sdp_parse_rtpmap(AVFormatContext *s, } if (par->codec_id == AV_CODEC_ID_NONE) { - RTPDynamicProtocolHandler *handler = + const RTPDynamicProtocolHandler *handler = ff_rtp_handler_find_by_name(buf, par->codec_type); init_rtp_handler(handler, rtsp_st, st); /* If no dynamic handler was found, check with the list of standard @@ -487,7 +495,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, if (CONFIG_RTPDEC && !rt->ts) rt->ts = avpriv_mpegts_parse_open(s); } else { - RTPDynamicProtocolHandler *handler; + const RTPDynamicProtocolHandler *handler; handler = ff_rtp_handler_find_by_id( rtsp_st->sdp_payload_type, AVMEDIA_TYPE_DATA); init_rtp_handler(handler, rtsp_st, NULL); @@ -505,7 +513,7 @@ static void sdp_parse_line(AVFormatContext *s, SDPParseState *s1, rtsp_st->stream_index = st->index; st->codecpar->codec_type = codec_type; if (rtsp_st->sdp_payload_type < RTP_PT_PRIVATE) { - RTPDynamicProtocolHandler *handler; + const RTPDynamicProtocolHandler *handler; /* if standard payload type, we can find the codec right now */ ff_rtp_get_codec_info(st->codecpar, rtsp_st->sdp_payload_type); if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && @@ -1686,7 +1694,7 @@ int ff_rtsp_connect(AVFormatContext *s) redirect: /* extract hostname and port */ av_url_split(proto, sizeof(proto), auth, sizeof(auth), - host, sizeof(host), &port, path, sizeof(path), s->filename); + host, sizeof(host), &port, path, sizeof(path), s->url); if (!strcmp(proto, "rtsps")) { lower_rtsp_proto = "tls"; @@ -1717,7 +1725,7 @@ int ff_rtsp_connect(AVFormatContext *s) } } - /* Construct the URI used in request; this is similar to s->filename, + /* Construct the URI used in request; this is similar to s->url, * but with authentication credentials removed and RTSP specific options * stripped out. */ ff_url_join(rt->control_uri, sizeof(rt->control_uri), proto, NULL, @@ -1905,13 +1913,19 @@ int ff_rtsp_connect(AVFormatContext *s) ff_rtsp_close_streams(s); ff_rtsp_close_connections(s); if (reply->status_code >=300 && reply->status_code < 400 && s->iformat) { - av_strlcpy(s->filename, reply->location, sizeof(s->filename)); + char *new_url = av_strdup(reply->location); + if (!new_url) { + err = AVERROR(ENOMEM); + goto fail2; + } + ff_format_set_url(s, new_url); rt->session_id[0] = '\0'; av_log(s, AV_LOG_INFO, "Status %d: Redirecting to %s\n", reply->status_code, - s->filename); + s->url); goto redirect; } + fail2: ff_network_close(); return err; } @@ -2009,7 +2023,9 @@ static int udp_read_packet(AVFormatContext *s, RTSPStream **prtsp_st, } #if CONFIG_RTSP_DEMUXER if (rt->rtsp_hd && p[0].revents & POLLIN) { - return parse_rtsp_message(s); + if ((ret = parse_rtsp_message(s)) < 0) { + return ret; + } } #endif } else if (n == 0 && ++timeout_cnt >= MAX_TIMEOUTS) { @@ -2423,7 +2439,7 @@ static int rtp_read_header(AVFormatContext *s) if (!ff_network_init()) return AVERROR(EIO); - ret = ffurl_open_whitelist(&in, s->filename, AVIO_FLAG_READ, + ret = ffurl_open_whitelist(&in, s->url, AVIO_FLAG_READ, &s->interrupt_callback, NULL, s->protocol_whitelist, s->protocol_blacklist, NULL); if (ret) goto fail; @@ -2474,7 +2490,7 @@ static int rtp_read_header(AVFormatContext *s) } av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, - NULL, 0, s->filename); + NULL, 0, s->url); snprintf(sdp, sizeof(sdp), "v=0\r\nc=IN IP%d %s\r\nm=%s %d RTP/AVP %d\r\n", diff --git a/libavformat/rtsp.h b/libavformat/rtsp.h index 36fdae492b4de..9a7f366b39290 100644 --- a/libavformat/rtsp.h +++ b/libavformat/rtsp.h @@ -458,7 +458,7 @@ typedef struct RTSPStream { /** The following are used for dynamic protocols (rtpdec_*.c/rdt.c) */ //@{ /** handler structure */ - RTPDynamicProtocolHandler *dynamic_handler; + const RTPDynamicProtocolHandler *dynamic_handler; /** private data associated with the dynamic protocol */ PayloadContext *dynamic_protocol_context; diff --git a/libavformat/rtspdec.c b/libavformat/rtspdec.c index fdf75a0979f15..32dff2319c51f 100644 --- a/libavformat/rtspdec.c +++ b/libavformat/rtspdec.c @@ -644,7 +644,7 @@ static int rtsp_listen(AVFormatContext *s) /* extract hostname and port */ av_url_split(proto, sizeof(proto), auth, sizeof(auth), host, sizeof(host), - &port, path, sizeof(path), s->filename); + &port, path, sizeof(path), s->url); /* ff_url_join. No authorization by now (NULL) */ ff_url_join(rt->control_uri, sizeof(rt->control_uri), proto, NULL, host, @@ -804,7 +804,7 @@ static int resetup_tcp(AVFormatContext *s) int port; av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, NULL, 0, - s->filename); + s->url); ff_rtsp_undo_setup(s, 0); return ff_rtsp_make_setup_request(s, host, port, RTSP_LOWER_TRANSPORT_TCP, rt->real_challenge); diff --git a/libavformat/rtspenc.c b/libavformat/rtspenc.c index e7707bb5fb4ac..97e3ef6da3c1f 100644 --- a/libavformat/rtspenc.c +++ b/libavformat/rtspenc.c @@ -50,6 +50,7 @@ int ff_rtsp_setup_output_streams(AVFormatContext *s, const char *addr) int i; char *sdp; AVFormatContext sdp_ctx, *ctx_array[1]; + char url[1024]; if (s->start_time_realtime == 0 || s->start_time_realtime == AV_NOPTS_VALUE) s->start_time_realtime = av_gettime(); @@ -71,7 +72,8 @@ int ff_rtsp_setup_output_streams(AVFormatContext *s, const char *addr) * flexible SDP creation interface. */ sdp_ctx = *s; - ff_url_join(sdp_ctx.filename, sizeof(sdp_ctx.filename), + sdp_ctx.url = url; + ff_url_join(url, sizeof(url), "rtsp", NULL, addr, -1, NULL); ctx_array[0] = &sdp_ctx; if (av_sdp_create(ctx_array, 1, sdp, SDP_MAX_SIZE)) { diff --git a/libavformat/sapdec.c b/libavformat/sapdec.c index 522b38d10a215..7a6c8bf1761e5 100644 --- a/libavformat/sapdec.c +++ b/libavformat/sapdec.c @@ -74,7 +74,7 @@ static int sap_read_header(AVFormatContext *s) return AVERROR(EIO); av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &port, - path, sizeof(path), s->filename); + path, sizeof(path), s->url); if (port < 0) port = 9875; diff --git a/libavformat/sapenc.c b/libavformat/sapenc.c index 3098e340ca94a..f9afab0c33eb4 100644 --- a/libavformat/sapenc.c +++ b/libavformat/sapenc.c @@ -84,7 +84,7 @@ static int sap_write_header(AVFormatContext *s) /* extract hostname and port */ av_url_split(NULL, 0, NULL, 0, host, sizeof(host), &base_port, - path, sizeof(path), s->filename); + path, sizeof(path), s->url); if (base_port < 0) base_port = 5004; @@ -144,6 +144,7 @@ static int sap_write_header(AVFormatContext *s) s->start_time_realtime = av_gettime(); for (i = 0; i < s->nb_streams; i++) { URLContext *fd; + char *new_url; ff_url_join(url, sizeof(url), "rtp", NULL, host, base_port, "?ttl=%d", ttl); @@ -161,7 +162,12 @@ static int sap_write_header(AVFormatContext *s) goto fail; s->streams[i]->priv_data = contexts[i]; s->streams[i]->time_base = contexts[i]->streams[0]->time_base; - av_strlcpy(contexts[i]->filename, url, sizeof(contexts[i]->filename)); + new_url = av_strdup(url); + if (!new_url) { + ret = AVERROR(ENOMEM); + goto fail; + } + ff_format_set_url(contexts[i], new_url); } if (s->nb_streams > 0 && title) diff --git a/libavfilter/unsharp_opencl.h b/libavformat/sbcdec.c similarity index 61% rename from libavfilter/unsharp_opencl.h rename to libavformat/sbcdec.c index 3aefab62e00e1..ae74a220dc81a 100644 --- a/libavfilter/unsharp_opencl.h +++ b/libavformat/sbcdec.c @@ -1,5 +1,6 @@ /* - * Copyright (C) 2013 Wei Gao + * RAW SBC demuxer + * Copyright (C) 2017 Aurelien Jacobs * * This file is part of FFmpeg. * @@ -18,17 +19,15 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVFILTER_UNSHARP_OPENCL_H -#define AVFILTER_UNSHARP_OPENCL_H +#include "avformat.h" +#include "rawdec.h" -#include "unsharp.h" - -int ff_opencl_unsharp_init(AVFilterContext *ctx); - -void ff_opencl_unsharp_uninit(AVFilterContext *ctx); - -int ff_opencl_unsharp_process_inout_buf(AVFilterContext *ctx, AVFrame *in, AVFrame *out); - -int ff_opencl_apply_unsharp(AVFilterContext *ctx, AVFrame *in, AVFrame *out); - -#endif /* AVFILTER_UNSHARP_OPENCL_H */ +AVInputFormat ff_sbc_demuxer = { + .name = "sbc", + .long_name = NULL_IF_CONFIG_SMALL("raw SBC (low-complexity subband codec)"), + .extensions = "sbc,msbc", + .raw_codec_id = AV_CODEC_ID_SBC, + .read_header = ff_raw_audio_read_header, + .read_packet = ff_raw_read_partial_packet, + .flags = AVFMT_GENERIC_INDEX, +}; diff --git a/libavformat/sdp.c b/libavformat/sdp.c index 0242ca379c23e..a5d202e99cb28 100644 --- a/libavformat/sdp.c +++ b/libavformat/sdp.c @@ -584,6 +584,12 @@ static char *sdp_write_media_attributes(char *buff, int size, AVStream *st, int payload_type, p->sample_rate, p->channels); break; + case AV_CODEC_ID_PCM_S24BE: + if (payload_type >= RTP_PT_PRIVATE) + av_strlcatf(buff, size, "a=rtpmap:%d L24/%d/%d\r\n", + payload_type, + p->sample_rate, p->channels); + break; case AV_CODEC_ID_PCM_MULAW: if (payload_type >= RTP_PT_PRIVATE) av_strlcatf(buff, size, "a=rtpmap:%d PCMU/%d/%d\r\n", @@ -778,7 +784,7 @@ int av_sdp_create(AVFormatContext *ac[], int n_files, char *buf, int size) port = 0; ttl = 0; if (n_files == 1) { - port = sdp_get_address(dst, sizeof(dst), &ttl, ac[0]->filename); + port = sdp_get_address(dst, sizeof(dst), &ttl, ac[0]->url ? ac[0]->url : ""); is_multicast = resolve_destination(dst, sizeof(dst), dst_type, sizeof(dst_type)); if (!is_multicast) @@ -798,7 +804,7 @@ int av_sdp_create(AVFormatContext *ac[], int n_files, char *buf, int size) dst[0] = 0; for (i = 0; i < n_files; i++) { if (n_files != 1) { - port = sdp_get_address(dst, sizeof(dst), &ttl, ac[i]->filename); + port = sdp_get_address(dst, sizeof(dst), &ttl, ac[i]->url ? ac[i]->url : ""); is_multicast = resolve_destination(dst, sizeof(dst), dst_type, sizeof(dst_type)); if (!is_multicast) diff --git a/libavformat/segafilm.c b/libavformat/segafilm.c index 1fdef50cc75d7..e72c26b144904 100644 --- a/libavformat/segafilm.c +++ b/libavformat/segafilm.c @@ -239,7 +239,7 @@ static int film_read_header(AVFormatContext *s) } else { film->sample_table[i].stream = film->video_stream_index; film->sample_table[i].pts = AV_RB32(&scratch[8]) & 0x7FFFFFFF; - film->sample_table[i].keyframe = (scratch[8] & 0x80) ? 0 : 1; + film->sample_table[i].keyframe = (scratch[8] & 0x80) ? AVINDEX_KEYFRAME : 0; video_frame_counter++; if (film->video_type) av_add_index_entry(s->streams[film->video_stream_index], @@ -270,6 +270,8 @@ static int film_read_packet(AVFormatContext *s, FilmDemuxContext *film = s->priv_data; AVIOContext *pb = s->pb; film_sample *sample; + film_sample *next_sample = NULL; + int next_sample_id; int ret = 0; if (film->current_sample >= film->sample_count) @@ -277,6 +279,20 @@ static int film_read_packet(AVFormatContext *s, sample = &film->sample_table[film->current_sample]; + /* Find the next sample from the same stream, assuming there is one; + * this is used to calculate the duration below */ + next_sample_id = film->current_sample + 1; + while (next_sample == NULL) { + if (next_sample_id >= film->sample_count) + break; + + next_sample = &film->sample_table[next_sample_id]; + if (next_sample->stream != sample->stream) { + next_sample = NULL; + next_sample_id++; + } + } + /* position the stream (will probably be there anyway) */ avio_seek(pb, sample->sample_offset, SEEK_SET); @@ -285,7 +301,11 @@ static int film_read_packet(AVFormatContext *s, ret = AVERROR(EIO); pkt->stream_index = sample->stream; + pkt->dts = sample->pts; pkt->pts = sample->pts; + pkt->flags |= sample->keyframe ? AV_PKT_FLAG_KEY : 0; + if (next_sample != NULL) + pkt->duration = next_sample->pts - sample->pts; film->current_sample++; diff --git a/libavformat/segafilmenc.c b/libavformat/segafilmenc.c new file mode 100644 index 0000000000000..5b0d7e69e87a4 --- /dev/null +++ b/libavformat/segafilmenc.c @@ -0,0 +1,398 @@ +/* + * Sega FILM Format (CPK) Muxer + * Copyright (C) 2003 The FFmpeg project + * Copyright (C) 2018 Misty De Meo + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * Sega FILM (.cpk) file muxer + * @author Misty De Meo + * + * @see For more information regarding the Sega FILM file format, visit: + * http://wiki.multimedia.cx/index.php?title=Sega_FILM + */ + +#include "libavutil/intreadwrite.h" +#include "avformat.h" +#include "internal.h" +#include "avio_internal.h" + +typedef struct FILMPacket { + int audio; + int keyframe; + int32_t pts; + int32_t duration; + int32_t size; + int32_t index; + struct FILMPacket *next; +} FILMPacket; + +typedef struct FILMOutputContext { + const AVClass *class; + int audio_index; + int video_index; + int64_t stab_pos; + FILMPacket *start; + FILMPacket *last; + int64_t packet_count; +} FILMOutputContext; + +static int film_write_packet_to_header(AVFormatContext *format_context, FILMPacket *pkt) +{ + AVIOContext *pb = format_context->pb; + /* The bits in these two 32-bit integers contain info about the contents of this sample */ + int32_t info1 = 0; + int32_t info2 = 0; + + if (pkt->audio) { + /* Always the same, carries no more information than "this is audio" */ + info1 = 0xFFFFFFFF; + info2 = 1; + } else { + info1 = pkt->pts; + info2 = pkt->duration; + /* The top bit being set indicates a key frame */ + if (pkt->keyframe) + info1 |= (1 << 31); + } + + /* Write the 16-byte sample info packet to the STAB chunk in the header */ + avio_wb32(pb, pkt->index); + avio_wb32(pb, pkt->size); + avio_wb32(pb, info1); + avio_wb32(pb, info2); + + return 0; +} + +static int film_write_packet(AVFormatContext *format_context, AVPacket *pkt) +{ + FILMPacket *metadata; + AVIOContext *pb = format_context->pb; + FILMOutputContext *film = format_context->priv_data; + int encoded_buf_size = 0; + enum AVCodecID codec_id; + + /* Track the metadata used to write the header and add it to the linked list */ + metadata = av_mallocz(sizeof(FILMPacket)); + if (!metadata) + return AVERROR(ENOMEM); + metadata->audio = pkt->stream_index == film->audio_index; + metadata->keyframe = pkt->flags & AV_PKT_FLAG_KEY; + metadata->pts = pkt->pts; + metadata->duration = pkt->duration; + metadata->size = pkt->size; + if (film->last == NULL) { + metadata->index = 0; + } else { + metadata->index = film->last->index + film->last->size; + film->last->next = metadata; + } + metadata->next = NULL; + if (film->start == NULL) + film->start = metadata; + film->packet_count++; + film->last = metadata; + + codec_id = format_context->streams[pkt->stream_index]->codecpar->codec_id; + + /* Sega Cinepak has an extra two-byte header; write dummy data there, + * then adjust the cvid header to accommodate for the extra size */ + if (codec_id == AV_CODEC_ID_CINEPAK) { + encoded_buf_size = AV_RB24(&pkt->data[1]); + /* Already Sega Cinepak, so no need to reformat the packets */ + if (encoded_buf_size != pkt->size && (pkt->size % encoded_buf_size) != 0) { + avio_write(pb, pkt->data, pkt->size); + } else { + uint8_t padding[2] = {0, 0}; + /* In Sega Cinepak, the reported size in the Cinepak header is + * 8 bytes too short. However, the size in the STAB section of the header + * is correct, taking into account the extra two bytes. */ + AV_WB24(&pkt->data[1], pkt->size - 8 + 2); + metadata->size += 2; + + avio_write(pb, pkt->data, 10); + avio_write(pb, padding, 2); + avio_write(pb, &pkt->data[10], pkt->size - 10); + } + } else { + /* Other formats can just be written as-is */ + avio_write(pb, pkt->data, pkt->size); + } + + return 0; +} + +static int get_audio_codec_id(enum AVCodecID codec_id) +{ + /* 0 (PCM) and 2 (ADX) are the only known values */ + switch (codec_id) { + case AV_CODEC_ID_PCM_S8_PLANAR: + case AV_CODEC_ID_PCM_S16BE_PLANAR: + return 0; + break; + case AV_CODEC_ID_ADPCM_ADX: + return 2; + break; + default: + return -1; + } +} + +static int film_init(AVFormatContext *format_context) +{ + AVStream *audio = NULL; + FILMOutputContext *film = format_context->priv_data; + film->audio_index = -1; + film->video_index = -1; + film->stab_pos = 0; + film->packet_count = 0; + film->start = NULL; + film->last = NULL; + + for (int i = 0; i < format_context->nb_streams; i++) { + AVStream *st = format_context->streams[i]; + if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { + if (film->audio_index > -1) { + av_log(format_context, AV_LOG_ERROR, "Sega FILM allows a maximum of one audio stream.\n"); + return AVERROR(EINVAL); + } + film->audio_index = i; + audio = st; + } + + if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { + if (film->video_index > -1) { + av_log(format_context, AV_LOG_ERROR, "Sega FILM allows a maximum of one video stream.\n"); + return AVERROR(EINVAL); + } + film->video_index = i; + } + + if (film->video_index == -1) { + av_log(format_context, AV_LOG_ERROR, "No video stream present.\n"); + return AVERROR(EINVAL); + } + } + + if (audio != NULL && get_audio_codec_id(audio->codecpar->codec_id) < 0) { + av_log(format_context, AV_LOG_ERROR, "Incompatible audio stream format.\n"); + return AVERROR(EINVAL); + } + + return 0; +} + +static int shift_data(AVFormatContext *format_context, int64_t shift_size) +{ + int ret = 0; + int64_t pos, pos_end = avio_tell(format_context->pb); + uint8_t *buf, *read_buf[2]; + int read_buf_id = 0; + int read_size[2]; + AVIOContext *read_pb; + + buf = av_malloc(shift_size * 2); + if (!buf) + return AVERROR(ENOMEM); + read_buf[0] = buf; + read_buf[1] = buf + shift_size; + + /* Write the header at the beginning of the file, shifting all content as necessary; + * based on the approach used by MOV faststart. */ + avio_flush(format_context->pb); + ret = format_context->io_open(format_context, &read_pb, format_context->url, AVIO_FLAG_READ, NULL); + if (ret < 0) { + av_log(format_context, AV_LOG_ERROR, "Unable to re-open %s output file to " + "write the header\n", format_context->url); + av_free(buf); + return ret; + } + + /* mark the end of the shift to up to the last data we wrote, and get ready + * for writing */ + pos_end = avio_tell(format_context->pb); + avio_seek(format_context->pb, shift_size, SEEK_SET); + + /* start reading at where the new header will be placed */ + avio_seek(read_pb, 0, SEEK_SET); + pos = avio_tell(read_pb); + +#define READ_BLOCK do { \ + read_size[read_buf_id] = avio_read(read_pb, read_buf[read_buf_id], shift_size); \ + read_buf_id ^= 1; \ +} while (0) + + /* shift data by chunk of at most shift_size */ + READ_BLOCK; + do { + int n; + READ_BLOCK; + n = read_size[read_buf_id]; + if (n <= 0) + break; + avio_write(format_context->pb, read_buf[read_buf_id], n); + pos += n; + } while (pos < pos_end); + ff_format_io_close(format_context, &read_pb); + + av_free(buf); + return 0; +} + +static int film_write_header(AVFormatContext *format_context) +{ + int ret = 0; + int64_t sample_table_size, stabsize, headersize; + int8_t audio_codec; + AVIOContext *pb = format_context->pb; + FILMOutputContext *film = format_context->priv_data; + FILMPacket *prev, *packet; + AVStream *audio = NULL; + AVStream *video = NULL; + + /* Calculate how much we need to reserve for the header; + * this is the amount the rest of the data will be shifted up by. */ + sample_table_size = film->packet_count * 16; + stabsize = 16 + sample_table_size; + headersize = 16 + /* FILM header base */ + 32 + /* FDSC chunk */ + stabsize; + + ret = shift_data(format_context, headersize); + if (ret < 0) + return ret; + /* Seek back to the beginning to start writing the header now */ + avio_seek(pb, 0, SEEK_SET); + + if (film->audio_index > -1) + audio = format_context->streams[film->audio_index]; + if (film->video_index > -1) + video = format_context->streams[film->video_index]; + + if (audio != NULL) { + audio_codec = get_audio_codec_id(audio->codecpar->codec_id); + if (audio_codec < 0) { + av_log(format_context, AV_LOG_ERROR, "Incompatible audio stream format.\n"); + return AVERROR(EINVAL); + } + } + + if (video->codecpar->format != AV_PIX_FMT_RGB24) { + av_log(format_context, AV_LOG_ERROR, "Pixel format must be rgb24.\n"); + return AVERROR(EINVAL); + } + + /* First, write the FILM header; this is very simple */ + + ffio_wfourcc(pb, "FILM"); + avio_wb32(pb, 48 + stabsize); + /* This seems to be okay to hardcode, since this muxer targets 1.09 features; + * videos produced by this muxer are readable by 1.08 and lower players. */ + ffio_wfourcc(pb, "1.09"); + /* I have no idea what this field does, might be reserved */ + avio_wb32(pb, 0); + + /* Next write the FDSC (file description) chunk */ + ffio_wfourcc(pb, "FDSC"); + avio_wb32(pb, 0x20); /* Size of FDSC chunk */ + + /* The only two supported codecs; raw video is rare */ + switch (video->codecpar->codec_id) { + case AV_CODEC_ID_CINEPAK: + ffio_wfourcc(pb, "cvid"); + break; + case AV_CODEC_ID_RAWVIDEO: + ffio_wfourcc(pb, "raw "); + break; + default: + av_log(format_context, AV_LOG_ERROR, "Incompatible video stream format.\n"); + return AVERROR(EINVAL); + } + + avio_wb32(pb, video->codecpar->height); + avio_wb32(pb, video->codecpar->width); + avio_w8(pb, 24); /* Bits per pixel - observed to always be 24 */ + + if (audio != NULL) { + avio_w8(pb, audio->codecpar->channels); /* Audio channels */ + avio_w8(pb, audio->codecpar->bits_per_coded_sample); /* Audio bit depth */ + avio_w8(pb, audio_codec); /* Compression - 0 is PCM, 2 is ADX */ + avio_wb16(pb, audio->codecpar->sample_rate); /* Audio sampling rate */ + } else { + /* Set all these fields to 0 if there's no audio */ + avio_w8(pb, 0); + avio_w8(pb, 0); + avio_w8(pb, 0); + avio_wb16(pb, 0); + } + + /* I have no idea what this pair of fields does either, might be reserved */ + avio_wb32(pb, 0); + avio_wb16(pb, 0); + + /* Finally, write the STAB (sample table) chunk */ + ffio_wfourcc(pb, "STAB"); + avio_wb32(pb, 16 + (film->packet_count * 16)); + /* Framerate base frequency. Here we're assuming that the frame rate is even. + * In real world Sega FILM files, there are usually a couple of approaches: + * a) framerate base frequency is the same as the framerate, and ticks + * increment by 1 every frame, or + * b) framerate base frequency is a much larger number, and ticks + * increment by larger steps every frame. + * The latter occurs even in cases where the frame rate is even; for example, in + * Lunar: Silver Star Story, the base frequency is 600 and each frame, the ticks + * are incremented by 25 for an evenly spaced framerate of 24fps. */ + avio_wb32(pb, av_q2d(av_inv_q(video->time_base))); + + avio_wb32(pb, film->packet_count); + + avio_flush(pb); + + /* Finally, write out each packet's data to the header */ + packet = film->start; + while (packet != NULL) { + film_write_packet_to_header(format_context, packet); + prev = packet; + packet = packet->next; + av_freep(&prev); + } + + return 0; +} + +static const AVClass film_muxer_class = { + .class_name = "Sega FILM muxer", + .item_name = av_default_item_name, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVOutputFormat ff_segafilm_muxer = { + .name = "film_cpk", + .long_name = NULL_IF_CONFIG_SMALL("Sega FILM / CPK"), + .extensions = "cpk", + .priv_data_size = sizeof(FILMOutputContext), + .audio_codec = AV_CODEC_ID_PCM_S16BE_PLANAR, + .video_codec = AV_CODEC_ID_CINEPAK, + .init = film_init, + .write_trailer = film_write_header, + .write_packet = film_write_packet, + .priv_class = &film_muxer_class, +}; diff --git a/libavformat/segment.c b/libavformat/segment.c index 81d3f1d9408bc..7fb4dc7d2124c 100644 --- a/libavformat/segment.c +++ b/libavformat/segment.c @@ -192,6 +192,8 @@ static int set_segment_filename(AVFormatContext *s) AVFormatContext *oc = seg->avf; size_t size; int ret; + char buf[1024]; + char *new_name; if (seg->segment_idx_wrap) seg->segment_idx %= seg->segment_idx_wrap; @@ -200,18 +202,22 @@ static int set_segment_filename(AVFormatContext *s) struct tm *tm, tmpbuf; time(&now0); tm = localtime_r(&now0, &tmpbuf); - if (!strftime(oc->filename, sizeof(oc->filename), s->filename, tm)) { + if (!strftime(buf, sizeof(buf), s->url, tm)) { av_log(oc, AV_LOG_ERROR, "Could not get segment filename with strftime\n"); return AVERROR(EINVAL); } - } else if (av_get_frame_filename(oc->filename, sizeof(oc->filename), - s->filename, seg->segment_idx) < 0) { - av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", s->filename); + } else if (av_get_frame_filename(buf, sizeof(buf), + s->url, seg->segment_idx) < 0) { + av_log(oc, AV_LOG_ERROR, "Invalid segment filename template '%s'\n", s->url); return AVERROR(EINVAL); } + new_name = av_strdup(buf); + if (!new_name) + return AVERROR(ENOMEM); + ff_format_set_url(oc, new_name); /* copy modified name in list entry */ - size = strlen(av_basename(oc->filename)) + 1; + size = strlen(av_basename(oc->url)) + 1; if (seg->entry_prefix) size += strlen(seg->entry_prefix); @@ -219,7 +225,7 @@ static int set_segment_filename(AVFormatContext *s) return ret; snprintf(seg->cur_entry.filename, size, "%s%s", seg->entry_prefix ? seg->entry_prefix : "", - av_basename(oc->filename)); + av_basename(oc->url)); return 0; } @@ -245,8 +251,8 @@ static int segment_start(AVFormatContext *s, int write_header) if ((err = set_segment_filename(s)) < 0) return err; - if ((err = s->io_open(s, &oc->pb, oc->filename, AVIO_FLAG_WRITE, NULL)) < 0) { - av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", oc->filename); + if ((err = s->io_open(s, &oc->pb, oc->url, AVIO_FLAG_WRITE, NULL)) < 0) { + av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", oc->url); return err; } if (!seg->individual_header_trailer) @@ -360,7 +366,7 @@ static int segment_end(AVFormatContext *s, int write_trailer, int is_last) if (ret < 0) av_log(s, AV_LOG_ERROR, "Failure occurred when ending segment '%s'\n", - oc->filename); + oc->url); if (seg->list) { if (seg->list_size || seg->list_type == LIST_TYPE_M3U8) { @@ -403,7 +409,7 @@ static int segment_end(AVFormatContext *s, int write_trailer, int is_last) } av_log(s, AV_LOG_VERBOSE, "segment:'%s' count:%d ended\n", - seg->avf->filename, seg->segment_count); + seg->avf->url, seg->segment_count); seg->segment_count++; if (seg->increment_tc) { @@ -726,7 +732,7 @@ static int seg_init(AVFormatContext *s) seg->reference_stream_index, av_get_media_type_string(s->streams[seg->reference_stream_index]->codecpar->codec_type)); - seg->oformat = av_guess_format(seg->format, s->filename, NULL); + seg->oformat = av_guess_format(seg->format, s->url, NULL); if (!seg->oformat) return AVERROR_MUXER_NOT_FOUND; @@ -745,9 +751,9 @@ static int seg_init(AVFormatContext *s) if (seg->write_header_trailer) { if ((ret = s->io_open(s, &oc->pb, - seg->header_filename ? seg->header_filename : oc->filename, + seg->header_filename ? seg->header_filename : oc->url, AVIO_FLAG_WRITE, NULL)) < 0) { - av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", oc->filename); + av_log(s, AV_LOG_ERROR, "Failed to open segment '%s'\n", oc->url); return ret; } if (!seg->individual_header_trailer) @@ -830,7 +836,7 @@ static int seg_write_header(AVFormatContext *s) } else { close_null_ctxp(&oc->pb); } - if ((ret = oc->io_open(oc, &oc->pb, oc->filename, AVIO_FLAG_WRITE, NULL)) < 0) + if ((ret = oc->io_open(oc, &oc->pb, oc->url, AVIO_FLAG_WRITE, NULL)) < 0) return ret; if (!seg->individual_header_trailer) oc->pb->seekable = 0; @@ -917,7 +923,7 @@ static int seg_write_packet(AVFormatContext *s, AVPacket *pkt) if (seg->segment_frame_count == 0) { av_log(s, AV_LOG_VERBOSE, "segment:'%s' starts with packet stream:%d pts:%s pts_time:%s frame:%d\n", - seg->avf->filename, pkt->stream_index, + seg->avf->url, pkt->stream_index, av_ts2str(pkt->pts), av_ts2timestr(pkt->pts, &st->time_base), seg->frame_count); } @@ -1058,6 +1064,7 @@ static const AVOption options[] = { { NULL }, }; +#if CONFIG_SEGMENT_MUXER static const AVClass seg_class = { .class_name = "segment muxer", .item_name = av_default_item_name, @@ -1078,7 +1085,9 @@ AVOutputFormat ff_segment_muxer = { .check_bitstream = seg_check_bitstream, .priv_class = &seg_class, }; +#endif +#if CONFIG_STREAM_SEGMENT_MUXER static const AVClass sseg_class = { .class_name = "stream_segment muxer", .item_name = av_default_item_name, @@ -1099,3 +1108,4 @@ AVOutputFormat ff_stream_segment_muxer = { .check_bitstream = seg_check_bitstream, .priv_class = &sseg_class, }; +#endif diff --git a/libavformat/smoothstreamingenc.c b/libavformat/smoothstreamingenc.c index 54a1c49caae69..094712af27dd6 100644 --- a/libavformat/smoothstreamingenc.c +++ b/libavformat/smoothstreamingenc.c @@ -221,8 +221,8 @@ static int write_manifest(AVFormatContext *s, int final) int ret, i, video_chunks = 0, audio_chunks = 0, video_streams = 0, audio_streams = 0; int64_t duration = 0; - snprintf(filename, sizeof(filename), "%s/Manifest", s->filename); - snprintf(temp_filename, sizeof(temp_filename), "%s/Manifest.tmp", s->filename); + snprintf(filename, sizeof(filename), "%s/Manifest", s->url); + snprintf(temp_filename, sizeof(temp_filename), "%s/Manifest.tmp", s->url); ret = s->io_open(s, &out, temp_filename, AVIO_FLAG_WRITE, NULL); if (ret < 0) { av_log(s, AV_LOG_ERROR, "Unable to open %s for writing\n", temp_filename); @@ -295,7 +295,7 @@ static int ism_write_header(AVFormatContext *s) int ret = 0, i; AVOutputFormat *oformat; - if (mkdir(s->filename, 0777) == -1 && errno != EEXIST) { + if (mkdir(s->url, 0777) == -1 && errno != EEXIST) { ret = AVERROR(errno); av_log(s, AV_LOG_ERROR, "mkdir failed\n"); goto fail; @@ -324,7 +324,7 @@ static int ism_write_header(AVFormatContext *s) ret = AVERROR(EINVAL); goto fail; } - snprintf(os->dirname, sizeof(os->dirname), "%s/QualityLevels(%"PRId64")", s->filename, s->streams[i]->codecpar->bit_rate); + snprintf(os->dirname, sizeof(os->dirname), "%s/QualityLevels(%"PRId64")", s->url, s->streams[i]->codecpar->bit_rate); if (mkdir(os->dirname, 0777) == -1 && errno != EEXIST) { ret = AVERROR(errno); av_log(s, AV_LOG_ERROR, "mkdir failed\n"); @@ -609,9 +609,9 @@ static int ism_write_trailer(AVFormatContext *s) if (c->remove_at_exit) { char filename[1024]; - snprintf(filename, sizeof(filename), "%s/Manifest", s->filename); + snprintf(filename, sizeof(filename), "%s/Manifest", s->url); unlink(filename); - rmdir(s->filename); + rmdir(s->url); } ism_free(s); diff --git a/libavformat/spdifdec.c b/libavformat/spdifdec.c index f7288376f62ff..21bfce422696b 100644 --- a/libavformat/spdifdec.c +++ b/libavformat/spdifdec.c @@ -25,18 +25,22 @@ * @author Anssi Hannula */ +#include "libavutil/bswap.h" + +#include "libavcodec/ac3.h" +#include "libavcodec/adts_parser.h" + #include "avformat.h" #include "spdif.h" -#include "libavcodec/ac3.h" -#include "libavcodec/aacadtsdec.h" static int spdif_get_offset_and_codec(AVFormatContext *s, enum IEC61937DataType data_type, const char *buf, int *offset, enum AVCodecID *codec) { - AACADTSHeaderInfo aac_hdr; - GetBitContext gbc; + uint32_t samples; + uint8_t frames; + int ret; switch (data_type & 0xff) { case IEC61937_AC3: @@ -56,13 +60,13 @@ static int spdif_get_offset_and_codec(AVFormatContext *s, *codec = AV_CODEC_ID_MP3; break; case IEC61937_MPEG2_AAC: - init_get_bits(&gbc, buf, AAC_ADTS_HEADER_SIZE * 8); - if (avpriv_aac_parse_header(&gbc, &aac_hdr) < 0) { + ret = av_adts_header_parse(buf, &samples, &frames); + if (ret < 0) { if (s) /* be silent during a probe */ av_log(s, AV_LOG_ERROR, "Invalid AAC packet in IEC 61937\n"); - return AVERROR_INVALIDDATA; + return ret; } - *offset = aac_hdr.samples << 2; + *offset = samples << 2; *codec = AV_CODEC_ID_AAC; break; case IEC61937_MPEG2_LAYER1_LSF: @@ -100,7 +104,7 @@ static int spdif_get_offset_and_codec(AVFormatContext *s, } /* Largest offset between bursts we currently handle, i.e. AAC with - aac_hdr.samples = 4096 */ + samples = 4096 */ #define SPDIF_MAX_OFFSET 16384 static int spdif_probe(AVProbeData *p) @@ -132,7 +136,7 @@ int ff_spdif_probe(const uint8_t *p_buf, int buf_size, enum AVCodecID *codec) } else consecutive_codes = 0; - if (buf + 4 + AAC_ADTS_HEADER_SIZE > p_buf + buf_size) + if (buf + 4 + AV_AAC_ADTS_HEADER_SIZE > p_buf + buf_size) break; /* continue probing to find more sync codes */ diff --git a/libavformat/spdifenc.c b/libavformat/spdifenc.c index b47ec123e8b6a..9514ff8e10e35 100644 --- a/libavformat/spdifenc.c +++ b/libavformat/spdifenc.c @@ -50,9 +50,9 @@ #include "avio_internal.h" #include "spdif.h" #include "libavcodec/ac3.h" +#include "libavcodec/adts_parser.h" #include "libavcodec/dca.h" #include "libavcodec/dca_syncwords.h" -#include "libavcodec/aacadtsdec.h" #include "libavutil/opt.h" typedef struct IEC61937Context { @@ -118,7 +118,8 @@ static int spdif_header_eac3(AVFormatContext *s, AVPacket *pkt) static const uint8_t eac3_repeat[4] = {6, 3, 2, 1}; int repeat = 1; - if ((pkt->data[4] & 0xc0) != 0xc0) /* fscod */ + int bsid = pkt->data[5] >> 3; + if (bsid > 10 && (pkt->data[4] & 0xc0) != 0xc0) /* fscod */ repeat = eac3_repeat[(pkt->data[4] & 0x30) >> 4]; /* numblkscod */ ctx->hd_buf = av_fast_realloc(ctx->hd_buf, &ctx->hd_buf_size, ctx->hd_buf_filled + pkt->size); @@ -349,19 +350,18 @@ static int spdif_header_mpeg(AVFormatContext *s, AVPacket *pkt) static int spdif_header_aac(AVFormatContext *s, AVPacket *pkt) { IEC61937Context *ctx = s->priv_data; - AACADTSHeaderInfo hdr; - GetBitContext gbc; + uint32_t samples; + uint8_t frames; int ret; - init_get_bits(&gbc, pkt->data, AAC_ADTS_HEADER_SIZE * 8); - ret = avpriv_aac_parse_header(&gbc, &hdr); + ret = av_adts_header_parse(pkt->data, &samples, &frames); if (ret < 0) { av_log(s, AV_LOG_ERROR, "Wrong AAC file format\n"); - return AVERROR_INVALIDDATA; + return ret; } - ctx->pkt_offset = hdr.samples << 2; - switch (hdr.num_aac_frames) { + ctx->pkt_offset = samples << 2; + switch (frames) { case 1: ctx->data_type = IEC61937_MPEG2_AAC; break; @@ -373,7 +373,7 @@ static int spdif_header_aac(AVFormatContext *s, AVPacket *pkt) break; default: av_log(s, AV_LOG_ERROR, - "%"PRIu32" samples in AAC frame not supported\n", hdr.samples); + "%"PRIu32" samples in AAC frame not supported\n", samples); return AVERROR(EINVAL); } //TODO Data type dependent info (LC profile/SBR) diff --git a/libavformat/subfile.c b/libavformat/subfile.c index 497cf852116fd..b527f2bee17e1 100644 --- a/libavformat/subfile.c +++ b/libavformat/subfile.c @@ -72,6 +72,9 @@ static int subfile_open(URLContext *h, const char *filename, int flags, SubfileContext *c = h->priv_data; int ret; + if (!c->end) + c->end = INT64_MAX; + if (c->end <= c->start) { av_log(h, AV_LOG_ERROR, "end before start\n"); return AVERROR(EINVAL); diff --git a/libavformat/swfdec.c b/libavformat/swfdec.c index 57b619fb203d0..212157f54aeb9 100644 --- a/libavformat/swfdec.c +++ b/libavformat/swfdec.c @@ -95,7 +95,7 @@ static int swf_probe(AVProbeData *p) if (p->buf[3] >= 20 || xmax < 16 || ymax < 16) return AVPROBE_SCORE_MAX / 4; - return AVPROBE_SCORE_MAX; + return AVPROBE_SCORE_EXTENSION + 1; } #if CONFIG_ZLIB diff --git a/libavformat/swfenc.c b/libavformat/swfenc.c index cada45ef9a7bf..f53db0fb2b3ff 100644 --- a/libavformat/swfenc.c +++ b/libavformat/swfenc.c @@ -69,7 +69,7 @@ static inline void max_nbits(int *nbits_ptr, int val) if (val == 0) return; - val = abs(val); + val = FFABS(val); n = 1; while (val != 0) { n++; diff --git a/libavformat/takdec.c b/libavformat/takdec.c index 1535bec64f378..6fda35c1bef20 100644 --- a/libavformat/takdec.c +++ b/libavformat/takdec.c @@ -103,7 +103,6 @@ static int tak_read_header(AVFormatContext *s) } } - init_get_bits8(&gb, buffer, size - 3); break; case TAK_METADATA_MD5: { uint8_t md5[16]; @@ -145,7 +144,9 @@ static int tak_read_header(AVFormatContext *s) if (type == TAK_METADATA_STREAMINFO) { TAKStreamInfo ti; - avpriv_tak_parse_streaminfo(&gb, &ti); + ret = avpriv_tak_parse_streaminfo(&ti, buffer, size -3); + if (ret < 0) + return AVERROR_INVALIDDATA; if (ti.samples > 0) st->duration = ti.samples; st->codecpar->bits_per_coded_sample = ti.bps; @@ -161,11 +162,13 @@ static int tak_read_header(AVFormatContext *s) } else if (type == TAK_METADATA_LAST_FRAME) { if (size != 11) return AVERROR_INVALIDDATA; + init_get_bits8(&gb, buffer, size - 3); tc->mlast_frame = 1; tc->data_end = get_bits64(&gb, TAK_LAST_FRAME_POS_BITS) + get_bits(&gb, TAK_LAST_FRAME_SIZE_BITS); av_freep(&buffer); } else if (type == TAK_METADATA_ENCODER) { + init_get_bits8(&gb, buffer, size - 3); av_log(s, AV_LOG_VERBOSE, "encoder version: %0X\n", get_bits_long(&gb, TAK_ENCODER_VERSION_BITS)); av_freep(&buffer); diff --git a/libavformat/tcp.c b/libavformat/tcp.c index 07b4ed9fa3a8e..d6ce413235fbe 100644 --- a/libavformat/tcp.c +++ b/libavformat/tcp.c @@ -23,6 +23,8 @@ #include "libavutil/parseutils.h" #include "libavutil/opt.h" #include "libavutil/time.h" +#include "libavutil/application.h" +#include "libavutil/dns_cache.h" #include "internal.h" #include "network.h" @@ -31,6 +33,9 @@ #if HAVE_POLL_H #include #endif +#if HAVE_PTHREADS +#include +#endif typedef struct TCPContext { const AVClass *class; @@ -41,17 +46,41 @@ typedef struct TCPContext { int listen_timeout; int recv_buffer_size; int send_buffer_size; + int tcp_nodelay; + int64_t app_ctx_intptr; + + int addrinfo_one_by_one; + int addrinfo_timeout; + int64_t dns_cache_timeout; + int dns_cache_clear; + + AVApplicationContext *app_ctx; + char uri[1024]; + int fastopen; + int tcp_connected; + int fastopen_success; } TCPContext; +#define FAST_OPEN_FLAG 0x20000000 + #define OFFSET(x) offsetof(TCPContext, x) #define D AV_OPT_FLAG_DECODING_PARAM #define E AV_OPT_FLAG_ENCODING_PARAM static const AVOption options[] = { { "listen", "Listen for incoming connections", OFFSET(listen), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, .flags = D|E }, { "timeout", "set timeout (in microseconds) of socket I/O operations", OFFSET(rw_timeout), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, + { "connect_timeout", "set connect timeout (in microseconds) of socket", OFFSET(open_timeout), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, { "listen_timeout", "Connection awaiting timeout (in milliseconds)", OFFSET(listen_timeout), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, { "send_buffer_size", "Socket send buffer size (in bytes)", OFFSET(send_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, { "recv_buffer_size", "Socket receive buffer size (in bytes)", OFFSET(recv_buffer_size), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, + { "tcp_nodelay", "Use TCP_NODELAY to disable nagle's algorithm", OFFSET(tcp_nodelay), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, .flags = D|E }, + { "ijkapplication", "AVApplicationContext", OFFSET(app_ctx_intptr), AV_OPT_TYPE_INT64, { .i64 = 0 }, INT64_MIN, INT64_MAX, .flags = D }, + + { "addrinfo_one_by_one", "parse addrinfo one by one in getaddrinfo()", OFFSET(addrinfo_one_by_one), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, .flags = D|E }, + { "addrinfo_timeout", "set timeout (in microseconds) for getaddrinfo()", OFFSET(addrinfo_timeout), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, .flags = D|E }, + { "dns_cache_timeout", "dns cache TTL (in microseconds)", OFFSET(dns_cache_timeout), AV_OPT_TYPE_INT, { .i64 = 0 }, -1, INT64_MAX, .flags = D|E }, + { "dns_cache_clear", "clear dns cache", OFFSET(dns_cache_clear), AV_OPT_TYPE_INT, { .i64 = 0}, -1, INT_MAX, .flags = D|E }, + { "fastopen", "enable fastopen", OFFSET(fastopen), AV_OPT_TYPE_INT, { .i64 = 0}, 0, INT_MAX, .flags = D|E }, { NULL } }; @@ -62,6 +91,254 @@ static const AVClass tcp_class = { .version = LIBAVUTIL_VERSION_INT, }; +int ijk_tcp_getaddrinfo_nonblock(const char *hostname, const char *servname, + const struct addrinfo *hints, struct addrinfo **res, + int64_t timeout, + const AVIOInterruptCB *int_cb, int one_by_one); +#ifdef HAVE_PTHREADS + +typedef struct TCPAddrinfoRequest +{ + AVBufferRef *buffer; + + pthread_mutex_t mutex; + pthread_cond_t cond; + + AVIOInterruptCB interrupt_callback; + + char *hostname; + char *servname; + struct addrinfo hints; + struct addrinfo *res; + + volatile int finished; + int last_error; +} TCPAddrinfoRequest; + +static void tcp_getaddrinfo_request_free(TCPAddrinfoRequest *req) +{ + av_assert0(req); + if (req->res) { + freeaddrinfo(req->res); + req->res = NULL; + } + + av_freep(&req->servname); + av_freep(&req->hostname); + pthread_cond_destroy(&req->cond); + pthread_mutex_destroy(&req->mutex); + av_freep(&req); +} + +static void tcp_getaddrinfo_request_free_buffer(void *opaque, uint8_t *data) +{ + av_assert0(opaque); + TCPAddrinfoRequest *req = (TCPAddrinfoRequest *)opaque; + tcp_getaddrinfo_request_free(req); +} + +static int tcp_getaddrinfo_request_create(TCPAddrinfoRequest **request, + const char *hostname, + const char *servname, + const struct addrinfo *hints, + const AVIOInterruptCB *int_cb) +{ + TCPAddrinfoRequest *req = (TCPAddrinfoRequest *) av_mallocz(sizeof(TCPAddrinfoRequest)); + if (!req) + return AVERROR(ENOMEM); + + if (pthread_mutex_init(&req->mutex, NULL)) { + av_freep(&req); + return AVERROR(ENOMEM); + } + + if (pthread_cond_init(&req->cond, NULL)) { + pthread_mutex_destroy(&req->mutex); + av_freep(&req); + return AVERROR(ENOMEM); + } + + if (int_cb) + req->interrupt_callback = *int_cb; + + if (hostname) { + req->hostname = av_strdup(hostname); + if (!req->hostname) + goto fail; + } + + if (servname) { + req->servname = av_strdup(servname); + if (!req->hostname) + goto fail; + } + + if (hints) { + req->hints.ai_family = hints->ai_family; + req->hints.ai_socktype = hints->ai_socktype; + req->hints.ai_protocol = hints->ai_protocol; + req->hints.ai_flags = hints->ai_flags; + } + + req->buffer = av_buffer_create(NULL, 0, tcp_getaddrinfo_request_free_buffer, req, 0); + if (!req->buffer) + goto fail; + + *request = req; + return 0; +fail: + tcp_getaddrinfo_request_free(req); + return AVERROR(ENOMEM); +} + +static void *tcp_getaddrinfo_worker(void *arg) +{ + TCPAddrinfoRequest *req = arg; + + getaddrinfo(req->hostname, req->servname, &req->hints, &req->res); + pthread_mutex_lock(&req->mutex); + req->finished = 1; + pthread_cond_signal(&req->cond); + pthread_mutex_unlock(&req->mutex); + av_buffer_unref(&req->buffer); + return NULL; +} + +static void *tcp_getaddrinfo_one_by_one_worker(void *arg) +{ + struct addrinfo *temp_addrinfo = NULL; + struct addrinfo *cur = NULL; + int ret = EAI_FAIL; + int i = 0; + int option_length = 0; + + TCPAddrinfoRequest *req = (TCPAddrinfoRequest *)arg; + + int family_option[2] = {AF_INET, AF_INET6}; + + option_length = sizeof(family_option) / sizeof(family_option[0]); + + for (; i < option_length; ++i) { + struct addrinfo *hint = &req->hints; + hint->ai_family = family_option[i]; + ret = getaddrinfo(req->hostname, req->servname, hint, &temp_addrinfo); + if (ret) { + req->last_error = ret; + continue; + } + pthread_mutex_lock(&req->mutex); + if (!req->res) { + req->res = temp_addrinfo; + } else { + cur = req->res; + while (cur->ai_next) + cur = cur->ai_next; + cur->ai_next = temp_addrinfo; + } + pthread_mutex_unlock(&req->mutex); + } + pthread_mutex_lock(&req->mutex); + req->finished = 1; + pthread_cond_signal(&req->cond); + pthread_mutex_unlock(&req->mutex); + av_buffer_unref(&req->buffer); + return NULL; +} + +int ijk_tcp_getaddrinfo_nonblock(const char *hostname, const char *servname, + const struct addrinfo *hints, struct addrinfo **res, + int64_t timeout, + const AVIOInterruptCB *int_cb, int one_by_one) +{ + int ret; + int64_t start; + int64_t now; + AVBufferRef *req_ref = NULL; + TCPAddrinfoRequest *req = NULL; + pthread_t work_thread; + + if (hostname && !hostname[0]) + hostname = NULL; + + if (timeout <= 0) + return getaddrinfo(hostname, servname, hints, res); + + ret = tcp_getaddrinfo_request_create(&req, hostname, servname, hints, int_cb); + if (ret) + goto fail; + + req_ref = av_buffer_ref(req->buffer); + if (req_ref == NULL) { + ret = AVERROR(ENOMEM); + goto fail; + } + + /* FIXME: using a thread pool would be better. */ + if (one_by_one) + ret = pthread_create(&work_thread, NULL, tcp_getaddrinfo_one_by_one_worker, req); + else + ret = pthread_create(&work_thread, NULL, tcp_getaddrinfo_worker, req); + + if (ret) { + ret = AVERROR(ret); + goto fail; + } + + pthread_detach(work_thread); + + start = av_gettime(); + now = start; + + pthread_mutex_lock(&req->mutex); + while (1) { + int64_t wait_time = now + 100000; + struct timespec tv = { .tv_sec = wait_time / 1000000, + .tv_nsec = (wait_time % 1000000) * 1000 }; + + if (req->finished || (start + timeout < now)) { + if (req->res) { + ret = 0; + *res = req->res; + req->res = NULL; + } else { + ret = req->last_error ? req->last_error : AVERROR_EXIT; + } + break; + } +#if defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC) + ret = pthread_cond_timedwait_monotonic_np(&req->cond, &req->mutex, &tv); +#else + ret = pthread_cond_timedwait(&req->cond, &req->mutex, &tv); +#endif + if (ret != 0 && ret != ETIMEDOUT) { + av_log(NULL, AV_LOG_ERROR, "pthread_cond_timedwait failed: %d\n", ret); + ret = AVERROR_EXIT; + break; + } + + if (ff_check_interrupt(&req->interrupt_callback)) { + ret = AVERROR_EXIT; + break; + } + + now = av_gettime(); + } + pthread_mutex_unlock(&req->mutex); +fail: + av_buffer_unref(&req_ref); + return ret; +} + +#else +int ijk_tcp_getaddrinfo_nonblock(const char *hostname, const char *servname, + const struct addrinfo *hints, struct addrinfo **res, + int64_t timeout, + const AVIOInterruptCB *int_cb) +{ + return getaddrinfo(hostname, servname, hints, res); +} +#endif + /* return non zero if error */ static int tcp_open(URLContext *h, const char *uri, int flags) { @@ -73,7 +350,20 @@ static int tcp_open(URLContext *h, const char *uri, int flags) int ret; char hostname[1024],proto[1024],path[1024]; char portstr[10]; - s->open_timeout = 5000000; + AVAppTcpIOControl control = {0}; + DnsCacheEntry *dns_entry = NULL; + + if (s->open_timeout < 0) { + s->open_timeout = 15000000; + } + + s->app_ctx = (AVApplicationContext *)(intptr_t)s->app_ctx_intptr; + + if (s->fastopen) { + s->tcp_connected = 0; + strcpy(s->uri, uri); + return 0; + } av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), &port, path, sizeof(path), uri); @@ -94,32 +384,57 @@ static int tcp_open(URLContext *h, const char *uri, int flags) } if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) { s->rw_timeout = strtol(buf, NULL, 10); + if (s->rw_timeout >= 0) { + s->open_timeout = s->rw_timeout; + } } if (av_find_info_tag(buf, sizeof(buf), "listen_timeout", p)) { s->listen_timeout = strtol(buf, NULL, 10); } } - if (s->rw_timeout >= 0) { - s->open_timeout = - h->rw_timeout = s->rw_timeout; + if (s->rw_timeout >= 0 ) { + h->rw_timeout = s->rw_timeout; } + hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; snprintf(portstr, sizeof(portstr), "%d", port); if (s->listen) hints.ai_flags |= AI_PASSIVE; - if (!hostname[0]) - ret = getaddrinfo(NULL, portstr, &hints, &ai); - else - ret = getaddrinfo(hostname, portstr, &hints, &ai); - if (ret) { - av_log(h, AV_LOG_ERROR, - "Failed to resolve hostname %s: %s\n", - hostname, gai_strerror(ret)); - return AVERROR(EIO); + + if (s->dns_cache_timeout > 0) { + if (s->dns_cache_clear) { + av_log(NULL, AV_LOG_INFO, "will delete dns cache entry, uri = %s\n", uri); + remove_dns_cache_entry(uri); + } else { + dns_entry = get_dns_cache_reference(uri); + } } - cur_ai = ai; + if (!dns_entry) { +#ifdef HAVE_PTHREADS + ret = ijk_tcp_getaddrinfo_nonblock(hostname, portstr, &hints, &ai, s->addrinfo_timeout, &h->interrupt_callback, s->addrinfo_one_by_one); +#else + if (s->addrinfo_timeout > 0) + av_log(h, AV_LOG_WARNING, "Ignore addrinfo_timeout without pthreads support.\n"); + if (!hostname[0]) + ret = getaddrinfo(NULL, portstr, &hints, &ai); + else + ret = getaddrinfo(hostname, portstr, &hints, &ai); +#endif + + if (ret) { + av_log(h, AV_LOG_ERROR, + "Failed to resolve hostname %s: %s\n", + hostname, gai_strerror(ret)); + return AVERROR(EIO); + } + + cur_ai = ai; + } else { + av_log(NULL, AV_LOG_INFO, "hit dns cache uri = %s\n", uri); + cur_ai = dns_entry->res; + } restart: #if HAVE_STRUCT_SOCKADDR_IN6 @@ -148,6 +463,9 @@ static int tcp_open(URLContext *h, const char *uri, int flags) if (s->send_buffer_size > 0) { setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &s->send_buffer_size, sizeof (s->send_buffer_size)); } + if (s->tcp_nodelay > 0) { + setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &s->tcp_nodelay, sizeof (s->tcp_nodelay)); + } if (s->listen == 2) { // multi-client @@ -161,20 +479,233 @@ static int tcp_open(URLContext *h, const char *uri, int flags) // Socket descriptor already closed here. Safe to overwrite to client one. fd = ret; } else { + ret = av_application_on_tcp_will_open(s->app_ctx); + if (ret) { + av_log(NULL, AV_LOG_WARNING, "terminated by application in AVAPP_CTRL_WILL_TCP_OPEN"); + goto fail1; + } + if ((ret = ff_listen_connect(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, s->open_timeout / 1000, h, !!cur_ai->ai_next)) < 0) { + if (ret == AVERROR(ETIMEDOUT)) { + ret = AVERROR_TCP_CONNECT_TIMEOUT; + } + if (av_application_on_tcp_did_open(s->app_ctx, ret, fd, &control)) + goto fail1; + if (ret == AVERROR_EXIT) + goto fail1; + else + goto fail; + } else { + ret = av_application_on_tcp_did_open(s->app_ctx, 0, fd, &control); + if (ret) { + av_log(NULL, AV_LOG_WARNING, "terminated by application in AVAPP_CTRL_DID_TCP_OPEN"); + goto fail1; + } else if (!dns_entry && !strstr(uri, control.ip) && s->dns_cache_timeout > 0) { + add_dns_cache_entry(uri, cur_ai, s->dns_cache_timeout); + av_log(NULL, AV_LOG_INFO, "add dns cache uri = %s, ip = %s\n", uri , control.ip); + } + av_log(NULL, AV_LOG_INFO, "tcp did open uri = %s, ip = %s\n", uri , control.ip); + } + } + + h->is_streamed = 1; + s->fd = fd; + if (dns_entry) { + release_dns_cache_reference(uri, &dns_entry); + } else { + freeaddrinfo(ai); + } + return 0; + + fail: + if (cur_ai->ai_next) { + /* Retry with the next sockaddr */ + cur_ai = cur_ai->ai_next; + if (fd >= 0) + closesocket(fd); + ret = 0; + goto restart; + } + fail1: + if (fd >= 0) + closesocket(fd); + + if (dns_entry) { + av_log(NULL, AV_LOG_ERROR, "hit dns cache but connect fail uri = %s, ip = %s\n", uri , control.ip); + release_dns_cache_reference(uri, &dns_entry); + remove_dns_cache_entry(uri); + } else { + freeaddrinfo(ai); + } + + return ret; +} + +/* return non zero if error */ +static int tcp_fast_open(URLContext *h, const char *http_request, const char *uri, int flags) +{ + struct addrinfo hints = { 0 }, *ai, *cur_ai; + int port, fd = -1; + TCPContext *s = h->priv_data; + const char *p; + char buf[256]; + int ret; + char hostname[1024],proto[1024],path[1024]; + char portstr[10]; + AVAppTcpIOControl control = {0}; + DnsCacheEntry *dns_entry = NULL; + av_url_split(proto, sizeof(proto), NULL, 0, hostname, sizeof(hostname), + &port, path, sizeof(path), uri); + if (strcmp(proto, "tcp")) + return AVERROR(EINVAL); + if (port <= 0 || port >= 65536) { + av_log(h, AV_LOG_ERROR, "Port missing in uri\n"); + return AVERROR(EINVAL); + } + p = strchr(uri, '?'); + + if (p) { + if (av_find_info_tag(buf, sizeof(buf), "listen", p)) { + char *endptr = NULL; + s->listen = strtol(buf, &endptr, 10); + /* assume if no digits were found it is a request to enable it */ + if (buf == endptr) + s->listen = 1; + } + if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) { + s->rw_timeout = strtol(buf, NULL, 10); + if (s->rw_timeout >= 0) { + s->open_timeout = s->rw_timeout; + } + } + if (av_find_info_tag(buf, sizeof(buf), "listen_timeout", p)) { + s->listen_timeout = strtol(buf, NULL, 10); + } + } + if (s->rw_timeout >= 0 ) { + h->rw_timeout = s->rw_timeout; + } + + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + snprintf(portstr, sizeof(portstr), "%d", port); + if (s->listen) + hints.ai_flags |= AI_PASSIVE; + + if (s->dns_cache_timeout > 0) { + if (s->dns_cache_clear) { + av_log(NULL, AV_LOG_INFO, "will delete dns cache entry, uri = %s\n", uri); + remove_dns_cache_entry(uri); + } else { + dns_entry = get_dns_cache_reference(uri); + } + } + + if (!dns_entry) { +#ifdef HAVE_PTHREADS + ret = ijk_tcp_getaddrinfo_nonblock(hostname, portstr, &hints, &ai, s->addrinfo_timeout, &h->interrupt_callback, s->addrinfo_one_by_one); +#else + if (s->addrinfo_timeout > 0) + av_log(h, AV_LOG_WARNING, "Ignore addrinfo_timeout without pthreads support.\n"); + if (!hostname[0]) + ret = getaddrinfo(NULL, portstr, &hints, &ai); + else + ret = getaddrinfo(hostname, portstr, &hints, &ai); +#endif + + if (ret) { + av_log(h, AV_LOG_ERROR, + "Failed to resolve hostname %s: %s\n", + hostname, gai_strerror(ret)); + return AVERROR(EIO); + } + + cur_ai = ai; + } else { + av_log(NULL, AV_LOG_INFO, "hit dns cache uri = %s\n", uri); + cur_ai = dns_entry->res; + } + + restart: +#if HAVE_STRUCT_SOCKADDR_IN6 + // workaround for IOS9 getaddrinfo in IPv6 only network use hardcode IPv4 address can not resolve port number. + if (cur_ai->ai_family == AF_INET6){ + struct sockaddr_in6 * sockaddr_v6 = (struct sockaddr_in6 *)cur_ai->ai_addr; + if (!sockaddr_v6->sin6_port){ + sockaddr_v6->sin6_port = htons(port); + } + } +#endif + fd = ff_socket(cur_ai->ai_family, + cur_ai->ai_socktype, + cur_ai->ai_protocol); + if (fd < 0) { + ret = ff_neterrno(); + goto fail; + } + /* Set the socket's send or receive buffer sizes, if specified. + If unspecified or setting fails, system default is used. */ + if (s->recv_buffer_size > 0) { + setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &s->recv_buffer_size, sizeof (s->recv_buffer_size)); + } + if (s->send_buffer_size > 0) { + setsockopt (fd, SOL_SOCKET, SO_SNDBUF, &s->send_buffer_size, sizeof (s->send_buffer_size)); + } + if (s->listen == 2) { + // multi-client + if ((ret = ff_listen(fd, cur_ai->ai_addr, cur_ai->ai_addrlen)) < 0) + goto fail1; + } else if (s->listen == 1) { + // single client + if ((ret = ff_listen_bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen, + s->listen_timeout, h)) < 0) + goto fail1; + // Socket descriptor already closed here. Safe to overwrite to client one. + fd = ret; + } else { + ret = av_application_on_tcp_will_open(s->app_ctx); + if (ret) { + av_log(NULL, AV_LOG_WARNING, "terminated by application in AVAPP_CTRL_WILL_TCP_OPEN"); + goto fail1; + } + + if ((ret = ff_sendto(fd, http_request, strlen(http_request), FAST_OPEN_FLAG, + cur_ai->ai_addr, cur_ai->ai_addrlen, s->open_timeout / 1000, h, !!cur_ai->ai_next)) < 0) { + s->fastopen_success = 0; + if (av_application_on_tcp_did_open(s->app_ctx, ret, fd, &control)) + goto fail1; if (ret == AVERROR_EXIT) goto fail1; else goto fail; + } else { + if (ret == 0) { + s->fastopen_success = 0; + } else { + s->fastopen_success = 1; + } + ret = av_application_on_tcp_did_open(s->app_ctx, 0, fd, &control); + if (ret) { + av_log(NULL, AV_LOG_WARNING, "terminated by application in AVAPP_CTRL_DID_TCP_OPEN"); + goto fail1; + } else if (!dns_entry && !strstr(uri, control.ip) && s->dns_cache_timeout > 0) { + add_dns_cache_entry(uri, cur_ai, s->dns_cache_timeout); + av_log(NULL, AV_LOG_INFO, "add dns cache uri = %s, ip = %s\n", uri , control.ip); + } + av_log(NULL, AV_LOG_INFO, "tcp did open uri = %s, ip = %s\n", uri , control.ip); } } h->is_streamed = 1; s->fd = fd; - freeaddrinfo(ai); + if (dns_entry) { + release_dns_cache_reference(uri, &dns_entry); + } else { + freeaddrinfo(ai); + } return 0; fail: @@ -189,7 +720,15 @@ static int tcp_open(URLContext *h, const char *uri, int flags) fail1: if (fd >= 0) closesocket(fd); - freeaddrinfo(ai); + + if (dns_entry) { + av_log(NULL, AV_LOG_ERROR, "hit dns cache but connect fail uri = %s, ip = %s\n", uri , control.ip); + release_dns_cache_reference(uri, &dns_entry); + remove_dns_cache_entry(uri); + } else { + freeaddrinfo(ai); + } + return ret; } @@ -216,10 +755,18 @@ static int tcp_read(URLContext *h, uint8_t *buf, int size) if (!(h->flags & AVIO_FLAG_NONBLOCK)) { ret = ff_network_wait_fd_timeout(s->fd, 0, h->rw_timeout, &h->interrupt_callback); - if (ret) + if (ret) { + if (ret == AVERROR(ETIMEDOUT)) { + ret = AVERROR_TCP_READ_TIMEOUT; + } return ret; + } } ret = recv(s->fd, buf, size, 0); + if (ret == 0) + return AVERROR_EOF; + if (ret > 0) + av_application_did_io_tcp_read(s->app_ctx, (void*)h, ret); return ret < 0 ? ff_neterrno() : ret; } @@ -230,9 +777,32 @@ static int tcp_write(URLContext *h, const uint8_t *buf, int size) if (!(h->flags & AVIO_FLAG_NONBLOCK)) { ret = ff_network_wait_fd_timeout(s->fd, 1, h->rw_timeout, &h->interrupt_callback); - if (ret) + if (ret) { + if (ret == AVERROR(ETIMEDOUT)) { + ret = AVERROR_TCP_WRITE_TIMEOUT; + } return ret; + } } + + if (s->fastopen && !s->tcp_connected && av_stristart(buf, "GET", NULL)) { + ret = tcp_fast_open(h, buf, s->uri, 0); + if (!ret) { + s->tcp_connected = 1; + if (!s->fastopen_success) { + ret = send(s->fd, buf, size, MSG_NOSIGNAL); + if (ret > 0) { + s->fastopen_success = 1; + } + return ret < 0 ? ff_neterrno() : ret; + } + return ret; + } else { + av_log(NULL, AV_LOG_WARNING, "tcp_fast_open is error ret = %d\n", ret); + return ret; + } + } + ret = send(s->fd, buf, size, MSG_NOSIGNAL); return ret < 0 ? ff_neterrno() : ret; } @@ -270,7 +840,7 @@ static int tcp_get_window_size(URLContext *h) { TCPContext *s = h->priv_data; int avail; - int avail_len = sizeof(avail); + socklen_t avail_len = sizeof(avail); #if HAVE_WINSOCK2_H /* SO_RCVBUF with winsock only reports the actual TCP window size when diff --git a/libavformat/tee.c b/libavformat/tee.c index dd1844ac0e162..ef3b113a47180 100644 --- a/libavformat/tee.c +++ b/libavformat/tee.c @@ -406,7 +406,7 @@ static void log_slave(TeeSlave *slave, void *log_ctx, int log_level) { int i; av_log(log_ctx, log_level, "filename:'%s' format:%s\n", - slave->avf->filename, slave->avf->oformat->name); + slave->avf->url, slave->avf->oformat->name); for (i = 0; i < slave->avf->nb_streams; i++) { AVStream *st = slave->avf->streams[i]; AVBSFContext *bsf = slave->bsfs[i]; @@ -448,7 +448,7 @@ static int tee_write_header(AVFormatContext *avf) { TeeContext *tee = avf->priv_data; unsigned nb_slaves = 0, i; - const char *filename = avf->filename; + const char *filename = avf->url; char **slaves = NULL; int ret; diff --git a/libavformat/tests/fifo_muxer.c b/libavformat/tests/fifo_muxer.c index e20bd6e7b2b1c..5127a8aadb926 100644 --- a/libavformat/tests/fifo_muxer.c +++ b/libavformat/tests/fifo_muxer.c @@ -31,8 +31,6 @@ #define SLEEPTIME_50_MS 50000 #define SLEEPTIME_10_MS 10000 -/* Implementation of mock muxer to simulate real muxer failures */ - /* This is structure of data sent in packets to * failing muxer */ typedef struct FailingMuxerPacketData { @@ -41,113 +39,7 @@ typedef struct FailingMuxerPacketData { unsigned sleep_time; /* sleep for this long in write_packet to simulate long I/O operation */ } FailingMuxerPacketData; - -typedef struct FailingMuxerContext { - AVClass *class; - int write_header_ret; - int write_trailer_ret; - /* If non-zero, summary of processed packets will be printed in deinit */ - int print_deinit_summary; - - int flush_count; - int pts_written[MAX_TST_PACKETS]; - int pts_written_nr; -} FailingMuxerContext; - -static int failing_write_header(AVFormatContext *avf) -{ - FailingMuxerContext *ctx = avf->priv_data; - return ctx->write_header_ret; -} - -static int failing_write_packet(AVFormatContext *avf, AVPacket *pkt) -{ - FailingMuxerContext *ctx = avf->priv_data; - int ret = 0; - if (!pkt) { - ctx->flush_count++; - } else { - FailingMuxerPacketData *data = (FailingMuxerPacketData*) pkt->data; - - if (!data->recover_after) { - data->ret = 0; - } else { - data->recover_after--; - } - - ret = data->ret; - - if (data->sleep_time) { - int64_t slept = 0; - while (slept < data->sleep_time) { - if (ff_check_interrupt(&avf->interrupt_callback)) - return AVERROR_EXIT; - av_usleep(SLEEPTIME_10_MS); - slept += SLEEPTIME_10_MS; - } - } - - if (!ret) { - ctx->pts_written[ctx->pts_written_nr++] = pkt->pts; - av_packet_unref(pkt); - } - } - return ret; -} - -static int failing_write_trailer(AVFormatContext *avf) -{ - FailingMuxerContext *ctx = avf->priv_data; - return ctx->write_trailer_ret; -} - -static void failing_deinit(AVFormatContext *avf) -{ - int i; - FailingMuxerContext *ctx = avf->priv_data; - - if (!ctx->print_deinit_summary) - return; - - printf("flush count: %d\n", ctx->flush_count); - printf("pts seen nr: %d\n", ctx->pts_written_nr); - printf("pts seen: "); - for (i = 0; i < ctx->pts_written_nr; ++i ) { - printf(i ? ",%d" : "%d", ctx->pts_written[i]); - } - printf("\n"); -} -#define OFFSET(x) offsetof(FailingMuxerContext, x) -static const AVOption options[] = { - {"write_header_ret", "write_header() return value", OFFSET(write_header_ret), - AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM}, - {"write_trailer_ret", "write_trailer() return value", OFFSET(write_trailer_ret), - AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM}, - {"print_deinit_summary", "print summary when deinitializing muxer", OFFSET(print_deinit_summary), - AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM}, - {NULL} - }; - -static const AVClass failing_muxer_class = { - .class_name = "Failing test muxer", - .item_name = av_default_item_name, - .option = options, - .version = LIBAVUTIL_VERSION_INT, -}; - -AVOutputFormat tst_failing_muxer = { - .name = "fail", - .long_name = NULL_IF_CONFIG_SMALL("Failing test muxer"), - .priv_data_size = sizeof(FailingMuxerContext), - .write_header = failing_write_header, - .write_packet = failing_write_packet, - .write_trailer = failing_write_trailer, - .deinit = failing_deinit, - .priv_class = &failing_muxer_class, - .flags = AVFMT_NOFILE | AVFMT_ALLOW_FLUSH, -}; - -static int prepare_packet(AVPacket *pkt,const FailingMuxerPacketData *pkt_data, int64_t pts) +static int prepare_packet(AVPacket *pkt, const FailingMuxerPacketData *pkt_data, int64_t pts) { int ret; FailingMuxerPacketData *data = av_malloc(sizeof(*data)); @@ -238,54 +130,6 @@ static int fifo_basic_test(AVFormatContext *oc, AVDictionary **opts, return ret; } -static int fifo_write_header_err_tst(AVFormatContext *oc, AVDictionary **opts, - const FailingMuxerPacketData *pkt_data) -{ - int ret = 0, i; - AVPacket pkt; - - av_init_packet(&pkt); - - ret = avformat_write_header(oc, opts); - if (ret) { - fprintf(stderr, "Unexpected write_header failure: %s\n", - av_err2str(ret)); - goto fail; - } - - for (i = 0; i < MAX_TST_PACKETS; i++ ) { - ret = prepare_packet(&pkt, pkt_data, i); - if (ret < 0) { - fprintf(stderr, "Failed to prepare test packet: %s\n", - av_err2str(ret)); - goto write_trailer_and_fail; - } - ret = av_write_frame(oc, &pkt); - av_packet_unref(&pkt); - if (ret < 0) { - break; - } - } - - if (!ret) { - fprintf(stderr, "write_packet not failed when supposed to.\n"); - goto fail; - } else if (ret != -1) { - fprintf(stderr, "Unexpected write_packet error: %s\n", av_err2str(ret)); - goto fail; - } - - ret = av_write_trailer(oc); - if (ret < 0) - fprintf(stderr, "Unexpected write_trailer error: %s\n", av_err2str(ret)); - - return ret; -write_trailer_and_fail: - av_write_trailer(oc); -fail: - return ret; -} - static int fifo_overflow_drop_test(AVFormatContext *oc, AVDictionary **opts, const FailingMuxerPacketData *data) { @@ -381,7 +225,7 @@ static int run_test(const TestCase *test) (int)test->print_summary_on_deinit, test->write_header_ret, test->write_trailer_ret); ret = av_dict_set(&opts, "format_opts", buffer, 0); - ret1 = av_dict_set(&opts, "fifo_format", "fail", 0); + ret1 = av_dict_set(&opts, "fifo_format", "fifo_test", 0); if (ret < 0 || ret1 < 0) { fprintf(stderr, "Failed to set options for test muxer: %s\n", av_err2str(ret)); @@ -403,10 +247,6 @@ const TestCase tests[] = { * exactly what was on input */ {fifo_basic_test, "nonfail test", NULL,1, 0, 0, {0, 0, 0}}, - /* Test that we receive delayed write_header error from one of the write_packet - * calls. */ - {fifo_write_header_err_tst, "write header error test", NULL, 0, -1, 0, {0, 0, 0}}, - /* Each write_packet will fail 3 times before operation is successful. If recovery * Since recovery is on, fifo muxer should not return any errors. */ {fifo_basic_test, "recovery test", "attempt_recovery=1:recovery_wait_time=0", @@ -434,9 +274,6 @@ int main(int argc, char *argv[]) { int i, ret, ret_all = 0; - av_register_all(); - av_register_output_format(&tst_failing_muxer); - for (i = 0; tests[i].test_func; i++) { ret = run_test(&tests[i]); if (!ret_all && ret < 0) diff --git a/libavformat/tests/movenc.c b/libavformat/tests/movenc.c index 8e59b74259e92..1d15d97ad92df 100644 --- a/libavformat/tests/movenc.c +++ b/libavformat/tests/movenc.c @@ -115,6 +115,7 @@ static int io_write_data_type(void *opaque, uint8_t *buf, int size, case AVIO_DATA_MARKER_BOUNDARY_POINT: str = "boundary"; break; case AVIO_DATA_MARKER_UNKNOWN: str = "unknown"; break; case AVIO_DATA_MARKER_TRAILER: str = "trailer"; break; + default: str = "unknown"; break; } if (time == AV_NOPTS_VALUE) snprintf(timebuf, sizeof(timebuf), "nopts"); @@ -378,8 +379,6 @@ int main(int argc, char **argv) } } - av_register_all(); - md5 = av_md5_alloc(); if (!md5) return 1; diff --git a/libavformat/tests/seek.c b/libavformat/tests/seek.c index 5cf3a123e33fb..e0067a64fc371 100644 --- a/libavformat/tests/seek.c +++ b/libavformat/tests/seek.c @@ -67,8 +67,6 @@ int main(int argc, char **argv) int frame_count = 1; int duration = 4; - ic->flags |= AVFMT_FLAG_KEEP_SIDE_DATA; - for(i=2; ipriv_data; - int ret = gnutls_record_recv(c->session, buf, size); + int ret; + // Set or clear the AVIO_FLAG_NONBLOCK on c->tls_shared.tcp + c->tls_shared.tcp->flags &= ~AVIO_FLAG_NONBLOCK; + c->tls_shared.tcp->flags |= h->flags & AVIO_FLAG_NONBLOCK; + ret = gnutls_record_recv(c->session, buf, size); if (ret > 0) return ret; if (ret == 0) @@ -234,7 +245,11 @@ static int tls_read(URLContext *h, uint8_t *buf, int size) static int tls_write(URLContext *h, const uint8_t *buf, int size) { TLSContext *c = h->priv_data; - int ret = gnutls_record_send(c->session, buf, size); + int ret; + // Set or clear the AVIO_FLAG_NONBLOCK on c->tls_shared.tcp + c->tls_shared.tcp->flags &= ~AVIO_FLAG_NONBLOCK; + c->tls_shared.tcp->flags |= h->flags & AVIO_FLAG_NONBLOCK; + ret = gnutls_record_send(c->session, buf, size); if (ret > 0) return ret; if (ret == 0) @@ -260,7 +275,7 @@ static const AVClass tls_class = { .version = LIBAVUTIL_VERSION_INT, }; -const URLProtocol ff_tls_gnutls_protocol = { +const URLProtocol ff_tls_protocol = { .name = "tls", .url_open2 = tls_open, .url_read = tls_read, diff --git a/libavformat/tls_libtls.c b/libavformat/tls_libtls.c new file mode 100644 index 0000000000000..ba83b56ffe2a3 --- /dev/null +++ b/libavformat/tls_libtls.c @@ -0,0 +1,207 @@ +/* + * TLS/SSL Protocol + * Copyright (c) 2011 Martin Storsjo + * Copyright (c) 2017 sfan5 + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avformat.h" +#include "internal.h" +#include "network.h" +#include "url.h" +#include "tls.h" +#include "libavcodec/internal.h" +#include "libavutil/avutil.h" +#include "libavutil/opt.h" + +#include + +typedef struct TLSContext { + const AVClass *class; + TLSShared tls_shared; + struct tls *ctx; +} TLSContext; + +static int ff_tls_close(URLContext *h) +{ + TLSContext *p = h->priv_data; + if (p->ctx) { + tls_close(p->ctx); + tls_free(p->ctx); + } + if (p->tls_shared.tcp) + ffurl_close(p->tls_shared.tcp); + return 0; +} + +static ssize_t tls_read_callback(struct tls *ctx, void *buf, size_t buflen, void *cb_arg) +{ + URLContext *h = (URLContext*) cb_arg; + int ret = ffurl_read(h, buf, buflen); + if (ret == AVERROR(EAGAIN)) + return TLS_WANT_POLLIN; + else if (ret == AVERROR_EXIT) + return 0; + return ret >= 0 ? ret : -1; +} + +static ssize_t tls_write_callback(struct tls *ctx, const void *buf, size_t buflen, void *cb_arg) +{ + URLContext *h = (URLContext*) cb_arg; + int ret = ffurl_write(h, buf, buflen); + if (ret == AVERROR(EAGAIN)) + return TLS_WANT_POLLOUT; + else if (ret == AVERROR_EXIT) + return 0; + return ret >= 0 ? ret : -1; +} + +static int ff_tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options) +{ + TLSContext *p = h->priv_data; + TLSShared *c = &p->tls_shared; + struct tls_config *cfg = NULL; + int ret; + + if (tls_init() == -1) { + ret = AVERROR(EIO); + goto fail; + } + + if ((ret = ff_tls_open_underlying(c, h, uri, options)) < 0) + goto fail; + + p->ctx = !c->listen ? tls_client() : tls_server(); + if (!p->ctx) { + ret = AVERROR(EIO); + goto fail; + } + + cfg = tls_config_new(); + if (!p->ctx) { + ret = AVERROR(EIO); + goto fail; + } + if (tls_config_set_protocols(cfg, TLS_PROTOCOLS_ALL) == -1) + goto err_config; + // While TLSv1.0 and TLSv1.1 are already enabled by the above, + // we need to be less strict with ciphers so it works in practice. + if (tls_config_set_ciphers(cfg, "compat") == -1) + goto err_config; + if (c->ca_file && tls_config_set_ca_file(cfg, c->ca_file) == -1) + goto err_config; + if (c->cert_file && tls_config_set_cert_file(cfg, c->cert_file) == -1) + goto err_config; + if (c->key_file && tls_config_set_key_file(cfg, c->key_file) == -1) + goto err_config; + if (!c->verify) { + tls_config_insecure_noverifycert(cfg); + tls_config_insecure_noverifyname(cfg); + tls_config_insecure_noverifytime(cfg); + } + if (tls_configure(p->ctx, cfg) == -1) + goto err_ctx; + + if (!c->listen) { + ret = tls_connect_cbs(p->ctx, tls_read_callback, tls_write_callback, + c->tcp, c->host); + } else { + struct tls *ctx_new; + ret = tls_accept_cbs(p->ctx, &ctx_new, tls_read_callback, + tls_write_callback, c->tcp); + if (ret == 0) { + // free "server" context and replace by "connection" context + tls_free(p->ctx); + p->ctx = ctx_new; + } + } + if (ret == -1) + goto err_ctx; + + tls_config_free(cfg); + return 0; +err_config: + av_log(h, AV_LOG_ERROR, "%s\n", tls_config_error(cfg)); + ret = AVERROR(EIO); + goto fail; +err_ctx: + av_log(h, AV_LOG_ERROR, "%s\n", tls_error(p->ctx)); + ret = AVERROR(EIO); + /* fallthrough */ +fail: + if (cfg) + tls_config_free(cfg); + ff_tls_close(h); + return ret; +} + +static int ff_tls_read(URLContext *h, uint8_t *buf, int size) +{ + TLSContext *p = h->priv_data; + ssize_t ret; + ret = tls_read(p->ctx, buf, size); + if (ret > 0) + return ret; + else if (ret == 0) + return AVERROR_EOF; + av_log(h, AV_LOG_ERROR, "%s\n", tls_error(p->ctx)); + return AVERROR(EIO); +} + +static int ff_tls_write(URLContext *h, const uint8_t *buf, int size) +{ + TLSContext *p = h->priv_data; + ssize_t ret; + ret = tls_write(p->ctx, buf, size); + if (ret > 0) + return ret; + else if (ret == 0) + return AVERROR_EOF; + av_log(h, AV_LOG_ERROR, "%s\n", tls_error(p->ctx)); + return AVERROR(EIO); +} + +static int tls_get_file_handle(URLContext *h) +{ + TLSContext *c = h->priv_data; + return ffurl_get_file_handle(c->tls_shared.tcp); +} + +static const AVOption options[] = { + TLS_COMMON_OPTIONS(TLSContext, tls_shared), + { NULL } +}; + +static const AVClass tls_class = { + .class_name = "tls", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const URLProtocol ff_tls_protocol = { + .name = "tls", + .url_open2 = ff_tls_open, + .url_read = ff_tls_read, + .url_write = ff_tls_write, + .url_close = ff_tls_close, + .url_get_file_handle = tls_get_file_handle, + .priv_data_size = sizeof(TLSContext), + .flags = URL_PROTOCOL_FLAG_NETWORK, + .priv_data_class = &tls_class, +}; diff --git a/libavformat/tls_openssl.c b/libavformat/tls_openssl.c index 38af8a21c0037..59a86150a793d 100644 --- a/libavformat/tls_openssl.c +++ b/libavformat/tls_openssl.c @@ -66,6 +66,85 @@ static unsigned long openssl_thread_id(void) #endif #endif +int ff_openssl_init(void) +{ + ff_lock_avformat(); + if (!openssl_init) { + SSL_library_init(); + SSL_load_error_strings(); +#if HAVE_THREADS + if (!CRYPTO_get_locking_callback()) { + int i; + openssl_mutexes = av_malloc_array(sizeof(pthread_mutex_t), CRYPTO_num_locks()); + if (!openssl_mutexes) { + ff_unlock_avformat(); + return AVERROR(ENOMEM); + } + + for (i = 0; i < CRYPTO_num_locks(); i++) + pthread_mutex_init(&openssl_mutexes[i], NULL); + CRYPTO_set_locking_callback(openssl_lock); +#if !defined(WIN32) && OPENSSL_VERSION_NUMBER < 0x10000000 + CRYPTO_set_id_callback(openssl_thread_id); +#endif + } +#endif + } + openssl_init++; + ff_unlock_avformat(); + + return 0; +} + +void ff_openssl_deinit(void) +{ + ff_lock_avformat(); + openssl_init--; + if (!openssl_init) { +#if HAVE_THREADS + if (CRYPTO_get_locking_callback() == openssl_lock) { + int i; + CRYPTO_set_locking_callback(NULL); + for (i = 0; i < CRYPTO_num_locks(); i++) + pthread_mutex_destroy(&openssl_mutexes[i]); + av_free(openssl_mutexes); + } +#endif + } + ff_unlock_avformat(); +} + +static int print_tls_error(URLContext *h, int ret) +{ + TLSContext *c = h->priv_data; + if (h->flags & AVIO_FLAG_NONBLOCK) { + int err = SSL_get_error(c->ssl, ret); + if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_READ) + return AVERROR(EAGAIN); + } + av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL)); + return AVERROR(EIO); +} + +static int tls_close(URLContext *h) +{ + TLSContext *c = h->priv_data; + if (c->ssl) { + SSL_shutdown(c->ssl); + SSL_free(c->ssl); + } + if (c->ctx) + SSL_CTX_free(c->ctx); + if (c->tls_shared.tcp) + ffurl_close(c->tls_shared.tcp); +#if OPENSSL_VERSION_NUMBER >= 0x1010000fL + if (c->url_bio_method) + BIO_meth_free(c->url_bio_method); +#endif + ff_openssl_deinit(); + return 0; +} + static int url_bio_create(BIO *b) { #if OPENSSL_VERSION_NUMBER >= 0x1010000fL @@ -98,6 +177,8 @@ static int url_bio_bread(BIO *b, char *buf, int len) if (ret >= 0) return ret; BIO_clear_retry_flags(b); + if (ret == AVERROR(EAGAIN)) + BIO_set_retry_read(b); if (ret == AVERROR_EXIT) return 0; return -1; @@ -110,6 +191,8 @@ static int url_bio_bwrite(BIO *b, const char *buf, int len) if (ret >= 0) return ret; BIO_clear_retry_flags(b); + if (ret == AVERROR(EAGAIN)) + BIO_set_retry_write(b); if (ret == AVERROR_EXIT) return 0; return -1; @@ -143,79 +226,6 @@ static BIO_METHOD url_bio_method = { }; #endif -int ff_openssl_init(void) -{ - avpriv_lock_avformat(); - if (!openssl_init) { - SSL_library_init(); - SSL_load_error_strings(); -#if HAVE_THREADS - if (!CRYPTO_get_locking_callback()) { - int i; - openssl_mutexes = av_malloc_array(sizeof(pthread_mutex_t), CRYPTO_num_locks()); - if (!openssl_mutexes) { - avpriv_unlock_avformat(); - return AVERROR(ENOMEM); - } - - for (i = 0; i < CRYPTO_num_locks(); i++) - pthread_mutex_init(&openssl_mutexes[i], NULL); - CRYPTO_set_locking_callback(openssl_lock); -#if !defined(WIN32) && OPENSSL_VERSION_NUMBER < 0x10000000 - CRYPTO_set_id_callback(openssl_thread_id); -#endif - } -#endif - } - openssl_init++; - avpriv_unlock_avformat(); - - return 0; -} - -void ff_openssl_deinit(void) -{ - avpriv_lock_avformat(); - openssl_init--; - if (!openssl_init) { -#if HAVE_THREADS - if (CRYPTO_get_locking_callback() == openssl_lock) { - int i; - CRYPTO_set_locking_callback(NULL); - for (i = 0; i < CRYPTO_num_locks(); i++) - pthread_mutex_destroy(&openssl_mutexes[i]); - av_free(openssl_mutexes); - } -#endif - } - avpriv_unlock_avformat(); -} - -static int print_tls_error(URLContext *h, int ret) -{ - av_log(h, AV_LOG_ERROR, "%s\n", ERR_error_string(ERR_get_error(), NULL)); - return AVERROR(EIO); -} - -static int tls_close(URLContext *h) -{ - TLSContext *c = h->priv_data; - if (c->ssl) { - SSL_shutdown(c->ssl); - SSL_free(c->ssl); - } - if (c->ctx) - SSL_CTX_free(c->ctx); - if (c->tls_shared.tcp) - ffurl_close(c->tls_shared.tcp); -#if OPENSSL_VERSION_NUMBER >= 0x1010000fL - if (c->url_bio_method) - BIO_meth_free(c->url_bio_method); -#endif - ff_openssl_deinit(); - return 0; -} - static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **options) { TLSContext *p = h->priv_data; @@ -302,7 +312,11 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op static int tls_read(URLContext *h, uint8_t *buf, int size) { TLSContext *c = h->priv_data; - int ret = SSL_read(c->ssl, buf, size); + int ret; + // Set or clear the AVIO_FLAG_NONBLOCK on c->tls_shared.tcp + c->tls_shared.tcp->flags &= ~AVIO_FLAG_NONBLOCK; + c->tls_shared.tcp->flags |= h->flags & AVIO_FLAG_NONBLOCK; + ret = SSL_read(c->ssl, buf, size); if (ret > 0) return ret; if (ret == 0) @@ -313,7 +327,11 @@ static int tls_read(URLContext *h, uint8_t *buf, int size) static int tls_write(URLContext *h, const uint8_t *buf, int size) { TLSContext *c = h->priv_data; - int ret = SSL_write(c->ssl, buf, size); + int ret; + // Set or clear the AVIO_FLAG_NONBLOCK on c->tls_shared.tcp + c->tls_shared.tcp->flags &= ~AVIO_FLAG_NONBLOCK; + c->tls_shared.tcp->flags |= h->flags & AVIO_FLAG_NONBLOCK; + ret = SSL_write(c->ssl, buf, size); if (ret > 0) return ret; if (ret == 0) @@ -339,7 +357,7 @@ static const AVClass tls_class = { .version = LIBAVUTIL_VERSION_INT, }; -const URLProtocol ff_tls_openssl_protocol = { +const URLProtocol ff_tls_protocol = { .name = "tls", .url_open2 = tls_open, .url_read = tls_read, diff --git a/libavformat/tls_schannel.c b/libavformat/tls_schannel.c index 9f1c08806fe74..f41b007773f17 100644 --- a/libavformat/tls_schannel.c +++ b/libavformat/tls_schannel.c @@ -413,11 +413,13 @@ static int tls_read(URLContext *h, uint8_t *buf, int len) ret = ffurl_read(s->tcp, c->enc_buf + c->enc_buf_offset, c->enc_buf_size - c->enc_buf_offset); - if (ret < 0) { + if (ret == AVERROR_EOF) { + c->connection_closed = 1; + ret = 0; + } else if (ret < 0) { av_log(h, AV_LOG_ERROR, "Unable to read from socket\n"); return ret; - } else if (ret == 0) - c->connection_closed = 1; + } c->enc_buf_offset += ret; } @@ -515,7 +517,7 @@ static int tls_read(URLContext *h, uint8_t *buf, int len) if (ret == 0 && !c->connection_closed) ret = AVERROR(EAGAIN); - return ret < 0 ? ret : 0; + return ret < 0 ? ret : AVERROR_EOF; } static int tls_write(URLContext *h, const uint8_t *buf, int len) @@ -595,7 +597,7 @@ static const AVClass tls_class = { .version = LIBAVUTIL_VERSION_INT, }; -const URLProtocol ff_tls_schannel_protocol = { +const URLProtocol ff_tls_protocol = { .name = "tls", .url_open2 = tls_open, .url_read = tls_read, diff --git a/libavformat/tls_securetransport.c b/libavformat/tls_securetransport.c index bc8a32069e27d..37380541b11c9 100644 --- a/libavformat/tls_securetransport.c +++ b/libavformat/tls_securetransport.c @@ -54,7 +54,7 @@ static int print_tls_error(URLContext *h, int ret) TLSContext *c = h->priv_data; switch (ret) { case errSSLWouldBlock: - break; + return AVERROR(EAGAIN); case errSSLXCertChainInvalid: av_log(h, AV_LOG_ERROR, "Invalid certificate chain\n"); return AVERROR(EIO); @@ -69,6 +69,9 @@ static int print_tls_error(URLContext *h, int ret) static int import_pem(URLContext *h, char *path, CFArrayRef *array) { +#if !HAVE_SECITEMIMPORT + return AVERROR_PATCHWELCOME; +#else AVIOContext *s = NULL; CFDataRef data = NULL; int64_t ret = 0; @@ -124,6 +127,7 @@ static int import_pem(URLContext *h, char *path, CFArrayRef *array) if (s) avio_close(s); return ret; +#endif } static int load_ca(URLContext *h) @@ -193,7 +197,8 @@ static OSStatus tls_read_cb(SSLConnectionRef connection, void *data, size_t *dat { URLContext *h = (URLContext*)connection; TLSContext *c = h->priv_data; - int read = ffurl_read_complete(c->tls_shared.tcp, data, *dataLength); + size_t requested = *dataLength; + int read = ffurl_read(c->tls_shared.tcp, data, requested); if (read <= 0) { *dataLength = 0; switch(AVUNERROR(read)) { @@ -210,7 +215,10 @@ static OSStatus tls_read_cb(SSLConnectionRef connection, void *data, size_t *dat } } else { *dataLength = read; - return noErr; + if (read < requested) + return errSSLWouldBlock; + else + return noErr; } } @@ -322,12 +330,13 @@ static int tls_open(URLContext *h, const char *uri, int flags, AVDictionary **op if (peerTrust) CFRelease(peerTrust); } - if (status == noErr) + if (status == noErr) { break; - - av_log(h, AV_LOG_ERROR, "Unable to negotiate TLS/SSL session: %i\n", (int)status); - ret = AVERROR(EIO); - goto fail; + } else if (status != errSSLWouldBlock) { + av_log(h, AV_LOG_ERROR, "Unable to negotiate TLS/SSL session: %i\n", (int)status); + ret = AVERROR(EIO); + goto fail; + } } return 0; @@ -344,6 +353,9 @@ static int map_ssl_error(OSStatus status, size_t processed) case errSSLClosedGraceful: case errSSLClosedNoNotify: return 0; + case errSSLWouldBlock: + if (processed > 0) + return processed; default: return (int)status; } @@ -352,8 +364,12 @@ static int map_ssl_error(OSStatus status, size_t processed) static int tls_read(URLContext *h, uint8_t *buf, int size) { TLSContext *c = h->priv_data; - size_t processed = 0; - int ret = SSLRead(c->ssl_context, buf, size, &processed); + size_t available = 0, processed = 0; + int ret; + SSLGetBufferedReadSize(c->ssl_context, &available); + if (available) + size = FFMIN(available, size); + ret = SSLRead(c->ssl_context, buf, size, &processed); ret = map_ssl_error(ret, processed); if (ret > 0) return ret; @@ -393,7 +409,7 @@ static const AVClass tls_class = { .version = LIBAVUTIL_VERSION_INT, }; -const URLProtocol ff_tls_securetransport_protocol = { +const URLProtocol ff_tls_protocol = { .name = "tls", .url_open2 = tls_open, .url_read = tls_read, diff --git a/libavformat/ttaenc.c b/libavformat/ttaenc.c index fdce1e3dc1c0f..d8e1136ead1a2 100644 --- a/libavformat/ttaenc.c +++ b/libavformat/ttaenc.c @@ -29,22 +29,23 @@ typedef struct TTAMuxContext { AVIOContext *seek_table; - AVIOContext *data; + AVPacketList *queue, *queue_end; uint32_t nb_samples; int frame_size; int last_frame; } TTAMuxContext; -static int tta_write_header(AVFormatContext *s) +static int tta_init(AVFormatContext *s) { TTAMuxContext *tta = s->priv_data; - AVCodecParameters *par = s->streams[0]->codecpar; - int ret; + AVCodecParameters *par; if (s->nb_streams != 1) { av_log(s, AV_LOG_ERROR, "Only one stream is supported\n"); return AVERROR(EINVAL); } + par = s->streams[0]->codecpar; + if (par->codec_id != AV_CODEC_ID_TTA) { av_log(s, AV_LOG_ERROR, "Unsupported codec\n"); return AVERROR(EINVAL); @@ -54,12 +55,25 @@ static int tta_write_header(AVFormatContext *s) return AVERROR_INVALIDDATA; } + /* Prevent overflow */ + if (par->sample_rate > 0x7FFFFFu) { + av_log(s, AV_LOG_ERROR, "Sample rate too large\n"); + return AVERROR(EINVAL); + } + tta->frame_size = par->sample_rate * 256 / 245; + avpriv_set_pts_info(s->streams[0], 64, 1, par->sample_rate); + + return 0; +} + +static int tta_write_header(AVFormatContext *s) +{ + TTAMuxContext *tta = s->priv_data; + AVCodecParameters *par = s->streams[0]->codecpar; + int ret; + if ((ret = avio_open_dyn_buf(&tta->seek_table)) < 0) return ret; - if ((ret = avio_open_dyn_buf(&tta->data)) < 0) { - ffio_free_dyn_buf(&tta->seek_table); - return ret; - } /* Ignore most extradata information if present. It can be innacurate if for example remuxing from Matroska */ @@ -70,13 +84,6 @@ static int tta_write_header(AVFormatContext *s) avio_wl16(s->pb, par->channels); avio_wl16(s->pb, par->bits_per_raw_sample); avio_wl32(s->pb, par->sample_rate); - /* Prevent overflow */ - if (par->sample_rate > 0x7FFFFFu) { - av_log(s, AV_LOG_ERROR, "Sample rate too large\n"); - return AVERROR(EINVAL); - } - tta->frame_size = par->sample_rate * 256 / 245; - avpriv_set_pts_info(s->streams[0], 64, 1, par->sample_rate); return 0; } @@ -84,8 +91,14 @@ static int tta_write_header(AVFormatContext *s) static int tta_write_packet(AVFormatContext *s, AVPacket *pkt) { TTAMuxContext *tta = s->priv_data; + int ret; + + ret = ff_packet_list_put(&tta->queue, &tta->queue_end, pkt, + FF_PACKETLIST_FLAG_REF_PACKET); + if (ret < 0) { + return ret; + } - avio_write(tta->data, pkt->data, pkt->size); avio_wl32(tta->seek_table, pkt->size); tta->nb_samples += pkt->duration; @@ -106,6 +119,18 @@ static int tta_write_packet(AVFormatContext *s, AVPacket *pkt) return 0; } +static void tta_queue_flush(AVFormatContext *s) +{ + TTAMuxContext *tta = s->priv_data; + AVPacket pkt; + + while (tta->queue) { + ff_packet_list_get(&tta->queue, &tta->queue_end, &pkt); + avio_write(s->pb, pkt.data, pkt.size); + av_packet_unref(&pkt); + } +} + static int tta_write_trailer(AVFormatContext *s) { TTAMuxContext *tta = s->priv_data; @@ -125,9 +150,7 @@ static int tta_write_trailer(AVFormatContext *s) av_free(ptr); /* Write audio data */ - size = avio_close_dyn_buf(tta->data, &ptr); - avio_write(s->pb, ptr, size); - av_free(ptr); + tta_queue_flush(s); ff_ape_write_tag(s); avio_flush(s->pb); @@ -143,6 +166,7 @@ AVOutputFormat ff_tta_muxer = { .priv_data_size = sizeof(TTAMuxContext), .audio_codec = AV_CODEC_ID_TTA, .video_codec = AV_CODEC_ID_NONE, + .init = tta_init, .write_header = tta_write_header, .write_packet = tta_write_packet, .write_trailer = tta_write_trailer, diff --git a/libavformat/ty.c b/libavformat/ty.c new file mode 100644 index 0000000000000..d348643f40cfb --- /dev/null +++ b/libavformat/ty.c @@ -0,0 +1,789 @@ +/* + * TiVo ty stream demuxer + * Copyright (c) 2005 VLC authors and VideoLAN + * Copyright (c) 2005 by Neal Symms (tivo@freakinzoo.com) - February 2005 + * based on code by Christopher Wingert for tivo-mplayer + * tivo(at)wingert.org, February 2003 + * Copyright (c) 2017 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/intreadwrite.h" +#include "avformat.h" +#include "internal.h" +#include "mpeg.h" + +#define SERIES1_PES_LENGTH 11 /* length of audio PES hdr on S1 */ +#define SERIES2_PES_LENGTH 16 /* length of audio PES hdr on S2 */ +#define AC3_PES_LENGTH 14 /* length of audio PES hdr for AC3 */ +#define VIDEO_PES_LENGTH 16 /* length of video PES header */ +#define DTIVO_PTS_OFFSET 6 /* offs into PES for MPEG PTS on DTivo */ +#define SA_PTS_OFFSET 9 /* offset into PES for MPEG PTS on SA */ +#define AC3_PTS_OFFSET 9 /* offset into PES for AC3 PTS on DTivo */ +#define VIDEO_PTS_OFFSET 9 /* offset into PES for video PTS on all */ +#define AC3_PKT_LENGTH 1536 /* size of TiVo AC3 pkts (w/o PES hdr) */ + +static const uint8_t ty_VideoPacket[] = { 0x00, 0x00, 0x01, 0xe0 }; +static const uint8_t ty_MPEGAudioPacket[] = { 0x00, 0x00, 0x01, 0xc0 }; +static const uint8_t ty_AC3AudioPacket[] = { 0x00, 0x00, 0x01, 0xbd }; + +#define TIVO_PES_FILEID 0xf5467abd +#define CHUNK_SIZE (128 * 1024) +#define CHUNK_PEEK_COUNT 3 /* number of chunks to probe */ + +typedef struct TyRecHdr { + int64_t rec_size; + uint8_t ex[2]; + uint8_t rec_type; + uint8_t subrec_type; + uint64_t ty_pts; /* TY PTS in the record header */ +} TyRecHdr; + +typedef enum { + TIVO_TYPE_UNKNOWN, + TIVO_TYPE_SA, + TIVO_TYPE_DTIVO +} TiVo_type; + +typedef enum { + TIVO_SERIES_UNKNOWN, + TIVO_SERIES1, + TIVO_SERIES2 +} TiVo_series; + +typedef enum { + TIVO_AUDIO_UNKNOWN, + TIVO_AUDIO_AC3, + TIVO_AUDIO_MPEG +} TiVo_audio; + +typedef struct TySeqTable { + uint64_t timestamp; + uint8_t chunk_bitmask[8]; +} TySeqTable; + +typedef struct TYDemuxContext { + unsigned cur_chunk; + unsigned cur_chunk_pos; + int64_t cur_pos; + TiVo_type tivo_type; /* TiVo type (SA / DTiVo) */ + TiVo_series tivo_series; /* Series1 or Series2 */ + TiVo_audio audio_type; /* AC3 or MPEG */ + int pes_length; /* Length of Audio PES header */ + int pts_offset; /* offset into audio PES of PTS */ + uint8_t pes_buffer[20]; /* holds incomplete pes headers */ + int pes_buf_cnt; /* how many bytes in our buffer */ + size_t ac3_pkt_size; /* length of ac3 pkt we've seen so far */ + uint64_t last_ty_pts; /* last TY timestamp we've seen */ + unsigned seq_table_size; /* number of entries in SEQ table */ + + int64_t first_audio_pts; + int64_t last_audio_pts; + int64_t last_video_pts; + + TyRecHdr *rec_hdrs; /* record headers array */ + int cur_rec; /* current record in this chunk */ + int num_recs; /* number of recs in this chunk */ + int seq_rec; /* record number where seq start is */ + TySeqTable *seq_table; /* table of SEQ entries from mstr chk */ + int first_chunk; + + uint8_t chunk[CHUNK_SIZE]; +} TYDemuxContext; + +static int ty_probe(AVProbeData *p) +{ + int i; + + for (i = 0; i + 12 < p->buf_size; i += CHUNK_SIZE) { + if (AV_RB32(p->buf + i) == TIVO_PES_FILEID && + AV_RB32(p->buf + i + 4) == 0x02 && + AV_RB32(p->buf + i + 8) == CHUNK_SIZE) { + return AVPROBE_SCORE_MAX; + } + } + + return 0; +} + +static TyRecHdr *parse_chunk_headers(const uint8_t *buf, + int num_recs) +{ + TyRecHdr *hdrs, *rec_hdr; + int i; + + hdrs = av_calloc(num_recs, sizeof(TyRecHdr)); + if (!hdrs) + return NULL; + + for (i = 0; i < num_recs; i++) { + const uint8_t *record_header = buf + (i * 16); + + rec_hdr = &hdrs[i]; /* for brevity */ + rec_hdr->rec_type = record_header[3]; + rec_hdr->subrec_type = record_header[2] & 0x0f; + if ((record_header[0] & 0x80) == 0x80) { + uint8_t b1, b2; + + /* marker bit 2 set, so read extended data */ + b1 = (((record_header[0] & 0x0f) << 4) | + ((record_header[1] & 0xf0) >> 4)); + b2 = (((record_header[1] & 0x0f) << 4) | + ((record_header[2] & 0xf0) >> 4)); + + rec_hdr->ex[0] = b1; + rec_hdr->ex[1] = b2; + rec_hdr->rec_size = 0; + rec_hdr->ty_pts = 0; + } else { + rec_hdr->rec_size = (record_header[0] << 8 | + record_header[1]) << 4 | + (record_header[2] >> 4); + rec_hdr->ty_pts = AV_RB64(&record_header[8]); + } + } + return hdrs; +} + +static int find_es_header(const uint8_t *header, + const uint8_t *buffer, int search_len) +{ + int count; + + for (count = 0; count < search_len; count++) { + if (!memcmp(&buffer[count], header, 4)) + return count; + } + return -1; +} + +static int analyze_chunk(AVFormatContext *s, const uint8_t *chunk) +{ + TYDemuxContext *ty = s->priv_data; + int num_recs, i; + TyRecHdr *hdrs; + int num_6e0, num_be0, num_9c0, num_3c0; + + /* skip if it's a Part header */ + if (AV_RB32(&chunk[0]) == TIVO_PES_FILEID) + return 0; + + /* number of records in chunk (we ignore high order byte; + * rarely are there > 256 chunks & we don't need that many anyway) */ + num_recs = chunk[0]; + if (num_recs < 5) { + /* try again with the next chunk. Sometimes there are dead ones */ + return 0; + } + + chunk += 4; /* skip past rec count & SEQ bytes */ + ff_dlog(s, "probe: chunk has %d recs\n", num_recs); + hdrs = parse_chunk_headers(chunk, num_recs); + if (!hdrs) + return AVERROR(ENOMEM); + + /* scan headers. + * 1. check video packets. Presence of 0x6e0 means S1. + * No 6e0 but have be0 means S2. + * 2. probe for audio 0x9c0 vs 0x3c0 (AC3 vs Mpeg) + * If AC-3, then we have DTivo. + * If MPEG, search for PTS offset. This will determine SA vs. DTivo. + */ + num_6e0 = num_be0 = num_9c0 = num_3c0 = 0; + for (i = 0; i < num_recs; i++) { + switch (hdrs[i].subrec_type << 8 | hdrs[i].rec_type) { + case 0x6e0: + num_6e0++; + break; + case 0xbe0: + num_be0++; + break; + case 0x3c0: + num_3c0++; + break; + case 0x9c0: + num_9c0++; + break; + } + } + ff_dlog(s, "probe: chunk has %d 0x6e0 recs, %d 0xbe0 recs.\n", + num_6e0, num_be0); + + /* set up our variables */ + if (num_6e0 > 0) { + ff_dlog(s, "detected Series 1 Tivo\n"); + ty->tivo_series = TIVO_SERIES1; + ty->pes_length = SERIES1_PES_LENGTH; + } else if (num_be0 > 0) { + ff_dlog(s, "detected Series 2 Tivo\n"); + ty->tivo_series = TIVO_SERIES2; + ty->pes_length = SERIES2_PES_LENGTH; + } + if (num_9c0 > 0) { + ff_dlog(s, "detected AC-3 Audio (DTivo)\n"); + ty->audio_type = TIVO_AUDIO_AC3; + ty->tivo_type = TIVO_TYPE_DTIVO; + ty->pts_offset = AC3_PTS_OFFSET; + ty->pes_length = AC3_PES_LENGTH; + } else if (num_3c0 > 0) { + ty->audio_type = TIVO_AUDIO_MPEG; + ff_dlog(s, "detected MPEG Audio\n"); + } + + /* if tivo_type still unknown, we can check PTS location + * in MPEG packets to determine tivo_type */ + if (ty->tivo_type == TIVO_TYPE_UNKNOWN) { + uint32_t data_offset = 16 * num_recs; + + for (i = 0; i < num_recs; i++) { + if (data_offset + hdrs[i].rec_size > CHUNK_SIZE) + break; + + if ((hdrs[i].subrec_type << 0x08 | hdrs[i].rec_type) == 0x3c0 && hdrs[i].rec_size > 15) { + /* first make sure we're aligned */ + int pes_offset = find_es_header(ty_MPEGAudioPacket, + &chunk[data_offset], 5); + if (pes_offset >= 0) { + /* pes found. on SA, PES has hdr data at offset 6, not PTS. */ + if ((chunk[data_offset + 6 + pes_offset] & 0x80) == 0x80) { + /* S1SA or S2(any) Mpeg Audio (PES hdr, not a PTS start) */ + if (ty->tivo_series == TIVO_SERIES1) + ff_dlog(s, "detected Stand-Alone Tivo\n"); + ty->tivo_type = TIVO_TYPE_SA; + ty->pts_offset = SA_PTS_OFFSET; + } else { + if (ty->tivo_series == TIVO_SERIES1) + ff_dlog(s, "detected DirecTV Tivo\n"); + ty->tivo_type = TIVO_TYPE_DTIVO; + ty->pts_offset = DTIVO_PTS_OFFSET; + } + break; + } + } + data_offset += hdrs[i].rec_size; + } + } + av_free(hdrs); + + return 0; +} + +static int ty_read_header(AVFormatContext *s) +{ + TYDemuxContext *ty = s->priv_data; + AVIOContext *pb = s->pb; + AVStream *st, *ast; + int i, ret = 0; + + ty->first_audio_pts = AV_NOPTS_VALUE; + ty->last_audio_pts = AV_NOPTS_VALUE; + ty->last_video_pts = AV_NOPTS_VALUE; + + for (i = 0; i < CHUNK_PEEK_COUNT; i++) { + avio_read(pb, ty->chunk, CHUNK_SIZE); + + ret = analyze_chunk(s, ty->chunk); + if (ret < 0) + return ret; + if (ty->tivo_series != TIVO_SERIES_UNKNOWN && + ty->audio_type != TIVO_AUDIO_UNKNOWN && + ty->tivo_type != TIVO_TYPE_UNKNOWN) + break; + } + + if (ty->tivo_series == TIVO_SERIES_UNKNOWN || + ty->audio_type == TIVO_AUDIO_UNKNOWN || + ty->tivo_type == TIVO_TYPE_UNKNOWN) + return AVERROR(EIO); + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + st->codecpar->codec_id = AV_CODEC_ID_MPEG2VIDEO; + st->need_parsing = AVSTREAM_PARSE_FULL_RAW; + avpriv_set_pts_info(st, 64, 1, 90000); + + ast = avformat_new_stream(s, NULL); + if (!ast) + return AVERROR(ENOMEM); + ast->codecpar->codec_type = AVMEDIA_TYPE_AUDIO; + + if (ty->audio_type == TIVO_AUDIO_MPEG) { + ast->codecpar->codec_id = AV_CODEC_ID_MP2; + ast->need_parsing = AVSTREAM_PARSE_FULL_RAW; + } else { + ast->codecpar->codec_id = AV_CODEC_ID_AC3; + } + avpriv_set_pts_info(ast, 64, 1, 90000); + + ty->first_chunk = 1; + + avio_seek(pb, 0, SEEK_SET); + + return 0; +} + +/* parse a master chunk, filling the SEQ table and other variables. + * We assume the stream is currently pointing to it. + */ +static void parse_master(AVFormatContext *s) +{ + TYDemuxContext *ty = s->priv_data; + unsigned map_size; /* size of bitmask, in bytes */ + unsigned i, j; + + /* Note that the entries in the SEQ table in the stream may have + different sizes depending on the bits per entry. We store them + all in the same size structure, so we have to parse them out one + by one. If we had a dynamic structure, we could simply read the + entire table directly from the stream into memory in place. */ + + /* clear the SEQ table */ + av_freep(&ty->seq_table); + + /* parse header info */ + + map_size = AV_RB32(ty->chunk + 20); /* size of bitmask, in bytes */ + i = AV_RB32(ty->chunk + 28); /* size of SEQ table, in bytes */ + + ty->seq_table_size = i / (8LL + map_size); + + if (ty->seq_table_size == 0) { + ty->seq_table = NULL; + return; + } + + /* parse all the entries */ + ty->seq_table = av_calloc(ty->seq_table_size, sizeof(TySeqTable)); + if (ty->seq_table == NULL) { + ty->seq_table_size = 0; + return; + } + + ty->cur_chunk_pos = 32; + for (j = 0; j < ty->seq_table_size; j++) { + if (ty->cur_chunk_pos >= CHUNK_SIZE - 8) + return; + ty->seq_table[j].timestamp = AV_RB64(ty->chunk + ty->cur_chunk_pos); + ty->cur_chunk_pos += 8; + if (map_size > 8) { + av_log(s, AV_LOG_ERROR, "Unsupported SEQ bitmap size in master chunk.\n"); + ty->cur_chunk_pos += map_size; + } else { + memcpy(ty->seq_table[j].chunk_bitmask, ty->chunk + ty->cur_chunk_pos, map_size); + } + } +} + +static int get_chunk(AVFormatContext *s) +{ + TYDemuxContext *ty = s->priv_data; + AVIOContext *pb = s->pb; + int read_size, num_recs; + + ff_dlog(s, "parsing ty chunk #%d\n", ty->cur_chunk); + + /* if we have left-over filler space from the last chunk, get that */ + if (avio_feof(pb)) + return AVERROR_EOF; + + /* read the TY packet header */ + read_size = avio_read(pb, ty->chunk, CHUNK_SIZE); + ty->cur_chunk++; + + if ((read_size < 4) || (AV_RB32(ty->chunk) == 0)) { + return AVERROR_EOF; + } + + /* check if it's a PART Header */ + if (AV_RB32(ty->chunk) == TIVO_PES_FILEID) { + parse_master(s); /* parse master chunk */ + return get_chunk(s); + } + + /* number of records in chunk (8- or 16-bit number) */ + if (ty->chunk[3] & 0x80) { + /* 16 bit rec cnt */ + ty->num_recs = num_recs = (ty->chunk[1] << 8) + ty->chunk[0]; + ty->seq_rec = (ty->chunk[3] << 8) + ty->chunk[2]; + if (ty->seq_rec != 0xffff) { + ty->seq_rec &= ~0x8000; + } + } else { + /* 8 bit reclen - TiVo 1.3 format */ + ty->num_recs = num_recs = ty->chunk[0]; + ty->seq_rec = ty->chunk[1]; + } + ty->cur_rec = 0; + ty->first_chunk = 0; + + ff_dlog(s, "chunk has %d records\n", num_recs); + ty->cur_chunk_pos = 4; + + av_freep(&ty->rec_hdrs); + + if (num_recs * 16 >= CHUNK_SIZE - 4) + return AVERROR_INVALIDDATA; + + ty->rec_hdrs = parse_chunk_headers(ty->chunk + 4, num_recs); + if (!ty->rec_hdrs) + return AVERROR(ENOMEM); + ty->cur_chunk_pos += 16 * num_recs; + + return 0; +} + +static int demux_video(AVFormatContext *s, TyRecHdr *rec_hdr, AVPacket *pkt) +{ + TYDemuxContext *ty = s->priv_data; + const int subrec_type = rec_hdr->subrec_type; + const int64_t rec_size = rec_hdr->rec_size; + int es_offset1; + int got_packet = 0; + + if (subrec_type != 0x02 && subrec_type != 0x0c && + subrec_type != 0x08 && rec_size > 4) { + /* get the PTS from this packet if it has one. + * on S1, only 0x06 has PES. On S2, however, most all do. + * Do NOT Pass the PES Header to the MPEG2 codec */ + es_offset1 = find_es_header(ty_VideoPacket, ty->chunk + ty->cur_chunk_pos, 5); + if (es_offset1 != -1) { + ty->last_video_pts = ff_parse_pes_pts( + ty->chunk + ty->cur_chunk_pos + es_offset1 + VIDEO_PTS_OFFSET); + if (subrec_type != 0x06) { + /* if we found a PES, and it's not type 6, then we're S2 */ + /* The packet will have video data (& other headers) so we + * chop out the PES header and send the rest */ + if (rec_size >= VIDEO_PES_LENGTH + es_offset1) { + int size = rec_hdr->rec_size - VIDEO_PES_LENGTH - es_offset1; + + ty->cur_chunk_pos += VIDEO_PES_LENGTH + es_offset1; + if (av_new_packet(pkt, size) < 0) + return AVERROR(ENOMEM); + memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, size); + ty->cur_chunk_pos += size; + pkt->stream_index = 0; + got_packet = 1; + } else { + ff_dlog(s, "video rec type 0x%02x has short PES" + " (%"PRId64" bytes)\n", subrec_type, rec_size); + /* nuke this block; it's too short, but has PES marker */ + ty->cur_chunk_pos += rec_size; + return 0; + } + } + } + } + + if (subrec_type == 0x06) { + /* type 6 (S1 DTivo) has no data, so we're done */ + ty->cur_chunk_pos += rec_size; + return 0; + } + + if (!got_packet) { + if (av_new_packet(pkt, rec_size) < 0) + return AVERROR(ENOMEM); + memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, rec_size); + ty->cur_chunk_pos += rec_size; + pkt->stream_index = 0; + got_packet = 1; + } + + /* if it's not a continue blk, then set PTS */ + if (subrec_type != 0x02) { + if (subrec_type == 0x0c && pkt->size >= 6) + pkt->data[5] |= 0x08; + if (subrec_type == 0x07) { + ty->last_ty_pts = rec_hdr->ty_pts; + } else { + /* yes I know this is a cheap hack. It's the timestamp + used for display and skipping fwd/back, so it + doesn't have to be accurate to the millisecond. + I adjust it here by roughly one 1/30 sec. Yes it + will be slightly off for UK streams, but it's OK. + */ + ty->last_ty_pts += 35000000; + //ty->last_ty_pts += 33366667; + } + /* set PTS for this block before we send */ + if (ty->last_video_pts > AV_NOPTS_VALUE) { + pkt->pts = ty->last_video_pts; + /* PTS gets used ONCE. + * Any subsequent frames we get BEFORE next PES + * header will have their PTS computed in the codec */ + ty->last_video_pts = AV_NOPTS_VALUE; + } + } + + return got_packet; +} + +static int check_sync_pes(AVFormatContext *s, AVPacket *pkt, + int32_t offset, int32_t rec_len) +{ + TYDemuxContext *ty = s->priv_data; + + if (offset < 0 || offset + ty->pes_length > rec_len) { + /* entire PES header not present */ + ff_dlog(s, "PES header at %"PRId32" not complete in record. storing.\n", offset); + /* save the partial pes header */ + if (offset < 0) { + /* no header found, fake some 00's (this works, believe me) */ + memset(ty->pes_buffer, 0, 4); + ty->pes_buf_cnt = 4; + if (rec_len > 4) + ff_dlog(s, "PES header not found in record of %"PRId32" bytes!\n", rec_len); + return -1; + } + /* copy the partial pes header we found */ + memcpy(ty->pes_buffer, pkt->data + offset, rec_len - offset); + ty->pes_buf_cnt = rec_len - offset; + + if (offset > 0) { + /* PES Header was found, but not complete, so trim the end of this record */ + pkt->size -= rec_len - offset; + return 1; + } + return -1; /* partial PES, no audio data */ + } + /* full PES header present, extract PTS */ + ty->last_audio_pts = ff_parse_pes_pts(&pkt->data[ offset + ty->pts_offset]); + if (ty->first_audio_pts == AV_NOPTS_VALUE) + ty->first_audio_pts = ty->last_audio_pts; + pkt->pts = ty->last_audio_pts; + memmove(pkt->data + offset, pkt->data + offset + ty->pes_length, rec_len - ty->pes_length); + pkt->size -= ty->pes_length; + return 0; +} + +static int demux_audio(AVFormatContext *s, TyRecHdr *rec_hdr, AVPacket *pkt) +{ + TYDemuxContext *ty = s->priv_data; + const int subrec_type = rec_hdr->subrec_type; + const int64_t rec_size = rec_hdr->rec_size; + int es_offset1; + + if (subrec_type == 2) { + int need = 0; + /* SA or DTiVo Audio Data, no PES (continued block) + * ================================================ + */ + + /* continue PES if previous was incomplete */ + if (ty->pes_buf_cnt > 0) { + need = ty->pes_length - ty->pes_buf_cnt; + + ff_dlog(s, "continuing PES header\n"); + /* do we have enough data to complete? */ + if (need >= rec_size) { + /* don't have complete PES hdr; save what we have and return */ + memcpy(ty->pes_buffer + ty->pes_buf_cnt, ty->chunk + ty->cur_chunk_pos, rec_size); + ty->cur_chunk_pos += rec_size; + ty->pes_buf_cnt += rec_size; + return 0; + } + + /* we have enough; reconstruct this frame with the new hdr */ + memcpy(ty->pes_buffer + ty->pes_buf_cnt, ty->chunk + ty->cur_chunk_pos, need); + ty->cur_chunk_pos += need; + /* get the PTS out of this PES header (MPEG or AC3) */ + if (ty->audio_type == TIVO_AUDIO_MPEG) { + es_offset1 = find_es_header(ty_MPEGAudioPacket, + ty->pes_buffer, 5); + } else { + es_offset1 = find_es_header(ty_AC3AudioPacket, + ty->pes_buffer, 5); + } + if (es_offset1 < 0) { + ff_dlog(s, "Can't find audio PES header in packet.\n"); + } else { + ty->last_audio_pts = ff_parse_pes_pts( + &ty->pes_buffer[es_offset1 + ty->pts_offset]); + pkt->pts = ty->last_audio_pts; + } + ty->pes_buf_cnt = 0; + + } + if (av_new_packet(pkt, rec_size - need) < 0) + return AVERROR(ENOMEM); + memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, rec_size - need); + ty->cur_chunk_pos += rec_size - need; + pkt->stream_index = 1; + + /* S2 DTivo has AC3 packets with 2 padding bytes at end. This is + * not allowed in the AC3 spec and will cause problems. So here + * we try to trim things. */ + /* Also, S1 DTivo has alternating short / long AC3 packets. That + * is, one packet is short (incomplete) and the next packet has + * the first one's missing data, plus all of its own. Strange. */ + if (ty->audio_type == TIVO_AUDIO_AC3 && + ty->tivo_series == TIVO_SERIES2) { + if (ty->ac3_pkt_size + pkt->size > AC3_PKT_LENGTH) { + pkt->size -= 2; + ty->ac3_pkt_size = 0; + } else { + ty->ac3_pkt_size += pkt->size; + } + } + } else if (subrec_type == 0x03) { + if (av_new_packet(pkt, rec_size) < 0) + return AVERROR(ENOMEM); + memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, rec_size); + ty->cur_chunk_pos += rec_size; + pkt->stream_index = 1; + /* MPEG Audio with PES Header, either SA or DTiVo */ + /* ================================================ */ + es_offset1 = find_es_header(ty_MPEGAudioPacket, pkt->data, 5); + + /* SA PES Header, No Audio Data */ + /* ================================================ */ + if ((es_offset1 == 0) && (rec_size == 16)) { + ty->last_audio_pts = ff_parse_pes_pts(&pkt->data[SA_PTS_OFFSET]); + if (ty->first_audio_pts == AV_NOPTS_VALUE) + ty->first_audio_pts = ty->last_audio_pts; + av_packet_unref(pkt); + return 0; + } + /* DTiVo Audio with PES Header */ + /* ================================================ */ + + /* Check for complete PES */ + if (check_sync_pes(s, pkt, es_offset1, rec_size) == -1) { + /* partial PES header found, nothing else. + * we're done. */ + av_packet_unref(pkt); + return 0; + } + } else if (subrec_type == 0x04) { + /* SA Audio with no PES Header */ + /* ================================================ */ + if (av_new_packet(pkt, rec_size) < 0) + return AVERROR(ENOMEM); + memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, rec_size); + ty->cur_chunk_pos += rec_size; + pkt->stream_index = 1; + pkt->pts = ty->last_audio_pts; + } else if (subrec_type == 0x09) { + if (av_new_packet(pkt, rec_size) < 0) + return AVERROR(ENOMEM); + memcpy(pkt->data, ty->chunk + ty->cur_chunk_pos, rec_size); + ty->cur_chunk_pos += rec_size ; + pkt->stream_index = 1; + + /* DTiVo AC3 Audio Data with PES Header */ + /* ================================================ */ + es_offset1 = find_es_header(ty_AC3AudioPacket, pkt->data, 5); + + /* Check for complete PES */ + if (check_sync_pes(s, pkt, es_offset1, rec_size) == -1) { + /* partial PES header found, nothing else. we're done. */ + av_packet_unref(pkt); + return 0; + } + /* S2 DTivo has invalid long AC3 packets */ + if (ty->tivo_series == TIVO_SERIES2) { + if (pkt->size > AC3_PKT_LENGTH) { + pkt->size -= 2; + ty->ac3_pkt_size = 0; + } else { + ty->ac3_pkt_size = pkt->size; + } + } + } else { + /* Unsupported/Unknown */ + ty->cur_chunk_pos += rec_size; + return 0; + } + + return 1; +} + +static int ty_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + TYDemuxContext *ty = s->priv_data; + AVIOContext *pb = s->pb; + TyRecHdr *rec; + int64_t rec_size = 0; + int ret = 0; + + if (avio_feof(pb)) + return AVERROR_EOF; + + while (ret <= 0) { + if (!ty->rec_hdrs || ty->first_chunk || ty->cur_rec >= ty->num_recs) { + if (get_chunk(s) < 0 || ty->num_recs <= 0) + return AVERROR_EOF; + } + + rec = &ty->rec_hdrs[ty->cur_rec]; + rec_size = rec->rec_size; + ty->cur_rec++; + + if (rec_size <= 0) + continue; + + if (ty->cur_chunk_pos + rec->rec_size > CHUNK_SIZE) + return AVERROR_INVALIDDATA; + + if (avio_feof(pb)) + return AVERROR_EOF; + + switch (rec->rec_type) { + case VIDEO_ID: + ret = demux_video(s, rec, pkt); + break; + case AUDIO_ID: + ret = demux_audio(s, rec, pkt); + break; + default: + ff_dlog(s, "Invalid record type 0x%02x\n", rec->rec_type); + case 0x01: + case 0x02: + case 0x03: /* TiVo data services */ + case 0x05: /* unknown, but seen regularly */ + ty->cur_chunk_pos += rec->rec_size; + break; + } + } + + return 0; +} + +static int ty_read_close(AVFormatContext *s) +{ + TYDemuxContext *ty = s->priv_data; + + av_freep(&ty->seq_table); + av_freep(&ty->rec_hdrs); + + return 0; +} + +AVInputFormat ff_ty_demuxer = { + .name = "ty", + .long_name = NULL_IF_CONFIG_SMALL("TiVo TY Stream"), + .priv_data_size = sizeof(TYDemuxContext), + .read_probe = ty_probe, + .read_header = ty_read_header, + .read_packet = ty_read_packet, + .read_close = ty_read_close, + .extensions = "ty,ty+", + .flags = AVFMT_TS_DISCONT, +}; diff --git a/libavformat/udp.c b/libavformat/udp.c index 3835f989c42ba..0dde0353fbe82 100644 --- a/libavformat/udp.c +++ b/libavformat/udp.c @@ -64,10 +64,6 @@ #include #endif -#ifndef HAVE_PTHREAD_CANCEL -#define HAVE_PTHREAD_CANCEL 0 -#endif - #ifndef IPV6_ADD_MEMBERSHIP #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP diff --git a/libavformat/unix.c b/libavformat/unix.c index 4f01d14a938e2..38016dbafea43 100644 --- a/libavformat/unix.c +++ b/libavformat/unix.c @@ -111,6 +111,8 @@ static int unix_read(URLContext *h, uint8_t *buf, int size) return ret; } ret = recv(s->fd, buf, size, 0); + if (!ret && s->type == SOCK_STREAM) + return AVERROR_EOF; return ret < 0 ? ff_neterrno() : ret; } diff --git a/libavformat/utils.c b/libavformat/utils.c index 1a7996c4fd854..dfbfb0a8d6436 100644 --- a/libavformat/utils.c +++ b/libavformat/utils.c @@ -32,6 +32,7 @@ #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "libavutil/pixdesc.h" +#include "libavutil/thread.h" #include "libavutil/time.h" #include "libavutil/time_internal.h" #include "libavutil/timestamp.h" @@ -55,6 +56,8 @@ #include "libavutil/ffversion.h" const char av_format_ffversion[] = "FFmpeg version " FFMPEG_VERSION; +static AVMutex avformat_mutex = AV_MUTEX_INITIALIZER; + /** * @file * various utility functions for use within FFmpeg @@ -77,6 +80,16 @@ const char *avformat_license(void) return LICENSE_PREFIX FFMPEG_LICENSE + sizeof(LICENSE_PREFIX) - 1; } +int ff_lock_avformat(void) +{ + return ff_mutex_lock(&avformat_mutex) ? -1 : 0; +} + +int ff_unlock_avformat(void) +{ + return ff_mutex_unlock(&avformat_mutex) ? -1 : 0; +} + #define RELATIVE_TS_BASE (INT64_MAX - (1LL<<48)) static int is_relative(int64_t ts) { @@ -104,8 +117,13 @@ static int64_t wrap_timestamp(const AVStream *st, int64_t timestamp) return timestamp; } +#if FF_API_FORMAT_GET_SET MAKE_ACCESSORS(AVStream, stream, AVRational, r_frame_rate) +#if FF_API_LAVF_FFSERVER +FF_DISABLE_DEPRECATION_WARNINGS MAKE_ACCESSORS(AVStream, stream, char *, recommended_encoder_configuration) +FF_ENABLE_DEPRECATION_WARNINGS +#endif MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, video_codec) MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, audio_codec) MAKE_ACCESSORS(AVFormatContext, format, AVCodec *, subtitle_codec) @@ -118,11 +136,12 @@ FF_DISABLE_DEPRECATION_WARNINGS MAKE_ACCESSORS(AVFormatContext, format, AVOpenCallback, open_cb) FF_ENABLE_DEPRECATION_WARNINGS #endif +#endif int64_t av_stream_get_end_pts(const AVStream *st) { - if (st->priv_pts) { - return st->priv_pts->val; + if (st->internal->priv_pts) { + return st->internal->priv_pts->val; } else return AV_NOPTS_VALUE; } @@ -215,10 +234,12 @@ static const AVCodec *find_probe_decoder(AVFormatContext *s, const AVStream *st, return codec; } +#if FF_API_FORMAT_GET_SET int av_format_get_probe_score(const AVFormatContext *s) { return s->probe_score; } +#endif /* an arbitrarily chosen "sane" max packet size -- 50M */ #define SANE_CHUNK_SIZE (50000000) @@ -320,6 +341,7 @@ static int set_codec_from_probe_data(AVFormatContext *s, AVStream *st, } fmt_id_type[] = { { "aac", AV_CODEC_ID_AAC, AVMEDIA_TYPE_AUDIO }, { "ac3", AV_CODEC_ID_AC3, AVMEDIA_TYPE_AUDIO }, + { "aptx", AV_CODEC_ID_APTX, AVMEDIA_TYPE_AUDIO }, { "dts", AV_CODEC_ID_DTS, AVMEDIA_TYPE_AUDIO }, { "dvbsub", AV_CODEC_ID_DVB_SUBTITLE,AVMEDIA_TYPE_SUBTITLE }, { "dvbtxt", AV_CODEC_ID_DVB_TELETEXT,AVMEDIA_TYPE_SUBTITLE }, @@ -422,8 +444,9 @@ static int init_input(AVFormatContext *s, const char *filename, s, 0, s->format_probesize); } -static int add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt, - AVPacketList **plast_pktl, int ref) +int ff_packet_list_put(AVPacketList **packet_buffer, + AVPacketList **plast_pktl, + AVPacket *pkt, int flags) { AVPacketList *pktl = av_mallocz(sizeof(AVPacketList)); int ret; @@ -431,12 +454,15 @@ static int add_to_pktbuf(AVPacketList **packet_buffer, AVPacket *pkt, if (!pktl) return AVERROR(ENOMEM); - if (ref) { + if (flags & FF_PACKETLIST_FLAG_REF_PACKET) { if ((ret = av_packet_ref(&pktl->pkt, pkt)) < 0) { av_free(pktl); return ret; } } else { + // TODO: Adapt callers in this file so the line below can use + // av_packet_move_ref() to effectively move the reference + // to the list. pktl->pkt = *pkt; } @@ -463,9 +489,10 @@ int avformat_queue_attached_pictures(AVFormatContext *s) continue; } - ret = add_to_pktbuf(&s->internal->raw_packet_buffer, - &s->streams[i]->attached_pic, - &s->internal->raw_packet_buffer_end, 1); + ret = ff_packet_list_put(&s->internal->raw_packet_buffer, + &s->internal->raw_packet_buffer_end, + &s->streams[i]->attached_pic, + FF_PACKETLIST_FLAG_REF_PACKET); if (ret < 0) return ret; } @@ -513,6 +540,7 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, AVFormatContext *s = *ps; int i, ret = 0; AVDictionary *tmp = NULL; + AVDictionary *tmp2 = NULL; ID3v2ExtraMeta *id3v2_extra_meta = NULL; if (!s && !(s = avformat_alloc_context())) @@ -533,7 +561,16 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, if ((ret = av_opt_set_dict(s, &tmp)) < 0) goto fail; + if (!(s->url = av_strdup(filename ? filename : ""))) { + ret = AVERROR(ENOMEM); + goto fail; + } + +#if FF_API_FORMAT_FILENAME +FF_DISABLE_DEPRECATION_WARNINGS av_strlcpy(s->filename, filename ? filename : "", sizeof(s->filename)); +FF_ENABLE_DEPRECATION_WARNINGS +#endif if ((ret = init_input(s, filename, &tmp)) < 0) goto fail; s->probe_score = ret; @@ -591,9 +628,16 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, ff_id3v2_read_dict(s->pb, &s->internal->id3v2_meta, ID3v2_DEFAULT_MAGIC, &id3v2_extra_meta); - if (!(s->flags&AVFMT_FLAG_PRIV_OPT) && s->iformat->read_header) - if ((ret = s->iformat->read_header(s)) < 0) + if (!(s->flags&AVFMT_FLAG_PRIV_OPT)) { + if (s->iformat->read_header2) { + if (options) + av_dict_copy(&tmp2, *options, 0); + + if ((ret = s->iformat->read_header2(s, &tmp2)) < 0) + goto fail; + } else if (s->iformat->read_header && (ret = s->iformat->read_header(s)) < 0) goto fail; + } if (!s->metadata) { s->metadata = s->internal->id3v2_meta; @@ -615,6 +659,8 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, goto fail; if ((ret = ff_id3v2_parse_chapters(s, &id3v2_extra_meta)) < 0) goto fail; + if ((ret = ff_id3v2_parse_priv(s, &id3v2_extra_meta)) < 0) + goto fail; } else av_log(s, AV_LOG_DEBUG, "demuxer does not support additional id3 data, skipping\n"); } @@ -636,6 +682,7 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, if (options) { av_dict_free(options); *options = tmp; + av_dict_free(&tmp2); } *ps = s; return 0; @@ -643,6 +690,7 @@ int avformat_open_input(AVFormatContext **ps, const char *filename, fail: ff_id3v2_free_extra_meta(&id3v2_extra_meta); av_dict_free(&tmp); + av_dict_free(&tmp2); if (s->pb && !(s->flags & AVFMT_FLAG_CUSTOM_IO)) avio_closep(&s->pb); avformat_free_context(s); @@ -834,13 +882,9 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt) continue; } - if (!pkt->buf) { - AVPacket tmp = { 0 }; - ret = av_packet_ref(&tmp, pkt); - if (ret < 0) - return ret; - *pkt = tmp; - } + err = av_packet_make_refcounted(pkt); + if (err < 0) + return err; if ((s->flags & AVFMT_FLAG_DISCARD_CORRUPT) && (pkt->flags & AV_PKT_FLAG_CORRUPT)) { @@ -880,8 +924,9 @@ int ff_read_packet(AVFormatContext *s, AVPacket *pkt) if (!pktl && st->request_probe <= 0) return ret; - err = add_to_pktbuf(&s->internal->raw_packet_buffer, pkt, - &s->internal->raw_packet_buffer_end, 0); + err = ff_packet_list_put(&s->internal->raw_packet_buffer, + &s->internal->raw_packet_buffer_end, + pkt, 0); if (err) return err; s->internal->raw_packet_buffer_remaining_size -= pkt->size; @@ -900,6 +945,7 @@ static int determinable_frame_size(AVCodecContext *avctx) case AV_CODEC_ID_MP1: case AV_CODEC_ID_MP2: case AV_CODEC_ID_MP3: + case AV_CODEC_ID_CODEC2: return 1; } @@ -1093,6 +1139,7 @@ static void update_initial_timestamps(AVFormatContext *s, int stream_index, if (st->first_dts != AV_NOPTS_VALUE || dts == AV_NOPTS_VALUE || st->cur_dts == AV_NOPTS_VALUE || + st->cur_dts < INT_MIN + RELATIVE_TS_BASE || is_relative(dts)) return; @@ -1124,7 +1171,9 @@ static void update_initial_timestamps(AVFormatContext *s, int stream_index, } if (st->start_time == AV_NOPTS_VALUE) { - st->start_time = pts; + if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO || !(pkt->flags & AV_PKT_FLAG_DISCARD)) { + st->start_time = pts; + } if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && st->codecpar->sample_rate) st->start_time += av_rescale_q(st->skip_samples, (AVRational){1, st->codecpar->sample_rate}, st->time_base); } @@ -1376,14 +1425,17 @@ FF_ENABLE_DEPRECATION_WARNINGS #endif } -static void free_packet_buffer(AVPacketList **pkt_buf, AVPacketList **pkt_buf_end) +void ff_packet_list_free(AVPacketList **pkt_buf, AVPacketList **pkt_buf_end) { - while (*pkt_buf) { - AVPacketList *pktl = *pkt_buf; - *pkt_buf = pktl->next; + AVPacketList *tmp = *pkt_buf; + + while (tmp) { + AVPacketList *pktl = tmp; + tmp = pktl->next; av_packet_unref(&pktl->pkt); av_freep(&pktl); } + *pkt_buf = NULL; *pkt_buf_end = NULL; } @@ -1430,6 +1482,22 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index) if (!out_pkt.size) continue; + if (pkt->buf && out_pkt.data == pkt->data) { + /* reference pkt->buf only when out_pkt.data is guaranteed to point + * to data in it and not in the parser's internal buffer. */ + /* XXX: Ensure this is the case with all parsers when st->parser->flags + * is PARSER_FLAG_COMPLETE_FRAMES and check for that instead? */ + out_pkt.buf = av_buffer_ref(pkt->buf); + if (!out_pkt.buf) { + ret = AVERROR(ENOMEM); + goto fail; + } + } else { + ret = av_packet_make_refcounted(&out_pkt); + if (ret < 0) + goto fail; + } + if (pkt->side_data) { out_pkt.side_data = pkt->side_data; out_pkt.side_data_elems = pkt->side_data_elems; @@ -1453,6 +1521,7 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index) out_pkt.pts = st->parser->pts; out_pkt.dts = st->parser->dts; out_pkt.pos = st->parser->pos; + out_pkt.flags |= pkt->flags & AV_PKT_FLAG_DISCARD; if (st->need_parsing == AVSTREAM_PARSE_FULL_RAW) out_pkt.pos = st->parser->frame_offset; @@ -1467,11 +1536,13 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index) compute_pkt_fields(s, st, st->parser, &out_pkt, next_dts, next_pts); - ret = add_to_pktbuf(&s->internal->parse_queue, &out_pkt, - &s->internal->parse_queue_end, 1); - av_packet_unref(&out_pkt); - if (ret < 0) + ret = ff_packet_list_put(&s->internal->parse_queue, + &s->internal->parse_queue_end, + &out_pkt, 0); + if (ret < 0) { + av_packet_unref(&out_pkt); goto fail; + } } /* end of the stream => close and free the parser */ @@ -1485,9 +1556,9 @@ static int parse_packet(AVFormatContext *s, AVPacket *pkt, int stream_index) return ret; } -static int read_from_packet_buffer(AVPacketList **pkt_buffer, - AVPacketList **pkt_buffer_end, - AVPacket *pkt) +int ff_packet_list_get(AVPacketList **pkt_buffer, + AVPacketList **pkt_buffer_end, + AVPacket *pkt) { AVPacketList *pktl; av_assert0(*pkt_buffer); @@ -1633,7 +1704,7 @@ FF_ENABLE_DEPRECATION_WARNINGS } if (!got_packet && s->internal->parse_queue) - ret = read_from_packet_buffer(&s->internal->parse_queue, &s->internal->parse_queue_end, pkt); + ret = ff_packet_list_get(&s->internal->parse_queue, &s->internal->parse_queue_end, pkt); if (ret >= 0) { AVStream *st = s->streams[pkt->stream_index]; @@ -1677,13 +1748,6 @@ FF_ENABLE_DEPRECATION_WARNINGS } st->inject_global_side_data = 0; } - -#if FF_API_LAVF_MERGE_SD -FF_DISABLE_DEPRECATION_WARNINGS - if (!(s->flags & AVFMT_FLAG_KEEP_SIDE_DATA)) - av_packet_merge_side_data(pkt); -FF_ENABLE_DEPRECATION_WARNINGS -#endif } av_opt_get_dict_val(s, "metadata", AV_OPT_SEARCH_CHILDREN, &metadata); @@ -1719,7 +1783,7 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt) if (!genpts) { ret = s->internal->packet_buffer - ? read_from_packet_buffer(&s->internal->packet_buffer, + ? ff_packet_list_get(&s->internal->packet_buffer, &s->internal->packet_buffer_end, pkt) : read_frame_internal(s, pkt); if (ret < 0) @@ -1738,10 +1802,11 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt) // last dts seen for this stream. if any of packets following // current one had no dts, we will set this to AV_NOPTS_VALUE. int64_t last_dts = next_pkt->dts; + av_assert2(wrap_bits <= 64); while (pktl && next_pkt->pts == AV_NOPTS_VALUE) { if (pktl->pkt.stream_index == next_pkt->stream_index && - (av_compare_mod(next_pkt->dts, pktl->pkt.dts, 2LL << (wrap_bits - 1)) < 0)) { - if (av_compare_mod(pktl->pkt.pts, pktl->pkt.dts, 2LL << (wrap_bits - 1))) { + av_compare_mod(next_pkt->dts, pktl->pkt.dts, 2ULL << (wrap_bits - 1)) < 0) { + if (av_compare_mod(pktl->pkt.pts, pktl->pkt.dts, 2ULL << (wrap_bits - 1))) { // not B-frame next_pkt->pts = pktl->pkt.dts; } @@ -1767,7 +1832,7 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt) st = s->streams[next_pkt->stream_index]; if (!(next_pkt->pts == AV_NOPTS_VALUE && st->discard < AVDISCARD_ALL && next_pkt->dts != AV_NOPTS_VALUE && !eof)) { - ret = read_from_packet_buffer(&s->internal->packet_buffer, + ret = ff_packet_list_get(&s->internal->packet_buffer, &s->internal->packet_buffer_end, pkt); goto return_packet; } @@ -1782,8 +1847,9 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt) return ret; } - ret = add_to_pktbuf(&s->internal->packet_buffer, pkt, - &s->internal->packet_buffer_end, 1); + ret = ff_packet_list_put(&s->internal->packet_buffer, + &s->internal->packet_buffer_end, + pkt, FF_PACKETLIST_FLAG_REF_PACKET); av_packet_unref(pkt); if (ret < 0) return ret; @@ -1810,9 +1876,9 @@ static void flush_packet_queue(AVFormatContext *s) { if (!s->internal) return; - free_packet_buffer(&s->internal->parse_queue, &s->internal->parse_queue_end); - free_packet_buffer(&s->internal->packet_buffer, &s->internal->packet_buffer_end); - free_packet_buffer(&s->internal->raw_packet_buffer, &s->internal->raw_packet_buffer_end); + ff_packet_list_free(&s->internal->parse_queue, &s->internal->parse_queue_end); + ff_packet_list_free(&s->internal->packet_buffer, &s->internal->packet_buffer_end); + ff_packet_list_free(&s->internal->raw_packet_buffer, &s->internal->raw_packet_buffer_end); s->internal->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE; } @@ -2037,7 +2103,7 @@ void ff_configure_buffers_for_index(AVFormatContext *s, int64_t time_tolerance) int64_t pos_delta = 0; int64_t skip = 0; //We could use URLProtocol flags here but as many user applications do not use URLProtocols this would be unreliable - const char *proto = avio_find_protocol_name(s->filename); + const char *proto = avio_find_protocol_name(s->url); if (!proto) { av_log(s, AV_LOG_INFO, @@ -2610,7 +2676,7 @@ static void update_stream_timings(AVFormatContext *ic) else if (start_time > start_time_text) av_log(ic, AV_LOG_VERBOSE, "Ignoring outlier non primary stream starttime %f\n", start_time_text / (float)AV_TIME_BASE); - if (end_time == INT64_MIN || (end_time < end_time_text && end_time_text - end_time < AV_TIME_BASE)) { + if (end_time == INT64_MIN || (end_time < end_time_text && end_time_text - (uint64_t)end_time < AV_TIME_BASE)) { end_time = end_time_text; } else if (end_time < end_time_text) { av_log(ic, AV_LOG_VERBOSE, "Ignoring outlier non primary stream endtime %f\n", end_time_text / (float)AV_TIME_BASE); @@ -3214,23 +3280,20 @@ static int tb_unreliable(AVCodecContext *c) int ff_alloc_extradata(AVCodecParameters *par, int size) { - int ret; + av_freep(&par->extradata); + par->extradata_size = 0; - if (size < 0 || size >= INT32_MAX - AV_INPUT_BUFFER_PADDING_SIZE) { - par->extradata = NULL; - par->extradata_size = 0; + if (size < 0 || size >= INT32_MAX - AV_INPUT_BUFFER_PADDING_SIZE) return AVERROR(EINVAL); - } + par->extradata = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE); - if (par->extradata) { - memset(par->extradata + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); - par->extradata_size = size; - ret = 0; - } else { - par->extradata_size = 0; - ret = AVERROR(ENOMEM); - } - return ret; + if (!par->extradata) + return AVERROR(ENOMEM); + + memset(par->extradata + size, 0, AV_INPUT_BUFFER_PADDING_SIZE); + par->extradata_size = size; + + return 0; } int ff_get_extradata(AVFormatContext *s, AVCodecParameters *par, AVIOContext *pb, int size) @@ -3512,6 +3575,64 @@ int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options) int eof_reached = 0; int *missing_streams = av_opt_ptr(ic->iformat->priv_class, ic->priv_data, "missing_streams"); + AVDictionaryEntry *t; + + t = av_dict_get(ic->metadata, "nb-streams", NULL, AV_DICT_MATCH_CASE); + if (t) { + int nb_streams = (int) strtol(t->value, NULL, 10); + if (nb_streams > 0) { + int64_t read_size = 0; + int found_all_streams = 0; + while (!found_all_streams) { + if (read_size >= probesize) { + av_log(NULL, AV_LOG_INFO, "probe fail\n"); + return ic->nb_streams; + } + + ret = read_frame_internal(ic, &pkt1); + if (ret == AVERROR(EAGAIN)) + continue; + if (ret < 0) { + /* EOF or error*/ + eof_reached = 1; + break; + } + pkt = &pkt1; + + if (!(ic->streams[pkt->stream_index]->disposition & AV_DISPOSITION_ATTACHED_PIC)) + read_size += pkt->size; + + if (!(ic->flags & AVFMT_FLAG_NOBUFFER)) { + ret = ff_packet_list_put(&ic->internal->raw_packet_buffer, + &ic->internal->raw_packet_buffer_end, + pkt,0); + if (ret < 0) + return ret; + } + + for(i = 0; i < ic->nb_streams; i++) { + int64_t cur_start_time = AV_NOPTS_VALUE; + if (ic->streams[i]->start_time != AV_NOPTS_VALUE) { + cur_start_time = av_rescale_q(ic->streams[i]->start_time, + ic->streams[i]->time_base, + AV_TIME_BASE_Q); + } + if (cur_start_time != AV_NOPTS_VALUE && + (ic->start_time == AV_NOPTS_VALUE || ic->start_time > cur_start_time)){ + ic->start_time = cur_start_time; + } + } + + if (ic->nb_streams >= nb_streams && ic->start_time != AV_NOPTS_VALUE) { + av_log(NULL, AV_LOG_INFO, "probe pass\n"); + found_all_streams = 1; + } + } + av_dict_set_int(&ic->metadata, "nb-streams", 0, 0); + return ret < 0 ? ret : ic->nb_streams; + } + } + flush_codecs = probesize > 0; av_opt_set(ic, "skip_clear", "1", AV_OPT_SEARCH_CHILDREN); @@ -3629,10 +3750,25 @@ FF_ENABLE_DEPRECATION_WARNINGS /* check if one codec still needs to be handled */ for (i = 0; i < ic->nb_streams; i++) { int fps_analyze_framecount = 20; + int count; st = ic->streams[i]; if (!has_codec_parameters(st, NULL)) break; + + if (ic->metadata) { + AVDictionaryEntry *t = av_dict_get(ic->metadata, "skip-calc-frame-rate", NULL, AV_DICT_MATCH_CASE); + if (t) { + int fps_flag = (int) strtol(t->value, NULL, 10); + if (!st->r_frame_rate.num && st->avg_frame_rate.num > 0 && st->avg_frame_rate.den > 0 && fps_flag > 0) { + int avg_fps = st->avg_frame_rate.num / st->avg_frame_rate.den; + if (avg_fps > 0 && avg_fps <= 120) { + st->r_frame_rate.num = st->avg_frame_rate.num; + st->r_frame_rate.den = st->avg_frame_rate.den; + } + } + } + } /* If the timebase is coarse (like the usual millisecond precision * of mkv), we need to analyze more frames to reliably arrive at * the correct fps. */ @@ -3645,14 +3781,18 @@ FF_ENABLE_DEPRECATION_WARNINGS if (st->disposition & AV_DISPOSITION_ATTACHED_PIC) fps_analyze_framecount = 0; /* variable fps and no guess at the real fps */ + count = (ic->iformat->flags & AVFMT_NOTIMESTAMPS) ? + st->info->codec_info_duration_fields/2 : + st->info->duration_count; if (!(st->r_frame_rate.num && st->avg_frame_rate.num) && st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { - int count = (ic->iformat->flags & AVFMT_NOTIMESTAMPS) ? - st->info->codec_info_duration_fields/2 : - st->info->duration_count; if (count < fps_analyze_framecount) break; } + // Look at the first 3 frames if there is evidence of frame delay + // but the decoder delay is not set. + if (st->info->frame_delay_evidence && count < 2 && st->internal->avctx->has_b_frames == 0) + break; if (!st->internal->avctx->extradata && (!st->internal->extract_extradata.inited || st->internal->extract_extradata.bsf) && @@ -3710,8 +3850,9 @@ FF_ENABLE_DEPRECATION_WARNINGS pkt = &pkt1; if (!(ic->flags & AVFMT_FLAG_NOBUFFER)) { - ret = add_to_pktbuf(&ic->internal->packet_buffer, pkt, - &ic->internal->packet_buffer_end, 0); + ret = ff_packet_list_put(&ic->internal->packet_buffer, + &ic->internal->packet_buffer_end, + pkt, 0); if (ret < 0) goto find_stream_info_err; } @@ -3747,7 +3888,7 @@ FF_ENABLE_DEPRECATION_WARNINGS if (st->info->fps_last_dts != AV_NOPTS_VALUE && st->info->fps_last_dts_idx > st->info->fps_first_dts_idx && (pkt->dts - st->info->fps_last_dts) / 1000 > - (st->info->fps_last_dts - st->info->fps_first_dts) / + (st->info->fps_last_dts - (uint64_t)st->info->fps_first_dts) / (st->info->fps_last_dts_idx - st->info->fps_first_dts_idx)) { av_log(ic, AV_LOG_WARNING, "DTS discontinuity in stream %d: packet %d with DTS " @@ -3802,10 +3943,13 @@ FF_ENABLE_DEPRECATION_WARNINGS st->info->codec_info_duration_fields += st->parser && st->need_parsing && avctx->ticks_per_frame ==2 ? st->parser->repeat_pict + 1 : 2; } } + if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { #if FF_API_R_FRAME_RATE - if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) ff_rfps_add_frame(ic, st, pkt->dts); #endif + if (pkt->dts != pkt->pts && pkt->dts != AV_NOPTS_VALUE && pkt->pts != AV_NOPTS_VALUE) + st->info->frame_delay_evidence = 1; + } if (!st->internal->avctx->extradata) { ret = extract_extradata(st, pkt); if (ret < 0) @@ -3882,12 +4026,6 @@ FF_ENABLE_DEPRECATION_WARNINGS } } - // close codecs which were opened in try_decode_frame() - for (i = 0; i < ic->nb_streams; i++) { - st = ic->streams[i]; - avcodec_close(st->internal->avctx); - } - ff_rfps_calculate(ic); for (i = 0; i < ic->nb_streams; i++) { @@ -4027,11 +4165,13 @@ FF_ENABLE_DEPRECATION_WARNINGS ret = avcodec_parameters_from_context(st->codecpar, st->internal->avctx); if (ret < 0) goto find_stream_info_err; +#if FF_API_LOWRES // The decoder might reduce the video size by the lowres factor. - if (av_codec_get_lowres(st->internal->avctx) && orig_w) { + if (st->internal->avctx->lowres && orig_w) { st->codecpar->width = orig_w; st->codecpar->height = orig_h; } +#endif } #if FF_API_LAVF_AVCTX @@ -4040,13 +4180,15 @@ FF_DISABLE_DEPRECATION_WARNINGS if (ret < 0) goto find_stream_info_err; +#if FF_API_LOWRES // The old API (AVStream.codec) "requires" the resolution to be adjusted // by the lowres factor. - if (av_codec_get_lowres(st->internal->avctx) && st->internal->avctx->width) { - av_codec_set_lowres(st->codec, av_codec_get_lowres(st->internal->avctx)); + if (st->internal->avctx->lowres && st->internal->avctx->width) { + st->codec->lowres = st->internal->avctx->lowres; st->codec->width = st->internal->avctx->width; st->codec->height = st->internal->avctx->height; } +#endif if (st->codec->codec_tag != MKTAG('t','m','c','d')) { st->codec->time_base = st->internal->avctx->time_base; @@ -4078,6 +4220,7 @@ FF_ENABLE_DEPRECATION_WARNINGS st = ic->streams[i]; if (st->info) av_freep(&st->info->duration_error); + avcodec_close(ic->streams[i]->internal->avctx); av_freep(&ic->streams[i]->info); av_bsf_free(&ic->streams[i]->internal->extract_extradata.bsf); av_packet_free(&ic->streams[i]->internal->extract_extradata.pkt); @@ -4236,6 +4379,8 @@ int ff_stream_encode_params_copy(AVStream *dst, const AVStream *src) } } +#if FF_API_LAVF_FFSERVER +FF_DISABLE_DEPRECATION_WARNINGS av_freep(&dst->recommended_encoder_configuration); if (src->recommended_encoder_configuration) { const char *conf_str = src->recommended_encoder_configuration; @@ -4243,6 +4388,8 @@ int ff_stream_encode_params_copy(AVStream *dst, const AVStream *src) if (!dst->recommended_encoder_configuration) return AVERROR(ENOMEM); } +FF_ENABLE_DEPRECATION_WARNINGS +#endif return 0; } @@ -4271,6 +4418,7 @@ static void free_stream(AVStream **pst) av_bsf_free(&st->internal->bsfcs[i]); av_freep(&st->internal->bsfcs); } + av_freep(&st->internal->priv_pts); av_bsf_free(&st->internal->extract_extradata.bsf); av_packet_free(&st->internal->extract_extradata.pkt); } @@ -4289,8 +4437,11 @@ FF_ENABLE_DEPRECATION_WARNINGS if (st->info) av_freep(&st->info->duration_error); av_freep(&st->info); +#if FF_API_LAVF_FFSERVER +FF_DISABLE_DEPRECATION_WARNINGS av_freep(&st->recommended_encoder_configuration); - av_freep(&st->priv_pts); +FF_ENABLE_DEPRECATION_WARNINGS +#endif av_freep(pst); } @@ -4337,6 +4488,7 @@ void avformat_free_context(AVFormatContext *s) av_freep(&s->streams); flush_packet_queue(s); av_freep(&s->internal); + av_freep(&s->url); av_free(s); } @@ -4761,10 +4913,10 @@ void avpriv_set_pts_info(AVStream *s, int pts_wrap_bits, s->time_base = new_tb; #if FF_API_LAVF_AVCTX FF_DISABLE_DEPRECATION_WARNINGS - av_codec_set_pkt_timebase(s->codec, new_tb); + s->codec->pkt_timebase = new_tb; FF_ENABLE_DEPRECATION_WARNINGS #endif - av_codec_set_pkt_timebase(s->internal->avctx, new_tb); + s->internal->avctx->pkt_timebase = new_tb; s->pts_wrap_bits = pts_wrap_bits; } @@ -4853,7 +5005,6 @@ int avformat_network_init(void) { #if CONFIG_NETWORK int ret; - ff_network_inited_globally = 1; if ((ret = ff_network_init()) < 0) return ret; if ((ret = ff_tls_init()) < 0) @@ -4867,7 +5018,6 @@ int avformat_network_deinit(void) #if CONFIG_NETWORK ff_network_close(); ff_tls_deinit(); - ff_network_inited_globally = 0; #endif return 0; } @@ -5020,11 +5170,94 @@ FF_ENABLE_DEPRECATION_WARNINGS if (s->programs[i]->id != prog_id) continue; - if (*endptr++ == ':') { - int stream_idx = strtol(endptr, NULL, 0); - return stream_idx >= 0 && - stream_idx < s->programs[i]->nb_stream_indexes && - st->index == s->programs[i]->stream_index[stream_idx]; + if (*endptr++ == ':') { // p::.... + if ( *endptr == 'a' || *endptr == 'v' || + *endptr == 's' || *endptr == 'd') { // p::[:] + enum AVMediaType type; + + switch (*endptr++) { + case 'v': type = AVMEDIA_TYPE_VIDEO; break; + case 'a': type = AVMEDIA_TYPE_AUDIO; break; + case 's': type = AVMEDIA_TYPE_SUBTITLE; break; + case 'd': type = AVMEDIA_TYPE_DATA; break; + default: av_assert0(0); + } + if (*endptr++ == ':') { // p::: + int stream_idx = strtol(endptr, NULL, 0), type_counter = 0; + for (j = 0; j < s->programs[i]->nb_stream_indexes; j++) { + int stream_index = s->programs[i]->stream_index[j]; + if (st->index == s->programs[i]->stream_index[j]) { +#if FF_API_LAVF_AVCTX +FF_DISABLE_DEPRECATION_WARNINGS + return type_counter == stream_idx && + (type == st->codecpar->codec_type || + type == st->codec->codec_type); +FF_ENABLE_DEPRECATION_WARNINGS +#else + return type_counter == stream_idx && + type == st->codecpar->codec_type; +#endif + } +#if FF_API_LAVF_AVCTX +FF_DISABLE_DEPRECATION_WARNINGS + if (type == s->streams[stream_index]->codecpar->codec_type || + type == s->streams[stream_index]->codec->codec_type) + type_counter++; +FF_ENABLE_DEPRECATION_WARNINGS +#else + if (type == s->streams[stream_index]->codecpar->codec_type) + type_counter++; +#endif + } + return 0; + } else { // p:: + for (j = 0; j < s->programs[i]->nb_stream_indexes; j++) + if (st->index == s->programs[i]->stream_index[j]) { +#if FF_API_LAVF_AVCTX +FF_DISABLE_DEPRECATION_WARNINGS + return type == st->codecpar->codec_type || + type == st->codec->codec_type; +FF_ENABLE_DEPRECATION_WARNINGS +#else + return type == st->codecpar->codec_type; +#endif + } + return 0; + } + + } else if ( *endptr == 'm') { // p::m: + AVDictionaryEntry *tag; + char *key, *val; + int ret = 0; + + if (*(++endptr) != ':') { + av_log(s, AV_LOG_ERROR, "Invalid stream specifier syntax, missing ':' sign after :m.\n"); + return AVERROR(EINVAL); + } + + val = strchr(++endptr, ':'); + key = val ? av_strndup(endptr, val - endptr) : av_strdup(endptr); + if (!key) + return AVERROR(ENOMEM); + + for (j = 0; j < s->programs[i]->nb_stream_indexes; j++) + if (st->index == s->programs[i]->stream_index[j]) { + tag = av_dict_get(st->metadata, key, NULL, 0); + if (tag && (!val || !strcmp(tag->value, val + 1))) + ret = 1; + + break; + } + + av_freep(&key); + return ret; + + } else { // p:: + int stream_idx = strtol(endptr, NULL, 0); + return stream_idx >= 0 && + stream_idx < s->programs[i]->nb_stream_indexes && + st->index == s->programs[i]->stream_index[stream_idx]; + } } for (j = 0; j < s->programs[i]->nb_stream_indexes; j++) @@ -5251,13 +5484,8 @@ int ff_generate_avci_extradata(AVStream *st) return 0; } -#if FF_API_NOCONST_GET_SIDE_DATA -uint8_t *av_stream_get_side_data(AVStream *st, - enum AVPacketSideDataType type, int *size) -#else uint8_t *av_stream_get_side_data(const AVStream *st, enum AVPacketSideDataType type, int *size) -#endif { int i; @@ -5457,6 +5685,11 @@ void ff_format_io_close(AVFormatContext *s, AVIOContext **pb) *pb = NULL; } +int ff_is_http_proto(char *filename) { + const char *proto = avio_find_protocol_name(filename); + return proto ? (!av_strcasecmp(proto, "http") || !av_strcasecmp(proto, "https")) : 0; +} + int ff_parse_creation_time_metadata(AVFormatContext *s, int64_t *timestamp, int return_seconds) { AVDictionaryEntry *entry; @@ -5604,3 +5837,15 @@ FF_ENABLE_DEPRECATION_WARNINGS return st->internal->avctx->time_base; #endif } + +void ff_format_set_url(AVFormatContext *s, char *url) +{ + av_assert0(url); + av_freep(&s->url); + s->url = url; +#if FF_API_FORMAT_FILENAME +FF_DISABLE_DEPRECATION_WARNINGS + av_strlcpy(s->filename, url, sizeof(s->filename)); +FF_ENABLE_DEPRECATION_WARNINGS +#endif +} diff --git a/libavformat/version.h b/libavformat/version.h index 878917d65ddb1..a0a26d536e4c3 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -31,8 +31,8 @@ // Major bumping may affect Ticket5467, 5421, 5451(compatibility with Chromium) // Also please add any ticket numbers that you believe might be affected here -#define LIBAVFORMAT_VERSION_MAJOR 57 -#define LIBAVFORMAT_VERSION_MINOR 83 +#define LIBAVFORMAT_VERSION_MAJOR 58 +#define LIBAVFORMAT_VERSION_MINOR 12 #define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ @@ -55,47 +55,44 @@ * at once through the bump. This improves the git bisect-ability of the change. * */ -#ifndef FF_API_LAVF_BITEXACT -#define FF_API_LAVF_BITEXACT (LIBAVFORMAT_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_LAVF_FRAC -#define FF_API_LAVF_FRAC (LIBAVFORMAT_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_LAVF_CODEC_TB -#define FF_API_LAVF_CODEC_TB (LIBAVFORMAT_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_URL_FEOF -#define FF_API_URL_FEOF (LIBAVFORMAT_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_LAVF_FMT_RAWPICTURE -#define FF_API_LAVF_FMT_RAWPICTURE (LIBAVFORMAT_VERSION_MAJOR < 58) -#endif #ifndef FF_API_COMPUTE_PKT_FIELDS2 -#define FF_API_COMPUTE_PKT_FIELDS2 (LIBAVFORMAT_VERSION_MAJOR < 58) +#define FF_API_COMPUTE_PKT_FIELDS2 (LIBAVFORMAT_VERSION_MAJOR < 59) #endif #ifndef FF_API_OLD_OPEN_CALLBACKS -#define FF_API_OLD_OPEN_CALLBACKS (LIBAVFORMAT_VERSION_MAJOR < 58) +#define FF_API_OLD_OPEN_CALLBACKS (LIBAVFORMAT_VERSION_MAJOR < 59) #endif #ifndef FF_API_LAVF_AVCTX -#define FF_API_LAVF_AVCTX (LIBAVFORMAT_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_NOCONST_GET_SIDE_DATA -#define FF_API_NOCONST_GET_SIDE_DATA (LIBAVFORMAT_VERSION_MAJOR < 58) +#define FF_API_LAVF_AVCTX (LIBAVFORMAT_VERSION_MAJOR < 59) #endif #ifndef FF_API_HTTP_USER_AGENT -#define FF_API_HTTP_USER_AGENT (LIBAVFORMAT_VERSION_MAJOR < 58) +#define FF_API_HTTP_USER_AGENT (LIBAVFORMAT_VERSION_MAJOR < 59) #endif #ifndef FF_API_HLS_WRAP -#define FF_API_HLS_WRAP (LIBAVFORMAT_VERSION_MAJOR < 58) -#endif -#ifndef FF_API_LAVF_MERGE_SD -#define FF_API_LAVF_MERGE_SD (LIBAVFORMAT_VERSION_MAJOR < 58) +#define FF_API_HLS_WRAP (LIBAVFORMAT_VERSION_MAJOR < 59) #endif #ifndef FF_API_LAVF_KEEPSIDE_FLAG -#define FF_API_LAVF_KEEPSIDE_FLAG (LIBAVFORMAT_VERSION_MAJOR < 58) +#define FF_API_LAVF_KEEPSIDE_FLAG (LIBAVFORMAT_VERSION_MAJOR < 59) #endif #ifndef FF_API_OLD_ROTATE_API -#define FF_API_OLD_ROTATE_API (LIBAVFORMAT_VERSION_MAJOR < 58) +#define FF_API_OLD_ROTATE_API (LIBAVFORMAT_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_FORMAT_GET_SET +#define FF_API_FORMAT_GET_SET (LIBAVFORMAT_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_OLD_AVIO_EOF_0 +#define FF_API_OLD_AVIO_EOF_0 (LIBAVFORMAT_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_LAVF_FFSERVER +#define FF_API_LAVF_FFSERVER (LIBAVFORMAT_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_FORMAT_FILENAME +#define FF_API_FORMAT_FILENAME (LIBAVFORMAT_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_OLD_RTSP_OPTIONS +#define FF_API_OLD_RTSP_OPTIONS (LIBAVFORMAT_VERSION_MAJOR < 59) +#endif +#ifndef FF_API_NEXT +#define FF_API_NEXT (LIBAVFORMAT_VERSION_MAJOR < 59) #endif diff --git a/libavformat/wavdec.c b/libavformat/wavdec.c index b016185a1b733..e280be4d44e65 100644 --- a/libavformat/wavdec.c +++ b/libavformat/wavdec.c @@ -822,6 +822,7 @@ static int w64_read_header(AVFormatContext *s) samples = avio_rl64(pb); if (samples > 0) st->duration = samples; + avio_skip(pb, FFALIGN(size, INT64_C(8)) - 32); } else if (!memcmp(guid, ff_w64_guid_data, 16)) { wav->data_end = avio_tell(pb) + size - 24; diff --git a/libavformat/wavenc.c b/libavformat/wavenc.c index adb20cb215689..159119d693624 100644 --- a/libavformat/wavenc.c +++ b/libavformat/wavenc.c @@ -74,8 +74,6 @@ typedef struct WAVMuxContext { uint32_t peak_num_frames; uint32_t peak_outbuf_size; uint32_t peak_outbuf_bytes; - uint32_t peak_pos_pop; - uint16_t peak_pop; uint8_t *peak_output; int last_duration; int write_bext; @@ -195,7 +193,6 @@ static void peak_write_frame(AVFormatContext *s) { WAVMuxContext *wav = s->priv_data; AVCodecParameters *par = s->streams[0]->codecpar; - int peak_of_peaks; int c; if (!wav->peak_output) @@ -213,12 +210,6 @@ static void peak_write_frame(AVFormatContext *s) wav->peak_maxpos[c] = FFMAX(wav->peak_maxpos[c], wav->peak_maxneg[c]); - peak_of_peaks = FFMAX3(wav->peak_maxpos[c], wav->peak_maxneg[c], - wav->peak_pop); - if (peak_of_peaks > wav->peak_pop) - wav->peak_pos_pop = wav->peak_num_frames; - wav->peak_pop = peak_of_peaks; - if (wav->peak_outbuf_size - wav->peak_outbuf_bytes < wav->peak_format * wav->peak_ppv) { wav->peak_outbuf_size += PEAK_BUFFER_SIZE; @@ -287,7 +278,7 @@ static int peak_write_chunk(AVFormatContext *s) avio_wl32(pb, wav->peak_block_size); /* frames per value */ avio_wl32(pb, par->channels); /* number of channels */ avio_wl32(pb, wav->peak_num_frames); /* number of peak frames */ - avio_wl32(pb, wav->peak_pos_pop); /* audio sample frame index */ + avio_wl32(pb, -1); /* audio sample frame position (not implemented) */ avio_wl32(pb, 128); /* equal to size of header */ avio_write(pb, timestamp, 28); /* ASCII time stamp */ ffio_fill(pb, 0, 60); diff --git a/libavformat/webm_chunk.c b/libavformat/webm_chunk.c index f8dbaa3339506..549ec2879a5ef 100644 --- a/libavformat/webm_chunk.c +++ b/libavformat/webm_chunk.c @@ -99,8 +99,8 @@ static int get_chunk_filename(AVFormatContext *s, int is_header, char *filename) av_strlcpy(filename, wc->header_filename, strlen(wc->header_filename) + 1); } else { if (av_get_frame_filename(filename, MAX_FILENAME_SIZE, - s->filename, wc->chunk_index - 1) < 0) { - av_log(oc, AV_LOG_ERROR, "Invalid chunk filename template '%s'\n", s->filename); + s->url, wc->chunk_index - 1) < 0) { + av_log(oc, AV_LOG_ERROR, "Invalid chunk filename template '%s'\n", s->url); return AVERROR(EINVAL); } } @@ -119,7 +119,7 @@ static int webm_chunk_write_header(AVFormatContext *s) if (s->nb_streams != 1) { return AVERROR_INVALIDDATA; } wc->chunk_index = wc->chunk_start_index; - wc->oformat = av_guess_format("webm", s->filename, "video/webm"); + wc->oformat = av_guess_format("webm", s->url, "video/webm"); if (!wc->oformat) return AVERROR_MUXER_NOT_FOUND; @@ -127,12 +127,12 @@ static int webm_chunk_write_header(AVFormatContext *s) if (ret < 0) return ret; oc = wc->avf; - ret = get_chunk_filename(s, 1, oc->filename); + ret = get_chunk_filename(s, 1, oc->url); if (ret < 0) return ret; if (wc->http_method) av_dict_set(&options, "method", wc->http_method, 0); - ret = s->io_open(s, &oc->pb, oc->filename, AVIO_FLAG_WRITE, &options); + ret = s->io_open(s, &oc->pb, oc->url, AVIO_FLAG_WRITE, &options); av_dict_free(&options); if (ret < 0) return ret; diff --git a/libavformat/wtvdec.c b/libavformat/wtvdec.c index 27be5c9c04d90..301163bdcb1f6 100644 --- a/libavformat/wtvdec.c +++ b/libavformat/wtvdec.c @@ -65,7 +65,7 @@ static int64_t seek_by_sector(AVIOContext *pb, int64_t sector, int64_t offset) } /** - * @return bytes read, 0 on end of file, or <0 on error + * @return bytes read, AVERROR_EOF on end of file, or <0 on error */ static int wtvfile_read_packet(void *opaque, uint8_t *buf, int buf_size) { @@ -76,7 +76,7 @@ static int wtvfile_read_packet(void *opaque, uint8_t *buf, int buf_size) if (wf->error || pb->error) return -1; if (wf->position >= wf->length || avio_feof(pb)) - return 0; + return AVERROR_EOF; buf_size = FFMIN(buf_size, wf->length - wf->position); while(nread < buf_size) { diff --git a/libavformat/yuv4mpegdec.c b/libavformat/yuv4mpegdec.c index 462b823860642..ff0125e4cf306 100644 --- a/libavformat/yuv4mpegdec.c +++ b/libavformat/yuv4mpegdec.c @@ -126,6 +126,12 @@ static int yuv4_read_header(AVFormatContext *s) pix_fmt = AV_PIX_FMT_YUV444P; } else if (strncmp("mono16", tokstart, 6) == 0) { pix_fmt = AV_PIX_FMT_GRAY16; + } else if (strncmp("mono12", tokstart, 6) == 0) { + pix_fmt = AV_PIX_FMT_GRAY12; + } else if (strncmp("mono10", tokstart, 6) == 0) { + pix_fmt = AV_PIX_FMT_GRAY10; + } else if (strncmp("mono9", tokstart, 5) == 0) { + pix_fmt = AV_PIX_FMT_GRAY9; } else if (strncmp("mono", tokstart, 4) == 0) { pix_fmt = AV_PIX_FMT_GRAY8; } else { diff --git a/libavformat/yuv4mpegenc.c b/libavformat/yuv4mpegenc.c index b4dc6e9ef64eb..44f40bbad98d0 100644 --- a/libavformat/yuv4mpegenc.c +++ b/libavformat/yuv4mpegenc.c @@ -69,6 +69,15 @@ static int yuv4_generate_header(AVFormatContext *s, char* buf) case AV_PIX_FMT_GRAY8: colorspace = " Cmono"; break; + case AV_PIX_FMT_GRAY9: + colorspace = " Cmono9"; + break; + case AV_PIX_FMT_GRAY10: + colorspace = " Cmono10"; + break; + case AV_PIX_FMT_GRAY12: + colorspace = " Cmono12"; + break; case AV_PIX_FMT_GRAY16: colorspace = " Cmono16"; break; @@ -184,6 +193,9 @@ static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt) case AV_PIX_FMT_YUV422P: case AV_PIX_FMT_YUV444P: break; + case AV_PIX_FMT_GRAY9: + case AV_PIX_FMT_GRAY10: + case AV_PIX_FMT_GRAY12: case AV_PIX_FMT_GRAY16: case AV_PIX_FMT_YUV420P9: case AV_PIX_FMT_YUV422P9: @@ -213,7 +225,8 @@ static int yuv4_write_packet(AVFormatContext *s, AVPacket *pkt) ptr += frame->linesize[0]; } - if (st->codecpar->format != AV_PIX_FMT_GRAY8 && + if (st->codecpar->format != AV_PIX_FMT_GRAY8 && st->codecpar->format != AV_PIX_FMT_GRAY9 && + st->codecpar->format != AV_PIX_FMT_GRAY10 && st->codecpar->format != AV_PIX_FMT_GRAY12 && st->codecpar->format != AV_PIX_FMT_GRAY16) { // Adjust for smaller Cb and Cr planes av_pix_fmt_get_chroma_sub_sample(st->codecpar->format, &h_chroma_shift, @@ -255,11 +268,14 @@ static int yuv4_write_header(AVFormatContext *s) "stream, some mjpegtools might not work.\n"); break; case AV_PIX_FMT_GRAY8: - case AV_PIX_FMT_GRAY16: case AV_PIX_FMT_YUV420P: case AV_PIX_FMT_YUV422P: case AV_PIX_FMT_YUV444P: break; + case AV_PIX_FMT_GRAY9: + case AV_PIX_FMT_GRAY10: + case AV_PIX_FMT_GRAY12: + case AV_PIX_FMT_GRAY16: case AV_PIX_FMT_YUV420P9: case AV_PIX_FMT_YUV422P9: case AV_PIX_FMT_YUV444P9: @@ -291,7 +307,8 @@ static int yuv4_write_header(AVFormatContext *s) "yuv444p10, yuv422p10, yuv420p10, " "yuv444p12, yuv422p12, yuv420p12, " "yuv444p14, yuv422p14, yuv420p14, " - "yuv444p16, yuv422p16, yuv420p16 " + "yuv444p16, yuv422p16, yuv420p16, " + "gray9, gray10, gray12 " "and gray16 pixel formats. " "Use -pix_fmt to select one.\n"); return AVERROR(EIO); diff --git a/libavresample/avresample.h b/libavresample/avresample.h index 193443e2a6b17..5ac9adb44b9de 100644 --- a/libavresample/avresample.h +++ b/libavresample/avresample.h @@ -105,22 +105,31 @@ typedef struct AVAudioResampleContext AVAudioResampleContext; -/** Mixing Coefficient Types */ -enum AVMixCoeffType { +/** + * @deprecated use libswresample + * + * Mixing Coefficient Types */ +enum attribute_deprecated AVMixCoeffType { AV_MIX_COEFF_TYPE_Q8, /** 16-bit 8.8 fixed-point */ AV_MIX_COEFF_TYPE_Q15, /** 32-bit 17.15 fixed-point */ AV_MIX_COEFF_TYPE_FLT, /** floating-point */ AV_MIX_COEFF_TYPE_NB, /** Number of coeff types. Not part of ABI */ }; -/** Resampling Filter Types */ -enum AVResampleFilterType { +/** + * @deprecated use libswresample + * + * Resampling Filter Types */ +enum attribute_deprecated AVResampleFilterType { AV_RESAMPLE_FILTER_TYPE_CUBIC, /**< Cubic */ AV_RESAMPLE_FILTER_TYPE_BLACKMAN_NUTTALL, /**< Blackman Nuttall Windowed Sinc */ AV_RESAMPLE_FILTER_TYPE_KAISER, /**< Kaiser Windowed Sinc */ }; -enum AVResampleDitherMethod { +/** + * @deprecated use libswresample + */ +enum attribute_deprecated AVResampleDitherMethod { AV_RESAMPLE_DITHER_NONE, /**< Do not use dithering */ AV_RESAMPLE_DITHER_RECTANGULAR, /**< Rectangular Dither */ AV_RESAMPLE_DITHER_TRIANGULAR, /**< Triangular Dither*/ @@ -130,22 +139,37 @@ enum AVResampleDitherMethod { }; /** + * + * @deprecated use libswresample + * * Return the LIBAVRESAMPLE_VERSION_INT constant. */ +attribute_deprecated unsigned avresample_version(void); /** + * + * @deprecated use libswresample + * * Return the libavresample build-time configuration. * @return configure string */ +attribute_deprecated const char *avresample_configuration(void); /** + * + * @deprecated use libswresample + * * Return the libavresample license. */ +attribute_deprecated const char *avresample_license(void); /** + * + * @deprecated use libswresample + * * Get the AVClass for AVAudioResampleContext. * * Can be used in combination with AV_OPT_SEARCH_FAKE_OBJ for examining options @@ -155,16 +179,24 @@ const char *avresample_license(void); * * @return AVClass for AVAudioResampleContext */ +attribute_deprecated const AVClass *avresample_get_class(void); /** + * + * @deprecated use libswresample + * * Allocate AVAudioResampleContext and set options. * * @return allocated audio resample context, or NULL on failure */ +attribute_deprecated AVAudioResampleContext *avresample_alloc_context(void); /** + * + * @deprecated use libswresample + * * Initialize AVAudioResampleContext. * @note The context must be configured using the AVOption API. * @note The fields "in_channel_layout", "out_channel_layout", @@ -178,17 +210,25 @@ AVAudioResampleContext *avresample_alloc_context(void); * @param avr audio resample context * @return 0 on success, negative AVERROR code on failure */ +attribute_deprecated int avresample_open(AVAudioResampleContext *avr); /** + * + * @deprecated use libswresample + * * Check whether an AVAudioResampleContext is open or closed. * * @param avr AVAudioResampleContext to check * @return 1 if avr is open, 0 if avr is closed. */ +attribute_deprecated int avresample_is_open(AVAudioResampleContext *avr); /** + * + * @deprecated use libswresample + * * Close AVAudioResampleContext. * * This closes the context, but it does not change the parameters. The context @@ -201,18 +241,26 @@ int avresample_is_open(AVAudioResampleContext *avr); * * @param avr audio resample context */ +attribute_deprecated void avresample_close(AVAudioResampleContext *avr); /** + * + * @deprecated use libswresample + * * Free AVAudioResampleContext and associated AVOption values. * * This also calls avresample_close() before freeing. * * @param avr audio resample context */ +attribute_deprecated void avresample_free(AVAudioResampleContext **avr); /** + * + * @deprecated use libswresample + * * Generate a channel mixing matrix. * * This function is the one used internally by libavresample for building the @@ -234,12 +282,16 @@ void avresample_free(AVAudioResampleContext **avr); * @param matrix_encoding matrixed stereo downmix mode (e.g. dplii) * @return 0 on success, negative AVERROR code on failure */ +attribute_deprecated int avresample_build_matrix(uint64_t in_layout, uint64_t out_layout, double center_mix_level, double surround_mix_level, double lfe_mix_level, int normalize, double *matrix, int stride, enum AVMatrixEncoding matrix_encoding); /** + * + * @deprecated use libswresample + * * Get the current channel mixing matrix. * * If no custom matrix has been previously set or the AVAudioResampleContext is @@ -251,10 +303,14 @@ int avresample_build_matrix(uint64_t in_layout, uint64_t out_layout, * @param stride distance between adjacent input channels in the matrix array * @return 0 on success, negative AVERROR code on failure */ +attribute_deprecated int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix, int stride); /** + * + * @deprecated use libswresample + * * Set channel mixing matrix. * * Allows for setting a custom mixing matrix, overriding the default matrix @@ -272,10 +328,14 @@ int avresample_get_matrix(AVAudioResampleContext *avr, double *matrix, * @param stride distance between adjacent input channels in the matrix array * @return 0 on success, negative AVERROR code on failure */ +attribute_deprecated int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix, int stride); /** + * + * @deprecated use libswresample + * * Set a customized input channel mapping. * * This function can only be called when the allocated context is not open. @@ -302,10 +362,14 @@ int avresample_set_matrix(AVAudioResampleContext *avr, const double *matrix, * @param channel_map customized input channel mapping * @return 0 on success, negative AVERROR code on failure */ +attribute_deprecated int avresample_set_channel_mapping(AVAudioResampleContext *avr, const int *channel_map); /** + * + * @deprecated use libswresample + * * Set compensation for resampling. * * This can be called anytime after avresample_open(). If resampling is not @@ -318,10 +382,14 @@ int avresample_set_channel_mapping(AVAudioResampleContext *avr, * @param compensation_distance compensation distance, in samples * @return 0 on success, negative AVERROR code on failure */ +attribute_deprecated int avresample_set_compensation(AVAudioResampleContext *avr, int sample_delta, int compensation_distance); /** + * + * @deprecated use libswresample + * * Provide the upper bound on the number of samples the configured * conversion would output. * @@ -331,10 +399,13 @@ int avresample_set_compensation(AVAudioResampleContext *avr, int sample_delta, * @return number of samples or AVERROR(EINVAL) if the value * would exceed INT_MAX */ - +attribute_deprecated int avresample_get_out_samples(AVAudioResampleContext *avr, int in_nb_samples); /** + * + * @deprecated use libswresample + * * Convert input samples and write them to the output FIFO. * * The upper bound on the number of output samples can be obtained through @@ -376,12 +447,16 @@ int avresample_get_out_samples(AVAudioResampleContext *avr, int in_nb_samples); * not including converted samples added to the internal * output FIFO */ +attribute_deprecated int avresample_convert(AVAudioResampleContext *avr, uint8_t **output, int out_plane_size, int out_samples, uint8_t * const *input, int in_plane_size, int in_samples); /** + * + * @deprecated use libswresample + * * Return the number of samples currently in the resampling delay buffer. * * When resampling, there may be a delay between the input and output. Any @@ -394,9 +469,13 @@ int avresample_convert(AVAudioResampleContext *avr, uint8_t **output, * @param avr audio resample context * @return number of samples currently in the resampling delay buffer */ +attribute_deprecated int avresample_get_delay(AVAudioResampleContext *avr); /** + * + * @deprecated use libswresample + * * Return the number of available samples in the output FIFO. * * During conversion, if the user does not specify an output buffer or @@ -411,9 +490,13 @@ int avresample_get_delay(AVAudioResampleContext *avr); * @param avr audio resample context * @return number of samples available for reading */ +attribute_deprecated int avresample_available(AVAudioResampleContext *avr); /** + * + * @deprecated use libswresample + * * Read samples from the output FIFO. * * During conversion, if the user does not specify an output buffer or @@ -430,9 +513,13 @@ int avresample_available(AVAudioResampleContext *avr); * @param nb_samples number of samples to read from the FIFO * @return the number of samples written to output */ +attribute_deprecated int avresample_read(AVAudioResampleContext *avr, uint8_t **output, int nb_samples); /** + * + * @deprecated use libswresample + * * Convert the samples in the input AVFrame and write them to the output AVFrame. * * Input and output AVFrames must have channel_layout, sample_rate and format set. @@ -476,10 +563,14 @@ int avresample_read(AVAudioResampleContext *avr, uint8_t **output, int nb_sample * @return 0 on success, AVERROR on failure or nonmatching * configuration. */ +attribute_deprecated int avresample_convert_frame(AVAudioResampleContext *avr, AVFrame *output, AVFrame *input); /** + * + * @deprecated use libswresample + * * Configure or reconfigure the AVAudioResampleContext using the information * provided by the AVFrames. * @@ -494,6 +585,7 @@ int avresample_convert_frame(AVAudioResampleContext *avr, * @param in input AVFrame * @return 0 on success, AVERROR on failure. */ +attribute_deprecated int avresample_config(AVAudioResampleContext *avr, AVFrame *out, AVFrame *in); /** diff --git a/libavresample/version.h b/libavresample/version.h index 20c78c74d3f5a..d5d3ea82b133e 100644 --- a/libavresample/version.h +++ b/libavresample/version.h @@ -27,8 +27,8 @@ #include "libavutil/version.h" -#define LIBAVRESAMPLE_VERSION_MAJOR 3 -#define LIBAVRESAMPLE_VERSION_MINOR 7 +#define LIBAVRESAMPLE_VERSION_MAJOR 4 +#define LIBAVRESAMPLE_VERSION_MINOR 0 #define LIBAVRESAMPLE_VERSION_MICRO 0 #define LIBAVRESAMPLE_VERSION_INT AV_VERSION_INT(LIBAVRESAMPLE_VERSION_MAJOR, \ diff --git a/libavutil/Makefile b/libavutil/Makefile index 65e285a70114a..f4b03c6160651 100644 --- a/libavutil/Makefile +++ b/libavutil/Makefile @@ -4,6 +4,7 @@ DESC = FFmpeg utility library HEADERS = adler32.h \ aes.h \ aes_ctr.h \ + application.h \ attributes.h \ audio_fifo.h \ avassert.h \ @@ -24,6 +25,8 @@ HEADERS = adler32.h \ dict.h \ display.h \ downmix_info.h \ + encryption_info.h \ + dns_cache.h \ error.h \ eval.h \ fifo.h \ @@ -37,6 +40,7 @@ HEADERS = adler32.h \ hwcontext_drm.h \ hwcontext_dxva2.h \ hwcontext_qsv.h \ + hwcontext_mediacodec.h \ hwcontext_vaapi.h \ hwcontext_videotoolbox.h \ hwcontext_vdpau.h \ @@ -76,11 +80,10 @@ HEADERS = adler32.h \ version.h \ xtea.h \ tea.h \ + thread.h \ HEADERS-$(CONFIG_LZO) += lzo.h -HEADERS-$(CONFIG_OPENCL) += opencl.h - ARCH_HEADERS = bswap.h \ intmath.h \ intreadwrite.h \ @@ -92,6 +95,7 @@ BUILT_HEADERS = avconfig.h \ OBJS = adler32.o \ aes.o \ aes_ctr.o \ + application.o \ audio_fifo.o \ avstring.o \ base64.o \ @@ -108,6 +112,8 @@ OBJS = adler32.o \ dict.o \ display.o \ downmix_info.o \ + encryption_info.o \ + dns_cache.o \ error.o \ eval.o \ fifo.o \ @@ -156,18 +162,17 @@ OBJS = adler32.o \ xtea.o \ tea.o \ -OBJS-$(!HAVE_ATOMICS_NATIVE) += atomic.o \ - OBJS-$(CONFIG_CUDA) += hwcontext_cuda.o OBJS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.o OBJS-$(CONFIG_DXVA2) += hwcontext_dxva2.o OBJS-$(CONFIG_QSV) += hwcontext_qsv.o OBJS-$(CONFIG_LIBDRM) += hwcontext_drm.o OBJS-$(CONFIG_LZO) += lzo.o -OBJS-$(CONFIG_OPENCL) += opencl.o opencl_internal.o +OBJS-$(CONFIG_OPENCL) += hwcontext_opencl.o OBJS-$(CONFIG_VAAPI) += hwcontext_vaapi.o OBJS-$(CONFIG_VIDEOTOOLBOX) += hwcontext_videotoolbox.o OBJS-$(CONFIG_VDPAU) += hwcontext_vdpau.o +OBJS-$(CONFIG_MEDIACODEC) += hwcontext_mediacodec.o OBJS += $(COMPAT_OBJS:%=../compat/%) @@ -179,18 +184,14 @@ SKIPHEADERS-$(CONFIG_CUDA) += hwcontext_cuda_internal.h SKIPHEADERS-$(CONFIG_D3D11VA) += hwcontext_d3d11va.h SKIPHEADERS-$(CONFIG_DXVA2) += hwcontext_dxva2.h SKIPHEADERS-$(CONFIG_QSV) += hwcontext_qsv.h +SKIPHEADERS-$(CONFIG_OPENCL) += hwcontext_opencl.h SKIPHEADERS-$(CONFIG_VAAPI) += hwcontext_vaapi.h SKIPHEADERS-$(CONFIG_VIDEOTOOLBOX) += hwcontext_videotoolbox.h SKIPHEADERS-$(CONFIG_VDPAU) += hwcontext_vdpau.h -SKIPHEADERS-$(HAVE_ATOMICS_GCC) += atomic_gcc.h -SKIPHEADERS-$(HAVE_ATOMICS_SUNCC) += atomic_suncc.h -SKIPHEADERS-$(HAVE_ATOMICS_WIN32) += atomic_win32.h -SKIPHEADERS-$(CONFIG_OPENCL) += opencl.h TESTPROGS = adler32 \ aes \ aes_ctr \ - atomic \ audio_fifo \ avstring \ base64 \ @@ -210,6 +211,7 @@ TESTPROGS = adler32 \ fifo \ hash \ hmac \ + integer \ imgutils \ lfg \ lls \ diff --git a/libavutil/aarch64/asm.S b/libavutil/aarch64/asm.S index 42897294280b1..fd32bf784e095 100644 --- a/libavutil/aarch64/asm.S +++ b/libavutil/aarch64/asm.S @@ -23,7 +23,7 @@ #ifdef __ELF__ # define ELF #else -# define ELF # +# define ELF # #endif #if HAVE_AS_FUNC @@ -82,6 +82,15 @@ ELF .size \name, . - \name adrp \rd, \val+(\offset)@PAGE add \rd, \rd, \val+(\offset)@PAGEOFF .endif +#elif CONFIG_PIC && defined(_WIN32) + .if \offset < 0 + adrp \rd, \val + add \rd, \rd, :lo12:\val + sub \rd, \rd, -(\offset) + .else + adrp \rd, \val+(\offset) + add \rd, \rd, :lo12:\val+(\offset) + .endif #elif CONFIG_PIC adrp \rd, \val+(\offset) add \rd, \rd, :lo12:\val+(\offset) diff --git a/libavutil/aarch64/cpu.h b/libavutil/aarch64/cpu.h index cf1b9cc516893..2ee3f9323aff2 100644 --- a/libavutil/aarch64/cpu.h +++ b/libavutil/aarch64/cpu.h @@ -19,7 +19,6 @@ #ifndef AVUTIL_AARCH64_CPU_H #define AVUTIL_AARCH64_CPU_H -#include "config.h" #include "libavutil/cpu.h" #include "libavutil/cpu_internal.h" diff --git a/libavutil/aes_ctr.c b/libavutil/aes_ctr.c index e9c568fe0d13d..0c2e86785f1bb 100644 --- a/libavutil/aes_ctr.c +++ b/libavutil/aes_ctr.c @@ -45,6 +45,12 @@ void av_aes_ctr_set_iv(struct AVAESCTR *a, const uint8_t* iv) a->block_offset = 0; } +void av_aes_ctr_set_full_iv(struct AVAESCTR *a, const uint8_t* iv) +{ + memcpy(a->counter, iv, sizeof(a->counter)); + a->block_offset = 0; +} + const uint8_t* av_aes_ctr_get_iv(struct AVAESCTR *a) { return a->counter; diff --git a/libavutil/aes_ctr.h b/libavutil/aes_ctr.h index f596fa6a46bac..e4aae126a764b 100644 --- a/libavutil/aes_ctr.h +++ b/libavutil/aes_ctr.h @@ -67,10 +67,15 @@ const uint8_t* av_aes_ctr_get_iv(struct AVAESCTR *a); void av_aes_ctr_set_random_iv(struct AVAESCTR *a); /** - * Forcefully change the iv + * Forcefully change the 8-byte iv */ void av_aes_ctr_set_iv(struct AVAESCTR *a, const uint8_t* iv); +/** + * Forcefully change the "full" 16-byte iv, including the counter + */ +void av_aes_ctr_set_full_iv(struct AVAESCTR *a, const uint8_t* iv); + /** * Increment the top 64 bit of the iv (performed after each frame) */ diff --git a/libavutil/application.c b/libavutil/application.c new file mode 100644 index 0000000000000..99751876bd631 --- /dev/null +++ b/libavutil/application.c @@ -0,0 +1,214 @@ +/* + * copyright (c) 2016 Zhang Rui + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "application.h" +#include "libavformat/network.h" +#include "libavutil/avstring.h" + +void av_application_on_io_traffic(AVApplicationContext *h, AVAppIOTraffic *event); + +int av_application_alloc(AVApplicationContext **ph, void *opaque) +{ + AVApplicationContext *h = NULL; + + h = av_mallocz(sizeof(AVApplicationContext)); + if (!h) + return AVERROR(ENOMEM); + + h->opaque = opaque; + + *ph = h; + return 0; +} + +int av_application_open(AVApplicationContext **ph, void *opaque) +{ + int ret = av_application_alloc(ph, opaque); + if (ret) + return ret; + + return 0; +} + +void av_application_close(AVApplicationContext *h) +{ + av_free(h); +} + +void av_application_closep(AVApplicationContext **ph) +{ + if (!ph || !*ph) + return; + + av_application_close(*ph); + *ph = NULL; +} + +void av_application_on_http_event(AVApplicationContext *h, int event_type, AVAppHttpEvent *event) +{ + if (h && h->func_on_app_event) + h->func_on_app_event(h, event_type, (void *)event, sizeof(AVAppHttpEvent)); +} + +void av_application_will_http_open(AVApplicationContext *h, void *obj, const char *url) +{ + AVAppHttpEvent event = {0}; + + if (!h || !obj || !url) + return; + + event.obj = obj; + av_strlcpy(event.url, url, sizeof(event.url)); + + av_application_on_http_event(h, AVAPP_EVENT_WILL_HTTP_OPEN, &event); +} + +void av_application_did_http_open(AVApplicationContext *h, void *obj, const char *url, int error, int http_code, int64_t filesize) +{ + AVAppHttpEvent event = {0}; + + if (!h || !obj || !url) + return; + + event.obj = obj; + av_strlcpy(event.url, url, sizeof(event.url)); + event.error = error; + event.http_code = http_code; + event.filesize = filesize; + + av_application_on_http_event(h, AVAPP_EVENT_DID_HTTP_OPEN, &event); +} + +void av_application_will_http_seek(AVApplicationContext *h, void *obj, const char *url, int64_t offset) +{ + AVAppHttpEvent event = {0}; + + if (!h || !obj || !url) + return; + + event.obj = obj; + event.offset = offset; + av_strlcpy(event.url, url, sizeof(event.url)); + + av_application_on_http_event(h, AVAPP_EVENT_WILL_HTTP_SEEK, &event); +} + +void av_application_did_http_seek(AVApplicationContext *h, void *obj, const char *url, int64_t offset, int error, int http_code) +{ + AVAppHttpEvent event = {0}; + + if (!h || !obj || !url) + return; + + event.obj = obj; + event.offset = offset; + av_strlcpy(event.url, url, sizeof(event.url)); + event.error = error; + event.http_code = http_code; + + av_application_on_http_event(h, AVAPP_EVENT_DID_HTTP_SEEK, &event); +} + +void av_application_on_io_traffic(AVApplicationContext *h, AVAppIOTraffic *event) +{ + if (h && h->func_on_app_event) + h->func_on_app_event(h, AVAPP_EVENT_IO_TRAFFIC, (void *)event, sizeof(AVAppIOTraffic)); +} + +int av_application_on_io_control(AVApplicationContext *h, int event_type, AVAppIOControl *control) +{ + if (h && h->func_on_app_event) + return h->func_on_app_event(h, event_type, (void *)control, sizeof(AVAppIOControl)); + return 0; +} + +int av_application_on_tcp_will_open(AVApplicationContext *h) +{ + if (h && h->func_on_app_event) { + AVAppTcpIOControl control = {0}; + return h->func_on_app_event(h, AVAPP_CTRL_WILL_TCP_OPEN, (void *)&control, sizeof(AVAppTcpIOControl)); + } + return 0; +} + +// only callback returns error +int av_application_on_tcp_did_open(AVApplicationContext *h, int error, int fd, AVAppTcpIOControl *control) +{ + struct sockaddr_storage so_stg; + int ret = 0; + socklen_t so_len = sizeof(so_stg); + int so_family; + char *so_ip_name = control->ip; + + if (!h || !h->func_on_app_event || fd <= 0) + return 0; + + ret = getpeername(fd, (struct sockaddr *)&so_stg, &so_len); + if (ret) + return 0; + control->error = error; + control->fd = fd; + + so_family = ((struct sockaddr*)&so_stg)->sa_family; + switch (so_family) { + case AF_INET: { + struct sockaddr_in* in4 = (struct sockaddr_in*)&so_stg; + if (inet_ntop(AF_INET, &(in4->sin_addr), so_ip_name, sizeof(control->ip))) { + control->family = AF_INET; + control->port = in4->sin_port; + } + break; + } + case AF_INET6: { + struct sockaddr_in6* in6 = (struct sockaddr_in6*)&so_stg; + if (inet_ntop(AF_INET6, &(in6->sin6_addr), so_ip_name, sizeof(control->ip))) { + control->family = AF_INET6; + control->port = in6->sin6_port; + } + break; + } + } + + return h->func_on_app_event(h, AVAPP_CTRL_DID_TCP_OPEN, (void *)control, sizeof(AVAppTcpIOControl)); +} + +void av_application_on_async_statistic(AVApplicationContext *h, AVAppAsyncStatistic *statistic) +{ + if (h && h->func_on_app_event) + h->func_on_app_event(h, AVAPP_EVENT_ASYNC_STATISTIC, (void *)statistic, sizeof(AVAppAsyncStatistic)); +} + +void av_application_on_async_read_speed(AVApplicationContext *h, AVAppAsyncReadSpeed *speed) +{ + if (h && h->func_on_app_event) + h->func_on_app_event(h, AVAPP_EVENT_ASYNC_READ_SPEED, (void *)speed, sizeof(AVAppAsyncReadSpeed)); +} + +void av_application_did_io_tcp_read(AVApplicationContext *h, void *obj, int bytes) +{ + AVAppIOTraffic event = {0}; + if (!h || !obj || bytes <= 0) + return; + + event.obj = obj; + event.bytes = bytes; + + av_application_on_io_traffic(h, &event); +} diff --git a/libavutil/application.h b/libavutil/application.h new file mode 100644 index 0000000000000..72fe902789913 --- /dev/null +++ b/libavutil/application.h @@ -0,0 +1,121 @@ +/* + * copyright (c) 2016 Zhang Rui + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_APPLICATION_H +#define AVUTIL_APPLICATION_H + +#include "libavutil/log.h" + +#define AVAPP_EVENT_WILL_HTTP_OPEN 1 //AVAppHttpEvent +#define AVAPP_EVENT_DID_HTTP_OPEN 2 //AVAppHttpEvent +#define AVAPP_EVENT_WILL_HTTP_SEEK 3 //AVAppHttpEvent +#define AVAPP_EVENT_DID_HTTP_SEEK 4 //AVAppHttpEvent + +#define AVAPP_EVENT_ASYNC_STATISTIC 0x11000 //AVAppAsyncStatistic +#define AVAPP_EVENT_ASYNC_READ_SPEED 0x11001 //AVAppAsyncReadSpeed +#define AVAPP_EVENT_IO_TRAFFIC 0x12204 //AVAppIOTraffic + +#define AVAPP_CTRL_WILL_TCP_OPEN 0x20001 //AVAppTcpIOControl +#define AVAPP_CTRL_DID_TCP_OPEN 0x20002 //AVAppTcpIOControl + +#define AVAPP_CTRL_WILL_HTTP_OPEN 0x20003 //AVAppIOControl +#define AVAPP_CTRL_WILL_LIVE_OPEN 0x20005 //AVAppIOControl + +#define AVAPP_CTRL_WILL_CONCAT_SEGMENT_OPEN 0x20007 //AVAppIOControl + +typedef struct AVAppIOControl { + size_t size; + char url[4096]; /* in, out */ + int segment_index; /* in, default = 0 */ + int retry_counter; /* in */ + + int is_handled; /* out, default = false */ + int is_url_changed; /* out, default = false */ +} AVAppIOControl; + +typedef struct AVAppTcpIOControl { + int error; + int family; + char ip[96]; + int port; + int fd; +} AVAppTcpIOControl; + +typedef struct AVAppAsyncStatistic { + size_t size; + int64_t buf_backwards; + int64_t buf_forwards; + int64_t buf_capacity; +} AVAppAsyncStatistic; + +typedef struct AVAppAsyncReadSpeed { + size_t size; + int is_full_speed; + int64_t io_bytes; + int64_t elapsed_milli; +} AVAppAsyncReadSpeed; + +typedef struct AVAppHttpEvent +{ + void *obj; + char url[4096]; + int64_t offset; + int error; + int http_code; + int64_t filesize; +} AVAppHttpEvent; + +typedef struct AVAppIOTraffic +{ + void *obj; + int bytes; +} AVAppIOTraffic; + +typedef struct AVApplicationContext AVApplicationContext; +struct AVApplicationContext { + const AVClass *av_class; /**< information for av_log(). Set by av_application_open(). */ + void *opaque; /**< user data. */ + + int (*func_on_app_event)(AVApplicationContext *h, int event_type ,void *obj, size_t size); +}; + +int av_application_alloc(AVApplicationContext **ph, void *opaque); +int av_application_open(AVApplicationContext **ph, void *opaque); +void av_application_close(AVApplicationContext *h); +void av_application_closep(AVApplicationContext **ph); + +void av_application_on_http_event(AVApplicationContext *h, int event_type, AVAppHttpEvent *event); +void av_application_will_http_open(AVApplicationContext *h, void *obj, const char *url); +void av_application_did_http_open(AVApplicationContext *h, void *obj, const char *url, int error, int http_code, int64_t filesize); +void av_application_will_http_seek(AVApplicationContext *h, void *obj, const char *url, int64_t offset); +void av_application_did_http_seek(AVApplicationContext *h, void *obj, const char *url, int64_t offset, int error, int http_code); + +void av_application_did_io_tcp_read(AVApplicationContext *h, void *obj, int bytes); + +int av_application_on_io_control(AVApplicationContext *h, int event_type, AVAppIOControl *control); + +int av_application_on_tcp_will_open(AVApplicationContext *h); +int av_application_on_tcp_did_open(AVApplicationContext *h, int error, int fd, AVAppTcpIOControl *control); + +void av_application_on_async_statistic(AVApplicationContext *h, AVAppAsyncStatistic *statistic); +void av_application_on_async_read_speed(AVApplicationContext *h, AVAppAsyncReadSpeed *speed); + + +#endif /* AVUTIL_APPLICATION_H */ diff --git a/libavutil/arm/asm.S b/libavutil/arm/asm.S index 7d33a64fac38e..6744f2a200490 100644 --- a/libavutil/arm/asm.S +++ b/libavutil/arm/asm.S @@ -46,6 +46,7 @@ # define FPU @ #endif +#if HAVE_AS_ARCH_DIRECTIVE #if HAVE_NEON .arch armv7-a #elif HAVE_ARMV6T2 @@ -55,6 +56,7 @@ #elif HAVE_ARMV5TE .arch armv5te #endif +#endif #if HAVE_AS_OBJECT_ARCH ELF .object_arch armv4 #endif @@ -109,11 +111,17 @@ FUNC .func \name ELF .size \name, . - \name .purgem endconst .endm -.if HAVE_SECTION_DATA_REL_RO && \relocate +#if HAVE_SECTION_DATA_REL_RO +.if \relocate .section .data.rel.ro .else .section .rodata .endif +#elif !defined(__MACH__) + .section .rodata +#else + .const_data +#endif .align \align \name: .endm diff --git a/libavutil/arm/cpu.h b/libavutil/arm/cpu.h index eb64ed5fcd1a3..1d6cc65dc486e 100644 --- a/libavutil/arm/cpu.h +++ b/libavutil/arm/cpu.h @@ -19,7 +19,6 @@ #ifndef AVUTIL_ARM_CPU_H #define AVUTIL_ARM_CPU_H -#include "config.h" #include "libavutil/cpu.h" #include "libavutil/cpu_internal.h" diff --git a/libavutil/arm/float_dsp_init_vfp.c b/libavutil/arm/float_dsp_init_vfp.c index e15abf3f54c9a..05873e7e37546 100644 --- a/libavutil/arm/float_dsp_init_vfp.c +++ b/libavutil/arm/float_dsp_init_vfp.c @@ -36,11 +36,11 @@ void ff_butterflies_float_vfp(float *av_restrict v1, float *av_restrict v2, int av_cold void ff_float_dsp_init_vfp(AVFloatDSPContext *fdsp, int cpu_flags) { - if (!have_vfpv3(cpu_flags)) { + if (have_vfp_vm(cpu_flags)) { fdsp->vector_fmul = ff_vector_fmul_vfp; fdsp->vector_fmul_window = ff_vector_fmul_window_vfp; } fdsp->vector_fmul_reverse = ff_vector_fmul_reverse_vfp; - if (!have_vfpv3(cpu_flags)) + if (have_vfp_vm(cpu_flags)) fdsp->butterflies_float = ff_butterflies_float_vfp; } diff --git a/libavutil/arm/intmath.h b/libavutil/arm/intmath.h index 65e42c5733d89..5311a7d52b17b 100644 --- a/libavutil/arm/intmath.h +++ b/libavutil/arm/intmath.h @@ -94,6 +94,22 @@ static av_always_inline int av_sat_dadd32_arm(int a, int b) return r; } +#define av_sat_sub32 av_sat_sub32_arm +static av_always_inline int av_sat_sub32_arm(int a, int b) +{ + int r; + __asm__ ("qsub %0, %1, %2" : "=r"(r) : "r"(a), "r"(b)); + return r; +} + +#define av_sat_dsub32 av_sat_dsub32_arm +static av_always_inline int av_sat_dsub32_arm(int a, int b) +{ + int r; + __asm__ ("qdsub %0, %1, %2" : "=r"(r) : "r"(a), "r"(b)); + return r; +} + #endif /* HAVE_ARMV6_INLINE */ #if HAVE_ASM_MOD_Q diff --git a/libavutil/atomic.c b/libavutil/atomic.c deleted file mode 100644 index 64cff2576fd30..0000000000000 --- a/libavutil/atomic.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2012 Ronald S. Bultje - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "config.h" -#include "atomic.h" - -#if !HAVE_ATOMICS_NATIVE - -#if HAVE_PTHREADS - -#include - -static pthread_mutex_t atomic_lock = PTHREAD_MUTEX_INITIALIZER; - -int avpriv_atomic_int_get(volatile int *ptr) -{ - int res; - - pthread_mutex_lock(&atomic_lock); - res = *ptr; - pthread_mutex_unlock(&atomic_lock); - - return res; -} - -void avpriv_atomic_int_set(volatile int *ptr, int val) -{ - pthread_mutex_lock(&atomic_lock); - *ptr = val; - pthread_mutex_unlock(&atomic_lock); -} - -int avpriv_atomic_int_add_and_fetch(volatile int *ptr, int inc) -{ - int res; - - pthread_mutex_lock(&atomic_lock); - *ptr += inc; - res = *ptr; - pthread_mutex_unlock(&atomic_lock); - - return res; -} - -void *avpriv_atomic_ptr_cas(void * volatile *ptr, void *oldval, void *newval) -{ - void *ret; - pthread_mutex_lock(&atomic_lock); - ret = *ptr; - if (ret == oldval) - *ptr = newval; - pthread_mutex_unlock(&atomic_lock); - return ret; -} - -#elif !HAVE_THREADS - -int avpriv_atomic_int_get(volatile int *ptr) -{ - return *ptr; -} - -void avpriv_atomic_int_set(volatile int *ptr, int val) -{ - *ptr = val; -} - -int avpriv_atomic_int_add_and_fetch(volatile int *ptr, int inc) -{ - *ptr += inc; - return *ptr; -} - -void *avpriv_atomic_ptr_cas(void * volatile *ptr, void *oldval, void *newval) -{ - if (*ptr == oldval) { - *ptr = newval; - return oldval; - } - return *ptr; -} - -#else /* HAVE_THREADS */ - -/* This should never trigger, unless a new threading implementation - * without correct atomics dependencies in configure or a corresponding - * atomics implementation is added. */ -#error "Threading is enabled, but there is no implementation of atomic operations available" - -#endif /* HAVE_PTHREADS */ - -#endif /* !HAVE_ATOMICS_NATIVE */ diff --git a/libavutil/atomic.h b/libavutil/atomic.h deleted file mode 100644 index 15906d24c9cb8..0000000000000 --- a/libavutil/atomic.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2012 Ronald S. Bultje - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVUTIL_ATOMIC_H -#define AVUTIL_ATOMIC_H - -#include "config.h" - -#if HAVE_ATOMICS_NATIVE - -#if HAVE_ATOMICS_GCC -#include "atomic_gcc.h" -#elif HAVE_ATOMICS_WIN32 -#include "atomic_win32.h" -#elif HAVE_ATOMICS_SUNCC -#include "atomic_suncc.h" -#endif - -#else - -/** - * Load the current value stored in an atomic integer. - * - * @param ptr atomic integer - * @return the current value of the atomic integer - * @note This acts as a memory barrier. - */ -int avpriv_atomic_int_get(volatile int *ptr); - -/** - * Store a new value in an atomic integer. - * - * @param ptr atomic integer - * @param val the value to store in the atomic integer - * @note This acts as a memory barrier. - */ -void avpriv_atomic_int_set(volatile int *ptr, int val); - -/** - * Add a value to an atomic integer. - * - * @param ptr atomic integer - * @param inc the value to add to the atomic integer (may be negative) - * @return the new value of the atomic integer. - * @note This does NOT act as a memory barrier. This is primarily - * intended for reference counting. - */ -int avpriv_atomic_int_add_and_fetch(volatile int *ptr, int inc); - -/** - * Atomic pointer compare and swap. - * - * @param ptr pointer to the pointer to operate on - * @param oldval do the swap if the current value of *ptr equals to oldval - * @param newval value to replace *ptr with - * @return the value of *ptr before comparison - */ -void *avpriv_atomic_ptr_cas(void * volatile *ptr, void *oldval, void *newval); - -#endif /* HAVE_ATOMICS_NATIVE */ - -#endif /* AVUTIL_ATOMIC_H */ diff --git a/libavutil/atomic_gcc.h b/libavutil/atomic_gcc.h deleted file mode 100644 index 2bb43c3cea0e8..0000000000000 --- a/libavutil/atomic_gcc.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2012 Ronald S. Bultje - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVUTIL_ATOMIC_GCC_H -#define AVUTIL_ATOMIC_GCC_H - -#include - -#include "atomic.h" - -#define avpriv_atomic_int_get atomic_int_get_gcc -static inline int atomic_int_get_gcc(volatile int *ptr) -{ - __sync_synchronize(); - return *ptr; -} - -#define avpriv_atomic_int_set atomic_int_set_gcc -static inline void atomic_int_set_gcc(volatile int *ptr, int val) -{ - *ptr = val; - __sync_synchronize(); -} - -#define avpriv_atomic_int_add_and_fetch atomic_int_add_and_fetch_gcc -static inline int atomic_int_add_and_fetch_gcc(volatile int *ptr, int inc) -{ - return __sync_add_and_fetch(ptr, inc); -} - -#define avpriv_atomic_ptr_cas atomic_ptr_cas_gcc -static inline void *atomic_ptr_cas_gcc(void * volatile *ptr, - void *oldval, void *newval) -{ -#ifdef __ARMCC_VERSION - // armcc will throw an error if ptr is not an integer type - volatile uintptr_t *tmp = (volatile uintptr_t*)ptr; - return (void*)__sync_val_compare_and_swap(tmp, oldval, newval); -#else - return __sync_val_compare_and_swap(ptr, oldval, newval); -#endif -} - -#endif /* AVUTIL_ATOMIC_GCC_H */ diff --git a/libavutil/atomic_suncc.h b/libavutil/atomic_suncc.h deleted file mode 100644 index a75a37b47eb72..0000000000000 --- a/libavutil/atomic_suncc.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVUTIL_ATOMIC_SUNCC_H -#define AVUTIL_ATOMIC_SUNCC_H - -#include -#include - -#include "atomic.h" - -#define avpriv_atomic_int_get atomic_int_get_suncc -static inline int atomic_int_get_suncc(volatile int *ptr) -{ - __machine_rw_barrier(); - return *ptr; -} - -#define avpriv_atomic_int_set atomic_int_set_suncc -static inline void atomic_int_set_suncc(volatile int *ptr, int val) -{ - *ptr = val; - __machine_rw_barrier(); -} - -#define avpriv_atomic_int_add_and_fetch atomic_int_add_and_fetch_suncc -static inline int atomic_int_add_and_fetch_suncc(volatile int *ptr, int inc) -{ - return atomic_add_int_nv(ptr, inc); -} - -#define avpriv_atomic_ptr_cas atomic_ptr_cas_suncc -static inline void *atomic_ptr_cas_suncc(void * volatile *ptr, - void *oldval, void *newval) -{ - return atomic_cas_ptr(ptr, oldval, newval); -} - -#endif /* AVUTIL_ATOMIC_SUNCC_H */ diff --git a/libavutil/atomic_win32.h b/libavutil/atomic_win32.h deleted file mode 100644 index f7299336f6b10..0000000000000 --- a/libavutil/atomic_win32.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2012 Ronald S. Bultje - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef AVUTIL_ATOMIC_WIN32_H -#define AVUTIL_ATOMIC_WIN32_H - -#define WIN32_LEAN_AND_MEAN -#include - -#define avpriv_atomic_int_get atomic_int_get_win32 -static inline int atomic_int_get_win32(volatile int *ptr) -{ - MemoryBarrier(); - return *ptr; -} - -#define avpriv_atomic_int_set atomic_int_set_win32 -static inline void atomic_int_set_win32(volatile int *ptr, int val) -{ - *ptr = val; - MemoryBarrier(); -} - -#define avpriv_atomic_int_add_and_fetch atomic_int_add_and_fetch_win32 -static inline int atomic_int_add_and_fetch_win32(volatile int *ptr, int inc) -{ - return inc + InterlockedExchangeAdd(ptr, inc); -} - -#define avpriv_atomic_ptr_cas atomic_ptr_cas_win32 -static inline void *atomic_ptr_cas_win32(void * volatile *ptr, - void *oldval, void *newval) -{ - return InterlockedCompareExchangePointer(ptr, newval, oldval); -} - -#endif /* AVUTIL_ATOMIC_WIN32_H */ diff --git a/libavutil/attributes.h b/libavutil/attributes.h index 54d1901116912..ced108aa2c75a 100644 --- a/libavutil/attributes.h +++ b/libavutil/attributes.h @@ -66,19 +66,19 @@ # define av_noinline #endif -#if AV_GCC_VERSION_AT_LEAST(3,1) +#if AV_GCC_VERSION_AT_LEAST(3,1) || defined(__clang__) # define av_pure __attribute__((pure)) #else # define av_pure #endif -#if AV_GCC_VERSION_AT_LEAST(2,6) +#if AV_GCC_VERSION_AT_LEAST(2,6) || defined(__clang__) # define av_const __attribute__((const)) #else # define av_const #endif -#if AV_GCC_VERSION_AT_LEAST(4,3) +#if AV_GCC_VERSION_AT_LEAST(4,3) || defined(__clang__) # define av_cold __attribute__((cold)) #else # define av_cold @@ -138,19 +138,19 @@ # define av_used #endif -#if AV_GCC_VERSION_AT_LEAST(3,3) +#if AV_GCC_VERSION_AT_LEAST(3,3) || defined(__clang__) # define av_alias __attribute__((may_alias)) #else # define av_alias #endif -#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__) +#if (defined(__GNUC__) || defined(__clang__)) && !defined(__INTEL_COMPILER) # define av_uninit(x) x=x #else # define av_uninit(x) x #endif -#ifdef __GNUC__ +#if defined(__GNUC__) || defined(__clang__) # define av_builtin_constant_p __builtin_constant_p # define av_printf_format(fmtpos, attrpos) __attribute__((__format__(__printf__, fmtpos, attrpos))) #else @@ -158,7 +158,7 @@ # define av_printf_format(fmtpos, attrpos) #endif -#if AV_GCC_VERSION_AT_LEAST(2,5) +#if AV_GCC_VERSION_AT_LEAST(2,5) || defined(__clang__) # define av_noreturn __attribute__((noreturn)) #else # define av_noreturn diff --git a/libavutil/common.h b/libavutil/common.h index 8142b31fdbb20..0fffa67714e81 100644 --- a/libavutil/common.h +++ b/libavutil/common.h @@ -158,7 +158,7 @@ static av_always_inline av_const int64_t av_clip64_c(int64_t a, int64_t amin, in */ static av_always_inline av_const uint8_t av_clip_uint8_c(int a) { - if (a&(~0xFF)) return (-a)>>31; + if (a&(~0xFF)) return (~a)>>31; else return a; } @@ -180,7 +180,7 @@ static av_always_inline av_const int8_t av_clip_int8_c(int a) */ static av_always_inline av_const uint16_t av_clip_uint16_c(int a) { - if (a&(~0xFFFF)) return (-a)>>31; + if (a&(~0xFFFF)) return (~a)>>31; else return a; } @@ -260,13 +260,37 @@ static av_always_inline int av_sat_add32_c(int a, int b) * * @param a first value * @param b value doubled and added to a - * @return sum with signed saturation + * @return sum sat(a + sat(2*b)) with signed saturation */ static av_always_inline int av_sat_dadd32_c(int a, int b) { return av_sat_add32(a, av_sat_add32(b, b)); } +/** + * Subtract two signed 32-bit values with saturation. + * + * @param a one value + * @param b another value + * @return difference with signed saturation + */ +static av_always_inline int av_sat_sub32_c(int a, int b) +{ + return av_clipl_int32((int64_t)a - b); +} + +/** + * Subtract a doubled value from another value with saturation at both stages. + * + * @param a first value + * @param b value doubled and subtracted from a + * @return difference sat(a - sat(2*b)) with signed saturation + */ +static av_always_inline int av_sat_dsub32_c(int a, int b) +{ + return av_sat_sub32(a, av_sat_add32(b, b)); +} + /** * Clip a float value into the amin-amax range. * @param a value to clip @@ -513,6 +537,12 @@ static av_always_inline av_const int av_parity_c(uint32_t v) #ifndef av_sat_dadd32 # define av_sat_dadd32 av_sat_dadd32_c #endif +#ifndef av_sat_sub32 +# define av_sat_sub32 av_sat_sub32_c +#endif +#ifndef av_sat_dsub32 +# define av_sat_dsub32 av_sat_dsub32_c +#endif #ifndef av_clipf # define av_clipf av_clipf_c #endif diff --git a/libavutil/cpu.c b/libavutil/cpu.c index c8401b825809b..6548cc3042aa8 100644 --- a/libavutil/cpu.c +++ b/libavutil/cpu.c @@ -80,7 +80,8 @@ void av_force_cpu_flags(int arg){ AV_CPU_FLAG_XOP | AV_CPU_FLAG_FMA3 | AV_CPU_FLAG_FMA4 | - AV_CPU_FLAG_AVX2 )) + AV_CPU_FLAG_AVX2 | + AV_CPU_FLAG_AVX512 )) && !(arg & AV_CPU_FLAG_MMX)) { av_log(NULL, AV_LOG_WARNING, "MMX implied by specified flags\n"); arg |= AV_CPU_FLAG_MMX; @@ -126,6 +127,7 @@ int av_parse_cpu_flags(const char *s) #define CPUFLAG_AVX2 (AV_CPU_FLAG_AVX2 | CPUFLAG_AVX) #define CPUFLAG_BMI2 (AV_CPU_FLAG_BMI2 | AV_CPU_FLAG_BMI1) #define CPUFLAG_AESNI (AV_CPU_FLAG_AESNI | CPUFLAG_SSE42) +#define CPUFLAG_AVX512 (AV_CPU_FLAG_AVX512 | CPUFLAG_AVX2) static const AVOption cpuflags_opts[] = { { "flags" , NULL, 0, AV_OPT_TYPE_FLAGS, { .i64 = 0 }, INT64_MIN, INT64_MAX, .unit = "flags" }, #if ARCH_PPC @@ -154,6 +156,7 @@ int av_parse_cpu_flags(const char *s) { "3dnowext", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_3DNOWEXT }, .unit = "flags" }, { "cmov", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_CMOV }, .unit = "flags" }, { "aesni" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_AESNI }, .unit = "flags" }, + { "avx512" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = CPUFLAG_AVX512 }, .unit = "flags" }, #elif ARCH_ARM { "armv5te", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV5TE }, .unit = "flags" }, { "armv6", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_ARMV6 }, .unit = "flags" }, @@ -216,6 +219,7 @@ int av_parse_cpu_caps(unsigned *flags, const char *s) { "3dnowext", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_3DNOWEXT }, .unit = "flags" }, { "cmov", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_CMOV }, .unit = "flags" }, { "aesni", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_AESNI }, .unit = "flags" }, + { "avx512" , NULL, 0, AV_OPT_TYPE_CONST, { .i64 = AV_CPU_FLAG_AVX512 }, .unit = "flags" }, #define CPU_FLAG_P2 AV_CPU_FLAG_CMOV | AV_CPU_FLAG_MMX #define CPU_FLAG_P3 CPU_FLAG_P2 | AV_CPU_FLAG_MMX2 | AV_CPU_FLAG_SSE diff --git a/libavutil/cpu.h b/libavutil/cpu.h index 9e5d40affef65..8bb9eb606bf2a 100644 --- a/libavutil/cpu.h +++ b/libavutil/cpu.h @@ -55,6 +55,7 @@ #define AV_CPU_FLAG_FMA3 0x10000 ///< Haswell FMA3 functions #define AV_CPU_FLAG_BMI1 0x20000 ///< Bit Manipulation Instruction Set 1 #define AV_CPU_FLAG_BMI2 0x40000 ///< Bit Manipulation Instruction Set 2 +#define AV_CPU_FLAG_AVX512 0x100000 ///< AVX-512 functions: requires OS support even if YMM/ZMM registers aren't used #define AV_CPU_FLAG_ALTIVEC 0x0001 ///< standard #define AV_CPU_FLAG_VSX 0x0002 ///< ISA 2.06 diff --git a/libavutil/cpu_internal.h b/libavutil/cpu_internal.h index b8bf1e5396482..37122d1c5f588 100644 --- a/libavutil/cpu_internal.h +++ b/libavutil/cpu_internal.h @@ -19,6 +19,8 @@ #ifndef AVUTIL_CPU_INTERNAL_H #define AVUTIL_CPU_INTERNAL_H +#include "config.h" + #include "cpu.h" #define CPUEXT_SUFFIX(flags, suffix, cpuext) \ diff --git a/libavutil/crc.c b/libavutil/crc.c index 495732b1636b7..c45ea63a62217 100644 --- a/libavutil/crc.c +++ b/libavutil/crc.c @@ -20,6 +20,8 @@ #include "config.h" +#include "thread.h" +#include "avassert.h" #include "bswap.h" #include "common.h" #include "crc.h" @@ -50,6 +52,30 @@ static const AVCRC av_crc_table[AV_CRC_MAX][257] = { 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3, 0x01 }, + [AV_CRC_8_EBU] = { + 0x00, 0x1D, 0x3A, 0x27, 0x74, 0x69, 0x4E, 0x53, 0xE8, 0xF5, 0xD2, 0xCF, + 0x9C, 0x81, 0xA6, 0xBB, 0xCD, 0xD0, 0xF7, 0xEA, 0xB9, 0xA4, 0x83, 0x9E, + 0x25, 0x38, 0x1F, 0x02, 0x51, 0x4C, 0x6B, 0x76, 0x87, 0x9A, 0xBD, 0xA0, + 0xF3, 0xEE, 0xC9, 0xD4, 0x6F, 0x72, 0x55, 0x48, 0x1B, 0x06, 0x21, 0x3C, + 0x4A, 0x57, 0x70, 0x6D, 0x3E, 0x23, 0x04, 0x19, 0xA2, 0xBF, 0x98, 0x85, + 0xD6, 0xCB, 0xEC, 0xF1, 0x13, 0x0E, 0x29, 0x34, 0x67, 0x7A, 0x5D, 0x40, + 0xFB, 0xE6, 0xC1, 0xDC, 0x8F, 0x92, 0xB5, 0xA8, 0xDE, 0xC3, 0xE4, 0xF9, + 0xAA, 0xB7, 0x90, 0x8D, 0x36, 0x2B, 0x0C, 0x11, 0x42, 0x5F, 0x78, 0x65, + 0x94, 0x89, 0xAE, 0xB3, 0xE0, 0xFD, 0xDA, 0xC7, 0x7C, 0x61, 0x46, 0x5B, + 0x08, 0x15, 0x32, 0x2F, 0x59, 0x44, 0x63, 0x7E, 0x2D, 0x30, 0x17, 0x0A, + 0xB1, 0xAC, 0x8B, 0x96, 0xC5, 0xD8, 0xFF, 0xE2, 0x26, 0x3B, 0x1C, 0x01, + 0x52, 0x4F, 0x68, 0x75, 0xCE, 0xD3, 0xF4, 0xE9, 0xBA, 0xA7, 0x80, 0x9D, + 0xEB, 0xF6, 0xD1, 0xCC, 0x9F, 0x82, 0xA5, 0xB8, 0x03, 0x1E, 0x39, 0x24, + 0x77, 0x6A, 0x4D, 0x50, 0xA1, 0xBC, 0x9B, 0x86, 0xD5, 0xC8, 0xEF, 0xF2, + 0x49, 0x54, 0x73, 0x6E, 0x3D, 0x20, 0x07, 0x1A, 0x6C, 0x71, 0x56, 0x4B, + 0x18, 0x05, 0x22, 0x3F, 0x84, 0x99, 0xBE, 0xA3, 0xF0, 0xED, 0xCA, 0xD7, + 0x35, 0x28, 0x0F, 0x12, 0x41, 0x5C, 0x7B, 0x66, 0xDD, 0xC0, 0xE7, 0xFA, + 0xA9, 0xB4, 0x93, 0x8E, 0xF8, 0xE5, 0xC2, 0xDF, 0x8C, 0x91, 0xB6, 0xAB, + 0x10, 0x0D, 0x2A, 0x37, 0x64, 0x79, 0x5E, 0x43, 0xB2, 0xAF, 0x88, 0x95, + 0xC6, 0xDB, 0xFC, 0xE1, 0x5A, 0x47, 0x60, 0x7D, 0x2E, 0x33, 0x14, 0x09, + 0x7F, 0x62, 0x45, 0x58, 0x0B, 0x16, 0x31, 0x2C, 0x97, 0x8A, 0xAD, 0xB0, + 0xE3, 0xFE, 0xD9, 0xC4, 0x01 + }, [AV_CRC_16_ANSI] = { 0x0000, 0x0580, 0x0F80, 0x0A00, 0x1B80, 0x1E00, 0x1400, 0x1180, 0x3380, 0x3600, 0x3C00, 0x3980, 0x2800, 0x2D80, 0x2780, 0x2200, @@ -291,20 +317,25 @@ static const AVCRC av_crc_table[AV_CRC_MAX][257] = { #else #define CRC_TABLE_SIZE 1024 #endif -static struct { - uint8_t le; - uint8_t bits; - uint32_t poly; -} av_crc_table_params[AV_CRC_MAX] = { - [AV_CRC_8_ATM] = { 0, 8, 0x07 }, - [AV_CRC_16_ANSI] = { 0, 16, 0x8005 }, - [AV_CRC_16_CCITT] = { 0, 16, 0x1021 }, - [AV_CRC_24_IEEE] = { 0, 24, 0x864CFB }, - [AV_CRC_32_IEEE] = { 0, 32, 0x04C11DB7 }, - [AV_CRC_32_IEEE_LE] = { 1, 32, 0xEDB88320 }, - [AV_CRC_16_ANSI_LE] = { 1, 16, 0xA001 }, -}; static AVCRC av_crc_table[AV_CRC_MAX][CRC_TABLE_SIZE]; + +#define DECLARE_CRC_INIT_TABLE_ONCE(id, le, bits, poly) \ +static AVOnce id ## _once_control = AV_ONCE_INIT; \ +static void id ## _init_table_once(void) \ +{ \ + av_assert0(av_crc_init(av_crc_table[id], le, bits, poly, sizeof(av_crc_table[id])) >= 0); \ +} + +#define CRC_INIT_TABLE_ONCE(id) ff_thread_once(&id ## _once_control, id ## _init_table_once) + +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_8_ATM, 0, 8, 0x07) +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_8_EBU, 0, 8, 0x1D) +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_16_ANSI, 0, 16, 0x8005) +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_16_CCITT, 0, 16, 0x1021) +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_24_IEEE, 0, 24, 0x864CFB) +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_32_IEEE, 0, 32, 0x04C11DB7) +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_32_IEEE_LE, 1, 32, 0xEDB88320) +DECLARE_CRC_INIT_TABLE_ONCE(AV_CRC_16_ANSI_LE, 1, 16, 0xA001) #endif int av_crc_init(AVCRC *ctx, int le, int bits, uint32_t poly, int ctx_size) @@ -343,13 +374,17 @@ int av_crc_init(AVCRC *ctx, int le, int bits, uint32_t poly, int ctx_size) const AVCRC *av_crc_get_table(AVCRCId crc_id) { #if !CONFIG_HARDCODED_TABLES - if (!av_crc_table[crc_id][FF_ARRAY_ELEMS(av_crc_table[crc_id]) - 1]) - if (av_crc_init(av_crc_table[crc_id], - av_crc_table_params[crc_id].le, - av_crc_table_params[crc_id].bits, - av_crc_table_params[crc_id].poly, - sizeof(av_crc_table[crc_id])) < 0) - return NULL; + switch (crc_id) { + case AV_CRC_8_ATM: CRC_INIT_TABLE_ONCE(AV_CRC_8_ATM); break; + case AV_CRC_8_EBU: CRC_INIT_TABLE_ONCE(AV_CRC_8_EBU); break; + case AV_CRC_16_ANSI: CRC_INIT_TABLE_ONCE(AV_CRC_16_ANSI); break; + case AV_CRC_16_CCITT: CRC_INIT_TABLE_ONCE(AV_CRC_16_CCITT); break; + case AV_CRC_24_IEEE: CRC_INIT_TABLE_ONCE(AV_CRC_24_IEEE); break; + case AV_CRC_32_IEEE: CRC_INIT_TABLE_ONCE(AV_CRC_32_IEEE); break; + case AV_CRC_32_IEEE_LE: CRC_INIT_TABLE_ONCE(AV_CRC_32_IEEE_LE); break; + case AV_CRC_16_ANSI_LE: CRC_INIT_TABLE_ONCE(AV_CRC_16_ANSI_LE); break; + default: av_assert0(0); + } #endif return av_crc_table[crc_id]; } diff --git a/libavutil/crc.h b/libavutil/crc.h index 2a1b0d7624502..47e22b4c7872b 100644 --- a/libavutil/crc.h +++ b/libavutil/crc.h @@ -53,11 +53,8 @@ typedef enum { AV_CRC_32_IEEE, AV_CRC_32_IEEE_LE, /*< reversed bitorder version of AV_CRC_32_IEEE */ AV_CRC_16_ANSI_LE, /*< reversed bitorder version of AV_CRC_16_ANSI */ -#if FF_API_CRC_BIG_TABLE - AV_CRC_24_IEEE = 12, -#else AV_CRC_24_IEEE, -#endif /* FF_API_CRC_BIG_TABLE */ + AV_CRC_8_EBU, AV_CRC_MAX, /*< Not part of public API! Do not use outside libavutil. */ }AVCRCId; diff --git a/libavutil/dict.c b/libavutil/dict.c index 0ea71386e5aea..521d49f2f4078 100644 --- a/libavutil/dict.c +++ b/libavutil/dict.c @@ -42,7 +42,7 @@ AVDictionaryEntry *av_dict_get(const AVDictionary *m, const char *key, { unsigned int i, j; - if (!m) + if (!m || !key) return NULL; if (prev) diff --git a/libavutil/dns_cache.c b/libavutil/dns_cache.c new file mode 100644 index 0000000000000..5135c0a5ce604 --- /dev/null +++ b/libavutil/dns_cache.c @@ -0,0 +1,229 @@ +/* + * copyright (c) 2017 Raymond Zheng + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * 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/dns_cache.h" +#include "libavutil/time.h" +#include "libavformat/network.h" + +#if HAVE_PTHREADS +#include +#endif + +typedef struct DnsCacheContext DnsCacheContext; +typedef struct DnsCacheContext { + AVDictionary *dns_dictionary; + pthread_mutex_t dns_dictionary_mutex; + int initialized; +} DnsCacheContext; + +static DnsCacheContext *context = NULL; +static pthread_once_t key_once = PTHREAD_ONCE_INIT; + +static void inner_init(void) { + int ret = 0; + context = (DnsCacheContext *) av_mallocz(sizeof(DnsCacheContext)); + if (context) { + ret = pthread_mutex_init(&context->dns_dictionary_mutex, NULL); + if (!ret) { + context->initialized = 1; + } else { + av_freep(&context); + } + } +} + +static void free_private_addrinfo(struct addrinfo **p_ai) { + struct addrinfo *ai = *p_ai; + + if (ai) { + if (ai->ai_addr) { + av_freep(&ai->ai_addr); + } + av_freep(p_ai); + } +} + +static int inner_remove_dns_cache(const char *uri, DnsCacheEntry *dns_cache_entry) { + if (context && dns_cache_entry) { + if (dns_cache_entry->ref_count == 0) { + av_dict_set_int(&context->dns_dictionary, uri, 0, 0); + free_private_addrinfo(&dns_cache_entry->res); + av_freep(&dns_cache_entry); + } else { + dns_cache_entry->delete_flag = 1; + } + } + + return 0; +} + +static DnsCacheEntry *new_dns_cache_entry(const char *uri, struct addrinfo *cur_ai, int64_t timeout) { + DnsCacheEntry *new_entry = NULL; + int64_t cur_time = av_gettime_relative(); + + if (cur_time < 0) { + goto fail; + } + + new_entry = (DnsCacheEntry *) av_mallocz(sizeof(struct DnsCacheEntry)); + if (!new_entry) { + goto fail; + } + + new_entry->res = (struct addrinfo *) av_mallocz(sizeof(struct addrinfo)); + if (!new_entry->res) { + av_freep(&new_entry); + goto fail; + } + + memcpy(new_entry->res, cur_ai, sizeof(struct addrinfo)); + + new_entry->res->ai_addr = (struct sockaddr *) av_mallocz(sizeof(struct sockaddr)); + if (!new_entry->res->ai_addr) { + av_freep(&new_entry->res); + av_freep(&new_entry); + goto fail; + } + + memcpy(new_entry->res->ai_addr, cur_ai->ai_addr, sizeof(struct sockaddr)); + new_entry->res->ai_canonname = NULL; + new_entry->res->ai_next = NULL; + new_entry->ref_count = 0; + new_entry->delete_flag = 0; + new_entry->expired_time = cur_time + timeout * 1000; + + return new_entry; + +fail: + return NULL; +} + +DnsCacheEntry *get_dns_cache_reference(const char *uri) { + AVDictionaryEntry *elem = NULL; + DnsCacheEntry *dns_cache_entry = NULL; + int64_t cur_time = av_gettime_relative(); + + if (cur_time < 0 || !uri || strlen(uri) == 0) { + return NULL; + } + + if (!context || !context->initialized) { +#if HAVE_PTHREADS + pthread_once(&key_once, inner_init); +#endif + } + + if (context && context->initialized) { + pthread_mutex_lock(&context->dns_dictionary_mutex); + elem = av_dict_get(context->dns_dictionary, uri, NULL, AV_DICT_MATCH_CASE); + if (elem) { + dns_cache_entry = (DnsCacheEntry *) (intptr_t) strtoll(elem->value, NULL, 10); + if (dns_cache_entry) { + if (dns_cache_entry->expired_time < cur_time) { + inner_remove_dns_cache(uri, dns_cache_entry); + dns_cache_entry = NULL; + } else { + dns_cache_entry->ref_count++; + } + } + } + pthread_mutex_unlock(&context->dns_dictionary_mutex); + } + + return dns_cache_entry; +} + +int release_dns_cache_reference(const char *uri, DnsCacheEntry **p_entry) { + DnsCacheEntry *entry = *p_entry; + + if (!uri || strlen(uri) == 0) { + return -1; + } + + if (context && context->initialized && entry) { + pthread_mutex_lock(&context->dns_dictionary_mutex); + entry->ref_count--; + if (entry->delete_flag && entry->ref_count == 0) { + inner_remove_dns_cache(uri, entry); + entry = NULL; + } + pthread_mutex_unlock(&context->dns_dictionary_mutex); + } + return 0; +} + +int remove_dns_cache_entry(const char *uri) { + AVDictionaryEntry *elem = NULL; + DnsCacheEntry *dns_cache_entry = NULL; + + if (!uri || strlen(uri) == 0) { + return -1; + } + + if (context && context->initialized) { + pthread_mutex_lock(&context->dns_dictionary_mutex); + elem = av_dict_get(context->dns_dictionary, uri, NULL, AV_DICT_MATCH_CASE); + if (elem) { + dns_cache_entry = (DnsCacheEntry *) (intptr_t) strtoll(elem->value, NULL, 10); + if (dns_cache_entry) { + inner_remove_dns_cache(uri, dns_cache_entry); + } + } + pthread_mutex_unlock(&context->dns_dictionary_mutex); + } + + return 0; +} + +int add_dns_cache_entry(const char *uri, struct addrinfo *cur_ai, int64_t timeout) { + DnsCacheEntry *new_entry = NULL; + DnsCacheEntry *old_entry = NULL; + AVDictionaryEntry *elem = NULL; + + if (!uri || strlen(uri) == 0 || timeout <= 0) { + goto fail; + } + + if (cur_ai == NULL || cur_ai->ai_addr == NULL) { + goto fail; + } + + if (context && context->initialized) { + pthread_mutex_lock(&context->dns_dictionary_mutex); + elem = av_dict_get(context->dns_dictionary, uri, NULL, AV_DICT_MATCH_CASE); + if (elem) { + old_entry = (DnsCacheEntry *) (intptr_t) strtoll(elem->value, NULL, 10); + if (old_entry) { + pthread_mutex_unlock(&context->dns_dictionary_mutex); + goto fail; + } + } + new_entry = new_dns_cache_entry(uri, cur_ai, timeout); + if (new_entry) { + av_dict_set_int(&context->dns_dictionary, uri, (int64_t) (intptr_t) new_entry, 0); + } + pthread_mutex_unlock(&context->dns_dictionary_mutex); + + return 0; + } + +fail: + return -1; +} diff --git a/libavutil/dns_cache.h b/libavutil/dns_cache.h new file mode 100644 index 0000000000000..69b47bbc43772 --- /dev/null +++ b/libavutil/dns_cache.h @@ -0,0 +1,38 @@ +/* + * copyright (c) 2017 Raymond Zheng + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General 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_DNS_CACHE_H +#define AVUTIL_DNS_CACHE_H + +#include "libavutil/log.h" + +typedef struct DnsCacheEntry { + volatile int ref_count; + volatile int delete_flag; + int64_t expired_time; + struct addrinfo *res; // construct by private function, not support ai_next and ai_canonname, can only be released using free_private_addrinfo +} DnsCacheEntry; + +DnsCacheEntry *get_dns_cache_reference(const char *uri); +int release_dns_cache_reference(const char *uri, DnsCacheEntry **p_entry); +int remove_dns_cache_entry(const char *uri); +int add_dns_cache_entry(const char *uri, struct addrinfo *cur_ai, int64_t timeout); + +#endif /* AVUTIL_DNS_CACHE_H */ diff --git a/libavutil/encryption_info.c b/libavutil/encryption_info.c new file mode 100644 index 0000000000000..20a752d6b4ab2 --- /dev/null +++ b/libavutil/encryption_info.c @@ -0,0 +1,295 @@ +/** + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "encryption_info.h" +#include "mem.h" +#include "intreadwrite.h" + +#define FF_ENCRYPTION_INFO_EXTRA 24 + +// The format of the AVEncryptionInfo side data: +// u32be scheme +// u32be crypt_byte_block +// u32be skip_byte_block +// u32be key_id_size +// u32be iv_size +// u32be subsample_count +// u8[key_id_size] key_id +// u8[iv_size] iv +// { +// u32be bytes_of_clear_data +// u32be bytes_of_protected_data +// }[subsample_count] + +AVEncryptionInfo *av_encryption_info_alloc(uint32_t subsample_count, uint32_t key_id_size, uint32_t iv_size) +{ + AVEncryptionInfo *info; + + info = av_mallocz(sizeof(*info)); + if (!info) + return NULL; + + info->key_id = av_mallocz(key_id_size); + info->key_id_size = key_id_size; + info->iv = av_mallocz(iv_size); + info->iv_size = iv_size; + info->subsamples = av_mallocz_array(subsample_count, sizeof(*info->subsamples)); + info->subsample_count = subsample_count; + + // Allow info->subsamples to be NULL if there are no subsamples. + if (!info->key_id || !info->iv || (!info->subsamples && subsample_count)) { + av_encryption_info_free(info); + return NULL; + } + + return info; +} + +AVEncryptionInfo *av_encryption_info_clone(const AVEncryptionInfo *info) +{ + AVEncryptionInfo *ret; + + ret = av_encryption_info_alloc(info->subsample_count, info->key_id_size, info->iv_size); + if (!ret) + return NULL; + + ret->scheme = info->scheme; + ret->crypt_byte_block = info->crypt_byte_block; + ret->skip_byte_block = info->skip_byte_block; + memcpy(ret->iv, info->iv, info->iv_size); + memcpy(ret->key_id, info->key_id, info->key_id_size); + memcpy(ret->subsamples, info->subsamples, sizeof(*info->subsamples) * info->subsample_count); + return ret; +} + +void av_encryption_info_free(AVEncryptionInfo *info) +{ + if (info) { + av_free(info->key_id); + av_free(info->iv); + av_free(info->subsamples); + av_free(info); + } +} + +AVEncryptionInfo *av_encryption_info_get_side_data(const uint8_t* buffer, size_t size) +{ + AVEncryptionInfo *info; + uint64_t key_id_size, iv_size, subsample_count, i; + + if (!buffer || size < FF_ENCRYPTION_INFO_EXTRA) + return NULL; + + key_id_size = AV_RB32(buffer + 12); + iv_size = AV_RB32(buffer + 16); + subsample_count = AV_RB32(buffer + 20); + + if (size < FF_ENCRYPTION_INFO_EXTRA + key_id_size + iv_size + subsample_count * 8) + return NULL; + + info = av_encryption_info_alloc(subsample_count, key_id_size, iv_size); + if (!info) + return NULL; + + info->scheme = AV_RB32(buffer); + info->crypt_byte_block = AV_RB32(buffer + 4); + info->skip_byte_block = AV_RB32(buffer + 8); + memcpy(info->key_id, buffer + 24, key_id_size); + memcpy(info->iv, buffer + key_id_size + 24, iv_size); + + buffer += key_id_size + iv_size + 24; + for (i = 0; i < subsample_count; i++) { + info->subsamples[i].bytes_of_clear_data = AV_RB32(buffer); + info->subsamples[i].bytes_of_protected_data = AV_RB32(buffer + 4); + buffer += 8; + } + + return info; +} + +uint8_t *av_encryption_info_add_side_data(const AVEncryptionInfo *info, size_t *size) +{ + uint8_t *buffer, *cur_buffer; + uint32_t i; + + if (UINT32_MAX - FF_ENCRYPTION_INFO_EXTRA < info->key_id_size || + UINT32_MAX - FF_ENCRYPTION_INFO_EXTRA - info->key_id_size < info->iv_size || + (UINT32_MAX - FF_ENCRYPTION_INFO_EXTRA - info->key_id_size - info->iv_size) / 8 < info->subsample_count) { + return NULL; + } + + *size = FF_ENCRYPTION_INFO_EXTRA + info->key_id_size + info->iv_size + + (info->subsample_count * 8); + cur_buffer = buffer = av_malloc(*size); + if (!buffer) + return NULL; + + AV_WB32(cur_buffer, info->scheme); + AV_WB32(cur_buffer + 4, info->crypt_byte_block); + AV_WB32(cur_buffer + 8, info->skip_byte_block); + AV_WB32(cur_buffer + 12, info->key_id_size); + AV_WB32(cur_buffer + 16, info->iv_size); + AV_WB32(cur_buffer + 20, info->subsample_count); + cur_buffer += 24; + memcpy(cur_buffer, info->key_id, info->key_id_size); + cur_buffer += info->key_id_size; + memcpy(cur_buffer, info->iv, info->iv_size); + cur_buffer += info->iv_size; + for (i = 0; i < info->subsample_count; i++) { + AV_WB32(cur_buffer, info->subsamples[i].bytes_of_clear_data); + AV_WB32(cur_buffer + 4, info->subsamples[i].bytes_of_protected_data); + cur_buffer += 8; + } + + return buffer; +} + +// The format of the AVEncryptionInitInfo side data: +// u32be system_id_size +// u32be num_key_ids +// u32be key_id_size +// u32be data_size +// u8[system_id_size] system_id +// u8[key_id_size][num_key_id] key_ids +// u8[data_size] data + +#define FF_ENCRYPTION_INIT_INFO_EXTRA 16 + +AVEncryptionInitInfo *av_encryption_init_info_alloc( + uint32_t system_id_size, uint32_t num_key_ids, uint32_t key_id_size, uint32_t data_size) +{ + AVEncryptionInitInfo *info; + uint32_t i; + + info = av_mallocz(sizeof(*info)); + if (!info) + return NULL; + + info->system_id = av_mallocz(system_id_size); + info->system_id_size = system_id_size; + info->key_ids = key_id_size ? av_mallocz_array(num_key_ids, sizeof(*info->key_ids)) : NULL; + info->num_key_ids = num_key_ids; + info->key_id_size = key_id_size; + info->data = av_mallocz(data_size); + info->data_size = data_size; + + // Allow pointers to be NULL if the size is 0. + if ((!info->system_id && system_id_size) || (!info->data && data_size) || + (!info->key_ids && num_key_ids && key_id_size)) { + av_encryption_init_info_free(info); + return NULL; + } + + if (key_id_size) { + for (i = 0; i < num_key_ids; i++) { + info->key_ids[i] = av_mallocz(key_id_size); + if (!info->key_ids[i]) { + av_encryption_init_info_free(info); + return NULL; + } + } + } + + return info; +} + +void av_encryption_init_info_free(AVEncryptionInitInfo *info) +{ + uint32_t i; + if (info) { + for (i = 0; i < info->num_key_ids; i++) { + av_free(info->key_ids[i]); + } + av_free(info->system_id); + av_free(info->key_ids); + av_free(info->data); + av_free(info); + } +} + +AVEncryptionInitInfo *av_encryption_init_info_get_side_data( + const uint8_t *side_data, size_t side_data_size) +{ + AVEncryptionInitInfo *info; + uint64_t system_id_size, num_key_ids, key_id_size, data_size, i; + + if (!side_data || side_data_size < FF_ENCRYPTION_INIT_INFO_EXTRA) + return NULL; + + system_id_size = AV_RB32(side_data); + num_key_ids = AV_RB32(side_data + 4); + key_id_size = AV_RB32(side_data + 8); + data_size = AV_RB32(side_data + 12); + + // UINT32_MAX + UINT32_MAX + UINT32_MAX * UINT32_MAX == UINT64_MAX + if (side_data_size - FF_ENCRYPTION_INIT_INFO_EXTRA < system_id_size + data_size + num_key_ids * key_id_size) + return NULL; + + info = av_encryption_init_info_alloc(system_id_size, num_key_ids, key_id_size, data_size); + if (!info) + return NULL; + + memcpy(info->system_id, side_data + 16, system_id_size); + side_data += system_id_size + 16; + for (i = 0; i < num_key_ids; i++) { + memcpy(info->key_ids[i], side_data, key_id_size); + side_data += key_id_size; + } + memcpy(info->data, side_data, data_size); + + return info; +} + +uint8_t *av_encryption_init_info_add_side_data(const AVEncryptionInitInfo *info, size_t *side_data_size) +{ + uint8_t *buffer, *cur_buffer; + uint32_t i, max_size; + + if (UINT32_MAX - FF_ENCRYPTION_INIT_INFO_EXTRA < info->system_id_size || + UINT32_MAX - FF_ENCRYPTION_INIT_INFO_EXTRA - info->system_id_size < info->data_size) { + return NULL; + } + + if (info->num_key_ids) { + max_size = UINT32_MAX - FF_ENCRYPTION_INIT_INFO_EXTRA - info->system_id_size - info->data_size; + if (max_size / info->num_key_ids < info->key_id_size) + return NULL; + } + + *side_data_size = FF_ENCRYPTION_INIT_INFO_EXTRA + info->system_id_size + + info->data_size + (info->num_key_ids * info->key_id_size); + cur_buffer = buffer = av_malloc(*side_data_size); + if (!buffer) + return NULL; + + AV_WB32(cur_buffer, info->system_id_size); + AV_WB32(cur_buffer + 4, info->num_key_ids); + AV_WB32(cur_buffer + 8, info->key_id_size); + AV_WB32(cur_buffer + 12, info->data_size); + cur_buffer += 16; + + memcpy(cur_buffer, info->system_id, info->system_id_size); + cur_buffer += info->system_id_size; + for (i = 0; i < info->num_key_ids; i++) { + memcpy(cur_buffer, info->key_ids[i], info->key_id_size); + cur_buffer += info->key_id_size; + } + memcpy(cur_buffer, info->data, info->data_size); + + return buffer; +} diff --git a/libavutil/encryption_info.h b/libavutil/encryption_info.h new file mode 100644 index 0000000000000..47dc3a35cacce --- /dev/null +++ b/libavutil/encryption_info.h @@ -0,0 +1,200 @@ +/** + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_ENCRYPTION_INFO_H +#define AVUTIL_ENCRYPTION_INFO_H + +#include +#include + +typedef struct AVSubsampleEncryptionInfo { + /** The number of bytes that are clear. */ + unsigned int bytes_of_clear_data; + + /** + * The number of bytes that are protected. If using pattern encryption, + * the pattern applies to only the protected bytes; if not using pattern + * encryption, all these bytes are encrypted. + */ + unsigned int bytes_of_protected_data; +} AVSubsampleEncryptionInfo; + +/** + * This describes encryption info for a packet. This contains frame-specific + * info for how to decrypt the packet before passing it to the decoder. + * + * The size of this struct is not part of the public ABI. + */ +typedef struct AVEncryptionInfo { + /** The fourcc encryption scheme. */ + uint32_t scheme; + + /** + * Only used for pattern encryption. This is the number of 16-byte blocks + * that are encrypted. + */ + uint32_t crypt_byte_block; + + /** + * Only used for pattern encryption. This is the number of 16-byte blocks + * that are clear. + */ + uint32_t skip_byte_block; + + /** + * The ID of the key used to encrypt the packet. This should always be + * 16 bytes long, but may be changed in the future. + */ + uint8_t *key_id; + uint32_t key_id_size; + + /** + * The initialization vector. This may have been zero-filled to be the + * correct block size. This should always be 16 bytes long, but may be + * changed in the future. + */ + uint8_t *iv; + uint32_t iv_size; + + /** + * An array of subsample encryption info specifying how parts of the sample + * are encrypted. If there are no subsamples, then the whole sample is + * encrypted. + */ + AVSubsampleEncryptionInfo *subsamples; + uint32_t subsample_count; +} AVEncryptionInfo; + +/** + * This describes info used to initialize an encryption key system. + * + * The size of this struct is not part of the public ABI. + */ +typedef struct AVEncryptionInitInfo { + /** + * A unique identifier for the key system this is for, can be NULL if it + * is not known. This should always be 16 bytes, but may change in the + * future. + */ + uint8_t* system_id; + uint32_t system_id_size; + + /** + * An array of key IDs this initialization data is for. All IDs are the + * same length. Can be NULL if there are no known key IDs. + */ + uint8_t** key_ids; + /** The number of key IDs. */ + uint32_t num_key_ids; + /** + * The number of bytes in each key ID. This should always be 16, but may + * change in the future. + */ + uint32_t key_id_size; + + /** + * Key-system specific initialization data. This data is copied directly + * from the file and the format depends on the specific key system. This + * can be NULL if there is no initialization data; in that case, there + * will be at least one key ID. + */ + uint8_t* data; + uint32_t data_size; +} AVEncryptionInitInfo; + +/** + * Allocates an AVEncryptionInfo structure and sub-pointers to hold the given + * number of subsamples. This will allocate pointers for the key ID, IV, + * and subsample entries, set the size members, and zero-initialize the rest. + * + * @param subsample_count The number of subsamples. + * @param key_id_size The number of bytes in the key ID, should be 16. + * @param key_id_size The number of bytes in the IV, should be 16. + * + * @return The new AVEncryptionInfo structure, or NULL on error. + */ +AVEncryptionInfo *av_encryption_info_alloc(uint32_t subsample_count, uint32_t key_id_size, uint32_t iv_size); + +/** + * Allocates an AVEncryptionInfo structure with a copy of the given data. + * @return The new AVEncryptionInfo structure, or NULL on error. + */ +AVEncryptionInfo *av_encryption_info_clone(const AVEncryptionInfo *info); + +/** + * Frees the given encryption info object. This MUST NOT be used to free the + * side-data data pointer, that should use normal side-data methods. + */ +void av_encryption_info_free(AVEncryptionInfo *info); + +/** + * Creates a copy of the AVEncryptionInfo that is contained in the given side + * data. The resulting object should be passed to av_encryption_info_free() + * when done. + * + * @return The new AVEncryptionInfo structure, or NULL on error. + */ +AVEncryptionInfo *av_encryption_info_get_side_data(const uint8_t *side_data, size_t side_data_size); + +/** + * Allocates and initializes side data that holds a copy of the given encryption + * info. The resulting pointer should be either freed using av_free or given + * to av_packet_add_side_data(). + * + * @return The new side-data pointer, or NULL. + */ +uint8_t *av_encryption_info_add_side_data( + const AVEncryptionInfo *info, size_t *side_data_size); + + +/** + * Allocates an AVEncryptionInitInfo structure and sub-pointers to hold the + * given sizes. This will allocate pointers and set all the fields. + * + * @return The new AVEncryptionInitInfo structure, or NULL on error. + */ +AVEncryptionInitInfo *av_encryption_init_info_alloc( + uint32_t system_id_size, uint32_t num_key_ids, uint32_t key_id_size, uint32_t data_size); + +/** + * Frees the given encryption init info object. This MUST NOT be used to free + * the side-data data pointer, that should use normal side-data methods. + */ +void av_encryption_init_info_free(AVEncryptionInitInfo* info); + +/** + * Creates a copy of the AVEncryptionInitInfo that is contained in the given + * side data. The resulting object should be passed to + * av_encryption_init_info_free() when done. + * + * @return The new AVEncryptionInitInfo structure, or NULL on error. + */ +AVEncryptionInitInfo *av_encryption_init_info_get_side_data( + const uint8_t* side_data, size_t side_data_size); + +/** + * Allocates and initializes side data that holds a copy of the given encryption + * init info. The resulting pointer should be either freed using av_free or + * given to av_packet_add_side_data(). + * + * @return The new side-data pointer, or NULL. + */ +uint8_t *av_encryption_init_info_add_side_data( + const AVEncryptionInitInfo *info, size_t *side_data_size); + +#endif /* AVUTIL_ENCRYPTION_INFO_H */ diff --git a/libavutil/error.h b/libavutil/error.h index 71df4da353b9c..6b44d2cd22f3b 100644 --- a/libavutil/error.h +++ b/libavutil/error.h @@ -82,6 +82,10 @@ #define AV_ERROR_MAX_STRING_SIZE 64 +#define AVERROR_TCP_CONNECT_TIMEOUT -1001 +#define AVERROR_TCP_READ_TIMEOUT -1002 +#define AVERROR_TCP_WRITE_TIMEOUT -1003 + /** * Put a description of the AVERROR code errnum in errbuf. * In case of failure the global variable errno is set to indicate the diff --git a/libavutil/eval.c b/libavutil/eval.c index b5f4ea2409e76..5da9a6d83b91d 100644 --- a/libavutil/eval.c +++ b/libavutil/eval.c @@ -57,7 +57,14 @@ typedef struct Parser { double *var; } Parser; -static const AVClass eval_class = { "Eval", av_default_item_name, NULL, LIBAVUTIL_VERSION_INT, offsetof(Parser,log_offset), offsetof(Parser,log_ctx) }; +static const AVClass eval_class = { + .class_name = "Eval", + .item_name = av_default_item_name, + .option = NULL, + .version = LIBAVUTIL_VERSION_INT, + .log_level_offset_offset = offsetof(Parser, log_offset), + .parent_log_context_offset = offsetof(Parser, log_ctx), +}; static const struct { double bin_val; diff --git a/libavutil/file.c b/libavutil/file.c index 7bdf6cde840fb..24a86c3f353f4 100644 --- a/libavutil/file.c +++ b/libavutil/file.c @@ -42,8 +42,12 @@ typedef struct FileLogContext { } FileLogContext; static const AVClass file_log_ctx_class = { - "FILE", av_default_item_name, NULL, LIBAVUTIL_VERSION_INT, - offsetof(FileLogContext, log_offset), offsetof(FileLogContext, log_ctx) + .class_name = "FILE", + .item_name = av_default_item_name, + .option = NULL, + .version = LIBAVUTIL_VERSION_INT, + .log_level_offset_offset = offsetof(FileLogContext, log_offset), + .parent_log_context_offset = offsetof(FileLogContext, log_ctx), }; int av_file_map(const char *filename, uint8_t **bufptr, size_t *size, diff --git a/libavutil/file_open.c b/libavutil/file_open.c index 34070d933ba4b..a8da283583b61 100644 --- a/libavutil/file_open.c +++ b/libavutil/file_open.c @@ -29,7 +29,7 @@ #include #endif -#if defined(_WIN32) && !defined(__MINGW32CE__) +#ifdef _WIN32 #undef open #undef lseek #undef stat @@ -99,8 +99,12 @@ typedef struct FileLogContext { } FileLogContext; static const AVClass file_log_ctx_class = { - "TEMPFILE", av_default_item_name, NULL, LIBAVUTIL_VERSION_INT, - offsetof(FileLogContext, log_offset), offsetof(FileLogContext, log_ctx) + .class_name = "TEMPFILE", + .item_name = av_default_item_name, + .option = NULL, + .version = LIBAVUTIL_VERSION_INT, + .log_level_offset_offset = offsetof(FileLogContext, log_offset), + .parent_log_context_offset = offsetof(FileLogContext, log_ctx), }; int avpriv_tempfile(const char *prefix, char **filename, int log_offset, void *log_ctx) diff --git a/libavutil/frame.c b/libavutil/frame.c index d5fd2932e34a5..00215ac29a4fd 100644 --- a/libavutil/frame.c +++ b/libavutil/frame.c @@ -26,11 +26,7 @@ #include "mem.h" #include "samplefmt.h" - -static AVFrameSideData *frame_new_side_data(AVFrame *frame, - enum AVFrameSideDataType type, - AVBufferRef *buf); - +#if FF_API_FRAME_GET_SET MAKE_ACCESSORS(AVFrame, frame, int64_t, best_effort_timestamp) MAKE_ACCESSORS(AVFrame, frame, int64_t, pkt_duration) MAKE_ACCESSORS(AVFrame, frame, int64_t, pkt_pos) @@ -42,41 +38,84 @@ MAKE_ACCESSORS(AVFrame, frame, int, decode_error_flags) MAKE_ACCESSORS(AVFrame, frame, int, pkt_size) MAKE_ACCESSORS(AVFrame, frame, enum AVColorSpace, colorspace) MAKE_ACCESSORS(AVFrame, frame, enum AVColorRange, color_range) +#endif #define CHECK_CHANNELS_CONSISTENCY(frame) \ av_assert2(!(frame)->channel_layout || \ (frame)->channels == \ av_get_channel_layout_nb_channels((frame)->channel_layout)) -AVDictionary **avpriv_frame_get_metadatap(AVFrame *frame) {return &frame->metadata;}; - #if FF_API_FRAME_QP +struct qp_properties { + int stride; + int type; +}; + int av_frame_set_qp_table(AVFrame *f, AVBufferRef *buf, int stride, int qp_type) { + struct qp_properties *p; + AVFrameSideData *sd; + AVBufferRef *ref; + +FF_DISABLE_DEPRECATION_WARNINGS av_buffer_unref(&f->qp_table_buf); f->qp_table_buf = buf; - -FF_DISABLE_DEPRECATION_WARNINGS f->qscale_table = buf->data; f->qstride = stride; f->qscale_type = qp_type; FF_ENABLE_DEPRECATION_WARNINGS + av_frame_remove_side_data(f, AV_FRAME_DATA_QP_TABLE_PROPERTIES); + av_frame_remove_side_data(f, AV_FRAME_DATA_QP_TABLE_DATA); + + ref = av_buffer_ref(buf); + if (!av_frame_new_side_data_from_buf(f, AV_FRAME_DATA_QP_TABLE_DATA, ref)) { + av_buffer_unref(&ref); + return AVERROR(ENOMEM); + } + + sd = av_frame_new_side_data(f, AV_FRAME_DATA_QP_TABLE_PROPERTIES, + sizeof(struct qp_properties)); + if (!sd) + return AVERROR(ENOMEM); + + p = (struct qp_properties *)sd->data; + p->stride = stride; + p->type = qp_type; + return 0; } int8_t *av_frame_get_qp_table(AVFrame *f, int *stride, int *type) { + AVBufferRef *buf = NULL; + + *stride = 0; + *type = 0; + FF_DISABLE_DEPRECATION_WARNINGS - *stride = f->qstride; - *type = f->qscale_type; + if (f->qp_table_buf) { + *stride = f->qstride; + *type = f->qscale_type; + buf = f->qp_table_buf; FF_ENABLE_DEPRECATION_WARNINGS + } else { + AVFrameSideData *sd; + struct qp_properties *p; + sd = av_frame_get_side_data(f, AV_FRAME_DATA_QP_TABLE_PROPERTIES); + if (!sd) + return NULL; + p = (struct qp_properties *)sd->data; + sd = av_frame_get_side_data(f, AV_FRAME_DATA_QP_TABLE_DATA); + if (!sd) + return NULL; + *stride = p->stride; + *type = p->type; + buf = sd->buf; + } - if (!f->qp_table_buf) - return NULL; - - return f->qp_table_buf->data; + return buf ? buf->data : NULL; } #endif @@ -208,7 +247,7 @@ static int get_video_buffer(AVFrame *frame, int align) frame->data[i] = frame->buf[i]->data; } - if (desc->flags & AV_PIX_FMT_FLAG_PAL || desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) { + if (desc->flags & AV_PIX_FMT_FLAG_PAL || desc->flags & FF_PSEUDOPAL) { av_buffer_unref(&frame->buf[1]); frame->buf[1] = av_buffer_alloc(AVPALETTE_SIZE); if (!frame->buf[1]) @@ -356,8 +395,10 @@ FF_ENABLE_DEPRECATION_WARNINGS } memcpy(sd_dst->data, sd_src->data, sd_src->size); } else { - sd_dst = frame_new_side_data(dst, sd_src->type, av_buffer_ref(sd_src->buf)); + AVBufferRef *ref = av_buffer_ref(sd_src->buf); + sd_dst = av_frame_new_side_data_from_buf(dst, sd_src->type, ref); if (!sd_dst) { + av_buffer_unref(&ref); wipe_side_data(dst); return AVERROR(ENOMEM); } @@ -383,12 +424,17 @@ FF_ENABLE_DEPRECATION_WARNINGS #endif av_buffer_unref(&dst->opaque_ref); + av_buffer_unref(&dst->private_ref); if (src->opaque_ref) { dst->opaque_ref = av_buffer_ref(src->opaque_ref); if (!dst->opaque_ref) return AVERROR(ENOMEM); } - + if (src->private_ref) { + dst->private_ref = av_buffer_ref(src->private_ref); + if (!dst->private_ref) + return AVERROR(ENOMEM); + } return 0; } @@ -518,12 +564,15 @@ void av_frame_unref(AVFrame *frame) av_freep(&frame->extended_buf); av_dict_free(&frame->metadata); #if FF_API_FRAME_QP +FF_DISABLE_DEPRECATION_WARNINGS av_buffer_unref(&frame->qp_table_buf); +FF_ENABLE_DEPRECATION_WARNINGS #endif av_buffer_unref(&frame->hw_frames_ctx); av_buffer_unref(&frame->opaque_ref); + av_buffer_unref(&frame->private_ref); get_frame_defaults(frame); } @@ -636,9 +685,9 @@ AVBufferRef *av_frame_get_plane_buffer(AVFrame *frame, int plane) return NULL; } -static AVFrameSideData *frame_new_side_data(AVFrame *frame, - enum AVFrameSideDataType type, - AVBufferRef *buf) +AVFrameSideData *av_frame_new_side_data_from_buf(AVFrame *frame, + enum AVFrameSideDataType type, + AVBufferRef *buf) { AVFrameSideData *ret, **tmp; @@ -646,17 +695,17 @@ static AVFrameSideData *frame_new_side_data(AVFrame *frame, return NULL; if (frame->nb_side_data > INT_MAX / sizeof(*frame->side_data) - 1) - goto fail; + return NULL; tmp = av_realloc(frame->side_data, (frame->nb_side_data + 1) * sizeof(*frame->side_data)); if (!tmp) - goto fail; + return NULL; frame->side_data = tmp; ret = av_mallocz(sizeof(*ret)); if (!ret) - goto fail; + return NULL; ret->buf = buf; ret->data = ret->buf->data; @@ -666,17 +715,18 @@ static AVFrameSideData *frame_new_side_data(AVFrame *frame, 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 *ret; + AVBufferRef *buf = av_buffer_alloc(size); + ret = av_frame_new_side_data_from_buf(frame, type, buf); + if (!ret) + av_buffer_unref(&buf); + return ret; } AVFrameSideData *av_frame_get_side_data(const AVFrame *frame, @@ -782,6 +832,8 @@ const char *av_frame_side_data_name(enum AVFrameSideDataType type) 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"; + case AV_FRAME_DATA_QP_TABLE_PROPERTIES: return "QP table properties"; + case AV_FRAME_DATA_QP_TABLE_DATA: return "QP table data"; } return NULL; } @@ -796,7 +848,7 @@ static int calc_cropping_offsets(size_t offsets[4], const AVFrame *frame, 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) { + if (desc->flags & (AV_PIX_FMT_FLAG_PAL | FF_PSEUDOPAL) && i == 1) { offsets[i] = 0; break; } diff --git a/libavutil/frame.h b/libavutil/frame.h index abe4f4fd178d5..9d57d6ce66ff9 100644 --- a/libavutil/frame.h +++ b/libavutil/frame.h @@ -141,6 +141,23 @@ enum AVFrameSideDataType { * metadata key entry "name". */ AV_FRAME_DATA_ICC_PROFILE, + +#if FF_API_FRAME_QP + /** + * Implementation-specific description of the format of AV_FRAME_QP_TABLE_DATA. + * The contents of this side data are undocumented and internal; use + * av_frame_set_qp_table() and av_frame_get_qp_table() to access this in a + * meaningful way instead. + */ + AV_FRAME_DATA_QP_TABLE_PROPERTIES, + + /** + * Raw QP table data. Its format is described by + * AV_FRAME_DATA_QP_TABLE_PROPERTIES. Use av_frame_set_qp_table() and + * av_frame_get_qp_table() to access this instead. + */ + AV_FRAME_DATA_QP_TABLE_DATA, +#endif }; enum AVActiveFormatDescription { @@ -529,6 +546,7 @@ typedef struct AVFrame { attribute_deprecated int qscale_type; + attribute_deprecated AVBufferRef *qp_table_buf; #endif /** @@ -563,39 +581,77 @@ typedef struct AVFrame { /** * @} */ + + /** + * AVBufferRef for internal use by a single libav* library. + * Must not be used to transfer data between libraries. + * Has to be NULL when ownership of the frame leaves the respective library. + * + * Code outside the FFmpeg libs should never check or change the contents of the buffer ref. + * + * FFmpeg calls av_buffer_unref() on it when the frame is unreferenced. + * av_frame_copy_props() calls create a new reference with av_buffer_ref() + * for the target frame's private_ref field. + */ + AVBufferRef *private_ref; } AVFrame; +#if FF_API_FRAME_GET_SET /** * Accessors for some AVFrame fields. These used to be provided for ABI * compatibility, and do not need to be used anymore. */ +attribute_deprecated int64_t av_frame_get_best_effort_timestamp(const AVFrame *frame); +attribute_deprecated void av_frame_set_best_effort_timestamp(AVFrame *frame, int64_t val); +attribute_deprecated int64_t av_frame_get_pkt_duration (const AVFrame *frame); +attribute_deprecated void av_frame_set_pkt_duration (AVFrame *frame, int64_t val); +attribute_deprecated int64_t av_frame_get_pkt_pos (const AVFrame *frame); +attribute_deprecated void av_frame_set_pkt_pos (AVFrame *frame, int64_t val); +attribute_deprecated int64_t av_frame_get_channel_layout (const AVFrame *frame); +attribute_deprecated void av_frame_set_channel_layout (AVFrame *frame, int64_t val); +attribute_deprecated int av_frame_get_channels (const AVFrame *frame); +attribute_deprecated void av_frame_set_channels (AVFrame *frame, int val); +attribute_deprecated int av_frame_get_sample_rate (const AVFrame *frame); +attribute_deprecated void av_frame_set_sample_rate (AVFrame *frame, int val); +attribute_deprecated AVDictionary *av_frame_get_metadata (const AVFrame *frame); +attribute_deprecated void av_frame_set_metadata (AVFrame *frame, AVDictionary *val); +attribute_deprecated int av_frame_get_decode_error_flags (const AVFrame *frame); +attribute_deprecated void av_frame_set_decode_error_flags (AVFrame *frame, int val); +attribute_deprecated int av_frame_get_pkt_size(const AVFrame *frame); +attribute_deprecated void av_frame_set_pkt_size(AVFrame *frame, int val); -AVDictionary **avpriv_frame_get_metadatap(AVFrame *frame); #if FF_API_FRAME_QP +attribute_deprecated int8_t *av_frame_get_qp_table(AVFrame *f, int *stride, int *type); +attribute_deprecated int av_frame_set_qp_table(AVFrame *f, AVBufferRef *buf, int stride, int type); #endif +attribute_deprecated enum AVColorSpace av_frame_get_colorspace(const AVFrame *frame); +attribute_deprecated void av_frame_set_colorspace(AVFrame *frame, enum AVColorSpace val); +attribute_deprecated enum AVColorRange av_frame_get_color_range(const AVFrame *frame); +attribute_deprecated void av_frame_set_color_range(AVFrame *frame, enum AVColorRange val); +#endif /** * Get the name of a colorspace. @@ -762,6 +818,22 @@ AVFrameSideData *av_frame_new_side_data(AVFrame *frame, enum AVFrameSideDataType type, int size); +/** + * Add a new side data to a frame from an existing AVBufferRef + * + * @param frame a frame to which the side data should be added + * @param type the type of the added side data + * @param buf an AVBufferRef to add as side data. The ownership of + * the reference is transferred to the frame. + * + * @return newly added side data on success, NULL on error. On failure + * the frame is unchanged and the AVBufferRef remains owned by + * the caller. + */ +AVFrameSideData *av_frame_new_side_data_from_buf(AVFrame *frame, + enum AVFrameSideDataType type, + AVBufferRef *buf); + /** * @return a pointer to the side data of a given type on success, NULL if there * is no side data with such type in this frame. diff --git a/libavutil/hash.c b/libavutil/hash.c index 7037b0d6ff7e3..75edb6db78865 100644 --- a/libavutil/hash.c +++ b/libavutil/hash.c @@ -155,7 +155,11 @@ void av_hash_init(AVHashContext *ctx) } } +#if FF_API_CRYPTO_SIZE_T void av_hash_update(AVHashContext *ctx, const uint8_t *src, int len) +#else +void av_hash_update(AVHashContext *ctx, const uint8_t *src, size_t len) +#endif { switch (ctx->type) { case MD5: av_md5_update(ctx->ctx, src, len); break; diff --git a/libavutil/hash.h b/libavutil/hash.h index a20b8934f196f..7693e6bf0dbca 100644 --- a/libavutil/hash.h +++ b/libavutil/hash.h @@ -29,6 +29,8 @@ #include +#include "version.h" + /** * @defgroup lavu_hash Hash Functions * @ingroup lavu_crypto @@ -179,7 +181,11 @@ void av_hash_init(struct AVHashContext *ctx); * @param[in] src Data to be added to the hash context * @param[in] len Size of the additional data */ +#if FF_API_CRYPTO_SIZE_T void av_hash_update(struct AVHashContext *ctx, const uint8_t *src, int len); +#else +void av_hash_update(struct AVHashContext *ctx, const uint8_t *src, size_t len); +#endif /** * Finalize a hash context and compute the actual hash value. diff --git a/libavutil/hmac.h b/libavutil/hmac.h index 576a0a4fb9629..412e950719ba5 100644 --- a/libavutil/hmac.h +++ b/libavutil/hmac.h @@ -35,7 +35,7 @@ enum AVHMACType { AV_HMAC_SHA1, AV_HMAC_SHA224, AV_HMAC_SHA256, - AV_HMAC_SHA384 = 12, + AV_HMAC_SHA384, AV_HMAC_SHA512, }; diff --git a/libavutil/hwcontext.c b/libavutil/hwcontext.c index 048e82126fbaa..70c556ecacbb0 100644 --- a/libavutil/hwcontext.c +++ b/libavutil/hwcontext.c @@ -41,6 +41,9 @@ static const HWContextType * const hw_table[] = { #if CONFIG_DXVA2 &ff_hwcontext_type_dxva2, #endif +#if CONFIG_OPENCL + &ff_hwcontext_type_opencl, +#endif #if CONFIG_QSV &ff_hwcontext_type_qsv, #endif @@ -52,6 +55,9 @@ static const HWContextType * const hw_table[] = { #endif #if CONFIG_VIDEOTOOLBOX &ff_hwcontext_type_videotoolbox, +#endif +#if CONFIG_MEDIACODEC + &ff_hwcontext_type_mediacodec, #endif NULL, }; @@ -61,10 +67,12 @@ static const char *const hw_type_names[] = { [AV_HWDEVICE_TYPE_DRM] = "drm", [AV_HWDEVICE_TYPE_DXVA2] = "dxva2", [AV_HWDEVICE_TYPE_D3D11VA] = "d3d11va", + [AV_HWDEVICE_TYPE_OPENCL] = "opencl", [AV_HWDEVICE_TYPE_QSV] = "qsv", [AV_HWDEVICE_TYPE_VAAPI] = "vaapi", [AV_HWDEVICE_TYPE_VDPAU] = "vdpau", [AV_HWDEVICE_TYPE_VIDEOTOOLBOX] = "videotoolbox", + [AV_HWDEVICE_TYPE_MEDIACODEC] = "mediacodec", }; enum AVHWDeviceType av_hwdevice_find_type_by_name(const char *name) @@ -79,7 +87,8 @@ enum AVHWDeviceType av_hwdevice_find_type_by_name(const char *name) const char *av_hwdevice_get_type_name(enum AVHWDeviceType type) { - if (type >= 0 && type < FF_ARRAY_ELEMS(hw_type_names)) + if (type > AV_HWDEVICE_TYPE_NONE && + type < FF_ARRAY_ELEMS(hw_type_names)) return hw_type_names[type]; else return NULL; @@ -212,19 +221,16 @@ static void hwframe_ctx_free(void *opaque, uint8_t *data) { AVHWFramesContext *ctx = (AVHWFramesContext*)data; - if (ctx->internal->source_frames) { - av_buffer_unref(&ctx->internal->source_frames); + if (ctx->internal->pool_internal) + av_buffer_pool_uninit(&ctx->internal->pool_internal); - } else { - if (ctx->internal->pool_internal) - av_buffer_pool_uninit(&ctx->internal->pool_internal); + if (ctx->internal->hw_type->frames_uninit) + ctx->internal->hw_type->frames_uninit(ctx); - if (ctx->internal->hw_type->frames_uninit) - ctx->internal->hw_type->frames_uninit(ctx); + if (ctx->free) + ctx->free(ctx); - if (ctx->free) - ctx->free(ctx); - } + av_buffer_unref(&ctx->internal->source_frames); av_buffer_unref(&ctx->device_ref); @@ -477,8 +483,10 @@ int av_hwframe_get_buffer(AVBufferRef *hwframe_ref, AVFrame *frame, int flags) ret = av_hwframe_get_buffer(ctx->internal->source_frames, src_frame, 0); - if (ret < 0) + if (ret < 0) { + av_frame_free(&src_frame); return ret; + } ret = av_hwframe_map(frame, src_frame, ctx->internal->source_allocation_map_flags); diff --git a/libavutil/hwcontext.h b/libavutil/hwcontext.h index 03334e20e06ca..f5a4b62387747 100644 --- a/libavutil/hwcontext.h +++ b/libavutil/hwcontext.h @@ -25,15 +25,17 @@ #include "pixfmt.h" enum AVHWDeviceType { + AV_HWDEVICE_TYPE_NONE, AV_HWDEVICE_TYPE_VDPAU, AV_HWDEVICE_TYPE_CUDA, AV_HWDEVICE_TYPE_VAAPI, AV_HWDEVICE_TYPE_DXVA2, AV_HWDEVICE_TYPE_QSV, AV_HWDEVICE_TYPE_VIDEOTOOLBOX, - AV_HWDEVICE_TYPE_NONE, AV_HWDEVICE_TYPE_D3D11VA, AV_HWDEVICE_TYPE_DRM, + AV_HWDEVICE_TYPE_OPENCL, + AV_HWDEVICE_TYPE_MEDIACODEC, }; typedef struct AVHWDeviceInternal AVHWDeviceInternal; diff --git a/libavutil/hwcontext_cuda.c b/libavutil/hwcontext_cuda.c index dfb67bc941e27..37827a770c3a6 100644 --- a/libavutil/hwcontext_cuda.c +++ b/libavutil/hwcontext_cuda.c @@ -336,7 +336,7 @@ static int cuda_device_init(AVHWDeviceContext *ctx) } if (!hwctx->internal->cuda_dl) { - ret = cuda_load_functions(&hwctx->internal->cuda_dl); + ret = cuda_load_functions(&hwctx->internal->cuda_dl, ctx); if (ret < 0) { av_log(ctx, AV_LOG_ERROR, "Could not dynamically load CUDA\n"); goto error; diff --git a/libavutil/hwcontext_d3d11va.c b/libavutil/hwcontext_d3d11va.c index 52683b92cd742..b68d26280442c 100644 --- a/libavutil/hwcontext_d3d11va.c +++ b/libavutil/hwcontext_d3d11va.c @@ -20,14 +20,6 @@ #include -// Include thread.h before redefining _WIN32_WINNT, to get -// the right implementation for AVOnce -#include "thread.h" - -#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600 -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 -#endif #define COBJMACROS #include @@ -46,6 +38,7 @@ #include "imgutils.h" #include "pixdesc.h" #include "pixfmt.h" +#include "thread.h" typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory); @@ -120,9 +113,42 @@ static void d3d11va_frames_uninit(AVHWFramesContext *ctx) s->staging_texture = NULL; } +static int d3d11va_frames_get_constraints(AVHWDeviceContext *ctx, + const void *hwconfig, + AVHWFramesConstraints *constraints) +{ + AVD3D11VADeviceContext *device_hwctx = ctx->hwctx; + int nb_sw_formats = 0; + HRESULT hr; + int i; + + constraints->valid_sw_formats = av_malloc_array(FF_ARRAY_ELEMS(supported_formats) + 1, + sizeof(*constraints->valid_sw_formats)); + if (!constraints->valid_sw_formats) + return AVERROR(ENOMEM); + + for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) { + UINT format_support = 0; + hr = ID3D11Device_CheckFormatSupport(device_hwctx->device, supported_formats[i].d3d_format, &format_support); + if (SUCCEEDED(hr) && (format_support & D3D11_FORMAT_SUPPORT_TEXTURE2D)) + constraints->valid_sw_formats[nb_sw_formats++] = supported_formats[i].pix_fmt; + } + constraints->valid_sw_formats[nb_sw_formats] = AV_PIX_FMT_NONE; + + constraints->valid_hw_formats = av_malloc_array(2, sizeof(*constraints->valid_hw_formats)); + if (!constraints->valid_hw_formats) + return AVERROR(ENOMEM); + + constraints->valid_hw_formats[0] = AV_PIX_FMT_D3D11; + constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE; + + return 0; +} + static void free_texture(void *opaque, uint8_t *data) { ID3D11Texture2D_Release((ID3D11Texture2D *)opaque); + av_free(data); } static AVBufferRef *wrap_texture_buf(ID3D11Texture2D *tex, int index) @@ -457,20 +483,31 @@ static void d3d11va_device_uninit(AVHWDeviceContext *hwdev) { AVD3D11VADeviceContext *device_hwctx = hwdev->hwctx; - if (device_hwctx->device) + if (device_hwctx->device) { ID3D11Device_Release(device_hwctx->device); + device_hwctx->device = NULL; + } - if (device_hwctx->device_context) + if (device_hwctx->device_context) { ID3D11DeviceContext_Release(device_hwctx->device_context); + device_hwctx->device_context = NULL; + } - if (device_hwctx->video_device) + if (device_hwctx->video_device) { ID3D11VideoDevice_Release(device_hwctx->video_device); + device_hwctx->video_device = NULL; + } - if (device_hwctx->video_context) + if (device_hwctx->video_context) { ID3D11VideoContext_Release(device_hwctx->video_context); + device_hwctx->video_context = NULL; + } - if (device_hwctx->lock == d3d11va_default_lock) + if (device_hwctx->lock == d3d11va_default_lock) { CloseHandle(device_hwctx->lock_ctx); + device_hwctx->lock_ctx = INVALID_HANDLE_VALUE; + device_hwctx->lock = NULL; + } } static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device, @@ -512,6 +549,15 @@ static int d3d11va_device_create(AVHWDeviceContext *ctx, const char *device, } } + if (pAdapter) { + DXGI_ADAPTER_DESC2 desc; + hr = IDXGIAdapter2_GetDesc(pAdapter, &desc); + if (!FAILED(hr)) { + av_log(ctx, AV_LOG_INFO, "Using device %04x:%04x (%ls).\n", + desc.VendorId, desc.DeviceId, desc.Description); + } + } + hr = mD3D11CreateDevice(pAdapter, pAdapter ? D3D_DRIVER_TYPE_UNKNOWN : D3D_DRIVER_TYPE_HARDWARE, NULL, creationFlags, NULL, 0, D3D11_SDK_VERSION, &device_hwctx->device, NULL, NULL); if (pAdapter) @@ -557,6 +603,7 @@ const HWContextType ff_hwcontext_type_d3d11va = { .device_create = d3d11va_device_create, .device_init = d3d11va_device_init, .device_uninit = d3d11va_device_uninit, + .frames_get_constraints = d3d11va_frames_get_constraints, .frames_init = d3d11va_frames_init, .frames_uninit = d3d11va_frames_uninit, .frames_get_buffer = d3d11va_get_buffer, diff --git a/libavutil/hwcontext_d3d11va.h b/libavutil/hwcontext_d3d11va.h index 98db7ce34310d..9f91e9b1b67bf 100644 --- a/libavutil/hwcontext_d3d11va.h +++ b/libavutil/hwcontext_d3d11va.h @@ -37,6 +37,7 @@ */ #include +#include /** * This struct is allocated as AVHWDeviceContext.hwctx diff --git a/libavutil/hwcontext_drm.h b/libavutil/hwcontext_drm.h index 2e225451e1158..42709f215ef9a 100644 --- a/libavutil/hwcontext_drm.h +++ b/libavutil/hwcontext_drm.h @@ -58,6 +58,9 @@ typedef struct AVDRMObjectDescriptor { size_t size; /** * Format modifier applied to the object (DRM_FORMAT_MOD_*). + * + * If the format modifier is unknown then this should be set to + * DRM_FORMAT_MOD_INVALID. */ uint64_t format_modifier; } AVDRMObjectDescriptor; diff --git a/libavutil/hwcontext_dxva2.c b/libavutil/hwcontext_dxva2.c index 2ddd4be7b1df8..4585f323bb61d 100644 --- a/libavutil/hwcontext_dxva2.c +++ b/libavutil/hwcontext_dxva2.c @@ -18,10 +18,6 @@ #include -#if !defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600 -#undef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 -#endif #define DXVA2API_USE_BITFIELDS #define COBJMACROS @@ -485,7 +481,12 @@ static int dxva2_device_create9ex(AVHWDeviceContext *ctx, UINT adapter) if (FAILED(hr)) return AVERROR_UNKNOWN; - IDirect3D9Ex_GetAdapterDisplayModeEx(d3d9ex, adapter, &modeex, NULL); + modeex.Size = sizeof(D3DDISPLAYMODEEX); + hr = IDirect3D9Ex_GetAdapterDisplayModeEx(d3d9ex, adapter, &modeex, NULL); + if (FAILED(hr)) { + IDirect3D9Ex_Release(d3d9ex); + return AVERROR_UNKNOWN; + } d3dpp.BackBufferFormat = modeex.Format; diff --git a/libavutil/hwcontext_internal.h b/libavutil/hwcontext_internal.h index 2d75d3db0877e..332062ddaa06d 100644 --- a/libavutil/hwcontext_internal.h +++ b/libavutil/hwcontext_internal.h @@ -161,9 +161,11 @@ extern const HWContextType ff_hwcontext_type_cuda; extern const HWContextType ff_hwcontext_type_d3d11va; extern const HWContextType ff_hwcontext_type_drm; extern const HWContextType ff_hwcontext_type_dxva2; +extern const HWContextType ff_hwcontext_type_opencl; extern const HWContextType ff_hwcontext_type_qsv; extern const HWContextType ff_hwcontext_type_vaapi; extern const HWContextType ff_hwcontext_type_vdpau; extern const HWContextType ff_hwcontext_type_videotoolbox; +extern const HWContextType ff_hwcontext_type_mediacodec; #endif /* AVUTIL_HWCONTEXT_INTERNAL_H */ diff --git a/libavutil/hwcontext_mediacodec.c b/libavutil/hwcontext_mediacodec.c new file mode 100644 index 0000000000000..b0d8993e15888 --- /dev/null +++ b/libavutil/hwcontext_mediacodec.c @@ -0,0 +1,50 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "config.h" + +#include "buffer.h" +#include "common.h" +#include "hwcontext.h" +#include "hwcontext_internal.h" +#include "hwcontext_mediacodec.h" + +static int mc_device_create(AVHWDeviceContext *ctx, const char *device, + AVDictionary *opts, int flags) +{ + if (device && device[0]) { + av_log(ctx, AV_LOG_ERROR, "Device selection unsupported.\n"); + return AVERROR_UNKNOWN; + } + + return 0; +} + +const HWContextType ff_hwcontext_type_mediacodec = { + .type = AV_HWDEVICE_TYPE_MEDIACODEC, + .name = "mediacodec", + + .device_hwctx_size = sizeof(AVMediaCodecDeviceContext), + + .device_create = mc_device_create, + + .pix_fmts = (const enum AVPixelFormat[]){ + AV_PIX_FMT_MEDIACODEC, + AV_PIX_FMT_NONE + }, +}; diff --git a/libavfilter/avfiltergraph.h b/libavutil/hwcontext_mediacodec.h similarity index 63% rename from libavfilter/avfiltergraph.h rename to libavutil/hwcontext_mediacodec.h index b31d581ca0301..101a9806d59e3 100644 --- a/libavfilter/avfiltergraph.h +++ b/libavutil/hwcontext_mediacodec.h @@ -1,7 +1,4 @@ /* - * Filter graphs - * copyright (c) 2007 Bobby Bingham - * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or @@ -19,10 +16,21 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef AVFILTER_AVFILTERGRAPH_H -#define AVFILTER_AVFILTERGRAPH_H +#ifndef AVUTIL_HWCONTEXT_MEDIACODEC_H +#define AVUTIL_HWCONTEXT_MEDIACODEC_H -#include "avfilter.h" -#include "libavutil/log.h" +/** + * MediaCodec details. + * + * Allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVMediaCodecDeviceContext { + /** + * android/view/Surface handle, to be filled by the user. + * + * This is the default surface used by decoders on this device. + */ + void *surface; +} AVMediaCodecDeviceContext; -#endif /* AVFILTER_AVFILTERGRAPH_H */ +#endif /* AVUTIL_HWCONTEXT_MEDIACODEC_H */ diff --git a/libavutil/hwcontext_opencl.c b/libavutil/hwcontext_opencl.c new file mode 100644 index 0000000000000..43b5c5ae0cbd1 --- /dev/null +++ b/libavutil/hwcontext_opencl.c @@ -0,0 +1,2941 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#define CL_USE_DEPRECATED_OPENCL_1_2_APIS + +#include + +#include "config.h" + +#include "avassert.h" +#include "avstring.h" +#include "common.h" +#include "hwcontext.h" +#include "hwcontext_internal.h" +#include "hwcontext_opencl.h" +#include "mem.h" +#include "pixdesc.h" + +#if HAVE_OPENCL_VAAPI_BEIGNET +#include +#include +#include +#include +#include "hwcontext_vaapi.h" +#endif + +#if HAVE_OPENCL_DRM_BEIGNET +#include +#include +#include "hwcontext_drm.h" +#endif + +#if HAVE_OPENCL_VAAPI_INTEL_MEDIA +#include +#include +#include +#include "hwcontext_vaapi.h" +#endif + +#if HAVE_OPENCL_DXVA2 +#define COBJMACROS +#include +#include +#include "hwcontext_dxva2.h" +#endif + +#if HAVE_OPENCL_D3D11 +#include +#include "hwcontext_d3d11va.h" +#endif + +#if HAVE_OPENCL_DRM_ARM +#include +#include +#include "hwcontext_drm.h" +#endif + + +typedef struct OpenCLDeviceContext { + // Default command queue to use for transfer/mapping operations on + // the device. If the user supplies one, this is a reference to it. + // Otherwise, it is newly-created. + cl_command_queue command_queue; + + // The platform the context exists on. This is needed to query and + // retrieve extension functions. + cl_platform_id platform_id; + + // Platform/device-specific functions. +#if HAVE_OPENCL_DRM_BEIGNET + int beignet_drm_mapping_usable; + clCreateImageFromFdINTEL_fn clCreateImageFromFdINTEL; +#endif + +#if HAVE_OPENCL_VAAPI_INTEL_MEDIA + int qsv_mapping_usable; + clCreateFromVA_APIMediaSurfaceINTEL_fn + clCreateFromVA_APIMediaSurfaceINTEL; + clEnqueueAcquireVA_APIMediaSurfacesINTEL_fn + clEnqueueAcquireVA_APIMediaSurfacesINTEL; + clEnqueueReleaseVA_APIMediaSurfacesINTEL_fn + clEnqueueReleaseVA_APIMediaSurfacesINTEL; +#endif + +#if HAVE_OPENCL_DXVA2 + int dxva2_mapping_usable; + cl_dx9_media_adapter_type_khr dx9_media_adapter_type; + + clCreateFromDX9MediaSurfaceKHR_fn + clCreateFromDX9MediaSurfaceKHR; + clEnqueueAcquireDX9MediaSurfacesKHR_fn + clEnqueueAcquireDX9MediaSurfacesKHR; + clEnqueueReleaseDX9MediaSurfacesKHR_fn + clEnqueueReleaseDX9MediaSurfacesKHR; +#endif + +#if HAVE_OPENCL_D3D11 + int d3d11_mapping_usable; + clCreateFromD3D11Texture2DKHR_fn + clCreateFromD3D11Texture2DKHR; + clEnqueueAcquireD3D11ObjectsKHR_fn + clEnqueueAcquireD3D11ObjectsKHR; + clEnqueueReleaseD3D11ObjectsKHR_fn + clEnqueueReleaseD3D11ObjectsKHR; +#endif + +#if HAVE_OPENCL_DRM_ARM + int drm_arm_mapping_usable; +#endif +} OpenCLDeviceContext; + +typedef struct OpenCLFramesContext { + // Command queue used for transfer/mapping operations on this frames + // context. If the user supplies one, this is a reference to it. + // Otherwise, it is a reference to the default command queue for the + // device. + cl_command_queue command_queue; + +#if HAVE_OPENCL_DXVA2 || HAVE_OPENCL_D3D11 + // For mapping APIs which have separate creation and acquire/release + // steps, this stores the OpenCL memory objects corresponding to each + // frame. + int nb_mapped_frames; + AVOpenCLFrameDescriptor *mapped_frames; +#endif +} OpenCLFramesContext; + + +static void opencl_error_callback(const char *errinfo, + const void *private_info, size_t cb, + void *user_data) +{ + AVHWDeviceContext *ctx = user_data; + av_log(ctx, AV_LOG_ERROR, "OpenCL error: %s\n", errinfo); +} + +static void opencl_device_free(AVHWDeviceContext *hwdev) +{ + AVOpenCLDeviceContext *hwctx = hwdev->hwctx; + cl_int cle; + + cle = clReleaseContext(hwctx->context); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to release OpenCL " + "context: %d.\n", cle); + } +} + +static struct { + const char *key; + cl_platform_info name; +} opencl_platform_params[] = { + { "platform_profile", CL_PLATFORM_PROFILE }, + { "platform_version", CL_PLATFORM_VERSION }, + { "platform_name", CL_PLATFORM_NAME }, + { "platform_vendor", CL_PLATFORM_VENDOR }, + { "platform_extensions", CL_PLATFORM_EXTENSIONS }, +}; + +static struct { + const char *key; + cl_device_info name; +} opencl_device_params[] = { + { "device_name", CL_DEVICE_NAME }, + { "device_vendor", CL_DEVICE_VENDOR }, + { "driver_version", CL_DRIVER_VERSION }, + { "device_version", CL_DEVICE_VERSION }, + { "device_profile", CL_DEVICE_PROFILE }, + { "device_extensions", CL_DEVICE_EXTENSIONS }, +}; + +static struct { + const char *key; + cl_device_type type; +} opencl_device_types[] = { + { "cpu", CL_DEVICE_TYPE_CPU }, + { "gpu", CL_DEVICE_TYPE_GPU }, + { "accelerator", CL_DEVICE_TYPE_ACCELERATOR }, + { "custom", CL_DEVICE_TYPE_CUSTOM }, + { "default", CL_DEVICE_TYPE_DEFAULT }, + { "all", CL_DEVICE_TYPE_ALL }, +}; + +static char *opencl_get_platform_string(cl_platform_id platform_id, + cl_platform_info key) +{ + char *str; + size_t size; + cl_int cle; + cle = clGetPlatformInfo(platform_id, key, 0, NULL, &size); + if (cle != CL_SUCCESS) + return NULL; + str = av_malloc(size); + if (!str) + return NULL; + cle = clGetPlatformInfo(platform_id, key, size, str, &size); + if (cle != CL_SUCCESS) { + av_free(str); + return NULL; + } + av_assert0(strlen(str) + 1 == size); + return str; +} + +static char *opencl_get_device_string(cl_device_id device_id, + cl_device_info key) +{ + char *str; + size_t size; + cl_int cle; + cle = clGetDeviceInfo(device_id, key, 0, NULL, &size); + if (cle != CL_SUCCESS) + return NULL; + str = av_malloc(size); + if (!str) + return NULL; + cle = clGetDeviceInfo(device_id, key, size, str, &size); + if (cle != CL_SUCCESS) { + av_free(str); + return NULL; + } + av_assert0(strlen(str) + 1== size); + return str; +} + +static int opencl_check_platform_extension(cl_platform_id platform_id, + const char *name) +{ + char *str; + int found = 0; + str = opencl_get_platform_string(platform_id, + CL_PLATFORM_EXTENSIONS); + if (str && strstr(str, name)) + found = 1; + av_free(str); + return found; +} + +static int opencl_check_device_extension(cl_device_id device_id, + const char *name) +{ + char *str; + int found = 0; + str = opencl_get_device_string(device_id, + CL_DEVICE_EXTENSIONS); + if (str && strstr(str, name)) + found = 1; + av_free(str); + return found; +} + +static av_unused int opencl_check_extension(AVHWDeviceContext *hwdev, + const char *name) +{ + AVOpenCLDeviceContext *hwctx = hwdev->hwctx; + OpenCLDeviceContext *priv = hwdev->internal->priv; + + if (opencl_check_platform_extension(priv->platform_id, name)) { + av_log(hwdev, AV_LOG_DEBUG, + "%s found as platform extension.\n", name); + return 1; + } + + if (opencl_check_device_extension(hwctx->device_id, name)) { + av_log(hwdev, AV_LOG_DEBUG, + "%s found as device extension.\n", name); + return 1; + } + + return 0; +} + +static int opencl_enumerate_platforms(AVHWDeviceContext *hwdev, + cl_uint *nb_platforms, + cl_platform_id **platforms, + void *context) +{ + cl_int cle; + + cle = clGetPlatformIDs(0, NULL, nb_platforms); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get number of " + "OpenCL platforms: %d.\n", cle); + return AVERROR(ENODEV); + } + av_log(hwdev, AV_LOG_DEBUG, "%u OpenCL platforms found.\n", + *nb_platforms); + + *platforms = av_malloc_array(*nb_platforms, sizeof(**platforms)); + if (!*platforms) + return AVERROR(ENOMEM); + + cle = clGetPlatformIDs(*nb_platforms, *platforms, NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get list of OpenCL " + "platforms: %d.\n", cle); + av_freep(platforms); + return AVERROR(ENODEV); + } + + return 0; +} + +static int opencl_filter_platform(AVHWDeviceContext *hwdev, + cl_platform_id platform_id, + const char *platform_name, + void *context) +{ + AVDictionary *opts = context; + const AVDictionaryEntry *param; + char *str; + int i, ret = 0; + + for (i = 0; i < FF_ARRAY_ELEMS(opencl_platform_params); i++) { + param = av_dict_get(opts, opencl_platform_params[i].key, + NULL, 0); + if (!param) + continue; + + str = opencl_get_platform_string(platform_id, + opencl_platform_params[i].name); + if (!str) { + av_log(hwdev, AV_LOG_ERROR, "Failed to query %s " + "of platform \"%s\".\n", + opencl_platform_params[i].key, platform_name); + return AVERROR_UNKNOWN; + } + if (!av_stristr(str, param->value)) { + av_log(hwdev, AV_LOG_DEBUG, "%s does not match (\"%s\").\n", + param->key, str); + ret = 1; + } + av_free(str); + } + + return ret; +} + +static int opencl_enumerate_devices(AVHWDeviceContext *hwdev, + cl_platform_id platform_id, + const char *platform_name, + cl_uint *nb_devices, + cl_device_id **devices, + void *context) +{ + cl_int cle; + + cle = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_ALL, + 0, NULL, nb_devices); + if (cle == CL_DEVICE_NOT_FOUND) { + av_log(hwdev, AV_LOG_DEBUG, "No devices found " + "on platform \"%s\".\n", platform_name); + *nb_devices = 0; + return 0; + } else if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices " + "on platform \"%s\": %d.\n", platform_name, cle); + return AVERROR(ENODEV); + } + av_log(hwdev, AV_LOG_DEBUG, "%u OpenCL devices found on " + "platform \"%s\".\n", *nb_devices, platform_name); + + *devices = av_malloc_array(*nb_devices, sizeof(**devices)); + if (!*devices) + return AVERROR(ENOMEM); + + cle = clGetDeviceIDs(platform_id, CL_DEVICE_TYPE_ALL, + *nb_devices, *devices, NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get list of devices " + "on platform \"%s\": %d.\n", platform_name, cle); + av_freep(devices); + return AVERROR(ENODEV); + } + + return 0; +} + +static int opencl_filter_device(AVHWDeviceContext *hwdev, + cl_device_id device_id, + const char *device_name, + void *context) +{ + AVDictionary *opts = context; + const AVDictionaryEntry *param; + char *str; + int i, ret = 0; + + param = av_dict_get(opts, "device_type", NULL, 0); + if (param) { + cl_device_type match_type = 0, device_type; + cl_int cle; + + for (i = 0; i < FF_ARRAY_ELEMS(opencl_device_types); i++) { + if (!strcmp(opencl_device_types[i].key, param->value)) { + match_type = opencl_device_types[i].type; + break; + } + } + if (!match_type) { + av_log(hwdev, AV_LOG_ERROR, "Unknown device type %s.\n", + param->value); + return AVERROR(EINVAL); + } + + cle = clGetDeviceInfo(device_id, CL_DEVICE_TYPE, + sizeof(device_type), &device_type, NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to query device type " + "of device \"%s\".\n", device_name); + return AVERROR_UNKNOWN; + } + + if (!(device_type & match_type)) { + av_log(hwdev, AV_LOG_DEBUG, "device_type does not match.\n"); + return 1; + } + } + + for (i = 0; i < FF_ARRAY_ELEMS(opencl_device_params); i++) { + param = av_dict_get(opts, opencl_device_params[i].key, + NULL, 0); + if (!param) + continue; + + str = opencl_get_device_string(device_id, + opencl_device_params[i].name); + if (!str) { + av_log(hwdev, AV_LOG_ERROR, "Failed to query %s " + "of device \"%s\".\n", + opencl_device_params[i].key, device_name); + return AVERROR_UNKNOWN; + } + if (!av_stristr(str, param->value)) { + av_log(hwdev, AV_LOG_DEBUG, "%s does not match (\"%s\").\n", + param->key, str); + ret = 1; + } + av_free(str); + } + + return ret; +} + +typedef struct OpenCLDeviceSelector { + int platform_index; + int device_index; + void *context; + int (*enumerate_platforms)(AVHWDeviceContext *hwdev, + cl_uint *nb_platforms, + cl_platform_id **platforms, + void *context); + int (*filter_platform) (AVHWDeviceContext *hwdev, + cl_platform_id platform_id, + const char *platform_name, + void *context); + int (*enumerate_devices) (AVHWDeviceContext *hwdev, + cl_platform_id platform_id, + const char *platform_name, + cl_uint *nb_devices, + cl_device_id **devices, + void *context); + int (*filter_device) (AVHWDeviceContext *hwdev, + cl_device_id device_id, + const char *device_name, + void *context); +} OpenCLDeviceSelector; + +static int opencl_device_create_internal(AVHWDeviceContext *hwdev, + const OpenCLDeviceSelector *selector, + cl_context_properties *props) +{ + cl_uint nb_platforms; + cl_platform_id *platforms = NULL; + cl_platform_id platform_id; + cl_uint nb_devices; + cl_device_id *devices = NULL; + AVOpenCLDeviceContext *hwctx = hwdev->hwctx; + cl_int cle; + cl_context_properties default_props[3]; + char *platform_name_src = NULL, + *device_name_src = NULL; + int err, found, p, d; + + err = selector->enumerate_platforms(hwdev, &nb_platforms, &platforms, + selector->context); + if (err) + return err; + + found = 0; + for (p = 0; p < nb_platforms; p++) { + const char *platform_name; + + if (selector->platform_index >= 0 && + selector->platform_index != p) + continue; + + av_freep(&platform_name_src); + platform_name_src = opencl_get_platform_string(platforms[p], + CL_PLATFORM_NAME); + if (platform_name_src) + platform_name = platform_name_src; + else + platform_name = "Unknown Platform"; + + if (selector->filter_platform) { + err = selector->filter_platform(hwdev, platforms[p], + platform_name, + selector->context); + if (err < 0) + goto fail; + if (err > 0) + continue; + } + + err = opencl_enumerate_devices(hwdev, platforms[p], platform_name, + &nb_devices, &devices, + selector->context); + if (err < 0) + continue; + + for (d = 0; d < nb_devices; d++) { + const char *device_name; + + if (selector->device_index >= 0 && + selector->device_index != d) + continue; + + av_freep(&device_name_src); + device_name_src = opencl_get_device_string(devices[d], + CL_DEVICE_NAME); + if (device_name_src) + device_name = device_name_src; + else + device_name = "Unknown Device"; + + if (selector->filter_device) { + err = selector->filter_device(hwdev, devices[d], + device_name, + selector->context); + if (err < 0) + goto fail; + if (err > 0) + continue; + } + + av_log(hwdev, AV_LOG_VERBOSE, "%d.%d: %s / %s\n", p, d, + platform_name, device_name); + + ++found; + platform_id = platforms[p]; + hwctx->device_id = devices[d]; + } + + av_freep(&devices); + } + + if (found == 0) { + av_log(hwdev, AV_LOG_ERROR, "No matching devices found.\n"); + err = AVERROR(ENODEV); + goto fail; + } + if (found > 1) { + av_log(hwdev, AV_LOG_ERROR, "More than one matching device found.\n"); + err = AVERROR(ENODEV); + goto fail; + } + + if (!props) { + props = default_props; + default_props[0] = CL_CONTEXT_PLATFORM; + default_props[1] = (intptr_t)platform_id; + default_props[2] = 0; + } else { + if (props[0] == CL_CONTEXT_PLATFORM && props[1] == 0) + props[1] = (intptr_t)platform_id; + } + + hwctx->context = clCreateContext(props, 1, &hwctx->device_id, + &opencl_error_callback, hwdev, &cle); + if (!hwctx->context) { + av_log(hwdev, AV_LOG_ERROR, "Failed to create OpenCL context: " + "%d.\n", cle); + err = AVERROR(ENODEV); + goto fail; + } + + hwdev->free = &opencl_device_free; + + err = 0; +fail: + av_freep(&platform_name_src); + av_freep(&device_name_src); + av_freep(&platforms); + av_freep(&devices); + return err; +} + +static int opencl_device_create(AVHWDeviceContext *hwdev, const char *device, + AVDictionary *opts, int flags) +{ + OpenCLDeviceSelector selector = { + .context = opts, + .enumerate_platforms = &opencl_enumerate_platforms, + .filter_platform = &opencl_filter_platform, + .enumerate_devices = &opencl_enumerate_devices, + .filter_device = &opencl_filter_device, + }; + + if (device && device[0]) { + // Match one or both indices for platform and device. + int d = -1, p = -1, ret; + if (device[0] == '.') + ret = sscanf(device, ".%d", &d); + else + ret = sscanf(device, "%d.%d", &p, &d); + if (ret < 1) { + av_log(hwdev, AV_LOG_ERROR, "Invalid OpenCL platform/device " + "index specification \"%s\".\n", device); + return AVERROR(EINVAL); + } + selector.platform_index = p; + selector.device_index = d; + } else { + selector.platform_index = -1; + selector.device_index = -1; + } + + return opencl_device_create_internal(hwdev, &selector, NULL); +} + +static int opencl_device_init(AVHWDeviceContext *hwdev) +{ + AVOpenCLDeviceContext *hwctx = hwdev->hwctx; + OpenCLDeviceContext *priv = hwdev->internal->priv; + cl_int cle; + + if (hwctx->command_queue) { + cle = clRetainCommandQueue(hwctx->command_queue); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to retain external " + "command queue: %d.\n", cle); + return AVERROR(EIO); + } + priv->command_queue = hwctx->command_queue; + } else { + priv->command_queue = clCreateCommandQueue(hwctx->context, + hwctx->device_id, + 0, &cle); + if (!priv->command_queue) { + av_log(hwdev, AV_LOG_ERROR, "Failed to create internal " + "command queue: %d.\n", cle); + return AVERROR(EIO); + } + } + + cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_PLATFORM, + sizeof(priv->platform_id), &priv->platform_id, + NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to determine the OpenCL " + "platform containing the device.\n"); + return AVERROR(EIO); + } + +#define CL_FUNC(name, desc) do { \ + if (fail) \ + break; \ + priv->name = clGetExtensionFunctionAddressForPlatform( \ + priv->platform_id, #name); \ + if (!priv->name) { \ + av_log(hwdev, AV_LOG_VERBOSE, \ + desc " function not found (%s).\n", #name); \ + fail = 1; \ + } else { \ + av_log(hwdev, AV_LOG_VERBOSE, \ + desc " function found (%s).\n", #name); \ + } \ + } while (0) + +#if HAVE_OPENCL_DRM_BEIGNET + { + int fail = 0; + + CL_FUNC(clCreateImageFromFdINTEL, + "Beignet DRM to OpenCL image mapping"); + + if (fail) { + av_log(hwdev, AV_LOG_WARNING, "Beignet DRM to OpenCL " + "mapping not usable.\n"); + priv->beignet_drm_mapping_usable = 0; + } else { + priv->beignet_drm_mapping_usable = 1; + } + } +#endif + +#if HAVE_OPENCL_VAAPI_INTEL_MEDIA + { + size_t props_size; + cl_context_properties *props = NULL; + VADisplay va_display; + const char *va_ext = "cl_intel_va_api_media_sharing"; + int i, fail = 0; + + if (!opencl_check_extension(hwdev, va_ext)) { + av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is " + "required for QSV to OpenCL mapping.\n", va_ext); + goto no_qsv; + } + + cle = clGetContextInfo(hwctx->context, CL_CONTEXT_PROPERTIES, + 0, NULL, &props_size); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_VERBOSE, "Failed to get context " + "properties: %d.\n", cle); + goto no_qsv; + } + if (props_size == 0) { + av_log(hwdev, AV_LOG_VERBOSE, "Media sharing must be " + "enabled on context creation to use QSV to " + "OpenCL mapping.\n"); + goto no_qsv; + } + + props = av_malloc(props_size); + if (!props) + return AVERROR(ENOMEM); + + cle = clGetContextInfo(hwctx->context, CL_CONTEXT_PROPERTIES, + props_size, props, NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_VERBOSE, "Failed to get context " + "properties: %d.\n", cle); + goto no_qsv; + } + + va_display = NULL; + for (i = 0; i < (props_size / sizeof(*props) - 1); i++) { + if (props[i] == CL_CONTEXT_VA_API_DISPLAY_INTEL) { + va_display = (VADisplay)(intptr_t)props[i+1]; + break; + } + } + if (!va_display) { + av_log(hwdev, AV_LOG_VERBOSE, "Media sharing must be " + "enabled on context creation to use QSV to " + "OpenCL mapping.\n"); + goto no_qsv; + } + if (!vaDisplayIsValid(va_display)) { + av_log(hwdev, AV_LOG_VERBOSE, "A valid VADisplay is " + "required on context creation to use QSV to " + "OpenCL mapping.\n"); + goto no_qsv; + } + + CL_FUNC(clCreateFromVA_APIMediaSurfaceINTEL, + "Intel QSV to OpenCL mapping"); + CL_FUNC(clEnqueueAcquireVA_APIMediaSurfacesINTEL, + "Intel QSV in OpenCL acquire"); + CL_FUNC(clEnqueueReleaseVA_APIMediaSurfacesINTEL, + "Intel QSV in OpenCL release"); + + if (fail) { + no_qsv: + av_log(hwdev, AV_LOG_WARNING, "QSV to OpenCL mapping " + "not usable.\n"); + priv->qsv_mapping_usable = 0; + } else { + priv->qsv_mapping_usable = 1; + } + av_free(props); + } +#endif + +#if HAVE_OPENCL_DXVA2 + { + int fail = 0; + + CL_FUNC(clCreateFromDX9MediaSurfaceKHR, + "DXVA2 to OpenCL mapping"); + CL_FUNC(clEnqueueAcquireDX9MediaSurfacesKHR, + "DXVA2 in OpenCL acquire"); + CL_FUNC(clEnqueueReleaseDX9MediaSurfacesKHR, + "DXVA2 in OpenCL release"); + + if (fail) { + av_log(hwdev, AV_LOG_WARNING, "DXVA2 to OpenCL mapping " + "not usable.\n"); + priv->dxva2_mapping_usable = 0; + } else { + priv->dx9_media_adapter_type = CL_ADAPTER_D3D9EX_KHR; + priv->dxva2_mapping_usable = 1; + } + } +#endif + +#if HAVE_OPENCL_D3D11 + { + const char *d3d11_ext = "cl_khr_d3d11_sharing"; + const char *nv12_ext = "cl_intel_d3d11_nv12_media_sharing"; + int fail = 0; + + if (!opencl_check_extension(hwdev, d3d11_ext)) { + av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is " + "required for D3D11 to OpenCL mapping.\n", d3d11_ext); + fail = 1; + } else if (!opencl_check_extension(hwdev, nv12_ext)) { + av_log(hwdev, AV_LOG_VERBOSE, "The %s extension may be " + "required for D3D11 to OpenCL mapping.\n", nv12_ext); + // Not fatal. + } + + CL_FUNC(clCreateFromD3D11Texture2DKHR, + "D3D11 to OpenCL mapping"); + CL_FUNC(clEnqueueAcquireD3D11ObjectsKHR, + "D3D11 in OpenCL acquire"); + CL_FUNC(clEnqueueReleaseD3D11ObjectsKHR, + "D3D11 in OpenCL release"); + + if (fail) { + av_log(hwdev, AV_LOG_WARNING, "D3D11 to OpenCL mapping " + "not usable.\n"); + priv->d3d11_mapping_usable = 0; + } else { + priv->d3d11_mapping_usable = 1; + } + } +#endif + +#if HAVE_OPENCL_DRM_ARM + { + const char *drm_arm_ext = "cl_arm_import_memory"; + const char *image_ext = "cl_khr_image2d_from_buffer"; + int fail = 0; + + if (!opencl_check_extension(hwdev, drm_arm_ext)) { + av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is " + "required for DRM to OpenCL mapping on ARM.\n", + drm_arm_ext); + fail = 1; + } + if (!opencl_check_extension(hwdev, image_ext)) { + av_log(hwdev, AV_LOG_VERBOSE, "The %s extension is " + "required for DRM to OpenCL mapping on ARM.\n", + image_ext); + fail = 1; + } + + // clImportMemoryARM() is linked statically. + + if (fail) { + av_log(hwdev, AV_LOG_WARNING, "DRM to OpenCL mapping on ARM " + "not usable.\n"); + priv->drm_arm_mapping_usable = 0; + } else { + priv->drm_arm_mapping_usable = 1; + } + } +#endif + +#undef CL_FUNC + + return 0; +} + +static void opencl_device_uninit(AVHWDeviceContext *hwdev) +{ + OpenCLDeviceContext *priv = hwdev->internal->priv; + cl_int cle; + + if (priv->command_queue) { + cle = clReleaseCommandQueue(priv->command_queue); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to release internal " + "command queue reference: %d.\n", cle); + } + priv->command_queue = NULL; + } +} + +#if HAVE_OPENCL_VAAPI_INTEL_MEDIA +static int opencl_filter_intel_media_vaapi_platform(AVHWDeviceContext *hwdev, + cl_platform_id platform_id, + const char *platform_name, + void *context) +{ + // This doesn't exist as a platform extension, so just test whether + // the function we will use for device enumeration exists. + + if (!clGetExtensionFunctionAddressForPlatform(platform_id, + "clGetDeviceIDsFromVA_APIMediaAdapterINTEL")) { + av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not export the " + "VAAPI device enumeration function.\n", platform_name); + return 1; + } else { + return 0; + } +} + +static int opencl_enumerate_intel_media_vaapi_devices(AVHWDeviceContext *hwdev, + cl_platform_id platform_id, + const char *platform_name, + cl_uint *nb_devices, + cl_device_id **devices, + void *context) +{ + VADisplay va_display = context; + clGetDeviceIDsFromVA_APIMediaAdapterINTEL_fn + clGetDeviceIDsFromVA_APIMediaAdapterINTEL; + cl_int cle; + int err; + + clGetDeviceIDsFromVA_APIMediaAdapterINTEL = + clGetExtensionFunctionAddressForPlatform(platform_id, + "clGetDeviceIDsFromVA_APIMediaAdapterINTEL"); + if (!clGetDeviceIDsFromVA_APIMediaAdapterINTEL) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get address of " + "clGetDeviceIDsFromVA_APIMediaAdapterINTEL().\n"); + return AVERROR_UNKNOWN; + } + + cle = clGetDeviceIDsFromVA_APIMediaAdapterINTEL( + platform_id, CL_VA_API_DISPLAY_INTEL, va_display, + CL_PREFERRED_DEVICES_FOR_VA_API_INTEL, 0, NULL, nb_devices); + if (cle == CL_DEVICE_NOT_FOUND) { + av_log(hwdev, AV_LOG_DEBUG, "No VAAPI-supporting devices found " + "on platform \"%s\".\n", platform_name); + *nb_devices = 0; + return 0; + } else if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices " + "on platform \"%s\": %d.\n", platform_name, cle); + return AVERROR_UNKNOWN; + } + + *devices = av_malloc_array(*nb_devices, sizeof(**devices)); + if (!*devices) + return AVERROR(ENOMEM); + + cle = clGetDeviceIDsFromVA_APIMediaAdapterINTEL( + platform_id, CL_VA_API_DISPLAY_INTEL, va_display, + CL_PREFERRED_DEVICES_FOR_VA_API_INTEL, *nb_devices, *devices, NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get list of VAAPI-supporting " + "devices on platform \"%s\": %d.\n", platform_name, cle); + av_freep(devices); + return AVERROR_UNKNOWN; + } + + return 0; +} + +static int opencl_filter_intel_media_vaapi_device(AVHWDeviceContext *hwdev, + cl_device_id device_id, + const char *device_name, + void *context) +{ + const char *va_ext = "cl_intel_va_api_media_sharing"; + + if (opencl_check_device_extension(device_id, va_ext)) { + return 0; + } else { + av_log(hwdev, AV_LOG_DEBUG, "Device %s does not support the " + "%s extension.\n", device_name, va_ext); + return 1; + } +} +#endif + +#if HAVE_OPENCL_DXVA2 +static int opencl_filter_dxva2_platform(AVHWDeviceContext *hwdev, + cl_platform_id platform_id, + const char *platform_name, + void *context) +{ + const char *dx9_ext = "cl_khr_dx9_media_sharing"; + + if (opencl_check_platform_extension(platform_id, dx9_ext)) { + return 0; + } else { + av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not support the " + "%s extension.\n", platform_name, dx9_ext); + return 1; + } +} + +static int opencl_enumerate_dxva2_devices(AVHWDeviceContext *hwdev, + cl_platform_id platform_id, + const char *platform_name, + cl_uint *nb_devices, + cl_device_id **devices, + void *context) +{ + IDirect3DDevice9 *device = context; + clGetDeviceIDsFromDX9MediaAdapterKHR_fn + clGetDeviceIDsFromDX9MediaAdapterKHR; + cl_dx9_media_adapter_type_khr media_adapter_type = CL_ADAPTER_D3D9EX_KHR; + cl_int cle; + + clGetDeviceIDsFromDX9MediaAdapterKHR = + clGetExtensionFunctionAddressForPlatform(platform_id, + "clGetDeviceIDsFromDX9MediaAdapterKHR"); + if (!clGetDeviceIDsFromDX9MediaAdapterKHR) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get address of " + "clGetDeviceIDsFromDX9MediaAdapterKHR().\n"); + return AVERROR_UNKNOWN; + } + + cle = clGetDeviceIDsFromDX9MediaAdapterKHR( + platform_id, 1, &media_adapter_type, (void**)&device, + CL_PREFERRED_DEVICES_FOR_DX9_MEDIA_ADAPTER_KHR, + 0, NULL, nb_devices); + if (cle == CL_DEVICE_NOT_FOUND) { + av_log(hwdev, AV_LOG_DEBUG, "No DXVA2-supporting devices found " + "on platform \"%s\".\n", platform_name); + *nb_devices = 0; + return 0; + } else if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices " + "on platform \"%s\": %d.\n", platform_name, cle); + return AVERROR_UNKNOWN; + } + + *devices = av_malloc_array(*nb_devices, sizeof(**devices)); + if (!*devices) + return AVERROR(ENOMEM); + + cle = clGetDeviceIDsFromDX9MediaAdapterKHR( + platform_id, 1, &media_adapter_type, (void**)&device, + CL_PREFERRED_DEVICES_FOR_DX9_MEDIA_ADAPTER_KHR, + *nb_devices, *devices, NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get list of DXVA2-supporting " + "devices on platform \"%s\": %d.\n", platform_name, cle); + av_freep(devices); + return AVERROR_UNKNOWN; + } + + return 0; +} +#endif + +#if HAVE_OPENCL_D3D11 +static int opencl_filter_d3d11_platform(AVHWDeviceContext *hwdev, + cl_platform_id platform_id, + const char *platform_name, + void *context) +{ + const char *d3d11_ext = "cl_khr_d3d11_sharing"; + + if (opencl_check_platform_extension(platform_id, d3d11_ext)) { + return 0; + } else { + av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not support the " + "%s extension.\n", platform_name, d3d11_ext); + return 1; + } +} + +static int opencl_enumerate_d3d11_devices(AVHWDeviceContext *hwdev, + cl_platform_id platform_id, + const char *platform_name, + cl_uint *nb_devices, + cl_device_id **devices, + void *context) +{ + ID3D11Device *device = context; + clGetDeviceIDsFromD3D11KHR_fn clGetDeviceIDsFromD3D11KHR; + cl_int cle; + + clGetDeviceIDsFromD3D11KHR = + clGetExtensionFunctionAddressForPlatform(platform_id, + "clGetDeviceIDsFromD3D11KHR"); + if (!clGetDeviceIDsFromD3D11KHR) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get address of " + "clGetDeviceIDsFromD3D11KHR().\n"); + return AVERROR_UNKNOWN; + } + + cle = clGetDeviceIDsFromD3D11KHR(platform_id, + CL_D3D11_DEVICE_KHR, device, + CL_PREFERRED_DEVICES_FOR_D3D11_KHR, + 0, NULL, nb_devices); + if (cle == CL_DEVICE_NOT_FOUND) { + av_log(hwdev, AV_LOG_DEBUG, "No D3D11-supporting devices found " + "on platform \"%s\".\n", platform_name); + *nb_devices = 0; + return 0; + } else if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get number of devices " + "on platform \"%s\": %d.\n", platform_name, cle); + return AVERROR_UNKNOWN; + } + + *devices = av_malloc_array(*nb_devices, sizeof(**devices)); + if (!*devices) + return AVERROR(ENOMEM); + + cle = clGetDeviceIDsFromD3D11KHR(platform_id, + CL_D3D11_DEVICE_KHR, device, + CL_PREFERRED_DEVICES_FOR_D3D11_KHR, + *nb_devices, *devices, NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to get list of D3D11-supporting " + "devices on platform \"%s\": %d.\n", platform_name, cle); + av_freep(devices); + return AVERROR_UNKNOWN; + } + + return 0; +} +#endif + +#if HAVE_OPENCL_DXVA2 || HAVE_OPENCL_D3D11 +static int opencl_filter_gpu_device(AVHWDeviceContext *hwdev, + cl_device_id device_id, + const char *device_name, + void *context) +{ + cl_device_type device_type; + cl_int cle; + + cle = clGetDeviceInfo(device_id, CL_DEVICE_TYPE, + sizeof(device_type), &device_type, NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to query device type " + "of device \"%s\".\n", device_name); + return AVERROR_UNKNOWN; + } + if (!(device_type & CL_DEVICE_TYPE_GPU)) { + av_log(hwdev, AV_LOG_DEBUG, "Device %s skipped (not GPU).\n", + device_name); + return 1; + } + + return 0; +} +#endif + +#if HAVE_OPENCL_DRM_ARM +static int opencl_filter_drm_arm_platform(AVHWDeviceContext *hwdev, + cl_platform_id platform_id, + const char *platform_name, + void *context) +{ + const char *drm_arm_ext = "cl_arm_import_memory"; + + if (opencl_check_platform_extension(platform_id, drm_arm_ext)) { + return 0; + } else { + av_log(hwdev, AV_LOG_DEBUG, "Platform %s does not support the " + "%s extension.\n", platform_name, drm_arm_ext); + return 1; + } +} + +static int opencl_filter_drm_arm_device(AVHWDeviceContext *hwdev, + cl_device_id device_id, + const char *device_name, + void *context) +{ + const char *drm_arm_ext = "cl_arm_import_memory"; + + if (opencl_check_device_extension(device_id, drm_arm_ext)) { + return 0; + } else { + av_log(hwdev, AV_LOG_DEBUG, "Device %s does not support the " + "%s extension.\n", device_name, drm_arm_ext); + return 1; + } +} +#endif + +static int opencl_device_derive(AVHWDeviceContext *hwdev, + AVHWDeviceContext *src_ctx, + int flags) +{ + int err; + switch (src_ctx->type) { + +#if HAVE_OPENCL_DRM_BEIGNET + case AV_HWDEVICE_TYPE_DRM: + case AV_HWDEVICE_TYPE_VAAPI: + { + // Surface mapping works via DRM PRIME fds with no special + // initialisation required in advance. This just finds the + // Beignet ICD by name. + AVDictionary *opts = NULL; + + err = av_dict_set(&opts, "platform_vendor", "Intel", 0); + if (err >= 0) + err = av_dict_set(&opts, "platform_version", "beignet", 0); + if (err >= 0) { + OpenCLDeviceSelector selector = { + .platform_index = -1, + .device_index = 0, + .context = opts, + .enumerate_platforms = &opencl_enumerate_platforms, + .filter_platform = &opencl_filter_platform, + .enumerate_devices = &opencl_enumerate_devices, + .filter_device = NULL, + }; + err = opencl_device_create_internal(hwdev, &selector, NULL); + } + av_dict_free(&opts); + } + break; +#endif + +#if HAVE_OPENCL_VAAPI_INTEL_MEDIA + // The generic code automatically attempts to derive from all + // ancestors of the given device, so we can ignore QSV devices here + // and just consider the inner VAAPI device it was derived from. + case AV_HWDEVICE_TYPE_VAAPI: + { + AVVAAPIDeviceContext *src_hwctx = src_ctx->hwctx; + cl_context_properties props[7] = { + CL_CONTEXT_PLATFORM, + 0, + CL_CONTEXT_VA_API_DISPLAY_INTEL, + (intptr_t)src_hwctx->display, + CL_CONTEXT_INTEROP_USER_SYNC, + CL_FALSE, + 0, + }; + OpenCLDeviceSelector selector = { + .platform_index = -1, + .device_index = -1, + .context = src_hwctx->display, + .enumerate_platforms = &opencl_enumerate_platforms, + .filter_platform = &opencl_filter_intel_media_vaapi_platform, + .enumerate_devices = &opencl_enumerate_intel_media_vaapi_devices, + .filter_device = &opencl_filter_intel_media_vaapi_device, + }; + + err = opencl_device_create_internal(hwdev, &selector, props); + } + break; +#endif + +#if HAVE_OPENCL_DXVA2 + case AV_HWDEVICE_TYPE_DXVA2: + { + AVDXVA2DeviceContext *src_hwctx = src_ctx->hwctx; + IDirect3DDevice9 *device; + HANDLE device_handle; + HRESULT hr; + + hr = IDirect3DDeviceManager9_OpenDeviceHandle(src_hwctx->devmgr, + &device_handle); + if (FAILED(hr)) { + av_log(hwdev, AV_LOG_ERROR, "Failed to open device handle " + "for Direct3D9 device: %lx.\n", (unsigned long)hr); + err = AVERROR_UNKNOWN; + break; + } + + hr = IDirect3DDeviceManager9_LockDevice(src_hwctx->devmgr, + device_handle, + &device, FALSE); + if (SUCCEEDED(hr)) { + cl_context_properties props[5] = { + CL_CONTEXT_PLATFORM, + 0, + CL_CONTEXT_ADAPTER_D3D9EX_KHR, + (intptr_t)device, + 0, + }; + OpenCLDeviceSelector selector = { + .platform_index = -1, + .device_index = -1, + .context = device, + .enumerate_platforms = &opencl_enumerate_platforms, + .filter_platform = &opencl_filter_dxva2_platform, + .enumerate_devices = &opencl_enumerate_dxva2_devices, + .filter_device = &opencl_filter_gpu_device, + }; + + err = opencl_device_create_internal(hwdev, &selector, props); + + IDirect3DDeviceManager9_UnlockDevice(src_hwctx->devmgr, + device_handle, FALSE); + } else { + av_log(hwdev, AV_LOG_ERROR, "Failed to lock device handle " + "for Direct3D9 device: %lx.\n", (unsigned long)hr); + err = AVERROR_UNKNOWN; + } + + IDirect3DDeviceManager9_CloseDeviceHandle(src_hwctx->devmgr, + device_handle); + } + break; +#endif + +#if HAVE_OPENCL_D3D11 + case AV_HWDEVICE_TYPE_D3D11VA: + { + AVD3D11VADeviceContext *src_hwctx = src_ctx->hwctx; + cl_context_properties props[5] = { + CL_CONTEXT_PLATFORM, + 0, + CL_CONTEXT_D3D11_DEVICE_KHR, + (intptr_t)src_hwctx->device, + 0, + }; + OpenCLDeviceSelector selector = { + .platform_index = -1, + .device_index = -1, + .context = src_hwctx->device, + .enumerate_platforms = &opencl_enumerate_platforms, + .filter_platform = &opencl_filter_d3d11_platform, + .enumerate_devices = &opencl_enumerate_d3d11_devices, + .filter_device = &opencl_filter_gpu_device, + }; + + err = opencl_device_create_internal(hwdev, &selector, props); + } + break; +#endif + +#if HAVE_OPENCL_DRM_ARM + case AV_HWDEVICE_TYPE_DRM: + { + OpenCLDeviceSelector selector = { + .platform_index = -1, + .device_index = -1, + .context = NULL, + .enumerate_platforms = &opencl_enumerate_platforms, + .filter_platform = &opencl_filter_drm_arm_platform, + .enumerate_devices = &opencl_enumerate_devices, + .filter_device = &opencl_filter_drm_arm_device, + }; + + err = opencl_device_create_internal(hwdev, &selector, NULL); + } + break; +#endif + + default: + err = AVERROR(ENOSYS); + break; + } + + if (err < 0) + return err; + + return opencl_device_init(hwdev); +} + +static int opencl_get_plane_format(enum AVPixelFormat pixfmt, + int plane, int width, int height, + cl_image_format *image_format, + cl_image_desc *image_desc) +{ + const AVPixFmtDescriptor *desc; + const AVComponentDescriptor *comp; + int channels = 0, order = 0, depth = 0, step = 0; + int wsub, hsub, alpha; + int c; + + if (plane >= AV_NUM_DATA_POINTERS) + return AVERROR(ENOENT); + + desc = av_pix_fmt_desc_get(pixfmt); + + // Only normal images are allowed. + if (desc->flags & (AV_PIX_FMT_FLAG_BITSTREAM | + AV_PIX_FMT_FLAG_HWACCEL | + AV_PIX_FMT_FLAG_PAL)) + return AVERROR(EINVAL); + + wsub = 1 << desc->log2_chroma_w; + hsub = 1 << desc->log2_chroma_h; + // Subsampled components must be exact. + if (width & wsub - 1 || height & hsub - 1) + return AVERROR(EINVAL); + + for (c = 0; c < desc->nb_components; c++) { + comp = &desc->comp[c]; + if (comp->plane != plane) + continue; + // The step size must be a power of two. + if (comp->step != 1 && comp->step != 2 && + comp->step != 4 && comp->step != 8) + return AVERROR(EINVAL); + // The bits in each component must be packed in the + // most-significant-bits of the relevant bytes. + if (comp->shift + comp->depth != 8 && + comp->shift + comp->depth != 16) + return AVERROR(EINVAL); + // The depth must not vary between components. + if (depth && comp->depth != depth) + return AVERROR(EINVAL); + // If a single data element crosses multiple bytes then + // it must match the native endianness. + if (comp->depth > 8 && + HAVE_BIGENDIAN == !(desc->flags & AV_PIX_FMT_FLAG_BE)) + return AVERROR(EINVAL); + // A single data element must not contain multiple samples + // from the same component. + if (step && comp->step != step) + return AVERROR(EINVAL); + order = order * 10 + c + 1; + depth = comp->depth; + step = comp->step; + alpha = (desc->flags & AV_PIX_FMT_FLAG_ALPHA && + c == desc->nb_components - 1); + ++channels; + } + if (channels == 0) + return AVERROR(ENOENT); + + memset(image_format, 0, sizeof(*image_format)); + memset(image_desc, 0, sizeof(*image_desc)); + image_desc->image_type = CL_MEM_OBJECT_IMAGE2D; + + if (plane == 0 || alpha) { + image_desc->image_width = width; + image_desc->image_height = height; + image_desc->image_row_pitch = step * width; + } else { + image_desc->image_width = width / wsub; + image_desc->image_height = height / hsub; + image_desc->image_row_pitch = step * width / wsub; + } + + if (depth <= 8) { + image_format->image_channel_data_type = CL_UNORM_INT8; + } else { + if (depth <= 16) + image_format->image_channel_data_type = CL_UNORM_INT16; + else + return AVERROR(EINVAL); + } + +#define CHANNEL_ORDER(order, type) \ + case order: image_format->image_channel_order = type; break; + switch (order) { + CHANNEL_ORDER(1, CL_R); + CHANNEL_ORDER(2, CL_R); + CHANNEL_ORDER(3, CL_R); + CHANNEL_ORDER(4, CL_R); + CHANNEL_ORDER(12, CL_RG); + CHANNEL_ORDER(23, CL_RG); + CHANNEL_ORDER(1234, CL_RGBA); + CHANNEL_ORDER(3214, CL_BGRA); + CHANNEL_ORDER(4123, CL_ARGB); +#ifdef CL_ABGR + CHANNEL_ORDER(4321, CL_ABGR); +#endif + default: + return AVERROR(EINVAL); + } +#undef CHANNEL_ORDER + + return 0; +} + +static int opencl_frames_get_constraints(AVHWDeviceContext *hwdev, + const void *hwconfig, + AVHWFramesConstraints *constraints) +{ + AVOpenCLDeviceContext *hwctx = hwdev->hwctx; + cl_uint nb_image_formats; + cl_image_format *image_formats = NULL; + cl_int cle; + enum AVPixelFormat pix_fmt; + int err, pix_fmts_found; + size_t max_width, max_height; + + cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_IMAGE2D_MAX_WIDTH, + sizeof(max_width), &max_width, NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to query maximum " + "supported image width: %d.\n", cle); + } else { + constraints->max_width = max_width; + } + cle = clGetDeviceInfo(hwctx->device_id, CL_DEVICE_IMAGE2D_MAX_HEIGHT, + sizeof(max_height), &max_height, NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to query maximum " + "supported image height: %d.\n", cle); + } else { + constraints->max_height = max_height; + } + av_log(hwdev, AV_LOG_DEBUG, "Maximum supported image size %dx%d.\n", + constraints->max_width, constraints->max_height); + + cle = clGetSupportedImageFormats(hwctx->context, + CL_MEM_READ_WRITE, + CL_MEM_OBJECT_IMAGE2D, + 0, NULL, &nb_image_formats); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to query supported " + "image formats: %d.\n", cle); + err = AVERROR(ENOSYS); + goto fail; + } + if (nb_image_formats == 0) { + av_log(hwdev, AV_LOG_ERROR, "No image support in OpenCL " + "driver (zero supported image formats).\n"); + err = AVERROR(ENOSYS); + goto fail; + } + + image_formats = + av_malloc_array(nb_image_formats, sizeof(*image_formats)); + if (!image_formats) { + err = AVERROR(ENOMEM); + goto fail; + } + + cle = clGetSupportedImageFormats(hwctx->context, + CL_MEM_READ_WRITE, + CL_MEM_OBJECT_IMAGE2D, + nb_image_formats, + image_formats, NULL); + if (cle != CL_SUCCESS) { + av_log(hwdev, AV_LOG_ERROR, "Failed to query supported " + "image formats: %d.\n", cle); + err = AVERROR(ENOSYS); + goto fail; + } + + pix_fmts_found = 0; + for (pix_fmt = 0; pix_fmt < AV_PIX_FMT_NB; pix_fmt++) { + cl_image_format image_format; + cl_image_desc image_desc; + int plane, i; + + for (plane = 0;; plane++) { + err = opencl_get_plane_format(pix_fmt, plane, 0, 0, + &image_format, + &image_desc); + if (err < 0) + break; + + for (i = 0; i < nb_image_formats; i++) { + if (image_formats[i].image_channel_order == + image_format.image_channel_order && + image_formats[i].image_channel_data_type == + image_format.image_channel_data_type) + break; + } + if (i == nb_image_formats) { + err = AVERROR(EINVAL); + break; + } + } + if (err != AVERROR(ENOENT)) + continue; + + av_log(hwdev, AV_LOG_DEBUG, "Format %s supported.\n", + av_get_pix_fmt_name(pix_fmt)); + + err = av_reallocp_array(&constraints->valid_sw_formats, + pix_fmts_found + 2, + sizeof(*constraints->valid_sw_formats)); + if (err < 0) + goto fail; + constraints->valid_sw_formats[pix_fmts_found] = pix_fmt; + constraints->valid_sw_formats[pix_fmts_found + 1] = + AV_PIX_FMT_NONE; + ++pix_fmts_found; + } + + av_freep(&image_formats); + + constraints->valid_hw_formats = + av_malloc_array(2, sizeof(*constraints->valid_hw_formats)); + if (!constraints->valid_hw_formats) { + err = AVERROR(ENOMEM); + goto fail; + } + constraints->valid_hw_formats[0] = AV_PIX_FMT_OPENCL; + constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE; + + return 0; + +fail: + av_freep(&image_formats); + return err; +} + +static void opencl_pool_free(void *opaque, uint8_t *data) +{ + AVHWFramesContext *hwfc = opaque; + AVOpenCLFrameDescriptor *desc = (AVOpenCLFrameDescriptor*)data; + cl_int cle; + int p; + + for (p = 0; p < desc->nb_planes; p++) { + cle = clReleaseMemObject(desc->planes[p]); + if (cle != CL_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to release plane %d: " + "%d.\n", p, cle); + } + } + + av_free(desc); +} + +static AVBufferRef *opencl_pool_alloc(void *opaque, int size) +{ + AVHWFramesContext *hwfc = opaque; + AVOpenCLDeviceContext *hwctx = hwfc->device_ctx->hwctx; + AVOpenCLFrameDescriptor *desc; + cl_int cle; + cl_mem image; + cl_image_format image_format; + cl_image_desc image_desc; + int err, p; + AVBufferRef *ref; + + desc = av_mallocz(sizeof(*desc)); + if (!desc) + return NULL; + + for (p = 0;; p++) { + err = opencl_get_plane_format(hwfc->sw_format, p, + hwfc->width, hwfc->height, + &image_format, &image_desc); + if (err == AVERROR(ENOENT)) + break; + if (err < 0) + goto fail; + + // For generic image objects, the pitch is determined by the + // implementation. + image_desc.image_row_pitch = 0; + + image = clCreateImage(hwctx->context, CL_MEM_READ_WRITE, + &image_format, &image_desc, NULL, &cle); + if (!image) { + av_log(hwfc, AV_LOG_ERROR, "Failed to create image for " + "plane %d: %d.\n", p, cle); + goto fail; + } + + desc->planes[p] = image; + } + + desc->nb_planes = p; + + ref = av_buffer_create((uint8_t*)desc, sizeof(*desc), + &opencl_pool_free, hwfc, 0); + if (!ref) + goto fail; + + return ref; + +fail: + for (p = 0; desc->planes[p]; p++) + clReleaseMemObject(desc->planes[p]); + av_free(desc); + return NULL; +} + +static int opencl_frames_init_command_queue(AVHWFramesContext *hwfc) +{ + AVOpenCLFramesContext *hwctx = hwfc->hwctx; + OpenCLDeviceContext *devpriv = hwfc->device_ctx->internal->priv; + OpenCLFramesContext *priv = hwfc->internal->priv; + cl_int cle; + + priv->command_queue = hwctx->command_queue ? hwctx->command_queue + : devpriv->command_queue; + cle = clRetainCommandQueue(priv->command_queue); + if (cle != CL_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to retain frame " + "command queue: %d.\n", cle); + return AVERROR(EIO); + } + + return 0; +} + +static int opencl_frames_init(AVHWFramesContext *hwfc) +{ + if (!hwfc->pool) { + hwfc->internal->pool_internal = + av_buffer_pool_init2(sizeof(cl_mem), hwfc, + &opencl_pool_alloc, NULL); + if (!hwfc->internal->pool_internal) + return AVERROR(ENOMEM); + } + + return opencl_frames_init_command_queue(hwfc); +} + +static void opencl_frames_uninit(AVHWFramesContext *hwfc) +{ + OpenCLFramesContext *priv = hwfc->internal->priv; + cl_int cle; + +#if HAVE_OPENCL_DXVA2 || HAVE_OPENCL_D3D11 + int i, p; + for (i = 0; i < priv->nb_mapped_frames; i++) { + AVOpenCLFrameDescriptor *desc = &priv->mapped_frames[i]; + for (p = 0; p < desc->nb_planes; p++) { + cle = clReleaseMemObject(desc->planes[p]); + if (cle != CL_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to release mapped " + "frame object (frame %d plane %d): %d.\n", + i, p, cle); + } + } + } + av_freep(&priv->mapped_frames); +#endif + + cle = clReleaseCommandQueue(priv->command_queue); + if (cle != CL_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to release frame " + "command queue: %d.\n", cle); + } +} + +static int opencl_get_buffer(AVHWFramesContext *hwfc, AVFrame *frame) +{ + AVOpenCLFrameDescriptor *desc; + int p; + + frame->buf[0] = av_buffer_pool_get(hwfc->pool); + if (!frame->buf[0]) + return AVERROR(ENOMEM); + + desc = (AVOpenCLFrameDescriptor*)frame->buf[0]->data; + + for (p = 0; p < desc->nb_planes; p++) + frame->data[p] = (uint8_t*)desc->planes[p]; + + frame->format = AV_PIX_FMT_OPENCL; + frame->width = hwfc->width; + frame->height = hwfc->height; + + return 0; +} + +static int opencl_transfer_get_formats(AVHWFramesContext *hwfc, + enum AVHWFrameTransferDirection dir, + enum AVPixelFormat **formats) +{ + enum AVPixelFormat *fmts; + + fmts = av_malloc_array(2, sizeof(*fmts)); + if (!fmts) + return AVERROR(ENOMEM); + + fmts[0] = hwfc->sw_format; + fmts[1] = AV_PIX_FMT_NONE; + + *formats = fmts; + return 0; +} + +static int opencl_wait_events(AVHWFramesContext *hwfc, + cl_event *events, int nb_events) +{ + cl_int cle; + int i; + + cle = clWaitForEvents(nb_events, events); + if (cle != CL_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to wait for event " + "completion: %d.\n", cle); + return AVERROR(EIO); + } + + for (i = 0; i < nb_events; i++) { + cle = clReleaseEvent(events[i]); + if (cle != CL_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to release " + "event: %d.\n", cle); + } + } + + return 0; +} + +static int opencl_transfer_data_from(AVHWFramesContext *hwfc, + AVFrame *dst, const AVFrame *src) +{ + OpenCLFramesContext *priv = hwfc->internal->priv; + cl_image_format image_format; + cl_image_desc image_desc; + cl_int cle; + size_t origin[3] = { 0, 0, 0 }; + size_t region[3]; + cl_event events[AV_NUM_DATA_POINTERS]; + int err, p; + + if (dst->format != hwfc->sw_format) + return AVERROR(EINVAL); + + for (p = 0;; p++) { + err = opencl_get_plane_format(hwfc->sw_format, p, + src->width, src->height, + &image_format, &image_desc); + if (err < 0) { + if (err == AVERROR(ENOENT)) + err = 0; + break; + } + + if (!dst->data[p]) { + av_log(hwfc, AV_LOG_ERROR, "Plane %d missing on " + "destination frame for transfer.\n", p); + err = AVERROR(EINVAL); + break; + } + + region[0] = image_desc.image_width; + region[1] = image_desc.image_height; + region[2] = 1; + + cle = clEnqueueReadImage(priv->command_queue, + (cl_mem)src->data[p], + CL_FALSE, origin, region, + dst->linesize[p], 0, + dst->data[p], + 0, NULL, &events[p]); + if (cle != CL_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to enqueue read of " + "OpenCL image plane %d: %d.\n", p, cle); + err = AVERROR(EIO); + break; + } + } + + opencl_wait_events(hwfc, events, p); + + return err; +} + +static int opencl_transfer_data_to(AVHWFramesContext *hwfc, + AVFrame *dst, const AVFrame *src) +{ + OpenCLFramesContext *priv = hwfc->internal->priv; + cl_image_format image_format; + cl_image_desc image_desc; + cl_int cle; + size_t origin[3] = { 0, 0, 0 }; + size_t region[3]; + cl_event events[AV_NUM_DATA_POINTERS]; + int err, p; + + if (src->format != hwfc->sw_format) + return AVERROR(EINVAL); + + for (p = 0;; p++) { + err = opencl_get_plane_format(hwfc->sw_format, p, + src->width, src->height, + &image_format, &image_desc); + if (err < 0) { + if (err == AVERROR(ENOENT)) + err = 0; + break; + } + + if (!src->data[p]) { + av_log(hwfc, AV_LOG_ERROR, "Plane %d missing on " + "source frame for transfer.\n", p); + err = AVERROR(EINVAL); + break; + } + + region[0] = image_desc.image_width; + region[1] = image_desc.image_height; + region[2] = 1; + + cle = clEnqueueWriteImage(priv->command_queue, + (cl_mem)dst->data[p], + CL_FALSE, origin, region, + src->linesize[p], 0, + src->data[p], + 0, NULL, &events[p]); + if (cle != CL_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to enqueue write of " + "OpenCL image plane %d: %d.\n", p, cle); + err = AVERROR(EIO); + break; + } + } + + opencl_wait_events(hwfc, events, p); + + return err; +} + +typedef struct OpenCLMapping { + // The mapped addresses for each plane. + // The destination frame is not available when we unmap, so these + // need to be stored separately. + void *address[AV_NUM_DATA_POINTERS]; +} OpenCLMapping; + +static void opencl_unmap_frame(AVHWFramesContext *hwfc, + HWMapDescriptor *hwmap) +{ + OpenCLFramesContext *priv = hwfc->internal->priv; + OpenCLMapping *map = hwmap->priv; + cl_event events[AV_NUM_DATA_POINTERS]; + int p, e; + cl_int cle; + + for (p = e = 0; p < FF_ARRAY_ELEMS(map->address); p++) { + if (!map->address[p]) + break; + + cle = clEnqueueUnmapMemObject(priv->command_queue, + (cl_mem)hwmap->source->data[p], + map->address[p], + 0, NULL, &events[e]); + if (cle != CL_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to unmap OpenCL " + "image plane %d: %d.\n", p, cle); + } + ++e; + } + + opencl_wait_events(hwfc, events, e); + + av_free(map); +} + +static int opencl_map_frame(AVHWFramesContext *hwfc, AVFrame *dst, + const AVFrame *src, int flags) +{ + OpenCLFramesContext *priv = hwfc->internal->priv; + cl_map_flags map_flags; + cl_image_format image_format; + cl_image_desc image_desc; + cl_int cle; + OpenCLMapping *map; + size_t origin[3] = { 0, 0, 0 }; + size_t region[3]; + size_t row_pitch; + cl_event events[AV_NUM_DATA_POINTERS]; + int err, p; + + av_assert0(hwfc->sw_format == dst->format); + + if (flags & AV_HWFRAME_MAP_OVERWRITE && + !(flags & AV_HWFRAME_MAP_READ)) { + // This is mutually exclusive with the read/write flags, so + // there is no way to map with read here. + map_flags = CL_MAP_WRITE_INVALIDATE_REGION; + } else { + map_flags = 0; + if (flags & AV_HWFRAME_MAP_READ) + map_flags |= CL_MAP_READ; + if (flags & AV_HWFRAME_MAP_WRITE) + map_flags |= CL_MAP_WRITE; + } + + map = av_mallocz(sizeof(*map)); + if (!map) + return AVERROR(ENOMEM); + + for (p = 0;; p++) { + err = opencl_get_plane_format(hwfc->sw_format, p, + src->width, src->height, + &image_format, &image_desc); + if (err == AVERROR(ENOENT)) + break; + if (err < 0) + goto fail; + + region[0] = image_desc.image_width; + region[1] = image_desc.image_height; + region[2] = 1; + + map->address[p] = + clEnqueueMapImage(priv->command_queue, + (cl_mem)src->data[p], + CL_FALSE, map_flags, origin, region, + &row_pitch, NULL, 0, NULL, + &events[p], &cle); + if (!map->address[p]) { + av_log(hwfc, AV_LOG_ERROR, "Failed to map OpenCL " + "image plane %d: %d.\n", p, cle); + err = AVERROR(EIO); + goto fail; + } + + dst->data[p] = map->address[p]; + + av_log(hwfc, AV_LOG_DEBUG, "Map plane %d (%p -> %p).\n", + p, src->data[p], dst->data[p]); + } + + err = opencl_wait_events(hwfc, events, p); + if (err < 0) + goto fail; + + err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, + &opencl_unmap_frame, map); + if (err < 0) + goto fail; + + dst->width = src->width; + dst->height = src->height; + + return 0; + +fail: + for (p = 0; p < AV_NUM_DATA_POINTERS; p++) { + if (!map->address[p]) + break; + clEnqueueUnmapMemObject(priv->command_queue, + (cl_mem)src->data[p], + map->address[p], + 0, NULL, &events[p]); + } + if (p > 0) + opencl_wait_events(hwfc, events, p); + av_freep(&map); + return err; +} + +#if HAVE_OPENCL_DRM_BEIGNET + +typedef struct DRMBeignetToOpenCLMapping { + AVFrame *drm_frame; + AVDRMFrameDescriptor *drm_desc; + + AVOpenCLFrameDescriptor frame; +} DRMBeignetToOpenCLMapping; + +static void opencl_unmap_from_drm_beignet(AVHWFramesContext *dst_fc, + HWMapDescriptor *hwmap) +{ + DRMBeignetToOpenCLMapping *mapping = hwmap->priv; + cl_int cle; + int i; + + for (i = 0; i < mapping->frame.nb_planes; i++) { + cle = clReleaseMemObject(mapping->frame.planes[i]); + if (cle != CL_SUCCESS) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to release CL image " + "of plane %d of DRM frame: %d.\n", i, cle); + } + } + + av_free(mapping); +} + +static int opencl_map_from_drm_beignet(AVHWFramesContext *dst_fc, + AVFrame *dst, const AVFrame *src, + int flags) +{ + AVOpenCLDeviceContext *hwctx = dst_fc->device_ctx->hwctx; + OpenCLDeviceContext *priv = dst_fc->device_ctx->internal->priv; + DRMBeignetToOpenCLMapping *mapping; + const AVDRMFrameDescriptor *desc; + cl_int cle; + int err, i, j, p; + + desc = (const AVDRMFrameDescriptor*)src->data[0]; + + mapping = av_mallocz(sizeof(*mapping)); + if (!mapping) + return AVERROR(ENOMEM); + + p = 0; + for (i = 0; i < desc->nb_layers; i++) { + const AVDRMLayerDescriptor *layer = &desc->layers[i]; + for (j = 0; j < layer->nb_planes; j++) { + const AVDRMPlaneDescriptor *plane = &layer->planes[j]; + const AVDRMObjectDescriptor *object = + &desc->objects[plane->object_index]; + + cl_import_image_info_intel image_info = { + .fd = object->fd, + .size = object->size, + .type = CL_MEM_OBJECT_IMAGE2D, + .offset = plane->offset, + .row_pitch = plane->pitch, + }; + cl_image_desc image_desc; + + err = opencl_get_plane_format(dst_fc->sw_format, p, + src->width, src->height, + &image_info.fmt, + &image_desc); + if (err < 0) { + av_log(dst_fc, AV_LOG_ERROR, "DRM frame layer %d " + "plane %d is not representable in OpenCL: %d.\n", + i, j, err); + goto fail; + } + image_info.width = image_desc.image_width; + image_info.height = image_desc.image_height; + + mapping->frame.planes[p] = + priv->clCreateImageFromFdINTEL(hwctx->context, + &image_info, &cle); + if (!mapping->frame.planes[p]) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL image " + "from layer %d plane %d of DRM frame: %d.\n", + i, j, cle); + err = AVERROR(EIO); + goto fail; + } + + dst->data[p] = (uint8_t*)mapping->frame.planes[p]; + mapping->frame.nb_planes = ++p; + } + } + + err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src, + &opencl_unmap_from_drm_beignet, + mapping); + if (err < 0) + goto fail; + + dst->width = src->width; + dst->height = src->height; + + return 0; + +fail: + for (p = 0; p < mapping->frame.nb_planes; p++) { + if (mapping->frame.planes[p]) + clReleaseMemObject(mapping->frame.planes[p]); + } + av_free(mapping); + return err; +} + +#if HAVE_OPENCL_VAAPI_BEIGNET + +static int opencl_map_from_vaapi(AVHWFramesContext *dst_fc, + AVFrame *dst, const AVFrame *src, + int flags) +{ + HWMapDescriptor *hwmap; + AVFrame *tmp; + int err; + + tmp = av_frame_alloc(); + if (!tmp) + return AVERROR(ENOMEM); + + tmp->format = AV_PIX_FMT_DRM_PRIME; + + err = av_hwframe_map(tmp, src, flags); + if (err < 0) + goto fail; + + err = opencl_map_from_drm_beignet(dst_fc, dst, tmp, flags); + if (err < 0) + goto fail; + + // Adjust the map descriptor so that unmap works correctly. + hwmap = (HWMapDescriptor*)dst->buf[0]->data; + av_frame_unref(hwmap->source); + err = av_frame_ref(hwmap->source, src); + +fail: + av_frame_free(&tmp); + return err; +} + +#endif /* HAVE_OPENCL_VAAPI_BEIGNET */ +#endif /* HAVE_OPENCL_DRM_BEIGNET */ + +static inline cl_mem_flags opencl_mem_flags_for_mapping(int map_flags) +{ + if ((map_flags & AV_HWFRAME_MAP_READ) && + (map_flags & AV_HWFRAME_MAP_WRITE)) + return CL_MEM_READ_WRITE; + else if (map_flags & AV_HWFRAME_MAP_READ) + return CL_MEM_READ_ONLY; + else if (map_flags & AV_HWFRAME_MAP_WRITE) + return CL_MEM_WRITE_ONLY; + else + return 0; +} + +#if HAVE_OPENCL_VAAPI_INTEL_MEDIA + +static void opencl_unmap_from_qsv(AVHWFramesContext *dst_fc, + HWMapDescriptor *hwmap) +{ + AVOpenCLFrameDescriptor *desc = hwmap->priv; + OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv; + OpenCLFramesContext *frames_priv = dst_fc->internal->priv; + cl_event event; + cl_int cle; + int p; + + av_log(dst_fc, AV_LOG_DEBUG, "Unmap QSV/VAAPI surface from OpenCL.\n"); + + cle = device_priv->clEnqueueReleaseVA_APIMediaSurfacesINTEL( + frames_priv->command_queue, desc->nb_planes, desc->planes, + 0, NULL, &event); + if (cle != CL_SUCCESS) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to release surface " + "handles: %d.\n", cle); + } + + opencl_wait_events(dst_fc, &event, 1); + + for (p = 0; p < desc->nb_planes; p++) { + cle = clReleaseMemObject(desc->planes[p]); + if (cle != CL_SUCCESS) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to release CL " + "image of plane %d of QSV/VAAPI surface: %d\n", + p, cle); + } + } + + av_free(desc); +} + +static int opencl_map_from_qsv(AVHWFramesContext *dst_fc, AVFrame *dst, + const AVFrame *src, int flags) +{ + AVHWFramesContext *src_fc = + (AVHWFramesContext*)src->hw_frames_ctx->data; + AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx; + OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv; + OpenCLFramesContext *frames_priv = dst_fc->internal->priv; + AVOpenCLFrameDescriptor *desc; + VASurfaceID va_surface; + cl_mem_flags cl_flags; + cl_event event; + cl_int cle; + int err, p; + + if (src->format == AV_PIX_FMT_QSV) { + mfxFrameSurface1 *mfx_surface = (mfxFrameSurface1*)src->data[3]; + va_surface = *(VASurfaceID*)mfx_surface->Data.MemId; + } else if (src->format == AV_PIX_FMT_VAAPI) { + va_surface = (VASurfaceID)(uintptr_t)src->data[3]; + } else { + return AVERROR(ENOSYS); + } + + cl_flags = opencl_mem_flags_for_mapping(flags); + if (!cl_flags) + return AVERROR(EINVAL); + + av_log(src_fc, AV_LOG_DEBUG, "Map QSV/VAAPI surface %#x to " + "OpenCL.\n", va_surface); + + desc = av_mallocz(sizeof(*desc)); + if (!desc) + return AVERROR(ENOMEM); + + // The cl_intel_va_api_media_sharing extension only supports NV12 + // surfaces, so for now there are always exactly two planes. + desc->nb_planes = 2; + + for (p = 0; p < desc->nb_planes; p++) { + desc->planes[p] = + device_priv->clCreateFromVA_APIMediaSurfaceINTEL( + dst_dev->context, cl_flags, &va_surface, p, &cle); + if (!desc->planes[p]) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL " + "image from plane %d of QSV/VAAPI surface " + "%#x: %d.\n", p, va_surface, cle); + err = AVERROR(EIO); + goto fail; + } + + dst->data[p] = (uint8_t*)desc->planes[p]; + } + + cle = device_priv->clEnqueueAcquireVA_APIMediaSurfacesINTEL( + frames_priv->command_queue, desc->nb_planes, desc->planes, + 0, NULL, &event); + if (cle != CL_SUCCESS) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to acquire surface " + "handles: %d.\n", cle); + err = AVERROR(EIO); + goto fail; + } + + err = opencl_wait_events(dst_fc, &event, 1); + if (err < 0) + goto fail; + + err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src, + &opencl_unmap_from_qsv, desc); + if (err < 0) + goto fail; + + dst->width = src->width; + dst->height = src->height; + + return 0; + +fail: + for (p = 0; p < desc->nb_planes; p++) + if (desc->planes[p]) + clReleaseMemObject(desc->planes[p]); + av_freep(&desc); + return err; +} + +#endif + +#if HAVE_OPENCL_DXVA2 + +static void opencl_unmap_from_dxva2(AVHWFramesContext *dst_fc, + HWMapDescriptor *hwmap) +{ + AVOpenCLFrameDescriptor *desc = hwmap->priv; + OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv; + OpenCLFramesContext *frames_priv = dst_fc->device_ctx->internal->priv; + cl_event event; + cl_int cle; + + av_log(dst_fc, AV_LOG_DEBUG, "Unmap DXVA2 surface from OpenCL.\n"); + + cle = device_priv->clEnqueueReleaseDX9MediaSurfacesKHR( + frames_priv->command_queue, desc->nb_planes, desc->planes, + 0, NULL, &event); + if (cle != CL_SUCCESS) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to release surface " + "handle: %d.\n", cle); + return; + } + + opencl_wait_events(dst_fc, &event, 1); +} + +static int opencl_map_from_dxva2(AVHWFramesContext *dst_fc, AVFrame *dst, + const AVFrame *src, int flags) +{ + AVHWFramesContext *src_fc = + (AVHWFramesContext*)src->hw_frames_ctx->data; + AVDXVA2FramesContext *src_hwctx = src_fc->hwctx; + OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv; + OpenCLFramesContext *frames_priv = dst_fc->internal->priv; + AVOpenCLFrameDescriptor *desc; + cl_event event; + cl_int cle; + int err, i; + + av_log(dst_fc, AV_LOG_DEBUG, "Map DXVA2 surface %p to " + "OpenCL.\n", src->data[3]); + + for (i = 0; i < src_hwctx->nb_surfaces; i++) { + if (src_hwctx->surfaces[i] == (IDirect3DSurface9*)src->data[3]) + break; + } + if (i >= src_hwctx->nb_surfaces) { + av_log(dst_fc, AV_LOG_ERROR, "Trying to map from a surface which " + "is not in the mapped frames context.\n"); + return AVERROR(EINVAL); + } + + desc = &frames_priv->mapped_frames[i]; + + cle = device_priv->clEnqueueAcquireDX9MediaSurfacesKHR( + frames_priv->command_queue, desc->nb_planes, desc->planes, + 0, NULL, &event); + if (cle != CL_SUCCESS) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to acquire surface " + "handle: %d.\n", cle); + return AVERROR(EIO); + } + + err = opencl_wait_events(dst_fc, &event, 1); + if (err < 0) + goto fail; + + for (i = 0; i < desc->nb_planes; i++) + dst->data[i] = (uint8_t*)desc->planes[i]; + + err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src, + &opencl_unmap_from_dxva2, desc); + if (err < 0) + goto fail; + + dst->width = src->width; + dst->height = src->height; + + return 0; + +fail: + cle = device_priv->clEnqueueReleaseDX9MediaSurfacesKHR( + frames_priv->command_queue, desc->nb_planes, desc->planes, + 0, NULL, &event); + if (cle == CL_SUCCESS) + opencl_wait_events(dst_fc, &event, 1); + return err; +} + +static int opencl_frames_derive_from_dxva2(AVHWFramesContext *dst_fc, + AVHWFramesContext *src_fc, int flags) +{ + AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx; + AVDXVA2FramesContext *src_hwctx = src_fc->hwctx; + OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv; + OpenCLFramesContext *frames_priv = dst_fc->internal->priv; + cl_mem_flags cl_flags; + cl_int cle; + int err, i, p, nb_planes; + + if (src_fc->sw_format != AV_PIX_FMT_NV12) { + av_log(dst_fc, AV_LOG_ERROR, "Only NV12 textures are supported " + "for DXVA2 to OpenCL mapping.\n"); + return AVERROR(EINVAL); + } + nb_planes = 2; + + if (src_fc->initial_pool_size == 0) { + av_log(dst_fc, AV_LOG_ERROR, "Only fixed-size pools are supported " + "for DXVA2 to OpenCL mapping.\n"); + return AVERROR(EINVAL); + } + + cl_flags = opencl_mem_flags_for_mapping(flags); + if (!cl_flags) + return AVERROR(EINVAL); + + frames_priv->nb_mapped_frames = src_hwctx->nb_surfaces; + + frames_priv->mapped_frames = + av_mallocz_array(frames_priv->nb_mapped_frames, + sizeof(*frames_priv->mapped_frames)); + if (!frames_priv->mapped_frames) + return AVERROR(ENOMEM); + + for (i = 0; i < frames_priv->nb_mapped_frames; i++) { + AVOpenCLFrameDescriptor *desc = &frames_priv->mapped_frames[i]; + cl_dx9_surface_info_khr surface_info = { + .resource = src_hwctx->surfaces[i], + .shared_handle = NULL, + }; + desc->nb_planes = nb_planes; + for (p = 0; p < nb_planes; p++) { + desc->planes[p] = + device_priv->clCreateFromDX9MediaSurfaceKHR( + dst_dev->context, cl_flags, + device_priv->dx9_media_adapter_type, + &surface_info, p, &cle); + if (!desc->planes[p]) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL " + "image from plane %d of DXVA2 surface %d: %d.\n", + p, i, cle); + err = AVERROR(EIO); + goto fail; + } + } + } + + return 0; + +fail: + for (i = 0; i < frames_priv->nb_mapped_frames; i++) { + AVOpenCLFrameDescriptor *desc = &frames_priv->mapped_frames[i]; + for (p = 0; p < desc->nb_planes; p++) { + if (desc->planes[p]) + clReleaseMemObject(desc->planes[p]); + } + } + av_freep(&frames_priv->mapped_frames); + frames_priv->nb_mapped_frames = 0; + return err; +} + +#endif + +#if HAVE_OPENCL_D3D11 + +static void opencl_unmap_from_d3d11(AVHWFramesContext *dst_fc, + HWMapDescriptor *hwmap) +{ + AVOpenCLFrameDescriptor *desc = hwmap->priv; + OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv; + OpenCLFramesContext *frames_priv = dst_fc->device_ctx->internal->priv; + cl_event event; + cl_int cle; + + cle = device_priv->clEnqueueReleaseD3D11ObjectsKHR( + frames_priv->command_queue, desc->nb_planes, desc->planes, + 0, NULL, &event); + if (cle != CL_SUCCESS) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to release surface " + "handle: %d.\n", cle); + } + + opencl_wait_events(dst_fc, &event, 1); +} + +static int opencl_map_from_d3d11(AVHWFramesContext *dst_fc, AVFrame *dst, + const AVFrame *src, int flags) +{ + OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv; + OpenCLFramesContext *frames_priv = dst_fc->internal->priv; + AVOpenCLFrameDescriptor *desc; + cl_event event; + cl_int cle; + int err, index, i; + + index = (intptr_t)src->data[1]; + if (index >= frames_priv->nb_mapped_frames) { + av_log(dst_fc, AV_LOG_ERROR, "Texture array index out of range for " + "mapping: %d >= %d.\n", index, frames_priv->nb_mapped_frames); + return AVERROR(EINVAL); + } + + av_log(dst_fc, AV_LOG_DEBUG, "Map D3D11 texture %d to OpenCL.\n", + index); + + desc = &frames_priv->mapped_frames[index]; + + cle = device_priv->clEnqueueAcquireD3D11ObjectsKHR( + frames_priv->command_queue, desc->nb_planes, desc->planes, + 0, NULL, &event); + if (cle != CL_SUCCESS) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to acquire surface " + "handle: %d.\n", cle); + return AVERROR(EIO); + } + + err = opencl_wait_events(dst_fc, &event, 1); + if (err < 0) + goto fail; + + for (i = 0; i < desc->nb_planes; i++) + dst->data[i] = (uint8_t*)desc->planes[i]; + + err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src, + &opencl_unmap_from_d3d11, desc); + if (err < 0) + goto fail; + + dst->width = src->width; + dst->height = src->height; + + return 0; + +fail: + cle = device_priv->clEnqueueReleaseD3D11ObjectsKHR( + frames_priv->command_queue, desc->nb_planes, desc->planes, + 0, NULL, &event); + if (cle == CL_SUCCESS) + opencl_wait_events(dst_fc, &event, 1); + return err; +} + +static int opencl_frames_derive_from_d3d11(AVHWFramesContext *dst_fc, + AVHWFramesContext *src_fc, int flags) +{ + AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx; + AVD3D11VAFramesContext *src_hwctx = src_fc->hwctx; + OpenCLDeviceContext *device_priv = dst_fc->device_ctx->internal->priv; + OpenCLFramesContext *frames_priv = dst_fc->internal->priv; + cl_mem_flags cl_flags; + cl_int cle; + int err, i, p, nb_planes; + + if (src_fc->sw_format != AV_PIX_FMT_NV12) { + av_log(dst_fc, AV_LOG_ERROR, "Only NV12 textures are supported " + "for D3D11 to OpenCL mapping.\n"); + return AVERROR(EINVAL); + } + nb_planes = 2; + + if (src_fc->initial_pool_size == 0) { + av_log(dst_fc, AV_LOG_ERROR, "Only fixed-size pools are supported " + "for D3D11 to OpenCL mapping.\n"); + return AVERROR(EINVAL); + } + + cl_flags = opencl_mem_flags_for_mapping(flags); + if (!cl_flags) + return AVERROR(EINVAL); + + frames_priv->nb_mapped_frames = src_fc->initial_pool_size; + + frames_priv->mapped_frames = + av_mallocz_array(frames_priv->nb_mapped_frames, + sizeof(*frames_priv->mapped_frames)); + if (!frames_priv->mapped_frames) + return AVERROR(ENOMEM); + + for (i = 0; i < frames_priv->nb_mapped_frames; i++) { + AVOpenCLFrameDescriptor *desc = &frames_priv->mapped_frames[i]; + desc->nb_planes = nb_planes; + for (p = 0; p < nb_planes; p++) { + UINT subresource = 2 * i + p; + + desc->planes[p] = + device_priv->clCreateFromD3D11Texture2DKHR( + dst_dev->context, cl_flags, src_hwctx->texture, + subresource, &cle); + if (!desc->planes[p]) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL " + "image from plane %d of D3D texture " + "index %d (subresource %u): %d.\n", + p, i, (unsigned int)subresource, cle); + err = AVERROR(EIO); + goto fail; + } + } + } + + return 0; + +fail: + for (i = 0; i < frames_priv->nb_mapped_frames; i++) { + AVOpenCLFrameDescriptor *desc = &frames_priv->mapped_frames[i]; + for (p = 0; p < desc->nb_planes; p++) { + if (desc->planes[p]) + clReleaseMemObject(desc->planes[p]); + } + } + av_freep(&frames_priv->mapped_frames); + frames_priv->nb_mapped_frames = 0; + return err; +} + +#endif + +#if HAVE_OPENCL_DRM_ARM + +typedef struct DRMARMtoOpenCLMapping { + int nb_objects; + cl_mem object_buffers[AV_DRM_MAX_PLANES]; + int nb_planes; + cl_mem plane_images[AV_DRM_MAX_PLANES]; +} DRMARMtoOpenCLMapping; + +static void opencl_unmap_from_drm_arm(AVHWFramesContext *dst_fc, + HWMapDescriptor *hwmap) +{ + DRMARMtoOpenCLMapping *mapping = hwmap->priv; + int i; + + for (i = 0; i < mapping->nb_planes; i++) + clReleaseMemObject(mapping->plane_images[i]); + + for (i = 0; i < mapping->nb_objects; i++) + clReleaseMemObject(mapping->object_buffers[i]); + + av_free(mapping); +} + +static int opencl_map_from_drm_arm(AVHWFramesContext *dst_fc, AVFrame *dst, + const AVFrame *src, int flags) +{ + AVHWFramesContext *src_fc = + (AVHWFramesContext*)src->hw_frames_ctx->data; + AVOpenCLDeviceContext *dst_dev = dst_fc->device_ctx->hwctx; + const AVDRMFrameDescriptor *desc; + DRMARMtoOpenCLMapping *mapping = NULL; + cl_mem_flags cl_flags; + const cl_import_properties_arm props[3] = { + CL_IMPORT_TYPE_ARM, CL_IMPORT_TYPE_DMA_BUF_ARM, 0, + }; + cl_int cle; + int err, i, j; + + desc = (const AVDRMFrameDescriptor*)src->data[0]; + + cl_flags = opencl_mem_flags_for_mapping(flags); + if (!cl_flags) + return AVERROR(EINVAL); + + mapping = av_mallocz(sizeof(*mapping)); + if (!mapping) + return AVERROR(ENOMEM); + + mapping->nb_objects = desc->nb_objects; + for (i = 0; i < desc->nb_objects; i++) { + int fd = desc->objects[i].fd; + + av_log(dst_fc, AV_LOG_DEBUG, "Map DRM PRIME fd %d to OpenCL.\n", fd); + + if (desc->objects[i].format_modifier) { + av_log(dst_fc, AV_LOG_DEBUG, "Warning: object %d fd %d has " + "nonzero format modifier %"PRId64", result may not " + "be as expected.\n", i, fd, + desc->objects[i].format_modifier); + } + + mapping->object_buffers[i] = + clImportMemoryARM(dst_dev->context, cl_flags, props, + &fd, desc->objects[i].size, &cle); + if (!mapping->object_buffers[i]) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to create CL buffer " + "from object %d (fd %d, size %"SIZE_SPECIFIER") of DRM frame: %d.\n", + i, fd, desc->objects[i].size, cle); + err = AVERROR(EIO); + goto fail; + } + } + + mapping->nb_planes = 0; + for (i = 0; i < desc->nb_layers; i++) { + const AVDRMLayerDescriptor *layer = &desc->layers[i]; + + for (j = 0; j < layer->nb_planes; j++) { + const AVDRMPlaneDescriptor *plane = &layer->planes[j]; + cl_mem plane_buffer; + cl_image_format image_format; + cl_image_desc image_desc; + cl_buffer_region region; + int p = mapping->nb_planes; + + err = opencl_get_plane_format(src_fc->sw_format, p, + src_fc->width, src_fc->height, + &image_format, &image_desc); + if (err < 0) { + av_log(dst_fc, AV_LOG_ERROR, "Invalid plane %d (DRM " + "layer %d plane %d): %d.\n", p, i, j, err); + goto fail; + } + + region.origin = plane->offset; + region.size = image_desc.image_row_pitch * + image_desc.image_height; + + plane_buffer = + clCreateSubBuffer(mapping->object_buffers[plane->object_index], + cl_flags, + CL_BUFFER_CREATE_TYPE_REGION, + ®ion, &cle); + if (!plane_buffer) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to create sub-buffer " + "for plane %d: %d.\n", p, cle); + err = AVERROR(EIO); + goto fail; + } + + image_desc.buffer = plane_buffer; + + mapping->plane_images[p] = + clCreateImage(dst_dev->context, cl_flags, + &image_format, &image_desc, NULL, &cle); + + // Unreference the sub-buffer immediately - we don't need it + // directly and a reference is held by the image. + clReleaseMemObject(plane_buffer); + + if (!mapping->plane_images[p]) { + av_log(dst_fc, AV_LOG_ERROR, "Failed to create image " + "for plane %d: %d.\n", p, cle); + err = AVERROR(EIO); + goto fail; + } + + ++mapping->nb_planes; + } + } + + for (i = 0; i < mapping->nb_planes; i++) + dst->data[i] = (uint8_t*)mapping->plane_images[i]; + + err = ff_hwframe_map_create(dst->hw_frames_ctx, dst, src, + &opencl_unmap_from_drm_arm, mapping); + if (err < 0) + goto fail; + + dst->width = src->width; + dst->height = src->height; + + return 0; + +fail: + for (i = 0; i < mapping->nb_planes; i++) { + clReleaseMemObject(mapping->plane_images[i]); + } + for (i = 0; i < mapping->nb_objects; i++) { + if (mapping->object_buffers[i]) + clReleaseMemObject(mapping->object_buffers[i]); + } + av_free(mapping); + return err; +} + +#endif + +static int opencl_map_from(AVHWFramesContext *hwfc, AVFrame *dst, + const AVFrame *src, int flags) +{ + av_assert0(src->format == AV_PIX_FMT_OPENCL); + if (hwfc->sw_format != dst->format) + return AVERROR(ENOSYS); + return opencl_map_frame(hwfc, dst, src, flags); +} + +static int opencl_map_to(AVHWFramesContext *hwfc, AVFrame *dst, + const AVFrame *src, int flags) +{ + OpenCLDeviceContext *priv = hwfc->device_ctx->internal->priv; + av_assert0(dst->format == AV_PIX_FMT_OPENCL); + switch (src->format) { +#if HAVE_OPENCL_DRM_BEIGNET + case AV_PIX_FMT_DRM_PRIME: + if (priv->beignet_drm_mapping_usable) + return opencl_map_from_drm_beignet(hwfc, dst, src, flags); +#endif +#if HAVE_OPENCL_VAAPI_BEIGNET + case AV_PIX_FMT_VAAPI: + if (priv->beignet_drm_mapping_usable) + return opencl_map_from_vaapi(hwfc, dst, src, flags); +#endif +#if HAVE_OPENCL_VAAPI_INTEL_MEDIA + case AV_PIX_FMT_QSV: + case AV_PIX_FMT_VAAPI: + if (priv->qsv_mapping_usable) + return opencl_map_from_qsv(hwfc, dst, src, flags); +#endif +#if HAVE_OPENCL_DXVA2 + case AV_PIX_FMT_DXVA2_VLD: + if (priv->dxva2_mapping_usable) + return opencl_map_from_dxva2(hwfc, dst, src, flags); +#endif +#if HAVE_OPENCL_D3D11 + case AV_PIX_FMT_D3D11: + if (priv->d3d11_mapping_usable) + return opencl_map_from_d3d11(hwfc, dst, src, flags); +#endif +#if HAVE_OPENCL_DRM_ARM + case AV_PIX_FMT_DRM_PRIME: + if (priv->drm_arm_mapping_usable) + return opencl_map_from_drm_arm(hwfc, dst, src, flags); +#endif + } + return AVERROR(ENOSYS); +} + +static int opencl_frames_derive_to(AVHWFramesContext *dst_fc, + AVHWFramesContext *src_fc, int flags) +{ + OpenCLDeviceContext *priv = dst_fc->device_ctx->internal->priv; + switch (src_fc->device_ctx->type) { +#if HAVE_OPENCL_DRM_BEIGNET + case AV_HWDEVICE_TYPE_DRM: + if (!priv->beignet_drm_mapping_usable) + return AVERROR(ENOSYS); + break; +#endif +#if HAVE_OPENCL_VAAPI_BEIGNET + case AV_HWDEVICE_TYPE_VAAPI: + if (!priv->beignet_drm_mapping_usable) + return AVERROR(ENOSYS); + break; +#endif +#if HAVE_OPENCL_VAAPI_INTEL_MEDIA + case AV_HWDEVICE_TYPE_QSV: + case AV_HWDEVICE_TYPE_VAAPI: + if (!priv->qsv_mapping_usable) + return AVERROR(ENOSYS); + break; +#endif +#if HAVE_OPENCL_DXVA2 + case AV_HWDEVICE_TYPE_DXVA2: + if (!priv->dxva2_mapping_usable) + return AVERROR(ENOSYS); + { + int err; + err = opencl_frames_derive_from_dxva2(dst_fc, src_fc, flags); + if (err < 0) + return err; + } + break; +#endif +#if HAVE_OPENCL_D3D11 + case AV_HWDEVICE_TYPE_D3D11VA: + if (!priv->d3d11_mapping_usable) + return AVERROR(ENOSYS); + { + int err; + err = opencl_frames_derive_from_d3d11(dst_fc, src_fc, flags); + if (err < 0) + return err; + } + break; +#endif +#if HAVE_OPENCL_DRM_ARM + case AV_HWDEVICE_TYPE_DRM: + if (!priv->drm_arm_mapping_usable) + return AVERROR(ENOSYS); + break; +#endif + default: + return AVERROR(ENOSYS); + } + return opencl_frames_init_command_queue(dst_fc); +} + +const HWContextType ff_hwcontext_type_opencl = { + .type = AV_HWDEVICE_TYPE_OPENCL, + .name = "OpenCL", + + .device_hwctx_size = sizeof(AVOpenCLDeviceContext), + .device_priv_size = sizeof(OpenCLDeviceContext), + .frames_hwctx_size = sizeof(AVOpenCLFramesContext), + .frames_priv_size = sizeof(OpenCLFramesContext), + + .device_create = &opencl_device_create, + .device_derive = &opencl_device_derive, + .device_init = &opencl_device_init, + .device_uninit = &opencl_device_uninit, + + .frames_get_constraints = &opencl_frames_get_constraints, + .frames_init = &opencl_frames_init, + .frames_uninit = &opencl_frames_uninit, + .frames_get_buffer = &opencl_get_buffer, + + .transfer_get_formats = &opencl_transfer_get_formats, + .transfer_data_to = &opencl_transfer_data_to, + .transfer_data_from = &opencl_transfer_data_from, + + .map_from = &opencl_map_from, + .map_to = &opencl_map_to, + .frames_derive_to = &opencl_frames_derive_to, + + .pix_fmts = (const enum AVPixelFormat[]) { + AV_PIX_FMT_OPENCL, + AV_PIX_FMT_NONE + }, +}; diff --git a/libavutil/hwcontext_opencl.h b/libavutil/hwcontext_opencl.h new file mode 100644 index 0000000000000..ef54486c95f00 --- /dev/null +++ b/libavutil/hwcontext_opencl.h @@ -0,0 +1,100 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_HWCONTEXT_OPENCL_H +#define AVUTIL_HWCONTEXT_OPENCL_H + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#include "frame.h" + +/** + * @file + * API-specific header for AV_HWDEVICE_TYPE_OPENCL. + * + * Pools allocated internally are always dynamic, and are primarily intended + * to be used in OpenCL-only cases. If interoperation is required, it is + * typically required to allocate frames in the other API and then map the + * frames context to OpenCL with av_hwframe_ctx_create_derived(). + */ + +/** + * OpenCL frame descriptor for pool allocation. + * + * In user-allocated pools, AVHWFramesContext.pool must return AVBufferRefs + * with the data pointer pointing at an object of this type describing the + * planes of the frame. + */ +typedef struct AVOpenCLFrameDescriptor { + /** + * Number of planes in the frame. + */ + int nb_planes; + /** + * OpenCL image2d objects for each plane of the frame. + */ + cl_mem planes[AV_NUM_DATA_POINTERS]; +} AVOpenCLFrameDescriptor; + +/** + * OpenCL device details. + * + * Allocated as AVHWDeviceContext.hwctx + */ +typedef struct AVOpenCLDeviceContext { + /** + * The primary device ID of the device. If multiple OpenCL devices + * are associated with the context then this is the one which will + * be used for all operations internal to FFmpeg. + */ + cl_device_id device_id; + /** + * The OpenCL context which will contain all operations and frames on + * this device. + */ + cl_context context; + /** + * The default command queue for this device, which will be used by all + * frames contexts which do not have their own command queue. If not + * intialised by the user, a default queue will be created on the + * primary device. + */ + cl_command_queue command_queue; +} AVOpenCLDeviceContext; + +/** + * OpenCL-specific data associated with a frame pool. + * + * Allocated as AVHWFramesContext.hwctx. + */ +typedef struct AVOpenCLFramesContext { + /** + * The command queue used for internal asynchronous operations on this + * device (av_hwframe_transfer_data(), av_hwframe_map()). + * + * If this is not set, the command queue from the associated device is + * used instead. + */ + cl_command_queue command_queue; +} AVOpenCLFramesContext; + +#endif /* AVUTIL_HWCONTEXT_OPENCL_H */ diff --git a/libavutil/hwcontext_qsv.c b/libavutil/hwcontext_qsv.c index f1d16d8bf92c6..250091c4e85a2 100644 --- a/libavutil/hwcontext_qsv.c +++ b/libavutil/hwcontext_qsv.c @@ -234,8 +234,8 @@ static int qsv_init_child_ctx(AVHWFramesContext *ctx) child_frames_ctx->format = device_priv->child_pix_fmt; child_frames_ctx->sw_format = ctx->sw_format; child_frames_ctx->initial_pool_size = ctx->initial_pool_size; - child_frames_ctx->width = ctx->width; - child_frames_ctx->height = ctx->height; + child_frames_ctx->width = FFALIGN(ctx->width, 16); + child_frames_ctx->height = FFALIGN(ctx->height, 16); #if CONFIG_DXVA2 if (child_device_ctx->type == AV_HWDEVICE_TYPE_DXVA2) { @@ -307,12 +307,13 @@ static int qsv_init_surface(AVHWFramesContext *ctx, mfxFrameSurface1 *surf) surf->Info.ChromaFormat = MFX_CHROMAFORMAT_YUV444; surf->Info.FourCC = fourcc; - surf->Info.Width = ctx->width; + surf->Info.Width = FFALIGN(ctx->width, 16); surf->Info.CropW = ctx->width; - surf->Info.Height = ctx->height; + surf->Info.Height = FFALIGN(ctx->height, 16); surf->Info.CropH = ctx->height; surf->Info.FrameRateExtN = 25; surf->Info.FrameRateExtD = 1; + surf->Info.PicStruct = MFX_PICSTRUCT_PROGRESSIVE; return 0; } @@ -989,7 +990,6 @@ static int qsv_device_derive_from_child(AVHWDeviceContext *ctx, int flags) { AVQSVDeviceContext *hwctx = ctx->hwctx; - QSVDeviceContext *s = ctx->internal->priv; mfxVersion ver = { { 3, 1 } }; mfxHDL handle; @@ -1029,6 +1029,27 @@ static int qsv_device_derive_from_child(AVHWDeviceContext *ctx, goto fail; } + err = MFXQueryVersion(hwctx->session, &ver); + if (err != MFX_ERR_NONE) { + av_log(ctx, AV_LOG_ERROR, "Error querying an MFX session: %d.\n", err); + ret = AVERROR_UNKNOWN; + goto fail; + } + + av_log(ctx, AV_LOG_VERBOSE, + "Initialize MFX session: API version is %d.%d, implementation version is %d.%d\n", + MFX_VERSION_MAJOR, MFX_VERSION_MINOR, ver.Major, ver.Minor); + + MFXClose(hwctx->session); + + err = MFXInit(implementation, &ver, &hwctx->session); + if (err != MFX_ERR_NONE) { + av_log(ctx, AV_LOG_ERROR, + "Error initializing an MFX session: %d.\n", err); + ret = AVERROR_UNKNOWN; + goto fail; + } + err = MFXVideoCORE_SetHandle(hwctx->session, handle_type, handle); if (err != MFX_ERR_NONE) { av_log(ctx, AV_LOG_ERROR, "Error setting child device handle: " @@ -1037,6 +1058,11 @@ static int qsv_device_derive_from_child(AVHWDeviceContext *ctx, goto fail; } + ret = MFXQueryVersion(hwctx->session,&ver); + if (ret == MFX_ERR_NONE) { + av_log(ctx, AV_LOG_VERBOSE, "MFX compile/runtime API: %d.%d/%d.%d\n", + MFX_VERSION_MAJOR, MFX_VERSION_MINOR, ver.Major, ver.Minor); + } return 0; fail: diff --git a/libavutil/hwcontext_vaapi.c b/libavutil/hwcontext_vaapi.c index 40a85d288c6a9..53a5b02822efd 100644 --- a/libavutil/hwcontext_vaapi.c +++ b/libavutil/hwcontext_vaapi.c @@ -28,6 +28,9 @@ #if CONFIG_LIBDRM # include # include +# ifndef DRM_FORMAT_MOD_INVALID +# define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1) +# endif #endif #include @@ -40,15 +43,13 @@ #include "buffer.h" #include "common.h" #include "hwcontext.h" +#include "hwcontext_drm.h" #include "hwcontext_internal.h" #include "hwcontext_vaapi.h" #include "mem.h" #include "pixdesc.h" #include "pixfmt.h" -#if CONFIG_LIBDRM -# include "hwcontext_drm.h" -#endif typedef struct VAAPIDevicePriv { #if HAVE_VAAPI_X11 @@ -101,13 +102,18 @@ static const struct { MAP(NV12, YUV420, NV12), MAP(YV12, YUV420, YUV420P), // With U/V planes swapped. MAP(IYUV, YUV420, YUV420P), - //MAP(I420, YUV420, YUV420P), // Not in libva but used by Intel driver. +#ifdef VA_FOURCC_I420 + MAP(I420, YUV420, YUV420P), +#endif #ifdef VA_FOURCC_YV16 MAP(YV16, YUV422, YUV422P), // With U/V planes swapped. #endif MAP(422H, YUV422, YUV422P), MAP(UYVY, YUV422, UYVY422), MAP(YUY2, YUV422, YUYV422), + MAP(411P, YUV411, YUV411P), + MAP(422V, YUV422, YUV440P), + MAP(444P, YUV444, YUV444P), MAP(Y800, YUV400, GRAY8), #ifdef VA_FOURCC_P010 MAP(P010, YUV420_10BPP, P010), @@ -470,9 +476,9 @@ static int vaapi_frames_init(AVHWFramesContext *hwfc) int need_memory_type = !(hwctx->driver_quirks & AV_VAAPI_DRIVER_QUIRK_ATTRIB_MEMTYPE); int need_pixel_format = 1; for (i = 0; i < avfc->nb_attributes; i++) { - if (ctx->attributes[i].type == VASurfaceAttribMemoryType) + if (avfc->attributes[i].type == VASurfaceAttribMemoryType) need_memory_type = 0; - if (ctx->attributes[i].type == VASurfaceAttribPixelFormat) + if (avfc->attributes[i].type == VASurfaceAttribPixelFormat) need_pixel_format = 0; } ctx->nb_attributes = @@ -625,24 +631,31 @@ static int vaapi_transfer_get_formats(AVHWFramesContext *hwfc, enum AVPixelFormat **formats) { VAAPIDeviceContext *ctx = hwfc->device_ctx->internal->priv; - enum AVPixelFormat *pix_fmts, preferred_format; - int i, k; + enum AVPixelFormat *pix_fmts; + int i, k, sw_format_available; - preferred_format = hwfc->sw_format; + sw_format_available = 0; + for (i = 0; i < ctx->nb_formats; i++) { + if (ctx->formats[i].pix_fmt == hwfc->sw_format) + sw_format_available = 1; + } pix_fmts = av_malloc((ctx->nb_formats + 1) * sizeof(*pix_fmts)); if (!pix_fmts) return AVERROR(ENOMEM); - pix_fmts[0] = preferred_format; - k = 1; + if (sw_format_available) { + pix_fmts[0] = hwfc->sw_format; + k = 1; + } else { + k = 0; + } for (i = 0; i < ctx->nb_formats; i++) { - if (ctx->formats[i].pix_fmt == preferred_format) + if (ctx->formats[i].pix_fmt == hwfc->sw_format) continue; av_assert0(k < ctx->nb_formats); pix_fmts[k++] = ctx->formats[i].pix_fmt; } - av_assert0(k == ctx->nb_formats); pix_fmts[k] = AV_PIX_FMT_NONE; *formats = pix_fmts; @@ -1061,8 +1074,9 @@ static int vaapi_map_from_drm(AVHWFramesContext *src_fc, AVFrame *dst, return 0; } -static void vaapi_unmap_to_drm(AVHWFramesContext *dst_fc, - HWMapDescriptor *hwmap) +#if VA_CHECK_VERSION(1, 1, 0) +static void vaapi_unmap_to_drm_esh(AVHWFramesContext *hwfc, + HWMapDescriptor *hwmap) { AVDRMFrameDescriptor *drm_desc = hwmap->priv; int i; @@ -1073,24 +1087,28 @@ static void vaapi_unmap_to_drm(AVHWFramesContext *dst_fc, av_freep(&drm_desc); } -static int vaapi_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst, - const AVFrame *src, int flags) +static int vaapi_map_to_drm_esh(AVHWFramesContext *hwfc, AVFrame *dst, + const AVFrame *src, int flags) { -#if CONFIG_VAAPI_1 AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; VASurfaceID surface_id; VAStatus vas; VADRMPRIMESurfaceDescriptor va_desc; AVDRMFrameDescriptor *drm_desc = NULL; + uint32_t export_flags; int err, i, j; surface_id = (VASurfaceID)(uintptr_t)src->data[3]; + export_flags = VA_EXPORT_SURFACE_SEPARATE_LAYERS; + if (flags & AV_HWFRAME_MAP_READ) + export_flags |= VA_EXPORT_SURFACE_READ_ONLY; + if (flags & AV_HWFRAME_MAP_WRITE) + export_flags |= VA_EXPORT_SURFACE_WRITE_ONLY; + vas = vaExportSurfaceHandle(hwctx->display, surface_id, VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2, - VA_EXPORT_SURFACE_READ_ONLY | - VA_EXPORT_SURFACE_SEPARATE_LAYERS, - &va_desc); + export_flags, &va_desc); if (vas != VA_STATUS_SUCCESS) { if (vas == VA_STATUS_ERROR_UNIMPLEMENTED) return AVERROR(ENOSYS); @@ -1128,7 +1146,7 @@ static int vaapi_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst, } err = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, - &vaapi_unmap_to_drm, drm_desc); + &vaapi_unmap_to_drm_esh, drm_desc); if (err < 0) goto fail; @@ -1143,15 +1161,182 @@ static int vaapi_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst, close(va_desc.objects[i].fd); av_freep(&drm_desc); return err; -#else - // Older versions without vaExportSurfaceHandle() are not supported - - // in theory this is possible with a combination of vaDeriveImage() - // and vaAcquireBufferHandle(), but it doesn't carry enough metadata - // to actually use the result in a generic way. - return AVERROR(ENOSYS); +} #endif + +typedef struct VAAPIDRMImageBufferMapping { + VAImage image; + VABufferInfo buffer_info; + + AVDRMFrameDescriptor drm_desc; +} VAAPIDRMImageBufferMapping; + +static void vaapi_unmap_to_drm_abh(AVHWFramesContext *hwfc, + HWMapDescriptor *hwmap) +{ + AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; + VAAPIDRMImageBufferMapping *mapping = hwmap->priv; + VASurfaceID surface_id; + VAStatus vas; + + surface_id = (VASurfaceID)(uintptr_t)hwmap->source->data[3]; + av_log(hwfc, AV_LOG_DEBUG, "Unmap VAAPI surface %#x from DRM.\n", + surface_id); + + // DRM PRIME file descriptors are closed by vaReleaseBufferHandle(), + // so we shouldn't close them separately. + + vas = vaReleaseBufferHandle(hwctx->display, mapping->image.buf); + if (vas != VA_STATUS_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to release buffer " + "handle of image %#x (derived from surface %#x): " + "%d (%s).\n", mapping->image.buf, surface_id, + vas, vaErrorStr(vas)); + } + + vas = vaDestroyImage(hwctx->display, mapping->image.image_id); + if (vas != VA_STATUS_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to destroy image " + "derived from surface %#x: %d (%s).\n", + surface_id, vas, vaErrorStr(vas)); + } + + av_free(mapping); } + +static int vaapi_map_to_drm_abh(AVHWFramesContext *hwfc, AVFrame *dst, + const AVFrame *src, int flags) +{ + AVVAAPIDeviceContext *hwctx = hwfc->device_ctx->hwctx; + VAAPIDRMImageBufferMapping *mapping = NULL; + VASurfaceID surface_id; + VAStatus vas; + int err, i, p; + + surface_id = (VASurfaceID)(uintptr_t)src->data[3]; + av_log(hwfc, AV_LOG_DEBUG, "Map VAAPI surface %#x to DRM.\n", + surface_id); + + mapping = av_mallocz(sizeof(*mapping)); + if (!mapping) + return AVERROR(ENOMEM); + + vas = vaDeriveImage(hwctx->display, surface_id, + &mapping->image); + if (vas != VA_STATUS_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to derive image from " + "surface %#x: %d (%s).\n", + surface_id, vas, vaErrorStr(vas)); + err = AVERROR(EIO); + goto fail; + } + + for (i = 0; i < FF_ARRAY_ELEMS(vaapi_drm_format_map); i++) { + if (vaapi_drm_format_map[i].va_fourcc == + mapping->image.format.fourcc) + break; + } + if (i >= FF_ARRAY_ELEMS(vaapi_drm_format_map)) { + av_log(hwfc, AV_LOG_ERROR, "No matching DRM format for " + "VAAPI format %#x.\n", mapping->image.format.fourcc); + err = AVERROR(EINVAL); + goto fail_derived; + } + + mapping->buffer_info.mem_type = + VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME; + + mapping->drm_desc.nb_layers = + vaapi_drm_format_map[i].nb_layer_formats; + if (mapping->drm_desc.nb_layers > 1) { + if (mapping->drm_desc.nb_layers != mapping->image.num_planes) { + av_log(hwfc, AV_LOG_ERROR, "Image properties do not match " + "expected format: got %d planes, but expected %d.\n", + mapping->image.num_planes, mapping->drm_desc.nb_layers); + err = AVERROR(EINVAL); + goto fail_derived; + } + + for(p = 0; p < mapping->drm_desc.nb_layers; p++) { + mapping->drm_desc.layers[p] = (AVDRMLayerDescriptor) { + .format = vaapi_drm_format_map[i].layer_formats[p], + .nb_planes = 1, + .planes[0] = { + .object_index = 0, + .offset = mapping->image.offsets[p], + .pitch = mapping->image.pitches[p], + }, + }; + } + } else { + mapping->drm_desc.layers[0].format = + vaapi_drm_format_map[i].layer_formats[0]; + mapping->drm_desc.layers[0].nb_planes = mapping->image.num_planes; + for (p = 0; p < mapping->image.num_planes; p++) { + mapping->drm_desc.layers[0].planes[p] = (AVDRMPlaneDescriptor) { + .object_index = 0, + .offset = mapping->image.offsets[p], + .pitch = mapping->image.pitches[p], + }; + } + } + + vas = vaAcquireBufferHandle(hwctx->display, mapping->image.buf, + &mapping->buffer_info); + if (vas != VA_STATUS_SUCCESS) { + av_log(hwfc, AV_LOG_ERROR, "Failed to get buffer " + "handle from image %#x (derived from surface %#x): " + "%d (%s).\n", mapping->image.buf, surface_id, + vas, vaErrorStr(vas)); + err = AVERROR(EIO); + goto fail_derived; + } + + av_log(hwfc, AV_LOG_DEBUG, "DRM PRIME fd is %ld.\n", + mapping->buffer_info.handle); + + mapping->drm_desc.nb_objects = 1; + mapping->drm_desc.objects[0] = (AVDRMObjectDescriptor) { + .fd = mapping->buffer_info.handle, + .size = mapping->image.data_size, + // There is no way to get the format modifier with this API. + .format_modifier = DRM_FORMAT_MOD_INVALID, + }; + + err = ff_hwframe_map_create(src->hw_frames_ctx, + dst, src, &vaapi_unmap_to_drm_abh, + mapping); + if (err < 0) + goto fail_mapped; + + dst->data[0] = (uint8_t*)&mapping->drm_desc; + dst->width = src->width; + dst->height = src->height; + + return 0; + +fail_mapped: + vaReleaseBufferHandle(hwctx->display, mapping->image.buf); +fail_derived: + vaDestroyImage(hwctx->display, mapping->image.image_id); +fail: + av_freep(&mapping); + return err; +} + +static int vaapi_map_to_drm(AVHWFramesContext *hwfc, AVFrame *dst, + const AVFrame *src, int flags) +{ +#if VA_CHECK_VERSION(1, 1, 0) + int err; + err = vaapi_map_to_drm_esh(hwfc, dst, src, flags); + if (err != AVERROR(ENOSYS)) + return err; #endif + return vaapi_map_to_drm_abh(hwfc, dst, src, flags); +} + +#endif /* CONFIG_LIBDRM */ static int vaapi_map_to(AVHWFramesContext *hwfc, AVFrame *dst, const AVFrame *src, int flags) @@ -1312,7 +1497,7 @@ static int vaapi_device_create(AVHWDeviceContext *ctx, const char *device, static int vaapi_device_derive(AVHWDeviceContext *ctx, AVHWDeviceContext *src_ctx, int flags) { -#if CONFIG_LIBDRM +#if HAVE_VAAPI_DRM if (src_ctx->type == AV_HWDEVICE_TYPE_DRM) { AVDRMDeviceContext *src_hwctx = src_ctx->hwctx; VADisplay *display; diff --git a/libavutil/hwcontext_vdpau.c b/libavutil/hwcontext_vdpau.c index 9b8f83964740e..c11c3cfdab25e 100644 --- a/libavutil/hwcontext_vdpau.c +++ b/libavutil/hwcontext_vdpau.c @@ -79,11 +79,12 @@ static const VDPAUPixFmtMap pix_fmts_444[] = { static const struct { VdpChromaType chroma_type; + enum AVPixelFormat frames_sw_format; const VDPAUPixFmtMap *map; } vdpau_pix_fmts[] = { - { VDP_CHROMA_TYPE_420, pix_fmts_420 }, - { VDP_CHROMA_TYPE_422, pix_fmts_422 }, - { VDP_CHROMA_TYPE_444, pix_fmts_444 }, + { VDP_CHROMA_TYPE_420, AV_PIX_FMT_YUV420P, pix_fmts_420 }, + { VDP_CHROMA_TYPE_422, AV_PIX_FMT_YUV422P, pix_fmts_422 }, + { VDP_CHROMA_TYPE_444, AV_PIX_FMT_YUV444P, pix_fmts_444 }, }; static int count_pixfmts(const VDPAUPixFmtMap *map) @@ -170,6 +171,35 @@ static void vdpau_device_uninit(AVHWDeviceContext *ctx) av_freep(&priv->pix_fmts[i]); } +static int vdpau_frames_get_constraints(AVHWDeviceContext *ctx, + const void *hwconfig, + AVHWFramesConstraints *constraints) +{ + VDPAUDeviceContext *priv = ctx->internal->priv; + int nb_sw_formats = 0; + int i; + + constraints->valid_sw_formats = av_malloc_array(FF_ARRAY_ELEMS(vdpau_pix_fmts) + 1, + sizeof(*constraints->valid_sw_formats)); + if (!constraints->valid_sw_formats) + return AVERROR(ENOMEM); + + for (i = 0; i < FF_ARRAY_ELEMS(vdpau_pix_fmts); i++) { + if (priv->nb_pix_fmts[i] > 1) + constraints->valid_sw_formats[nb_sw_formats++] = vdpau_pix_fmts[i].frames_sw_format; + } + constraints->valid_sw_formats[nb_sw_formats] = AV_PIX_FMT_NONE; + + constraints->valid_hw_formats = av_malloc_array(2, sizeof(*constraints->valid_hw_formats)); + if (!constraints->valid_hw_formats) + return AVERROR(ENOMEM); + + constraints->valid_hw_formats[0] = AV_PIX_FMT_VDPAU; + constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE; + + return 0; +} + static void vdpau_buffer_free(void *opaque, uint8_t *data) { AVHWFramesContext *ctx = opaque; @@ -214,26 +244,18 @@ static int vdpau_frames_init(AVHWFramesContext *ctx) int i; - switch (ctx->sw_format) { - case AV_PIX_FMT_YUV420P: priv->chroma_type = VDP_CHROMA_TYPE_420; break; - case AV_PIX_FMT_YUV422P: priv->chroma_type = VDP_CHROMA_TYPE_422; break; - case AV_PIX_FMT_YUV444P: priv->chroma_type = VDP_CHROMA_TYPE_444; break; - default: - av_log(ctx, AV_LOG_ERROR, "Unsupported data layout: %s\n", - av_get_pix_fmt_name(ctx->sw_format)); - return AVERROR(ENOSYS); - } - for (i = 0; i < FF_ARRAY_ELEMS(vdpau_pix_fmts); i++) { - if (vdpau_pix_fmts[i].chroma_type == priv->chroma_type) { + if (vdpau_pix_fmts[i].frames_sw_format == ctx->sw_format) { + priv->chroma_type = vdpau_pix_fmts[i].chroma_type; priv->chroma_idx = i; priv->pix_fmts = device_priv->pix_fmts[i]; priv->nb_pix_fmts = device_priv->nb_pix_fmts[i]; break; } } - if (!priv->pix_fmts) { - av_log(ctx, AV_LOG_ERROR, "Unsupported chroma type: %d\n", priv->chroma_type); + if (priv->nb_pix_fmts < 2) { + av_log(ctx, AV_LOG_ERROR, "Unsupported sw format: %s\n", + av_get_pix_fmt_name(ctx->sw_format)); return AVERROR(ENOSYS); } @@ -468,6 +490,7 @@ const HWContextType ff_hwcontext_type_vdpau = { #endif .device_init = vdpau_device_init, .device_uninit = vdpau_device_uninit, + .frames_get_constraints = vdpau_frames_get_constraints, .frames_init = vdpau_frames_init, .frames_get_buffer = vdpau_get_buffer, .transfer_get_formats = vdpau_transfer_get_formats, diff --git a/libavutil/imgutils.c b/libavutil/imgutils.c index 50051788041d1..4938a7ef6767f 100644 --- a/libavutil/imgutils.c +++ b/libavutil/imgutils.c @@ -125,7 +125,7 @@ int av_image_fill_pointers(uint8_t *data[4], enum AVPixelFormat pix_fmt, int hei size[0] = linesizes[0] * height; if (desc->flags & AV_PIX_FMT_FLAG_PAL || - desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) { + desc->flags & FF_PSEUDOPAL) { data[1] = ptr + size[0]; /* palette is stored here as 256 32 bits words */ return size[0] + 256 * 4; } @@ -216,7 +216,7 @@ int av_image_alloc(uint8_t *pointers[4], int linesizes[4], av_free(buf); return ret; } - if (desc->flags & AV_PIX_FMT_FLAG_PAL || desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) { + if (desc->flags & AV_PIX_FMT_FLAG_PAL || (desc->flags & FF_PSEUDOPAL && pointers[1])) { avpriv_set_systematic_pal2((uint32_t*)pointers[1], pix_fmt); if (align < 4) { av_log(NULL, AV_LOG_ERROR, "Formats with a palette require a minimum alignment of 4\n"); @@ -225,7 +225,7 @@ int av_image_alloc(uint8_t *pointers[4], int linesizes[4], } if ((desc->flags & AV_PIX_FMT_FLAG_PAL || - desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) && + desc->flags & FF_PSEUDOPAL) && pointers[1] && pointers[1] - pointers[0] > linesizes[0] * h) { /* zero-initialize the padding before the palette */ memset(pointers[0] + linesizes[0] * h, 0, @@ -242,9 +242,10 @@ typedef struct ImgUtils { } ImgUtils; static const AVClass imgutils_class = { - .class_name = "IMGUTILS", - .item_name = av_default_item_name, - .version = LIBAVUTIL_VERSION_INT, + .class_name = "IMGUTILS", + .item_name = av_default_item_name, + .option = NULL, + .version = LIBAVUTIL_VERSION_INT, .log_level_offset_offset = offsetof(ImgUtils, log_offset), .parent_log_context_offset = offsetof(ImgUtils, log_ctx), }; @@ -353,12 +354,13 @@ static void image_copy(uint8_t *dst_data[4], const ptrdiff_t dst_linesizes[4], return; if (desc->flags & AV_PIX_FMT_FLAG_PAL || - desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) { + desc->flags & FF_PSEUDOPAL) { 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); + if ((desc->flags & AV_PIX_FMT_FLAG_PAL) || (dst_data[1] && src_data[1])) + memcpy(dst_data[1], src_data[1], 4*256); } else { int i, planes_nb = 0; @@ -441,7 +443,7 @@ int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, return ret; // do not include palette for these pseudo-paletted formats - if (desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL) + if (desc->flags & FF_PSEUDOPAL) return FFALIGN(width, align) * height; return av_image_fill_arrays(data, linesize, NULL, pix_fmt, diff --git a/libavutil/integer.c b/libavutil/integer.c index 6d6855fa1b9e3..890e314dced6d 100644 --- a/libavutil/integer.c +++ b/libavutil/integer.c @@ -164,41 +164,3 @@ int64_t av_i2int(AVInteger a){ } return out; } - -#ifdef TEST - -const uint8_t ff_log2_tab[256]={ - 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 -}; - -int main(void){ - int64_t a,b; - - for(a=7; a<256*256*256; a+=13215){ - for(b=3; b<256*256*256; b+=27118){ - AVInteger ai= av_int2i(a); - AVInteger bi= av_int2i(b); - - av_assert0(av_i2int(ai) == a); - av_assert0(av_i2int(bi) == b); - av_assert0(av_i2int(av_add_i(ai,bi)) == a+b); - av_assert0(av_i2int(av_sub_i(ai,bi)) == a-b); - av_assert0(av_i2int(av_mul_i(ai,bi)) == a*b); - av_assert0(av_i2int(av_shr_i(ai, 9)) == a>>9); - av_assert0(av_i2int(av_shr_i(ai,-9)) == a<<9); - av_assert0(av_i2int(av_shr_i(ai, 17)) == a>>17); - av_assert0(av_i2int(av_shr_i(ai,-17)) == a<<17); - av_assert0(av_log2_i(ai) == av_log2(a)); - av_assert0(av_i2int(av_div_i(ai,bi)) == a/b); - } - } - return 0; -} -#endif diff --git a/libavutil/internal.h b/libavutil/internal.h index a2d73e3cc6c63..06bd561e82c0c 100644 --- a/libavutil/internal.h +++ b/libavutil/internal.h @@ -43,6 +43,7 @@ #include "cpu.h" #include "dict.h" #include "macros.h" +#include "mem.h" #include "pixfmt.h" #include "version.h" @@ -62,10 +63,10 @@ #endif #endif -#if defined(_MSC_VER) && CONFIG_SHARED -# define av_export __declspec(dllimport) +#if defined(_WIN32) && CONFIG_SHARED && !defined(BUILDING_avutil) +# define av_export_avutil __declspec(dllimport) #else -# define av_export +# define av_export_avutil #endif #if HAVE_PRAGMA_DEPRECATED @@ -76,8 +77,8 @@ # define FF_DISABLE_DEPRECATION_WARNINGS __pragma(warning(push)) __pragma(warning(disable:4996)) # define FF_ENABLE_DEPRECATION_WARNINGS __pragma(warning(pop)) # else -# define FF_DISABLE_DEPRECATION_WARNINGS _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") -# define FF_ENABLE_DEPRECATION_WARNINGS _Pragma("GCC diagnostic warning \"-Wdeprecated-declarations\"") +# define FF_DISABLE_DEPRECATION_WARNINGS _Pragma("GCC diagnostic push") _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +# define FF_ENABLE_DEPRECATION_WARNINGS _Pragma("GCC diagnostic pop") # endif #else # define FF_DISABLE_DEPRECATION_WARNINGS @@ -110,24 +111,30 @@ DECLARE_ALIGNED(a, t, la_##v) s o; \ t (*v) o = la_##v -#define LOCAL_ALIGNED(a, t, v, ...) E1(LOCAL_ALIGNED_A(a, t, v, __VA_ARGS__,,)) +#define LOCAL_ALIGNED(a, t, v, ...) LOCAL_ALIGNED_##a(t, v, __VA_ARGS__) -#if HAVE_LOCAL_ALIGNED_8 +#if HAVE_LOCAL_ALIGNED +# define LOCAL_ALIGNED_4(t, v, ...) E1(LOCAL_ALIGNED_D(4, t, v, __VA_ARGS__,,)) +#else +# define LOCAL_ALIGNED_4(t, v, ...) E1(LOCAL_ALIGNED_A(4, t, v, __VA_ARGS__,,)) +#endif + +#if HAVE_LOCAL_ALIGNED # define LOCAL_ALIGNED_8(t, v, ...) E1(LOCAL_ALIGNED_D(8, t, v, __VA_ARGS__,,)) #else -# define LOCAL_ALIGNED_8(t, v, ...) LOCAL_ALIGNED(8, t, v, __VA_ARGS__) +# define LOCAL_ALIGNED_8(t, v, ...) E1(LOCAL_ALIGNED_A(8, t, v, __VA_ARGS__,,)) #endif -#if HAVE_LOCAL_ALIGNED_16 +#if HAVE_LOCAL_ALIGNED # define LOCAL_ALIGNED_16(t, v, ...) E1(LOCAL_ALIGNED_D(16, t, v, __VA_ARGS__,,)) #else -# define LOCAL_ALIGNED_16(t, v, ...) LOCAL_ALIGNED(16, t, v, __VA_ARGS__) +# define LOCAL_ALIGNED_16(t, v, ...) E1(LOCAL_ALIGNED_A(16, t, v, __VA_ARGS__,,)) #endif -#if HAVE_LOCAL_ALIGNED_32 +#if HAVE_LOCAL_ALIGNED # define LOCAL_ALIGNED_32(t, v, ...) E1(LOCAL_ALIGNED_D(32, t, v, __VA_ARGS__,,)) #else -# define LOCAL_ALIGNED_32(t, v, ...) LOCAL_ALIGNED(32, t, v, __VA_ARGS__) +# define LOCAL_ALIGNED_32(t, v, ...) E1(LOCAL_ALIGNED_A(32, t, v, __VA_ARGS__,,)) #endif #define FF_ALLOC_OR_GOTO(ctx, p, size, label)\ @@ -353,4 +360,13 @@ void ff_check_pixfmt_descriptors(void); */ int avpriv_dict_set_timestamp(AVDictionary **dict, const char *key, int64_t timestamp); +// Helper macro for AV_PIX_FMT_FLAG_PSEUDOPAL deprecation. Code inside FFmpeg +// should always use FF_PSEUDOPAL. Once the public API flag gets removed, all +// code using it is dead code. +#if FF_API_PSEUDOPAL +#define FF_PSEUDOPAL AV_PIX_FMT_FLAG_PSEUDOPAL +#else +#define FF_PSEUDOPAL 0 +#endif + #endif /* AVUTIL_INTERNAL_H */ diff --git a/libavutil/intreadwrite.h b/libavutil/intreadwrite.h index d54d4b91d6ce9..67c763b135cce 100644 --- a/libavutil/intreadwrite.h +++ b/libavutil/intreadwrite.h @@ -215,7 +215,7 @@ typedef union { * by per-arch headers. */ -#if defined(__GNUC__) && !defined(__TI_COMPILER_VERSION__) +#if defined(__GNUC__) union unaligned_64 { uint64_t l; } __attribute__((packed)) av_alias; union unaligned_32 { uint32_t l; } __attribute__((packed)) av_alias; @@ -224,12 +224,7 @@ union unaligned_16 { uint16_t l; } __attribute__((packed)) av_alias; # define AV_RN(s, p) (((const union unaligned_##s *) (p))->l) # define AV_WN(s, p, v) ((((union unaligned_##s *) (p))->l) = (v)) -#elif defined(__DECC) - -# define AV_RN(s, p) (*((const __unaligned uint##s##_t*)(p))) -# define AV_WN(s, p, v) (*((__unaligned uint##s##_t*)(p)) = (v)) - -#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_X64)) && AV_HAVE_FAST_UNALIGNED +#elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_X64) || defined(_M_ARM64)) && AV_HAVE_FAST_UNALIGNED # define AV_RN(s, p) (*((const __unaligned uint##s##_t*)(p))) # define AV_WN(s, p, v) (*((__unaligned uint##s##_t*)(p)) = (v)) diff --git a/libavutil/log.c b/libavutil/log.c index be806202ffbb8..9b7d48487f6ff 100644 --- a/libavutil/log.c +++ b/libavutil/log.c @@ -39,11 +39,9 @@ #include "common.h" #include "internal.h" #include "log.h" +#include "thread.h" -#if HAVE_PTHREADS -#include -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -#endif +static AVMutex mutex = AV_MUTEX_INITIALIZER; #define LINE_SZ 1024 @@ -57,7 +55,7 @@ static int av_log_level = AV_LOG_INFO; static int flags; #define NB_LEVELS 8 -#if defined(_WIN32) && !defined(__MINGW32CE__) && HAVE_SETCONSOLETEXTATTRIBUTE +#if defined(_WIN32) && HAVE_SETCONSOLETEXTATTRIBUTE #include static const uint8_t color[16 + AV_CLASS_CATEGORY_NB] = { [AV_LOG_PANIC /8] = 12, @@ -124,7 +122,7 @@ static int use_color = -1; static void check_color_terminal(void) { -#if defined(_WIN32) && !defined(__MINGW32CE__) && HAVE_SETCONSOLETEXTATTRIBUTE +#if defined(_WIN32) && HAVE_SETCONSOLETEXTATTRIBUTE CONSOLE_SCREEN_BUFFER_INFO con_info; con = GetStdHandle(STD_ERROR_HANDLE); use_color = (con != INVALID_HANDLE_VALUE) && !getenv("NO_COLOR") && @@ -159,7 +157,7 @@ static void colored_fputs(int level, int tint, const char *str) if (level == AV_LOG_INFO/8) local_use_color = 0; else local_use_color = use_color; -#if defined(_WIN32) && !defined(__MINGW32CE__) && HAVE_SETCONSOLETEXTATTRIBUTE +#if defined(_WIN32) && HAVE_SETCONSOLETEXTATTRIBUTE if (local_use_color) SetConsoleTextAttribute(con, background | color[level]); fputs(str, stderr); @@ -268,11 +266,11 @@ static void format_line(void *avcl, int level, const char *fmt, va_list vl, av_bprintf(part+1, "[%s @ %p] ", avc->item_name(avcl), avcl); if(type) type[1] = get_category(avcl); - - if (flags & AV_LOG_PRINT_LEVEL) - av_bprintf(part+2, "[%s] ", get_level_str(level)); } + if (*print_prefix && (level > AV_LOG_QUIET) && (flags & AV_LOG_PRINT_LEVEL)) + av_bprintf(part+2, "[%s] ", get_level_str(level)); + av_vbprintf(part+3, fmt, vl); if(*part[0].str || *part[1].str || *part[2].str || *part[3].str) { @@ -317,9 +315,7 @@ void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl) if (level > av_log_level) return; -#if HAVE_PTHREADS - pthread_mutex_lock(&mutex); -#endif + ff_mutex_lock(&mutex); format_line(ptr, level, fmt, vl, part, &print_prefix, type); snprintf(line, sizeof(line), "%s%s%s%s", part[0].str, part[1].str, part[2].str, part[3].str); @@ -356,9 +352,7 @@ void av_log_default_callback(void* ptr, int level, const char* fmt, va_list vl) #endif end: av_bprint_finalize(part+3, NULL); -#if HAVE_PTHREADS - pthread_mutex_unlock(&mutex); -#endif + ff_mutex_unlock(&mutex); } static void (*av_log_callback)(void*, int, const char*, va_list) = diff --git a/libavutil/log.h b/libavutil/log.h index f0a57385dfe37..d9554e609d400 100644 --- a/libavutil/log.h +++ b/libavutil/log.h @@ -334,20 +334,6 @@ void av_log_format_line(void *ptr, int level, const char *fmt, va_list vl, int av_log_format_line2(void *ptr, int level, const char *fmt, va_list vl, char *line, int line_size, int *print_prefix); -#if FF_API_DLOG -/** - * av_dlog macros - * @deprecated unused - * Useful to print debug messages that shouldn't get compiled in normally. - */ - -#ifdef DEBUG -# define av_dlog(pctx, ...) av_log(pctx, AV_LOG_DEBUG, __VA_ARGS__) -#else -# define av_dlog(pctx, ...) do { if (0) av_log(pctx, AV_LOG_DEBUG, __VA_ARGS__); } while (0) -#endif -#endif /* FF_API_DLOG */ - /** * Skip repeated messages, this requires the user app to use av_log() instead of * (f)printf as the 2 would otherwise interfere and lead to diff --git a/libavutil/mastering_display_metadata.h b/libavutil/mastering_display_metadata.h index 847b0b62c6cf5..c23b07c3cd80d 100644 --- a/libavutil/mastering_display_metadata.h +++ b/libavutil/mastering_display_metadata.h @@ -1,4 +1,4 @@ -/** +/* * Copyright (c) 2016 Neil Birkbeck * * This file is part of FFmpeg. diff --git a/libavutil/mem.c b/libavutil/mem.c index 36740f1154bf2..6149755a6b88e 100644 --- a/libavutil/mem.c +++ b/libavutil/mem.c @@ -61,7 +61,7 @@ void free(void *ptr); #include "mem_internal.h" -#define ALIGN (HAVE_AVX ? 32 : 16) +#define ALIGN (HAVE_AVX512 ? 64 : (HAVE_AVX ? 32 : 16)) /* NOTE: if you want to override these functions with your own * implementations (not recommended) you have to link libav* as @@ -181,6 +181,20 @@ int av_reallocp(void *ptr, size_t size) return 0; } +void *av_malloc_array(size_t nmemb, size_t size) +{ + if (!size || nmemb >= INT_MAX / size) + return NULL; + return av_malloc(nmemb * size); +} + +void *av_mallocz_array(size_t nmemb, size_t size) +{ + if (!size || nmemb >= INT_MAX / size) + return NULL; + return av_mallocz(nmemb * size); +} + void *av_realloc_array(void *ptr, size_t nmemb, size_t size) { if (!size || nmemb >= INT_MAX / size) @@ -449,10 +463,15 @@ void av_memcpy_backptr(uint8_t *dst, int back, int cnt) void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size) { - if (min_size < *size) + if (min_size <= *size) return ptr; - min_size = FFMAX(min_size + min_size / 16 + 32, min_size); + if (min_size > max_alloc_size - 32) { + *size = 0; + return NULL; + } + + min_size = FFMIN(max_alloc_size - 32, FFMAX(min_size + min_size / 16 + 32, min_size)); ptr = av_realloc(ptr, min_size); /* we could set this to the unmodified min_size but this is safer diff --git a/libavutil/mem.h b/libavutil/mem.h index 527cd03191a90..7e0b12a8a782c 100644 --- a/libavutil/mem.h +++ b/libavutil/mem.h @@ -73,6 +73,19 @@ * @param v Name of the variable */ +/** + * @def DECLARE_ASM_ALIGNED(n,t,v) + * Declare an aligned variable appropriate for use in inline assembly code. + * + * @code{.c} + * DECLARE_ASM_ALIGNED(16, uint64_t, pw_08) = UINT64_C(0x0008000800080008); + * @endcode + * + * @param n Minimum alignment in bytes + * @param t Type of the variable (or array element) + * @param v Name of the variable + */ + /** * @def DECLARE_ASM_CONST(n,t,v) * Declare a static constant aligned variable appropriate for use in inline @@ -89,25 +102,23 @@ #if defined(__INTEL_COMPILER) && __INTEL_COMPILER < 1110 || defined(__SUNPRO_C) #define DECLARE_ALIGNED(n,t,v) t __attribute__ ((aligned (n))) v + #define DECLARE_ASM_ALIGNED(n,t,v) t __attribute__ ((aligned (n))) v #define DECLARE_ASM_CONST(n,t,v) const t __attribute__ ((aligned (n))) v -#elif defined(__TI_COMPILER_VERSION__) - #define DECLARE_ALIGNED(n,t,v) \ - AV_PRAGMA(DATA_ALIGN(v,n)) \ - t __attribute__((aligned(n))) v - #define DECLARE_ASM_CONST(n,t,v) \ - AV_PRAGMA(DATA_ALIGN(v,n)) \ - static const t __attribute__((aligned(n))) v #elif defined(__DJGPP__) #define DECLARE_ALIGNED(n,t,v) t __attribute__ ((aligned (FFMIN(n, 16)))) v + #define DECLARE_ASM_ALIGNED(n,t,v) t av_used __attribute__ ((aligned (FFMIN(n, 16)))) v #define DECLARE_ASM_CONST(n,t,v) static const t av_used __attribute__ ((aligned (FFMIN(n, 16)))) v #elif defined(__GNUC__) || defined(__clang__) #define DECLARE_ALIGNED(n,t,v) t __attribute__ ((aligned (n))) v + #define DECLARE_ASM_ALIGNED(n,t,v) t av_used __attribute__ ((aligned (n))) v #define DECLARE_ASM_CONST(n,t,v) static const t av_used __attribute__ ((aligned (n))) v #elif defined(_MSC_VER) #define DECLARE_ALIGNED(n,t,v) __declspec(align(n)) t v + #define DECLARE_ASM_ALIGNED(n,t,v) __declspec(align(n)) t v #define DECLARE_ASM_CONST(n,t,v) __declspec(align(n)) static const t v #else #define DECLARE_ALIGNED(n,t,v) t v + #define DECLARE_ASM_ALIGNED(n,t,v) t v #define DECLARE_ASM_CONST(n,t,v) static const t v #endif @@ -206,12 +217,7 @@ void *av_mallocz(size_t size) av_malloc_attrib av_alloc_size(1); * be allocated * @see av_malloc() */ -av_alloc_size(1, 2) static inline void *av_malloc_array(size_t nmemb, size_t size) -{ - if (!size || nmemb >= INT_MAX / size) - return NULL; - return av_malloc(nmemb * size); -} +av_alloc_size(1, 2) void *av_malloc_array(size_t nmemb, size_t size); /** * Allocate a memory block for an array with av_mallocz(). @@ -226,12 +232,7 @@ av_alloc_size(1, 2) static inline void *av_malloc_array(size_t nmemb, size_t siz * @see av_mallocz() * @see av_malloc_array() */ -av_alloc_size(1, 2) static inline void *av_mallocz_array(size_t nmemb, size_t size) -{ - if (!size || nmemb >= INT_MAX / size) - return NULL; - return av_mallocz(nmemb * size); -} +av_alloc_size(1, 2) void *av_mallocz_array(size_t nmemb, size_t size); /** * Non-inlined equivalent of av_mallocz_array(). diff --git a/libavutil/mips/generic_macros_msa.h b/libavutil/mips/generic_macros_msa.h index c892529f05ac7..6a467046631f4 100644 --- a/libavutil/mips/generic_macros_msa.h +++ b/libavutil/mips/generic_macros_msa.h @@ -1088,6 +1088,25 @@ out_m; \ } ) +#define CLIP_SW_0_255_MAX_SATU(in) \ +( { \ + v4i32 out_m; \ + \ + out_m = __msa_maxi_s_w((v4i32) in, 0); \ + out_m = (v4i32) __msa_sat_u_w((v4u32) out_m, 7); \ + out_m; \ +} ) +#define CLIP_SW2_0_255_MAX_SATU(in0, in1) \ +{ \ + in0 = CLIP_SW_0_255_MAX_SATU(in0); \ + in1 = CLIP_SW_0_255_MAX_SATU(in1); \ +} +#define CLIP_SW4_0_255_MAX_SATU(in0, in1, in2, in3) \ +{ \ + CLIP_SW2_0_255_MAX_SATU(in0, in1); \ + CLIP_SW2_0_255_MAX_SATU(in2, in3); \ +} + /* Description : Addition of 4 signed word elements 4 signed word elements of input vector are added together and resulted integer sum is returned @@ -2244,6 +2263,22 @@ out3 = in6 - in7; \ } +/* Description : Sign extend byte elements from right half of the vector + Arguments : Input - in (byte vector) + Output - out (sign extended halfword vector) + Return Type - signed halfword + Details : Sign bit of byte elements from input vector 'in' is + extracted and interleaved with same vector 'in' to generate + 8 halfword elements keeping sign intact +*/ +#define UNPCK_R_SB_SH(in, out) \ +{ \ + v16i8 sign_m; \ + \ + sign_m = __msa_clti_s_b((v16i8) in, 0); \ + out = (v8i16) __msa_ilvr_b(sign_m, (v16i8) in); \ +} + /* Description : Sign extend halfword elements from right half of the vector Arguments : Inputs - in (input halfword vector) Outputs - out (sign extended word vectors) diff --git a/libavutil/murmur3.c b/libavutil/murmur3.c index 4271e01453f77..7961752515692 100644 --- a/libavutil/murmur3.c +++ b/libavutil/murmur3.c @@ -60,7 +60,7 @@ static uint64_t inline get_k1(const uint8_t *src) return k; } -static uint64_t inline get_k2(const uint8_t *src) +static inline uint64_t get_k2(const uint8_t *src) { uint64_t k = AV_RL64(src + 8); k *= c2; @@ -69,7 +69,7 @@ static uint64_t inline get_k2(const uint8_t *src) return k; } -static uint64_t inline update_h1(uint64_t k, uint64_t h1, uint64_t h2) +static inline uint64_t update_h1(uint64_t k, uint64_t h1, uint64_t h2) { k ^= h1; k = ROT(k, 27); @@ -79,7 +79,7 @@ static uint64_t inline update_h1(uint64_t k, uint64_t h1, uint64_t h2) return k; } -static uint64_t inline update_h2(uint64_t k, uint64_t h1, uint64_t h2) +static inline uint64_t update_h2(uint64_t k, uint64_t h1, uint64_t h2) { k ^= h2; k = ROT(k, 31); @@ -89,7 +89,11 @@ static uint64_t inline update_h2(uint64_t k, uint64_t h1, uint64_t h2) return k; } +#if FF_API_CRYPTO_SIZE_T void av_murmur3_update(AVMurMur3 *c, const uint8_t *src, int len) +#else +void av_murmur3_update(AVMurMur3 *c, const uint8_t *src, size_t len) +#endif { const uint8_t *end; uint64_t h1 = c->h1, h2 = c->h2; diff --git a/libavutil/murmur3.h b/libavutil/murmur3.h index 6a1694c08df29..1b09175c1ec21 100644 --- a/libavutil/murmur3.h +++ b/libavutil/murmur3.h @@ -29,6 +29,8 @@ #include +#include "version.h" + /** * @defgroup lavu_murmur3 Murmur3 * @ingroup lavu_hash @@ -97,7 +99,11 @@ void av_murmur3_init(struct AVMurMur3 *c); * @param[in] src Input data to update hash with * @param[in] len Number of bytes to read from `src` */ +#if FF_API_CRYPTO_SIZE_T void av_murmur3_update(struct AVMurMur3 *c, const uint8_t *src, int len); +#else +void av_murmur3_update(struct AVMurMur3 *c, const uint8_t *src, size_t len); +#endif /** * Finish hashing and output digest value. diff --git a/libavutil/opencl.c b/libavutil/opencl.c deleted file mode 100644 index 202756516b005..0000000000000 --- a/libavutil/opencl.c +++ /dev/null @@ -1,875 +0,0 @@ -/* - * Copyright (C) 2012 Peng Gao - * Copyright (C) 2012 Li Cao - * Copyright (C) 2012 Wei Gao - * Copyright (C) 2013 Lenny Wang - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "opencl.h" -#include "avstring.h" -#include "log.h" -#include "avassert.h" -#include "opt.h" - -#if HAVE_THREADS -#include "thread.h" -#include "atomic.h" - -static pthread_mutex_t * volatile atomic_opencl_lock = NULL; -#define LOCK_OPENCL pthread_mutex_lock(atomic_opencl_lock) -#define UNLOCK_OPENCL pthread_mutex_unlock(atomic_opencl_lock) -#else -#define LOCK_OPENCL -#define UNLOCK_OPENCL -#endif - -#define MAX_KERNEL_CODE_NUM 200 - -typedef struct { - int is_compiled; - const char *kernel_string; -} KernelCode; - -typedef struct { - const AVClass *class; - int log_offset; - void *log_ctx; - int init_count; - int opt_init_flag; - /** - * if set to 1, the OpenCL environment was created by the user and - * passed as AVOpenCLExternalEnv when initing ,0:created by opencl wrapper. - */ - int is_user_created; - int platform_idx; - int device_idx; - cl_platform_id platform_id; - cl_device_type device_type; - cl_context context; - cl_device_id device_id; - cl_command_queue command_queue; - int kernel_code_count; - KernelCode kernel_code[MAX_KERNEL_CODE_NUM]; - AVOpenCLDeviceList device_list; -} OpenclContext; - -#define OFFSET(x) offsetof(OpenclContext, x) - -static const AVOption opencl_options[] = { - { "platform_idx", "set platform index value", OFFSET(platform_idx), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX}, - { "device_idx", "set device index value", OFFSET(device_idx), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX}, - { NULL } -}; - -static const AVClass openclutils_class = { - .class_name = "opencl", - .option = opencl_options, - .item_name = av_default_item_name, - .version = LIBAVUTIL_VERSION_INT, - .log_level_offset_offset = offsetof(OpenclContext, log_offset), - .parent_log_context_offset = offsetof(OpenclContext, log_ctx), -}; - -static OpenclContext opencl_ctx = {&openclutils_class}; - -static const cl_device_type device_type[] = {CL_DEVICE_TYPE_GPU, CL_DEVICE_TYPE_CPU}; - -typedef struct { - int err_code; - const char *err_str; -} OpenclErrorMsg; - -static const OpenclErrorMsg opencl_err_msg[] = { - {CL_DEVICE_NOT_FOUND, "DEVICE NOT FOUND"}, - {CL_DEVICE_NOT_AVAILABLE, "DEVICE NOT AVAILABLE"}, - {CL_COMPILER_NOT_AVAILABLE, "COMPILER NOT AVAILABLE"}, - {CL_MEM_OBJECT_ALLOCATION_FAILURE, "MEM OBJECT ALLOCATION FAILURE"}, - {CL_OUT_OF_RESOURCES, "OUT OF RESOURCES"}, - {CL_OUT_OF_HOST_MEMORY, "OUT OF HOST MEMORY"}, - {CL_PROFILING_INFO_NOT_AVAILABLE, "PROFILING INFO NOT AVAILABLE"}, - {CL_MEM_COPY_OVERLAP, "MEM COPY OVERLAP"}, - {CL_IMAGE_FORMAT_MISMATCH, "IMAGE FORMAT MISMATCH"}, - {CL_IMAGE_FORMAT_NOT_SUPPORTED, "IMAGE FORMAT NOT_SUPPORTED"}, - {CL_BUILD_PROGRAM_FAILURE, "BUILD PROGRAM FAILURE"}, - {CL_MAP_FAILURE, "MAP FAILURE"}, - {CL_MISALIGNED_SUB_BUFFER_OFFSET, "MISALIGNED SUB BUFFER OFFSET"}, - {CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST, "EXEC STATUS ERROR FOR EVENTS IN WAIT LIST"}, - {CL_COMPILE_PROGRAM_FAILURE, "COMPILE PROGRAM FAILURE"}, - {CL_LINKER_NOT_AVAILABLE, "LINKER NOT AVAILABLE"}, - {CL_LINK_PROGRAM_FAILURE, "LINK PROGRAM FAILURE"}, - {CL_DEVICE_PARTITION_FAILED, "DEVICE PARTITION FAILED"}, - {CL_KERNEL_ARG_INFO_NOT_AVAILABLE, "KERNEL ARG INFO NOT AVAILABLE"}, - {CL_INVALID_VALUE, "INVALID VALUE"}, - {CL_INVALID_DEVICE_TYPE, "INVALID DEVICE TYPE"}, - {CL_INVALID_PLATFORM, "INVALID PLATFORM"}, - {CL_INVALID_DEVICE, "INVALID DEVICE"}, - {CL_INVALID_CONTEXT, "INVALID CONTEXT"}, - {CL_INVALID_QUEUE_PROPERTIES, "INVALID QUEUE PROPERTIES"}, - {CL_INVALID_COMMAND_QUEUE, "INVALID COMMAND QUEUE"}, - {CL_INVALID_HOST_PTR, "INVALID HOST PTR"}, - {CL_INVALID_MEM_OBJECT, "INVALID MEM OBJECT"}, - {CL_INVALID_IMAGE_FORMAT_DESCRIPTOR, "INVALID IMAGE FORMAT DESCRIPTOR"}, - {CL_INVALID_IMAGE_SIZE, "INVALID IMAGE SIZE"}, - {CL_INVALID_SAMPLER, "INVALID SAMPLER"}, - {CL_INVALID_BINARY, "INVALID BINARY"}, - {CL_INVALID_BUILD_OPTIONS, "INVALID BUILD OPTIONS"}, - {CL_INVALID_PROGRAM, "INVALID PROGRAM"}, - {CL_INVALID_PROGRAM_EXECUTABLE, "INVALID PROGRAM EXECUTABLE"}, - {CL_INVALID_KERNEL_NAME, "INVALID KERNEL NAME"}, - {CL_INVALID_KERNEL_DEFINITION, "INVALID KERNEL DEFINITION"}, - {CL_INVALID_KERNEL, "INVALID KERNEL"}, - {CL_INVALID_ARG_INDEX, "INVALID ARG INDEX"}, - {CL_INVALID_ARG_VALUE, "INVALID ARG VALUE"}, - {CL_INVALID_ARG_SIZE, "INVALID ARG_SIZE"}, - {CL_INVALID_KERNEL_ARGS, "INVALID KERNEL ARGS"}, - {CL_INVALID_WORK_DIMENSION, "INVALID WORK DIMENSION"}, - {CL_INVALID_WORK_GROUP_SIZE, "INVALID WORK GROUP SIZE"}, - {CL_INVALID_WORK_ITEM_SIZE, "INVALID WORK ITEM SIZE"}, - {CL_INVALID_GLOBAL_OFFSET, "INVALID GLOBAL OFFSET"}, - {CL_INVALID_EVENT_WAIT_LIST, "INVALID EVENT WAIT LIST"}, - {CL_INVALID_EVENT, "INVALID EVENT"}, - {CL_INVALID_OPERATION, "INVALID OPERATION"}, - {CL_INVALID_GL_OBJECT, "INVALID GL OBJECT"}, - {CL_INVALID_BUFFER_SIZE, "INVALID BUFFER SIZE"}, - {CL_INVALID_MIP_LEVEL, "INVALID MIP LEVEL"}, - {CL_INVALID_GLOBAL_WORK_SIZE, "INVALID GLOBAL WORK SIZE"}, - {CL_INVALID_PROPERTY, "INVALID PROPERTY"}, - {CL_INVALID_IMAGE_DESCRIPTOR, "INVALID IMAGE DESCRIPTOR"}, - {CL_INVALID_COMPILER_OPTIONS, "INVALID COMPILER OPTIONS"}, - {CL_INVALID_LINKER_OPTIONS, "INVALID LINKER OPTIONS"}, - {CL_INVALID_DEVICE_PARTITION_COUNT, "INVALID DEVICE PARTITION COUNT"}, -}; - -const char *av_opencl_errstr(cl_int status) -{ - int i; - for (i = 0; i < FF_ARRAY_ELEMS(opencl_err_msg); i++) { - if (opencl_err_msg[i].err_code == status) - return opencl_err_msg[i].err_str; - } - return "unknown error"; -} - -static void free_device_list(AVOpenCLDeviceList *device_list) -{ - int i, j; - if (!device_list || !device_list->platform_node) - return; - for (i = 0; i < device_list->platform_num; i++) { - if (!device_list->platform_node[i]) - continue; - for (j = 0; j < device_list->platform_node[i]->device_num; j++) { - av_freep(&(device_list->platform_node[i]->device_node[j]->device_name)); - av_freep(&(device_list->platform_node[i]->device_node[j])); - } - av_freep(&device_list->platform_node[i]->device_node); - av_freep(&(device_list->platform_node[i]->platform_name)); - av_freep(&device_list->platform_node[i]); - } - av_freep(&device_list->platform_node); - device_list->platform_num = 0; -} - -static int get_device_list(AVOpenCLDeviceList *device_list) -{ - cl_int status; - int i, j, k, device_num, total_devices_num, ret = 0; - int *devices_num; - cl_platform_id *platform_ids = NULL; - cl_device_id *device_ids = NULL; - AVOpenCLDeviceNode *device_node = NULL; - size_t platform_name_size = 0; - size_t device_name_size = 0; - status = clGetPlatformIDs(0, NULL, &device_list->platform_num); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not get OpenCL platform ids: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - platform_ids = av_mallocz_array(device_list->platform_num, sizeof(cl_platform_id)); - if (!platform_ids) - return AVERROR(ENOMEM); - status = clGetPlatformIDs(device_list->platform_num, platform_ids, NULL); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not get OpenCL platform ids: %s\n", av_opencl_errstr(status)); - ret = AVERROR_EXTERNAL; - goto end; - } - device_list->platform_node = av_mallocz_array(device_list->platform_num, sizeof(AVOpenCLPlatformNode *)); - if (!device_list->platform_node) { - ret = AVERROR(ENOMEM); - goto end; - } - devices_num = av_mallocz(sizeof(int) * FF_ARRAY_ELEMS(device_type)); - if (!devices_num) { - ret = AVERROR(ENOMEM); - goto end; - } - for (i = 0; i < device_list->platform_num; i++) { - device_list->platform_node[i] = av_mallocz(sizeof(AVOpenCLPlatformNode)); - if (!device_list->platform_node[i]) { - ret = AVERROR(ENOMEM); - goto end; - } - device_list->platform_node[i]->platform_id = platform_ids[i]; - status = clGetPlatformInfo(platform_ids[i], CL_PLATFORM_VENDOR, - 0, NULL, &platform_name_size); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_WARNING, - "Could not get size of platform name: %s\n", av_opencl_errstr(status)); - } else { - device_list->platform_node[i]->platform_name = av_malloc(platform_name_size * sizeof(char)); - if (!device_list->platform_node[i]->platform_name) { - av_log(&opencl_ctx, AV_LOG_WARNING, - "Could not allocate memory for device name: %s\n", av_opencl_errstr(status)); - } else { - status = clGetPlatformInfo(platform_ids[i], CL_PLATFORM_VENDOR, - platform_name_size * sizeof(char), - device_list->platform_node[i]->platform_name, NULL); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_WARNING, - "Could not get platform name: %s\n", av_opencl_errstr(status)); - } - } - } - total_devices_num = 0; - for (j = 0; j < FF_ARRAY_ELEMS(device_type); j++) { - status = clGetDeviceIDs(device_list->platform_node[i]->platform_id, - device_type[j], 0, NULL, &devices_num[j]); - total_devices_num += devices_num[j]; - } - device_list->platform_node[i]->device_node = av_mallocz_array(total_devices_num, sizeof(AVOpenCLDeviceNode *)); - if (!device_list->platform_node[i]->device_node) { - ret = AVERROR(ENOMEM); - goto end; - } - for (j = 0; j < FF_ARRAY_ELEMS(device_type); j++) { - if (devices_num[j]) { - device_ids = av_mallocz_array(devices_num[j], sizeof(cl_device_id)); - if (!device_ids) { - ret = AVERROR(ENOMEM); - goto end; - } - status = clGetDeviceIDs(device_list->platform_node[i]->platform_id, device_type[j], - devices_num[j], device_ids, NULL); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_WARNING, - "Could not get device ID: %s:\n", av_opencl_errstr(status)); - av_freep(&device_ids); - continue; - } - for (k = 0; k < devices_num[j]; k++) { - device_num = device_list->platform_node[i]->device_num; - device_list->platform_node[i]->device_node[device_num] = av_mallocz(sizeof(AVOpenCLDeviceNode)); - if (!device_list->platform_node[i]->device_node[device_num]) { - ret = AVERROR(ENOMEM); - goto end; - } - device_node = device_list->platform_node[i]->device_node[device_num]; - device_node->device_id = device_ids[k]; - device_node->device_type = device_type[j]; - status = clGetDeviceInfo(device_node->device_id, CL_DEVICE_NAME, - 0, NULL, &device_name_size); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_WARNING, - "Could not get size of device name: %s\n", av_opencl_errstr(status)); - continue; - } - device_node->device_name = av_malloc(device_name_size * sizeof(char)); - if (!device_node->device_name) { - av_log(&opencl_ctx, AV_LOG_WARNING, - "Could not allocate memory for device name: %s\n", av_opencl_errstr(status)); - continue; - } - status = clGetDeviceInfo(device_node->device_id, CL_DEVICE_NAME, - device_name_size * sizeof(char), - device_node->device_name, NULL); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_WARNING, - "Could not get device name: %s\n", av_opencl_errstr(status)); - continue; - } - device_list->platform_node[i]->device_num++; - } - av_freep(&device_ids); - } - } - } -end: - av_freep(&platform_ids); - av_freep(&devices_num); - av_freep(&device_ids); - if (ret < 0) - free_device_list(device_list); - return ret; -} - -int av_opencl_get_device_list(AVOpenCLDeviceList **device_list) -{ - int ret = 0; - *device_list = av_mallocz(sizeof(AVOpenCLDeviceList)); - if (!(*device_list)) { - av_log(&opencl_ctx, AV_LOG_ERROR, "Could not allocate opencl device list\n"); - return AVERROR(ENOMEM); - } - ret = get_device_list(*device_list); - if (ret < 0) { - av_log(&opencl_ctx, AV_LOG_ERROR, "Could not get device list from environment\n"); - free_device_list(*device_list); - av_freep(device_list); - return ret; - } - return ret; -} - -void av_opencl_free_device_list(AVOpenCLDeviceList **device_list) -{ - free_device_list(*device_list); - av_freep(device_list); -} - -static inline int init_opencl_mtx(void) -{ -#if HAVE_THREADS - if (!atomic_opencl_lock) { - int err; - pthread_mutex_t *tmp = av_malloc(sizeof(pthread_mutex_t)); - if (!tmp) - return AVERROR(ENOMEM); - if ((err = pthread_mutex_init(tmp, NULL))) { - av_free(tmp); - return AVERROR(err); - } - if (avpriv_atomic_ptr_cas((void * volatile *)&atomic_opencl_lock, NULL, tmp)) { - pthread_mutex_destroy(tmp); - av_free(tmp); - } - } -#endif - return 0; -} - -int av_opencl_set_option(const char *key, const char *val) -{ - int ret = init_opencl_mtx( ); - if (ret < 0) - return ret; - LOCK_OPENCL; - if (!opencl_ctx.opt_init_flag) { - av_opt_set_defaults(&opencl_ctx); - opencl_ctx.opt_init_flag = 1; - } - ret = av_opt_set(&opencl_ctx, key, val, 0); - UNLOCK_OPENCL; - return ret; -} - -int av_opencl_get_option(const char *key, uint8_t **out_val) -{ - int ret = 0; - LOCK_OPENCL; - ret = av_opt_get(&opencl_ctx, key, 0, out_val); - UNLOCK_OPENCL; - return ret; -} - -void av_opencl_free_option(void) -{ - /*FIXME: free openclutils context*/ - LOCK_OPENCL; - av_opt_free(&opencl_ctx); - UNLOCK_OPENCL; -} - -AVOpenCLExternalEnv *av_opencl_alloc_external_env(void) -{ - AVOpenCLExternalEnv *ext = av_mallocz(sizeof(AVOpenCLExternalEnv)); - if (!ext) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not malloc external opencl environment data space\n"); - } - return ext; -} - -void av_opencl_free_external_env(AVOpenCLExternalEnv **ext_opencl_env) -{ - av_freep(ext_opencl_env); -} - -int av_opencl_register_kernel_code(const char *kernel_code) -{ - int i, ret = init_opencl_mtx( ); - if (ret < 0) - return ret; - LOCK_OPENCL; - if (opencl_ctx.kernel_code_count >= MAX_KERNEL_CODE_NUM) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not register kernel code, maximum number of registered kernel code %d already reached\n", - MAX_KERNEL_CODE_NUM); - ret = AVERROR(EINVAL); - goto end; - } - for (i = 0; i < opencl_ctx.kernel_code_count; i++) { - if (opencl_ctx.kernel_code[i].kernel_string == kernel_code) { - av_log(&opencl_ctx, AV_LOG_WARNING, "Same kernel code has been registered\n"); - goto end; - } - } - opencl_ctx.kernel_code[opencl_ctx.kernel_code_count].kernel_string = kernel_code; - opencl_ctx.kernel_code[opencl_ctx.kernel_code_count].is_compiled = 0; - opencl_ctx.kernel_code_count++; -end: - UNLOCK_OPENCL; - return ret; -} - -cl_program av_opencl_compile(const char *program_name, const char *build_opts) -{ - int i; - cl_int status, build_status; - int kernel_code_idx = 0; - const char *kernel_source = NULL; - size_t kernel_code_len; - char* ptr = NULL; - cl_program program = NULL; - size_t log_size; - char *log = NULL; - - LOCK_OPENCL; - for (i = 0; i < opencl_ctx.kernel_code_count; i++) { - // identify a program using a unique name within the kernel source - ptr = av_stristr(opencl_ctx.kernel_code[i].kernel_string, program_name); - if (ptr && !opencl_ctx.kernel_code[i].is_compiled) { - kernel_source = opencl_ctx.kernel_code[i].kernel_string; - kernel_code_len = strlen(opencl_ctx.kernel_code[i].kernel_string); - kernel_code_idx = i; - break; - } - } - if (!kernel_source) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Unable to find OpenCL kernel source '%s'\n", program_name); - goto end; - } - - /* create a CL program from kernel source */ - program = clCreateProgramWithSource(opencl_ctx.context, 1, &kernel_source, &kernel_code_len, &status); - if(status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Unable to create OpenCL program '%s': %s\n", program_name, av_opencl_errstr(status)); - program = NULL; - goto end; - } - - build_status = clBuildProgram(program, 1, &(opencl_ctx.device_id), build_opts, NULL, NULL); - status = clGetProgramBuildInfo(program, opencl_ctx.device_id, - CL_PROGRAM_BUILD_LOG, 0, NULL, &log_size); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_WARNING, - "Failed to get compilation log: %s\n", - av_opencl_errstr(status)); - } else { - log = av_malloc(log_size); - if (log) { - status = clGetProgramBuildInfo(program, opencl_ctx.device_id, - CL_PROGRAM_BUILD_LOG, log_size, - log, NULL); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_WARNING, - "Failed to get compilation log: %s\n", - av_opencl_errstr(status)); - } else { - int level = build_status == CL_SUCCESS ? AV_LOG_DEBUG : - AV_LOG_ERROR; - av_log(&opencl_ctx, level, "Compilation log:\n%s\n", log); - } - } - av_freep(&log); - } - if (build_status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Compilation failed with OpenCL program '%s': %s\n", - program_name, av_opencl_errstr(build_status)); - program = NULL; - goto end; - } - - opencl_ctx.kernel_code[kernel_code_idx].is_compiled = 1; -end: - UNLOCK_OPENCL; - return program; -} - -cl_command_queue av_opencl_get_command_queue(void) -{ - return opencl_ctx.command_queue; -} - -static int init_opencl_env(OpenclContext *opencl_ctx, AVOpenCLExternalEnv *ext_opencl_env) -{ - cl_int status; - cl_context_properties cps[3]; - int i, ret = 0; - AVOpenCLDeviceNode *device_node = NULL; - - if (ext_opencl_env) { - if (opencl_ctx->is_user_created) - return 0; - opencl_ctx->platform_id = ext_opencl_env->platform_id; - opencl_ctx->is_user_created = 1; - opencl_ctx->command_queue = ext_opencl_env->command_queue; - opencl_ctx->context = ext_opencl_env->context; - opencl_ctx->device_id = ext_opencl_env->device_id; - opencl_ctx->device_type = ext_opencl_env->device_type; - } else { - if (!opencl_ctx->is_user_created) { - if (!opencl_ctx->device_list.platform_num) { - ret = get_device_list(&opencl_ctx->device_list); - if (ret < 0) { - return ret; - } - } - if (opencl_ctx->platform_idx >= 0) { - if (opencl_ctx->device_list.platform_num < opencl_ctx->platform_idx + 1) { - av_log(opencl_ctx, AV_LOG_ERROR, "User set platform index not exist\n"); - return AVERROR(EINVAL); - } - if (!opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->device_num) { - av_log(opencl_ctx, AV_LOG_ERROR, "No devices in user specific platform with index %d\n", - opencl_ctx->platform_idx); - return AVERROR(EINVAL); - } - opencl_ctx->platform_id = opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->platform_id; - } else { - /* get a usable platform by default*/ - for (i = 0; i < opencl_ctx->device_list.platform_num; i++) { - if (opencl_ctx->device_list.platform_node[i]->device_num) { - opencl_ctx->platform_id = opencl_ctx->device_list.platform_node[i]->platform_id; - opencl_ctx->platform_idx = i; - break; - } - } - } - if (!opencl_ctx->platform_id) { - av_log(opencl_ctx, AV_LOG_ERROR, "Could not get OpenCL platforms\n"); - return AVERROR_EXTERNAL; - } - /* get a usable device*/ - if (opencl_ctx->device_idx >= 0) { - if (opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->device_num < opencl_ctx->device_idx + 1) { - av_log(opencl_ctx, AV_LOG_ERROR, - "Could not get OpenCL device idx %d in the user set platform\n", opencl_ctx->platform_idx); - return AVERROR(EINVAL); - } - } else { - opencl_ctx->device_idx = 0; - } - - device_node = opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->device_node[opencl_ctx->device_idx]; - opencl_ctx->device_id = device_node->device_id; - opencl_ctx->device_type = device_node->device_type; - - /* - * Use available platform. - */ - av_log(opencl_ctx, AV_LOG_VERBOSE, "Platform Name: %s, Device Name: %s\n", - opencl_ctx->device_list.platform_node[opencl_ctx->platform_idx]->platform_name, - device_node->device_name); - cps[0] = CL_CONTEXT_PLATFORM; - cps[1] = (cl_context_properties)opencl_ctx->platform_id; - cps[2] = 0; - - opencl_ctx->context = clCreateContextFromType(cps, opencl_ctx->device_type, - NULL, NULL, &status); - if (status != CL_SUCCESS) { - av_log(opencl_ctx, AV_LOG_ERROR, - "Could not get OpenCL context from device type: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - opencl_ctx->command_queue = clCreateCommandQueue(opencl_ctx->context, opencl_ctx->device_id, - 0, &status); - if (status != CL_SUCCESS) { - av_log(opencl_ctx, AV_LOG_ERROR, - "Could not create OpenCL command queue: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - } - } - return ret; -} - -int av_opencl_init(AVOpenCLExternalEnv *ext_opencl_env) -{ - int ret = init_opencl_mtx( ); - if (ret < 0) - return ret; - LOCK_OPENCL; - if (!opencl_ctx.init_count) { - if (!opencl_ctx.opt_init_flag) { - av_opt_set_defaults(&opencl_ctx); - opencl_ctx.opt_init_flag = 1; - } - ret = init_opencl_env(&opencl_ctx, ext_opencl_env); - if (ret < 0) - goto end; - if (opencl_ctx.kernel_code_count <= 0) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "No kernel code is registered, compile kernel file failed\n"); - ret = AVERROR(EINVAL); - goto end; - } - } - opencl_ctx.init_count++; -end: - UNLOCK_OPENCL; - return ret; -} - -void av_opencl_uninit(void) -{ - int i; - cl_int status; - LOCK_OPENCL; - opencl_ctx.init_count--; - if (opencl_ctx.is_user_created) - goto end; - if (opencl_ctx.init_count > 0) - goto end; - if (opencl_ctx.command_queue) { - status = clReleaseCommandQueue(opencl_ctx.command_queue); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not release OpenCL command queue: %s\n", av_opencl_errstr(status)); - } - opencl_ctx.command_queue = NULL; - } - if (opencl_ctx.context) { - status = clReleaseContext(opencl_ctx.context); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not release OpenCL context: %s\n", av_opencl_errstr(status)); - } - opencl_ctx.context = NULL; - } - for (i = 0; i < opencl_ctx.kernel_code_count; i++) { - opencl_ctx.kernel_code[i].is_compiled = 0; - } - free_device_list(&opencl_ctx.device_list); -end: - if (opencl_ctx.init_count <= 0) - av_opt_free(&opencl_ctx); //FIXME: free openclutils context - UNLOCK_OPENCL; -} - -int av_opencl_buffer_create(cl_mem *cl_buf, size_t cl_buf_size, int flags, void *host_ptr) -{ - cl_int status; - *cl_buf = clCreateBuffer(opencl_ctx.context, flags, cl_buf_size, host_ptr, &status); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, "Could not create OpenCL buffer: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - return 0; -} - -void av_opencl_buffer_release(cl_mem *cl_buf) -{ - cl_int status = 0; - if (!cl_buf) - return; - status = clReleaseMemObject(*cl_buf); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not release OpenCL buffer: %s\n", av_opencl_errstr(status)); - } - memset(cl_buf, 0, sizeof(*cl_buf)); -} - -int av_opencl_buffer_write(cl_mem dst_cl_buf, uint8_t *src_buf, size_t buf_size) -{ - cl_int status; - void *mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, dst_cl_buf, - CL_TRUE, CL_MAP_WRITE, 0, sizeof(uint8_t) * buf_size, - 0, NULL, NULL, &status); - - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - memcpy(mapped, src_buf, buf_size); - - status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, dst_cl_buf, mapped, 0, NULL, NULL); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - return 0; -} - -int av_opencl_buffer_read(uint8_t *dst_buf, cl_mem src_cl_buf, size_t buf_size) -{ - cl_int status; - void *mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, src_cl_buf, - CL_TRUE, CL_MAP_READ, 0, buf_size, - 0, NULL, NULL, &status); - - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - memcpy(dst_buf, mapped, buf_size); - - status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, src_cl_buf, mapped, 0, NULL, NULL); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - return 0; -} - -int av_opencl_buffer_write_image(cl_mem dst_cl_buf, size_t cl_buffer_size, int dst_cl_offset, - uint8_t **src_data, int *plane_size, int plane_num) -{ - int i, buffer_size = 0; - uint8_t *temp; - cl_int status; - void *mapped; - if ((unsigned int)plane_num > 8) { - return AVERROR(EINVAL); - } - for (i = 0;i < plane_num;i++) { - buffer_size += plane_size[i]; - } - if (buffer_size > cl_buffer_size) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Cannot write image to OpenCL buffer: buffer too small\n"); - return AVERROR(EINVAL); - } - mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, dst_cl_buf, - CL_TRUE, CL_MAP_WRITE, 0, buffer_size + dst_cl_offset, - 0, NULL, NULL, &status); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - temp = mapped; - temp += dst_cl_offset; - for (i = 0; i < plane_num; i++) { - memcpy(temp, src_data[i], plane_size[i]); - temp += plane_size[i]; - } - status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, dst_cl_buf, mapped, 0, NULL, NULL); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - return 0; -} - -int av_opencl_buffer_read_image(uint8_t **dst_data, int *plane_size, int plane_num, - cl_mem src_cl_buf, size_t cl_buffer_size) -{ - int i,buffer_size = 0,ret = 0; - uint8_t *temp; - void *mapped; - cl_int status; - if ((unsigned int)plane_num > 8) { - return AVERROR(EINVAL); - } - for (i = 0; i < plane_num; i++) { - buffer_size += plane_size[i]; - } - if (buffer_size > cl_buffer_size) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Cannot write image to CPU buffer: OpenCL buffer too small\n"); - return AVERROR(EINVAL); - } - mapped = clEnqueueMapBuffer(opencl_ctx.command_queue, src_cl_buf, - CL_TRUE, CL_MAP_READ, 0, buffer_size, - 0, NULL, NULL, &status); - - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not map OpenCL buffer: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - temp = mapped; - if (ret >= 0) { - for (i = 0; i < plane_num; i++) { - memcpy(dst_data[i], temp, plane_size[i]); - temp += plane_size[i]; - } - } - status = clEnqueueUnmapMemObject(opencl_ctx.command_queue, src_cl_buf, mapped, 0, NULL, NULL); - if (status != CL_SUCCESS) { - av_log(&opencl_ctx, AV_LOG_ERROR, - "Could not unmap OpenCL buffer: %s\n", av_opencl_errstr(status)); - return AVERROR_EXTERNAL; - } - return 0; -} - -int64_t av_opencl_benchmark(AVOpenCLDeviceNode *device_node, cl_platform_id platform, - int64_t (*benchmark)(AVOpenCLExternalEnv *ext_opencl_env)) -{ - int64_t ret = 0; - cl_int status; - cl_context_properties cps[3]; - AVOpenCLExternalEnv *ext_opencl_env = NULL; - - ext_opencl_env = av_opencl_alloc_external_env(); - ext_opencl_env->device_id = device_node->device_id; - ext_opencl_env->device_type = device_node->device_type; - av_log(&opencl_ctx, AV_LOG_VERBOSE, "Performing test on OpenCL device %s\n", - device_node->device_name); - - cps[0] = CL_CONTEXT_PLATFORM; - cps[1] = (cl_context_properties)platform; - cps[2] = 0; - ext_opencl_env->context = clCreateContextFromType(cps, ext_opencl_env->device_type, - NULL, NULL, &status); - if (status != CL_SUCCESS || !ext_opencl_env->context) { - ret = AVERROR_EXTERNAL; - goto end; - } - ext_opencl_env->command_queue = clCreateCommandQueue(ext_opencl_env->context, - ext_opencl_env->device_id, 0, &status); - if (status != CL_SUCCESS || !ext_opencl_env->command_queue) { - ret = AVERROR_EXTERNAL; - goto end; - } - ret = benchmark(ext_opencl_env); - if (ret < 0) - av_log(&opencl_ctx, AV_LOG_ERROR, "Benchmark failed with OpenCL device %s\n", - device_node->device_name); -end: - if (ext_opencl_env->command_queue) - clReleaseCommandQueue(ext_opencl_env->command_queue); - if (ext_opencl_env->context) - clReleaseContext(ext_opencl_env->context); - av_opencl_free_external_env(&ext_opencl_env); - return ret; -} diff --git a/libavutil/opencl.h b/libavutil/opencl.h deleted file mode 100644 index b709927c42739..0000000000000 --- a/libavutil/opencl.h +++ /dev/null @@ -1,292 +0,0 @@ -/* - * Copyright (C) 2012 Peng Gao - * Copyright (C) 2012 Li Cao - * Copyright (C) 2012 Wei Gao - * Copyright (C) 2013 Lenny Wang - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/** - * @file - * OpenCL wrapper - * - * This interface is considered still experimental and its API and ABI may - * change without prior notice. - */ - -#ifndef AVUTIL_OPENCL_H -#define AVUTIL_OPENCL_H - -#define CL_USE_DEPRECATED_OPENCL_1_2_APIS 1 -#ifdef __APPLE__ -#include -#else -#include -#endif -#include -#include "dict.h" - -#include "libavutil/version.h" - -#define AV_OPENCL_KERNEL( ... )# __VA_ARGS__ - -typedef struct { - int device_type; - char *device_name; - cl_device_id device_id; -} AVOpenCLDeviceNode; - -typedef struct { - cl_platform_id platform_id; - char *platform_name; - int device_num; - AVOpenCLDeviceNode **device_node; -} AVOpenCLPlatformNode; - -typedef struct { - int platform_num; - AVOpenCLPlatformNode **platform_node; -} AVOpenCLDeviceList; - -typedef struct { - cl_platform_id platform_id; - cl_device_type device_type; - cl_context context; - cl_device_id device_id; - cl_command_queue command_queue; - char *platform_name; -} AVOpenCLExternalEnv; - -/** - * Get OpenCL device list. - * - * It must be freed with av_opencl_free_device_list(). - * - * @param device_list pointer to OpenCL environment device list, - * should be released by av_opencl_free_device_list() - * - * @return >=0 on success, a negative error code in case of failure - */ -int av_opencl_get_device_list(AVOpenCLDeviceList **device_list); - -/** - * Free OpenCL device list. - * - * @param device_list pointer to OpenCL environment device list - * created by av_opencl_get_device_list() - */ -void av_opencl_free_device_list(AVOpenCLDeviceList **device_list); - -/** - * Set option in the global OpenCL context. - * - * This options affect the operation performed by the next - * av_opencl_init() operation. - * - * The currently accepted options are: - * - platform: set index of platform in device list - * - device: set index of device in device list - * - * See reference "OpenCL Specification Version: 1.2 chapter 5.6.4". - * - * @param key option key - * @param val option value - * @return >=0 on success, a negative error code in case of failure - * @see av_opencl_get_option() - */ -int av_opencl_set_option(const char *key, const char *val); - -/** - * Get option value from the global OpenCL context. - * - * @param key option key - * @param out_val pointer to location where option value will be - * written, must be freed with av_freep() - * @return >=0 on success, a negative error code in case of failure - * @see av_opencl_set_option() - */ -int av_opencl_get_option(const char *key, uint8_t **out_val); - -/** - * Free option values of the global OpenCL context. - * - */ -void av_opencl_free_option(void); - -/** - * Allocate OpenCL external environment. - * - * It must be freed with av_opencl_free_external_env(). - * - * @return pointer to allocated OpenCL external environment - */ -AVOpenCLExternalEnv *av_opencl_alloc_external_env(void); - -/** - * Free OpenCL external environment. - * - * @param ext_opencl_env pointer to OpenCL external environment - * created by av_opencl_alloc_external_env() - */ -void av_opencl_free_external_env(AVOpenCLExternalEnv **ext_opencl_env); - -/** - * Get OpenCL error string. - * - * @param status OpenCL error code - * @return OpenCL error string - */ -const char *av_opencl_errstr(cl_int status); - -/** - * Register kernel code. - * - * The registered kernel code is stored in a global context, and compiled - * in the runtime environment when av_opencl_init() is called. - * - * @param kernel_code kernel code to be compiled in the OpenCL runtime environment - * @return >=0 on success, a negative error code in case of failure - */ -int av_opencl_register_kernel_code(const char *kernel_code); - -/** - * Initialize the run time OpenCL environment - * - * @param ext_opencl_env external OpenCL environment, created by an - * application program, ignored if set to NULL - * @return >=0 on success, a negative error code in case of failure - */ -int av_opencl_init(AVOpenCLExternalEnv *ext_opencl_env); - -/** - * compile specific OpenCL kernel source - * - * @param program_name pointer to a program name used for identification - * @param build_opts pointer to a string that describes the preprocessor - * build options to be used for building the program - * @return a cl_program object - */ -cl_program av_opencl_compile(const char *program_name, const char* build_opts); - -/** - * get OpenCL command queue - * - * @return a cl_command_queue object - */ -cl_command_queue av_opencl_get_command_queue(void); - -/** - * Create OpenCL buffer. - * - * The buffer is used to save the data used or created by an OpenCL - * kernel. - * The created buffer must be released with av_opencl_buffer_release(). - * - * See clCreateBuffer() function reference for more information about - * the parameters. - * - * @param cl_buf pointer to OpenCL buffer - * @param cl_buf_size size in bytes of the OpenCL buffer to create - * @param flags flags used to control buffer attributes - * @param host_ptr host pointer of the OpenCL buffer - * @return >=0 on success, a negative error code in case of failure - */ -int av_opencl_buffer_create(cl_mem *cl_buf, size_t cl_buf_size, int flags, void *host_ptr); - -/** - * Write OpenCL buffer with data from src_buf. - * - * @param dst_cl_buf pointer to OpenCL destination buffer - * @param src_buf pointer to source buffer - * @param buf_size size in bytes of the source and destination buffers - * @return >=0 on success, a negative error code in case of failure - */ -int av_opencl_buffer_write(cl_mem dst_cl_buf, uint8_t *src_buf, size_t buf_size); - -/** - * Read data from OpenCL buffer to memory buffer. - * - * @param dst_buf pointer to destination buffer (CPU memory) - * @param src_cl_buf pointer to source OpenCL buffer - * @param buf_size size in bytes of the source and destination buffers - * @return >=0 on success, a negative error code in case of failure - */ -int av_opencl_buffer_read(uint8_t *dst_buf, cl_mem src_cl_buf, size_t buf_size); - -/** - * Write image data from memory to OpenCL buffer. - * - * The source must be an array of pointers to image plane buffers. - * - * @param dst_cl_buf pointer to destination OpenCL buffer - * @param dst_cl_buf_size size in bytes of OpenCL buffer - * @param dst_cl_buf_offset the offset of the OpenCL buffer start position - * @param src_data array of pointers to source plane buffers - * @param src_plane_sizes array of sizes in bytes of the source plane buffers - * @param src_plane_num number of source image planes - * @return >=0 on success, a negative error code in case of failure - */ -int av_opencl_buffer_write_image(cl_mem dst_cl_buf, size_t cl_buffer_size, int dst_cl_offset, - uint8_t **src_data, int *plane_size, int plane_num); - -/** - * Read image data from OpenCL buffer. - * - * @param dst_data array of pointers to destination plane buffers - * @param dst_plane_sizes array of pointers to destination plane buffers - * @param dst_plane_num number of destination image planes - * @param src_cl_buf pointer to source OpenCL buffer - * @param src_cl_buf_size size in bytes of OpenCL buffer - * @return >=0 on success, a negative error code in case of failure - */ -int av_opencl_buffer_read_image(uint8_t **dst_data, int *plane_size, int plane_num, - cl_mem src_cl_buf, size_t cl_buffer_size); - -/** - * Release OpenCL buffer. - * - * @param cl_buf pointer to OpenCL buffer to release, which was - * previously filled with av_opencl_buffer_create() - */ -void av_opencl_buffer_release(cl_mem *cl_buf); - -/** - * Release OpenCL environment. - * - * The OpenCL environment is effectively released only if all the created - * kernels had been released with av_opencl_release_kernel(). - */ -void av_opencl_uninit(void); - -/** - * Benchmark an OpenCL device with a user defined callback function. This function - * sets up an external OpenCL environment including context and command queue on - * the device then tears it down in the end. The callback function should perform - * the rest of the work. - * - * @param device pointer to the OpenCL device to be used - * @param platform cl_platform_id handle to which the device belongs to - * @param benchmark callback function to perform the benchmark, return a - * negative value in case of failure - * @return the score passed from the callback function, a negative error code in case - * of failure - */ -int64_t av_opencl_benchmark(AVOpenCLDeviceNode *device, cl_platform_id platform, - int64_t (*benchmark)(AVOpenCLExternalEnv *ext_opencl_env)); - -#endif /* AVUTIL_OPENCL_H */ diff --git a/libavutil/opencl_internal.c b/libavutil/opencl_internal.c deleted file mode 100644 index bdb41936faf49..0000000000000 --- a/libavutil/opencl_internal.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2012 Peng Gao - * Copyright (C) 2012 Li Cao - * Copyright (C) 2012 Wei Gao - * - * This file is part of FFmpeg. - * - * FFmpeg is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * FFmpeg is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "opencl_internal.h" -#include "libavutil/log.h" - -int avpriv_opencl_set_parameter(FFOpenclParam *opencl_param, ...) -{ - int ret = 0; - va_list arg_ptr; - void *param; - size_t param_size; - cl_int status; - if (!opencl_param->kernel) { - av_log(opencl_param->ctx, AV_LOG_ERROR, "OpenCL kernel must be set\n"); - return AVERROR(EINVAL); - } - va_start(arg_ptr, opencl_param); - do { - param = va_arg(arg_ptr, void *); - if (!param) - break; - param_size = va_arg(arg_ptr, size_t); - if (!param_size) { - av_log(opencl_param->ctx, AV_LOG_ERROR, "Parameter size must not be 0\n"); - ret = AVERROR(EINVAL); - goto end; - } - status = clSetKernelArg(opencl_param->kernel, opencl_param->param_num, param_size, param); - if (status != CL_SUCCESS) { - av_log(opencl_param->ctx, AV_LOG_ERROR, "Cannot set kernel argument: %s\n", av_opencl_errstr(status)); - ret = AVERROR_EXTERNAL; - goto end; - } - opencl_param->param_num++; - } while (param && param_size); -end: - va_end(arg_ptr); - return ret; -} diff --git a/libavutil/opt.c b/libavutil/opt.c index df88663e3f09b..3b0aab4ee82ea 100644 --- a/libavutil/opt.c +++ b/libavutil/opt.c @@ -1181,6 +1181,7 @@ static void opt_list(void *obj, void *av_log_obj, const char *unit, av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_SUBTITLE_PARAM) ? 'S' : '.'); av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_EXPORT) ? 'X' : '.'); av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_READONLY) ? 'R' : '.'); + av_log(av_log_obj, AV_LOG_INFO, "%c", (opt->flags & AV_OPT_FLAG_BSF_PARAM) ? 'B' : '.'); if (opt->help) av_log(av_log_obj, AV_LOG_INFO, " %s", opt->help); diff --git a/libavutil/opt.h b/libavutil/opt.h index 0d893795deec9..07da68ea23d37 100644 --- a/libavutil/opt.h +++ b/libavutil/opt.h @@ -229,15 +229,15 @@ enum AVOptionType{ 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'), - AV_OPT_TYPE_SAMPLE_FMT = MKBETAG('S','F','M','T'), - AV_OPT_TYPE_VIDEO_RATE = MKBETAG('V','R','A','T'), ///< offset must point to AVRational - AV_OPT_TYPE_DURATION = MKBETAG('D','U','R',' '), - AV_OPT_TYPE_COLOR = MKBETAG('C','O','L','R'), - AV_OPT_TYPE_CHANNEL_LAYOUT = MKBETAG('C','H','L','A'), - AV_OPT_TYPE_BOOL = MKBETAG('B','O','O','L'), + AV_OPT_TYPE_CONST, + AV_OPT_TYPE_IMAGE_SIZE, ///< offset must point to two consecutive integers + AV_OPT_TYPE_PIXEL_FMT, + AV_OPT_TYPE_SAMPLE_FMT, + AV_OPT_TYPE_VIDEO_RATE, ///< offset must point to AVRational + AV_OPT_TYPE_DURATION, + AV_OPT_TYPE_COLOR, + AV_OPT_TYPE_CHANNEL_LAYOUT, + AV_OPT_TYPE_BOOL, }; /** @@ -275,9 +275,6 @@ typedef struct AVOption { int flags; #define AV_OPT_FLAG_ENCODING_PARAM 1 ///< a generic parameter which can be set by the user for muxing or encoding #define AV_OPT_FLAG_DECODING_PARAM 2 ///< a generic parameter which can be set by the user for demuxing or decoding -#if FF_API_OPT_TYPE_METADATA -#define AV_OPT_FLAG_METADATA 4 ///< some data extracted or inserted into the file like title, comment, ... -#endif #define AV_OPT_FLAG_AUDIO_PARAM 8 #define AV_OPT_FLAG_VIDEO_PARAM 16 #define AV_OPT_FLAG_SUBTITLE_PARAM 32 @@ -290,6 +287,7 @@ typedef struct AVOption { * This flag only makes sense when AV_OPT_FLAG_EXPORT is also set. */ #define AV_OPT_FLAG_READONLY 128 +#define AV_OPT_FLAG_BSF_PARAM (1<<8) ///< a generic parameter which can be set by the user for bit stream filtering #define AV_OPT_FLAG_FILTERING_PARAM (1<<16) ///< a generic parameter which can be set by the user for filtering //FIXME think about enc-audio, ... style flags diff --git a/libavutil/parseutils.c b/libavutil/parseutils.c index 7ca07b37a19ad..924c49d52cf65 100644 --- a/libavutil/parseutils.c +++ b/libavutil/parseutils.c @@ -590,7 +590,7 @@ int av_parse_time(int64_t *timeval, const char *timestr, int duration) int64_t t, now64; time_t now; struct tm dt = { 0 }, tmbuf; - int today = 0, negative = 0, microseconds = 0; + int today = 0, negative = 0, microseconds = 0, suffix = 1000000; int i; static const char * const date_fmt[] = { "%Y - %m - %d", @@ -689,6 +689,16 @@ int av_parse_time(int64_t *timeval, const char *timestr, int duration) if (duration) { t = dt.tm_hour * 3600 + dt.tm_min * 60 + dt.tm_sec; + if (q[0] == 'm' && q[1] == 's') { + suffix = 1000; + microseconds /= 1000; + q += 2; + } else if (q[0] == 'u' && q[1] == 's') { + suffix = 1; + microseconds = 0; + q += 2; + } else if (*q == 's') + q++; } else { int is_utc = *q == 'Z' || *q == 'z'; int tzoffset = 0; @@ -724,7 +734,7 @@ int av_parse_time(int64_t *timeval, const char *timestr, int duration) if (*q) return AVERROR(EINVAL); - t *= 1000000; + t *= suffix; t += microseconds; *timeval = negative ? -t : t; return 0; diff --git a/libavutil/pixdesc.c b/libavutil/pixdesc.c index 2cfab89c030fa..8ed52751c1a8b 100644 --- a/libavutil/pixdesc.c +++ b/libavutil/pixdesc.c @@ -257,7 +257,7 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { .comp = { { 0, 1, 0, 0, 8, 0, 7, 1 }, /* Y */ }, - .flags = AV_PIX_FMT_FLAG_PSEUDOPAL, + .flags = FF_PSEUDOPAL, .alias = "gray8,y8", }, [AV_PIX_FMT_MONOWHITE] = { @@ -326,22 +326,10 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { }, .flags = AV_PIX_FMT_FLAG_PLANAR, }, -#if FF_API_XVMC - [AV_PIX_FMT_XVMC_MPEG2_MC] = { - .name = "xvmcmc", - .flags = AV_PIX_FMT_FLAG_HWACCEL, - }, - [AV_PIX_FMT_XVMC_MPEG2_IDCT] = { - .name = "xvmcidct", - .flags = AV_PIX_FMT_FLAG_HWACCEL, - }, -#endif /* FF_API_XVMC */ -#if !FF_API_XVMC [AV_PIX_FMT_XVMC] = { .name = "xvmc", .flags = AV_PIX_FMT_FLAG_HWACCEL, }, -#endif /* !FF_API_XVMC */ [AV_PIX_FMT_UYVY422] = { .name = "uyvy422", .nb_components = 3, @@ -374,7 +362,7 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { { 0, 1, 0, 3, 3, 0, 2, 1 }, /* G */ { 0, 1, 0, 6, 2, 0, 1, 1 }, /* B */ }, - .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_PSEUDOPAL, + .flags = AV_PIX_FMT_FLAG_RGB | FF_PSEUDOPAL, }, [AV_PIX_FMT_BGR4] = { .name = "bgr4", @@ -398,7 +386,7 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { { 0, 1, 0, 1, 2, 0, 1, 1 }, /* G */ { 0, 1, 0, 3, 1, 0, 0, 1 }, /* B */ }, - .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_PSEUDOPAL, + .flags = AV_PIX_FMT_FLAG_RGB | FF_PSEUDOPAL, }, [AV_PIX_FMT_RGB8] = { .name = "rgb8", @@ -410,7 +398,7 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { { 0, 1, 0, 3, 3, 0, 2, 1 }, /* G */ { 0, 1, 0, 0, 3, 0, 2, 1 }, /* B */ }, - .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_PSEUDOPAL, + .flags = AV_PIX_FMT_FLAG_RGB | FF_PSEUDOPAL, }, [AV_PIX_FMT_RGB4] = { .name = "rgb4", @@ -434,7 +422,7 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { { 0, 1, 0, 1, 2, 0, 1, 1 }, /* G */ { 0, 1, 0, 0, 1, 0, 0, 1 }, /* B */ }, - .flags = AV_PIX_FMT_FLAG_RGB | AV_PIX_FMT_FLAG_PSEUDOPAL, + .flags = AV_PIX_FMT_FLAG_RGB | FF_PSEUDOPAL, }, [AV_PIX_FMT_NV12] = { .name = "nv12", @@ -989,44 +977,6 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { }, .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_ALPHA, }, -#if FF_API_VDPAU - [AV_PIX_FMT_VDPAU_H264] = { - .name = "vdpau_h264", - .log2_chroma_w = 1, - .log2_chroma_h = 1, - .flags = AV_PIX_FMT_FLAG_HWACCEL, - }, - [AV_PIX_FMT_VDPAU_MPEG1] = { - .name = "vdpau_mpeg1", - .log2_chroma_w = 1, - .log2_chroma_h = 1, - .flags = AV_PIX_FMT_FLAG_HWACCEL, - }, - [AV_PIX_FMT_VDPAU_MPEG2] = { - .name = "vdpau_mpeg2", - .log2_chroma_w = 1, - .log2_chroma_h = 1, - .flags = AV_PIX_FMT_FLAG_HWACCEL, - }, - [AV_PIX_FMT_VDPAU_WMV3] = { - .name = "vdpau_wmv3", - .log2_chroma_w = 1, - .log2_chroma_h = 1, - .flags = AV_PIX_FMT_FLAG_HWACCEL, - }, - [AV_PIX_FMT_VDPAU_VC1] = { - .name = "vdpau_vc1", - .log2_chroma_w = 1, - .log2_chroma_h = 1, - .flags = AV_PIX_FMT_FLAG_HWACCEL, - }, - [AV_PIX_FMT_VDPAU_MPEG4] = { - .name = "vdpau_mpeg4", - .log2_chroma_w = 1, - .log2_chroma_h = 1, - .flags = AV_PIX_FMT_FLAG_HWACCEL, - }, -#endif [AV_PIX_FMT_RGB48BE] = { .name = "rgb48be", .nb_components = 3, @@ -1670,12 +1620,6 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { .log2_chroma_h = 1, .flags = AV_PIX_FMT_FLAG_HWACCEL, }, - [AV_PIX_FMT_VDA_VLD] = { - .name = "vda_vld", - .log2_chroma_w = 1, - .log2_chroma_h = 1, - .flags = AV_PIX_FMT_FLAG_HWACCEL, - }, [AV_PIX_FMT_YA8] = { .name = "ya8", .nb_components = 2, @@ -2029,10 +1973,6 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { }, .flags = AV_PIX_FMT_FLAG_PLANAR | AV_PIX_FMT_FLAG_BE, }, - [AV_PIX_FMT_VDA] = { - .name = "vda", - .flags = AV_PIX_FMT_FLAG_HWACCEL, - }, [AV_PIX_FMT_QSV] = { .name = "qsv", .flags = AV_PIX_FMT_FLAG_HWACCEL, @@ -2241,6 +2181,10 @@ static const AVPixFmtDescriptor av_pix_fmt_descriptors[AV_PIX_FMT_NB] = { .name = "drm_prime", .flags = AV_PIX_FMT_FLAG_HWACCEL, }, + [AV_PIX_FMT_OPENCL] = { + .name = "opencl", + .flags = AV_PIX_FMT_FLAG_HWACCEL, + }, }; #if FF_API_PLUS1_MINUS1 FF_ENABLE_DEPRECATION_WARNINGS diff --git a/libavutil/pixdesc.h b/libavutil/pixdesc.h index fc3737c4adee6..1ab372782ae19 100644 --- a/libavutil/pixdesc.h +++ b/libavutil/pixdesc.h @@ -154,6 +154,14 @@ typedef struct AVPixFmtDescriptor { * in some cases be simpler. Or the data can be interpreted purely based on * the pixel format without using the palette. * An example of a pseudo-paletted format is AV_PIX_FMT_GRAY8 + * + * @deprecated This flag is deprecated, and will be removed. When it is removed, + * the extra palette allocation in AVFrame.data[1] is removed as well. Only + * actual paletted formats (as indicated by AV_PIX_FMT_FLAG_PAL) will have a + * palette. Starting with FFmpeg versions which have this flag deprecated, the + * extra "pseudo" palette is already ignored, and API users are not required to + * allocate a palette for AV_PIX_FMT_FLAG_PSEUDOPAL formats (it was required + * before the deprecation, though). */ #define AV_PIX_FMT_FLAG_PSEUDOPAL (1 << 6) @@ -225,11 +233,6 @@ enum AVPixelFormat av_pix_fmt_desc_get_id(const AVPixFmtDescriptor *desc); * Utility function to access log2_chroma_w log2_chroma_h from * the pixel format AVPixFmtDescriptor. * - * See av_get_chroma_sub_sample() for a function that asserts a - * valid pixel format instead of returning an error code. - * Its recommended that you use avcodec_get_chroma_sub_sample unless - * you do check the return code! - * * @param[in] pix_fmt the pixel format * @param[out] h_shift store log2_chroma_w (horizontal/width shift) * @param[out] v_shift store log2_chroma_h (vertical/height shift) diff --git a/libavutil/pixfmt.h b/libavutil/pixfmt.h index 24889c8e5288c..e184a56672dc5 100644 --- a/libavutil/pixfmt.h +++ b/libavutil/pixfmt.h @@ -74,11 +74,6 @@ enum AVPixelFormat { AV_PIX_FMT_YUVJ420P, ///< planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV420P and setting color_range AV_PIX_FMT_YUVJ422P, ///< planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV422P and setting color_range AV_PIX_FMT_YUVJ444P, ///< planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV444P and setting color_range -#if FF_API_XVMC - AV_PIX_FMT_XVMC_MPEG2_MC,///< XVideo Motion Acceleration via common packet passing - AV_PIX_FMT_XVMC_MPEG2_IDCT, - AV_PIX_FMT_XVMC = AV_PIX_FMT_XVMC_MPEG2_IDCT, -#endif /* FF_API_XVMC */ AV_PIX_FMT_UYVY422, ///< packed YUV 4:2:2, 16bpp, Cb Y0 Cr Y1 AV_PIX_FMT_UYYVYY411, ///< packed YUV 4:1:1, 12bpp, Cb Y0 Y1 Cr Y2 Y3 AV_PIX_FMT_BGR8, ///< packed RGB 3:3:2, 8bpp, (msb)2B 3G 3R(lsb) @@ -100,13 +95,6 @@ enum AVPixelFormat { AV_PIX_FMT_YUV440P, ///< planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples) AV_PIX_FMT_YUVJ440P, ///< planar YUV 4:4:0 full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV440P and setting color_range AV_PIX_FMT_YUVA420P, ///< planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples) -#if FF_API_VDPAU - AV_PIX_FMT_VDPAU_H264,///< H.264 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers - AV_PIX_FMT_VDPAU_MPEG1,///< MPEG-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers - AV_PIX_FMT_VDPAU_MPEG2,///< MPEG-2 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers - AV_PIX_FMT_VDPAU_WMV3,///< WMV3 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers - AV_PIX_FMT_VDPAU_VC1, ///< VC-1 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers -#endif AV_PIX_FMT_RGB48BE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as big-endian AV_PIX_FMT_RGB48LE, ///< packed RGB 16:16:16, 48bpp, 16R, 16G, 16B, the 2-byte value for each R/G/B component is stored as little-endian @@ -142,9 +130,6 @@ enum AVPixelFormat { AV_PIX_FMT_YUV422P16BE, ///< planar YUV 4:2:2, 32bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian AV_PIX_FMT_YUV444P16LE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian AV_PIX_FMT_YUV444P16BE, ///< planar YUV 4:4:4, 48bpp, (1 Cr & Cb sample per 1x1 Y samples), big-endian -#if FF_API_VDPAU - AV_PIX_FMT_VDPAU_MPEG4, ///< MPEG-4 HW decoding with VDPAU, data[0] contains a vdpau_render_state struct which contains the bitstream of the slices as well as various fields extracted from headers -#endif AV_PIX_FMT_DXVA2_VLD, ///< HW decoding through DXVA2, Picture.data[3] contains a LPDIRECT3DSURFACE9 pointer AV_PIX_FMT_RGB444LE, ///< packed RGB 4:4:4, 16bpp, (msb)4X 4R 4G 4B(lsb), little-endian, X=unused/undefined @@ -176,7 +161,6 @@ enum AVPixelFormat { AV_PIX_FMT_YUV444P10LE,///< planar YUV 4:4:4, 30bpp, (1 Cr & Cb sample per 1x1 Y samples), little-endian AV_PIX_FMT_YUV422P9BE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), big-endian AV_PIX_FMT_YUV422P9LE, ///< planar YUV 4:2:2, 18bpp, (1 Cr & Cb sample per 2x1 Y samples), little-endian - AV_PIX_FMT_VDA_VLD, ///< hardware decoding through VDA AV_PIX_FMT_GBRP, ///< planar GBR 4:4:4 24bpp AV_PIX_FMT_GBR24P = AV_PIX_FMT_GBRP, // alias for #AV_PIX_FMT_GBRP AV_PIX_FMT_GBRP9BE, ///< planar GBR 4:4:4 27bpp, big-endian @@ -221,8 +205,6 @@ enum AVPixelFormat { AV_PIX_FMT_YVYU422, ///< packed YUV 4:2:2, 16bpp, Y0 Cr Y1 Cb - AV_PIX_FMT_VDA, ///< HW acceleration through VDA, data[3] contains a CVPixelBufferRef - AV_PIX_FMT_YA16BE, ///< 16 bits gray, 16 bits alpha (big-endian) AV_PIX_FMT_YA16LE, ///< 16 bits gray, 16 bits alpha (little-endian) @@ -248,7 +230,7 @@ enum AVPixelFormat { */ AV_PIX_FMT_CUDA, - AV_PIX_FMT_0RGB=0x123+4,///< packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined + AV_PIX_FMT_0RGB, ///< packed RGB 8:8:8, 32bpp, XRGBXRGB... X=unused/undefined AV_PIX_FMT_RGB0, ///< packed RGB 8:8:8, 32bpp, RGBXRGBX... X=unused/undefined AV_PIX_FMT_0BGR, ///< packed BGR 8:8:8, 32bpp, XBGRXBGR... X=unused/undefined AV_PIX_FMT_BGR0, ///< packed BGR 8:8:8, 32bpp, BGRXBGRX... X=unused/undefined @@ -283,9 +265,9 @@ enum AVPixelFormat { AV_PIX_FMT_BAYER_GBRG16BE, ///< bayer, GBGB..(odd line), RGRG..(even line), 16-bit samples, big-endian */ AV_PIX_FMT_BAYER_GRBG16LE, ///< bayer, GRGR..(odd line), BGBG..(even line), 16-bit samples, little-endian */ AV_PIX_FMT_BAYER_GRBG16BE, ///< bayer, GRGR..(odd line), BGBG..(even line), 16-bit samples, big-endian */ -#if !FF_API_XVMC + AV_PIX_FMT_XVMC,///< XVideo Motion Acceleration via common packet passing -#endif /* !FF_API_XVMC */ + AV_PIX_FMT_YUV440P10LE, ///< planar YUV 4:4:0,20bpp, (1 Cr & Cb sample per 1x2 Y samples), little-endian AV_PIX_FMT_YUV440P10BE, ///< planar YUV 4:4:0,20bpp, (1 Cr & Cb sample per 1x2 Y samples), big-endian AV_PIX_FMT_YUV440P12LE, ///< planar YUV 4:4:0,24bpp, (1 Cr & Cb sample per 1x2 Y samples), little-endian @@ -340,6 +322,13 @@ enum AVPixelFormat { * data[0] points to an AVDRMFrameDescriptor. */ AV_PIX_FMT_DRM_PRIME, + /** + * Hardware surfaces for OpenCL. + * + * data[i] contain 2D image objects (typed in C as cl_mem, used + * in OpenCL as image2d_t) for each plane of the surface. + */ + AV_PIX_FMT_OPENCL, AV_PIX_FMT_NB ///< number of pixel formats, DO NOT USE THIS if you want to link with shared libav* because the number of formats might differ between versions }; diff --git a/libavutil/ppc/cpu.h b/libavutil/ppc/cpu.h index 0744157c87ad2..36973a54ea0b3 100644 --- a/libavutil/ppc/cpu.h +++ b/libavutil/ppc/cpu.h @@ -19,7 +19,6 @@ #ifndef AVUTIL_PPC_CPU_H #define AVUTIL_PPC_CPU_H -#include "config.h" #include "libavutil/cpu.h" #include "libavutil/cpu_internal.h" diff --git a/libavutil/ppc/util_altivec.h b/libavutil/ppc/util_altivec.h index 6ab7e5083ff6b..2548011be53b9 100644 --- a/libavutil/ppc/util_altivec.h +++ b/libavutil/ppc/util_altivec.h @@ -28,10 +28,6 @@ #include "config.h" -#if HAVE_ALTIVEC_H -#include -#endif - /*********************************************************************** * Vector types **********************************************************************/ @@ -56,6 +52,7 @@ #define zero_s32v (vec_s32) zerov #if HAVE_ALTIVEC +#include // used to build registers permutation vectors (vcprm) // the 's' are for words in the _s_econd vector diff --git a/libavutil/random_seed.c b/libavutil/random_seed.c index d1c9a3f7046d7..70dc509d2fde6 100644 --- a/libavutil/random_seed.c +++ b/libavutil/random_seed.c @@ -26,9 +26,9 @@ #if HAVE_IO_H #include #endif -#if HAVE_CRYPTGENRANDOM +#if HAVE_BCRYPT #include -#include +#include #endif #include #include @@ -121,13 +121,14 @@ uint32_t av_get_random_seed(void) { uint32_t seed; -#if HAVE_CRYPTGENRANDOM - HCRYPTPROV provider; - if (CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, - CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { - BOOL ret = CryptGenRandom(provider, sizeof(seed), (PBYTE) &seed); - CryptReleaseContext(provider, 0); - if (ret) +#if HAVE_BCRYPT + BCRYPT_ALG_HANDLE algo_handle; + NTSTATUS ret = BCryptOpenAlgorithmProvider(&algo_handle, BCRYPT_RNG_ALGORITHM, + MS_PRIMITIVE_PROVIDER, 0); + if (BCRYPT_SUCCESS(ret)) { + NTSTATUS ret = BCryptGenRandom(algo_handle, (UCHAR*)&seed, sizeof(seed), 0); + BCryptCloseAlgorithmProvider(algo_handle, 0); + if (BCRYPT_SUCCESS(ret)) return seed; } #endif diff --git a/libavutil/ripemd.c b/libavutil/ripemd.c index b0db2970db8a8..4f1c4ea899fbe 100644 --- a/libavutil/ripemd.c +++ b/libavutil/ripemd.c @@ -510,7 +510,11 @@ av_cold int av_ripemd_init(AVRIPEMD *ctx, int bits) return 0; } +#if FF_API_CRYPTO_SIZE_T void av_ripemd_update(AVRIPEMD* ctx, const uint8_t* data, unsigned int len) +#else +void av_ripemd_update(AVRIPEMD* ctx, const uint8_t* data, size_t len) +#endif { unsigned int i, j; diff --git a/libavutil/ripemd.h b/libavutil/ripemd.h index 6d6bb3208f1fb..0db6858ff3321 100644 --- a/libavutil/ripemd.h +++ b/libavutil/ripemd.h @@ -66,7 +66,11 @@ int av_ripemd_init(struct AVRIPEMD* context, int bits); * @param data input data to update hash with * @param len input data length */ +#if FF_API_CRYPTO_SIZE_T void av_ripemd_update(struct AVRIPEMD* context, const uint8_t* data, unsigned int len); +#else +void av_ripemd_update(struct AVRIPEMD* context, const uint8_t* data, size_t len); +#endif /** * Finish hashing and output digest value. diff --git a/libavutil/slicethread.c b/libavutil/slicethread.c index c43f87a2aa4aa..dfbe551ef2062 100644 --- a/libavutil/slicethread.c +++ b/libavutil/slicethread.c @@ -99,10 +99,6 @@ int avpriv_slicethread_create(AVSliceThread **pctx, void *priv, AVSliceThread *ctx; int nb_workers, i; -#if HAVE_W32THREADS - w32thread_init(); -#endif - av_assert0(nb_threads >= 0); if (!nb_threads) { int nb_cpus = av_cpu_count(); diff --git a/libavutil/softfloat.h b/libavutil/softfloat.h index b13d728f30827..a651406f749d2 100644 --- a/libavutil/softfloat.h +++ b/libavutil/softfloat.h @@ -43,6 +43,7 @@ static const SoftFloat FLOAT_EPSILON = { 0x29F16B12, -16}; static const SoftFloat FLOAT_1584893192 = { 0x32B771ED, 1}; ///< 1.584893192 (10^.2) static const SoftFloat FLOAT_100000 = { 0x30D40000, 17}; ///< 100000 static const SoftFloat FLOAT_0999999 = { 0x3FFFFBCE, 0}; ///< 0.999999 +static const SoftFloat FLOAT_MIN = { 0x20000000, MIN_EXP}; /** diff --git a/libavutil/stereo3d.h b/libavutil/stereo3d.h index 54f4c4c5c7851..d421aac2a26b1 100644 --- a/libavutil/stereo3d.h +++ b/libavutil/stereo3d.h @@ -141,6 +141,25 @@ enum AVStereo3DType { AV_STEREO3D_COLUMNS, }; +/** + * List of possible view types. + */ +enum AVStereo3DView { + /** + * Frame contains two packed views. + */ + AV_STEREO3D_VIEW_PACKED, + + /** + * Frame contains only the left view. + */ + AV_STEREO3D_VIEW_LEFT, + + /** + * Frame contains only the right view. + */ + AV_STEREO3D_VIEW_RIGHT, +}; /** * Inverted views, Right/Bottom represents the left view. @@ -164,6 +183,11 @@ typedef struct AVStereo3D { * Additional information about the frame packing. */ int flags; + + /** + * Determines which views are packed. + */ + enum AVStereo3DView view; } AVStereo3D; /** diff --git a/libavutil/tests/aes_ctr.c b/libavutil/tests/aes_ctr.c index c5ebeda7ac209..00fdb05d13a01 100644 --- a/libavutil/tests/aes_ctr.c +++ b/libavutil/tests/aes_ctr.c @@ -45,7 +45,7 @@ int main (void) av_aes_ctr_set_random_iv(ae); iv = av_aes_ctr_get_iv(ae); - av_aes_ctr_set_iv(ad, iv); + av_aes_ctr_set_full_iv(ad, iv); av_aes_ctr_crypt(ae, tmp, plain, sizeof(tmp)); av_aes_ctr_crypt(ad, tmp, tmp, sizeof(tmp)); diff --git a/libavutil/tests/cpu.c b/libavutil/tests/cpu.c index f02a54cbbb146..ce45b715a0d77 100644 --- a/libavutil/tests/cpu.c +++ b/libavutil/tests/cpu.c @@ -73,6 +73,7 @@ static const struct { { AV_CPU_FLAG_BMI1, "bmi1" }, { AV_CPU_FLAG_BMI2, "bmi2" }, { AV_CPU_FLAG_AESNI, "aesni" }, + { AV_CPU_FLAG_AVX512, "avx512" }, #endif { 0 } }; diff --git a/libavutil/tests/crc.c b/libavutil/tests/crc.c index 9825d6bec9014..413aada8a2eb2 100644 --- a/libavutil/tests/crc.c +++ b/libavutil/tests/crc.c @@ -25,20 +25,21 @@ int main(void) { uint8_t buf[1999]; int i; - static const unsigned p[6][3] = { + static const unsigned p[7][3] = { { AV_CRC_32_IEEE_LE, 0xEDB88320, 0x3D5CDD04 }, { AV_CRC_32_IEEE , 0x04C11DB7, 0xC0F5BAE0 }, { AV_CRC_24_IEEE , 0x864CFB , 0xB704CE }, { AV_CRC_16_ANSI_LE, 0xA001 , 0xBFD8 }, { AV_CRC_16_ANSI , 0x8005 , 0x1FBB }, - { AV_CRC_8_ATM , 0x07 , 0xE3 } + { AV_CRC_8_ATM , 0x07 , 0xE3 }, + { AV_CRC_8_EBU , 0x1D , 0xD6 }, }; const AVCRC *ctx; for (i = 0; i < sizeof(buf); i++) buf[i] = i + i * i; - for (i = 0; i < 6; i++) { + for (i = 0; i < 7; i++) { ctx = av_crc_get_table(p[i][0]); printf("crc %08X = %X\n", p[i][1], av_crc(ctx, 0, buf, sizeof(buf))); } diff --git a/libavutil/tests/hmac.c b/libavutil/tests/hmac.c index 5eeb63ce057b9..0fa50e4570891 100644 --- a/libavutil/tests/hmac.c +++ b/libavutil/tests/hmac.c @@ -70,7 +70,7 @@ int main(void) } /* SHA-2 */ - for (i = AV_HMAC_SHA224; i <= AV_HMAC_SHA256; i++) { + for (i = AV_HMAC_SHA224; i <= AV_HMAC_SHA512; i++) { hmac = av_hmac_alloc(i); if (!hmac) return 1; @@ -83,17 +83,5 @@ int main(void) av_hmac_free(hmac); } - for (i = AV_HMAC_SHA384; i <= AV_HMAC_SHA512; i++) { - hmac = av_hmac_alloc(i); - if (!hmac) - return 1; - // RFC 4231 test vectors - test(hmac, key1, sizeof(key1), data1, sizeof(data1)); - test(hmac, key2, sizeof(key2), data2, sizeof(data2)); - test(hmac, key3, 20, data3, sizeof(data3)); - test(hmac, key3, sizeof(key3), data4, sizeof(data4)); - test(hmac, key3, sizeof(key3), data6, sizeof(data6)); - av_hmac_free(hmac); - } return 0; } diff --git a/libavutil/tests/integer.c b/libavutil/tests/integer.c new file mode 100644 index 0000000000000..d2c8f2a903de0 --- /dev/null +++ b/libavutil/tests/integer.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2004 Michael Niedermayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +#include "libavutil/avassert.h" +#include "libavutil/integer.h" +#include "libavutil/intmath.h" + +int main(void){ + int64_t a,b; + + for(a=7; a<256*256*256; a+=13215){ + for(b=3; b<256*256*256; b+=27118){ + AVInteger ai= av_int2i(a); + AVInteger bi= av_int2i(b); + + av_assert0(av_i2int(ai) == a); + av_assert0(av_i2int(bi) == b); + av_assert0(av_i2int(av_add_i(ai,bi)) == a+b); + av_assert0(av_i2int(av_sub_i(ai,bi)) == a-b); + av_assert0(av_i2int(av_mul_i(ai,bi)) == a*b); + av_assert0(av_i2int(av_shr_i(ai, 9)) == a>>9); + av_assert0(av_i2int(av_shr_i(ai,-9)) == a<<9); + av_assert0(av_i2int(av_shr_i(ai, 17)) == a>>17); + av_assert0(av_i2int(av_shr_i(ai,-17)) == a<<17); + av_assert0(av_log2_i(ai) == av_log2(a)); + av_assert0(av_i2int(av_div_i(ai,bi)) == a/b); + } + } + return 0; +} diff --git a/libavutil/tests/opt.c b/libavutil/tests/opt.c index 568eb456683b3..f4cfa590aa9a0 100644 --- a/libavutil/tests/opt.c +++ b/libavutil/tests/opt.c @@ -98,9 +98,9 @@ static const char *test_get_name(void *ctx) } static const AVClass test_class = { - "TestContext", - test_get_name, - test_options + .class_name = "TestContext", + .item_name = test_get_name, + .option = test_options, }; static void log_callback_help(void *ptr, int level, const char *fmt, va_list vl) diff --git a/libavutil/thread.h b/libavutil/thread.h index f108e2005269f..cc5272d379345 100644 --- a/libavutil/thread.h +++ b/libavutil/thread.h @@ -134,6 +134,7 @@ static inline int strict_pthread_once(pthread_once_t *once_control, void (*init_ #endif #define AVMutex pthread_mutex_t +#define AV_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER #define ff_mutex_init pthread_mutex_init #define ff_mutex_lock pthread_mutex_lock @@ -148,11 +149,12 @@ static inline int strict_pthread_once(pthread_once_t *once_control, void (*init_ #else #define AVMutex char +#define AV_MUTEX_INITIALIZER 0 -#define ff_mutex_init(mutex, attr) (0) -#define ff_mutex_lock(mutex) (0) -#define ff_mutex_unlock(mutex) (0) -#define ff_mutex_destroy(mutex) (0) +static inline int ff_mutex_init(AVMutex *mutex, const void *attr){ return 0; } +static inline int ff_mutex_lock(AVMutex *mutex){ return 0; } +static inline int ff_mutex_unlock(AVMutex *mutex){ return 0; } +static inline int ff_mutex_destroy(AVMutex *mutex){ return 0; } #define AVOnce char #define AV_ONCE_INIT 0 diff --git a/libavutil/timecode.c b/libavutil/timecode.c index c0c67c8478689..60077ba0c0440 100644 --- a/libavutil/timecode.c +++ b/libavutil/timecode.c @@ -155,7 +155,7 @@ static int check_fps(int fps) static int check_timecode(void *log_ctx, AVTimecode *tc) { if ((int)tc->fps <= 0) { - av_log(log_ctx, AV_LOG_ERROR, "Timecode frame rate must be specified\n"); + av_log(log_ctx, AV_LOG_ERROR, "Valid timecode frame rate must be specified. Minimum value is 1\n"); return AVERROR(EINVAL); } if ((tc->flags & AV_TIMECODE_FLAG_DROPFRAME) && tc->fps != 30 && tc->fps != 60) { @@ -214,7 +214,7 @@ int av_timecode_init_from_string(AVTimecode *tc, AVRational rate, const char *st tc->start = (hh*3600 + mm*60 + ss) * tc->fps + ff; if (tc->flags & AV_TIMECODE_FLAG_DROPFRAME) { /* adjust frame number */ int tmins = 60*hh + mm; - tc->start -= 2 * (tmins - tmins/10); + tc->start -= (tc->fps == 30 ? 2 : 4) * (tmins - tmins/10); } return 0; } diff --git a/libavutil/timer.h b/libavutil/timer.h index f7ab455df22fe..0bb353cfcefd1 100644 --- a/libavutil/timer.h +++ b/libavutil/timer.h @@ -42,7 +42,7 @@ #include #include -#if HAVE_MACH_MACH_TIME_H +#if HAVE_MACH_ABSOLUTE_TIME #include #endif diff --git a/libavutil/utils.c b/libavutil/utils.c index 2c170db2e10db..230081ea475fb 100644 --- a/libavutil/utils.c +++ b/libavutil/utils.c @@ -41,9 +41,6 @@ unsigned avutil_version(void) if (checks_done) return LIBAVUTIL_VERSION_INT; -#if FF_API_VDPAU - av_assert0(AV_PIX_FMT_VDA_VLD == 81); //check if the pix fmt enum has not had anything inserted or removed by mistake -#endif av_assert0(AV_SAMPLE_FMT_DBLP == 9); av_assert0(AVMEDIA_TYPE_ATTACHMENT == 4); av_assert0(AV_PICTURE_TYPE_BI == 7); diff --git a/libavutil/version.h b/libavutil/version.h index f594dc069185f..3a63e6355f84a 100644 --- a/libavutil/version.h +++ b/libavutil/version.h @@ -78,9 +78,8 @@ * @{ */ - -#define LIBAVUTIL_VERSION_MAJOR 55 -#define LIBAVUTIL_VERSION_MINOR 78 +#define LIBAVUTIL_VERSION_MAJOR 56 +#define LIBAVUTIL_VERSION_MINOR 14 #define LIBAVUTIL_VERSION_MICRO 100 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \ @@ -106,38 +105,29 @@ * @{ */ -#ifndef FF_API_VDPAU -#define FF_API_VDPAU (LIBAVUTIL_VERSION_MAJOR < 56) -#endif -#ifndef FF_API_XVMC -#define FF_API_XVMC (LIBAVUTIL_VERSION_MAJOR < 56) -#endif -#ifndef FF_API_OPT_TYPE_METADATA -#define FF_API_OPT_TYPE_METADATA (LIBAVUTIL_VERSION_MAJOR < 56) -#endif -#ifndef FF_API_DLOG -#define FF_API_DLOG (LIBAVUTIL_VERSION_MAJOR < 56) -#endif #ifndef FF_API_VAAPI -#define FF_API_VAAPI (LIBAVUTIL_VERSION_MAJOR < 56) +#define FF_API_VAAPI (LIBAVUTIL_VERSION_MAJOR < 57) #endif #ifndef FF_API_FRAME_QP -#define FF_API_FRAME_QP (LIBAVUTIL_VERSION_MAJOR < 56) +#define FF_API_FRAME_QP (LIBAVUTIL_VERSION_MAJOR < 57) #endif #ifndef FF_API_PLUS1_MINUS1 -#define FF_API_PLUS1_MINUS1 (LIBAVUTIL_VERSION_MAJOR < 56) +#define FF_API_PLUS1_MINUS1 (LIBAVUTIL_VERSION_MAJOR < 57) #endif #ifndef FF_API_ERROR_FRAME -#define FF_API_ERROR_FRAME (LIBAVUTIL_VERSION_MAJOR < 56) -#endif -#ifndef FF_API_CRC_BIG_TABLE -#define FF_API_CRC_BIG_TABLE (LIBAVUTIL_VERSION_MAJOR < 56) +#define FF_API_ERROR_FRAME (LIBAVUTIL_VERSION_MAJOR < 57) #endif #ifndef FF_API_PKT_PTS -#define FF_API_PKT_PTS (LIBAVUTIL_VERSION_MAJOR < 56) +#define FF_API_PKT_PTS (LIBAVUTIL_VERSION_MAJOR < 57) #endif #ifndef FF_API_CRYPTO_SIZE_T -#define FF_API_CRYPTO_SIZE_T (LIBAVUTIL_VERSION_MAJOR < 56) +#define FF_API_CRYPTO_SIZE_T (LIBAVUTIL_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_FRAME_GET_SET +#define FF_API_FRAME_GET_SET (LIBAVUTIL_VERSION_MAJOR < 57) +#endif +#ifndef FF_API_PSEUDOPAL +#define FF_API_PSEUDOPAL (LIBAVUTIL_VERSION_MAJOR < 57) #endif diff --git a/libavutil/wchar_filename.h b/libavutil/wchar_filename.h index 2ade321bedd97..142d50e7c3c91 100644 --- a/libavutil/wchar_filename.h +++ b/libavutil/wchar_filename.h @@ -19,7 +19,7 @@ #ifndef AVUTIL_WCHAR_FILENAME_H #define AVUTIL_WCHAR_FILENAME_H -#if defined(_WIN32) && !defined(__MINGW32CE__) +#ifdef _WIN32 #include #include "mem.h" diff --git a/libavutil/x86/cpu.c b/libavutil/x86/cpu.c index f33088c8c7385..aca893174ea41 100644 --- a/libavutil/x86/cpu.c +++ b/libavutil/x86/cpu.c @@ -97,6 +97,7 @@ int ff_get_cpu_flags_x86(void) int max_std_level, max_ext_level, std_caps = 0, ext_caps = 0; int family = 0, model = 0; union { int i[3]; char c[12]; } vendor; + int xcr0_lo = 0, xcr0_hi = 0; if (!cpuid_test()) return 0; /* CPUID not supported */ @@ -132,8 +133,8 @@ int ff_get_cpu_flags_x86(void) /* Check OXSAVE and AVX bits */ if ((ecx & 0x18000000) == 0x18000000) { /* Check for OS support */ - xgetbv(0, eax, edx); - if ((eax & 0x6) == 0x6) { + xgetbv(0, xcr0_lo, xcr0_hi); + if ((xcr0_lo & 0x6) == 0x6) { rval |= AV_CPU_FLAG_AVX; if (ecx & 0x00001000) rval |= AV_CPU_FLAG_FMA3; @@ -147,6 +148,13 @@ int ff_get_cpu_flags_x86(void) #if HAVE_AVX2 if ((rval & AV_CPU_FLAG_AVX) && (ebx & 0x00000020)) rval |= AV_CPU_FLAG_AVX2; +#if HAVE_AVX512 /* F, CD, BW, DQ, VL */ + if ((xcr0_lo & 0xe0) == 0xe0) { /* OPMASK/ZMM state */ + if ((rval & AV_CPU_FLAG_AVX2) && (ebx & 0xd0030000) == 0xd0030000) + rval |= AV_CPU_FLAG_AVX512; + + } +#endif /* HAVE_AVX512 */ #endif /* HAVE_AVX2 */ /* BMI1/2 don't need OS support */ if (ebx & 0x00000008) { @@ -238,6 +246,8 @@ size_t ff_get_cpu_max_align_x86(void) { int flags = av_get_cpu_flags(); + if (flags & AV_CPU_FLAG_AVX512) + return 64; if (flags & (AV_CPU_FLAG_AVX2 | AV_CPU_FLAG_AVX | AV_CPU_FLAG_XOP | diff --git a/libavutil/x86/cpu.h b/libavutil/x86/cpu.h index 309b8e746c56e..937c697fa0ea2 100644 --- a/libavutil/x86/cpu.h +++ b/libavutil/x86/cpu.h @@ -19,7 +19,6 @@ #ifndef AVUTIL_X86_CPU_H #define AVUTIL_X86_CPU_H -#include "config.h" #include "libavutil/cpu.h" #include "libavutil/cpu_internal.h" @@ -50,6 +49,7 @@ #define X86_FMA4(flags) CPUEXT(flags, FMA4) #define X86_AVX2(flags) CPUEXT(flags, AVX2) #define X86_AESNI(flags) CPUEXT(flags, AESNI) +#define X86_AVX512(flags) CPUEXT(flags, AVX512) #define EXTERNAL_AMD3DNOW(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, AMD3DNOW) #define EXTERNAL_AMD3DNOWEXT(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, AMD3DNOWEXT) @@ -79,6 +79,7 @@ #define EXTERNAL_AVX2_FAST(flags) CPUEXT_SUFFIX_FAST2(flags, _EXTERNAL, AVX2, AVX) #define EXTERNAL_AVX2_SLOW(flags) CPUEXT_SUFFIX_SLOW2(flags, _EXTERNAL, AVX2, AVX) #define EXTERNAL_AESNI(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, AESNI) +#define EXTERNAL_AVX512(flags) CPUEXT_SUFFIX(flags, _EXTERNAL, AVX512) #define INLINE_AMD3DNOW(flags) CPUEXT_SUFFIX(flags, _INLINE, AMD3DNOW) #define INLINE_AMD3DNOWEXT(flags) CPUEXT_SUFFIX(flags, _INLINE, AMD3DNOWEXT) diff --git a/libavutil/x86/intmath.h b/libavutil/x86/intmath.h index e83971c084ce5..40743fd13ef22 100644 --- a/libavutil/x86/intmath.h +++ b/libavutil/x86/intmath.h @@ -47,7 +47,8 @@ static av_always_inline av_const int ff_log2_x86(unsigned int v) # endif # define ff_log2_16bit av_log2 -#if defined(__INTEL_COMPILER) || (defined(_MSC_VER) && (_MSC_VER >= 1700)) +#if defined(__INTEL_COMPILER) || (defined(_MSC_VER) && (_MSC_VER >= 1700) && \ + (defined(__BMI__) || !defined(__clang__))) # define ff_ctz(v) _tzcnt_u32(v) # if ARCH_X86_64 diff --git a/libavutil/x86/x86inc.asm b/libavutil/x86/x86inc.asm index 6a054a3e0925a..5044ee86f0d99 100644 --- a/libavutil/x86/x86inc.asm +++ b/libavutil/x86/x86inc.asm @@ -1,12 +1,12 @@ ;***************************************************************************** ;* x86inc.asm: x264asm abstraction layer ;***************************************************************************** -;* Copyright (C) 2005-2017 x264 project +;* Copyright (C) 2005-2018 x264 project ;* ;* Authors: Loren Merritt +;* Henrik Gramner ;* Anton Mitrofanov ;* Fiona Glaser -;* Henrik Gramner ;* ;* Permission to use, copy, modify, and/or distribute this software for any ;* purpose with or without fee is hereby granted, provided that the above @@ -90,6 +90,10 @@ SECTION .text %elifidn __OUTPUT_FORMAT__,coff SECTION .text + %elifidn __OUTPUT_FORMAT__,win32 + SECTION .rdata align=%1 + %elif WIN64 + SECTION .rdata align=%1 %else SECTION .rodata align=%1 %endif @@ -337,6 +341,8 @@ DECLARE_REG_TMP_SIZE 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 %endmacro %define required_stack_alignment ((mmsize + 15) & ~15) +%define vzeroupper_required (mmsize > 16 && (ARCH_X86_64 == 0 || xmm_regs_used > 16 || notcpuflag(avx512))) +%define high_mm_regs (16*cpuflag(avx512)) %macro ALLOC_STACK 1-2 0 ; stack_size, n_xmm_regs (for win64 only) %ifnum %1 @@ -450,15 +456,16 @@ DECLARE_REG 14, R13, 120 %macro WIN64_PUSH_XMM 0 ; Use the shadow space to store XMM6 and XMM7, the rest needs stack space allocated. - %if xmm_regs_used > 6 + %if xmm_regs_used > 6 + high_mm_regs movaps [rstk + stack_offset + 8], xmm6 %endif - %if xmm_regs_used > 7 + %if xmm_regs_used > 7 + high_mm_regs movaps [rstk + stack_offset + 24], xmm7 %endif - %if xmm_regs_used > 8 + %assign %%xmm_regs_on_stack xmm_regs_used - high_mm_regs - 8 + %if %%xmm_regs_on_stack > 0 %assign %%i 8 - %rep xmm_regs_used-8 + %rep %%xmm_regs_on_stack movaps [rsp + (%%i-8)*16 + stack_size + 32], xmm %+ %%i %assign %%i %%i+1 %endrep @@ -467,10 +474,11 @@ DECLARE_REG 14, R13, 120 %macro WIN64_SPILL_XMM 1 %assign xmm_regs_used %1 - ASSERT xmm_regs_used <= 16 - %if xmm_regs_used > 8 + ASSERT xmm_regs_used <= 16 + high_mm_regs + %assign %%xmm_regs_on_stack xmm_regs_used - high_mm_regs - 8 + %if %%xmm_regs_on_stack > 0 ; Allocate stack space for callee-saved xmm registers plus shadow space and align the stack. - %assign %%pad (xmm_regs_used-8)*16 + 32 + %assign %%pad %%xmm_regs_on_stack*16 + 32 %assign stack_size_padded %%pad + ((-%%pad-stack_offset-gprsize) & (STACK_ALIGNMENT-1)) SUB rsp, stack_size_padded %endif @@ -479,9 +487,10 @@ DECLARE_REG 14, R13, 120 %macro WIN64_RESTORE_XMM_INTERNAL 0 %assign %%pad_size 0 - %if xmm_regs_used > 8 - %assign %%i xmm_regs_used - %rep xmm_regs_used-8 + %assign %%xmm_regs_on_stack xmm_regs_used - high_mm_regs - 8 + %if %%xmm_regs_on_stack > 0 + %assign %%i xmm_regs_used - high_mm_regs + %rep %%xmm_regs_on_stack %assign %%i %%i-1 movaps xmm %+ %%i, [rsp + (%%i-8)*16 + stack_size + 32] %endrep @@ -494,10 +503,10 @@ DECLARE_REG 14, R13, 120 %assign %%pad_size stack_size_padded %endif %endif - %if xmm_regs_used > 7 + %if xmm_regs_used > 7 + high_mm_regs movaps xmm7, [rsp + stack_offset - %%pad_size + 24] %endif - %if xmm_regs_used > 6 + %if xmm_regs_used > 6 + high_mm_regs movaps xmm6, [rsp + stack_offset - %%pad_size + 8] %endif %endmacro @@ -509,12 +518,12 @@ DECLARE_REG 14, R13, 120 %assign xmm_regs_used 0 %endmacro -%define has_epilogue regs_used > 7 || xmm_regs_used > 6 || mmsize == 32 || stack_size > 0 +%define has_epilogue regs_used > 7 || stack_size > 0 || vzeroupper_required || xmm_regs_used > 6+high_mm_regs %macro RET 0 WIN64_RESTORE_XMM_INTERNAL POP_IF_USED 14, 13, 12, 11, 10, 9, 8, 7 - %if mmsize == 32 + %if vzeroupper_required vzeroupper %endif AUTO_REP_RET @@ -538,9 +547,10 @@ DECLARE_REG 12, R15, 56 DECLARE_REG 13, R12, 64 DECLARE_REG 14, R13, 72 -%macro PROLOGUE 2-5+ ; #args, #regs, #xmm_regs, [stack_size,] arg_names... +%macro PROLOGUE 2-5+ 0 ; #args, #regs, #xmm_regs, [stack_size,] arg_names... %assign num_args %1 %assign regs_used %2 + %assign xmm_regs_used %3 ASSERT regs_used >= num_args SETUP_STACK_POINTER %4 ASSERT regs_used <= 15 @@ -550,7 +560,7 @@ DECLARE_REG 14, R13, 72 DEFINE_ARGS_INTERNAL %0, %4, %5 %endmacro -%define has_epilogue regs_used > 9 || mmsize == 32 || stack_size > 0 +%define has_epilogue regs_used > 9 || stack_size > 0 || vzeroupper_required %macro RET 0 %if stack_size_padded > 0 @@ -561,7 +571,7 @@ DECLARE_REG 14, R13, 72 %endif %endif POP_IF_USED 14, 13, 12, 11, 10, 9 - %if mmsize == 32 + %if vzeroupper_required vzeroupper %endif AUTO_REP_RET @@ -606,7 +616,7 @@ DECLARE_ARG 7, 8, 9, 10, 11, 12, 13, 14 DEFINE_ARGS_INTERNAL %0, %4, %5 %endmacro -%define has_epilogue regs_used > 3 || mmsize == 32 || stack_size > 0 +%define has_epilogue regs_used > 3 || stack_size > 0 || vzeroupper_required %macro RET 0 %if stack_size_padded > 0 @@ -617,7 +627,7 @@ DECLARE_ARG 7, 8, 9, 10, 11, 12, 13, 14 %endif %endif POP_IF_USED 6, 5, 4, 3 - %if mmsize == 32 + %if vzeroupper_required vzeroupper %endif AUTO_REP_RET @@ -727,12 +737,22 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %assign stack_offset 0 ; stack pointer offset relative to the return address %assign stack_size 0 ; amount of stack space that can be freely used inside a function %assign stack_size_padded 0 ; total amount of allocated stack space, including space for callee-saved xmm registers on WIN64 and alignment padding - %assign xmm_regs_used 0 ; number of XMM registers requested, used for dealing with callee-saved registers on WIN64 + %assign xmm_regs_used 0 ; number of XMM registers requested, used for dealing with callee-saved registers on WIN64 and vzeroupper %ifnidn %3, "" PROLOGUE %3 %endif %endmacro +; Create a global symbol from a local label with the correct name mangling and type +%macro cglobal_label 1 + %if FORMAT_ELF + global current_function %+ %1:function hidden + %else + global current_function %+ %1 + %endif + %1: +%endmacro + %macro cextern 1 %xdefine %1 mangle(private_prefix %+ _ %+ %1) CAT_XDEFINE cglobaled_, %1, 1 @@ -803,10 +823,10 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %assign cpuflags_bmi1 (1<<17)| cpuflags_avx|cpuflags_lzcnt %assign cpuflags_bmi2 (1<<18)| cpuflags_bmi1 %assign cpuflags_avx2 (1<<19)| cpuflags_fma3|cpuflags_bmi2 +%assign cpuflags_avx512 (1<<20)| cpuflags_avx2 ; F, CD, BW, DQ, VL -%assign cpuflags_cache32 (1<<20) -%assign cpuflags_cache64 (1<<21) -%assign cpuflags_slowctz (1<<22) +%assign cpuflags_cache32 (1<<21) +%assign cpuflags_cache64 (1<<22) %assign cpuflags_aligned (1<<23) ; not a cpu feature, but a function variant %assign cpuflags_atom (1<<24) @@ -856,11 +876,12 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %endif %endmacro -; Merge mmx and sse* +; Merge mmx, sse*, and avx* ; m# is a simd register of the currently selected size ; xm# is the corresponding xmm register if mmsize >= 16, otherwise the same as m# ; ym# is the corresponding ymm register if mmsize >= 32, otherwise the same as m# -; (All 3 remain in sync through SWAP.) +; zm# is the corresponding zmm register if mmsize >= 64, otherwise the same as m# +; (All 4 remain in sync through SWAP.) %macro CAT_XDEFINE 3 %xdefine %1%2 %3 @@ -870,69 +891,99 @@ BRANCH_INSTR jz, je, jnz, jne, jl, jle, jnl, jnle, jg, jge, jng, jnge, ja, jae, %undef %1%2 %endmacro +%macro DEFINE_MMREGS 1 ; mmtype + %assign %%prev_mmregs 0 + %ifdef num_mmregs + %assign %%prev_mmregs num_mmregs + %endif + + %assign num_mmregs 8 + %if ARCH_X86_64 && mmsize >= 16 + %assign num_mmregs 16 + %if cpuflag(avx512) || mmsize == 64 + %assign num_mmregs 32 + %endif + %endif + + %assign %%i 0 + %rep num_mmregs + CAT_XDEFINE m, %%i, %1 %+ %%i + CAT_XDEFINE nn%1, %%i, %%i + %assign %%i %%i+1 + %endrep + %if %%prev_mmregs > num_mmregs + %rep %%prev_mmregs - num_mmregs + CAT_UNDEF m, %%i + CAT_UNDEF nn %+ mmtype, %%i + %assign %%i %%i+1 + %endrep + %endif + %xdefine mmtype %1 +%endmacro + +; Prefer registers 16-31 over 0-15 to avoid having to use vzeroupper +%macro AVX512_MM_PERMUTATION 0-1 0 ; start_reg + %if ARCH_X86_64 && cpuflag(avx512) + %assign %%i %1 + %rep 16-%1 + %assign %%i_high %%i+16 + SWAP %%i, %%i_high + %assign %%i %%i+1 + %endrep + %endif +%endmacro + %macro INIT_MMX 0-1+ %assign avx_enabled 0 %define RESET_MM_PERMUTATION INIT_MMX %1 %define mmsize 8 - %define num_mmregs 8 %define mova movq %define movu movq %define movh movd %define movnta movntq - %assign %%i 0 - %rep 8 - CAT_XDEFINE m, %%i, mm %+ %%i - CAT_XDEFINE nnmm, %%i, %%i - %assign %%i %%i+1 - %endrep - %rep 8 - CAT_UNDEF m, %%i - CAT_UNDEF nnmm, %%i - %assign %%i %%i+1 - %endrep INIT_CPUFLAGS %1 + DEFINE_MMREGS mm %endmacro %macro INIT_XMM 0-1+ %assign avx_enabled 0 %define RESET_MM_PERMUTATION INIT_XMM %1 %define mmsize 16 - %define num_mmregs 8 - %if ARCH_X86_64 - %define num_mmregs 16 - %endif %define mova movdqa %define movu movdqu %define movh movq %define movnta movntdq - %assign %%i 0 - %rep num_mmregs - CAT_XDEFINE m, %%i, xmm %+ %%i - CAT_XDEFINE nnxmm, %%i, %%i - %assign %%i %%i+1 - %endrep INIT_CPUFLAGS %1 + DEFINE_MMREGS xmm + %if WIN64 + AVX512_MM_PERMUTATION 6 ; Swap callee-saved registers with volatile registers + %endif %endmacro %macro INIT_YMM 0-1+ %assign avx_enabled 1 %define RESET_MM_PERMUTATION INIT_YMM %1 %define mmsize 32 - %define num_mmregs 8 - %if ARCH_X86_64 - %define num_mmregs 16 - %endif %define mova movdqa %define movu movdqu %undef movh %define movnta movntdq - %assign %%i 0 - %rep num_mmregs - CAT_XDEFINE m, %%i, ymm %+ %%i - CAT_XDEFINE nnymm, %%i, %%i - %assign %%i %%i+1 - %endrep INIT_CPUFLAGS %1 + DEFINE_MMREGS ymm + AVX512_MM_PERMUTATION +%endmacro + +%macro INIT_ZMM 0-1+ + %assign avx_enabled 1 + %define RESET_MM_PERMUTATION INIT_ZMM %1 + %define mmsize 64 + %define mova movdqa + %define movu movdqu + %undef movh + %define movnta movntdq + INIT_CPUFLAGS %1 + DEFINE_MMREGS zmm + AVX512_MM_PERMUTATION %endmacro INIT_XMM @@ -941,18 +992,26 @@ INIT_XMM %define mmmm%1 mm%1 %define mmxmm%1 mm%1 %define mmymm%1 mm%1 + %define mmzmm%1 mm%1 %define xmmmm%1 mm%1 %define xmmxmm%1 xmm%1 %define xmmymm%1 xmm%1 + %define xmmzmm%1 xmm%1 %define ymmmm%1 mm%1 %define ymmxmm%1 xmm%1 %define ymmymm%1 ymm%1 + %define ymmzmm%1 ymm%1 + %define zmmmm%1 mm%1 + %define zmmxmm%1 xmm%1 + %define zmmymm%1 ymm%1 + %define zmmzmm%1 zmm%1 %define xm%1 xmm %+ m%1 %define ym%1 ymm %+ m%1 + %define zm%1 zmm %+ m%1 %endmacro %assign i 0 -%rep 16 +%rep 32 DECLARE_MMCAST i %assign i i+1 %endrep @@ -1087,12 +1146,17 @@ INIT_XMM ;============================================================================= %assign i 0 -%rep 16 +%rep 32 %if i < 8 CAT_XDEFINE sizeofmm, i, 8 + CAT_XDEFINE regnumofmm, i, i %endif CAT_XDEFINE sizeofxmm, i, 16 CAT_XDEFINE sizeofymm, i, 32 + CAT_XDEFINE sizeofzmm, i, 64 + CAT_XDEFINE regnumofxmm, i, i + CAT_XDEFINE regnumofymm, i, i + CAT_XDEFINE regnumofzmm, i, i %assign i i+1 %endrep %undef i @@ -1209,7 +1273,7 @@ INIT_XMM %endmacro %endmacro -; Instructions with both VEX and non-VEX encodings +; Instructions with both VEX/EVEX and legacy encodings ; Non-destructive instructions are written without parameters AVX_INSTR addpd, sse2, 1, 0, 1 AVX_INSTR addps, sse, 1, 0, 1 @@ -1231,10 +1295,42 @@ AVX_INSTR blendpd, sse4, 1, 1, 0 AVX_INSTR blendps, sse4, 1, 1, 0 AVX_INSTR blendvpd, sse4 ; can't be emulated AVX_INSTR blendvps, sse4 ; can't be emulated +AVX_INSTR cmpeqpd, sse2, 1, 0, 1 +AVX_INSTR cmpeqps, sse, 1, 0, 1 +AVX_INSTR cmpeqsd, sse2, 1, 0, 0 +AVX_INSTR cmpeqss, sse, 1, 0, 0 +AVX_INSTR cmplepd, sse2, 1, 0, 0 +AVX_INSTR cmpleps, sse, 1, 0, 0 +AVX_INSTR cmplesd, sse2, 1, 0, 0 +AVX_INSTR cmpless, sse, 1, 0, 0 +AVX_INSTR cmpltpd, sse2, 1, 0, 0 +AVX_INSTR cmpltps, sse, 1, 0, 0 +AVX_INSTR cmpltsd, sse2, 1, 0, 0 +AVX_INSTR cmpltss, sse, 1, 0, 0 +AVX_INSTR cmpneqpd, sse2, 1, 0, 1 +AVX_INSTR cmpneqps, sse, 1, 0, 1 +AVX_INSTR cmpneqsd, sse2, 1, 0, 0 +AVX_INSTR cmpneqss, sse, 1, 0, 0 +AVX_INSTR cmpnlepd, sse2, 1, 0, 0 +AVX_INSTR cmpnleps, sse, 1, 0, 0 +AVX_INSTR cmpnlesd, sse2, 1, 0, 0 +AVX_INSTR cmpnless, sse, 1, 0, 0 +AVX_INSTR cmpnltpd, sse2, 1, 0, 0 +AVX_INSTR cmpnltps, sse, 1, 0, 0 +AVX_INSTR cmpnltsd, sse2, 1, 0, 0 +AVX_INSTR cmpnltss, sse, 1, 0, 0 +AVX_INSTR cmpordpd, sse2 1, 0, 1 +AVX_INSTR cmpordps, sse 1, 0, 1 +AVX_INSTR cmpordsd, sse2 1, 0, 0 +AVX_INSTR cmpordss, sse 1, 0, 0 AVX_INSTR cmppd, sse2, 1, 1, 0 AVX_INSTR cmpps, sse, 1, 1, 0 AVX_INSTR cmpsd, sse2, 1, 1, 0 AVX_INSTR cmpss, sse, 1, 1, 0 +AVX_INSTR cmpunordpd, sse2, 1, 0, 1 +AVX_INSTR cmpunordps, sse, 1, 0, 1 +AVX_INSTR cmpunordsd, sse2, 1, 0, 0 +AVX_INSTR cmpunordss, sse, 1, 0, 0 AVX_INSTR comisd, sse2 AVX_INSTR comiss, sse AVX_INSTR cvtdq2pd, sse2 @@ -1545,6 +1641,52 @@ FMA4_INSTR fmsubadd, pd, ps FMA4_INSTR fnmadd, pd, ps, sd, ss FMA4_INSTR fnmsub, pd, ps, sd, ss +; Macros for converting VEX instructions to equivalent EVEX ones. +%macro EVEX_INSTR 2-3 0 ; vex, evex, prefer_evex + %macro %1 2-7 fnord, fnord, %1, %2, %3 + %ifidn %3, fnord + %define %%args %1, %2 + %elifidn %4, fnord + %define %%args %1, %2, %3 + %else + %define %%args %1, %2, %3, %4 + %endif + %assign %%evex_required cpuflag(avx512) & %7 + %ifnum regnumof%1 + %if regnumof%1 >= 16 || sizeof%1 > 32 + %assign %%evex_required 1 + %endif + %endif + %ifnum regnumof%2 + %if regnumof%2 >= 16 || sizeof%2 > 32 + %assign %%evex_required 1 + %endif + %endif + %if %%evex_required + %6 %%args + %else + %5 %%args ; Prefer VEX over EVEX due to shorter instruction length + %endif + %endmacro +%endmacro + +EVEX_INSTR vbroadcastf128, vbroadcastf32x4 +EVEX_INSTR vbroadcasti128, vbroadcasti32x4 +EVEX_INSTR vextractf128, vextractf32x4 +EVEX_INSTR vextracti128, vextracti32x4 +EVEX_INSTR vinsertf128, vinsertf32x4 +EVEX_INSTR vinserti128, vinserti32x4 +EVEX_INSTR vmovdqa, vmovdqa32 +EVEX_INSTR vmovdqu, vmovdqu32 +EVEX_INSTR vpand, vpandd +EVEX_INSTR vpandn, vpandnd +EVEX_INSTR vpor, vpord +EVEX_INSTR vpxor, vpxord +EVEX_INSTR vrcpps, vrcp14ps, 1 ; EVEX versions have higher precision +EVEX_INSTR vrcpss, vrcp14ss, 1 +EVEX_INSTR vrsqrtps, vrsqrt14ps, 1 +EVEX_INSTR vrsqrtss, vrsqrt14ss, 1 + ; workaround: vpbroadcastq is broken in x86_32 due to a yasm bug (fixed in 1.3.0) %ifdef __YASM_VER__ %if __YASM_VERSION_ID__ < 0x01030000 && ARCH_X86_64 == 0 diff --git a/libavutil/x86/x86util.asm b/libavutil/x86/x86util.asm index e1220dfc1a431..d7cd996842f59 100644 --- a/libavutil/x86/x86util.asm +++ b/libavutil/x86/x86util.asm @@ -357,7 +357,7 @@ %endif %endmacro -%macro ABSB 2 ; source mmreg, temp mmreg (unused for ssse3) +%macro ABSB 2 ; source mmreg, temp mmreg (unused for SSSE3) %if cpuflag(ssse3) pabsb %1, %1 %else @@ -381,7 +381,7 @@ %endif %endmacro -%macro ABSD2_MMX 4 +%macro ABSD2 4 pxor %3, %3 pxor %4, %4 pcmpgtd %3, %1 @@ -475,7 +475,7 @@ %else palignr %1, %2, %3 %endif -%elif cpuflag(mmx) ; [dst,] src1, src2, imm, tmp +%else ; [dst,] src1, src2, imm, tmp %define %%dst %1 %if %0==5 %ifnidn %1, %2 @@ -799,37 +799,47 @@ pminsw %1, %3 %endmacro -%macro PMINSD_MMX 3 ; dst, src, tmp +%macro PMINSD 3 ; dst, src, tmp/unused +%if cpuflag(sse4) + pminsd %1, %2 +%elif cpuflag(sse2) + cvtdq2ps %1, %1 + minps %1, %2 + cvtps2dq %1, %1 +%else mova %3, %2 pcmpgtd %3, %1 pxor %1, %2 pand %1, %3 pxor %1, %2 +%endif %endmacro -%macro PMAXSD_MMX 3 ; dst, src, tmp +%macro PMAXSD 3 ; dst, src, tmp/unused +%if cpuflag(sse4) + pmaxsd %1, %2 +%else mova %3, %1 pcmpgtd %3, %2 pand %1, %3 pandn %3, %2 por %1, %3 +%endif %endmacro -%macro CLIPD_MMX 3-4 ; src/dst, min, max, tmp - PMINSD_MMX %1, %3, %4 - PMAXSD_MMX %1, %2, %4 -%endmacro - -%macro CLIPD_SSE2 3-4 ; src/dst, min (float), max (float), unused +%macro CLIPD 3-4 +%if cpuflag(sse4); src/dst, min, max, unused + pminsd %1, %3 + pmaxsd %1, %2 +%elif cpuflag(sse2) ; src/dst, min (float), max (float), unused cvtdq2ps %1, %1 minps %1, %3 maxps %1, %2 cvtps2dq %1, %1 -%endmacro - -%macro CLIPD_SSE41 3-4 ; src/dst, min, max, unused - pminsd %1, %3 - pmaxsd %1, %2 +%else ; src/dst, min, max, tmp + PMINSD %1, %3, %4 + PMAXSD %1, %2, %4 +%endif %endmacro %macro VBROADCASTSS 2 ; dst xmm/ymm, src m32/xmm @@ -880,6 +890,14 @@ %endif %endmacro +%macro VBROADCASTI128 2 ; dst xmm/ymm, src : 128bits val +%if mmsize > 16 + vbroadcasti128 %1, %2 +%else + mova %1, %2 +%endif +%endmacro + %macro SHUFFLE_MASK_W 8 %rep 8 %if %1>=0x80 diff --git a/libavutil/xga_font_data.h b/libavutil/xga_font_data.h index 5e40f542e49a7..69dc337120e24 100644 --- a/libavutil/xga_font_data.h +++ b/libavutil/xga_font_data.h @@ -29,7 +29,7 @@ #include #include "internal.h" -extern av_export const uint8_t avpriv_cga_font[2048]; -extern av_export const uint8_t avpriv_vga16_font[4096]; +extern av_export_avutil const uint8_t avpriv_cga_font[2048]; +extern av_export_avutil const uint8_t avpriv_vga16_font[4096]; #endif /* AVUTIL_XGA_FONT_DATA_H */ diff --git a/libpostproc/postprocess.h b/libpostproc/postprocess.h index d180686e7392b..348ee7cc6100e 100644 --- a/libpostproc/postprocess.h +++ b/libpostproc/postprocess.h @@ -53,10 +53,6 @@ const char *postproc_license(void); #define PP_QUALITY_MAX 6 -#if FF_API_QP_TYPE -#define QP_STORE_T int8_t //deprecated -#endif - #include typedef void pp_context; diff --git a/libpostproc/version.h b/libpostproc/version.h index e8f0abe81374f..c6772055afb8d 100644 --- a/libpostproc/version.h +++ b/libpostproc/version.h @@ -28,8 +28,8 @@ #include "libavutil/avutil.h" -#define LIBPOSTPROC_VERSION_MAJOR 54 -#define LIBPOSTPROC_VERSION_MINOR 7 +#define LIBPOSTPROC_VERSION_MAJOR 55 +#define LIBPOSTPROC_VERSION_MINOR 1 #define LIBPOSTPROC_VERSION_MICRO 100 #define LIBPOSTPROC_VERSION_INT AV_VERSION_INT(LIBPOSTPROC_VERSION_MAJOR, \ @@ -42,8 +42,4 @@ #define LIBPOSTPROC_IDENT "postproc" AV_STRINGIFY(LIBPOSTPROC_VERSION) -#ifndef FF_API_QP_TYPE -#define FF_API_QP_TYPE (LIBPOSTPROC_VERSION_MAJOR < 55) -#endif - #endif /* POSTPROC_VERSION_H */ diff --git a/libswresample/arm/audio_convert_neon.S b/libswresample/arm/audio_convert_neon.S index 1f88316ddec83..7729514701d3a 100644 --- a/libswresample/arm/audio_convert_neon.S +++ b/libswresample/arm/audio_convert_neon.S @@ -22,6 +22,7 @@ #include "libavutil/arm/asm.S" function swri_oldapi_conv_flt_to_s16_neon, export=1 +_swri_oldapi_conv_flt_to_s16_neon: subs r2, r2, #8 vld1.32 {q0}, [r1,:128]! vcvt.s32.f32 q8, q0, #31 @@ -66,6 +67,7 @@ function swri_oldapi_conv_flt_to_s16_neon, export=1 endfunc function swri_oldapi_conv_fltp_to_s16_2ch_neon, export=1 +_swri_oldapi_conv_fltp_to_s16_2ch_neon: ldm r1, {r1, r3} subs r2, r2, #8 vld1.32 {q0}, [r1,:128]! @@ -133,8 +135,8 @@ function swri_oldapi_conv_fltp_to_s16_nch_neon, export=1 cmp r3, #2 itt lt ldrlt r1, [r1] - blt X(swri_oldapi_conv_flt_to_s16_neon) - beq X(swri_oldapi_conv_fltp_to_s16_2ch_neon) + blt _swri_oldapi_conv_flt_to_s16_neon + beq _swri_oldapi_conv_fltp_to_s16_2ch_neon push {r4-r8, lr} cmp r3, #4 diff --git a/libswresample/rematrix.c b/libswresample/rematrix.c index 66a43c16c165a..82277300564d6 100644 --- a/libswresample/rematrix.c +++ b/libswresample/rematrix.c @@ -69,8 +69,10 @@ int swr_set_matrix(struct SwrContext *s, const double *matrix, int stride) return AVERROR(EINVAL); memset(s->matrix, 0, sizeof(s->matrix)); memset(s->matrix_flt, 0, sizeof(s->matrix_flt)); - nb_in = av_get_channel_layout_nb_channels(s->user_in_ch_layout); - nb_out = av_get_channel_layout_nb_channels(s->user_out_ch_layout); + nb_in = (s->user_in_ch_count > 0) ? s->user_in_ch_count : + av_get_channel_layout_nb_channels(s->user_in_ch_layout); + nb_out = (s->user_out_ch_count > 0) ? s->user_out_ch_count : + av_get_channel_layout_nb_channels(s->user_out_ch_layout); for (out = 0; out < nb_out; out++) { for (in = 0; in < nb_in; in++) s->matrix_flt[out][in] = s->matrix[out][in] = matrix[in]; @@ -445,14 +447,23 @@ av_cold int swri_rematrix_init(SwrContext *s){ s->mix_2_1_f = (mix_2_1_func_type*)sum2_double; s->mix_any_f = (mix_any_func_type*)get_mix_any_func_double(s); }else if(s->midbuf.fmt == AV_SAMPLE_FMT_S32P){ - // Only for dithering currently -// s->native_matrix = av_calloc(nb_in * nb_out, sizeof(double)); s->native_one = av_mallocz(sizeof(int)); if (!s->native_one) return AVERROR(ENOMEM); -// for (i = 0; i < nb_out; i++) -// for (j = 0; j < nb_in; j++) -// ((double*)s->native_matrix)[i * nb_in + j] = s->matrix[i][j]; + s->native_matrix = av_calloc(nb_in * nb_out, sizeof(int)); + if (!s->native_matrix) { + av_freep(&s->native_one); + return AVERROR(ENOMEM); + } + for (i = 0; i < nb_out; i++) { + double rem = 0; + + for (j = 0; j < nb_in; j++) { + double target = s->matrix[i][j] * 32768 + rem; + ((int*)s->native_matrix)[i * nb_in + j] = lrintf(target); + rem += target - ((int*)s->native_matrix)[i * nb_in + j]; + } + } *((int*)s->native_one) = 32768; s->mix_1_1_f = (mix_1_1_func_type*)copy_s32; s->mix_2_1_f = (mix_2_1_func_type*)sum2_s32; diff --git a/libswresample/swresample.c b/libswresample/swresample.c index 74c96dce605e4..5bd39caac4dfe 100644 --- a/libswresample/swresample.c +++ b/libswresample/swresample.c @@ -240,7 +240,7 @@ av_cold int swr_init(struct SwrContext *s){ &&s->int_sample_fmt != AV_SAMPLE_FMT_S64P &&s->int_sample_fmt != AV_SAMPLE_FMT_FLTP &&s->int_sample_fmt != AV_SAMPLE_FMT_DBLP){ - av_log(s, AV_LOG_ERROR, "Requested sample format %s is not supported internally, S16/S32/S64/FLT/DBL is supported\n", av_get_sample_fmt_name(s->int_sample_fmt)); + av_log(s, AV_LOG_ERROR, "Requested sample format %s is not supported internally, s16p/s32p/s64p/fltp/dblp are supported\n", av_get_sample_fmt_name(s->int_sample_fmt)); return AVERROR(EINVAL); } @@ -276,7 +276,7 @@ av_cold int swr_init(struct SwrContext *s){ && s->int_sample_fmt != AV_SAMPLE_FMT_FLTP && s->int_sample_fmt != AV_SAMPLE_FMT_DBLP && s->resample){ - av_log(s, AV_LOG_ERROR, "Resampling only supported with internal s16/s32/flt/dbl\n"); + av_log(s, AV_LOG_ERROR, "Resampling only supported with internal s16p/s32p/fltp/dblp\n"); ret = AVERROR(EINVAL); goto fail; } @@ -678,7 +678,7 @@ static int swr_convert_internal(struct SwrContext *s, AudioData *out, int out_co s->mix_2_1_simd(conv_src->ch[ch], preout->ch[ch], s->dither.noise.ch[ch] + s->dither.noise.bps * s->dither.noise_pos, s->native_simd_one, 0, 0, len1); if(out_count != len1) for(ch=0; chch_count; ch++) - s->mix_2_1_f(conv_src->ch[ch] + off, preout->ch[ch] + off, s->dither.noise.ch[ch] + s->dither.noise.bps * s->dither.noise_pos + off + len1, s->native_one, 0, 0, out_count - len1); + s->mix_2_1_f(conv_src->ch[ch] + off, preout->ch[ch] + off, s->dither.noise.ch[ch] + s->dither.noise.bps * s->dither.noise_pos + off, s->native_one, 0, 0, out_count - len1); } else { for(ch=0; chch_count; ch++) s->mix_2_1_f(conv_src->ch[ch], preout->ch[ch], s->dither.noise.ch[ch] + s->dither.noise.bps * s->dither.noise_pos, s->native_one, 0, 0, out_count); diff --git a/libswresample/version.h b/libswresample/version.h index 6a66173f3bd13..efc462f46d5b6 100644 --- a/libswresample/version.h +++ b/libswresample/version.h @@ -28,8 +28,8 @@ #include "libavutil/avutil.h" -#define LIBSWRESAMPLE_VERSION_MAJOR 2 -#define LIBSWRESAMPLE_VERSION_MINOR 9 +#define LIBSWRESAMPLE_VERSION_MAJOR 3 +#define LIBSWRESAMPLE_VERSION_MINOR 1 #define LIBSWRESAMPLE_VERSION_MICRO 100 #define LIBSWRESAMPLE_VERSION_INT AV_VERSION_INT(LIBSWRESAMPLE_VERSION_MAJOR, \ diff --git a/libswscale/arm/rgb2yuv_neon_16.S b/libswscale/arm/rgb2yuv_neon_16.S index 601bc9a9b7c42..ad7e679ca910d 100644 --- a/libswscale/arm/rgb2yuv_neon_16.S +++ b/libswscale/arm/rgb2yuv_neon_16.S @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config.h" +#if HAVE_AS_DN_DIRECTIVE #include "rgb2yuv_neon_common.S" /* downsampled R16G16B16 x8 */ @@ -78,3 +80,4 @@ alias_qw c8x8x2, q10 .endm loop_420sp rgbx, nv12, init, kernel_420_16x2, 16 +#endif diff --git a/libswscale/arm/rgb2yuv_neon_32.S b/libswscale/arm/rgb2yuv_neon_32.S index f51a5f149f046..4fd0f64a09e97 100644 --- a/libswscale/arm/rgb2yuv_neon_32.S +++ b/libswscale/arm/rgb2yuv_neon_32.S @@ -18,6 +18,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include "config.h" +#if HAVE_AS_DN_DIRECTIVE #include "rgb2yuv_neon_common.S" /* downsampled R16G16B16 x8 */ @@ -117,3 +119,4 @@ alias_qw c8x8x2, q10 loop_420sp rgbx, nv12, init, kernel_420_16x2, 32 +#endif diff --git a/libswscale/arm/swscale_unscaled.c b/libswscale/arm/swscale_unscaled.c index e1597ab42dfcd..e41f294eacc10 100644 --- a/libswscale/arm/swscale_unscaled.c +++ b/libswscale/arm/swscale_unscaled.c @@ -23,6 +23,7 @@ #include "libswscale/swscale_internal.h" #include "libavutil/arm/cpu.h" +#if HAVE_AS_DN_DIRECTIVE extern void rgbx_to_nv12_neon_32(const uint8_t *src, uint8_t *y, uint8_t *chroma, int width, int height, int y_stride, int c_stride, int src_stride, @@ -178,3 +179,8 @@ void ff_get_unscaled_swscale_arm(SwsContext *c) if (have_neon(cpu_flags)) get_unscaled_swscale_neon(c); } +#else +void ff_get_unscaled_swscale_arm(SwsContext *c) +{ +} +#endif diff --git a/libswscale/output.c b/libswscale/output.c index f30bce8dd3c1e..0af2fffea4e83 100644 --- a/libswscale/output.c +++ b/libswscale/output.c @@ -180,6 +180,34 @@ yuv2planeX_16_c_template(const int16_t *filter, int filterSize, } } +static void yuv2p016cX_c(SwsContext *c, const int16_t *chrFilter, int chrFilterSize, + const int16_t **chrUSrc, const int16_t **chrVSrc, + uint8_t *dest8, int chrDstW) +{ + uint16_t *dest = (uint16_t*)dest8; + const int32_t **uSrc = (const int32_t **)chrUSrc; + const int32_t **vSrc = (const int32_t **)chrVSrc; + int shift = 15; + int big_endian = c->dstFormat == AV_PIX_FMT_P016BE; + int i, j; + + for (i = 0; i < chrDstW; i++) { + int u = 1 << (shift - 1); + int v = 1 << (shift - 1); + + /* See yuv2planeX_16_c_template for details. */ + u -= 0x40000000; + v -= 0x40000000; + for (j = 0; j < chrFilterSize; j++) { + u += uSrc[j][i] * (unsigned)chrFilter[j]; + v += vSrc[j][i] * (unsigned)chrFilter[j]; + } + + output_pixel(&dest[2*i] , u, 0x8000, int); + output_pixel(&dest[2*i+1], v, 0x8000, int); + } +} + #undef output_pixel #define output_pixel(pos, val) \ @@ -2257,6 +2285,9 @@ av_cold void ff_sws_init_output_funcs(SwsContext *c, } else if (is16BPS(dstFormat)) { *yuv2planeX = isBE(dstFormat) ? yuv2planeX_16BE_c : yuv2planeX_16LE_c; *yuv2plane1 = isBE(dstFormat) ? yuv2plane1_16BE_c : yuv2plane1_16LE_c; + if (dstFormat == AV_PIX_FMT_P016LE || dstFormat == AV_PIX_FMT_P016BE) { + *yuv2nv12cX = yuv2p016cX_c; + } } else if (isNBPS(dstFormat)) { if (desc->comp[0].depth == 9) { *yuv2planeX = isBE(dstFormat) ? yuv2planeX_9BE_c : yuv2planeX_9LE_c; diff --git a/libswscale/rgb2rgb.c b/libswscale/rgb2rgb.c index 04b7908b5e7a9..eab8e6aebb370 100644 --- a/libswscale/rgb2rgb.c +++ b/libswscale/rgb2rgb.c @@ -53,6 +53,10 @@ void (*rgb15to32)(const uint8_t *src, uint8_t *dst, int src_size); void (*shuffle_bytes_0321)(const uint8_t *src, uint8_t *dst, int src_size); void (*shuffle_bytes_2103)(const uint8_t *src, uint8_t *dst, int src_size); +void (*shuffle_bytes_1230)(const uint8_t *src, uint8_t *dst, int src_size); +void (*shuffle_bytes_3012)(const uint8_t *src, uint8_t *dst, int src_size); +void (*shuffle_bytes_3210)(const uint8_t *src, uint8_t *dst, int src_size); + void (*yv12toyuy2)(const uint8_t *ysrc, const uint8_t *usrc, const uint8_t *vsrc, uint8_t *dst, @@ -319,25 +323,6 @@ void rgb12tobgr12(const uint8_t *src, uint8_t *dst, int src_size) } } - -#define DEFINE_SHUFFLE_BYTES(a, b, c, d) \ -void shuffle_bytes_ ## a ## b ## c ## d(const uint8_t *src, \ - uint8_t *dst, int src_size) \ -{ \ - int i; \ - \ - for (i = 0; i < src_size; i += 4) { \ - dst[i + 0] = src[i + a]; \ - dst[i + 1] = src[i + b]; \ - dst[i + 2] = src[i + c]; \ - dst[i + 3] = src[i + d]; \ - } \ -} - -DEFINE_SHUFFLE_BYTES(1, 2, 3, 0) -DEFINE_SHUFFLE_BYTES(3, 0, 1, 2) -DEFINE_SHUFFLE_BYTES(3, 2, 1, 0) - #define DEFINE_RGB48TOBGR48(need_bswap, swap) \ void rgb48tobgr48_ ## need_bswap(const uint8_t *src, \ uint8_t *dst, int src_size) \ diff --git a/libswscale/rgb2rgb.h b/libswscale/rgb2rgb.h index 6994839299da3..3569254df93ac 100644 --- a/libswscale/rgb2rgb.h +++ b/libswscale/rgb2rgb.h @@ -52,6 +52,9 @@ extern void (*rgb32tobgr15)(const uint8_t *src, uint8_t *dst, int src_size); extern void (*shuffle_bytes_0321)(const uint8_t *src, uint8_t *dst, int src_size); extern void (*shuffle_bytes_2103)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*shuffle_bytes_1230)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*shuffle_bytes_3012)(const uint8_t *src, uint8_t *dst, int src_size); +extern void (*shuffle_bytes_3210)(const uint8_t *src, uint8_t *dst, int src_size); void rgb64tobgr48_nobswap(const uint8_t *src, uint8_t *dst, int src_size); void rgb64tobgr48_bswap(const uint8_t *src, uint8_t *dst, int src_size); @@ -76,10 +79,6 @@ void rgb15tobgr15(const uint8_t *src, uint8_t *dst, int src_size); void rgb12tobgr12(const uint8_t *src, uint8_t *dst, int src_size); void rgb12to15(const uint8_t *src, uint8_t *dst, int src_size); -void shuffle_bytes_1230(const uint8_t *src, uint8_t *dst, int src_size); -void shuffle_bytes_3012(const uint8_t *src, uint8_t *dst, int src_size); -void shuffle_bytes_3210(const uint8_t *src, uint8_t *dst, int src_size); - void ff_rgb24toyv12_c(const uint8_t *src, uint8_t *ydst, uint8_t *udst, uint8_t *vdst, int width, int height, int lumStride, int chromStride, int srcStride, int32_t *rgb2yuv); diff --git a/libswscale/rgb2rgb_template.c b/libswscale/rgb2rgb_template.c index 499d25b26d8c8..fb7d663ccc593 100644 --- a/libswscale/rgb2rgb_template.c +++ b/libswscale/rgb2rgb_template.c @@ -342,6 +342,24 @@ static inline void shuffle_bytes_0321_c(const uint8_t *src, uint8_t *dst, } } +#define DEFINE_SHUFFLE_BYTES(name, a, b, c, d) \ +static void shuffle_bytes_##name (const uint8_t *src, \ + uint8_t *dst, int src_size) \ +{ \ + int i; \ + \ + for (i = 0; i < src_size; i += 4) { \ + dst[i + 0] = src[i + a]; \ + dst[i + 1] = src[i + b]; \ + dst[i + 2] = src[i + c]; \ + dst[i + 3] = src[i + d]; \ + } \ +} + +DEFINE_SHUFFLE_BYTES(1230_c, 1, 2, 3, 0) +DEFINE_SHUFFLE_BYTES(3012_c, 3, 0, 1, 2) +DEFINE_SHUFFLE_BYTES(3210_c, 3, 2, 1, 0) + static inline void rgb24tobgr24_c(const uint8_t *src, uint8_t *dst, int src_size) { unsigned i; @@ -949,6 +967,9 @@ static av_cold void rgb2rgb_init_c(void) #else shuffle_bytes_0321 = shuffle_bytes_0321_c; shuffle_bytes_2103 = shuffle_bytes_2103_c; + shuffle_bytes_1230 = shuffle_bytes_1230_c; + shuffle_bytes_3012 = shuffle_bytes_3012_c; + shuffle_bytes_3210 = shuffle_bytes_3210_c; #endif rgb32tobgr16 = rgb32tobgr16_c; rgb32tobgr15 = rgb32tobgr15_c; diff --git a/libswscale/swscale_internal.h b/libswscale/swscale_internal.h index 0f51df95d7520..1703856ab2db0 100644 --- a/libswscale/swscale_internal.h +++ b/libswscale/swscale_internal.h @@ -676,6 +676,17 @@ static av_always_inline int isPlanarYUV(enum AVPixelFormat pix_fmt) return ((desc->flags & AV_PIX_FMT_FLAG_PLANAR) && isYUV(pix_fmt)); } +/* + * Identity semi-planar YUV formats. Specifically, those are YUV formats + * where the second and third components (U & V) are on the same plane. + */ +static av_always_inline int isSemiPlanarYUV(enum AVPixelFormat pix_fmt) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + av_assert0(desc); + return (isPlanarYUV(pix_fmt) && desc->comp[1].plane == desc->comp[2].plane); +} + static av_always_inline int isRGB(enum AVPixelFormat pix_fmt) { const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); @@ -795,9 +806,17 @@ static av_always_inline int isPlanarRGB(enum AVPixelFormat pix_fmt) static av_always_inline int usePal(enum AVPixelFormat pix_fmt) { - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); - av_assert0(desc); - return (desc->flags & AV_PIX_FMT_FLAG_PAL) || (desc->flags & AV_PIX_FMT_FLAG_PSEUDOPAL); + switch (pix_fmt) { + case AV_PIX_FMT_PAL8: + case AV_PIX_FMT_BGR4_BYTE: + case AV_PIX_FMT_BGR8: + case AV_PIX_FMT_GRAY8: + case AV_PIX_FMT_RGB4_BYTE: + case AV_PIX_FMT_RGB8: + return 1; + default: + return 0; + } } extern const uint64_t ff_dither4[2]; diff --git a/libswscale/swscale_unscaled.c b/libswscale/swscale_unscaled.c index ef36aec500bec..13f9cd83e36bf 100644 --- a/libswscale/swscale_unscaled.c +++ b/libswscale/swscale_unscaled.c @@ -110,24 +110,6 @@ DECLARE_ALIGNED(8, static const uint8_t, dithers)[8][8][8]={ { 112, 16,104, 8,118, 22,110, 14,}, }}; -static const uint16_t dither_scale[15][16]={ -{ 2, 3, 3, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,}, -{ 2, 3, 7, 7, 13, 13, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,}, -{ 3, 3, 4, 15, 15, 29, 57, 57, 57, 113, 113, 113, 113, 113, 113, 113,}, -{ 3, 4, 4, 5, 31, 31, 61, 121, 241, 241, 241, 241, 481, 481, 481, 481,}, -{ 3, 4, 5, 5, 6, 63, 63, 125, 249, 497, 993, 993, 993, 993, 993, 1985,}, -{ 3, 5, 6, 6, 6, 7, 127, 127, 253, 505, 1009, 2017, 4033, 4033, 4033, 4033,}, -{ 3, 5, 6, 7, 7, 7, 8, 255, 255, 509, 1017, 2033, 4065, 8129,16257,16257,}, -{ 3, 5, 6, 8, 8, 8, 8, 9, 511, 511, 1021, 2041, 4081, 8161,16321,32641,}, -{ 3, 5, 7, 8, 9, 9, 9, 9, 10, 1023, 1023, 2045, 4089, 8177,16353,32705,}, -{ 3, 5, 7, 8, 10, 10, 10, 10, 10, 11, 2047, 2047, 4093, 8185,16369,32737,}, -{ 3, 5, 7, 8, 10, 11, 11, 11, 11, 11, 12, 4095, 4095, 8189,16377,32753,}, -{ 3, 5, 7, 9, 10, 12, 12, 12, 12, 12, 12, 13, 8191, 8191,16381,32761,}, -{ 3, 5, 7, 9, 10, 12, 13, 13, 13, 13, 13, 13, 14,16383,16383,32765,}, -{ 3, 5, 7, 9, 10, 12, 14, 14, 14, 14, 14, 14, 14, 15,32767,32767,}, -{ 3, 5, 7, 9, 11, 12, 14, 15, 15, 15, 15, 15, 15, 15, 16,65535,}, -}; - static void fillPlane(uint8_t *plane, int stride, int width, int height, int y, uint8_t val) @@ -198,16 +180,28 @@ static int nv12ToPlanarWrapper(SwsContext *c, const uint8_t *src[], return srcSliceH; } -static int planarToP010Wrapper(SwsContext *c, const uint8_t *src8[], +static int planarToP01xWrapper(SwsContext *c, const uint8_t *src8[], int srcStride[], int srcSliceY, int srcSliceH, uint8_t *dstParam8[], int dstStride[]) { + const AVPixFmtDescriptor *src_format = av_pix_fmt_desc_get(c->srcFormat); + const AVPixFmtDescriptor *dst_format = av_pix_fmt_desc_get(c->dstFormat); const uint16_t **src = (const uint16_t**)src8; uint16_t *dstY = (uint16_t*)(dstParam8[0] + dstStride[0] * srcSliceY); uint16_t *dstUV = (uint16_t*)(dstParam8[1] + dstStride[1] * srcSliceY / 2); int x, y; + /* Calculate net shift required for values. */ + const int shift[3] = { + dst_format->comp[0].depth + dst_format->comp[0].shift - + src_format->comp[0].depth - src_format->comp[0].shift, + dst_format->comp[1].depth + dst_format->comp[1].shift - + src_format->comp[1].depth - src_format->comp[1].shift, + dst_format->comp[2].depth + dst_format->comp[2].shift - + src_format->comp[2].depth - src_format->comp[2].shift, + }; + av_assert0(!(srcStride[0] % 2 || srcStride[1] % 2 || srcStride[2] % 2 || dstStride[0] % 2 || dstStride[1] % 2)); @@ -215,7 +209,7 @@ static int planarToP010Wrapper(SwsContext *c, const uint8_t *src8[], uint16_t *tdstY = dstY; const uint16_t *tsrc0 = src[0]; for (x = c->srcW; x > 0; x--) { - *tdstY++ = *tsrc0++ << 6; + *tdstY++ = *tsrc0++ << shift[0]; } src[0] += srcStride[0] / 2; dstY += dstStride[0] / 2; @@ -225,8 +219,8 @@ static int planarToP010Wrapper(SwsContext *c, const uint8_t *src8[], const uint16_t *tsrc1 = src[1]; const uint16_t *tsrc2 = src[2]; for (x = c->srcW / 2; x > 0; x--) { - *tdstUV++ = *tsrc1++ << 6; - *tdstUV++ = *tsrc2++ << 6; + *tdstUV++ = *tsrc1++ << shift[1]; + *tdstUV++ = *tsrc2++ << shift[2]; } src[1] += srcStride[1] / 2; src[2] += srcStride[2] / 2; @@ -1502,24 +1496,63 @@ static int packedCopyWrapper(SwsContext *c, const uint8_t *src[], } #define DITHER_COPY(dst, dstStride, src, srcStride, bswap, dbswap)\ - uint16_t scale= dither_scale[dst_depth-1][src_depth-1];\ - int shift= src_depth-dst_depth + dither_scale[src_depth-2][dst_depth-1];\ - for (i = 0; i < height; i++) {\ - const uint8_t *dither= dithers[src_depth-9][i&7];\ - for (j = 0; j < length-7; j+=8){\ - dst[j+0] = dbswap((bswap(src[j+0]) + dither[0])*scale>>shift);\ - dst[j+1] = dbswap((bswap(src[j+1]) + dither[1])*scale>>shift);\ - dst[j+2] = dbswap((bswap(src[j+2]) + dither[2])*scale>>shift);\ - dst[j+3] = dbswap((bswap(src[j+3]) + dither[3])*scale>>shift);\ - dst[j+4] = dbswap((bswap(src[j+4]) + dither[4])*scale>>shift);\ - dst[j+5] = dbswap((bswap(src[j+5]) + dither[5])*scale>>shift);\ - dst[j+6] = dbswap((bswap(src[j+6]) + dither[6])*scale>>shift);\ - dst[j+7] = dbswap((bswap(src[j+7]) + dither[7])*scale>>shift);\ + unsigned shift= src_depth-dst_depth, tmp;\ + if (c->dither == SWS_DITHER_NONE) {\ + for (i = 0; i < height; i++) {\ + for (j = 0; j < length-7; j+=8) {\ + dst[j+0] = dbswap(bswap(src[j+0])>>shift);\ + dst[j+1] = dbswap(bswap(src[j+1])>>shift);\ + dst[j+2] = dbswap(bswap(src[j+2])>>shift);\ + dst[j+3] = dbswap(bswap(src[j+3])>>shift);\ + dst[j+4] = dbswap(bswap(src[j+4])>>shift);\ + dst[j+5] = dbswap(bswap(src[j+5])>>shift);\ + dst[j+6] = dbswap(bswap(src[j+6])>>shift);\ + dst[j+7] = dbswap(bswap(src[j+7])>>shift);\ + }\ + for (; j < length; j++) {\ + dst[j] = dbswap(bswap(src[j])>>shift);\ + }\ + dst += dstStride;\ + src += srcStride;\ + }\ + } else if (shiftonly) {\ + for (i = 0; i < height; i++) {\ + const uint8_t *dither= dithers[shift-1][i&7];\ + for (j = 0; j < length-7; j+=8) {\ + tmp = (bswap(src[j+0]) + dither[0])>>shift; dst[j+0] = dbswap(tmp - (tmp>>dst_depth));\ + tmp = (bswap(src[j+1]) + dither[1])>>shift; dst[j+1] = dbswap(tmp - (tmp>>dst_depth));\ + tmp = (bswap(src[j+2]) + dither[2])>>shift; dst[j+2] = dbswap(tmp - (tmp>>dst_depth));\ + tmp = (bswap(src[j+3]) + dither[3])>>shift; dst[j+3] = dbswap(tmp - (tmp>>dst_depth));\ + tmp = (bswap(src[j+4]) + dither[4])>>shift; dst[j+4] = dbswap(tmp - (tmp>>dst_depth));\ + tmp = (bswap(src[j+5]) + dither[5])>>shift; dst[j+5] = dbswap(tmp - (tmp>>dst_depth));\ + tmp = (bswap(src[j+6]) + dither[6])>>shift; dst[j+6] = dbswap(tmp - (tmp>>dst_depth));\ + tmp = (bswap(src[j+7]) + dither[7])>>shift; dst[j+7] = dbswap(tmp - (tmp>>dst_depth));\ + }\ + for (; j < length; j++) {\ + tmp = (bswap(src[j]) + dither[j&7])>>shift; dst[j] = dbswap(tmp - (tmp>>dst_depth));\ + }\ + dst += dstStride;\ + src += srcStride;\ + }\ + } else {\ + for (i = 0; i < height; i++) {\ + const uint8_t *dither= dithers[shift-1][i&7];\ + for (j = 0; j < length-7; j+=8) {\ + tmp = bswap(src[j+0]); dst[j+0] = dbswap((tmp - (tmp>>dst_depth) + dither[0])>>shift);\ + tmp = bswap(src[j+1]); dst[j+1] = dbswap((tmp - (tmp>>dst_depth) + dither[1])>>shift);\ + tmp = bswap(src[j+2]); dst[j+2] = dbswap((tmp - (tmp>>dst_depth) + dither[2])>>shift);\ + tmp = bswap(src[j+3]); dst[j+3] = dbswap((tmp - (tmp>>dst_depth) + dither[3])>>shift);\ + tmp = bswap(src[j+4]); dst[j+4] = dbswap((tmp - (tmp>>dst_depth) + dither[4])>>shift);\ + tmp = bswap(src[j+5]); dst[j+5] = dbswap((tmp - (tmp>>dst_depth) + dither[5])>>shift);\ + tmp = bswap(src[j+6]); dst[j+6] = dbswap((tmp - (tmp>>dst_depth) + dither[6])>>shift);\ + tmp = bswap(src[j+7]); dst[j+7] = dbswap((tmp - (tmp>>dst_depth) + dither[7])>>shift);\ + }\ + for (; j < length; j++) {\ + tmp = bswap(src[j]); dst[j] = dbswap((tmp - (tmp>>dst_depth) + dither[j&7])>>shift);\ + }\ + dst += dstStride;\ + src += srcStride;\ }\ - for (; j < length; j++)\ - dst[j] = dbswap((bswap(src[j]) + dither[j&7])*scale>>shift);\ - dst += dstStride;\ - src += srcStride;\ } static int planarCopyWrapper(SwsContext *c, const uint8_t *src[], @@ -1717,14 +1750,17 @@ void ff_get_unscaled_swscale(SwsContext *c) !(flags & SWS_ACCURATE_RND) && (c->dither == SWS_DITHER_BAYER || c->dither == SWS_DITHER_AUTO) && !(dstH & 1)) { c->swscale = ff_yuv2rgb_get_func_ptr(c); } - /* yuv420p10_to_p010 */ - if ((srcFormat == AV_PIX_FMT_YUV420P10 || srcFormat == AV_PIX_FMT_YUVA420P10) && - dstFormat == AV_PIX_FMT_P010) { - c->swscale = planarToP010Wrapper; + /* yuv420p1x_to_p01x */ + if ((srcFormat == AV_PIX_FMT_YUV420P10 || srcFormat == AV_PIX_FMT_YUVA420P10 || + srcFormat == AV_PIX_FMT_YUV420P12 || + srcFormat == AV_PIX_FMT_YUV420P14 || + srcFormat == AV_PIX_FMT_YUV420P16 || srcFormat == AV_PIX_FMT_YUVA420P16) && + (dstFormat == AV_PIX_FMT_P010 || dstFormat == AV_PIX_FMT_P016)) { + c->swscale = planarToP01xWrapper; } - /* yuv420p_to_p010le */ + /* yuv420p_to_p01xle */ if ((srcFormat == AV_PIX_FMT_YUV420P || srcFormat == AV_PIX_FMT_YUVA420P) && - dstFormat == AV_PIX_FMT_P010LE) { + (dstFormat == AV_PIX_FMT_P010LE || dstFormat == AV_PIX_FMT_P016LE)) { c->swscale = planar8ToP01xleWrapper; } @@ -1894,12 +1930,7 @@ void ff_get_unscaled_swscale(SwsContext *c) (isPlanarYUV(srcFormat) && isPlanarYUV(dstFormat) && c->chrDstHSubSample == c->chrSrcHSubSample && c->chrDstVSubSample == c->chrSrcVSubSample && - dstFormat != AV_PIX_FMT_NV12 && dstFormat != AV_PIX_FMT_NV21 && - dstFormat != AV_PIX_FMT_P010LE && dstFormat != AV_PIX_FMT_P010BE && - dstFormat != AV_PIX_FMT_P016LE && dstFormat != AV_PIX_FMT_P016BE && - srcFormat != AV_PIX_FMT_NV12 && srcFormat != AV_PIX_FMT_NV21 && - srcFormat != AV_PIX_FMT_P010LE && srcFormat != AV_PIX_FMT_P010BE && - srcFormat != AV_PIX_FMT_P016LE && srcFormat != AV_PIX_FMT_P016BE)) + !isSemiPlanarYUV(srcFormat) && !isSemiPlanarYUV(dstFormat))) { if (isPacked(c->srcFormat)) c->swscale = packedCopyWrapper; diff --git a/libswscale/tests/swscale.c b/libswscale/tests/swscale.c index b4b8173a31489..e72c4c3306ad4 100644 --- a/libswscale/tests/swscale.c +++ b/libswscale/tests/swscale.c @@ -55,8 +55,8 @@ (x) == AV_PIX_FMT_RGB32_1 || \ (x) == AV_PIX_FMT_YUVA420P) -static uint64_t getSSD(const uint8_t *src1, const uint8_t *src2, int stride1, - int stride2, int w, int h) +static uint64_t getSSD(const uint8_t *src1, const uint8_t *src2, + int stride1, int stride2, int w, int h) { int x, y; uint64_t ssd = 0; @@ -80,7 +80,7 @@ struct Results { // test by ref -> src -> dst -> out & compare out against ref // ref & out are YV12 -static int doTest(uint8_t *ref[4], int refStride[4], int w, int h, +static int doTest(const uint8_t * const ref[4], int refStride[4], int w, int h, enum AVPixelFormat srcFormat, enum AVPixelFormat dstFormat, int srcW, int srcH, int dstW, int dstH, int flags, struct Results *r) @@ -90,7 +90,7 @@ static int doTest(uint8_t *ref[4], int refStride[4], int w, int h, const AVPixFmtDescriptor *desc_dst = av_pix_fmt_desc_get(dstFormat); static enum AVPixelFormat cur_srcFormat; static int cur_srcW, cur_srcH; - static uint8_t *src[4]; + static const uint8_t *src[4]; static int srcStride[4]; uint8_t *dst[4] = { 0 }; uint8_t *out[4] = { 0 }; @@ -132,7 +132,8 @@ static int doTest(uint8_t *ref[4], int refStride[4], int w, int h, res = -1; goto end; } - sws_scale(srcContext, (const uint8_t * const*)ref, refStride, 0, h, src, srcStride); + sws_scale(srcContext, ref, refStride, 0, h, + (uint8_t * const *) src, srcStride); sws_freeContext(srcContext); cur_srcFormat = srcFormat; @@ -211,7 +212,8 @@ static int doTest(uint8_t *ref[4], int refStride[4], int w, int h, res = -1; goto end; } - sws_scale(outContext, (const uint8_t * const*)dst, dstStride, 0, dstH, out, refStride); + sws_scale(outContext, (const uint8_t * const *) dst, dstStride, 0, dstH, + out, refStride); ssdY = getSSD(ref[0], out[0], refStride[0], refStride[0], w, h); if (hasChroma(srcFormat) && hasChroma(dstFormat)) { @@ -249,7 +251,8 @@ static int doTest(uint8_t *ref[4], int refStride[4], int w, int h, return res; } -static void selfTest(uint8_t *ref[4], int refStride[4], int w, int h, +static void selfTest(const uint8_t * const ref[4], int refStride[4], + int w, int h, enum AVPixelFormat srcFormat_in, enum AVPixelFormat dstFormat_in) { @@ -299,7 +302,8 @@ static void selfTest(uint8_t *ref[4], int refStride[4], int w, int h, } } -static int fileTest(uint8_t *ref[4], int refStride[4], int w, int h, FILE *fp, +static int fileTest(const uint8_t * const ref[4], int refStride[4], + int w, int h, FILE *fp, enum AVPixelFormat srcFormat_in, enum AVPixelFormat dstFormat_in) { @@ -362,7 +366,7 @@ int main(int argc, char **argv) const uint8_t * const rgb_src[4] = { rgb_data, NULL, NULL, NULL }; int rgb_stride[4] = { 4 * W, 0, 0, 0 }; uint8_t *data = av_malloc(4 * W * H); - uint8_t *src[4] = { data, data + W * H, data + W * H * 2, data + W * H * 3 }; + const uint8_t * const src[4] = { data, data + W * H, data + W * H * 2, data + W * H * 3 }; int stride[4] = { W, W, W, W }; int x, y; struct SwsContext *sws; @@ -418,7 +422,7 @@ int main(int argc, char **argv) for (y = 0; y < H; y++) for (x = 0; x < W * 4; x++) rgb_data[ x + y * 4 * W] = av_lfg_get(&rand); - sws_scale(sws, rgb_src, rgb_stride, 0, H / 12, src, stride); + sws_scale(sws, rgb_src, rgb_stride, 0, H / 12, (uint8_t * const *) src, stride); sws_freeContext(sws); av_free(rgb_data); diff --git a/libswscale/utils.c b/libswscale/utils.c index dcab707de64bb..98a6b994760fb 100644 --- a/libswscale/utils.c +++ b/libswscale/utils.c @@ -27,7 +27,7 @@ #include #include #include -#if HAVE_SYS_MMAN_H +#if HAVE_MMAP #include #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) #define MAP_ANONYMOUS MAP_ANON @@ -254,8 +254,8 @@ static const FormatEntry format_entries[AV_PIX_FMT_NB] = { [AV_PIX_FMT_AYUV64LE] = { 1, 1}, [AV_PIX_FMT_P010LE] = { 1, 1 }, [AV_PIX_FMT_P010BE] = { 1, 1 }, - [AV_PIX_FMT_P016LE] = { 1, 0 }, - [AV_PIX_FMT_P016BE] = { 1, 0 }, + [AV_PIX_FMT_P016LE] = { 1, 1 }, + [AV_PIX_FMT_P016BE] = { 1, 1 }, }; int sws_isSupportedInput(enum AVPixelFormat pix_fmt) diff --git a/libswscale/version.h b/libswscale/version.h index 474e93b2615e3..6d80527509fbd 100644 --- a/libswscale/version.h +++ b/libswscale/version.h @@ -26,8 +26,8 @@ #include "libavutil/version.h" -#define LIBSWSCALE_VERSION_MAJOR 4 -#define LIBSWSCALE_VERSION_MINOR 8 +#define LIBSWSCALE_VERSION_MAJOR 5 +#define LIBSWSCALE_VERSION_MINOR 1 #define LIBSWSCALE_VERSION_MICRO 100 #define LIBSWSCALE_VERSION_INT AV_VERSION_INT(LIBSWSCALE_VERSION_MAJOR, \ diff --git a/libswscale/x86/Makefile b/libswscale/x86/Makefile index b50c7f265a666..f317d5dd9bf7a 100644 --- a/libswscale/x86/Makefile +++ b/libswscale/x86/Makefile @@ -11,3 +11,4 @@ OBJS-$(CONFIG_XMM_CLOBBER_TEST) += x86/w64xmmtest.o X86ASM-OBJS += x86/input.o \ x86/output.o \ x86/scale.o \ + x86/rgb_2_rgb.o \ diff --git a/libswscale/x86/rgb2rgb.c b/libswscale/x86/rgb2rgb.c index ffd12e16094c4..e5f318a72c205 100644 --- a/libswscale/x86/rgb2rgb.c +++ b/libswscale/x86/rgb2rgb.c @@ -144,11 +144,17 @@ DECLARE_ALIGNED(8, extern const uint64_t, ff_bgr2UVOffset); #endif /* HAVE_INLINE_ASM */ +void ff_shuffle_bytes_2103_ssse3(const uint8_t *src, uint8_t *dst, int src_size); +void ff_shuffle_bytes_0321_ssse3(const uint8_t *src, uint8_t *dst, int src_size); +void ff_shuffle_bytes_1230_ssse3(const uint8_t *src, uint8_t *dst, int src_size); +void ff_shuffle_bytes_3012_ssse3(const uint8_t *src, uint8_t *dst, int src_size); +void ff_shuffle_bytes_3210_ssse3(const uint8_t *src, uint8_t *dst, int src_size); + av_cold void rgb2rgb_init_x86(void) { -#if HAVE_INLINE_ASM int cpu_flags = av_get_cpu_flags(); +#if HAVE_INLINE_ASM if (INLINE_MMX(cpu_flags)) rgb2rgb_init_mmx(); if (INLINE_AMD3DNOW(cpu_flags)) @@ -160,4 +166,12 @@ av_cold void rgb2rgb_init_x86(void) if (INLINE_AVX(cpu_flags)) rgb2rgb_init_avx(); #endif /* HAVE_INLINE_ASM */ + + if (EXTERNAL_SSSE3(cpu_flags)) { + shuffle_bytes_0321 = ff_shuffle_bytes_0321_ssse3; + shuffle_bytes_2103 = ff_shuffle_bytes_2103_ssse3; + shuffle_bytes_1230 = ff_shuffle_bytes_1230_ssse3; + shuffle_bytes_3012 = ff_shuffle_bytes_3012_ssse3; + shuffle_bytes_3210 = ff_shuffle_bytes_3210_ssse3; + } } diff --git a/libswscale/x86/rgb_2_rgb.asm b/libswscale/x86/rgb_2_rgb.asm new file mode 100644 index 0000000000000..db45e313d82cd --- /dev/null +++ b/libswscale/x86/rgb_2_rgb.asm @@ -0,0 +1,86 @@ +;****************************************************************************** +;* Copyright Nick Kurshev +;* Copyright Michael (michaelni@gmx.at) +;* Copyright 2018 Jokyo Images +;* +;* This file is part of FFmpeg. +;* +;* FFmpeg is free software; you can redistribute it and/or +;* modify it under the terms of the GNU Lesser General Public +;* License as published by the Free Software Foundation; either +;* version 2.1 of the License, or (at your option) any later version. +;* +;* FFmpeg is distributed in the hope that it will be useful, +;* but WITHOUT ANY WARRANTY; without even the implied warranty of +;* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;* Lesser General Public License for more details. +;* +;* You should have received a copy of the GNU Lesser General Public +;* License along with FFmpeg; if not, write to the Free Software +;* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +;****************************************************************************** + +%include "libavutil/x86/x86util.asm" + +SECTION_RODATA + +pb_shuffle2103: db 2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15 +pb_shuffle0321: db 0, 3, 2, 1, 4, 7, 6, 5, 8, 11, 10, 9, 12, 15, 14, 13 +pb_shuffle1230: db 1, 2, 3, 0, 5, 6, 7, 4, 9, 10, 11, 8, 13, 14, 15, 12 +pb_shuffle3012: db 3, 0, 1, 2, 7, 4, 5, 6, 11, 8, 9, 10, 15, 12, 13, 14 +pb_shuffle3210: db 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12 + +SECTION .text + +;------------------------------------------------------------------------------ +; shuffle_bytes_## (const uint8_t *src, uint8_t *dst, int src_size) +;------------------------------------------------------------------------------ +; %1-4 index shuffle +%macro SHUFFLE_BYTES 4 +cglobal shuffle_bytes_%1%2%3%4, 3, 5, 2, src, dst, w, tmp, x + VBROADCASTI128 m0, [pb_shuffle%1%2%3%4] + movsxdifnidn wq, wd + mov xq, wq + + add srcq, wq + add dstq, wq + neg wq + +;calc scalar loop + and xq, mmsize-4 + je .loop_simd + +.loop_scalar: + mov tmpb, [srcq + wq + %1] + mov [dstq+wq + 0], tmpb + mov tmpb, [srcq + wq + %2] + mov [dstq+wq + 1], tmpb + mov tmpb, [srcq + wq + %3] + mov [dstq+wq + 2], tmpb + mov tmpb, [srcq + wq + %4] + mov [dstq+wq + 3], tmpb + add wq, 4 + sub xq, 4 + jg .loop_scalar + +;check if src_size < mmsize +cmp wq, 0 +jge .end + +.loop_simd: + movu m1, [srcq+wq] + pshufb m1, m0 + movu [dstq+wq], m1 + add wq, mmsize + jl .loop_simd + +.end: + RET +%endmacro + +INIT_XMM ssse3 +SHUFFLE_BYTES 2, 1, 0, 3 +SHUFFLE_BYTES 0, 3, 2, 1 +SHUFFLE_BYTES 1, 2, 3, 0 +SHUFFLE_BYTES 3, 0, 1, 2 +SHUFFLE_BYTES 3, 2, 1, 0 diff --git a/libswscale/x86/scale.asm b/libswscale/x86/scale.asm index f9781703a9f1f..83cabff722a0a 100644 --- a/libswscale/x86/scale.asm +++ b/libswscale/x86/scale.asm @@ -364,15 +364,7 @@ cglobal hscale%1to%2_%4, %5, 10, %6, pos0, dst, w, srcmem, filter, fltpos, fltsi movd [dstq+wq*2], m0 %endif ; %3 ==/!= X %else ; %2 == 19 -%if mmsize == 8 - PMINSD_MMX m0, m2, m4 -%elif cpuflag(sse4) - pminsd m0, m2 -%else ; sse2/ssse3 - cvtdq2ps m0, m0 - minps m0, m2 - cvtps2dq m0, m0 -%endif ; mmx/sse2/ssse3/sse4 + PMINSD m0, m2, m4 %ifnidn %3, X mova [dstq+wq*(4>>wshr)], m0 %else ; %3 == X diff --git a/libswscale/x86/swscale.c b/libswscale/x86/swscale.c index 869e7fb176401..7dc2d7057442f 100644 --- a/libswscale/x86/swscale.c +++ b/libswscale/x86/swscale.c @@ -53,13 +53,13 @@ DECLARE_ASM_CONST(8, uint64_t, b15Mask)= 0x001F001F001F001FLL; DECLARE_ASM_CONST(8, uint64_t, g15Mask)= 0x03E003E003E003E0LL; DECLARE_ASM_CONST(8, uint64_t, r15Mask)= 0x7C007C007C007C00LL; -DECLARE_ALIGNED(8, const uint64_t, ff_M24A) = 0x00FF0000FF0000FFLL; -DECLARE_ALIGNED(8, const uint64_t, ff_M24B) = 0xFF0000FF0000FF00LL; -DECLARE_ALIGNED(8, const uint64_t, ff_M24C) = 0x0000FF0000FF0000LL; +DECLARE_ASM_ALIGNED(8, const uint64_t, ff_M24A) = 0x00FF0000FF0000FFLL; +DECLARE_ASM_ALIGNED(8, const uint64_t, ff_M24B) = 0xFF0000FF0000FF00LL; +DECLARE_ASM_ALIGNED(8, const uint64_t, ff_M24C) = 0x0000FF0000FF0000LL; -DECLARE_ALIGNED(8, const uint64_t, ff_bgr2YOffset) = 0x1010101010101010ULL; -DECLARE_ALIGNED(8, const uint64_t, ff_bgr2UVOffset) = 0x8080808080808080ULL; -DECLARE_ALIGNED(8, const uint64_t, ff_w1111) = 0x0001000100010001ULL; +DECLARE_ASM_ALIGNED(8, const uint64_t, ff_bgr2YOffset) = 0x1010101010101010ULL; +DECLARE_ASM_ALIGNED(8, const uint64_t, ff_bgr2UVOffset) = 0x8080808080808080ULL; +DECLARE_ASM_ALIGNED(8, const uint64_t, ff_w1111) = 0x0001000100010001ULL; //MMX versions diff --git a/libswscale/yuv2rgb.c b/libswscale/yuv2rgb.c index 1fe5abed9c49c..737cbb06c806e 100644 --- a/libswscale/yuv2rgb.c +++ b/libswscale/yuv2rgb.c @@ -267,7 +267,11 @@ ENDYUV2RGBLINE(8, 1) PUTRGB(dst_2, py_2, 0); ENDYUV2RGBFUNC() +#if HAVE_BIGENDIAN +YUV2RGBFUNC(yuva2argb_c, uint32_t, 1) +#else YUV2RGBFUNC(yuva2rgba_c, uint32_t, 1) +#endif LOADCHROMA(0); PUTRGBA(dst_1, py_1, pa_1, 0, 24); PUTRGBA(dst_2, py_2, pa_2, 0, 24); @@ -301,7 +305,11 @@ ENDYUV2RGBLINE(8, 1) PUTRGBA(dst_2, py_2, pa_2, 0, 24); ENDYUV2RGBFUNC() +#if HAVE_BIGENDIAN +YUV2RGBFUNC(yuva2rgba_c, uint32_t, 1) +#else YUV2RGBFUNC(yuva2argb_c, uint32_t, 1) +#endif LOADCHROMA(0); PUTRGBA(dst_1, py_1, pa_1, 0, 0); PUTRGBA(dst_2, py_2, pa_2, 0, 0); diff --git a/tests/Makefile b/tests/Makefile index 278be24ccbcd4..6074ac748e07c 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -1,5 +1,3 @@ -FFSERVER_REFFILE = $(SRC_PATH)/tests/ffserver.regression.ref - THREADS = 1 VREF = tests/vsynth1/00.pgm AREF = tests/data/asynth1.sw @@ -11,14 +9,6 @@ FFMPEG=ffmpeg$(PROGSSUF)$(EXESUF) $(AREF): CMP= -ffservertest: export PROGSUF = $(PROGSSUF) -ffservertest: ffserver$(PROGSSUF)$(EXESUF) ffmpeg$(PROGSSUF)$(EXESUF) tests/vsynth1/00.pgm tests/data/asynth1.sw - @echo - @echo "Unfortunately ffserver is broken and therefore its regression" - @echo "test fails randomly. Treat the results accordingly." - @echo - $(SRC_PATH)/tests/ffserver-regression.sh $(FFSERVER_REFFILE) $(SRC_PATH)/tests/ffserver.conf "$(TARGET_SAMPLES)" "$(TARGET_EXEC)" "$(TARGET_PATH)" - APITESTSDIR := tests/api OBJDIRS += tests/data tests/vsynth1 tests/data/filtergraphs $(APITESTSDIR)/ @@ -113,7 +103,9 @@ include $(SRC_PATH)/tests/fate/apng.mak include $(SRC_PATH)/tests/fate/atrac.mak include $(SRC_PATH)/tests/fate/audio.mak include $(SRC_PATH)/tests/fate/bmp.mak +include $(SRC_PATH)/tests/fate/build.mak include $(SRC_PATH)/tests/fate/canopus.mak +include $(SRC_PATH)/tests/fate/cbs.mak include $(SRC_PATH)/tests/fate/cdxl.mak include $(SRC_PATH)/tests/fate/checkasm.mak include $(SRC_PATH)/tests/fate/concatdec.mak @@ -137,7 +129,9 @@ include $(SRC_PATH)/tests/fate/flvenc.mak include $(SRC_PATH)/tests/fate/gapless.mak include $(SRC_PATH)/tests/fate/gif.mak include $(SRC_PATH)/tests/fate/h264.mak +include $(SRC_PATH)/tests/fate/hap.mak include $(SRC_PATH)/tests/fate/hevc.mak +include $(SRC_PATH)/tests/fate/id3v2.mak include $(SRC_PATH)/tests/fate/image.mak include $(SRC_PATH)/tests/fate/indeo.mak include $(SRC_PATH)/tests/fate/libavcodec.mak @@ -156,6 +150,7 @@ include $(SRC_PATH)/tests/fate/mov.mak include $(SRC_PATH)/tests/fate/mp3.mak include $(SRC_PATH)/tests/fate/mpc.mak include $(SRC_PATH)/tests/fate/mpeg4.mak +include $(SRC_PATH)/tests/fate/mpegps.mak include $(SRC_PATH)/tests/fate/mpegts.mak include $(SRC_PATH)/tests/fate/mxf.mak include $(SRC_PATH)/tests/fate/opus.mak diff --git a/tests/api/api-band-test.c b/tests/api/api-band-test.c index 5ccba4f766555..a84f6b7e5560d 100644 --- a/tests/api/api-band-test.c +++ b/tests/api/api-band-test.c @@ -214,8 +214,6 @@ int main(int argc, char **argv) return 1; } - av_register_all(); - if (video_decode(argv[1]) != 0) return 1; diff --git a/tests/api/api-codec-param-test.c b/tests/api/api-codec-param-test.c index 377a5e9c793ef..0868322cb4b91 100644 --- a/tests/api/api-codec-param-test.c +++ b/tests/api/api-codec-param-test.c @@ -231,8 +231,6 @@ int main(int argc, char* argv[]) AVFormatContext *fmt_ctx = NULL; AVFormatContext *fmt_ctx_no_decode = NULL; - av_register_all(); - if (argc < 2) { av_log(NULL, AV_LOG_ERROR, "Usage: %s \n", argv[0]); return -1; diff --git a/tests/api/api-flac-test.c b/tests/api/api-flac-test.c index c5a37f03e11e7..2e9081266f829 100644 --- a/tests/api/api-flac-test.c +++ b/tests/api/api-flac-test.c @@ -245,8 +245,6 @@ int main(void) int sample_rates[] = {8000, 44100, 48000, 192000}; int cl, sr; - avcodec_register_all(); - enc = avcodec_find_encoder(AV_CODEC_ID_FLAC); if (!enc) { av_log(NULL, AV_LOG_ERROR, "Can't find encoder\n"); diff --git a/tests/api/api-h264-test.c b/tests/api/api-h264-test.c index 52282e0007458..66669fa0c353c 100644 --- a/tests/api/api-h264-test.c +++ b/tests/api/api-h264-test.c @@ -158,8 +158,6 @@ int main(int argc, char **argv) return 1; } - av_register_all(); - if (video_decode_example(argv[1]) != 0) return 1; diff --git a/tests/api/api-seek-test.c b/tests/api/api-seek-test.c index 2b32cb9e4f382..d0531a2f731f8 100644 --- a/tests/api/api-seek-test.c +++ b/tests/api/api-seek-test.c @@ -279,8 +279,6 @@ int main(int argc, char **argv) return 1; } - av_register_all(); - if (seek_test(argv[1], argv[2], argv[3]) != 0) return 1; diff --git a/tests/audiomatch.c b/tests/audiomatch.c index ca56df09b302e..d44c4070e072f 100644 --- a/tests/audiomatch.c +++ b/tests/audiomatch.c @@ -25,23 +25,23 @@ #define FFMIN(a,b) ((a) > (b) ? (b) : (a)) #define FFMAX(a,b) ((a) > (b) ? (a) : (b)) -static int64_t fsize(FILE *f){ - int64_t end, pos= ftell(f); +static int64_t fsize(FILE *f) { + int64_t end, pos = ftell(f); fseek(f, 0, SEEK_END); end = ftell(f); fseek(f, pos, SEEK_SET); return end; } -int main(int argc, char **argv){ +int main(int argc, char **argv) { FILE *f[2]; int i, pos; int siglen, datlen; int bestpos = 0; - double bestc=0; - double sigamp= 0; + double bestc = 0; + double sigamp = 0; int16_t *signal, *data; - int maxshift= 16384; + int maxshift = 16384; if (argc < 3) { printf("audiomatch \n"); @@ -80,31 +80,35 @@ int main(int argc, char **argv){ data = malloc(datlen * sizeof(*data)); signal = malloc(siglen * sizeof(*signal)); - fread(data , 1, datlen, f[0]); - fread(signal, 1, siglen, f[1]); + if (fread(data , 1, datlen, f[0]) != datlen) + return 1; + if (fread(signal, 1, siglen, f[1]) != siglen) + return 1; datlen /= 2; siglen /= 2; - for(i=0; i sigamp * 0.94) + if (fabs(c) > sigamp * 0.94) maxshift = FFMIN(maxshift, fabs(pos)+32); - if(fabs(c)>fabs(bestc)){ - bestc= c; + if (fabs(c) > fabs(bestc)) { + bestc = c; bestpos = pos; } } printf("presig: %d postsig:%d c:%7.4f lenerr:%d\n", bestpos, datlen - siglen - bestpos, bestc / sigamp, datlen - siglen); + + return 0; } diff --git a/tests/checkasm/Makefile b/tests/checkasm/Makefile index 14916e5100c55..0233d2f98927d 100644 --- a/tests/checkasm/Makefile +++ b/tests/checkasm/Makefile @@ -10,6 +10,7 @@ AVCODECOBJS-$(CONFIG_H264DSP) += h264dsp.o AVCODECOBJS-$(CONFIG_H264PRED) += h264pred.o AVCODECOBJS-$(CONFIG_H264QPEL) += h264qpel.o AVCODECOBJS-$(CONFIG_LLVIDDSP) += llviddsp.o +AVCODECOBJS-$(CONFIG_LLVIDENCDSP) += llviddspenc.o AVCODECOBJS-$(CONFIG_VP8DSP) += vp8dsp.o AVCODECOBJS-$(CONFIG_VIDEODSP) += videodsp.o @@ -19,9 +20,11 @@ AVCODECOBJS-$(CONFIG_AAC_DECODER) += aacpsdsp.o \ AVCODECOBJS-$(CONFIG_ALAC_DECODER) += alacdsp.o AVCODECOBJS-$(CONFIG_DCA_DECODER) += synth_filter.o AVCODECOBJS-$(CONFIG_EXR_DECODER) += exrdsp.o +AVCODECOBJS-$(CONFIG_HUFFYUV_DECODER) += huffyuvdsp.o AVCODECOBJS-$(CONFIG_JPEG2000_DECODER) += jpeg2000dsp.o AVCODECOBJS-$(CONFIG_PIXBLOCKDSP) += pixblockdsp.o -AVCODECOBJS-$(CONFIG_HEVC_DECODER) += hevc_add_res.o hevc_idct.o +AVCODECOBJS-$(CONFIG_HEVC_DECODER) += hevc_add_res.o hevc_idct.o hevc_sao.o +AVCODECOBJS-$(CONFIG_UTVIDEO_DECODER) += utvideodsp.o AVCODECOBJS-$(CONFIG_V210_ENCODER) += v210enc.o AVCODECOBJS-$(CONFIG_VP9_DECODER) += vp9dsp.o @@ -30,9 +33,17 @@ CHECKASMOBJS-$(CONFIG_AVCODEC) += $(AVCODECOBJS-yes) # libavfilter tests AVFILTEROBJS-$(CONFIG_BLEND_FILTER) += vf_blend.o AVFILTEROBJS-$(CONFIG_COLORSPACE_FILTER) += vf_colorspace.o +AVFILTEROBJS-$(CONFIG_HFLIP_FILTER) += vf_hflip.o +AVFILTEROBJS-$(CONFIG_THRESHOLD_FILTER) += vf_threshold.o CHECKASMOBJS-$(CONFIG_AVFILTER) += $(AVFILTEROBJS-yes) +# swscale tests +SWSCALEOBJS += sw_rgb.o + +CHECKASMOBJS-$(CONFIG_SWSCALE) += $(SWSCALEOBJS) + +# libavutil tests AVUTILOBJS += fixed_dsp.o AVUTILOBJS += float_dsp.o @@ -56,7 +67,7 @@ tests/checkasm/checkasm.o: CFLAGS += -Umain CHECKASM := tests/checkasm/checkasm$(EXESUF) $(CHECKASM): $(CHECKASMOBJS) $(FF_STATIC_DEP_LIBS) - $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $(CHECKASMOBJS) $(FF_STATIC_DEP_LIBS) $(EXTRALIBS) + $(LD) $(LDFLAGS) $(LDEXEFLAGS) $(LD_O) $(CHECKASMOBJS) $(FF_STATIC_DEP_LIBS) $(EXTRALIBS-avcodec) $(EXTRALIBS-avfilter) $(EXTRALIBS-avformat) $(EXTRALIBS-avutil) $(EXTRALIBS-swresample) $(EXTRALIBS) checkasm: $(CHECKASM) diff --git a/tests/checkasm/aarch64/checkasm.S b/tests/checkasm/aarch64/checkasm.S index 75a9a561439b7..89f2b77548ba5 100644 --- a/tests/checkasm/aarch64/checkasm.S +++ b/tests/checkasm/aarch64/checkasm.S @@ -22,7 +22,7 @@ #include "libavutil/aarch64/asm.S" -const register_init +const register_init, align=4 .quad 0x21f86d66c8ca00ce .quad 0x75b6ba21077c48ad .quad 0xed56bb2dcb3c7736 diff --git a/tests/checkasm/checkasm.c b/tests/checkasm/checkasm.c index b8b0e32dbd4b5..ba1d1d0253d2b 100644 --- a/tests/checkasm/checkasm.c +++ b/tests/checkasm/checkasm.c @@ -116,6 +116,10 @@ static const struct { #if CONFIG_HEVC_DECODER { "hevc_add_res", checkasm_check_hevc_add_res }, { "hevc_idct", checkasm_check_hevc_idct }, + { "hevc_sao", checkasm_check_hevc_sao }, + #endif + #if CONFIG_HUFFYUV_DECODER + { "huffyuvdsp", checkasm_check_huffyuvdsp }, #endif #if CONFIG_JPEG2000_DECODER { "jpeg2000dsp", checkasm_check_jpeg2000dsp }, @@ -123,9 +127,15 @@ static const struct { #if CONFIG_HUFFYUVDSP { "llviddsp", checkasm_check_llviddsp }, #endif + #if CONFIG_LLVIDENCDSP + { "llviddspenc", checkasm_check_llviddspenc }, + #endif #if CONFIG_PIXBLOCKDSP { "pixblockdsp", checkasm_check_pixblockdsp }, #endif + #if CONFIG_UTVIDEO_DECODER + { "utvideodsp", checkasm_check_utvideodsp }, + #endif #if CONFIG_V210_ENCODER { "v210enc", checkasm_check_v210enc }, #endif @@ -146,6 +156,15 @@ static const struct { #if CONFIG_COLORSPACE_FILTER { "vf_colorspace", checkasm_check_colorspace }, #endif + #if CONFIG_HFLIP_FILTER + { "vf_hflip", checkasm_check_vf_hflip }, + #endif + #if CONFIG_THRESHOLD_FILTER + { "vf_threshold", checkasm_check_vf_threshold }, + #endif +#endif +#if CONFIG_SWSCALE + { "sw_rgb", checkasm_check_sw_rgb }, #endif #if CONFIG_AVUTIL { "fixed_dsp", checkasm_check_fixed_dsp }, @@ -192,6 +211,7 @@ static const struct { { "FMA3", "fma3", AV_CPU_FLAG_FMA3 }, { "FMA4", "fma4", AV_CPU_FLAG_FMA4 }, { "AVX2", "avx2", AV_CPU_FLAG_AVX2 }, + { "AVX-512", "avx512", AV_CPU_FLAG_AVX512 }, #endif { NULL } }; @@ -274,8 +294,12 @@ int float_near_ulp_array(const float *a, const float *b, unsigned max_ulp, int float_near_abs_eps(float a, float b, float eps) { float abs_diff = fabsf(a - b); + if (abs_diff < eps) + return 1; - return abs_diff < eps; + fprintf(stderr, "test failed comparing %g with %g (abs diff=%g with EPS=%g)\n", a, b, abs_diff, eps); + + return 0; } int float_near_abs_eps_array(const float *a, const float *b, float eps, diff --git a/tests/checkasm/checkasm.h b/tests/checkasm/checkasm.h index e5b1877dc00a3..dcab74de06019 100644 --- a/tests/checkasm/checkasm.h +++ b/tests/checkasm/checkasm.h @@ -57,12 +57,19 @@ void checkasm_check_h264pred(void); void checkasm_check_h264qpel(void); void checkasm_check_hevc_add_res(void); void checkasm_check_hevc_idct(void); +void checkasm_check_hevc_sao(void); +void checkasm_check_huffyuvdsp(void); void checkasm_check_jpeg2000dsp(void); void checkasm_check_llviddsp(void); +void checkasm_check_llviddspenc(void); void checkasm_check_pixblockdsp(void); void checkasm_check_sbrdsp(void); void checkasm_check_synth_filter(void); +void checkasm_check_sw_rgb(void); +void checkasm_check_utvideodsp(void); void checkasm_check_v210enc(void); +void checkasm_check_vf_hflip(void); +void checkasm_check_vf_threshold(void); void checkasm_check_vp8dsp(void); void checkasm_check_vp9dsp(void); void checkasm_check_videodsp(void); diff --git a/tests/checkasm/float_dsp.c b/tests/checkasm/float_dsp.c index 9b0a221c25d2c..2f999a3162571 100644 --- a/tests/checkasm/float_dsp.c +++ b/tests/checkasm/float_dsp.c @@ -165,7 +165,8 @@ static void test_vector_dmul_scalar(const double *src0, const double *src1) call_ref(cdst, src0, src1[0], LEN); call_new(odst, src0, src1[0], LEN); for (i = 0; i < LEN; i++) { - if (!double_near_abs_eps(cdst[i], odst[i], DBL_EPSILON)) { + double t = fabs(src1[0]) + fabs(src0[i]) + fabs(src1[0] * src0[i]) + 1.0; + if (!double_near_abs_eps(cdst[i], odst[i], t * 2 * DBL_EPSILON)) { fprintf(stderr, "%d: %- .12f - %- .12f = % .12g\n", i, cdst[i], odst[i], cdst[i] - odst[i]); fail(); diff --git a/tests/checkasm/h264dsp.c b/tests/checkasm/h264dsp.c index 945423703f91a..5f73bc9f08254 100644 --- a/tests/checkasm/h264dsp.c +++ b/tests/checkasm/h264dsp.c @@ -22,6 +22,7 @@ #include "checkasm.h" #include "libavcodec/avcodec.h" #include "libavcodec/h264dsp.h" +#include "libavcodec/h264data.h" #include "libavutil/common.h" #include "libavutil/internal.h" #include "libavutil/intreadwrite.h" @@ -223,10 +224,97 @@ static void check_idct(void) } } } - report("idct"); +} + +static void check_idct_multiple(void) +{ + LOCAL_ALIGNED_16(uint8_t, dst_full, [16 * 16 * 2]); + LOCAL_ALIGNED_16(int16_t, coef_full, [16 * 16 * 2]); + LOCAL_ALIGNED_16(uint8_t, dst0, [16 * 16 * 2]); + LOCAL_ALIGNED_16(uint8_t, dst1, [16 * 16 * 2]); + LOCAL_ALIGNED_16(int16_t, coef0, [16 * 16 * 2]); + LOCAL_ALIGNED_16(int16_t, coef1, [16 * 16 * 2]); + LOCAL_ALIGNED_16(uint8_t, nnzc, [15 * 8]); + H264DSPContext h; + int bit_depth, i, y, func; + declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *dst, const int *block_offset, int16_t *block, int stride, const uint8_t nnzc[15*8]); + + for (bit_depth = 8; bit_depth <= 10; bit_depth++) { + ff_h264dsp_init(&h, bit_depth, 1); + for (func = 0; func < 3; func++) { + void (*idct)(uint8_t *, const int *, int16_t *, int, const uint8_t[]) = NULL; + const char *name; + int sz = 4, intra = 0; + int block_offset[16] = { 0 }; + switch (func) { + case 0: + idct = h.h264_idct_add16; + name = "h264_idct_add16"; + break; + case 1: + idct = h.h264_idct_add16intra; + name = "h264_idct_add16intra"; + intra = 1; + break; + case 2: + idct = h.h264_idct8_add4; + name = "h264_idct8_add4"; + sz = 8; + break; + } + memset(nnzc, 0, 15 * 8); + memset(coef_full, 0, 16 * 16 * SIZEOF_COEF); + for (i = 0; i < 16 * 16; i += sz * sz) { + uint8_t src[8 * 8 * 2]; + uint8_t dst[8 * 8 * 2]; + int16_t coef[8 * 8 * 2]; + int index = i / sz; + int block_y = (index / 16) * sz; + int block_x = index % 16; + int offset = (block_y * 16 + block_x) * SIZEOF_PIXEL; + int nnz = rnd() % 3; + + randomize_buffers(); + if (sz == 4) + dct4x4(coef, bit_depth); + else + dct8x8(coef, bit_depth); + + for (y = 0; y < sz; y++) + memcpy(&dst_full[offset + y * 16 * SIZEOF_PIXEL], + &dst[PIXEL_STRIDE * y], sz * SIZEOF_PIXEL); + + if (nnz > 1) + nnz = sz * sz; + memcpy(&coef_full[i * SIZEOF_COEF/sizeof(coef[0])], + coef, nnz * SIZEOF_COEF); + + if (intra && nnz == 1) + nnz = 0; + + nnzc[scan8[i / 16]] = nnz; + block_offset[i / 16] = offset; + } + + if (check_func(idct, "%s_%dbpp", name, bit_depth)) { + memcpy(coef0, coef_full, 16 * 16 * SIZEOF_COEF); + memcpy(coef1, coef_full, 16 * 16 * SIZEOF_COEF); + memcpy(dst0, dst_full, 16 * 16 * SIZEOF_PIXEL); + memcpy(dst1, dst_full, 16 * 16 * SIZEOF_PIXEL); + call_ref(dst0, block_offset, coef0, 16 * SIZEOF_PIXEL, nnzc); + call_new(dst1, block_offset, coef1, 16 * SIZEOF_PIXEL, nnzc); + if (memcmp(dst0, dst1, 16 * 16 * SIZEOF_PIXEL) || + memcmp(coef0, coef1, 16 * 16 * SIZEOF_COEF)) + fail(); + bench_new(dst1, block_offset, coef1, 16 * SIZEOF_PIXEL, nnzc); + } + } + } } void checkasm_check_h264dsp(void) { check_idct(); + check_idct_multiple(); + report("idct"); } diff --git a/tests/checkasm/hevc_add_res.c b/tests/checkasm/hevc_add_res.c index 185656ae8c602..e92c6b427b656 100644 --- a/tests/checkasm/hevc_add_res.c +++ b/tests/checkasm/hevc_add_res.c @@ -61,7 +61,7 @@ static void check_add_res(HEVCDSPContext h, int bit_depth) memcpy(res1, res0, sizeof(*res0) * size); memcpy(dst1, dst0, sizeof(int16_t) * size); - if (check_func(h.add_residual[i - 2], "add_res_%dx%d_%d", block_size, block_size, bit_depth)) { + if (check_func(h.add_residual[i - 2], "hevc_add_res_%dx%d_%d", block_size, block_size, bit_depth)) { call_ref(dst0, res0, stride); call_new(dst1, res1, stride); if (memcmp(dst0, dst1, size)) diff --git a/tests/checkasm/hevc_idct.c b/tests/checkasm/hevc_idct.c index eea712101d3d7..c20111c2df9ae 100644 --- a/tests/checkasm/hevc_idct.c +++ b/tests/checkasm/hevc_idct.c @@ -87,7 +87,7 @@ void checkasm_check_hevc_idct(void) { int bit_depth; - for (bit_depth = 8; bit_depth <= 10; bit_depth++) { + for (bit_depth = 8; bit_depth <= 12; bit_depth += 2) { HEVCDSPContext h; ff_hevc_dsp_init(&h, bit_depth); @@ -95,7 +95,7 @@ void checkasm_check_hevc_idct(void) } report("idct_dc"); - for (bit_depth = 8; bit_depth <= 10; bit_depth++) { + for (bit_depth = 8; bit_depth <= 12; bit_depth += 2) { HEVCDSPContext h; ff_hevc_dsp_init(&h, bit_depth); diff --git a/tests/checkasm/hevc_sao.c b/tests/checkasm/hevc_sao.c new file mode 100644 index 0000000000000..8d0cf807746dc --- /dev/null +++ b/tests/checkasm/hevc_sao.c @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2018 Yingming Fan + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#include "libavutil/intreadwrite.h" + +#include "libavcodec/avcodec.h" + +#include "libavcodec/hevcdsp.h" + +#include "checkasm.h" + +static const uint32_t pixel_mask[3] = { 0xffffffff, 0x03ff03ff, 0x0fff0fff }; +static const uint32_t sao_size[5] = {8, 16, 32, 48, 64}; + +#define SIZEOF_PIXEL ((bit_depth + 7) / 8) +#define PIXEL_STRIDE (2*MAX_PB_SIZE + AV_INPUT_BUFFER_PADDING_SIZE) //same with sao_edge src_stride +#define BUF_SIZE (PIXEL_STRIDE * (64+2) * 2) //+2 for top and bottom row, *2 for high bit depth +#define OFFSET_THRESH (1 << (bit_depth - 5)) +#define OFFSET_LENGTH 5 + +#define randomize_buffers(buf0, buf1, size) \ + do { \ + uint32_t mask = pixel_mask[(bit_depth - 8) >> 1]; \ + int k; \ + for (k = 0; k < size; k += 4) { \ + uint32_t r = rnd() & mask; \ + AV_WN32A(buf0 + k, r); \ + AV_WN32A(buf1 + k, r); \ + } \ + } while (0) + +#define randomize_buffers2(buf, size) \ + do { \ + uint32_t max_offset = OFFSET_THRESH; \ + int k; \ + if (bit_depth == 8) { \ + for (k = 0; k < size; k++) { \ + uint8_t r = rnd() % max_offset; \ + buf[k] = r; \ + } \ + } else { \ + for (k = 0; k < size; k++) { \ + uint16_t r = rnd() % max_offset; \ + buf[k] = r; \ + } \ + } \ + } while (0) + +static void check_sao_band(HEVCDSPContext h, int bit_depth) +{ + int i; + LOCAL_ALIGNED_32(uint8_t, dst0, [BUF_SIZE]); + LOCAL_ALIGNED_32(uint8_t, dst1, [BUF_SIZE]); + LOCAL_ALIGNED_32(uint8_t, src0, [BUF_SIZE]); + LOCAL_ALIGNED_32(uint8_t, src1, [BUF_SIZE]); + int16_t offset_val[OFFSET_LENGTH]; + int left_class = rnd()%32; + + for (i = 0; i <= 4; i++) { + int block_size = sao_size[i]; + ptrdiff_t stride = PIXEL_STRIDE*SIZEOF_PIXEL; + declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *dst, uint8_t *src, ptrdiff_t dst_stride, ptrdiff_t src_stride, + int16_t *sao_offset_val, int sao_left_class, int width, int height); + + randomize_buffers(src0, src1, BUF_SIZE); + randomize_buffers2(offset_val, OFFSET_LENGTH); + memset(dst0, 0, BUF_SIZE); + memset(dst1, 0, BUF_SIZE); + + if (check_func(h.sao_band_filter[i], "hevc_sao_band_%dx%d_%d", block_size, block_size, bit_depth)) { + call_ref(dst0, src0, stride, stride, offset_val, left_class, block_size, block_size); + call_new(dst1, src1, stride, stride, offset_val, left_class, block_size, block_size); + if (memcmp(dst0, dst1, BUF_SIZE)) + fail(); + bench_new(dst1, src1, stride, stride, offset_val, left_class, block_size, block_size); + } + } +} + +static void check_sao_edge(HEVCDSPContext h, int bit_depth) +{ + int i; + LOCAL_ALIGNED_32(uint8_t, dst0, [BUF_SIZE]); + LOCAL_ALIGNED_32(uint8_t, dst1, [BUF_SIZE]); + LOCAL_ALIGNED_32(uint8_t, src0, [BUF_SIZE]); + LOCAL_ALIGNED_32(uint8_t, src1, [BUF_SIZE]); + int16_t offset_val[OFFSET_LENGTH]; + int eo = rnd()%4; + + for (i = 0; i <= 4; i++) { + int block_size = sao_size[i]; + ptrdiff_t stride = PIXEL_STRIDE*SIZEOF_PIXEL; + int offset = (AV_INPUT_BUFFER_PADDING_SIZE + PIXEL_STRIDE)*SIZEOF_PIXEL; + declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *dst, uint8_t *src, ptrdiff_t stride_dst, + int16_t *sao_offset_val, int eo, int width, int height); + + randomize_buffers(src0, src1, BUF_SIZE); + randomize_buffers2(offset_val, OFFSET_LENGTH); + memset(dst0, 0, BUF_SIZE); + memset(dst1, 0, BUF_SIZE); + + if (check_func(h.sao_edge_filter[i], "hevc_sao_edge_%dx%d_%d", block_size, block_size, bit_depth)) { + call_ref(dst0, src0 + offset, stride, offset_val, eo, block_size, block_size); + call_new(dst1, src1 + offset, stride, offset_val, eo, block_size, block_size); + if (memcmp(dst0, dst1, BUF_SIZE)) + fail(); + bench_new(dst1, src1 + offset, stride, offset_val, eo, block_size, block_size); + } + } +} + +void checkasm_check_hevc_sao(void) +{ + int bit_depth; + + for (bit_depth = 8; bit_depth <= 12; bit_depth += 2) { + HEVCDSPContext h; + + ff_hevc_dsp_init(&h, bit_depth); + check_sao_band(h, bit_depth); + } + report("sao_band"); + + for (bit_depth = 8; bit_depth <= 12; bit_depth += 2) { + HEVCDSPContext h; + + ff_hevc_dsp_init(&h, bit_depth); + check_sao_edge(h, bit_depth); + } + report("sao_edge"); +} diff --git a/tests/checkasm/huffyuvdsp.c b/tests/checkasm/huffyuvdsp.c new file mode 100644 index 0000000000000..8392022c0488e --- /dev/null +++ b/tests/checkasm/huffyuvdsp.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2016 Alexandra Hájková + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#include "libavutil/common.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" + +#include "libavcodec/huffyuvdsp.h" + +#include "checkasm.h" + +#define randomize_buffers(buf, size) \ + do { \ + int j; \ + for (j = 0; j < size; j++) \ + buf[j] = rnd() & 0xFFFF; \ + } while (0) + +static void check_add_int16(HuffYUVDSPContext c, unsigned mask, int width, const char * name) +{ + uint16_t *src0 = av_mallocz(width * sizeof(uint16_t)); + uint16_t *src1 = av_mallocz(width * sizeof(uint16_t)); + uint16_t *dst0 = av_mallocz(width * sizeof(uint16_t)); + uint16_t *dst1 = av_mallocz(width * sizeof(uint16_t)); + + declare_func_emms(AV_CPU_FLAG_MMX, void, uint16_t *dst, uint16_t *src, unsigned mask, int w); + + if (!src0 || !src1 || !dst0 || !dst1) + fail(); + + randomize_buffers(src0, width); + memcpy(src1, src0, width * sizeof(uint16_t)); + + if (check_func(c.add_int16, "%s", name)) { + call_ref(dst0, src0, mask, width); + call_new(dst1, src1, mask, width); + if (memcmp(dst0, dst1, width * sizeof(uint16_t))) + fail(); + bench_new(dst1, src1, mask, width); + } + + av_free(src0); + av_free(src1); + av_free(dst0); + av_free(dst1); +} + +void checkasm_check_huffyuvdsp(void) +{ + HuffYUVDSPContext c; + int width = 16 * av_clip(rnd(), 16, 128); + + ff_huffyuvdsp_init(&c, AV_PIX_FMT_YUV422P); + + /*! test width not multiple of mmsize */ + check_add_int16(c, 65535, width, "add_int16_rnd_width"); + report("add_int16_rnd_width"); + + /*! test always with the same size (for perf test) */ + check_add_int16(c, 65535, 16*128, "add_int16_128"); + report("add_int16_128"); +} diff --git a/tests/checkasm/jpeg2000dsp.c b/tests/checkasm/jpeg2000dsp.c index 48559df085e41..bce534dbaf6c5 100644 --- a/tests/checkasm/jpeg2000dsp.c +++ b/tests/checkasm/jpeg2000dsp.c @@ -29,43 +29,75 @@ #define randomize_buffers() \ do { \ int i; \ - for (i = 0; i < BUF_SIZE; i += 4) { \ - uint32_t r = rnd(); \ - AV_WN32A(ref0 + i, r); \ - AV_WN32A(new0 + i, r); \ - r = rnd(); \ - AV_WN32A(ref1 + i, r); \ - AV_WN32A(new1 + i, r); \ - r = rnd(); \ - AV_WN32A(ref2 + i, r); \ - AV_WN32A(new2 + i, r); \ - } \ + for (i = 0; i < BUF_SIZE*3; i++) \ + src[i] = rnd(); \ } while (0) -static void check_mct(uint8_t *ref0, uint8_t *ref1, uint8_t *ref2, - uint8_t *new0, uint8_t *new1, uint8_t *new2) { +#define randomize_buffers_float() \ + do { \ + int i; \ + for (i = 0; i < BUF_SIZE*3; i++) \ + src[i] = (float)rnd() / (UINT_MAX >> 5); \ + } while (0) + +static void check_rct_int(void) +{ + LOCAL_ALIGNED_32(int32_t, src, [BUF_SIZE*3]); + LOCAL_ALIGNED_32(int32_t, ref, [BUF_SIZE*3]); + LOCAL_ALIGNED_32(int32_t, new, [BUF_SIZE*3]); + int32_t *ref0 = &ref[BUF_SIZE*0], *new0 = &new[BUF_SIZE*0]; + int32_t *ref1 = &ref[BUF_SIZE*1], *new1 = &new[BUF_SIZE*1]; + int32_t *ref2 = &ref[BUF_SIZE*2], *new2 = &new[BUF_SIZE*2]; + declare_func(void, void *src0, void *src1, void *src2, int csize); randomize_buffers(); - call_ref(ref0, ref1, ref2, BUF_SIZE / sizeof(int32_t)); - call_new(new0, new1, new2, BUF_SIZE / sizeof(int32_t)); - if (memcmp(ref0, new0, BUF_SIZE) || memcmp(ref1, new1, BUF_SIZE) || - memcmp(ref2, new2, BUF_SIZE)) + memcpy(ref, src, BUF_SIZE * 3 * sizeof(*src)); + memcpy(new, src, BUF_SIZE * 3 * sizeof(*src)); + call_ref(ref0, ref1, ref2, BUF_SIZE); + call_new(new0, new1, new2, BUF_SIZE); + if (memcmp(ref0, new0, BUF_SIZE * sizeof(*src)) || + memcmp(ref1, new1, BUF_SIZE * sizeof(*src)) || + memcmp(ref2, new2, BUF_SIZE * sizeof(*src))) + fail(); + memcpy(new, src, BUF_SIZE * 3 * sizeof(*src)); + bench_new(new0, new1, new2, BUF_SIZE); +} + +static void check_ict_float(void) +{ + LOCAL_ALIGNED_32(float, src, [BUF_SIZE*3]); + LOCAL_ALIGNED_32(float, ref, [BUF_SIZE*3]); + LOCAL_ALIGNED_32(float, new, [BUF_SIZE*3]); + float *ref0 = &ref[BUF_SIZE*0], *new0 = &new[BUF_SIZE*0]; + float *ref1 = &ref[BUF_SIZE*1], *new1 = &new[BUF_SIZE*1]; + float *ref2 = &ref[BUF_SIZE*2], *new2 = &new[BUF_SIZE*2]; + + declare_func(void, void *src0, void *src1, void *src2, int csize); + + randomize_buffers_float(); + memcpy(ref, src, BUF_SIZE * 3 * sizeof(*src)); + memcpy(new, src, BUF_SIZE * 3 * sizeof(*src)); + call_ref(ref0, ref1, ref2, BUF_SIZE); + call_new(new0, new1, new2, BUF_SIZE); + if (!float_near_abs_eps_array(ref0, new0, 1.0e-5, BUF_SIZE) || + !float_near_abs_eps_array(ref1, new1, 1.0e-5, BUF_SIZE) || + !float_near_abs_eps_array(ref2, new2, 1.0e-5, BUF_SIZE)) fail(); - bench_new(new0, new1, new2, BUF_SIZE / sizeof(int32_t)); + memcpy(new, src, BUF_SIZE * 3 * sizeof(*src)); + bench_new(new0, new1, new2, BUF_SIZE); } void checkasm_check_jpeg2000dsp(void) { - LOCAL_ALIGNED_32(uint8_t, ref, [BUF_SIZE*3]); - LOCAL_ALIGNED_32(uint8_t, new, [BUF_SIZE*3]); Jpeg2000DSPContext h; ff_jpeg2000dsp_init(&h); if (check_func(h.mct_decode[FF_DWT53], "jpeg2000_rct_int")) - check_mct(&ref[BUF_SIZE*0], &ref[BUF_SIZE*1], &ref[BUF_SIZE*2], - &new[BUF_SIZE*0], &new[BUF_SIZE*1], &new[BUF_SIZE*2]); + check_rct_int(); + if (check_func(h.mct_decode[FF_DWT97], "jpeg2000_ict_float")) + check_ict_float(); report("mct_decode"); } diff --git a/tests/checkasm/llviddsp.c b/tests/checkasm/llviddsp.c index b1f3b83b43b59..4f75ffc4593b6 100644 --- a/tests/checkasm/llviddsp.c +++ b/tests/checkasm/llviddsp.c @@ -31,23 +31,30 @@ #define randomize_buffers(buf, size) \ do { \ int j; \ + uint8_t *tmp_buf = (uint8_t *)buf;\ for (j = 0; j < size; j++) \ - buf[j] = rnd() & 0xFF; \ + tmp_buf[j] = rnd() & 0xFF; \ } while (0) +#define init_buffer(a0, a1, type, width)\ + if (!a0 || !a1)\ + fail();\ + randomize_buffers(a0, width * sizeof(type));\ + memcpy(a1, a0, width*sizeof(type));\ + static void check_add_bytes(LLVidDSPContext c, int width) { - uint8_t *src0 = av_mallocz(width); - uint8_t *src1 = av_mallocz(width); uint8_t *dst0 = av_mallocz(width); uint8_t *dst1 = av_mallocz(width); + uint8_t *src0 = av_mallocz_array(width, sizeof(uint8_t)); + uint8_t *src1 = av_mallocz_array(width, sizeof(uint8_t)); declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *dst, uint8_t *src, ptrdiff_t w); - if (!src0 || !src1 || !dst0 || !dst1) + init_buffer(src0, src1, uint8_t, width); + + if (!dst0 || !dst1) fail(); - randomize_buffers(src0, width); - memcpy(src1, src0, width); if (check_func(c.add_bytes, "add_bytes")) { call_ref(dst0, src0, width); @@ -63,14 +70,151 @@ static void check_add_bytes(LLVidDSPContext c, int width) av_free(dst1); } +static void check_add_median_pred(LLVidDSPContext c, int width) { + int A0, A1, B0, B1; + uint8_t *dst0 = av_mallocz(width); + uint8_t *dst1 = av_mallocz(width); + uint8_t *src0 = av_mallocz_array(width, sizeof(uint8_t)); + uint8_t *src1 = av_mallocz_array(width, sizeof(uint8_t)); + uint8_t *diff0 = av_mallocz_array(width, sizeof(uint8_t)); + uint8_t *diff1 = av_mallocz_array(width, sizeof(uint8_t)); + declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *dst, const uint8_t *src1, + const uint8_t *diff, ptrdiff_t w, + int *left, int *left_top); + + init_buffer(src0, src1, uint8_t, width); + init_buffer(diff0, diff1, uint8_t, width); + + A0 = rnd() & 0xFF; + B0 = rnd() & 0xFF; + A1 = A0; + B1 = B0; + + + if (check_func(c.add_median_pred, "add_median_pred")) { + call_ref(dst0, src0, diff0, width, &A0, &B0); + call_new(dst1, src1, diff1, width, &A1, &B1); + if (memcmp(dst0, dst1, width) || (A0 != A1) || (B0 != B1)) + fail(); + bench_new(dst1, src1, diff1, width, &A1, &B1); + } + + av_free(src0); + av_free(src1); + av_free(diff0); + av_free(diff1); + av_free(dst0); + av_free(dst1); +} + +static void check_add_left_pred(LLVidDSPContext c, int width, int acc, const char * report) +{ + int res0, res1; + uint8_t *dst0 = av_mallocz(width); + uint8_t *dst1 = av_mallocz(width); + uint8_t *src0 = av_mallocz_array(width, sizeof(uint8_t)); + uint8_t *src1 = av_mallocz_array(width, sizeof(uint8_t)); + declare_func_emms(AV_CPU_FLAG_MMX, int, uint8_t *dst, uint8_t *src, ptrdiff_t w, int acc); + + init_buffer(src0, src1, uint8_t, width); + + if (!dst0 || !dst1) + fail(); + + if (check_func(c.add_left_pred, "%s", report)) { + res0 = call_ref(dst0, src0, width, acc); + res1 = call_new(dst1, src1, width, acc); + if ((res0 & 0xFF) != (res1 & 0xFF)||\ + memcmp(dst0, dst1, width)) + fail(); + bench_new(dst1, src1, width, acc); + } + + av_free(src0); + av_free(src1); + av_free(dst0); + av_free(dst1); +} + +static void check_add_left_pred_16(LLVidDSPContext c, unsigned mask, int width, unsigned acc, const char * report) +{ + int res0, res1; + uint16_t *dst0 = av_mallocz_array(width, sizeof(uint16_t)); + uint16_t *dst1 = av_mallocz_array(width, sizeof(uint16_t)); + uint16_t *src0 = av_mallocz_array(width, sizeof(uint16_t)); + uint16_t *src1 = av_mallocz_array(width, sizeof(uint16_t)); + declare_func_emms(AV_CPU_FLAG_MMX, int, uint16_t *dst, uint16_t *src, unsigned mask, ptrdiff_t w, unsigned acc); + + init_buffer(src0, src1, uint16_t, width); + + if (!dst0 || !dst1) + fail(); + + if (check_func(c.add_left_pred_int16, "%s", report)) { + res0 = call_ref(dst0, src0, mask, width, acc); + res1 = call_new(dst1, src1, mask, width, acc); + if ((res0 &0xFFFF) != (res1 &0xFFFF)||\ + memcmp(dst0, dst1, width)) + fail(); + bench_new(dst1, src1, mask, width, acc); + } + + av_free(src0); + av_free(src1); + av_free(dst0); + av_free(dst1); +} + +static void check_add_gradient_pred(LLVidDSPContext c, int w) { + int src_size, stride; + uint8_t *src0, *src1; + declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *src, const ptrdiff_t stride, + const ptrdiff_t width); + + stride = w + 32; + src_size = (stride + 32) * 2; /* dsp need previous line, and ignore the start of the line */ + src0 = av_mallocz(src_size); + src1 = av_mallocz(src_size); + + init_buffer(src0, src1, uint8_t, src_size); + + if (check_func(c.add_gradient_pred, "add_gradient_pred")) { + call_ref(src0 + stride + 32, stride, w); + call_new(src1 + stride + 32, stride, w); + if (memcmp(src0, src1, stride)||/* previous line doesn't change */ + memcmp(src0+stride, src1 + stride, w + 32)) { + fail(); + } + bench_new(src1 + stride + 32, stride, w); + } + + av_free(src0); + av_free(src1); +} + void checkasm_check_llviddsp(void) { LLVidDSPContext c; int width = 16 * av_clip(rnd(), 16, 128); + int accRnd = rnd() & 0xFF; ff_llviddsp_init(&c); check_add_bytes(c, width); - report("add_bytes"); + + check_add_median_pred(c, width); + report("add_median_pred"); + + check_add_left_pred(c, width, 0, "add_left_pred_zero"); + report("add_left_pred_zero"); + + check_add_left_pred(c, width, accRnd, "add_left_pred_rnd_acc"); + report("add_left_pred_rnd_acc"); + + check_add_left_pred_16(c, 255, width, accRnd, "add_left_pred_int16"); + report("add_left_pred_int16"); + + check_add_gradient_pred(c, width); + report("add_gradient_pred"); } diff --git a/tests/checkasm/llviddspenc.c b/tests/checkasm/llviddspenc.c new file mode 100644 index 0000000000000..31eafd5526d1a --- /dev/null +++ b/tests/checkasm/llviddspenc.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2016 Alexandra Hájková + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#include "libavutil/common.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" + +#include "libavcodec/lossless_videoencdsp.h" + +#include "checkasm.h" + +#define randomize_buffers(buf, size) \ + do { \ + int j; \ + for (j = 0; j < size; j+=4) \ + AV_WN32(buf + j, rnd()); \ + } while (0) + +static const struct {uint8_t w, h, s;} planes[] = { + {16,16,16}, {21,23,25}, {32,17,48}, {15,128,16}, {128,127,128} +}; + +#define MAX_STRIDE 128 +#define MAX_HEIGHT 127 + +static void check_diff_bytes(LLVidEncDSPContext *c) +{ + int i; + LOCAL_ALIGNED_32(uint8_t, dst0, [MAX_STRIDE]); + LOCAL_ALIGNED_32(uint8_t, dst1, [MAX_STRIDE]); + LOCAL_ALIGNED_32(uint8_t, src0, [MAX_STRIDE]); + LOCAL_ALIGNED_32(uint8_t, src1, [MAX_STRIDE]); + LOCAL_ALIGNED_32(uint8_t, src2, [MAX_STRIDE]); + LOCAL_ALIGNED_32(uint8_t, src3, [MAX_STRIDE]); + + declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *dst, const uint8_t *src1, + const uint8_t *src2, intptr_t w); + + memset(dst0, 0, MAX_STRIDE); + memset(dst1, 0, MAX_STRIDE); + randomize_buffers(src0, MAX_STRIDE); + memcpy(src1, src0, MAX_STRIDE); + randomize_buffers(src2, MAX_STRIDE); + memcpy(src3, src2, MAX_STRIDE); + + if (check_func(c->diff_bytes, "diff_bytes")) { + for (i = 0; i < 5; i ++) { + call_ref(dst0, src0, src2, planes[i].w); + call_new(dst1, src1, src3, planes[i].w); + if (memcmp(dst0, dst1, planes[i].w)) + fail(); + } + bench_new(dst1, src0, src2, planes[4].w); + } +} + +static void check_sub_left_pred(LLVidEncDSPContext *c) +{ + int i; + LOCAL_ALIGNED_32(uint8_t, dst0, [MAX_STRIDE * MAX_HEIGHT]); + LOCAL_ALIGNED_32(uint8_t, dst1, [MAX_STRIDE * MAX_HEIGHT]); + LOCAL_ALIGNED_32(uint8_t, src0, [MAX_STRIDE * MAX_HEIGHT]); + LOCAL_ALIGNED_32(uint8_t, src1, [MAX_STRIDE * MAX_HEIGHT]); + + declare_func_emms(AV_CPU_FLAG_MMX, void, uint8_t *dst, const uint8_t *src, + ptrdiff_t stride, ptrdiff_t width, int height); + + memset(dst0, 0, MAX_STRIDE * MAX_HEIGHT); + memset(dst1, 0, MAX_STRIDE * MAX_HEIGHT); + randomize_buffers(src0, MAX_STRIDE * MAX_HEIGHT); + memcpy(src1, src0, MAX_STRIDE * MAX_HEIGHT); + + if (check_func(c->sub_left_predict, "sub_left_predict")) { + for (i = 0; i < 5; i ++) { + call_ref(dst0, src0, planes[i].s, planes[i].w, planes[i].h); + call_new(dst1, src1, planes[i].s, planes[i].w, planes[i].h); + if (memcmp(dst0, dst1, planes[i].w * planes[i].h)) + fail(); + break; + } + bench_new(dst1, src0, planes[4].s, planes[4].w, planes[4].h); + } +} + +void checkasm_check_llviddspenc(void) +{ + LLVidEncDSPContext c; + ff_llvidencdsp_init(&c); + + check_diff_bytes(&c); + report("diff_bytes"); + + check_sub_left_pred(&c); + report("sub_left_predict"); +} diff --git a/tests/checkasm/sw_rgb.c b/tests/checkasm/sw_rgb.c new file mode 100644 index 0000000000000..8fc2cfee9e4ba --- /dev/null +++ b/tests/checkasm/sw_rgb.c @@ -0,0 +1,85 @@ +/* + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#include "libavutil/common.h" +#include "libavutil/intreadwrite.h" +#include "libavutil/mem.h" + +#include "libswscale/rgb2rgb.h" + +#include "checkasm.h" + +#define randomize_buffers(buf, size) \ + do { \ + int j; \ + for (j = 0; j < size; j+=4) \ + AV_WN32(buf + j, rnd()); \ + } while (0) + +static const uint8_t width[] = {12, 16, 20, 32, 36, 128}; + +#define MAX_STRIDE 128 + +static void check_shuffle_bytes(void * func, const char * report) +{ + int i; + LOCAL_ALIGNED_32(uint8_t, src0, [MAX_STRIDE]); + LOCAL_ALIGNED_32(uint8_t, src1, [MAX_STRIDE]); + LOCAL_ALIGNED_32(uint8_t, dst0, [MAX_STRIDE]); + LOCAL_ALIGNED_32(uint8_t, dst1, [MAX_STRIDE]); + + declare_func_emms(AV_CPU_FLAG_MMX, void, const uint8_t *src, uint8_t *dst, int src_size); + + memset(dst0, 0, MAX_STRIDE); + memset(dst1, 0, MAX_STRIDE); + randomize_buffers(src0, MAX_STRIDE); + memcpy(src1, src0, MAX_STRIDE); + + if (check_func(func, "%s", report)) { + for (i = 0; i < 6; i ++) { + call_ref(src0, dst0, width[i]); + call_new(src1, dst1, width[i]); + if (memcmp(dst0, dst1, MAX_STRIDE)) + fail(); + } + bench_new(src0, dst0, width[5]); + } +} + +void checkasm_check_sw_rgb(void) +{ + ff_sws_rgb2rgb_init(); + + check_shuffle_bytes(shuffle_bytes_2103, "shuffle_bytes_2103"); + report("shuffle_bytes_2103"); + + check_shuffle_bytes(shuffle_bytes_0321, "shuffle_bytes_0321"); + report("shuffle_bytes_0321"); + + check_shuffle_bytes(shuffle_bytes_1230, "shuffle_bytes_1230"); + report("shuffle_bytes_1230"); + + check_shuffle_bytes(shuffle_bytes_3012, "shuffle_bytes_3012"); + report("shuffle_bytes_3012"); + + check_shuffle_bytes(shuffle_bytes_3210, "shuffle_bytes_3210"); + report("shuffle_bytes_3210"); +} diff --git a/tests/checkasm/utvideodsp.c b/tests/checkasm/utvideodsp.c new file mode 100644 index 0000000000000..080b4287d73f8 --- /dev/null +++ b/tests/checkasm/utvideodsp.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2017 Jokyo Images + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include + +#include "checkasm.h" +#include "libavcodec/avcodec.h" +#include "libavcodec/utvideodsp.h" +#include "libavutil/intreadwrite.h" + +#define WIDTH 240 +#define HEIGHT 120 +#define WIDTH_PADDED (WIDTH + 16) /* padded to 32 */ +#define BUFFER_SIZE (WIDTH_PADDED * HEIGHT) + + +#define randomize_plane(buf, type) \ + do { \ + int w, h; \ + type * tmp = buf; \ + for (h = 0; h < HEIGHT; h++) { \ + for (w = 0; w < WIDTH; w++) \ + tmp[w] = rnd() & 0xFF; \ + tmp += WIDTH_PADDED; \ + } \ + } while (0) + +#define cmp_plane(buf0, buf1, s) \ + do { \ + int h; \ + for (h = 0; h < HEIGHT; h++) { \ + if (memcmp(buf0 + h*WIDTH_PADDED, \ + buf1 + h*WIDTH_PADDED, WIDTH *s)) \ + fail();\ + } \ + } while (0) + + +#define CHECK_RESTORE(type)\ +LOCAL_ALIGNED_32(type, src_r0, [BUFFER_SIZE]); \ +LOCAL_ALIGNED_32(type, src_g0, [BUFFER_SIZE]); \ +LOCAL_ALIGNED_32(type, src_b0, [BUFFER_SIZE]); \ +LOCAL_ALIGNED_32(type, src_r1, [BUFFER_SIZE]); \ +LOCAL_ALIGNED_32(type, src_g1, [BUFFER_SIZE]); \ +LOCAL_ALIGNED_32(type, src_b1, [BUFFER_SIZE]); \ +declare_func(void, type *src_r, type *src_g, type *src_b, \ + ptrdiff_t linesize_r, ptrdiff_t linesize_g, \ + ptrdiff_t linesize_b, int width, int height); \ +memset(src_r0, 0, BUFFER_SIZE * sizeof(type)); \ +memset(src_g0, 0, BUFFER_SIZE * sizeof(type)); \ +memset(src_b0, 0, BUFFER_SIZE * sizeof(type)); \ +randomize_plane(src_r0, type); \ +randomize_plane(src_g0, type); \ +randomize_plane(src_b0, type); \ +memcpy(src_r1, src_r0, BUFFER_SIZE * sizeof(type)); \ +memcpy(src_g1, src_g0, BUFFER_SIZE * sizeof(type)); \ +memcpy(src_b1, src_b0, BUFFER_SIZE * sizeof(type)); \ +call_ref(src_r0, src_g0, src_b0, WIDTH_PADDED, WIDTH_PADDED, WIDTH_PADDED, WIDTH, HEIGHT);\ +call_new(src_r1, src_g1, src_b1, WIDTH_PADDED, WIDTH_PADDED, WIDTH_PADDED, WIDTH, HEIGHT);\ +cmp_plane(src_r0, src_r1, sizeof(type)); \ +cmp_plane(src_g0, src_g1, sizeof(type)); \ +cmp_plane(src_b0, src_b1, sizeof(type)); \ +bench_new(src_r1, src_g1, src_b1, WIDTH_PADDED, WIDTH_PADDED, WIDTH_PADDED, WIDTH, HEIGHT) + +static void check_restore_rgb_planes(void) { + CHECK_RESTORE(uint8_t); +} + +static void check_restore_rgb_planes10(void) { + CHECK_RESTORE(uint16_t); +} + +void checkasm_check_utvideodsp(void) +{ + UTVideoDSPContext h; + + ff_utvideodsp_init(&h); + + if (check_func(h.restore_rgb_planes, "restore_rgb_planes")) + check_restore_rgb_planes(); + + report("restore_rgb_planes"); + + if (check_func(h.restore_rgb_planes10, "restore_rgb_planes10")) + check_restore_rgb_planes10(); + + report("restore_rgb_planes10"); +} diff --git a/tests/checkasm/vf_blend.c b/tests/checkasm/vf_blend.c index be6573045288c..912f3a2c38b66 100644 --- a/tests/checkasm/vf_blend.c +++ b/tests/checkasm/vf_blend.c @@ -60,28 +60,29 @@ } \ } while (0) -#define check_blend_func() \ +#define check_blend_func(depth) \ do { \ - int i; \ + int i, w; \ declare_func(void, const uint8_t *top, ptrdiff_t top_linesize, \ const uint8_t *bottom, ptrdiff_t bottom_linesize, \ uint8_t *dst, ptrdiff_t dst_linesize, \ ptrdiff_t width, ptrdiff_t height, \ struct FilterParams *param, double *values); \ + w = WIDTH / depth; \ \ for (i = 0; i < BUF_UNITS - 1; i++) { \ int src_offset = i * SIZE_PER_UNIT + i; /* Test various alignments */ \ int dst_offset = i * SIZE_PER_UNIT; /* dst must be aligned */ \ randomize_buffers(); \ - call_ref(top1 + src_offset, WIDTH, bot1 + src_offset, WIDTH, \ - dst1 + dst_offset, WIDTH, WIDTH, HEIGHT, ¶m, NULL); \ - call_new(top2 + src_offset, WIDTH, bot2 + src_offset, WIDTH, \ - dst2 + dst_offset, WIDTH, WIDTH, HEIGHT, ¶m, NULL); \ + call_ref(top1 + src_offset, w, bot1 + src_offset, w, \ + dst1 + dst_offset, w, w, HEIGHT, ¶m, NULL); \ + call_new(top2 + src_offset, w, bot2 + src_offset, w, \ + dst2 + dst_offset, w, w, HEIGHT, ¶m, NULL); \ if (memcmp(top1, top2, BUF_SIZE) || memcmp(bot1, bot2, BUF_SIZE) || memcmp(dst1, dst2, BUF_SIZE)) \ fail(); \ } \ - bench_new(top2, WIDTH / 4, bot2, WIDTH / 4, dst2, WIDTH / 4, \ - WIDTH / 4, HEIGHT / 4, ¶m, NULL); \ + bench_new(top2, w / 4, bot2, w / 4, dst2, w / 4, \ + w / 4, HEIGHT / 4, ¶m, NULL); \ } while (0) void checkasm_check_blend(void) @@ -96,32 +97,49 @@ void checkasm_check_blend(void) .opacity = 1.0, }; -#define check_and_report(name, val) \ +#define check_and_report(name, val, depth) \ param.mode = val; \ - ff_blend_init(¶m, 0); \ + ff_blend_init(¶m, depth - 1); \ if (check_func(param.blend, #name)) \ - check_blend_func(); + check_blend_func(depth); - check_and_report(addition, BLEND_ADDITION) - check_and_report(grainmerge, BLEND_GRAINMERGE) - check_and_report(and, BLEND_AND) - check_and_report(average, BLEND_AVERAGE) - check_and_report(darken, BLEND_DARKEN) - check_and_report(grainextract, BLEND_GRAINEXTRACT) - check_and_report(hardmix, BLEND_HARDMIX) - check_and_report(lighten, BLEND_LIGHTEN) - check_and_report(multiply, BLEND_MULTIPLY) - check_and_report(or, BLEND_OR) - check_and_report(phoenix, BLEND_PHOENIX) - check_and_report(screen, BLEND_SCREEN) - check_and_report(subtract, BLEND_SUBTRACT) - check_and_report(xor, BLEND_XOR) - check_and_report(difference, BLEND_DIFFERENCE) - check_and_report(extremity, BLEND_EXTREMITY) - check_and_report(negation, BLEND_NEGATION) + check_and_report(addition, BLEND_ADDITION, 1) + check_and_report(grainmerge, BLEND_GRAINMERGE, 1) + check_and_report(and, BLEND_AND, 1) + check_and_report(average, BLEND_AVERAGE, 1) + check_and_report(darken, BLEND_DARKEN, 1) + check_and_report(grainextract, BLEND_GRAINEXTRACT, 1) + check_and_report(hardmix, BLEND_HARDMIX, 1) + check_and_report(lighten, BLEND_LIGHTEN, 1) + check_and_report(multiply, BLEND_MULTIPLY, 1) + check_and_report(or, BLEND_OR, 1) + check_and_report(phoenix, BLEND_PHOENIX, 1) + check_and_report(screen, BLEND_SCREEN, 1) + check_and_report(subtract, BLEND_SUBTRACT, 1) + check_and_report(xor, BLEND_XOR, 1) + check_and_report(difference, BLEND_DIFFERENCE, 1) + check_and_report(extremity, BLEND_EXTREMITY, 1) + check_and_report(negation, BLEND_NEGATION, 1) report("8bit"); + check_and_report(addition_16, BLEND_ADDITION, 2) + check_and_report(grainmerge_16, BLEND_GRAINMERGE, 2) + check_and_report(and_16, BLEND_AND, 2) + check_and_report(average_16, BLEND_AVERAGE, 2) + check_and_report(darken_16, BLEND_DARKEN, 2) + check_and_report(grainextract_16, BLEND_GRAINEXTRACT, 2) + check_and_report(difference_16, BLEND_DIFFERENCE, 2) + check_and_report(extremity_16, BLEND_EXTREMITY, 2) + check_and_report(negation_16, BLEND_NEGATION, 2) + check_and_report(lighten_16, BLEND_LIGHTEN, 2) + check_and_report(or_16, BLEND_OR, 2) + check_and_report(phoenix_16, BLEND_PHOENIX, 2) + check_and_report(subtract_16, BLEND_SUBTRACT, 2) + check_and_report(xor_16, BLEND_SUBTRACT, 2) + + report("16bit"); + av_freep(&top1); av_freep(&top2); av_freep(&bot1); diff --git a/tests/checkasm/vf_hflip.c b/tests/checkasm/vf_hflip.c new file mode 100644 index 0000000000000..6bb4d09d64e6d --- /dev/null +++ b/tests/checkasm/vf_hflip.c @@ -0,0 +1,76 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include "checkasm.h" +#include "libavfilter/hflip.h" +#include "libavutil/intreadwrite.h" + +#define WIDTH 256 +#define WIDTH_PADDED 256 + 32 + +#define randomize_buffers(buf, size) \ + do { \ + int j; \ + uint8_t *tmp_buf = (uint8_t *)buf;\ + for (j = 0; j < size; j++) \ + tmp_buf[j] = rnd() & 0xFF; \ + } while (0) + +static void check_hflip(int step, const char * report_name){ + LOCAL_ALIGNED_32(uint8_t, src, [WIDTH_PADDED]); + LOCAL_ALIGNED_32(uint8_t, dst_ref, [WIDTH_PADDED]); + LOCAL_ALIGNED_32(uint8_t, dst_new, [WIDTH_PADDED]); + int w = WIDTH; + int i; + int step_array[4] = {1, 1, 1, 1}; + FlipContext s; + + declare_func(void, const uint8_t *src, uint8_t *dst, int w); + + memset(src, 0, WIDTH_PADDED); + memset(dst_ref, 0, WIDTH_PADDED); + memset(dst_new, 0, WIDTH_PADDED); + randomize_buffers(src, WIDTH_PADDED); + + if (step == 2) { + w /= 2; + for (i = 0; i < 4; i++) + step_array[i] = step; + } + + ff_hflip_init(&s, step_array, 4); + + if (check_func(s.flip_line[0], "hflip_%s", report_name)) { + for (i = 1; i < w; i++) { + call_ref(src + (w - 1) * step, dst_ref, i); + call_new(src + (w - 1) * step, dst_new, i); + if (memcmp(dst_ref, dst_new, i * step)) + fail(); + } + bench_new(src + (w - 1) * step, dst_new, w); + } +} +void checkasm_check_vf_hflip(void) +{ + check_hflip(1, "byte"); + report("hflip_byte"); + + check_hflip(2, "short"); + report("hflip_short"); +} diff --git a/tests/checkasm/vf_threshold.c b/tests/checkasm/vf_threshold.c new file mode 100644 index 0000000000000..5a2fc0e4ee4f8 --- /dev/null +++ b/tests/checkasm/vf_threshold.c @@ -0,0 +1,85 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with FFmpeg; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include "checkasm.h" +#include "libavfilter/threshold.h" +#include "libavutil/intreadwrite.h" + +#define WIDTH 256 +#define WIDTH_PADDED 256 + 32 + +#define randomize_buffers(buf, size) \ + do { \ + int j; \ + uint8_t *tmp_buf = (uint8_t *)buf;\ + for (j = 0; j < size; j++) \ + tmp_buf[j] = rnd() & 0xFF; \ + } while (0) + +static void check_threshold(int depth){ + LOCAL_ALIGNED_32(uint8_t, in , [WIDTH_PADDED]); + LOCAL_ALIGNED_32(uint8_t, threshold, [WIDTH_PADDED]); + LOCAL_ALIGNED_32(uint8_t, min , [WIDTH_PADDED]); + LOCAL_ALIGNED_32(uint8_t, max , [WIDTH_PADDED]); + LOCAL_ALIGNED_32(uint8_t, out_ref , [WIDTH_PADDED]); + LOCAL_ALIGNED_32(uint8_t, out_new , [WIDTH_PADDED]); + ptrdiff_t line_size = WIDTH_PADDED; + int w = WIDTH; + + declare_func(void, const uint8_t *in, const uint8_t *threshold, + const uint8_t *min, const uint8_t *max, uint8_t *out, + ptrdiff_t ilinesize, ptrdiff_t tlinesize, + ptrdiff_t flinesize, ptrdiff_t slinesize, + ptrdiff_t olinesize, int w, int h); + + ThresholdContext s; + s.depth = depth; + ff_threshold_init(&s); + + memset(in, 0, WIDTH_PADDED); + memset(threshold, 0, WIDTH_PADDED); + memset(min, 0, WIDTH_PADDED); + memset(max, 0, WIDTH_PADDED); + memset(out_ref, 0, WIDTH_PADDED); + memset(out_new, 0, WIDTH_PADDED); + randomize_buffers(in, WIDTH); + randomize_buffers(threshold, WIDTH); + randomize_buffers(min, WIDTH); + randomize_buffers(max, WIDTH); + + if (depth == 16) + w /= 2; + + if (check_func(s.threshold, "threshold%d", depth)) { + call_ref(in, threshold, min, max, out_ref, line_size, line_size, line_size, line_size, line_size, w, 1); + call_new(in, threshold, min, max, out_new, line_size, line_size, line_size, line_size, line_size, w, 1); + if (memcmp(out_ref, out_new, WIDTH)) + fail(); + bench_new(in, threshold, min, max, out_new, line_size, line_size, line_size, line_size, line_size, w, 1); + } +} + +void checkasm_check_vf_threshold(void) +{ + check_threshold(8); + report("threshold8"); + + check_threshold(16); + report("threshold16"); +} diff --git a/tests/fate-run.sh b/tests/fate-run.sh index 4641640d42b7e..457761c152913 100755 --- a/tests/fate-run.sh +++ b/tests/fate-run.sh @@ -88,6 +88,10 @@ probefmt(){ run ffprobe${PROGSUF} -show_entries format=format_name -print_format default=nw=1:nk=1 -v 0 "$@" } +probetags(){ + run ffprobe${PROGSUF} -show_entries format_tags -v 0 "$@" +} + runlocal(){ test "${V:-0}" -gt 0 && echo ${base}/"$@" ${base} >&3 ${base}/"$@" ${base} @@ -127,15 +131,15 @@ ffmpeg(){ } framecrc(){ - ffmpeg "$@" -flags +bitexact -fflags +bitexact -f framecrc - + ffmpeg "$@" -bitexact -f framecrc - } ffmetadata(){ - ffmpeg "$@" -flags +bitexact -fflags +bitexact -f ffmetadata - + ffmpeg "$@" -bitexact -f ffmetadata - } framemd5(){ - ffmpeg "$@" -flags +bitexact -fflags +bitexact -f framemd5 - + ffmpeg "$@" -bitexact -f framemd5 - } crc(){ @@ -160,7 +164,7 @@ pcm(){ fmtstdout(){ fmt=$1 shift 1 - ffmpeg -flags +bitexact -fflags +bitexact "$@" -f $fmt - + ffmpeg -bitexact "$@" -f $fmt - } enc_dec_pcm(){ @@ -173,7 +177,7 @@ enc_dec_pcm(){ cleanfiles=$encfile encfile=$(target_path ${encfile}) ffmpeg -i $src_file "$@" -f $out_fmt -y ${encfile} || return - ffmpeg -flags +bitexact -fflags +bitexact -i ${encfile} -c:a pcm_${pcm_fmt} -fflags +bitexact -f ${dec_fmt} - + ffmpeg -bitexact -i ${encfile} -c:a pcm_${pcm_fmt} -fflags +bitexact -f ${dec_fmt} - } FLAGS="-flags +bitexact -sws_flags +accurate_rnd+bitexact -fflags +bitexact" @@ -222,6 +226,22 @@ transcode(){ -f framecrc - || return } +stream_remux(){ + src_fmt=$1 + srcfile=$2 + enc_fmt=$3 + stream_maps=$4 + final_decode=$5 + encfile="${outdir}/${test}.${enc_fmt}" + test "$7" = -keep || cleanfiles="$cleanfiles $encfile" + tsrcfile=$(target_path $srcfile) + tencfile=$(target_path $encfile) + ffmpeg -f $src_fmt -i $tsrcfile $stream_maps -codec copy $FLAGS \ + -f $enc_fmt -y $tencfile || return + ffmpeg $DEC_OPTS -i $encfile $ENC_OPTS $FLAGS $final_decode \ + -f framecrc - || return +} + lavffatetest(){ t="${test#lavf-fate-}" ref=${base}/ref/lavf-fate/$t @@ -294,16 +314,16 @@ gapless(){ cleanfiles="$cleanfiles $decfile1 $decfile2 $decfile3" # test packet data - ffmpeg $extra_args -i "$sample" -flags +bitexact -fflags +bitexact -c:a copy -f framecrc -y $decfile1 + ffmpeg $extra_args -i "$sample" -bitexact -c:a copy -f framecrc -y $decfile1 do_md5sum $decfile1 # test decoded (and cut) data - ffmpeg $extra_args -i "$sample" -flags +bitexact -fflags +bitexact -f wav md5: + ffmpeg $extra_args -i "$sample" -bitexact -f wav md5: # the same as above again, with seeking to the start - ffmpeg $extra_args -ss 0 -seek_timestamp 1 -i "$sample" -flags +bitexact -fflags +bitexact -c:a copy -f framecrc -y $decfile2 + ffmpeg $extra_args -ss 0 -seek_timestamp 1 -i "$sample" -bitexact -c:a copy -f framecrc -y $decfile2 do_md5sum $decfile2 - ffmpeg $extra_args -ss 0 -seek_timestamp 1 -i "$sample" -flags +bitexact -fflags +bitexact -f wav md5: + ffmpeg $extra_args -ss 0 -seek_timestamp 1 -i "$sample" -bitexact -f wav md5: # test packet data, with seeking to a specific position - ffmpeg $extra_args -ss 5 -seek_timestamp 1 -i "$sample" -flags +bitexact -fflags +bitexact -c:a copy -f framecrc -y $decfile3 + ffmpeg $extra_args -ss 5 -seek_timestamp 1 -i "$sample" -bitexact -c:a copy -f framecrc -y $decfile3 do_md5sum $decfile3 } @@ -316,7 +336,7 @@ gaplessenc(){ cleanfiles="$cleanfiles $file1" # test data after reencoding - ffmpeg -i "$sample" -flags +bitexact -fflags +bitexact -map 0:a -c:a $codec -f $format -y "$file1" + ffmpeg -i "$sample" -bitexact -map 0:a -c:a $codec -f $format -y "$file1" probegaplessinfo "$file1" } @@ -328,7 +348,7 @@ audio_match(){ decfile="${outdir}/${test}.wav" cleanfiles="$cleanfiles $decfile" - ffmpeg -i "$sample" -flags +bitexact -fflags +bitexact $extra_args -y $decfile + ffmpeg -i "$sample" -bitexact $extra_args -y $decfile tests/audiomatch $decfile $trefile } @@ -352,6 +372,10 @@ concat(){ fi } +null(){ + : +} + mkdir -p "$outdir" # Disable globbing: command arguments may contain globbing characters and diff --git a/tests/fate/aac.mak b/tests/fate/aac.mak index e8cbcef54d7a9..bd283225c1f91 100644 --- a/tests/fate/aac.mak +++ b/tests/fate/aac.mak @@ -154,7 +154,7 @@ fate-aac-aref-encode: CMD = enc_dec_pcm adts wav s16le $(REF) -c:a aac -aac_is 0 fate-aac-aref-encode: CMP = stddev fate-aac-aref-encode: REF = ./tests/data/asynth-44100-2.wav fate-aac-aref-encode: CMP_SHIFT = -4096 -fate-aac-aref-encode: CMP_TARGET = 669 +fate-aac-aref-encode: CMP_TARGET = 596 fate-aac-aref-encode: SIZE_TOLERANCE = 2464 fate-aac-aref-encode: FUZZ = 89 @@ -163,7 +163,7 @@ fate-aac-ln-encode: CMD = enc_dec_pcm adts wav s16le $(TARGET_SAMPLES)/audio-ref fate-aac-ln-encode: CMP = stddev fate-aac-ln-encode: REF = $(SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav fate-aac-ln-encode: CMP_SHIFT = -4096 -fate-aac-ln-encode: CMP_TARGET = 61 +fate-aac-ln-encode: CMP_TARGET = 72 fate-aac-ln-encode: SIZE_TOLERANCE = 3560 fate-aac-ln-encode: FUZZ = 30 @@ -172,7 +172,7 @@ fate-aac-ln-encode-128k: CMD = enc_dec_pcm adts wav s16le $(TARGET_SAMPLES)/audi fate-aac-ln-encode-128k: CMP = stddev fate-aac-ln-encode-128k: REF = $(SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav fate-aac-ln-encode-128k: CMP_SHIFT = -4096 -fate-aac-ln-encode-128k: CMP_TARGET = 800 +fate-aac-ln-encode-128k: CMP_TARGET = 622 fate-aac-ln-encode-128k: SIZE_TOLERANCE = 3560 fate-aac-ln-encode-128k: FUZZ = 5 @@ -181,7 +181,7 @@ fate-aac-pns-encode: CMD = enc_dec_pcm adts wav s16le $(TARGET_SAMPLES)/audio-re fate-aac-pns-encode: CMP = stddev fate-aac-pns-encode: REF = $(SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav fate-aac-pns-encode: CMP_SHIFT = -4096 -fate-aac-pns-encode: CMP_TARGET = 616 +fate-aac-pns-encode: CMP_TARGET = 655 fate-aac-pns-encode: SIZE_TOLERANCE = 3560 fate-aac-pns-encode: FUZZ = 74 @@ -190,7 +190,7 @@ fate-aac-tns-encode: CMD = enc_dec_pcm adts wav s16le $(TARGET_SAMPLES)/audio-re fate-aac-tns-encode: CMP = stddev fate-aac-tns-encode: REF = $(SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav fate-aac-tns-encode: CMP_SHIFT = -4096 -fate-aac-tns-encode: CMP_TARGET = 817 +fate-aac-tns-encode: CMP_TARGET = 637 fate-aac-tns-encode: FUZZ = 7 fate-aac-tns-encode: SIZE_TOLERANCE = 3560 @@ -199,7 +199,7 @@ fate-aac-is-encode: CMD = enc_dec_pcm adts wav s16le $(TARGET_SAMPLES)/audio-ref fate-aac-is-encode: CMP = stddev fate-aac-is-encode: REF = $(SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav fate-aac-is-encode: CMP_SHIFT = -4096 -fate-aac-is-encode: CMP_TARGET = 615 +fate-aac-is-encode: CMP_TARGET = 514 fate-aac-is-encode: SIZE_TOLERANCE = 3560 fate-aac-is-encode: FUZZ = 10 @@ -208,26 +208,17 @@ fate-aac-ms-encode: CMD = enc_dec_pcm adts wav s16le $(TARGET_SAMPLES)/audio-ref fate-aac-ms-encode: CMP = stddev fate-aac-ms-encode: REF = $(SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav fate-aac-ms-encode: CMP_SHIFT = -4096 -fate-aac-ms-encode: CMP_TARGET = 675 +fate-aac-ms-encode: CMP_TARGET = 558 fate-aac-ms-encode: SIZE_TOLERANCE = 3560 fate-aac-ms-encode: FUZZ = 15 -FATE_AAC_ENCODE += fate-aac-ltp-encode -fate-aac-ltp-encode: CMD = enc_dec_pcm adts wav s16le $(TARGET_SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav -strict -2 -c:a aac -profile:a aac_ltp -aac_pns 0 -aac_is 0 -aac_ms 0 -aac_tns 0 -b:a 36k -fflags +bitexact -flags +bitexact -fate-aac-ltp-encode: CMP = stddev -fate-aac-ltp-encode: REF = $(SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav -fate-aac-ltp-encode: CMP_SHIFT = -4096 -fate-aac-ltp-encode: CMP_TARGET = 1270 -fate-aac-ltp-encode: SIZE_TOLERANCE = 3560 -fate-aac-ltp-encode: FUZZ = 17 - #Ticket1784 FATE_AAC_ENCODE += fate-aac-yoraw-encode fate-aac-yoraw-encode: CMD = enc_dec_pcm adts wav s16le $(TARGET_SAMPLES)/audio-reference/yo.raw-short.wav -c:a aac -fflags +bitexact -flags +bitexact fate-aac-yoraw-encode: CMP = stddev fate-aac-yoraw-encode: REF = $(SAMPLES)/audio-reference/yo.raw-short.wav fate-aac-yoraw-encode: CMP_SHIFT = -12288 -fate-aac-yoraw-encode: CMP_TARGET = 259 +fate-aac-yoraw-encode: CMP_TARGET = 226 fate-aac-yoraw-encode: SIZE_TOLERANCE = 3560 fate-aac-yoraw-encode: FUZZ = 17 @@ -237,7 +228,7 @@ fate-aac-pred-encode: CMD = enc_dec_pcm adts wav s16le $(TARGET_SAMPLES)/audio-r fate-aac-pred-encode: CMP = stddev fate-aac-pred-encode: REF = $(SAMPLES)/audio-reference/luckynight_2ch_44kHz_s16.wav fate-aac-pred-encode: CMP_SHIFT = -4096 -fate-aac-pred-encode: CMP_TARGET = 841 +fate-aac-pred-encode: CMP_TARGET = 662 fate-aac-pred-encode: FUZZ = 12 fate-aac-pred-encode: SIZE_TOLERANCE = 3560 diff --git a/tests/fate/ac3.mak b/tests/fate/ac3.mak index 76be2e869a3e7..bb02d3829d307 100644 --- a/tests/fate/ac3.mak +++ b/tests/fate/ac3.mak @@ -60,6 +60,10 @@ FATE_EAC3 += fate-eac3-4 fate-eac3-4: CMD = pcm -i $(TARGET_SAMPLES)/eac3/serenity_english_5.1_1536_small.eac3 fate-eac3-4: REF = $(SAMPLES)/eac3/serenity_english_5.1_1536_small_v2.pcm +FATE_EAC3 += fate-eac3-5 +fate-eac3-5: CMD = pcm -i $(TARGET_SAMPLES)/eac3/the_great_wall_7.1.eac3 +fate-eac3-5: REF = $(SAMPLES)/eac3/the_great_wall_7.1.pcm + $(FATE_AC3) $(FATE_EAC3): CMP = oneoff FATE_AC3-$(call DEMDEC, AC3, AC3) += $(FATE_AC3) @@ -88,6 +92,11 @@ fate-ac3-fixed-encode: CMD = md5 -i $(SRC) -c ac3_fixed -ab 128k -f ac3 -flags + fate-ac3-fixed-encode: CMP = oneline fate-ac3-fixed-encode: REF = a1d1fc116463b771abf5aef7ed37d7b1 +FATE_EAC3-$(call ALLYES, EAC3_DEMUXER EAC3_MUXER EAC3_CORE_BSF) += fate-eac3-core-bsf +fate-eac3-core-bsf: CMD = md5pipe -i $(TARGET_SAMPLES)/eac3/the_great_wall_7.1.eac3 -c:a copy -bsf:a eac3_core -fflags +bitexact -f eac3 +fate-eac3-core-bsf: CMP = oneline +fate-eac3-core-bsf: REF = b704bf851e99b7442e9bed368b60e6ca + FATE_SAMPLES_AVCONV += $(FATE_AC3-yes) $(FATE_EAC3-yes) fate-ac3: $(FATE_AC3-yes) $(FATE_EAC3-yes) diff --git a/tests/fate/acodec.mak b/tests/fate/acodec.mak index 5c3fea90c5822..80d26de0f9c91 100644 --- a/tests/fate/acodec.mak +++ b/tests/fate/acodec.mak @@ -104,14 +104,14 @@ fate-acodec-dca: tests/data/asynth-44100-2.wav fate-acodec-dca: SRC = tests/data/asynth-44100-2.wav fate-acodec-dca: CMD = md5 -i $(TARGET_PATH)/$(SRC) -c:a dca -strict -2 -f dts -flags +bitexact fate-acodec-dca: CMP = oneline -fate-acodec-dca: REF = 7cd79a3717943a06b217f1130223a86f +fate-acodec-dca: REF = 2aa580ac67820fce4f581b96ebb34acc FATE_ACODEC-$(call ENCDEC, DCA, WAV) += fate-acodec-dca2 fate-acodec-dca2: CMD = enc_dec_pcm dts wav s16le $(SRC) -c:a dca -strict -2 -flags +bitexact fate-acodec-dca2: REF = $(SRC) fate-acodec-dca2: CMP = stddev fate-acodec-dca2: CMP_SHIFT = -2048 -fate-acodec-dca2: CMP_TARGET = 527 +fate-acodec-dca2: CMP_TARGET = 535 fate-acodec-dca2: SIZE_TOLERANCE = 1632 FATE_ACODEC-$(call ENCDEC, FLAC, FLAC) += fate-acodec-flac fate-acodec-flac-exact-rice diff --git a/tests/fate/avformat.mak b/tests/fate/avformat.mak index c9ea99ad1b1fa..a12f9ccc71169 100644 --- a/tests/fate/avformat.mak +++ b/tests/fate/avformat.mak @@ -9,7 +9,6 @@ FATE_LAVF-$(call ENCDEC, BMP, IMAGE2) += bmp FATE_LAVF-$(call ENCDEC, PCM_S16BE, CAF) += caf FATE_LAVF-$(call ENCDEC, DPX, IMAGE2) += dpx FATE_LAVF-$(call ENCDEC2, DVVIDEO, PCM_S16LE, AVI) += dv_fmt -FATE_LAVF-$(call ENCDEC2, MPEG1VIDEO, MP2, FFM) += ffm FATE_LAVF-$(call ENCDEC, FITS, FITS) += fits FATE_LAVF-$(call ENCDEC, RAWVIDEO, FILMSTRIP) += flm FATE_LAVF-$(call ENCDEC, FLV, FLV) += flv_fmt diff --git a/tests/fate/build.mak b/tests/fate/build.mak new file mode 100644 index 0000000000000..f97f9ebe5cf76 --- /dev/null +++ b/tests/fate/build.mak @@ -0,0 +1,17 @@ +FATE_BUILD += fate-build-alltools +fate-build-alltools: alltools + +FATE_BUILD += fate-build-checkheaders +fate-build-checkheaders: checkheaders + +FATE_BUILD += fate-build-examples +fate-build-examples: examples + +FATE_BUILD += fate-build-testprogs +fate-build-testprogs: testprogs + +$(FATE_BUILD): CMD = null +$(FATE_BUILD): CMP = null + +# FATE += $(FATE_BUILD) +fate-build: $(FATE_BUILD) diff --git a/tests/fate/cbs.mak b/tests/fate/cbs.mak new file mode 100644 index 0000000000000..fc5967e6f37df --- /dev/null +++ b/tests/fate/cbs.mak @@ -0,0 +1,79 @@ +# Read/write tests: this uses the codec metadata filter - with no +# arguments, it decomposes the stream fully and then recomposes it +# without making any changes. + +fate-cbs: fate-cbs-h264 fate-cbs-hevc fate-cbs-mpeg2 + +FATE_CBS_DEPS = $(call ALLYES, $(1)_DEMUXER $(1)_PARSER $(2)_METADATA_BSF $(3)_DECODER $(3)_MUXER) + +define FATE_CBS_TEST +# (codec, test_name, sample_file, output_format) +FATE_CBS_$(1) += fate-cbs-$(1)-$(2) +fate-cbs-$(1)-$(2): CMD = md5 -i $(TARGET_SAMPLES)/$(3) -c:v copy -bsf:v $(1)_metadata -f $(4) +endef + +# H.264 read/write + +FATE_CBS_H264_SAMPLES = \ + SVA_Base_B.264 \ + BASQP1_Sony_C.jsv \ + FM1_BT_B.h264 \ + CVFC1_Sony_C.jsv \ + AUD_MW_E.264 \ + CVBS3_Sony_C.jsv \ + MR1_BT_A.h264 \ + CVWP1_TOSHIBA_E.264 \ + CVNLFI1_Sony_C.jsv \ + Sharp_MP_PAFF_1r2.jvt \ + CVMANL1_TOSHIBA_B.264 \ + sp1_bt_a.h264 \ + CVSE2_Sony_B.jsv \ + CABACI3_Sony_B.jsv + +$(foreach N,$(FATE_CBS_H264_SAMPLES),$(eval $(call FATE_CBS_TEST,h264,$(basename $(N)),h264-conformance/$(N),h264))) + +FATE_CBS_H264-$(call FATE_CBS_DEPS, H264, H264, H264) = $(FATE_CBS_h264) +FATE_SAMPLES_AVCONV += $(FATE_CBS_H264-yes) +fate-cbs-h264: $(FATE_CBS_H264-yes) + +# H.265 read/write + +FATE_CBS_HEVC_SAMPLES = \ + STRUCT_A_Samsung_5.bit \ + WP_A_Toshiba_3.bit \ + SLIST_A_Sony_4.bit \ + SLIST_D_Sony_9.bit \ + CAINIT_E_SHARP_3.bit \ + CAINIT_H_SHARP_3.bit \ + TILES_B_Cisco_1.bit \ + WPP_A_ericsson_MAIN_2.bit \ + WPP_F_ericsson_MAIN_2.bit \ + ipcm_E_NEC_2.bit \ + NUT_A_ericsson_5.bit \ + PICSIZE_A_Bossen_1.bit \ + PICSIZE_B_Bossen_1.bit \ + RPS_A_docomo_4.bit \ + RPS_E_qualcomm_5.bit \ + LTRPSPS_A_Qualcomm_1.bit \ + RPLM_A_qualcomm_4.bit \ + CONFWIN_A_Sony_1.bit \ + HRD_A_Fujitsu_2.bit + +$(foreach N,$(FATE_CBS_HEVC_SAMPLES),$(eval $(call FATE_CBS_TEST,hevc,$(basename $(N)),hevc-conformance/$(N),hevc))) + +FATE_CBS_HEVC-$(call FATE_CBS_DEPS, HEVC, HEVC, HEVC) = $(FATE_CBS_hevc) +FATE_SAMPLES_AVCONV += $(FATE_CBS_HEVC-yes) +fate-cbs-hevc: $(FATE_CBS_HEVC-yes) + +# MPEG-2 read/write + +FATE_CBS_MPEG2_SAMPLES = \ + hhi_burst_422_short.bits \ + sony-ct3.bs \ + tcela-6.bits + +$(foreach N,$(FATE_CBS_MPEG2_SAMPLES),$(eval $(call FATE_CBS_TEST,mpeg2,$(basename $(N)),mpeg2/$(N),mpeg2video))) + +FATE_CBS_MPEG2-$(call FATE_CBS_DEPS, MPEGVIDEO, MPEG2, MPEG2VIDEO) = $(FATE_CBS_mpeg2) +FATE_SAMPLES_AVCONV += $(FATE_CBS_MPEG2-yes) +fate-cbs-mpeg2: $(FATE_CBS_MPEG2-yes) diff --git a/tests/fate/checkasm.mak b/tests/fate/checkasm.mak index fbf60e9848453..a722b4a9172f7 100644 --- a/tests/fate/checkasm.mak +++ b/tests/fate/checkasm.mak @@ -14,14 +14,19 @@ FATE_CHECKASM = fate-checkasm-aacpsdsp \ fate-checkasm-h264qpel \ fate-checkasm-hevc_add_res \ fate-checkasm-hevc_idct \ + fate-checkasm-hevc_sao \ fate-checkasm-jpeg2000dsp \ fate-checkasm-llviddsp \ + fate-checkasm-llviddspenc \ fate-checkasm-pixblockdsp \ fate-checkasm-sbrdsp \ fate-checkasm-synth_filter \ + fate-checkasm-sw_rgb \ fate-checkasm-v210enc \ fate-checkasm-vf_blend \ fate-checkasm-vf_colorspace \ + fate-checkasm-vf_hflip \ + fate-checkasm-vf_threshold \ fate-checkasm-videodsp \ fate-checkasm-vp8dsp \ fate-checkasm-vp9dsp \ @@ -30,5 +35,5 @@ $(FATE_CHECKASM): tests/checkasm/checkasm$(EXESUF) $(FATE_CHECKASM): CMD = run tests/checkasm/checkasm --test=$(@:fate-checkasm-%=%) $(FATE_CHECKASM): CMP = null -FATE-$(CONFIG_STATIC) += $(FATE_CHECKASM) +FATE += $(FATE_CHECKASM) fate-checkasm: $(FATE_CHECKASM) diff --git a/tests/fate/dca.mak b/tests/fate/dca.mak index b1681c6b59313..fad3a7529ecd1 100644 --- a/tests/fate/dca.mak +++ b/tests/fate/dca.mak @@ -75,5 +75,10 @@ fate-dts_es: CMD = pcm -i $(TARGET_SAMPLES)/dts/dts_es.dts fate-dts_es: CMP = oneoff fate-dts_es: REF = $(SAMPLES)/dts/dts_es_2.pcm +FATE_DCA-$(call ALLYES, DTS_DEMUXER DTS_MUXER DCA_CORE_BSF) += fate-dca-core-bsf +fate-dca-core-bsf: CMD = md5pipe -i $(TARGET_SAMPLES)/dts/master_audio_7.1_24bit.dts -c:a copy -bsf:a dca_core -fflags +bitexact -f dts +fate-dca-core-bsf: CMP = oneline +fate-dca-core-bsf: REF = ca22b00d8c641cd168e2f7ca8d2f340e + FATE_SAMPLES_AUDIO += $(FATE_DCA-yes) fate-dca: $(FATE_DCA-yes) diff --git a/tests/fate/demux.mak b/tests/fate/demux.mak index 9427ac30c8ccf..ef9e677821a82 100644 --- a/tests/fate/demux.mak +++ b/tests/fate/demux.mak @@ -1,9 +1,11 @@ FATE_SAMPLES_DEMUX-$(call DEMDEC, AVI, FRAPS) += fate-avio-direct fate-avio-direct: CMD = framecrc -avioflags direct -i $(TARGET_SAMPLES)/fraps/fraps-v5-bouncing-balls-partial.avi -avioflags direct -FATE_SAMPLES_DEMUX-$(call DEMDEC, AAC, AAC) += fate-adts-demux fate-adts-id3v1-demux +FATE_SAMPLES_DEMUX-$(call DEMDEC, AAC, AAC) += fate-adts-demux fate-adts-id3v1-demux fate-adts-id3v2-demux fate-adts-id3v2-two-tags-demux fate-adts-demux: CMD = crc -i $(TARGET_SAMPLES)/aac/ct_faac-adts.aac -c:a copy fate-adts-id3v1-demux: CMD = framecrc -f aac -i $(TARGET_SAMPLES)/aac/id3v1.aac -c:a copy +fate-adts-id3v2-demux: CMD = framecrc -f aac -i $(TARGET_SAMPLES)/aac/id3v2.aac -c:a copy +fate-adts-id3v2-two-tags-demux: CMD = framecrc -i $(TARGET_SAMPLES)/aac/id3v2_two_tags.aac -c:a copy FATE_SAMPLES_DEMUX-$(CONFIG_AEA_DEMUXER) += fate-aea-demux fate-aea-demux: CMD = crc -i $(TARGET_SAMPLES)/aea/chirp.aea -c:a copy diff --git a/tests/fate/ffmpeg.mak b/tests/fate/ffmpeg.mak index d8f2e715901df..0975af2612664 100644 --- a/tests/fate/ffmpeg.mak +++ b/tests/fate/ffmpeg.mak @@ -26,6 +26,14 @@ fate-mapchan: $(FATE_MAPCHAN) FATE_FFMPEG-$(CONFIG_COLOR_FILTER) += fate-ffmpeg-filter_complex fate-ffmpeg-filter_complex: CMD = framecrc -filter_complex color=d=1:r=5 -fflags +bitexact +# Ticket 6603 +FATE_FFMPEG-$(call ALLYES, AEVALSRC_FILTER ASETNSAMPLES_FILTER AC3_FIXED_ENCODER) += fate-ffmpeg-filter_complex_audio +fate-ffmpeg-filter_complex_audio: CMD = framecrc -filter_complex "aevalsrc=0:d=0.1,asetnsamples=1537" -c ac3_fixed + +# Ticket 6375, use case of NoX +FATE_SAMPLES_FFMPEG-$(call ALLYES, MOV_DEMUXER PNG_DECODER ALAC_DECODER PCM_S16LE_ENCODER RAWVIDEO_ENCODER) += fate-ffmpeg-attached_pics +fate-ffmpeg-attached_pics: CMD = threads=2 framecrc -i $(TARGET_SAMPLES)/lossless-audio/inside.m4a -c:a pcm_s16le -max_muxing_queue_size 16 + FATE_SAMPLES_FFMPEG-$(CONFIG_COLORKEY_FILTER) += fate-ffmpeg-filter_colorkey fate-ffmpeg-filter_colorkey: tests/data/filtergraphs/colorkey fate-ffmpeg-filter_colorkey: CMD = framecrc -idct simple -fflags +bitexact -flags +bitexact -sws_flags +accurate_rnd+bitexact -i $(TARGET_SAMPLES)/cavs/cavs.mpg -fflags +bitexact -flags +bitexact -sws_flags +accurate_rnd+bitexact -i $(TARGET_SAMPLES)/lena.pnm -an -filter_complex_script $(TARGET_PATH)/tests/data/filtergraphs/colorkey -sws_flags +accurate_rnd+bitexact -fflags +bitexact -flags +bitexact -qscale 2 -frames:v 10 diff --git a/tests/fate/filter-audio.mak b/tests/fate/filter-audio.mak index bd8b3d3c351c2..2a3ba1992fc79 100644 --- a/tests/fate/filter-audio.mak +++ b/tests/fate/filter-audio.mak @@ -128,6 +128,36 @@ fate-filter-firequalizer: CMP = oneoff fate-filter-firequalizer: CMP_UNIT = s16 fate-filter-firequalizer: SIZE_TOLERANCE = 1058400 - 1097208 +FATE_AFILTER-$(call FILTERDEMDECENCMUX, PAN, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-filter-pan-mono1 +fate-filter-pan-mono1: tests/data/asynth-44100-2.wav +fate-filter-pan-mono1: SRC = $(TARGET_PATH)/tests/data/asynth-44100-2.wav +fate-filter-pan-mono1: CMD = framecrc -ss 3.14 -i $(SRC) -frames:a 20 -filter:a "pan=mono|FC=FL" + +FATE_AFILTER-$(call FILTERDEMDECENCMUX, PAN, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-filter-pan-mono2 +fate-filter-pan-mono2: tests/data/asynth-44100-2.wav +fate-filter-pan-mono2: SRC = $(TARGET_PATH)/tests/data/asynth-44100-2.wav +fate-filter-pan-mono2: CMD = framecrc -ss 3.14 -i $(SRC) -frames:a 20 -filter:a "pan=1C|c0=c0+c1" + +FATE_AFILTER-$(call FILTERDEMDECENCMUX, PAN, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-filter-pan-stereo1 +fate-filter-pan-stereo1: tests/data/asynth-44100-3.wav +fate-filter-pan-stereo1: SRC = $(TARGET_PATH)/tests/data/asynth-44100-3.wav +fate-filter-pan-stereo1: CMD = framecrc -ss 3.14 -i $(SRC) -frames:a 20 -filter:a "pan=2c|FL=FR|FR=FL" + +FATE_AFILTER-$(call FILTERDEMDECENCMUX, PAN, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-filter-pan-stereo2 +fate-filter-pan-stereo2: tests/data/asynth-44100-3.wav +fate-filter-pan-stereo2: SRC = $(TARGET_PATH)/tests/data/asynth-44100-3.wav +fate-filter-pan-stereo2: CMD = framecrc -ss 3.14 -i $(SRC) -frames:a 20 -filter:a "pan=stereo|c0=c0-c2|c1=c1-c2" + +FATE_AFILTER-$(call FILTERDEMDECENCMUX, PAN, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-filter-pan-stereo3 +fate-filter-pan-stereo3: tests/data/asynth-44100-2.wav +fate-filter-pan-stereo3: SRC = $(TARGET_PATH)/tests/data/asynth-44100-2.wav +fate-filter-pan-stereo3: CMD = framecrc -ss 3.14 -i $(SRC) -frames:a 20 -filter:a "pan=FL+FR|FL<3*c0+2*c1|FR<2*c0+3*c1" + +FATE_AFILTER-$(call FILTERDEMDECENCMUX, PAN, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-filter-pan-stereo4 +fate-filter-pan-stereo4: tests/data/asynth-44100-2.wav +fate-filter-pan-stereo4: SRC = $(TARGET_PATH)/tests/data/asynth-44100-2.wav +fate-filter-pan-stereo4: CMD = framecrc -ss 3.14 -guess_layout_max 0 -i $(SRC) -frames:a 20 -filter:a "pan=4C|c0=c0-0.5*c1|c1=c1+0.5*c0|c2=0*c0|c3=0*c0" + FATE_AFILTER_SAMPLES-$(call FILTERDEMDECENCMUX, SILENCEREMOVE, WAV, PCM_S16LE, PCM_S16LE, WAV) += fate-filter-silenceremove fate-filter-silenceremove: SRC = $(TARGET_SAMPLES)/audio-reference/divertimenti_2ch_96kHz_s24.wav fate-filter-silenceremove: CMD = framecrc -i $(SRC) -frames:a 30 -af silenceremove=0:0:0:-1:0:-90dB diff --git a/tests/fate/filter-video.mak b/tests/fate/filter-video.mak index c19f301ff8dfc..17d6363678358 100644 --- a/tests/fate/filter-video.mak +++ b/tests/fate/filter-video.mak @@ -108,11 +108,14 @@ FATE_FILTER-$(call ALLYES, AVDEVICE TESTSRC_FILTER FORMAT_FILTER CONCAT_FILTER S fate-filter-lavd-scalenorm: tests/data/filtergraphs/scalenorm fate-filter-lavd-scalenorm: CMD = framecrc -f lavfi -graph_file $(TARGET_PATH)/tests/data/filtergraphs/scalenorm -i dummy - FATE_FILTER-$(call ALLYES, FRAMERATE_FILTER TESTSRC2_FILTER) += fate-filter-framerate-up fate-filter-framerate-down fate-filter-framerate-up: CMD = framecrc -lavfi testsrc2=r=2:d=10,framerate=fps=10 -t 1 fate-filter-framerate-down: CMD = framecrc -lavfi testsrc2=r=2:d=10,framerate=fps=1 -t 1 +FATE_FILTER-$(call ALLYES, FRAMERATE_FILTER TESTSRC2_FILTER FORMAT_FILTER) += fate-filter-framerate-12bit-up fate-filter-framerate-12bit-down +fate-filter-framerate-12bit-up: CMD = framecrc -lavfi testsrc2=r=50:d=1,format=pix_fmts=yuv422p12le,framerate=fps=60 -t 1 -pix_fmt yuv422p12le +fate-filter-framerate-12bit-down: CMD = framecrc -lavfi testsrc2=r=60:d=1,format=pix_fmts=yuv422p12le,framerate=fps=50 -t 1 -pix_fmt yuv422p12le + FATE_FILTER_VSYNTH-$(CONFIG_BOXBLUR_FILTER) += fate-filter-boxblur fate-filter-boxblur: CMD = framecrc -c:v pgmyuv -i $(SRC) -vf boxblur=2:1 @@ -422,6 +425,17 @@ fate-filter-concat: CMD = framecrc -filter_complex_script $(TARGET_PATH)/tests/d FATE_FILTER-$(call ALLYES, TESTSRC2_FILTER FPS_FILTER MPDECIMATE_FILTER) += fate-filter-mpdecimate fate-filter-mpdecimate: CMD = framecrc -lavfi testsrc2=r=2:d=10,fps=3,mpdecimate -r 3 -pix_fmt yuv420p +FATE_FILTER-$(call ALLYES, FPS_FILTER TESTSRC2_FILTER) += fate-filter-fps-up fate-filter-fps-up-round-down fate-filter-fps-up-round-up fate-filter-fps-down fate-filter-fps-down-round-down fate-filter-fps-down-round-up fate-filter-fps-down-eof-pass fate-filter-fps-start-drop fate-filter-fps-start-fill +fate-filter-fps-up: CMD = framecrc -lavfi testsrc2=r=3:d=2,fps=7 +fate-filter-fps-up-round-down: CMD = framecrc -lavfi testsrc2=r=3:d=2,fps=7:round=down +fate-filter-fps-up-round-up: CMD = framecrc -lavfi testsrc2=r=3:d=2,fps=7:round=up +fate-filter-fps-down: CMD = framecrc -lavfi testsrc2=r=7:d=3.5,fps=3 +fate-filter-fps-down-round-down: CMD = framecrc -lavfi testsrc2=r=7:d=3.5,fps=3:round=down +fate-filter-fps-down-round-up: CMD = framecrc -lavfi testsrc2=r=7:d=3.5,fps=3:round=up +fate-filter-fps-down-eof-pass: CMD = framecrc -lavfi testsrc2=r=7:d=3.5,fps=3:eof_action=pass +fate-filter-fps-start-drop: CMD = framecrc -lavfi testsrc2=r=7:d=3.5,fps=3:start_time=1.5 +fate-filter-fps-start-fill: CMD = framecrc -lavfi testsrc2=r=7:d=1.5,setpts=PTS+14,fps=3:start_time=1.5 + FATE_FILTER_SAMPLES-$(call ALLYES, MOV_DEMUXER FPS_FILTER QTRLE_DECODER) += fate-filter-fps-cfr fate-filter-fps fate-filter-fps-r fate-filter-fps-cfr: CMD = framecrc -i $(TARGET_SAMPLES)/qtrle/apple-animation-variable-fps-bug.mov -r 30 -vsync cfr -pix_fmt yuv420p fate-filter-fps-r: CMD = framecrc -i $(TARGET_SAMPLES)/qtrle/apple-animation-variable-fps-bug.mov -r 30 -vf fps -pix_fmt yuv420p @@ -680,6 +694,9 @@ fate-filter-pixfmts-tinterlace_pad: CMD = pixfmts "pad" FATE_FILTER_PIXFMTS-$(CONFIG_TINTERLACE_FILTER) += fate-filter-pixfmts-tinterlace_vlpf fate-filter-pixfmts-tinterlace_vlpf: CMD = pixfmts "interleave_top:vlpf" +FATE_FILTER_PIXFMTS-$(CONFIG_TRANSPOSE_FILTER) += fate-filter-pixfmts-transpose +fate-filter-pixfmts-transpose: CMD = pixfmts "dir=cclock_flip" + FATE_FILTER_PIXFMTS-$(CONFIG_VFLIP_FILTER) += fate-filter-pixfmts-vflip fate-filter-pixfmts-vflip: CMD = pixfmts @@ -710,10 +727,10 @@ FATE_METADATA_FILTER-$(call ALLYES, $(CROPDETECT_DEPS)) += fate-filter-metadata- fate-filter-metadata-cropdetect: SRC = $(TARGET_SAMPLES)/filter/cropdetect.mp4 fate-filter-metadata-cropdetect: CMD = run $(FILTER_METADATA_COMMAND) "sws_flags=+accurate_rnd+bitexact;movie='$(SRC)',cropdetect=max_outliers=3" -SILENCEDETECT_DEPS = FFPROBE AVDEVICE LAVFI_INDEV AMOVIE_FILTER AMR_DEMUXER AMRWB_DECODER SILENCEDETECT_FILTER +SILENCEDETECT_DEPS = FFPROBE AVDEVICE LAVFI_INDEV AMOVIE_FILTER TTA_DEMUXER TTA_DECODER SILENCEDETECT_FILTER FATE_METADATA_FILTER-$(call ALLYES, $(SILENCEDETECT_DEPS)) += fate-filter-metadata-silencedetect -fate-filter-metadata-silencedetect: SRC = $(TARGET_SAMPLES)/amrwb/seed-12k65.awb -fate-filter-metadata-silencedetect: CMD = run $(FILTER_METADATA_COMMAND) "amovie='$(SRC)',silencedetect=d=-20dB" +fate-filter-metadata-silencedetect: SRC = $(TARGET_SAMPLES)/lossless-audio/inside.tta +fate-filter-metadata-silencedetect: CMD = run $(FILTER_METADATA_COMMAND) "amovie='$(SRC)',silencedetect=n=-33.5dB:d=.2" EBUR128_METADATA_DEPS = FFPROBE AVDEVICE LAVFI_INDEV AMOVIE_FILTER FLAC_DEMUXER FLAC_DECODER EBUR128_FILTER FATE_METADATA_FILTER-$(call ALLYES, $(EBUR128_METADATA_DEPS)) += fate-filter-metadata-ebur128 diff --git a/tests/fate/fits.mak b/tests/fate/fits.mak index 3d58f98807007..113498cf7261f 100644 --- a/tests/fate/fits.mak +++ b/tests/fate/fits.mak @@ -8,7 +8,7 @@ tests/data/fits-multi.fits: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data map.tests/data/lena-gray.fits := gray8 map.tests/data/lena-gbrp.fits := rgb24 map.tests/data/lena-gbrp16.fits := rgb48 -map.tests/data/lena-gbrap16.fits := rgba64 +map.tests/data/lena-gbrap16le.fits := rgba64 tests/data/lena%.fits: TAG = GEN tests/data/lena%.fits: NAME = $(map.$(@)) @@ -18,16 +18,16 @@ tests/data/lena%.fits: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data -y $(TARGET_PATH)/$(@) 2>/dev/null FATE_FITS_DEC-$(call DEMDEC, FITS, FITS) += fate-fitsdec-ext_data_min_max -fate-fitsdec-ext_data_min_max: CMD = framecrc -i $(TARGET_SAMPLES)/fits/x0cj010ct_d0h.fit -pix_fmt gray16 +fate-fitsdec-ext_data_min_max: CMD = framecrc -i $(TARGET_SAMPLES)/fits/x0cj010ct_d0h.fit -pix_fmt gray16le FATE_FITS_DEC-$(call DEMDEC, FITS, FITS) += fate-fitsdec-blank_bitpix32 -fate-fitsdec-blank_bitpix32: CMD = framecrc -blank_value 65535 -i $(TARGET_SAMPLES)/fits/file008.fits -pix_fmt gray16 +fate-fitsdec-blank_bitpix32: CMD = framecrc -blank_value 65535 -i $(TARGET_SAMPLES)/fits/file008.fits -pix_fmt gray16le FATE_FITS_DEC-$(call DEMDEC, FITS, FITS) += fate-fitsdec-bitpix-32 -fate-fitsdec-bitpix-32: CMD = framecrc -i $(TARGET_SAMPLES)/fits/tst0005.fits -pix_fmt gray16 +fate-fitsdec-bitpix-32: CMD = framecrc -i $(TARGET_SAMPLES)/fits/tst0005.fits -pix_fmt gray16le FATE_FITS_DEC-$(call DEMDEC, FITS, FITS) += fate-fitsdec-bitpix-64 -fate-fitsdec-bitpix-64: CMD = framecrc -i $(TARGET_SAMPLES)/fits/tst0006.fits -pix_fmt gray16 +fate-fitsdec-bitpix-64: CMD = framecrc -i $(TARGET_SAMPLES)/fits/tst0006.fits -pix_fmt gray16le FATE_FITS_DEC-$(call ALLYES, GIF_DEMUXER FITS_DEMUXER GIF_DECODER FITS_DECODER FITS_ENCODER FITS_MUXER) += fate-fitsdec-multi fate-fitsdec-multi: tests/data/fits-multi.fits @@ -37,7 +37,7 @@ fate-fitsdec%: PIXFMT = $(word 3, $(subst -, ,$(@))) fate-fitsdec%: SRC = $(TARGET_PATH)/tests/data/lena-$(PIXFMT).fits fate-fitsdec%: CMD = framecrc -i $(SRC) -pix_fmt $(PIXFMT) -FATE_FITS_DEC_PIXFMT = gray gbrp gbrp16 gbrap16 +FATE_FITS_DEC_PIXFMT = gray gbrp gbrp16 gbrap16le $(FATE_FITS_DEC_PIXFMT:%=fate-fitsdec-%): fate-fitsdec-%: tests/data/lena-%.fits FATE_FITS_DEC-$(call ALLYES, FITS_DEMUXER IMAGE2_DEMUXER FITS_DECODER PNG_DECODER FITS_ENCODER FITS_MUXER) += $(FATE_FITS_DEC_PIXFMT:%=fate-fitsdec-%) diff --git a/tests/fate/gapless.mak b/tests/fate/gapless.mak index 0253b9ec61ee5..91fddb4130a2f 100644 --- a/tests/fate/gapless.mak +++ b/tests/fate/gapless.mak @@ -1,5 +1,5 @@ FATE_GAPLESS-$(CONFIG_MP3_DEMUXER) += fate-gapless-mp3 -fate-gapless-mp3: CMD = gapless $(TARGET_SAMPLES)/gapless/gapless.mp3 +fate-gapless-mp3: CMD = gapless $(TARGET_SAMPLES)/gapless/gapless.mp3 "-c:a mp3" FATE_GAPLESS-$(CONFIG_MP3_DEMUXER) += fate-audiomatch-square-mp3 fate-audiomatch-square-mp3: CMD = audio_match $(TARGET_SAMPLES)/audiomatch/square3.mp3 $(TARGET_SAMPLES)/audiomatch/square3.wav diff --git a/tests/fate/h264.mak b/tests/fate/h264.mak index 043e1f2d19d5e..1839b9b44eb0b 100644 --- a/tests/fate/h264.mak +++ b/tests/fate/h264.mak @@ -195,6 +195,7 @@ FATE_H264 := $(FATE_H264:%=fate-h264-conformance-%) \ fate-h264-lossless \ fate-h264-3386 \ fate-h264-missing-frame \ + fate-h264-ref-pic-mod-overflow \ FATE_H264-$(call DEMDEC, H264, H264) += $(FATE_H264) FATE_H264-$(call DEMDEC, MOV, H264) += fate-h264-crop-to-container @@ -434,6 +435,7 @@ fate-h264-intra-refresh-recovery: CMD = framecrc -i $(TARGET_SAM fate-h264-invalid-ref-mod: CMD = framecrc -i $(TARGET_SAMPLES)/h264/h264refframeregression.mp4 -an -frames 10 -pix_fmt yuv420p10le fate-h264-lossless: CMD = framecrc -i $(TARGET_SAMPLES)/h264/lossless.h264 fate-h264-mixed-nal-coding: CMD = framecrc -i $(TARGET_SAMPLES)/h264/mixed-nal-coding.mp4 +fate-h264-ref-pic-mod-overflow: CMD = framecrc -i $(TARGET_SAMPLES)/h264/ref-pic-mod-overflow.h264 fate-h264-twofields-packet: CMD = framecrc -i $(TARGET_SAMPLES)/h264/twofields_packet.mp4 -an -frames 30 fate-h264-unescaped-extradata: CMD = framecrc -i $(TARGET_SAMPLES)/h264/unescaped_extradata.mp4 -an -frames 10 fate-h264-3386: CMD = framecrc -i $(TARGET_SAMPLES)/h264/bbc2.sample.h264 diff --git a/tests/fate/hap.mak b/tests/fate/hap.mak new file mode 100644 index 0000000000000..075a602e458ea --- /dev/null +++ b/tests/fate/hap.mak @@ -0,0 +1,89 @@ +FATE_HAP += fate-hap1 +fate-hap1: CMD = framecrc -i $(TARGET_SAMPLES)/hap/hap1.mov + +FATE_HAP += fate-hap5 +fate-hap5: CMD = framecrc -i $(TARGET_SAMPLES)/hap/hap5.mov + +FATE_HAP += fate-hapy +fate-hapy: CMD = framecrc -i $(TARGET_SAMPLES)/hap/hapy.mov + +FATE_HAP += fate-hap-chunk +fate-hap-chunk: CMD = framecrc -i $(TARGET_SAMPLES)/hap/hapy-12-chunks.mov + +FATE_HAP += fate-hapqa-nosnappy-127x71 +fate-hapqa-nosnappy-127x71: CMD = framecrc -i $(TARGET_SAMPLES)/hap/HAPQA_NoSnappy_127x1.mov + +FATE_HAP += fate-hapqa-snappy1-127x71 +fate-hapqa-snappy1-127x71: CMD = framecrc -i $(TARGET_SAMPLES)/hap/HAPQA_Snappy_1chunk_127x1.mov + +FATE_HAP += fate-hapqa-snappy16-127x71 +fate-hapqa-snappy16-127x71: CMD = framecrc -i $(TARGET_SAMPLES)/hap/HAPQA_Snappy_16chunk_127x1.mov + +FATE_HAP += fate-hap-alpha-only-nosnappy-128x72 +fate-hap-alpha-only-nosnappy-128x72: CMD = framecrc -i $(TARGET_SAMPLES)/hap/HapAlphaOnly_NoSnappy_128x72.mov -pix_fmt gray8 + +FATE_HAP += fate-hap-alpha-only-snappy-127x71 +fate-hap-alpha-only-snappy-127x71: CMD = framecrc -i $(TARGET_SAMPLES)/hap/HapAlphaOnly_snappy1chunk_127x71.mov -pix_fmt gray8 + +FATE_SAMPLES_AVCONV-$(call DEMDEC, MOV, HAP) += $(FATE_HAP) +fate-hap: $(FATE_HAP) + + +#Test bsf conversion +FATE_HAPQA_EXTRACT_BSF += fate-hapqa-extract-snappy1-to-hapq +fate-hapqa-extract-snappy1-to-hapq: CMD = framecrc -i $(TARGET_SAMPLES)/hap/HAPQA_Snappy_1chunk_127x1.mov -c:v copy -bsf:v hapqa_extract=texture=color -tag:v HapY -metadata:s:v:0 encoder="HAPQ" + +FATE_HAPQA_EXTRACT_BSF += fate-hapqa-extract-snappy16-to-hapq +fate-hapqa-extract-snappy16-to-hapq: CMD = framecrc -i $(TARGET_SAMPLES)/hap/HAPQA_Snappy_16chunk_127x1.mov -c:v copy -bsf:v hapqa_extract=texture=color -tag:v HapY -metadata:s:v:0 encoder="HAPQ" + +FATE_HAPQA_EXTRACT_BSF += fate-hapqa-extract-snappy1-to-hapalphaonly +fate-hapqa-extract-snappy1-to-hapalphaonly: CMD = framecrc -i $(TARGET_SAMPLES)/hap/HAPQA_Snappy_1chunk_127x1.mov -c:v copy -bsf:v hapqa_extract=texture=alpha -tag:v HapA -metadata:s:v:0 encoder="HAPAlphaOnly" + +FATE_HAPQA_EXTRACT_BSF += fate-hapqa-extract-snappy16-to-hapalphaonly +fate-hapqa-extract-snappy16-to-hapalphaonly: CMD = framecrc -i $(TARGET_SAMPLES)/hap/HAPQA_Snappy_16chunk_127x1.mov -c:v copy -bsf:v hapqa_extract=texture=alpha -tag:v HapA -metadata:s:v:0 encoder="HAPAlphaOnly" + + +#Test bsf conversion and mov +tests/data/hapq_nosnappy.mov: TAG = GEN +tests/data/hapq_nosnappy.mov: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data + $(M)$(TARGET_EXEC) $(TARGET_PATH)/$< \ + -i $(TARGET_SAMPLES)/hap/HAPQA_NoSnappy_127x1.mov -nostdin -c:v copy -bsf:v hapqa_extract=texture=color \ + -tag:v HapY -metadata:s:v:0 encoder="HAPQ" $(TARGET_PATH)/$@ -y 2>/dev/null + +tests/data/hapalphaonly_nosnappy.mov: TAG = GEN +tests/data/hapalphaonly_nosnappy.mov: ffmpeg$(PROGSSUF)$(EXESUF) | tests/data + $(M)$(TARGET_EXEC) $(TARGET_PATH)/$< \ + -i $(TARGET_SAMPLES)/hap/HAPQA_NoSnappy_127x1.mov -nostdin -c:v copy -bsf:v hapqa_extract=texture=alpha \ + -tag:v HapA -metadata:s:v:0 encoder="HAPAlpha Only" $(TARGET_PATH)/$@ -y 2>/dev/null + + +FATE_HAPQA_EXTRACT_BSF_FFPROBE += fate-hapqa-extract-nosnappy-to-hapq-mov +fate-hapqa-extract-nosnappy-to-hapq-mov: tests/data/hapq_nosnappy.mov +fate-hapqa-extract-nosnappy-to-hapq-mov: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_packets -show_data_hash adler32 -show_streams -select_streams v -v 0 $(TARGET_PATH)/tests/data/hapq_nosnappy.mov + +FATE_HAPQA_EXTRACT_BSF_FFPROBE += fate-hapqa-extract-nosnappy-to-hapalphaonly-mov +fate-hapqa-extract-nosnappy-to-hapalphaonly-mov: tests/data/hapalphaonly_nosnappy.mov +fate-hapqa-extract-nosnappy-to-hapalphaonly-mov: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_packets -show_data_hash adler32 -show_streams -select_streams v -v 0 $(TARGET_PATH)/tests/data/hapalphaonly_nosnappy.mov + + +FATE_SAMPLES_FFMPEG-$(call ALLYES, MOV_DEMUXER HAPQA_EXTRACT_BSF MOV_MUXER) += $(FATE_HAPQA_EXTRACT_BSF) +FATE_SAMPLES_FFPROBE += $(FATE_HAPQA_EXTRACT_BSF_FFPROBE) + +fate-hapqa-extract-bsf: $(FATE_HAPQA_EXTRACT_BSF) $(FATE_HAPQA_EXTRACT_BSF_FFPROBE) + + +fate-hapenc%: CMD = framemd5 -f image2 -c:v pgmyuv -i $(TARGET_PATH)/tests/vsynth1/%02d.pgm -sws_flags +accurate_rnd+bitexact -vframes 5 -c:v hap ${OPTS} + +FATE_HAPENC += fate-hapenc-hap-none +fate-hapenc-hap-none: OPTS = -pix_fmt rgba -format hap -compressor none + +FATE_HAPENC += fate-hapenc-hapa-none +fate-hapenc-hapa-none: OPTS = -pix_fmt rgba -format hap_alpha -compressor none + +FATE_HAPENC += fate-hapenc-hapq-none +fate-hapenc-hapq-none: OPTS = -pix_fmt rgba -format hap_q -compressor none + +$(FATE_HAPENC): $(VREF) + +FATE_AVCONV-$(call ENCMUX, HAP, MOV) += $(FATE_HAPENC) +fate-hapenc: $(FATE_HAPENC) diff --git a/tests/fate/hevc.mak b/tests/fate/hevc.mak index 2e798eca60588..184349e5dd6c2 100644 --- a/tests/fate/hevc.mak +++ b/tests/fate/hevc.mak @@ -168,6 +168,7 @@ HEVC_SAMPLES_444_8BIT = \ HEVC_SAMPLES_444_12BIT = \ IPCM_B_RExt_NEC \ PERSIST_RPARAM_A_RExt_Sony_1\ + PERSIST_RPARAM_A_RExt_Sony_3\ SAO_A_RExt_MediaTek_1 \ @@ -187,7 +188,7 @@ HEVC_SAMPLES_444_12BIT = \ define FATE_HEVC_TEST FATE_HEVC += fate-hevc-conformance-$(1) -fate-hevc-conformance-$(1): CMD = framecrc -flags unaligned -vsync drop -i $(TARGET_SAMPLES)/hevc-conformance/$(1).bit +fate-hevc-conformance-$(1): CMD = framecrc -flags unaligned -vsync drop -i $(TARGET_SAMPLES)/hevc-conformance/$(1).bit -pix_fmt yuv420p endef define FATE_HEVC_TEST_10BIT @@ -207,7 +208,7 @@ endef define FATE_HEVC_TEST_444_8BIT FATE_HEVC += fate-hevc-conformance-$(1) -fate-hevc-conformance-$(1): CMD = framecrc -flags unaligned -i $(TARGET_SAMPLES)/hevc-conformance/$(1).bit +fate-hevc-conformance-$(1): CMD = framecrc -flags unaligned -i $(TARGET_SAMPLES)/hevc-conformance/$(1).bit -pix_fmt yuv444p endef define FATE_HEVC_TEST_444_12BIT @@ -239,6 +240,9 @@ fate-hevc-bsf-mp4toannexb: CMD = md5 -i $(TARGET_PATH)/tests/data/hevc-mp4.mov - fate-hevc-bsf-mp4toannexb: CMP = oneline fate-hevc-bsf-mp4toannexb: REF = 1873662a3af1848c37e4eb25722c8df9 +fate-hevc-skiploopfilter: CMD = framemd5 -skip_loop_filter nokey -i $(TARGET_SAMPLES)/hevc-conformance/SAO_D_Samsung_5.bit -sws_flags bitexact +FATE_HEVC += fate-hevc-skiploopfilter + FATE_HEVC-$(call DEMDEC, HEVC, HEVC) += $(FATE_HEVC) # this sample has two stsd entries and needs to reload extradata diff --git a/tests/fate/id3v2.mak b/tests/fate/id3v2.mak new file mode 100644 index 0000000000000..873f593d8cb39 --- /dev/null +++ b/tests/fate/id3v2.mak @@ -0,0 +1,5 @@ +FATE_SAMPLES_ID3V2-$(CONFIG_MP3_DEMUXER) += fate-id3v2-priv +fate-id3v2-priv: CMD = probetags $(TARGET_SAMPLES)/id3v2/id3v2_priv.mp3 + +FATE_SAMPLES_FFPROBE += $(FATE_SAMPLES_ID3V2-yes) +fate-id3v2: $(FATE_SAMPLES_ID3V2-yes) diff --git a/tests/fate/image.mak b/tests/fate/image.mak index 7e7be3f119e55..121405aab9cc6 100644 --- a/tests/fate/image.mak +++ b/tests/fate/image.mak @@ -284,6 +284,9 @@ fate-exr-y-scanline-zip-half-12x8: CMD = framecrc -i $(TARGET_SAMPLES)/exr/y_sca FATE_EXR += fate-exr-rgb-scanline-half-piz-dw-t08 fate-exr-rgb-scanline-half-piz-dw-t08: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgb_scanline_half_piz_dw_t08.exr -pix_fmt rgb48le +FATE_EXR += fate-exr-rgba-zip16-16x32-flag4 +fate-exr-rgba-zip16-16x32-flag4: CMD = framecrc -i $(TARGET_SAMPLES)/exr/rgba_zip16_16x32_flag4.exr -pix_fmt rgba64le + FATE_EXR-$(call DEMDEC, IMAGE2, EXR) += $(FATE_EXR) FATE_IMAGE += $(FATE_EXR-yes) diff --git a/tests/fate/libavcodec.mak b/tests/fate/libavcodec.mak index 27d631d16c4b1..d3b2dd874e96e 100644 --- a/tests/fate/libavcodec.mak +++ b/tests/fate/libavcodec.mak @@ -13,6 +13,11 @@ fate-celp_math: libavcodec/tests/celp_math$(EXESUF) fate-celp_math: CMD = run libavcodec/tests/celp_math fate-celp_math: CMP = null +FATE_LIBAVCODEC-yes += fate-codec_desc +fate-codec_desc: libavcodec/tests/codec_desc$(EXESUF) +fate-codec_desc: CMD = run libavcodec/tests/codec_desc +fate-codec_desc: CMP = null + FATE_LIBAVCODEC-$(CONFIG_GOLOMB) += fate-golomb fate-golomb: libavcodec/tests/golomb$(EXESUF) fate-golomb: CMD = run libavcodec/tests/golomb @@ -45,6 +50,11 @@ FATE_LIBAVCODEC-$(CONFIG_IIRFILTER) += fate-iirfilter fate-iirfilter: libavcodec/tests/iirfilter$(EXESUF) fate-iirfilter: CMD = run libavcodec/tests/iirfilter +FATE_LIBAVCODEC-$(CONFIG_MPEGVIDEO) += fate-mpeg12framerate +fate-mpeg12framerate: libavcodec/tests/mpeg12framerate$(EXESUF) +fate-mpeg12framerate: CMD = run libavcodec/tests/mpeg12framerate +fate-mpeg12framerate: REF = /dev/null + FATE_LIBAVCODEC-yes += fate-libavcodec-options fate-libavcodec-options: libavcodec/tests/options$(EXESUF) fate-libavcodec-options: CMD = run libavcodec/tests/options diff --git a/tests/fate/libavutil.mak b/tests/fate/libavutil.mak index 591cab9b583d0..9b32d880f516a 100644 --- a/tests/fate/libavutil.mak +++ b/tests/fate/libavutil.mak @@ -23,11 +23,6 @@ fate-cast5: libavutil/tests/cast5$(EXESUF) fate-cast5: CMD = run libavutil/tests/cast5 fate-cast5: CMP = null -FATE_LIBAVUTIL += fate-atomic -fate-atomic: libavutil/tests/atomic$(EXESUF) -fate-atomic: CMD = run libavutil/tests/atomic -fate-atomic: CMP = null - FATE_LIBAVUTIL += fate-audio_fifo fate-audio_fifo: libavutil/tests/audio_fifo$(EXESUF) fate-audio_fifo: CMD = run libavutil/tests/audio_fifo @@ -95,6 +90,11 @@ FATE_LIBAVUTIL += fate-imgutils fate-imgutils: libavutil/tests/imgutils$(EXESUF) fate-imgutils: CMD = run libavutil/tests/imgutils +FATE_LIBAVUTIL += fate-integer +fate-integer: libavutil/tests/integer$(EXESUF) +fate-integer: CMD = run libavutil/tests/integer +fate-integer: CMP = null + FATE_LIBAVUTIL += fate-lfg fate-lfg: libavutil/tests/lfg$(EXESUF) fate-lfg: CMD = run libavutil/tests/lfg diff --git a/tests/fate/mov.mak b/tests/fate/mov.mak index cfdada7a2e070..9d7d62a023238 100644 --- a/tests/fate/mov.mak +++ b/tests/fate/mov.mak @@ -6,13 +6,24 @@ FATE_MOV = fate-mov-3elist \ fate-mov-1elist-ends-last-bframe \ fate-mov-2elist-elist1-ends-bframe \ fate-mov-3elist-encrypted \ + fate-mov-invalid-elst-entry-count \ fate-mov-gpmf-remux \ + fate-mov-440hz-10ms \ + fate-mov-ibi-elst-starts-b \ + fate-mov-elst-ends-betn-b-and-i \ + fate-mov-frag-overlap \ + fate-mov-bbi-elst-starts-b \ + fate-mov-neg-firstpts-discard-frames \ -FATE_MOV_FFPROBE = fate-mov-aac-2048-priming \ +FATE_MOV_FFPROBE = fate-mov-neg-firstpts-discard \ + fate-mov-aac-2048-priming \ fate-mov-zombie \ fate-mov-init-nonkeyframe \ fate-mov-displaymatrix \ fate-mov-spherical-mono \ + fate-mov-guess-delay-1 \ + fate-mov-guess-delay-2 \ + fate-mov-guess-delay-3 \ FATE_SAMPLES_AVCONV += $(FATE_MOV) FATE_SAMPLES_FFPROBE += $(FATE_MOV_FFPROBE) @@ -39,6 +50,36 @@ fate-mov-1elist-ends-last-bframe: CMD = framemd5 -i $(TARGET_SAMPLES)/mov/mov-1e # Makes sure that we handle timestamps of packets in case of multiple edit lists with one of them ending on a B-frame correctly. fate-mov-2elist-elist1-ends-bframe: CMD = framemd5 -i $(TARGET_SAMPLES)/mov/mov-2elist-elist1-ends-bframe.mov +# Makes sure that if edit list ends on a B-frame but before the I-frame, then we output the B-frame but discard the I-frame. +fate-mov-elst-ends-betn-b-and-i: CMD = framemd5 -i $(TARGET_SAMPLES)/mov/elst_ends_betn_b_and_i.mp4 + +# Makes sure that we handle edit lists and start padding correctly. +fate-mov-440hz-10ms: CMD = framemd5 -i $(TARGET_SAMPLES)/mov/440hz-10ms.m4a + +# Makes sure that we handle invalid edit list entry count correctly. +fate-mov-invalid-elst-entry-count: CMD = framemd5 -idct simple -flags +bitexact -i $(TARGET_SAMPLES)/mov/invalid_elst_entry_count.mov + +# Makes sure that 1st key-frame is picked when, +# i) One B-frame between 2 key-frames +# ii) Edit list starts on B-frame. +# iii) Both key-frames have their DTS < edit list start +# i.e. Pts Order: I-B-I +fate-mov-ibi-elst-starts-b: CMD = framemd5 -flags +bitexact -i $(TARGET_SAMPLES)/mov/mov_ibi_elst_starts_b.mov + +# Makes sure that we handle overlapping framgments +fate-mov-frag-overlap: CMD = framemd5 -i $(TARGET_SAMPLES)/mov/frag_overlap.mp4 + +# Makes sure that we pick the right frames according to edit list when there is no keyframe with PTS < edit list start. +# For example, when video starts on a B-frame, and edit list starts on that B-frame too. +# GOP structure : B B I in presentation order. +fate-mov-bbi-elst-starts-b: CMD = framemd5 -flags +bitexact -acodec aac_fixed -i $(TARGET_SAMPLES)/h264/twofields_packet.mp4 + +# Makes sure that the stream start_time is not negative when the first packet is a DISCARD packet with negative timestamp. +fate-mov-neg-firstpts-discard: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_entries stream=start_time -bitexact $(TARGET_SAMPLES)/mov/mov_neg_first_pts_discard.mov + +# Makes sure that expected frames are generated for mov_neg_first_pts_discard.mov with -vsync 1 +fate-mov-neg-firstpts-discard-frames: CMD = framemd5 -flags +bitexact -i $(TARGET_SAMPLES)/mov/mov_neg_first_pts_discard.mov -vsync 1 + fate-mov-aac-2048-priming: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_packets -print_format compact $(TARGET_SAMPLES)/mov/aac-2048-priming.mov fate-mov-zombie: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_streams -show_packets -show_frames -bitexact -print_format compact $(TARGET_SAMPLES)/mov/white_zombie_scrunch-part.mov @@ -52,3 +93,7 @@ fate-mov-spherical-mono: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_entries str fate-mov-gpmf-remux: CMD = md5 -i $(TARGET_SAMPLES)/mov/fake-gp-media-with-real-gpmf.mp4 -map 0 -c copy -fflags +bitexact -f mp4 fate-mov-gpmf-remux: CMP = oneline fate-mov-gpmf-remux: REF = 8f48e435ee1f6b7e173ea756141eabf3 + +fate-mov-guess-delay-1: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_entries stream=has_b_frames -select_streams v $(TARGET_SAMPLES)/h264/h264_3bf_nopyramid_nobsrestriction.mp4 +fate-mov-guess-delay-2: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_entries stream=has_b_frames -select_streams v $(TARGET_SAMPLES)/h264/h264_3bf_pyramid_nobsrestriction.mp4 +fate-mov-guess-delay-3: CMD = run ffprobe$(PROGSSUF)$(EXESUF) -show_entries stream=has_b_frames -select_streams v $(TARGET_SAMPLES)/h264/h264_4bf_pyramid_nobsrestriction.mp4 diff --git a/tests/fate/mpegps.mak b/tests/fate/mpegps.mak new file mode 100644 index 0000000000000..cec1ea77fa126 --- /dev/null +++ b/tests/fate/mpegps.mak @@ -0,0 +1,7 @@ +# This tests that a 16-bit pcm_dvd stream is correctly remuxed in mpegps +FATE_MPEGPS-$(call DEMMUX, MPEGPS, MPEG1SYSTEM) += fate-mpegps-remuxed-pcm-demux +fate-mpegps-remuxed-pcm-demux: $(TARGET_SAMPLES)/mpegps/pcm_aud.mpg +fate-mpegps-remuxed-pcm-demux: CMD = stream_remux "mpeg" "$(TARGET_SAMPLES)/mpegps/pcm_aud.mpg" "mpeg" "-map 0:a:0" "-codec copy" + +FATE_SAMPLES_FFMPEG += $(FATE_MPEGPS-yes) +fate-mpegps: $(FATE_MPEGPS-yes) diff --git a/tests/fate/mpegts.mak b/tests/fate/mpegts.mak index bb0d9d98a7761..2b128492e0ab0 100644 --- a/tests/fate/mpegts.mak +++ b/tests/fate/mpegts.mak @@ -9,6 +9,12 @@ FATE_MPEGTS_PROBE-$(call DEMDEC, MPEGTS, HEVC, AAC_LATM) += fate-mpegts-probe-la fate-mpegts-probe-latm: SRC = $(TARGET_SAMPLES)/mpegts/loewe.ts fate-mpegts-probe-latm: CMD = run $(PROBE_CODEC_NAME_COMMAND) -i "$(SRC)" + +FATE_MPEGTS_PROBE-$(call DEMDEC, MPEGTS, HEVC, AAC_LATM) += fate-mpegts-probe-program +fate-mpegts-probe-program: SRC = $(TARGET_SAMPLES)/mpegts/loewe.ts +fate-mpegts-probe-program: CMD = run $(PROBE_CODEC_NAME_COMMAND) -select_streams p:769:v:0 -i "$(SRC)" + + FATE_SAMPLES_FFPROBE += $(FATE_MPEGTS_PROBE-yes) fate-mpegts: $(FATE_MPEGTS_PROBE-yes) diff --git a/tests/fate/mxf.mak b/tests/fate/mxf.mak index 7714b61569461..dce23d522ea65 100644 --- a/tests/fate/mxf.mak +++ b/tests/fate/mxf.mak @@ -33,9 +33,13 @@ FATE_MXF_PROBE-$(call ENCDEC2, DVVIDEO, PCM_S16LE, MXF) += fate-mxf-probe-dv25 fate-mxf-probe-dv25: SRC = $(TARGET_SAMPLES)/mxf/Avid-00005.mxf fate-mxf-probe-dv25: CMD = run $(PROBE_FORMAT_STREAMS_COMMAND) -i "$(SRC)" +FATE_MXF_REEL_NAME-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, MXF) += fate-mxf-reel_name +fate-mxf-reel_name: $(TARGET_SAMPLES)/mxf/Sony-00001.mxf +fate-mxf-reel_name: CMD = md5 -y -i $(TARGET_SAMPLES)/mxf/Sony-00001.mxf -c copy -timecode 00:00:00:00 -metadata "reel_name=test_reel" -fflags +bitexact -f mxf + FATE_MXF-$(CONFIG_MXF_DEMUXER) += $(FATE_MXF) -FATE_SAMPLES_AVCONV += $(FATE_MXF-yes) +FATE_SAMPLES_AVCONV += $(FATE_MXF-yes) $(FATE_MXF_REEL_NAME-yes) FATE_SAMPLES_FFPROBE += $(FATE_MXF_PROBE-yes) -fate-mxf: $(FATE_MXF-yes) $(FATE_MXF_PROBE-yes) +fate-mxf: $(FATE_MXF-yes) $(FATE_MXF_PROBE-yes) $(FATE_MXF_REEL_NAME-yes) diff --git a/tests/fate/opus.mak b/tests/fate/opus.mak index b13d86c138ecd..7f289455cf5d8 100644 --- a/tests/fate/opus.mak +++ b/tests/fate/opus.mak @@ -1,26 +1,22 @@ # The samples were produced by simply rewrapping the official test vectors from -# their custom format into Matroska. -# The reference files were created with our decoder and tested against the -# libopus output with the official opus_compare tool. We cannot use libopus -# output as reference directly, because the use of different resamplers would -# require too high fuzz values, which can hide bugs. -# Before adding new tests here, always make sure they pass opus_compare. +# their custom format into Matroska. The reference decoded outputs are from the +# newest testvectors file from RFC8251 -OPUS_CELT_SAMPLES = $(addprefix testvector, 01 07 11) tron.6ch.tinypkts +OPUS_CELT_SAMPLES = $(addprefix testvector, 01 11) tron.6ch.tinypkts OPUS_HYBRID_SAMPLES = $(addprefix testvector, 05 06) OPUS_SILK_SAMPLES = $(addprefix testvector, 02 03 04) -OPUS_SAMPLES = $(addprefix testvector, 08 09 10 12) +OPUS_SAMPLES = $(addprefix testvector, 07 08 09 10 12) define FATE_OPUS_TEST FATE_OPUS += fate-opus-$(1) FATE_OPUS$(2) += fate-opus-$(1) fate-opus-$(1): CMD = ffmpeg -i $(TARGET_SAMPLES)/opus/$(1).mka -f s16le - -fate-opus-$(1): REF = $(SAMPLES)/opus/$(1).dec +fate-opus-$(1): REF = $(SAMPLES)/opus/$(1)$(2).dec endef -$(foreach N,$(OPUS_CELT_SAMPLES), $(eval $(call FATE_OPUS_TEST,$(N),_CELT))) -$(foreach N,$(OPUS_HYBRID_SAMPLES),$(eval $(call FATE_OPUS_TEST,$(N),_HYBRID))) -$(foreach N,$(OPUS_SILK_SAMPLES), $(eval $(call FATE_OPUS_TEST,$(N),_SILK))) +$(foreach N,$(OPUS_CELT_SAMPLES), $(eval $(call FATE_OPUS_TEST,$(N)))) +$(foreach N,$(OPUS_HYBRID_SAMPLES),$(eval $(call FATE_OPUS_TEST,$(N),_v2))) +$(foreach N,$(OPUS_SILK_SAMPLES), $(eval $(call FATE_OPUS_TEST,$(N)))) $(foreach N,$(OPUS_SAMPLES), $(eval $(call FATE_OPUS_TEST,$(N),))) FATE_OPUS := $(sort $(FATE_OPUS)) @@ -28,14 +24,19 @@ FATE_OPUS := $(sort $(FATE_OPUS)) $(FATE_OPUS): CMP = stddev $(FATE_OPUS): CMP_UNIT = s16 $(FATE_OPUS): FUZZ = 3 -fate-opus-testvector02: CMP_TARGET = 191 -fate-opus-testvector03: CMP_TARGET = 139 -fate-opus-testvector04: CMP_TARGET = 119 -fate-opus-testvector05: CMP_TARGET = 108 -fate-opus-testvector06: CMP_TARGET = 106 -fate-opus-testvector08: CMP_TARGET = 6 -fate-opus-testvector10: CMP_TARGET = 38 -fate-opus-testvector12: CMP_TARGET = 160 +fate-opus-testvector01: CMP_TARGET = 0 +fate-opus-testvector02: CMP_TARGET = 191 +fate-opus-testvector03: CMP_TARGET = 139 +fate-opus-testvector04: CMP_TARGET = 119 +fate-opus-testvector05: CMP_TARGET = 108 +fate-opus-testvector06: CMP_TARGET = 106 +fate-opus-testvector07: CMP_TARGET = 0 +fate-opus-testvector08: CMP_TARGET = 6 +fate-opus-testvector09: CMP_TARGET = 0 +fate-opus-testvector10: CMP_TARGET = 38 +fate-opus-testvector11: CMP_TARGET = 0 +fate-opus-testvector12: CMP_TARGET = 160 +fate-opus-tron.6ch.tinypkts: CMP_TARGET = 0 $(FATE_OPUS_CELT): CMP = oneoff $(FATE_OPUS_CELT): FUZZ = 6 diff --git a/tests/fate/screen.mak b/tests/fate/screen.mak index 66dfa6ba7fa99..68b4f6f979cdc 100644 --- a/tests/fate/screen.mak +++ b/tests/fate/screen.mak @@ -8,6 +8,15 @@ fate-dxtory: CMD = framecrc -i $(TARGET_SAMPLES)/dxtory/dxtory_mic.avi -an FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, FIC) += fate-fic-avi fate-fic-avi: CMD = framecrc -i $(TARGET_SAMPLES)/fic/fic-partial-2MB.avi -an +FATE_FMVC += fate-fmvc-type1 +fate-fmvc-type1: CMD = framecrc -i $(TARGET_SAMPLES)/fmvc/6-methyl-5-hepten-2-one-CC-db_small.avi + +FATE_FMVC += fate-fmvc-type2 +fate-fmvc-type2: CMD = framecrc -i $(TARGET_SAMPLES)/fmvc/fmvcVirtualDub_small.avi + +FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, FMVC) += $(FATE_FMVC) +fate-fmvc: $(FATE_FMVC) + FATE_FRAPS += fate-fraps-v0 fate-fraps-v0: CMD = framecrc -i $(TARGET_SAMPLES)/fraps/Griffin_Ragdoll01-partial.avi diff --git a/tests/fate/seek.mak b/tests/fate/seek.mak index c863b2aaa454b..6a9f843d828db 100644 --- a/tests/fate/seek.mak +++ b/tests/fate/seek.mak @@ -168,7 +168,6 @@ FATE_SEEK_LAVF-$(call ENCDEC, PCM_S16BE, AU) += au FATE_SEEK_LAVF-$(call ENCDEC2, MPEG4, MP2, AVI) += avi FATE_SEEK_LAVF-$(call ENCDEC, BMP, IMAGE2) += bmp FATE_SEEK_LAVF-$(call ENCDEC2, DVVIDEO, PCM_S16LE, AVI) += dv_fmt -FATE_SEEK_LAVF-$(call ENCDEC2, MPEG1VIDEO, MP2, FFM) += ffm FATE_SEEK_LAVF-$(call ENCDEC, FLV, FLV) += flv_fmt FATE_SEEK_LAVF-$(call ENCDEC, GIF, IMAGE2) += gif FATE_SEEK_LAVF-$(call ENCDEC2, MPEG2VIDEO, PCM_S16LE, GXF) += gxf @@ -210,7 +209,6 @@ fate-seek-lavf-au: SRC = lavf/lavf.au fate-seek-lavf-avi: SRC = lavf/lavf.avi fate-seek-lavf-bmp: SRC = images/bmp/%02d.bmp fate-seek-lavf-dv_fmt: SRC = lavf/lavf.dv -fate-seek-lavf-ffm: SRC = lavf/lavf.ffm fate-seek-lavf-flv_fmt: SRC = lavf/lavf.flv fate-seek-lavf-gif: SRC = lavf/lavf.gif fate-seek-lavf-gxf: SRC = lavf/lavf.gxf @@ -253,9 +251,15 @@ FATE_SEEK_EXTRA-$(CONFIG_MP3_DEMUXER) += fate-seek-extra-mp3 FATE_SEEK_EXTRA-$(call ALLYES, CACHE_PROTOCOL PIPE_PROTOCOL MP3_DEMUXER) += fate-seek-cache-pipe FATE_SEEK_EXTRA-$(CONFIG_MATROSKA_DEMUXER) += fate-seek-mkv-codec-delay FATE_SEEK_EXTRA-$(CONFIG_MOV_DEMUXER) += fate-seek-extra-mp4 +FATE_SEEK_EXTRA-$(CONFIG_MOV_DEMUXER) += fate-seek-empty-edit-mp4 +FATE_SEEK_EXTRA-$(CONFIG_MOV_DEMUXER) += fate-seek-test-iibbibb-mp4 +FATE_SEEK_EXTRA-$(CONFIG_MOV_DEMUXER) += fate-seek-test-iibbibb-neg-ctts-mp4 fate-seek-extra-mp3: CMD = run libavformat/tests/seek$(EXESUF) $(TARGET_SAMPLES)/gapless/gapless.mp3 -fastseek 1 fate-seek-extra-mp4: CMD = run libavformat/tests/seek$(EXESUF) $(TARGET_SAMPLES)/mov/buck480p30_na.mp4 -duration 180 -frames 4 +fate-seek-empty-edit-mp4: CMD = run libavformat/tests/seek$(EXESUF) $(TARGET_SAMPLES)/mov/empty_edit_5s.mp4 -duration 15 -frames 4 +fate-seek-test-iibbibb-mp4: CMD = run libavformat/tests/seek$(EXESUF) $(TARGET_SAMPLES)/mov/test_iibbibb.mp4 -duration 13 -frames 4 +fate-seek-test-iibbibb-neg-ctts-mp4: CMD = run libavformat/tests/seek$(EXESUF) $(TARGET_SAMPLES)/mov/test_iibbibb_neg_ctts.mp4 -duration 13 -frames 4 fate-seek-cache-pipe: CMD = cat $(TARGET_SAMPLES)/gapless/gapless.mp3 | run libavformat/tests/seek$(EXESUF) cache:pipe:0 -read_ahead_limit -1 fate-seek-mkv-codec-delay: CMD = run libavformat/tests/seek$(EXESUF) $(TARGET_SAMPLES)/mkv/codec_delay_opus.mkv diff --git a/tests/fate/subtitles.mak b/tests/fate/subtitles.mak index 8c310adeff0c3..00429021617e5 100644 --- a/tests/fate/subtitles.mak +++ b/tests/fate/subtitles.mak @@ -7,6 +7,9 @@ fate-sub-cc: CMD = fmtstdout ass -f lavfi -i "movie=$(TARGET_SAMPLES)/sub/Closed FATE_SUBTITLES_ASS-$(call ALLYES, AVDEVICE LAVFI_INDEV CCAPTION_DECODER MOVIE_FILTER MPEGTS_DEMUXER) += fate-sub-cc-realtime fate-sub-cc-realtime: CMD = fmtstdout ass -real_time 1 -f lavfi -i "movie=$(TARGET_SAMPLES)/sub/Closedcaption_rollup.m2v[out0+subcc]" +FATE_SUBTITLES_ASS-$(call ALLYES, AVDEVICE LAVFI_INDEV CCAPTION_DECODER MOVIE_FILTER MPEGTS_DEMUXER) += fate-sub-cc-scte20 +fate-sub-cc-scte20: CMD = fmtstdout ass -f lavfi -i "movie=$(TARGET_SAMPLES)/sub/scte20.ts[out0+subcc]" + FATE_SUBTITLES_ASS-$(call DEMDEC, ASS, ASS) += fate-sub-ass-to-ass-transcode fate-sub-ass-to-ass-transcode: CMD = fmtstdout ass -i $(TARGET_SAMPLES)/sub/1ededcbd7b.ass diff --git a/tests/fate/utvideo.mak b/tests/fate/utvideo.mak index 2cf06b36f5865..23224718ee61a 100644 --- a/tests/fate/utvideo.mak +++ b/tests/fate/utvideo.mak @@ -10,6 +10,15 @@ fate-utvideo_rgba_left: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_rgba FATE_UTVIDEO += fate-utvideo_rgba_median fate-utvideo_rgba_median: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_rgba_median.avi +FATE_UTVIDEO += fate-utvideo_rgb_int_median +fate-utvideo_rgb_int_median: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_rgb_64x48_int_median.avi + +FATE_UTVIDEO += fate-utvideo_rgba_gradient +fate-utvideo_rgba_gradient: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_rgba_gradient.avi + +FATE_UTVIDEO += fate-utvideo_rgb_int_gradient +fate-utvideo_rgb_int_gradient: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_rgb_64x48_int_gradient.avi + FATE_UTVIDEO += fate-utvideo_rgba_single_symbol fate-utvideo_rgba_single_symbol: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_rgba_single_symbol.avi @@ -19,34 +28,64 @@ fate-utvideo_yuv420_left: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yu FATE_UTVIDEO += fate-utvideo_yuv420_median fate-utvideo_yuv420_median: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv420_median.avi +FATE_UTVIDEO += fate-utvideo_yuv420_int_median +fate-utvideo_yuv420_int_median: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv420_709_64x48_int_median.avi + +FATE_UTVIDEO += fate-utvideo_yuv420_gradient +fate-utvideo_yuv420_gradient: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv420_709_64x48_gradient.avi + +FATE_UTVIDEO += fate-utvideo_yuv420_int_gradient +fate-utvideo_yuv420_int_gradient: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv420_709_64x48_int_gradient.avi + FATE_UTVIDEO += fate-utvideo_yuv422_left fate-utvideo_yuv422_left: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv422_left.avi FATE_UTVIDEO += fate-utvideo_yuv422_median fate-utvideo_yuv422_median: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv422_median.avi +FATE_UTVIDEO += fate-utvideo_yuv422_int_median +fate-utvideo_yuv422_int_median: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv422_709_64x48_int_median.avi + +FATE_UTVIDEO += fate-utvideo_yuv422_gradient +fate-utvideo_yuv422_gradient: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv422_709_64x48_gradient.avi + +FATE_UTVIDEO += fate-utvideo_yuv422_int_gradient +fate-utvideo_yuv422_int_gradient: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv422_709_64x48_int_gradient.avi + +FATE_UTVIDEO += fate-utvideo_yuv444_709_median +fate-utvideo_yuv444_709_median: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv444_709_64x48_median.avi + +FATE_UTVIDEO += fate-utvideo_yuv444_709_int_median +fate-utvideo_yuv444_709_int_median: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv444_709_64x48_int_median.avi + +FATE_UTVIDEO += fate-utvideo_yuv444_709_gradient +fate-utvideo_yuv444_709_gradient: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv444_709_gradient.avi + +FATE_UTVIDEO += fate-utvideo_yuv444_709_int_gradient +fate-utvideo_yuv444_709_int_gradient: CMD = framecrc -i $(TARGET_SAMPLES)/utvideo/utvideo_yuv444_709_64x48_int_gradient.avi + FATE_SAMPLES_AVCONV-$(call DEMDEC, AVI, UTVIDEO) += $(FATE_UTVIDEO) fate-utvideo: $(FATE_UTVIDEO) fate-utvideoenc%: CMD = framemd5 -f image2 -c:v pgmyuv -i $(TARGET_PATH)/tests/vsynth1/%02d.pgm -c:v utvideo -slices 1 -sws_flags +accurate_rnd+bitexact ${OPTS} FATE_UTVIDEOENC += fate-utvideoenc_rgba_left -fate-utvideoenc_rgba_left: OPTS = -pix_fmt rgba -pred left +fate-utvideoenc_rgba_left: OPTS = -pix_fmt gbrap -pred left FATE_UTVIDEOENC += fate-utvideoenc_rgba_median -fate-utvideoenc_rgba_median: OPTS = -pix_fmt rgba -pred median +fate-utvideoenc_rgba_median: OPTS = -pix_fmt gbrap -pred median FATE_UTVIDEOENC += fate-utvideoenc_rgba_none -fate-utvideoenc_rgba_none: OPTS = -pix_fmt rgba -pred none +fate-utvideoenc_rgba_none: OPTS = -pix_fmt gbrap -pred none FATE_UTVIDEOENC += fate-utvideoenc_rgb_left -fate-utvideoenc_rgb_left: OPTS = -pix_fmt rgb24 -pred left +fate-utvideoenc_rgb_left: OPTS = -pix_fmt gbrp -pred left FATE_UTVIDEOENC += fate-utvideoenc_rgb_median -fate-utvideoenc_rgb_median: OPTS = -pix_fmt rgb24 -pred median +fate-utvideoenc_rgb_median: OPTS = -pix_fmt gbrp -pred median FATE_UTVIDEOENC += fate-utvideoenc_rgb_none -fate-utvideoenc_rgb_none: OPTS = -pix_fmt rgb24 -pred none +fate-utvideoenc_rgb_none: OPTS = -pix_fmt gbrp -pred none FATE_UTVIDEOENC += fate-utvideoenc_yuv420_left fate-utvideoenc_yuv420_left: OPTS = -pix_fmt yuv420p -pred left @@ -66,6 +105,15 @@ fate-utvideoenc_yuv422_median: OPTS = -pix_fmt yuv422p -pred median FATE_UTVIDEOENC += fate-utvideoenc_yuv422_none fate-utvideoenc_yuv422_none: OPTS = -pix_fmt yuv422p -pred none +FATE_UTVIDEOENC += fate-utvideoenc_yuv444_left +fate-utvideoenc_yuv444_left: OPTS = -pix_fmt yuv444p -pred left + +FATE_UTVIDEOENC += fate-utvideoenc_yuv444_median +fate-utvideoenc_yuv444_median: OPTS = -pix_fmt yuv444p -pred median + +FATE_UTVIDEOENC += fate-utvideoenc_yuv444_none +fate-utvideoenc_yuv444_none: OPTS = -pix_fmt yuv444p -pred none + $(FATE_UTVIDEOENC): $(VREF) FATE_AVCONV-$(call ENCMUX, UTVIDEO, AVI) += $(FATE_UTVIDEOENC) diff --git a/tests/fate/vcodec.mak b/tests/fate/vcodec.mak index c0344550f9de8..bbcf25d72a0b4 100644 --- a/tests/fate/vcodec.mak +++ b/tests/fate/vcodec.mak @@ -18,9 +18,9 @@ fate-vsynth%-asv1: ENCOPTS = -qscale 10 FATE_VCODEC-$(call ENCDEC, ASV2, AVI) += asv2 fate-vsynth%-asv2: ENCOPTS = -qscale 10 -FATE_VCODEC-$(call ENCDEC, CINEPAK, MOV) += cinepak -fate-vsynth%-cinepak: ENCOPTS = -c:v cinepak -frames 3 -fate-vsynth%-cinepak: FMT = mov +FATE_VCODEC-$(call ENCDEC, CINEPAK, AVI) += cinepak +fate-vsynth%-cinepak: ENCOPTS = -s sqcif -strip_number_adaptivity 1 +fate-vsynth%-cinepak: DECOPTS = -s sqcif FATE_VCODEC-$(call ENCDEC, CLJR, AVI) += cljr fate-vsynth%-cljr: ENCOPTS = -strict -1 diff --git a/tests/fate/video.mak b/tests/fate/video.mak index 930eece2cab14..43c3432c95498 100644 --- a/tests/fate/video.mak +++ b/tests/fate/video.mak @@ -69,6 +69,18 @@ fate-cavs: CMD = framecrc -i $(TARGET_SAMPLES)/cavs/cavs.mpg -an FATE_VIDEO-$(call DEMDEC, CDG, CDGRAPHICS) += fate-cdgraphics fate-cdgraphics: CMD = framecrc -i $(TARGET_SAMPLES)/cdgraphics/BrotherJohn.cdg -pix_fmt rgba -t 1 +FATE_CFHD-$(CONFIG_AVI_DEMUXER) += fate-cfhd-1 +fate-cfhd-1: CMD = framecrc -i $(TARGET_SAMPLES)/cfhd/cfhd_422.avi -pix_fmt yuv422p10le + +FATE_CFHD-$(CONFIG_AVI_DEMUXER) += fate-cfhd-2 +fate-cfhd-2: CMD = framecrc -i $(TARGET_SAMPLES)/cfhd/cfhd_444.avi -pix_fmt gbrp12le + +FATE_CFHD-$(CONFIG_MOV_DEMUXER) += fate-cfhd-3 +fate-cfhd-3: CMD = framecrc -i $(TARGET_SAMPLES)/cfhd/cfhd_odd.mov -pix_fmt yuv422p10le + +FATE_VIDEO-$(CONFIG_CFHD_DECODER) += $(FATE_CFHD-yes) +fate-cfhd: $(FATE_CFHD-yes) + FATE_VIDEO-$(call DEMDEC, AVI, CLJR) += fate-cljr fate-cljr: CMD = framecrc -i $(TARGET_SAMPLES)/cljr/testcljr-partial.avi @@ -159,21 +171,6 @@ fate-id-cin-video: CMD = framecrc -i $(TARGET_SAMPLES)/idcin/idlog-2MB.cin -pix_ FATE_VIDEO-$(call ENCDEC, ROQ PGMYUV, ROQ IMAGE2) += fate-idroq-video-encode fate-idroq-video-encode: CMD = md5 -f image2 -c:v pgmyuv -i $(TARGET_SAMPLES)/ffmpeg-synthetic/vsynth1/%02d.pgm -r 30 -sws_flags +bitexact -vf pad=512:512:80:112 -f roq -t 0.2 -FATE_HAP += fate-hap1 -fate-hap1: CMD = framecrc -i $(TARGET_SAMPLES)/hap/hap1.mov - -FATE_HAP += fate-hap5 -fate-hap5: CMD = framecrc -i $(TARGET_SAMPLES)/hap/hap5.mov - -FATE_HAP += fate-hapy -fate-hapy: CMD = framecrc -i $(TARGET_SAMPLES)/hap/hapy.mov - -FATE_HAP += fate-hap-chunk -fate-hap-chunk: CMD = framecrc -i $(TARGET_SAMPLES)/hap/hapy-12-chunks.mov - -FATE_VIDEO-$(call DEMDEC, MOV, HAP) += $(FATE_HAP) -fate-hap: $(FATE_HAP) - FATE_IFF-$(CONFIG_IFF_ILBM_DECODER) += fate-iff-byterun1 fate-iff-byterun1: CMD = framecrc -i $(TARGET_SAMPLES)/iff/ASH.LBM -pix_fmt rgb24 @@ -245,6 +242,9 @@ fate-mpeg2-ticket186: CMD = framecrc -flags +bitexact -idct simple -i $(TARGET_S FATE_VIDEO-$(call DEMDEC, MPEGPS, MPEG2VIDEO) += fate-mpeg2-ticket6024 fate-mpeg2-ticket6024: CMD = framecrc -flags +bitexact -idct simple -flags +truncated -i $(TARGET_SAMPLES)/mpeg2/matrixbench_mpeg2.lq1.mpg -an +FATE_VIDEO-$(call DEMDEC, MPEGVIDEO, MPEG2VIDEO) += fate-mpeg2-ticket6677 +fate-mpeg2-ticket6677: CMD = framecrc -flags +bitexact -idct simple -vsync drop -i $(TARGET_SAMPLES)/mpeg2/sony-ct3.bs + FATE_VIDEO-$(call DEMDEC, MV, MVC1) += fate-mv-mvc1 fate-mv-mvc1: CMD = framecrc -i $(TARGET_SAMPLES)/mv/posture.mv -an -frames 25 -pix_fmt rgb555le diff --git a/tests/ffserver-regression.sh b/tests/ffserver-regression.sh deleted file mode 100755 index 9007fe37ca8ff..0000000000000 --- a/tests/ffserver-regression.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh - -target_samples=$3 -target_exec=$4 -target_path=$5 - -#perl -e 'chomp($wd = `pwd`); print map { s!tests/data/!!; "\nFile $wd/tests/data/$_\n\n\n" } @ARGV' tests/data/a* >> tests/data/ffserver.conf -#perl -e 'chomp($wd = `pwd`); print map { s!tests/data/!!; "\nFile $wd/tests/data/$_\n\n\n" } @ARGV' tests/data/a* >> tests/data/ffserver.conf - -. $(dirname $0)/md5.sh - -FILES=$(sed -n 's/^[^#]*.*/\1/p' $2 | grep -v html) - -rm -f tests/feed1.ffm -$target_exec ${target_path}/ffserver${PROGSUF} -f "$2" & -FFSERVER_PID=$! -echo "Waiting for feeds to startup..." -sleep 2 -( - cd tests/data || exit $? - rm -f ff-* ffserver.regression - WGET_OPTIONS="--user-agent=NSPlayer -q --proxy=off -e verbose=off -e server_response=off -T3 --tries=1" - for file in $FILES; do - if [ $(expr $file : "a-*") != 0 ]; then - wget $WGET_OPTIONS -O - http://localhost:9999/$file > ff-$file - else - wget $WGET_OPTIONS -O - http://localhost:9999/$file?date=19700101T000000Z | dd bs=1 count=100000 > ff-$file 2>/dev/null - fi - do_md5sum ff-$file >>ffserver.regression - done - wget $WGET_OPTIONS -O - 'http://localhost:9999/teststat.html?abc' > ff-stat 2>/dev/null - do_md5sum ff-stat >>ffserver.regression -) -kill $FFSERVER_PID -wait > /dev/null 2>&1 -rm -f tests/feed1.ffm -if diff -u "$1" tests/data/ffserver.regression; then - echo - echo Server regression test succeeded. - exit 0 -else - echo - echo Server regression test: Error. - exit 1 -fi diff --git a/tests/ffserver.conf b/tests/ffserver.conf deleted file mode 100644 index 3495d959e2577..0000000000000 --- a/tests/ffserver.conf +++ /dev/null @@ -1,311 +0,0 @@ -# -# This is a test configuration file. You can invoke it with -# ../ffserver -f ffserver.conf -# when in the tests directory and once the vsynth1 subdirectory -# has been populated. Then point your browser at http://whatever:9999/teststat.html -# and you can look at the streams -# - -# -# Port on which the server is listening. You must select a different -# port from your standard http web server if it is running on the same -# computer. - -HTTPPort 9999 -RTSPPort 9990 - -# Address on which the server is bound. Only useful if you have -# several network interfaces. - -HTTPBindAddress 0.0.0.0 - -# Number of simultaneous requests that can be handled. Since FFServer -# is very fast, this limit is determined mainly by your Internet -# connection speed. - -MaxClients 1000 - -MaxBandwidth 100000 - -# Access Log file (uses standard Apache log file format) -# '-' is the standard output - -CustomLog - - -################################################################## -# Definition of the live feeds. Each live feed contains one video -# and/or audio sequence coming from an ffmpeg encoder or another -# ffserver. This sequence may be encoded simultaneously with several -# codecs at several resolutions. - - - -# You must use 'ffmpeg' to send a live feed to ffserver. In this -# example, you can type: -# -# ffmpeg http://localhost:8090/feed1.ffm - -# ffserver can also do time shifting. It means that it can stream any -# previously recorded live stream. The request should contain: -# "http://xxxx?date=[YYYY-MM-DDT][[HH:]MM:]SS[.m...]".You must specify -# a path where the feed is stored on disk. You also specify the -# maximum size of the feed (100M bytes here). Default: -# File=/tmp/feed_name.ffm FileMaxSize=5M - -File tests/feed1.ffm -FileMaxSize 100M - -# Fire up ffmpeg pointing at this stream - -Launch ./ffmpeg -v 0 -y -f image2 -flags +bitexact -fflags +bitexact -i tests/vsynth1/%02d.pgm -flags +bitexact -fflags +bitexact - -ACL allow localhost - - -################################################################## -# Now you can define each stream which will be generated from the -# original audio and video stream. Each format has a filename (here -# 'test128.mpg'). FFServer will send this stream when answering a -# request containing this filename. - - -Feed feed1.ffm -Format avi -# -BitExact -DctFastint -IdctSimple -VideoFrameRate 10 -VideoSize 352x288 -VideoBitRate 100 -VideoGopSize 30 -NoAudio - -PreRoll 10 -StartSendOnKey -MaxTime 100 - - - - -Feed feed1.ffm -Format avi -# -BitExact -DctFastint -IdctSimple -VideoFrameRate 2 -VideoSize 320x240 -VideoBitRate 40 -VideoGopSize 20 -NoAudio - -PreRoll 20 -StartSendOnKey -MaxTime 100 - - - -# -#Feed feed1.ffm -# -#VideoFrameRate 10 -#VideoSize 352x288 -#VideoBitRate 100 -#VideoGopSize 30 -#NoAudio - -#PreRoll 10 -#StartSendOnKey -#MaxTime 100 -# -# -# -# -#Feed feed1.ffm -## -#VideoFrameRate 2 -#VideoSize 320x240 -#VideoBitRate 40 -#VideoGopSize 20 -#NoAudio -# -#PreRoll 20 -#StartSendOnKey -#MaxTime 100 -# -# -# - -Feed feed1.ffm -# -BitExact -DctFastint -IdctSimple -Qscale 10 -VideoFrameRate 10 -VideoSize 352x288 -VideoBitRate 100 -VideoGopSize 30 -NoAudio - -PreRoll 10 -StartSendOnKey -MaxTime 100 - - - - -Feed feed1.ffm -Format asf -# -BitExact -DctFastint -IdctSimple -Qscale 10 -VideoFrameRate 10 -VideoSize 320x240 -VideoBitRate 100 -VideoGopSize 30 -NoAudio - -PreRoll 10 -StartSendOnKey -MaxTime 100 - -AVOptionVideo flags +global_header - -Metadata title "Test data stream" - - - - -Feed feed1.ffm -Format asf -# -BitExact -DctFastint -IdctSimple -Qscale 10 -VideoFrameRate 2 -VideoSize 320x240 -VideoBitRate 40 -VideoGopSize 20 -NoAudio - -PreRoll 20 -StartSendOnKey -MaxTime 100 - -AVOptionVideo flags +global_header - -Metadata title "Test data stream" - - - - - -Feed feed1.ffm -Format rm - -BitExact -DctFastint -IdctSimple -Qscale 10 -VideoBitRate 100 -VideoFrameRate 10 -VideoGopSize 30 -VideoSize 320x240 -NoAudio - -PreRoll 10 -StartSendOnKey -MaxTime 100 - - - - - -Feed feed1.ffm -Format rm - -BitExact -DctFastint -IdctSimple -Qscale 10 -VideoBitRate 40 -VideoFrameRate 2 -VideoGopSize 20 -VideoSize 320x240 -NoAudio - -PreRoll 20 -StartSendOnKey -MaxTime 100 - - - - - - -Feed feed1.ffm -Format jpeg -Strict -1 - -BitExact -DctFastint -IdctSimple -VideoFrameRate 1 -VideoSize 352x288 -NoAudio - -PreRoll 2 - - - - - -Feed feed1.ffm -Format jpeg -Strict -1 - -BitExact -DctFastint -IdctSimple -VideoFrameRate 1 -VideoSize 160x128 -NoAudio - -PreRoll 2 - - - - - -Feed feed1.ffm -Format mpjpeg -Strict -1 - -BitExact -DctFastint -IdctSimple -VideoFrameRate 1 -VideoSize 320x240 -NoAudio -StartSendOnKey - -PreRoll 1 -MaxTime 100 - - - - -################################################################## -# Special stream : server status - - - -Format status - - - diff --git a/tests/ffserver.regression.ref b/tests/ffserver.regression.ref deleted file mode 100644 index 398c28515603e..0000000000000 --- a/tests/ffserver.regression.ref +++ /dev/null @@ -1,11 +0,0 @@ -0c9639f09decbc54c9f091dcf1ca0e8f *ff-test_h.avi -e28ba75853caf975e06d92955c9f7f73 *ff-test_l.avi -a767dbdf5d1bded3450279f812f97b37 *ff-test.swf -dc16f607e13328a832e73801cd21ec98 *ff-test_h.asf -69337d6c8cd7ac7e626338decdbf41d3 *ff-test_l.asf -06f5a6a4c5d1c6735f4d0068e825c91f *ff-test_h.rm -1f57580f02f0317407b3b82a3d5e093f *ff-test_l.rm -4c887dfc1dd0f6ea1a3a2be6dd32e495 *ff-test.jpg -1d04b73b04aad27793cc762d5afabac1 *ff-test_small.jpg -bc36c40ee34ebee6ffe50f3094aab733 *ff-test.mjpg -fd038af80560e15271ce42651093ee43 *ff-stat diff --git a/tests/ref/fate/adts-id3v2-demux b/tests/ref/fate/adts-id3v2-demux new file mode 100644 index 0000000000000..db00e3b81eb9b --- /dev/null +++ b/tests/ref/fate/adts-id3v2-demux @@ -0,0 +1,240 @@ +#tb 0: 1/28224000 +#media_type 0: audio +#codec_id 0: aac +#sample_rate 0: 48000 +#channel_layout 0: 4 +#channel_layout_name 0: mono +0, 0, 0, 602112, 126, 0x639a3a5b +0, 602112, 602112, 602112, 135, 0x5b1f3ced +0, 1204224, 1204224, 602112, 123, 0xfcb73863 +0, 1806336, 1806336, 602112, 126, 0x639a3a5b +0, 2408448, 2408448, 602112, 135, 0x5b1f3ced +0, 3010560, 3010560, 602112, 123, 0xfcb73863 +0, 3612672, 3612672, 602112, 144, 0xa0434540 +0, 4214784, 4214784, 602112, 119, 0x45053cc1 +0, 4816896, 4816896, 602112, 111, 0x23043aaf +0, 5419008, 5419008, 602112, 126, 0x693a3a67 +0, 6021120, 6021120, 602112, 149, 0x31304a34 +0, 6623232, 6623232, 602112, 111, 0x21603aab +0, 7225344, 7225344, 602112, 132, 0xe42d43b3 +0, 7827456, 7827456, 602112, 135, 0x5b1f3ced +0, 8429568, 8429568, 602112, 123, 0xfe8b3867 +0, 9031680, 9031680, 602112, 144, 0xa26b4544 +0, 9633792, 9633792, 602112, 129, 0xf7de3bc7 +0, 10235904, 10235904, 602112, 111, 0x1fbc3aa7 +0, 10838016, 10838016, 602112, 126, 0x657a3a5f +0, 11440128, 11440128, 602112, 140, 0xdb6542ec +0, 12042240, 12042240, 602112, 123, 0xfcb73863 +0, 12644352, 12644352, 602112, 138, 0xad7e44b6 +0, 13246464, 13246464, 602112, 119, 0x46c93cc5 +0, 13848576, 13848576, 602112, 123, 0xfe8b3867 +0, 14450688, 14450688, 602112, 144, 0xa26b4544 +0, 15052800, 15052800, 602112, 129, 0xf7de3bc7 +0, 15654912, 15654912, 602112, 111, 0x1fbc3aa7 +0, 16257024, 16257024, 602112, 126, 0x657a3a5f +0, 16859136, 16859136, 602112, 140, 0xdb6542ec +0, 17461248, 17461248, 602112, 123, 0xfcb73863 +0, 18063360, 18063360, 602112, 138, 0xad7e44b6 +0, 18665472, 18665472, 602112, 119, 0x46c93cc5 +0, 19267584, 19267584, 602112, 123, 0xfe8b3867 +0, 19869696, 19869696, 602112, 144, 0xa26b4544 +0, 20471808, 20471808, 602112, 129, 0xf7de3bc7 +0, 21073920, 21073920, 602112, 111, 0x1fbc3aa7 +0, 21676032, 21676032, 602112, 126, 0x657a3a5f +0, 22278144, 22278144, 602112, 140, 0xdb6542ec +0, 22880256, 22880256, 602112, 123, 0xfcb73863 +0, 23482368, 23482368, 602112, 138, 0xad7e44b6 +0, 24084480, 24084480, 602112, 119, 0x488d3cc9 +0, 24686592, 24686592, 602112, 123, 0xfe8b3867 +0, 25288704, 25288704, 602112, 144, 0xa26b4544 +0, 25890816, 25890816, 602112, 129, 0xf7de3bc7 +0, 26492928, 26492928, 602112, 111, 0x1fbc3aa7 +0, 27095040, 27095040, 602112, 126, 0x657a3a5f +0, 27697152, 27697152, 602112, 140, 0xdb6542ec +0, 28299264, 28299264, 602112, 123, 0xfcb73863 +0, 28901376, 28901376, 602112, 126, 0x639a3a5b +0, 29503488, 29503488, 602112, 135, 0x5b1f3ced +0, 30105600, 30105600, 602112, 123, 0xfcb73863 +0, 30707712, 30707712, 602112, 126, 0x639a3a5b +0, 31309824, 31309824, 602112, 135, 0x5b1f3ced +0, 31911936, 31911936, 602112, 123, 0xfcb73863 +0, 32514048, 32514048, 602112, 144, 0xa0434540 +0, 33116160, 33116160, 602112, 119, 0x45053cc1 +0, 33718272, 33718272, 602112, 111, 0x23043aaf +0, 34320384, 34320384, 602112, 126, 0x693a3a67 +0, 34922496, 34922496, 602112, 149, 0x31304a34 +0, 35524608, 35524608, 602112, 111, 0x21603aab +0, 36126720, 36126720, 602112, 132, 0xe42d43b3 +0, 36728832, 36728832, 602112, 135, 0x5b1f3ced +0, 37330944, 37330944, 602112, 123, 0xfe8b3867 +0, 37933056, 37933056, 602112, 144, 0xa26b4544 +0, 38535168, 38535168, 602112, 129, 0xf7de3bc7 +0, 39137280, 39137280, 602112, 111, 0x1fbc3aa7 +0, 39739392, 39739392, 602112, 126, 0x657a3a5f +0, 40341504, 40341504, 602112, 140, 0xdb6542ec +0, 40943616, 40943616, 602112, 123, 0xfcb73863 +0, 41545728, 41545728, 602112, 138, 0xad7e44b6 +0, 42147840, 42147840, 602112, 119, 0x46c93cc5 +0, 42749952, 42749952, 602112, 123, 0xfe8b3867 +0, 43352064, 43352064, 602112, 144, 0xa26b4544 +0, 43954176, 43954176, 602112, 129, 0xf7de3bc7 +0, 44556288, 44556288, 602112, 111, 0x1fbc3aa7 +0, 45158400, 45158400, 602112, 126, 0x657a3a5f +0, 45760512, 45760512, 602112, 140, 0xdb6542ec +0, 46362624, 46362624, 602112, 123, 0xfcb73863 +0, 46964736, 46964736, 602112, 138, 0xad7e44b6 +0, 47566848, 47566848, 602112, 119, 0x46c93cc5 +0, 48168960, 48168960, 602112, 123, 0xfe8b3867 +0, 48771072, 48771072, 602112, 144, 0xa26b4544 +0, 49373184, 49373184, 602112, 129, 0xf7de3bc7 +0, 49975296, 49975296, 602112, 111, 0x1fbc3aa7 +0, 50577408, 50577408, 602112, 126, 0x657a3a5f +0, 51179520, 51179520, 602112, 140, 0xdb6542ec +0, 51781632, 51781632, 602112, 123, 0xfcb73863 +0, 52383744, 52383744, 602112, 138, 0xad7e44b6 +0, 52985856, 52985856, 602112, 119, 0x488d3cc9 +0, 53587968, 53587968, 602112, 123, 0xfe8b3867 +0, 54190080, 54190080, 602112, 144, 0xa26b4544 +0, 54792192, 54792192, 602112, 129, 0xf7de3bc7 +0, 55394304, 55394304, 602112, 111, 0x1fbc3aa7 +0, 55996416, 55996416, 602112, 126, 0x657a3a5f +0, 56598528, 56598528, 602112, 140, 0xdb6542ec +0, 57200640, 57200640, 602112, 123, 0xfcb73863 +0, 57802752, 57802752, 602112, 126, 0x639a3a5b +0, 58404864, 58404864, 602112, 135, 0x5b1f3ced +0, 59006976, 59006976, 602112, 123, 0xfcb73863 +0, 59609088, 59609088, 602112, 126, 0x639a3a5b +0, 60211200, 60211200, 602112, 135, 0x5b1f3ced +0, 60813312, 60813312, 602112, 123, 0xfcb73863 +0, 61415424, 61415424, 602112, 144, 0xa0434540 +0, 62017536, 62017536, 602112, 119, 0x45053cc1 +0, 62619648, 62619648, 602112, 111, 0x23043aaf +0, 63221760, 63221760, 602112, 126, 0x693a3a67 +0, 63823872, 63823872, 602112, 149, 0x31304a34 +0, 64425984, 64425984, 602112, 111, 0x21603aab +0, 65028096, 65028096, 602112, 132, 0xe42d43b3 +0, 65630208, 65630208, 602112, 135, 0x5b1f3ced +0, 66232320, 66232320, 602112, 123, 0xfe8b3867 +0, 66834432, 66834432, 602112, 144, 0xa26b4544 +0, 67436544, 67436544, 602112, 129, 0xf7de3bc7 +0, 68038656, 68038656, 602112, 111, 0x1fbc3aa7 +0, 68640768, 68640768, 602112, 126, 0x657a3a5f +0, 69242880, 69242880, 602112, 140, 0xdb6542ec +0, 69844992, 69844992, 602112, 123, 0xfcb73863 +0, 70447104, 70447104, 602112, 138, 0xad7e44b6 +0, 71049216, 71049216, 602112, 119, 0x46c93cc5 +0, 71651328, 71651328, 602112, 123, 0xfe8b3867 +0, 72253440, 72253440, 602112, 144, 0xa26b4544 +0, 72855552, 72855552, 602112, 129, 0xf7de3bc7 +0, 73457664, 73457664, 602112, 111, 0x1fbc3aa7 +0, 74059776, 74059776, 602112, 126, 0x657a3a5f +0, 74661888, 74661888, 602112, 140, 0xdb6542ec +0, 75264000, 75264000, 602112, 123, 0xfcb73863 +0, 75866112, 75866112, 602112, 138, 0xad7e44b6 +0, 76468224, 76468224, 602112, 119, 0x46c93cc5 +0, 77070336, 77070336, 602112, 123, 0xfe8b3867 +0, 77672448, 77672448, 602112, 144, 0xa26b4544 +0, 78274560, 78274560, 602112, 129, 0xf7de3bc7 +0, 78876672, 78876672, 602112, 111, 0x1fbc3aa7 +0, 79478784, 79478784, 602112, 126, 0x657a3a5f +0, 80080896, 80080896, 602112, 140, 0xdb6542ec +0, 80683008, 80683008, 602112, 123, 0xfcb73863 +0, 81285120, 81285120, 602112, 138, 0xad7e44b6 +0, 81887232, 81887232, 602112, 119, 0x488d3cc9 +0, 82489344, 82489344, 602112, 123, 0xfe8b3867 +0, 83091456, 83091456, 602112, 144, 0xa26b4544 +0, 83693568, 83693568, 602112, 129, 0xf7de3bc7 +0, 84295680, 84295680, 602112, 111, 0x1fbc3aa7 +0, 84897792, 84897792, 602112, 126, 0x657a3a5f +0, 85499904, 85499904, 602112, 140, 0xdb6542ec +0, 86102016, 86102016, 602112, 123, 0xfcb73863 +0, 86704128, 86704128, 602112, 126, 0x639a3a5b +0, 87306240, 87306240, 602112, 135, 0x5b1f3ced +0, 87908352, 87908352, 602112, 123, 0xfcb73863 +0, 88510464, 88510464, 602112, 126, 0x639a3a5b +0, 89112576, 89112576, 602112, 135, 0x5b1f3ced +0, 89714688, 89714688, 602112, 123, 0xfcb73863 +0, 90316800, 90316800, 602112, 144, 0xa0434540 +0, 90918912, 90918912, 602112, 119, 0x45053cc1 +0, 91521024, 91521024, 602112, 111, 0x23043aaf +0, 92123136, 92123136, 602112, 126, 0x693a3a67 +0, 92725248, 92725248, 602112, 149, 0x31304a34 +0, 93327360, 93327360, 602112, 111, 0x21603aab +0, 93929472, 93929472, 602112, 132, 0xe42d43b3 +0, 94531584, 94531584, 602112, 135, 0x5b1f3ced +0, 95133696, 95133696, 602112, 123, 0xfe8b3867 +0, 95735808, 95735808, 602112, 144, 0xa26b4544 +0, 96337920, 96337920, 602112, 129, 0xf7de3bc7 +0, 96940032, 96940032, 602112, 111, 0x1fbc3aa7 +0, 97542144, 97542144, 602112, 126, 0x657a3a5f +0, 98144256, 98144256, 602112, 140, 0xdb6542ec +0, 98746368, 98746368, 602112, 123, 0xfcb73863 +0, 99348480, 99348480, 602112, 138, 0xad7e44b6 +0, 99950592, 99950592, 602112, 119, 0x46c93cc5 +0, 100552704, 100552704, 602112, 123, 0xfe8b3867 +0, 101154816, 101154816, 602112, 144, 0xa26b4544 +0, 101756928, 101756928, 602112, 129, 0xf7de3bc7 +0, 102359040, 102359040, 602112, 111, 0x1fbc3aa7 +0, 102961152, 102961152, 602112, 126, 0x657a3a5f +0, 103563264, 103563264, 602112, 140, 0xdb6542ec +0, 104165376, 104165376, 602112, 123, 0xfcb73863 +0, 104767488, 104767488, 602112, 138, 0xad7e44b6 +0, 105369600, 105369600, 602112, 119, 0x46c93cc5 +0, 105971712, 105971712, 602112, 123, 0xfe8b3867 +0, 106573824, 106573824, 602112, 144, 0xa26b4544 +0, 107175936, 107175936, 602112, 129, 0xf7de3bc7 +0, 107778048, 107778048, 602112, 111, 0x1fbc3aa7 +0, 108380160, 108380160, 602112, 126, 0x657a3a5f +0, 108982272, 108982272, 602112, 140, 0xdb6542ec +0, 109584384, 109584384, 602112, 123, 0xfcb73863 +0, 110186496, 110186496, 602112, 138, 0xad7e44b6 +0, 110788608, 110788608, 602112, 119, 0x488d3cc9 +0, 111390720, 111390720, 602112, 123, 0xfe8b3867 +0, 111992832, 111992832, 602112, 144, 0xa26b4544 +0, 112594944, 112594944, 602112, 129, 0xf7de3bc7 +0, 113197056, 113197056, 602112, 111, 0x1fbc3aa7 +0, 113799168, 113799168, 602112, 126, 0x657a3a5f +0, 114401280, 114401280, 602112, 140, 0xdb6542ec +0, 115003392, 115003392, 602112, 123, 0xfcb73863 +0, 115605504, 115605504, 602112, 126, 0x639a3a5b +0, 116207616, 116207616, 602112, 135, 0x5b1f3ced +0, 116809728, 116809728, 602112, 123, 0xfcb73863 +0, 117411840, 117411840, 602112, 126, 0x639a3a5b +0, 118013952, 118013952, 602112, 135, 0x5b1f3ced +0, 118616064, 118616064, 602112, 123, 0xfcb73863 +0, 119218176, 119218176, 602112, 144, 0xa0434540 +0, 119820288, 119820288, 602112, 119, 0x45053cc1 +0, 120422400, 120422400, 602112, 111, 0x23043aaf +0, 121024512, 121024512, 602112, 126, 0x693a3a67 +0, 121626624, 121626624, 602112, 149, 0x31304a34 +0, 122228736, 122228736, 602112, 111, 0x21603aab +0, 122830848, 122830848, 602112, 132, 0xe42d43b3 +0, 123432960, 123432960, 602112, 135, 0x5b1f3ced +0, 124035072, 124035072, 602112, 123, 0xfe8b3867 +0, 124637184, 124637184, 602112, 144, 0xa26b4544 +0, 125239296, 125239296, 602112, 129, 0xf7de3bc7 +0, 125841408, 125841408, 602112, 111, 0x1fbc3aa7 +0, 126443520, 126443520, 602112, 126, 0x657a3a5f +0, 127045632, 127045632, 602112, 140, 0xdb6542ec +0, 127647744, 127647744, 602112, 123, 0xfcb73863 +0, 128249856, 128249856, 602112, 138, 0xad7e44b6 +0, 128851968, 128851968, 602112, 119, 0x46c93cc5 +0, 129454080, 129454080, 602112, 123, 0xfe8b3867 +0, 130056192, 130056192, 602112, 144, 0xa26b4544 +0, 130658304, 130658304, 602112, 129, 0xf7de3bc7 +0, 131260416, 131260416, 602112, 111, 0x1fbc3aa7 +0, 131862528, 131862528, 602112, 126, 0x657a3a5f +0, 132464640, 132464640, 602112, 140, 0xdb6542ec +0, 133066752, 133066752, 602112, 123, 0xfcb73863 +0, 133668864, 133668864, 602112, 138, 0xad7e44b6 +0, 134270976, 134270976, 602112, 119, 0x46c93cc5 +0, 134873088, 134873088, 602112, 123, 0xfe8b3867 +0, 135475200, 135475200, 602112, 144, 0xa26b4544 +0, 136077312, 136077312, 602112, 129, 0xf7de3bc7 +0, 136679424, 136679424, 602112, 111, 0x1fbc3aa7 +0, 137281536, 137281536, 602112, 126, 0x657a3a5f +0, 137883648, 137883648, 602112, 140, 0xdb6542ec +0, 138485760, 138485760, 602112, 123, 0xfcb73863 +0, 139087872, 139087872, 602112, 138, 0xad7e44b6 +0, 139689984, 139689984, 602112, 119, 0x488d3cc9 +0, 140292096, 140292096, 602112, 123, 0xfe8b3867 diff --git a/tests/ref/fate/adts-id3v2-two-tags-demux b/tests/ref/fate/adts-id3v2-two-tags-demux new file mode 100644 index 0000000000000..4fffd2e7675c9 --- /dev/null +++ b/tests/ref/fate/adts-id3v2-two-tags-demux @@ -0,0 +1,475 @@ +#tb 0: 1/28224000 +#media_type 0: audio +#codec_id 0: aac +#sample_rate 0: 48000 +#channel_layout 0: 4 +#channel_layout_name 0: mono +0, 0, 0, 602112, 128, 0x23291993 +0, 602112, 602112, 602112, 128, 0x23291993 +0, 1204224, 1204224, 602112, 128, 0x23291993 +0, 1806336, 1806336, 602112, 128, 0x23291993 +0, 2408448, 2408448, 602112, 128, 0x23291993 +0, 3010560, 3010560, 602112, 128, 0x23291993 +0, 3612672, 3612672, 602112, 128, 0x23291993 +0, 4214784, 4214784, 602112, 128, 0x23291993 +0, 4816896, 4816896, 602112, 128, 0x23291993 +0, 5419008, 5419008, 602112, 128, 0x23291993 +0, 6021120, 6021120, 602112, 128, 0x23291993 +0, 6623232, 6623232, 602112, 128, 0x23291993 +0, 7225344, 7225344, 602112, 128, 0x23291993 +0, 7827456, 7827456, 602112, 128, 0x23291993 +0, 8429568, 8429568, 602112, 128, 0x23291993 +0, 9031680, 9031680, 602112, 128, 0x23291993 +0, 9633792, 9633792, 602112, 128, 0x23291993 +0, 10235904, 10235904, 602112, 128, 0x23291993 +0, 10838016, 10838016, 602112, 128, 0x23291993 +0, 11440128, 11440128, 602112, 128, 0x23291993 +0, 12042240, 12042240, 602112, 128, 0x23291993 +0, 12644352, 12644352, 602112, 128, 0x23291993 +0, 13246464, 13246464, 602112, 128, 0x23291993 +0, 13848576, 13848576, 602112, 128, 0x23291993 +0, 14450688, 14450688, 602112, 128, 0x23291993 +0, 15052800, 15052800, 602112, 128, 0x23291993 +0, 15654912, 15654912, 602112, 128, 0x23291993 +0, 16257024, 16257024, 602112, 128, 0x23291993 +0, 16859136, 16859136, 602112, 128, 0x23291993 +0, 17461248, 17461248, 602112, 128, 0x23291993 +0, 18063360, 18063360, 602112, 128, 0x23291993 +0, 18665472, 18665472, 602112, 128, 0x23291993 +0, 19267584, 19267584, 602112, 128, 0x23291993 +0, 19869696, 19869696, 602112, 128, 0x23291993 +0, 20471808, 20471808, 602112, 128, 0x23291993 +0, 21073920, 21073920, 602112, 128, 0x23291993 +0, 21676032, 21676032, 602112, 128, 0x23291993 +0, 22278144, 22278144, 602112, 128, 0x23291993 +0, 22880256, 22880256, 602112, 128, 0x23291993 +0, 23482368, 23482368, 602112, 128, 0x23291993 +0, 24084480, 24084480, 602112, 128, 0x23291993 +0, 24686592, 24686592, 602112, 128, 0x23291993 +0, 25288704, 25288704, 602112, 128, 0x23291993 +0, 25890816, 25890816, 602112, 128, 0x23291993 +0, 26492928, 26492928, 602112, 128, 0x23291993 +0, 27095040, 27095040, 602112, 128, 0x23291993 +0, 27697152, 27697152, 602112, 128, 0x23291993 +0, 28299264, 28299264, 602112, 128, 0x23291993 +0, 28901376, 28901376, 602112, 128, 0x23291993 +0, 29503488, 29503488, 602112, 128, 0x23291993 +0, 30105600, 30105600, 602112, 128, 0x23291993 +0, 30707712, 30707712, 602112, 128, 0x23291993 +0, 31309824, 31309824, 602112, 128, 0x23291993 +0, 31911936, 31911936, 602112, 128, 0x23291993 +0, 32514048, 32514048, 602112, 128, 0x23291993 +0, 33116160, 33116160, 602112, 128, 0x23291993 +0, 33718272, 33718272, 602112, 128, 0x23291993 +0, 34320384, 34320384, 602112, 128, 0x23291993 +0, 34922496, 34922496, 602112, 128, 0x23291993 +0, 35524608, 35524608, 602112, 128, 0x23291993 +0, 36126720, 36126720, 602112, 128, 0x23291993 +0, 36728832, 36728832, 602112, 128, 0x23291993 +0, 37330944, 37330944, 602112, 128, 0x23291993 +0, 37933056, 37933056, 602112, 128, 0x23291993 +0, 38535168, 38535168, 602112, 128, 0x23291993 +0, 39137280, 39137280, 602112, 128, 0x23291993 +0, 39739392, 39739392, 602112, 128, 0x23291993 +0, 40341504, 40341504, 602112, 128, 0x23291993 +0, 40943616, 40943616, 602112, 128, 0x23291993 +0, 41545728, 41545728, 602112, 128, 0x23291993 +0, 42147840, 42147840, 602112, 128, 0x23291993 +0, 42749952, 42749952, 602112, 128, 0x23291993 +0, 43352064, 43352064, 602112, 128, 0x23291993 +0, 43954176, 43954176, 602112, 128, 0x23291993 +0, 44556288, 44556288, 602112, 128, 0x23291993 +0, 45158400, 45158400, 602112, 128, 0x23291993 +0, 45760512, 45760512, 602112, 128, 0x23291993 +0, 46362624, 46362624, 602112, 128, 0x23291993 +0, 46964736, 46964736, 602112, 128, 0x23291993 +0, 47566848, 47566848, 602112, 128, 0x23291993 +0, 48168960, 48168960, 602112, 128, 0x23291993 +0, 48771072, 48771072, 602112, 128, 0x23291993 +0, 49373184, 49373184, 602112, 128, 0x23291993 +0, 49975296, 49975296, 602112, 128, 0x23291993 +0, 50577408, 50577408, 602112, 128, 0x23291993 +0, 51179520, 51179520, 602112, 128, 0x23291993 +0, 51781632, 51781632, 602112, 128, 0x23291993 +0, 52383744, 52383744, 602112, 128, 0x23291993 +0, 52985856, 52985856, 602112, 128, 0x23291993 +0, 53587968, 53587968, 602112, 128, 0x23291993 +0, 54190080, 54190080, 602112, 128, 0x23291993 +0, 54792192, 54792192, 602112, 128, 0x23291993 +0, 55394304, 55394304, 602112, 128, 0x23291993 +0, 55996416, 55996416, 602112, 128, 0x23291993 +0, 56598528, 56598528, 602112, 128, 0x23291993 +0, 57200640, 57200640, 602112, 128, 0x23291993 +0, 57802752, 57802752, 602112, 128, 0x23291993 +0, 58404864, 58404864, 602112, 128, 0x23291993 +0, 59006976, 59006976, 602112, 128, 0x23291993 +0, 59609088, 59609088, 602112, 128, 0x23291993 +0, 60211200, 60211200, 602112, 128, 0x23291993 +0, 60813312, 60813312, 602112, 128, 0x23291993 +0, 61415424, 61415424, 602112, 128, 0x23291993 +0, 62017536, 62017536, 602112, 128, 0x23291993 +0, 62619648, 62619648, 602112, 128, 0x23291993 +0, 63221760, 63221760, 602112, 128, 0x23291993 +0, 63823872, 63823872, 602112, 128, 0x23291993 +0, 64425984, 64425984, 602112, 128, 0x23291993 +0, 65028096, 65028096, 602112, 128, 0x23291993 +0, 65630208, 65630208, 602112, 128, 0x23291993 +0, 66232320, 66232320, 602112, 128, 0x23291993 +0, 66834432, 66834432, 602112, 128, 0x23291993 +0, 67436544, 67436544, 602112, 128, 0x23291993 +0, 68038656, 68038656, 602112, 128, 0x23291993 +0, 68640768, 68640768, 602112, 128, 0x23291993 +0, 69242880, 69242880, 602112, 128, 0x23291993 +0, 69844992, 69844992, 602112, 128, 0x23291993 +0, 70447104, 70447104, 602112, 128, 0x23291993 +0, 71049216, 71049216, 602112, 128, 0x23291993 +0, 71651328, 71651328, 602112, 128, 0x23291993 +0, 72253440, 72253440, 602112, 128, 0x23291993 +0, 72855552, 72855552, 602112, 128, 0x23291993 +0, 73457664, 73457664, 602112, 128, 0x23291993 +0, 74059776, 74059776, 602112, 128, 0x23291993 +0, 74661888, 74661888, 602112, 128, 0x23291993 +0, 75264000, 75264000, 602112, 128, 0x23291993 +0, 75866112, 75866112, 602112, 128, 0x23291993 +0, 76468224, 76468224, 602112, 128, 0x23291993 +0, 77070336, 77070336, 602112, 128, 0x23291993 +0, 77672448, 77672448, 602112, 128, 0x23291993 +0, 78274560, 78274560, 602112, 128, 0x23291993 +0, 78876672, 78876672, 602112, 128, 0x23291993 +0, 79478784, 79478784, 602112, 128, 0x23291993 +0, 80080896, 80080896, 602112, 128, 0x23291993 +0, 80683008, 80683008, 602112, 128, 0x23291993 +0, 81285120, 81285120, 602112, 128, 0x23291993 +0, 81887232, 81887232, 602112, 128, 0x23291993 +0, 82489344, 82489344, 602112, 128, 0x23291993 +0, 83091456, 83091456, 602112, 128, 0x23291993 +0, 83693568, 83693568, 602112, 128, 0x23291993 +0, 84295680, 84295680, 602112, 128, 0x23291993 +0, 84897792, 84897792, 602112, 128, 0x23291993 +0, 85499904, 85499904, 602112, 128, 0x23291993 +0, 86102016, 86102016, 602112, 128, 0x23291993 +0, 86704128, 86704128, 602112, 128, 0x23291993 +0, 87306240, 87306240, 602112, 128, 0x23291993 +0, 87908352, 87908352, 602112, 128, 0x23291993 +0, 88510464, 88510464, 602112, 128, 0x23291993 +0, 89112576, 89112576, 602112, 128, 0x23291993 +0, 89714688, 89714688, 602112, 128, 0x23291993 +0, 90316800, 90316800, 602112, 128, 0x23291993 +0, 90918912, 90918912, 602112, 128, 0x23291993 +0, 91521024, 91521024, 602112, 128, 0x23291993 +0, 92123136, 92123136, 602112, 128, 0x23291993 +0, 92725248, 92725248, 602112, 128, 0x23291993 +0, 93327360, 93327360, 602112, 128, 0x23291993 +0, 93929472, 93929472, 602112, 128, 0x23291993 +0, 94531584, 94531584, 602112, 128, 0x23291993 +0, 95133696, 95133696, 602112, 128, 0x23291993 +0, 95735808, 95735808, 602112, 128, 0x23291993 +0, 96337920, 96337920, 602112, 128, 0x23291993 +0, 96940032, 96940032, 602112, 128, 0x23291993 +0, 97542144, 97542144, 602112, 128, 0x23291993 +0, 98144256, 98144256, 602112, 128, 0x23291993 +0, 98746368, 98746368, 602112, 128, 0x23291993 +0, 99348480, 99348480, 602112, 128, 0x23291993 +0, 99950592, 99950592, 602112, 128, 0x23291993 +0, 100552704, 100552704, 602112, 128, 0x23291993 +0, 101154816, 101154816, 602112, 128, 0x23291993 +0, 101756928, 101756928, 602112, 128, 0x23291993 +0, 102359040, 102359040, 602112, 128, 0x23291993 +0, 102961152, 102961152, 602112, 128, 0x23291993 +0, 103563264, 103563264, 602112, 128, 0x23291993 +0, 104165376, 104165376, 602112, 128, 0x23291993 +0, 104767488, 104767488, 602112, 128, 0x23291993 +0, 105369600, 105369600, 602112, 128, 0x23291993 +0, 105971712, 105971712, 602112, 128, 0x23291993 +0, 106573824, 106573824, 602112, 128, 0x23291993 +0, 107175936, 107175936, 602112, 128, 0x23291993 +0, 107778048, 107778048, 602112, 128, 0x23291993 +0, 108380160, 108380160, 602112, 128, 0x23291993 +0, 108982272, 108982272, 602112, 128, 0x23291993 +0, 109584384, 109584384, 602112, 128, 0x23291993 +0, 110186496, 110186496, 602112, 128, 0x23291993 +0, 110788608, 110788608, 602112, 128, 0x23291993 +0, 111390720, 111390720, 602112, 128, 0x23291993 +0, 111992832, 111992832, 602112, 128, 0x23291993 +0, 112594944, 112594944, 602112, 128, 0x23291993 +0, 113197056, 113197056, 602112, 128, 0x23291993 +0, 113799168, 113799168, 602112, 128, 0x23291993 +0, 114401280, 114401280, 602112, 128, 0x23291993 +0, 115003392, 115003392, 602112, 128, 0x23291993 +0, 115605504, 115605504, 602112, 128, 0x23291993 +0, 116207616, 116207616, 602112, 128, 0x23291993 +0, 116809728, 116809728, 602112, 128, 0x23291993 +0, 117411840, 117411840, 602112, 128, 0x23291993 +0, 118013952, 118013952, 602112, 128, 0x23291993 +0, 118616064, 118616064, 602112, 128, 0x23291993 +0, 119218176, 119218176, 602112, 128, 0x23291993 +0, 119820288, 119820288, 602112, 128, 0x23291993 +0, 120422400, 120422400, 602112, 128, 0x23291993 +0, 121024512, 121024512, 602112, 128, 0x23291993 +0, 121626624, 121626624, 602112, 128, 0x23291993 +0, 122228736, 122228736, 602112, 128, 0x23291993 +0, 122830848, 122830848, 602112, 128, 0x23291993 +0, 123432960, 123432960, 602112, 128, 0x23291993 +0, 124035072, 124035072, 602112, 128, 0x23291993 +0, 124637184, 124637184, 602112, 128, 0x23291993 +0, 125239296, 125239296, 602112, 128, 0x23291993 +0, 125841408, 125841408, 602112, 128, 0x23291993 +0, 126443520, 126443520, 602112, 128, 0x23291993 +0, 127045632, 127045632, 602112, 128, 0x23291993 +0, 127647744, 127647744, 602112, 128, 0x23291993 +0, 128249856, 128249856, 602112, 128, 0x23291993 +0, 128851968, 128851968, 602112, 128, 0x23291993 +0, 129454080, 129454080, 602112, 128, 0x23291993 +0, 130056192, 130056192, 602112, 128, 0x23291993 +0, 130658304, 130658304, 602112, 128, 0x23291993 +0, 131260416, 131260416, 602112, 128, 0x23291993 +0, 131862528, 131862528, 602112, 128, 0x23291993 +0, 132464640, 132464640, 602112, 128, 0x23291993 +0, 133066752, 133066752, 602112, 128, 0x23291993 +0, 133668864, 133668864, 602112, 128, 0x23291993 +0, 134270976, 134270976, 602112, 128, 0x23291993 +0, 134873088, 134873088, 602112, 128, 0x23291993 +0, 135475200, 135475200, 602112, 128, 0x23291993 +0, 136077312, 136077312, 602112, 128, 0x23291993 +0, 136679424, 136679424, 602112, 128, 0x23291993 +0, 137281536, 137281536, 602112, 128, 0x23291993 +0, 137883648, 137883648, 602112, 128, 0x23291993 +0, 138485760, 138485760, 602112, 128, 0x23291993 +0, 139087872, 139087872, 602112, 128, 0x23291993 +0, 139689984, 139689984, 602112, 128, 0x23291993 +0, 140292096, 140292096, 602112, 128, 0x23291993 +0, 140894208, 140894208, 602112, 128, 0x23291993 +0, 141496320, 141496320, 602112, 128, 0x23291993 +0, 142098432, 142098432, 602112, 128, 0x23291993 +0, 142700544, 142700544, 602112, 128, 0x23291993 +0, 143302656, 143302656, 602112, 128, 0x23291993 +0, 143904768, 143904768, 602112, 128, 0x23291993 +0, 144506880, 144506880, 602112, 128, 0x23291993 +0, 145108992, 145108992, 602112, 128, 0x23291993 +0, 145711104, 145711104, 602112, 128, 0x23291993 +0, 146313216, 146313216, 602112, 128, 0x23291993 +0, 146915328, 146915328, 602112, 128, 0x23291993 +0, 147517440, 147517440, 602112, 128, 0x23291993 +0, 148119552, 148119552, 602112, 128, 0x23291993 +0, 148721664, 148721664, 602112, 128, 0x23291993 +0, 149323776, 149323776, 602112, 128, 0x23291993 +0, 149925888, 149925888, 602112, 128, 0x23291993 +0, 150528000, 150528000, 602112, 128, 0x23291993 +0, 151130112, 151130112, 602112, 128, 0x23291993 +0, 151732224, 151732224, 602112, 128, 0x23291993 +0, 152334336, 152334336, 602112, 128, 0x23291993 +0, 152936448, 152936448, 602112, 128, 0x23291993 +0, 153538560, 153538560, 602112, 128, 0x23291993 +0, 154140672, 154140672, 602112, 128, 0x23291993 +0, 154742784, 154742784, 602112, 128, 0x23291993 +0, 155344896, 155344896, 602112, 128, 0x23291993 +0, 155947008, 155947008, 602112, 128, 0x23291993 +0, 156549120, 156549120, 602112, 128, 0x23291993 +0, 157151232, 157151232, 602112, 128, 0x23291993 +0, 157753344, 157753344, 602112, 128, 0x23291993 +0, 158355456, 158355456, 602112, 128, 0x23291993 +0, 158957568, 158957568, 602112, 128, 0x23291993 +0, 159559680, 159559680, 602112, 128, 0x23291993 +0, 160161792, 160161792, 602112, 128, 0x23291993 +0, 160763904, 160763904, 602112, 128, 0x23291993 +0, 161366016, 161366016, 602112, 128, 0x23291993 +0, 161968128, 161968128, 602112, 128, 0x23291993 +0, 162570240, 162570240, 602112, 128, 0x23291993 +0, 163172352, 163172352, 602112, 128, 0x23291993 +0, 163774464, 163774464, 602112, 128, 0x23291993 +0, 164376576, 164376576, 602112, 128, 0x23291993 +0, 164978688, 164978688, 602112, 128, 0x23291993 +0, 165580800, 165580800, 602112, 128, 0x23291993 +0, 166182912, 166182912, 602112, 128, 0x23291993 +0, 166785024, 166785024, 602112, 128, 0x23291993 +0, 167387136, 167387136, 602112, 128, 0x23291993 +0, 167989248, 167989248, 602112, 128, 0x23291993 +0, 168591360, 168591360, 602112, 128, 0x23291993 +0, 169193472, 169193472, 602112, 128, 0x23291993 +0, 169795584, 169795584, 602112, 128, 0x23291993 +0, 170397696, 170397696, 602112, 128, 0x23291993 +0, 170999808, 170999808, 602112, 128, 0x23291993 +0, 171601920, 171601920, 602112, 128, 0x23291993 +0, 172204032, 172204032, 602112, 128, 0x23291993 +0, 172806144, 172806144, 602112, 128, 0x23291993 +0, 173408256, 173408256, 602112, 128, 0x23291993 +0, 174010368, 174010368, 602112, 128, 0x23291993 +0, 174612480, 174612480, 602112, 128, 0x23291993 +0, 175214592, 175214592, 602112, 128, 0x23291993 +0, 175816704, 175816704, 602112, 128, 0x23291993 +0, 176418816, 176418816, 602112, 128, 0x23291993 +0, 177020928, 177020928, 602112, 128, 0x23291993 +0, 177623040, 177623040, 602112, 128, 0x23291993 +0, 178225152, 178225152, 602112, 128, 0x23291993 +0, 178827264, 178827264, 602112, 128, 0x23291993 +0, 179429376, 179429376, 602112, 128, 0x23291993 +0, 180031488, 180031488, 602112, 128, 0x23291993 +0, 180633600, 180633600, 602112, 128, 0x23291993 +0, 181235712, 181235712, 602112, 128, 0x23291993 +0, 181837824, 181837824, 602112, 128, 0x23291993 +0, 182439936, 182439936, 602112, 128, 0x23291993 +0, 183042048, 183042048, 602112, 128, 0x23291993 +0, 183644160, 183644160, 602112, 128, 0x23291993 +0, 184246272, 184246272, 602112, 128, 0x23291993 +0, 184848384, 184848384, 602112, 128, 0x23291993 +0, 185450496, 185450496, 602112, 128, 0x23291993 +0, 186052608, 186052608, 602112, 128, 0x23291993 +0, 186654720, 186654720, 602112, 128, 0x23291993 +0, 187256832, 187256832, 602112, 128, 0x23291993 +0, 187858944, 187858944, 602112, 128, 0x23291993 +0, 188461056, 188461056, 602112, 128, 0x23291993 +0, 189063168, 189063168, 602112, 128, 0x23291993 +0, 189665280, 189665280, 602112, 128, 0x23291993 +0, 190267392, 190267392, 602112, 128, 0x23291993 +0, 190869504, 190869504, 602112, 128, 0x23291993 +0, 191471616, 191471616, 602112, 128, 0x23291993 +0, 192073728, 192073728, 602112, 128, 0x23291993 +0, 192675840, 192675840, 602112, 128, 0x23291993 +0, 193277952, 193277952, 602112, 128, 0x23291993 +0, 193880064, 193880064, 602112, 128, 0x23291993 +0, 194482176, 194482176, 602112, 128, 0x23291993 +0, 195084288, 195084288, 602112, 128, 0x23291993 +0, 195686400, 195686400, 602112, 128, 0x23291993 +0, 196288512, 196288512, 602112, 128, 0x23291993 +0, 196890624, 196890624, 602112, 128, 0x23291993 +0, 197492736, 197492736, 602112, 128, 0x23291993 +0, 198094848, 198094848, 602112, 128, 0x23291993 +0, 198696960, 198696960, 602112, 128, 0x23291993 +0, 199299072, 199299072, 602112, 128, 0x23291993 +0, 199901184, 199901184, 602112, 128, 0x23291993 +0, 200503296, 200503296, 602112, 128, 0x23291993 +0, 201105408, 201105408, 602112, 128, 0x23291993 +0, 201707520, 201707520, 602112, 128, 0x23291993 +0, 202309632, 202309632, 602112, 128, 0x23291993 +0, 202911744, 202911744, 602112, 128, 0x23291993 +0, 203513856, 203513856, 602112, 128, 0x23291993 +0, 204115968, 204115968, 602112, 128, 0x23291993 +0, 204718080, 204718080, 602112, 128, 0x23291993 +0, 205320192, 205320192, 602112, 128, 0x23291993 +0, 205922304, 205922304, 602112, 128, 0x23291993 +0, 206524416, 206524416, 602112, 128, 0x23291993 +0, 207126528, 207126528, 602112, 128, 0x23291993 +0, 207728640, 207728640, 602112, 128, 0x23291993 +0, 208330752, 208330752, 602112, 128, 0x23291993 +0, 208932864, 208932864, 602112, 128, 0x23291993 +0, 209534976, 209534976, 602112, 128, 0x23291993 +0, 210137088, 210137088, 602112, 128, 0x23291993 +0, 210739200, 210739200, 602112, 128, 0x23291993 +0, 211341312, 211341312, 602112, 128, 0x23291993 +0, 211943424, 211943424, 602112, 128, 0x23291993 +0, 212545536, 212545536, 602112, 128, 0x23291993 +0, 213147648, 213147648, 602112, 128, 0x23291993 +0, 213749760, 213749760, 602112, 128, 0x23291993 +0, 214351872, 214351872, 602112, 128, 0x23291993 +0, 214953984, 214953984, 602112, 128, 0x23291993 +0, 215556096, 215556096, 602112, 128, 0x23291993 +0, 216158208, 216158208, 602112, 128, 0x23291993 +0, 216760320, 216760320, 602112, 128, 0x23291993 +0, 217362432, 217362432, 602112, 128, 0x23291993 +0, 217964544, 217964544, 602112, 128, 0x23291993 +0, 218566656, 218566656, 602112, 128, 0x23291993 +0, 219168768, 219168768, 602112, 128, 0x23291993 +0, 219770880, 219770880, 602112, 128, 0x23291993 +0, 220372992, 220372992, 602112, 128, 0x23291993 +0, 220975104, 220975104, 602112, 128, 0x23291993 +0, 221577216, 221577216, 602112, 128, 0x23291993 +0, 222179328, 222179328, 602112, 128, 0x23291993 +0, 222781440, 222781440, 602112, 128, 0x23291993 +0, 223383552, 223383552, 602112, 128, 0x23291993 +0, 223985664, 223985664, 602112, 128, 0x23291993 +0, 224587776, 224587776, 602112, 128, 0x23291993 +0, 225189888, 225189888, 602112, 128, 0x23291993 +0, 225792000, 225792000, 602112, 128, 0x23291993 +0, 226394112, 226394112, 602112, 128, 0x23291993 +0, 226996224, 226996224, 602112, 128, 0x23291993 +0, 227598336, 227598336, 602112, 128, 0x23291993 +0, 228200448, 228200448, 602112, 128, 0x23291993 +0, 228802560, 228802560, 602112, 128, 0x23291993 +0, 229404672, 229404672, 602112, 128, 0x23291993 +0, 230006784, 230006784, 602112, 128, 0x23291993 +0, 230608896, 230608896, 602112, 128, 0x23291993 +0, 231211008, 231211008, 602112, 128, 0x23291993 +0, 231813120, 231813120, 602112, 128, 0x23291993 +0, 232415232, 232415232, 602112, 128, 0x23291993 +0, 233017344, 233017344, 602112, 128, 0x23291993 +0, 233619456, 233619456, 602112, 128, 0x23291993 +0, 234221568, 234221568, 602112, 128, 0x23291993 +0, 234823680, 234823680, 602112, 128, 0x23291993 +0, 235425792, 235425792, 602112, 128, 0x23291993 +0, 236027904, 236027904, 602112, 128, 0x23291993 +0, 236630016, 236630016, 602112, 128, 0x23291993 +0, 237232128, 237232128, 602112, 128, 0x23291993 +0, 237834240, 237834240, 602112, 128, 0x23291993 +0, 238436352, 238436352, 602112, 128, 0x23291993 +0, 239038464, 239038464, 602112, 128, 0x23291993 +0, 239640576, 239640576, 602112, 128, 0x23291993 +0, 240242688, 240242688, 602112, 128, 0x23291993 +0, 240844800, 240844800, 602112, 128, 0x23291993 +0, 241446912, 241446912, 602112, 128, 0x23291993 +0, 242049024, 242049024, 602112, 128, 0x23291993 +0, 242651136, 242651136, 602112, 128, 0x23291993 +0, 243253248, 243253248, 602112, 128, 0x23291993 +0, 243855360, 243855360, 602112, 128, 0x23291993 +0, 244457472, 244457472, 602112, 128, 0x23291993 +0, 245059584, 245059584, 602112, 128, 0x23291993 +0, 245661696, 245661696, 602112, 128, 0x23291993 +0, 246263808, 246263808, 602112, 128, 0x23291993 +0, 246865920, 246865920, 602112, 128, 0x23291993 +0, 247468032, 247468032, 602112, 128, 0x23291993 +0, 248070144, 248070144, 602112, 128, 0x23291993 +0, 248672256, 248672256, 602112, 128, 0x23291993 +0, 249274368, 249274368, 602112, 128, 0x23291993 +0, 249876480, 249876480, 602112, 128, 0x23291993 +0, 250478592, 250478592, 602112, 128, 0x23291993 +0, 251080704, 251080704, 602112, 128, 0x23291993 +0, 251682816, 251682816, 602112, 128, 0x23291993 +0, 252284928, 252284928, 602112, 128, 0x23291993 +0, 252887040, 252887040, 602112, 128, 0x23291993 +0, 253489152, 253489152, 602112, 128, 0x23291993 +0, 254091264, 254091264, 602112, 128, 0x23291993 +0, 254693376, 254693376, 602112, 128, 0x23291993 +0, 255295488, 255295488, 602112, 128, 0x23291993 +0, 255897600, 255897600, 602112, 128, 0x23291993 +0, 256499712, 256499712, 602112, 128, 0x23291993 +0, 257101824, 257101824, 602112, 128, 0x23291993 +0, 257703936, 257703936, 602112, 128, 0x23291993 +0, 258306048, 258306048, 602112, 128, 0x23291993 +0, 258908160, 258908160, 602112, 128, 0x23291993 +0, 259510272, 259510272, 602112, 128, 0x23291993 +0, 260112384, 260112384, 602112, 128, 0x23291993 +0, 260714496, 260714496, 602112, 128, 0x23291993 +0, 261316608, 261316608, 602112, 128, 0x23291993 +0, 261918720, 261918720, 602112, 128, 0x23291993 +0, 262520832, 262520832, 602112, 128, 0x23291993 +0, 263122944, 263122944, 602112, 128, 0x23291993 +0, 263725056, 263725056, 602112, 128, 0x23291993 +0, 264327168, 264327168, 602112, 128, 0x23291993 +0, 264929280, 264929280, 602112, 128, 0x23291993 +0, 265531392, 265531392, 602112, 128, 0x23291993 +0, 266133504, 266133504, 602112, 128, 0x23291993 +0, 266735616, 266735616, 602112, 128, 0x23291993 +0, 267337728, 267337728, 602112, 128, 0x23291993 +0, 267939840, 267939840, 602112, 128, 0x23291993 +0, 268541952, 268541952, 602112, 128, 0x23291993 +0, 269144064, 269144064, 602112, 128, 0x23291993 +0, 269746176, 269746176, 602112, 128, 0x23291993 +0, 270348288, 270348288, 602112, 128, 0x23291993 +0, 270950400, 270950400, 602112, 128, 0x23291993 +0, 271552512, 271552512, 602112, 128, 0x23291993 +0, 272154624, 272154624, 602112, 128, 0x23291993 +0, 272756736, 272756736, 602112, 128, 0x23291993 +0, 273358848, 273358848, 602112, 128, 0x23291993 +0, 273960960, 273960960, 602112, 128, 0x23291993 +0, 274563072, 274563072, 602112, 128, 0x23291993 +0, 275165184, 275165184, 602112, 128, 0x23291993 +0, 275767296, 275767296, 602112, 128, 0x23291993 +0, 276369408, 276369408, 602112, 128, 0x23291993 +0, 276971520, 276971520, 602112, 128, 0x23291993 +0, 277573632, 277573632, 602112, 128, 0x23291993 +0, 278175744, 278175744, 602112, 128, 0x23291993 +0, 278777856, 278777856, 602112, 128, 0x23291993 +0, 279379968, 279379968, 602112, 128, 0x23291993 +0, 279982080, 279982080, 602112, 128, 0x23291993 +0, 280584192, 280584192, 602112, 128, 0x23291993 +0, 281186304, 281186304, 602112, 128, 0x23291993 +0, 281788416, 281788416, 602112, 128, 0x23291993 diff --git a/tests/ref/fate/aic b/tests/ref/fate/aic index 1f50350b967f1..244ea259677b2 100644 --- a/tests/ref/fate/aic +++ b/tests/ref/fate/aic @@ -3,18 +3,18 @@ #codec_id 0: rawvideo #dimensions 0: 1440x1080 #sar 0: 4/3 -0, 0, 0, 1, 2332800, 0xd941b42f -0, 1, 1, 1, 2332800, 0xd941b42f -0, 2, 2, 1, 2332800, 0xae0f5983 -0, 3, 3, 1, 2332800, 0x51cfc127 -0, 4, 4, 1, 2332800, 0x24d40447 -0, 5, 5, 1, 2332800, 0x858a9f51 -0, 6, 6, 1, 2332800, 0x533b48e8 -0, 7, 7, 1, 2332800, 0x2fd73267 -0, 8, 8, 1, 2332800, 0x153566c7 -0, 9, 9, 1, 2332800, 0xa1c49c45 -0, 10, 10, 1, 2332800, 0xb966e25a -0, 11, 11, 1, 2332800, 0xd0ce5985 -0, 12, 12, 1, 2332800, 0x0029a52e -0, 13, 13, 1, 2332800, 0x893116c5 -0, 14, 14, 1, 2332800, 0x073d2491 +0, 0, 0, 1, 2332800, 0xc22b8485 +0, 1, 1, 1, 2332800, 0xc22b8485 +0, 2, 2, 1, 2332800, 0xe0c21bd8 +0, 3, 3, 1, 2332800, 0x3e1a8fa0 +0, 4, 4, 1, 2332800, 0xbcb3f235 +0, 5, 5, 1, 2332800, 0x1a7cabd6 +0, 6, 6, 1, 2332800, 0xc0136ba8 +0, 7, 7, 1, 2332800, 0x295e59a6 +0, 8, 8, 1, 2332800, 0xf9c09288 +0, 9, 9, 1, 2332800, 0x0518cc8f +0, 10, 10, 1, 2332800, 0x9ad3068e +0, 11, 11, 1, 2332800, 0x5a8b7af1 +0, 12, 12, 1, 2332800, 0x7b35a8fa +0, 13, 13, 1, 2332800, 0xbe5801eb +0, 14, 14, 1, 2332800, 0x31ca019f diff --git a/tests/ref/fate/aic-oddsize b/tests/ref/fate/aic-oddsize index 3763e32b2cb29..be4346a20436e 100644 --- a/tests/ref/fate/aic-oddsize +++ b/tests/ref/fate/aic-oddsize @@ -3,60 +3,60 @@ #codec_id 0: rawvideo #dimensions 0: 481x241 #sar 0: 0/1 -0, 0, 0, 1, 174243, 0xa40491e1 -0, 1, 1, 1, 174243, 0xa12cbb56 -0, 2, 2, 1, 174243, 0xa12cbb56 -0, 3, 3, 1, 174243, 0xa12cbb56 -0, 4, 4, 1, 174243, 0xa12cbb56 -0, 5, 5, 1, 174243, 0xa12cbb56 -0, 6, 6, 1, 174243, 0xa12cbb56 -0, 7, 7, 1, 174243, 0xa12cbb56 -0, 8, 8, 1, 174243, 0xa12cbb56 -0, 9, 9, 1, 174243, 0x4e7b7299 -0, 10, 10, 1, 174243, 0x31573b99 -0, 11, 11, 1, 174243, 0x013397b6 -0, 12, 12, 1, 174243, 0xdd988ab8 -0, 13, 13, 1, 174243, 0xd6d96b1e -0, 14, 14, 1, 174243, 0xd6d96b1e -0, 15, 15, 1, 174243, 0xd6d96b1e -0, 16, 16, 1, 174243, 0x111627d3 -0, 17, 17, 1, 174243, 0x284d9ab7 -0, 18, 18, 1, 174243, 0xa348c492 -0, 19, 19, 1, 174243, 0xa348c492 -0, 20, 20, 1, 174243, 0xa348c492 -0, 21, 21, 1, 174243, 0xa348c492 -0, 22, 22, 1, 174243, 0x2d22c3b8 -0, 23, 23, 1, 174243, 0x2d22c3b8 -0, 24, 24, 1, 174243, 0x2d22c3b8 -0, 25, 25, 1, 174243, 0x2d22c3b8 -0, 26, 26, 1, 174243, 0xa6d7c890 -0, 27, 27, 1, 174243, 0x8068bfbb -0, 28, 28, 1, 174243, 0x420ae647 -0, 29, 29, 1, 174243, 0xc5467756 -0, 30, 30, 1, 174243, 0x238a13dd -0, 31, 31, 1, 174243, 0x5bab75dc -0, 32, 32, 1, 174243, 0x14d7f61f -0, 33, 33, 1, 174243, 0x2e1d334f -0, 34, 34, 1, 174243, 0xeade7dc0 -0, 35, 35, 1, 174243, 0xeade7dc0 -0, 36, 36, 1, 174243, 0xeade7dc0 -0, 37, 37, 1, 174243, 0xeade7dc0 -0, 38, 38, 1, 174243, 0x088c7ef9 -0, 39, 39, 1, 174243, 0x70a3554e -0, 40, 40, 1, 174243, 0x0753d1d4 -0, 41, 41, 1, 174243, 0x8266bd6d -0, 42, 42, 1, 174243, 0x4ce3cda9 -0, 43, 43, 1, 174243, 0x4ce3cda9 -0, 44, 44, 1, 174243, 0x4ce3cda9 -0, 45, 45, 1, 174243, 0x4ce3cda9 -0, 46, 46, 1, 174243, 0xe5f7cd98 -0, 47, 47, 1, 174243, 0xe5f7cd98 -0, 48, 48, 1, 174243, 0xe5f7cd98 -0, 49, 49, 1, 174243, 0xe5f7cd98 -0, 50, 50, 1, 174243, 0x78c5cdb7 -0, 51, 51, 1, 174243, 0x78c5cdb7 -0, 52, 52, 1, 174243, 0x78c5cdb7 -0, 53, 53, 1, 174243, 0xce7ccd92 -0, 54, 54, 1, 174243, 0xce7ccd92 -0, 55, 55, 1, 174243, 0xce7ccd92 -0, 56, 56, 1, 174243, 0xce7ccd92 +0, 0, 0, 1, 174243, 0x15ab835b +0, 1, 1, 1, 174243, 0x12d3acd0 +0, 2, 2, 1, 174243, 0x12d3acd0 +0, 3, 3, 1, 174243, 0x12d3acd0 +0, 4, 4, 1, 174243, 0x12d3acd0 +0, 5, 5, 1, 174243, 0x12d3acd0 +0, 6, 6, 1, 174243, 0x12d3acd0 +0, 7, 7, 1, 174243, 0x12d3acd0 +0, 8, 8, 1, 174243, 0x12d3acd0 +0, 9, 9, 1, 174243, 0xb21561b4 +0, 10, 10, 1, 174243, 0x49343b5b +0, 11, 11, 1, 174243, 0x9bd65f49 +0, 12, 12, 1, 174243, 0xed3b9960 +0, 13, 13, 1, 174243, 0x14f70294 +0, 14, 14, 1, 174243, 0x14f70294 +0, 15, 15, 1, 174243, 0x14f70294 +0, 16, 16, 1, 174243, 0x92ac2316 +0, 17, 17, 1, 174243, 0x12729ac0 +0, 18, 18, 1, 174243, 0x6db0bfbd +0, 19, 19, 1, 174243, 0x6db0bfbd +0, 20, 20, 1, 174243, 0x6db0bfbd +0, 21, 21, 1, 174243, 0x6db0bfbd +0, 22, 22, 1, 174243, 0xd66cbef7 +0, 23, 23, 1, 174243, 0xd66cbef7 +0, 24, 24, 1, 174243, 0xd66cbef7 +0, 25, 25, 1, 174243, 0xd66cbef7 +0, 26, 26, 1, 174243, 0x3314c3d3 +0, 27, 27, 1, 174243, 0x34efb358 +0, 28, 28, 1, 174243, 0x7307d8c8 +0, 29, 29, 1, 174243, 0x80b57ea1 +0, 30, 30, 1, 174243, 0xb0b51bf9 +0, 31, 31, 1, 174243, 0x60c07516 +0, 32, 32, 1, 174243, 0xcc35033f +0, 33, 33, 1, 174243, 0x2bf12dc4 +0, 34, 34, 1, 174243, 0xf3025eb7 +0, 35, 35, 1, 174243, 0xf3025eb7 +0, 36, 36, 1, 174243, 0xf3025eb7 +0, 37, 37, 1, 174243, 0xf3025eb7 +0, 38, 38, 1, 174243, 0x06e761b3 +0, 39, 39, 1, 174243, 0xa21152fb +0, 40, 40, 1, 174243, 0xd6dcc575 +0, 41, 41, 1, 174243, 0xd6ceb82a +0, 42, 42, 1, 174243, 0x20efc206 +0, 43, 43, 1, 174243, 0x20efc206 +0, 44, 44, 1, 174243, 0x20efc206 +0, 45, 45, 1, 174243, 0x20efc206 +0, 46, 46, 1, 174243, 0xba03c1f5 +0, 47, 47, 1, 174243, 0xba03c1f5 +0, 48, 48, 1, 174243, 0xba03c1f5 +0, 49, 49, 1, 174243, 0xba03c1f5 +0, 50, 50, 1, 174243, 0x4cd1c214 +0, 51, 51, 1, 174243, 0x4cd1c214 +0, 52, 52, 1, 174243, 0x4cd1c214 +0, 53, 53, 1, 174243, 0xa288c1ef +0, 54, 54, 1, 174243, 0xa288c1ef +0, 55, 55, 1, 174243, 0xa288c1ef +0, 56, 56, 1, 174243, 0xa288c1ef diff --git a/tests/ref/fate/api-mjpeg-codec-param b/tests/ref/fate/api-mjpeg-codec-param index 02f656df25a0d..290f941ff3c0d 100644 --- a/tests/ref/fate/api-mjpeg-codec-param +++ b/tests/ref/fate/api-mjpeg-codec-param @@ -3,7 +3,6 @@ stream=0, decode=0 ab=0 bt=4000000 flags=0x00000000 - me_method=5 time_base=0/1 g=12 ar=0 @@ -18,7 +17,6 @@ stream=0, decode=0 qdiff=3 bf=0 b_qfactor=1.250000 - rc_strategy=0 b_strategy=0 ps=0 mv_bits=0 @@ -38,18 +36,12 @@ stream=0, decode=0 has_b_frames=0 block_align=0 mpeg_quant=0 - qsquish=0.000000 - rc_qmod_amp=0.000000 - rc_qmod_freq=0 rc_override_count=0 - rc_eq= maxrate=0 minrate=0 bufsize=0 - rc_buf_aggressivity=1.000000 i_qfactor=-0.800000 i_qoffset=0.000000 - rc_init_cplx=0.000000 dct=0 lumi_mask=0.000000 tcplx_mask=0.000000 @@ -64,7 +56,6 @@ stream=0, decode=0 aspect=180/180 sar=180/180 debug=0x00000000 - vismv=0x00000000 cmp=0 subcmp=0 mbcmp=0 @@ -75,39 +66,28 @@ stream=0, decode=0 precmp=0 pre_dia_size=0 subq=8 - dtg_active_format=0 me_range=0 - ibias=999999 - pbias=999999 global_quality=0 coder=0 context=0 slice_flags=0 - xvmc_acceleration=0 mbd=0 - stream_codec_tag=0 sc_threshold=0 - lmin=0 - lmax=0 nr=0 rc_init_occupancy=0 flags2=0x00000000 - error=0 threads=1 - me_threshold=0 - mb_threshold=0 dc=0 nssew=8 skip_top=0 skip_bottom=0 - profile=-99 + profile=192 level=-99 lowres=0 skip_threshold=0 skip_factor=0 skip_exp=0 skipcmp=13 - border_mask=0.000000 mblmin=236 mblmax=3658 mepc=256 @@ -120,7 +100,6 @@ stream=0, decode=0 refs=1 chromaoffset=0 trellis=0 - sc_factor=6 mv0_threshold=256 b_sensitivity=40 compression_level=-1 @@ -158,12 +137,12 @@ stream=0, decode=0 video_size=400x225 max_pixels=2147483647 hwaccel_flags=0x00000001 + extra_hw_frames=-1 stream=0, decode=1 b=0 ab=0 bt=4000000 flags=0x00000000 - me_method=5 time_base=0/1 g=12 ar=0 @@ -178,7 +157,6 @@ stream=0, decode=1 qdiff=3 bf=0 b_qfactor=1.250000 - rc_strategy=0 b_strategy=0 ps=0 mv_bits=0 @@ -198,18 +176,12 @@ stream=0, decode=1 has_b_frames=0 block_align=0 mpeg_quant=0 - qsquish=0.000000 - rc_qmod_amp=0.000000 - rc_qmod_freq=0 rc_override_count=0 - rc_eq= maxrate=0 minrate=0 bufsize=0 - rc_buf_aggressivity=1.000000 i_qfactor=-0.800000 i_qoffset=0.000000 - rc_init_cplx=0.000000 dct=0 lumi_mask=0.000000 tcplx_mask=0.000000 @@ -224,7 +196,6 @@ stream=0, decode=1 aspect=180/180 sar=180/180 debug=0x00000000 - vismv=0x00000000 cmp=0 subcmp=0 mbcmp=0 @@ -235,39 +206,28 @@ stream=0, decode=1 precmp=0 pre_dia_size=0 subq=8 - dtg_active_format=0 me_range=0 - ibias=999999 - pbias=999999 global_quality=0 coder=0 context=0 slice_flags=0 - xvmc_acceleration=0 mbd=0 - stream_codec_tag=0 sc_threshold=0 - lmin=0 - lmax=0 nr=0 rc_init_occupancy=0 flags2=0x00000000 - error=0 threads=1 - me_threshold=0 - mb_threshold=0 dc=0 nssew=8 skip_top=0 skip_bottom=0 - profile=-99 + profile=192 level=-99 lowres=0 skip_threshold=0 skip_factor=0 skip_exp=0 skipcmp=13 - border_mask=0.000000 mblmin=236 mblmax=3658 mepc=256 @@ -280,7 +240,6 @@ stream=0, decode=1 refs=1 chromaoffset=0 trellis=0 - sc_factor=6 mv0_threshold=256 b_sensitivity=40 compression_level=-1 @@ -318,3 +277,4 @@ stream=0, decode=1 video_size=400x225 max_pixels=2147483647 hwaccel_flags=0x00000001 + extra_hw_frames=-1 diff --git a/tests/ref/fate/api-png-codec-param b/tests/ref/fate/api-png-codec-param index de86f1b25d92c..f04ffa757dc2d 100644 --- a/tests/ref/fate/api-png-codec-param +++ b/tests/ref/fate/api-png-codec-param @@ -3,7 +3,6 @@ stream=0, decode=0 ab=0 bt=4000000 flags=0x00000000 - me_method=5 time_base=0/1 g=12 ar=0 @@ -18,7 +17,6 @@ stream=0, decode=0 qdiff=3 bf=0 b_qfactor=1.250000 - rc_strategy=0 b_strategy=0 ps=0 mv_bits=0 @@ -38,18 +36,12 @@ stream=0, decode=0 has_b_frames=0 block_align=0 mpeg_quant=0 - qsquish=0.000000 - rc_qmod_amp=0.000000 - rc_qmod_freq=0 rc_override_count=0 - rc_eq= maxrate=0 minrate=0 bufsize=0 - rc_buf_aggressivity=1.000000 i_qfactor=-0.800000 i_qoffset=0.000000 - rc_init_cplx=0.000000 dct=0 lumi_mask=0.000000 tcplx_mask=0.000000 @@ -64,7 +56,6 @@ stream=0, decode=0 aspect=2835/2835 sar=2835/2835 debug=0x00000000 - vismv=0x00000000 cmp=0 subcmp=0 mbcmp=0 @@ -75,27 +66,17 @@ stream=0, decode=0 precmp=0 pre_dia_size=0 subq=8 - dtg_active_format=0 me_range=0 - ibias=999999 - pbias=999999 global_quality=0 coder=0 context=0 slice_flags=0 - xvmc_acceleration=0 mbd=0 - stream_codec_tag=0 sc_threshold=0 - lmin=0 - lmax=0 nr=0 rc_init_occupancy=0 flags2=0x00000000 - error=0 threads=1 - me_threshold=0 - mb_threshold=0 dc=0 nssew=8 skip_top=0 @@ -107,7 +88,6 @@ stream=0, decode=0 skip_factor=0 skip_exp=0 skipcmp=13 - border_mask=0.000000 mblmin=236 mblmax=3658 mepc=256 @@ -120,7 +100,6 @@ stream=0, decode=0 refs=1 chromaoffset=0 trellis=0 - sc_factor=6 mv0_threshold=256 b_sensitivity=40 compression_level=-1 @@ -158,12 +137,12 @@ stream=0, decode=0 video_size=128x128 max_pixels=2147483647 hwaccel_flags=0x00000001 + extra_hw_frames=-1 stream=0, decode=1 b=0 ab=0 bt=4000000 flags=0x00000000 - me_method=5 time_base=0/1 g=12 ar=0 @@ -178,7 +157,6 @@ stream=0, decode=1 qdiff=3 bf=0 b_qfactor=1.250000 - rc_strategy=0 b_strategy=0 ps=0 mv_bits=0 @@ -198,18 +176,12 @@ stream=0, decode=1 has_b_frames=0 block_align=0 mpeg_quant=0 - qsquish=0.000000 - rc_qmod_amp=0.000000 - rc_qmod_freq=0 rc_override_count=0 - rc_eq= maxrate=0 minrate=0 bufsize=0 - rc_buf_aggressivity=1.000000 i_qfactor=-0.800000 i_qoffset=0.000000 - rc_init_cplx=0.000000 dct=0 lumi_mask=0.000000 tcplx_mask=0.000000 @@ -224,7 +196,6 @@ stream=0, decode=1 aspect=2835/2835 sar=2835/2835 debug=0x00000000 - vismv=0x00000000 cmp=0 subcmp=0 mbcmp=0 @@ -235,27 +206,17 @@ stream=0, decode=1 precmp=0 pre_dia_size=0 subq=8 - dtg_active_format=0 me_range=0 - ibias=999999 - pbias=999999 global_quality=0 coder=0 context=0 slice_flags=0 - xvmc_acceleration=0 mbd=0 - stream_codec_tag=0 sc_threshold=0 - lmin=0 - lmax=0 nr=0 rc_init_occupancy=0 flags2=0x00000000 - error=0 threads=1 - me_threshold=0 - mb_threshold=0 dc=0 nssew=8 skip_top=0 @@ -267,7 +228,6 @@ stream=0, decode=1 skip_factor=0 skip_exp=0 skipcmp=13 - border_mask=0.000000 mblmin=236 mblmax=3658 mepc=256 @@ -280,7 +240,6 @@ stream=0, decode=1 refs=1 chromaoffset=0 trellis=0 - sc_factor=6 mv0_threshold=256 b_sensitivity=40 compression_level=-1 @@ -318,3 +277,4 @@ stream=0, decode=1 video_size=128x128 max_pixels=2147483647 hwaccel_flags=0x00000001 + extra_hw_frames=-1 diff --git a/tests/ref/fate/cbs-h264-AUD_MW_E b/tests/ref/fate/cbs-h264-AUD_MW_E new file mode 100644 index 0000000000000..f204792416260 --- /dev/null +++ b/tests/ref/fate/cbs-h264-AUD_MW_E @@ -0,0 +1 @@ +9b8884667eda0b9853bec631458686ce diff --git a/tests/ref/fate/cbs-h264-BASQP1_Sony_C b/tests/ref/fate/cbs-h264-BASQP1_Sony_C new file mode 100644 index 0000000000000..c2185c770b08a --- /dev/null +++ b/tests/ref/fate/cbs-h264-BASQP1_Sony_C @@ -0,0 +1 @@ +00c52ae60bf9a41ae1145fbf5fea9838 diff --git a/tests/ref/fate/cbs-h264-CABACI3_Sony_B b/tests/ref/fate/cbs-h264-CABACI3_Sony_B new file mode 100644 index 0000000000000..59aeb721555ff --- /dev/null +++ b/tests/ref/fate/cbs-h264-CABACI3_Sony_B @@ -0,0 +1 @@ +2d94c80b858aec880530bad47afe3668 diff --git a/tests/ref/fate/cbs-h264-CVBS3_Sony_C b/tests/ref/fate/cbs-h264-CVBS3_Sony_C new file mode 100644 index 0000000000000..55f5e0b50e53a --- /dev/null +++ b/tests/ref/fate/cbs-h264-CVBS3_Sony_C @@ -0,0 +1 @@ +59ff1df9b25e80277cad4ad99e634df6 diff --git a/tests/ref/fate/cbs-h264-CVFC1_Sony_C b/tests/ref/fate/cbs-h264-CVFC1_Sony_C new file mode 100644 index 0000000000000..98004cf63c904 --- /dev/null +++ b/tests/ref/fate/cbs-h264-CVFC1_Sony_C @@ -0,0 +1 @@ +669f4f3d3ae35fa5a6f5c94e48776dcf diff --git a/tests/ref/fate/cbs-h264-CVMANL1_TOSHIBA_B b/tests/ref/fate/cbs-h264-CVMANL1_TOSHIBA_B new file mode 100644 index 0000000000000..14aa45300d839 --- /dev/null +++ b/tests/ref/fate/cbs-h264-CVMANL1_TOSHIBA_B @@ -0,0 +1 @@ +0c1d9694df747cc4697caf866bd3051a diff --git a/tests/ref/fate/cbs-h264-CVNLFI1_Sony_C b/tests/ref/fate/cbs-h264-CVNLFI1_Sony_C new file mode 100644 index 0000000000000..d5f5ad1931a3b --- /dev/null +++ b/tests/ref/fate/cbs-h264-CVNLFI1_Sony_C @@ -0,0 +1 @@ +7817d89bd749bc617a225978958a3af0 diff --git a/tests/ref/fate/cbs-h264-CVSE2_Sony_B b/tests/ref/fate/cbs-h264-CVSE2_Sony_B new file mode 100644 index 0000000000000..7845723edd80c --- /dev/null +++ b/tests/ref/fate/cbs-h264-CVSE2_Sony_B @@ -0,0 +1 @@ +ca8bdba497bd2f3b97c50d59692eb537 diff --git a/tests/ref/fate/cbs-h264-CVWP1_TOSHIBA_E b/tests/ref/fate/cbs-h264-CVWP1_TOSHIBA_E new file mode 100644 index 0000000000000..4cb9c475fcfbb --- /dev/null +++ b/tests/ref/fate/cbs-h264-CVWP1_TOSHIBA_E @@ -0,0 +1 @@ +01290611165b8d8ccba8468f3dae4c4d diff --git a/tests/ref/fate/cbs-h264-FM1_BT_B b/tests/ref/fate/cbs-h264-FM1_BT_B new file mode 100644 index 0000000000000..862de950de28e --- /dev/null +++ b/tests/ref/fate/cbs-h264-FM1_BT_B @@ -0,0 +1 @@ +f7d5474ec576eea3f70d83a26a641a60 diff --git a/tests/ref/fate/cbs-h264-MR1_BT_A b/tests/ref/fate/cbs-h264-MR1_BT_A new file mode 100644 index 0000000000000..0532652e6cfc8 --- /dev/null +++ b/tests/ref/fate/cbs-h264-MR1_BT_A @@ -0,0 +1 @@ +699d37e66764ddb3b4265c299ca77dcd diff --git a/tests/ref/fate/cbs-h264-SVA_Base_B b/tests/ref/fate/cbs-h264-SVA_Base_B new file mode 100644 index 0000000000000..a591b811b12f8 --- /dev/null +++ b/tests/ref/fate/cbs-h264-SVA_Base_B @@ -0,0 +1 @@ +443e55dd5f63dccf9a62acbb48451b08 diff --git a/tests/ref/fate/cbs-h264-Sharp_MP_PAFF_1r2 b/tests/ref/fate/cbs-h264-Sharp_MP_PAFF_1r2 new file mode 100644 index 0000000000000..cc7d63931c79a --- /dev/null +++ b/tests/ref/fate/cbs-h264-Sharp_MP_PAFF_1r2 @@ -0,0 +1 @@ +fd01840ed6b086c3118b7c53c86d01f5 diff --git a/tests/ref/fate/cbs-h264-sp1_bt_a b/tests/ref/fate/cbs-h264-sp1_bt_a new file mode 100644 index 0000000000000..388c53aa5e756 --- /dev/null +++ b/tests/ref/fate/cbs-h264-sp1_bt_a @@ -0,0 +1 @@ +8405c5583d31d7015ed401b34b4ec93c diff --git a/tests/ref/fate/cbs-hevc-CAINIT_E_SHARP_3 b/tests/ref/fate/cbs-hevc-CAINIT_E_SHARP_3 new file mode 100644 index 0000000000000..53af86aaa4684 --- /dev/null +++ b/tests/ref/fate/cbs-hevc-CAINIT_E_SHARP_3 @@ -0,0 +1 @@ +44d1c0b80828af779d942cc20dde4ea4 diff --git a/tests/ref/fate/cbs-hevc-CAINIT_H_SHARP_3 b/tests/ref/fate/cbs-hevc-CAINIT_H_SHARP_3 new file mode 100644 index 0000000000000..5e127d7894cec --- /dev/null +++ b/tests/ref/fate/cbs-hevc-CAINIT_H_SHARP_3 @@ -0,0 +1 @@ +ae9311dfcaf65bb8de9c4fcf23ce0871 diff --git a/tests/ref/fate/cbs-hevc-CONFWIN_A_Sony_1 b/tests/ref/fate/cbs-hevc-CONFWIN_A_Sony_1 new file mode 100644 index 0000000000000..00445155d0a33 --- /dev/null +++ b/tests/ref/fate/cbs-hevc-CONFWIN_A_Sony_1 @@ -0,0 +1 @@ +dce8104b2addbdd601eb280a88e18583 diff --git a/tests/ref/fate/cbs-hevc-HRD_A_Fujitsu_2 b/tests/ref/fate/cbs-hevc-HRD_A_Fujitsu_2 new file mode 100644 index 0000000000000..b9c90ae3c372d --- /dev/null +++ b/tests/ref/fate/cbs-hevc-HRD_A_Fujitsu_2 @@ -0,0 +1 @@ +716a90051f028c90daeb86b3825af36d diff --git a/tests/ref/fate/cbs-hevc-LTRPSPS_A_Qualcomm_1 b/tests/ref/fate/cbs-hevc-LTRPSPS_A_Qualcomm_1 new file mode 100644 index 0000000000000..21dfa5763a83c --- /dev/null +++ b/tests/ref/fate/cbs-hevc-LTRPSPS_A_Qualcomm_1 @@ -0,0 +1 @@ +11b599202a4d25693123bea8bb003e54 diff --git a/tests/ref/fate/cbs-hevc-NUT_A_ericsson_5 b/tests/ref/fate/cbs-hevc-NUT_A_ericsson_5 new file mode 100644 index 0000000000000..32e58affe79e7 --- /dev/null +++ b/tests/ref/fate/cbs-hevc-NUT_A_ericsson_5 @@ -0,0 +1 @@ +25cf94dfa2e0334eeedbfa9a8ed1c4b2 diff --git a/tests/ref/fate/cbs-hevc-PICSIZE_A_Bossen_1 b/tests/ref/fate/cbs-hevc-PICSIZE_A_Bossen_1 new file mode 100644 index 0000000000000..cc180049202ce --- /dev/null +++ b/tests/ref/fate/cbs-hevc-PICSIZE_A_Bossen_1 @@ -0,0 +1 @@ +e87fbd90c297d401738db928e3e04dd4 diff --git a/tests/ref/fate/cbs-hevc-PICSIZE_B_Bossen_1 b/tests/ref/fate/cbs-hevc-PICSIZE_B_Bossen_1 new file mode 100644 index 0000000000000..5495cec6c3e91 --- /dev/null +++ b/tests/ref/fate/cbs-hevc-PICSIZE_B_Bossen_1 @@ -0,0 +1 @@ +4993d49d6f2f532dfc683a9d26c1e313 diff --git a/tests/ref/fate/cbs-hevc-RPLM_A_qualcomm_4 b/tests/ref/fate/cbs-hevc-RPLM_A_qualcomm_4 new file mode 100644 index 0000000000000..c68d615cbff4d --- /dev/null +++ b/tests/ref/fate/cbs-hevc-RPLM_A_qualcomm_4 @@ -0,0 +1 @@ +f5d2633eefcd95e189faf4302d270457 diff --git a/tests/ref/fate/cbs-hevc-RPS_A_docomo_4 b/tests/ref/fate/cbs-hevc-RPS_A_docomo_4 new file mode 100644 index 0000000000000..772d16a192693 --- /dev/null +++ b/tests/ref/fate/cbs-hevc-RPS_A_docomo_4 @@ -0,0 +1 @@ +97bd4fefd8cd95584f586027e244f283 diff --git a/tests/ref/fate/cbs-hevc-RPS_E_qualcomm_5 b/tests/ref/fate/cbs-hevc-RPS_E_qualcomm_5 new file mode 100644 index 0000000000000..faef7da0d9232 --- /dev/null +++ b/tests/ref/fate/cbs-hevc-RPS_E_qualcomm_5 @@ -0,0 +1 @@ +b2528ef681729176ccb38a77be93a0de diff --git a/tests/ref/fate/cbs-hevc-SLIST_A_Sony_4 b/tests/ref/fate/cbs-hevc-SLIST_A_Sony_4 new file mode 100644 index 0000000000000..23b2e324d15e5 --- /dev/null +++ b/tests/ref/fate/cbs-hevc-SLIST_A_Sony_4 @@ -0,0 +1 @@ +72cf53bbc967c9679e21a6d3203edb07 diff --git a/tests/ref/fate/cbs-hevc-SLIST_D_Sony_9 b/tests/ref/fate/cbs-hevc-SLIST_D_Sony_9 new file mode 100644 index 0000000000000..4cea86dba6c7b --- /dev/null +++ b/tests/ref/fate/cbs-hevc-SLIST_D_Sony_9 @@ -0,0 +1 @@ +59a22d715e30748492da5e0b9d421909 diff --git a/tests/ref/fate/cbs-hevc-STRUCT_A_Samsung_5 b/tests/ref/fate/cbs-hevc-STRUCT_A_Samsung_5 new file mode 100644 index 0000000000000..6a4508b0c5c12 --- /dev/null +++ b/tests/ref/fate/cbs-hevc-STRUCT_A_Samsung_5 @@ -0,0 +1 @@ +647eb851b935fd3bc6a98ce5ce45dbc7 diff --git a/tests/ref/fate/cbs-hevc-TILES_B_Cisco_1 b/tests/ref/fate/cbs-hevc-TILES_B_Cisco_1 new file mode 100644 index 0000000000000..d767e26d6839a --- /dev/null +++ b/tests/ref/fate/cbs-hevc-TILES_B_Cisco_1 @@ -0,0 +1 @@ +85a114def19cefbd0fb0daf8370d711c diff --git a/tests/ref/fate/cbs-hevc-WPP_A_ericsson_MAIN_2 b/tests/ref/fate/cbs-hevc-WPP_A_ericsson_MAIN_2 new file mode 100644 index 0000000000000..fe6928fc8bc48 --- /dev/null +++ b/tests/ref/fate/cbs-hevc-WPP_A_ericsson_MAIN_2 @@ -0,0 +1 @@ +de7d440b556eea827953e6d12aeb4023 diff --git a/tests/ref/fate/cbs-hevc-WPP_F_ericsson_MAIN_2 b/tests/ref/fate/cbs-hevc-WPP_F_ericsson_MAIN_2 new file mode 100644 index 0000000000000..08aee566f1286 --- /dev/null +++ b/tests/ref/fate/cbs-hevc-WPP_F_ericsson_MAIN_2 @@ -0,0 +1 @@ +f197136f1fb3242c3422a48470dd7d35 diff --git a/tests/ref/fate/cbs-hevc-WP_A_Toshiba_3 b/tests/ref/fate/cbs-hevc-WP_A_Toshiba_3 new file mode 100644 index 0000000000000..b868c438f8803 --- /dev/null +++ b/tests/ref/fate/cbs-hevc-WP_A_Toshiba_3 @@ -0,0 +1 @@ +158312a1a35ef4b20cb4aeee48549c03 diff --git a/tests/ref/fate/cbs-hevc-ipcm_E_NEC_2 b/tests/ref/fate/cbs-hevc-ipcm_E_NEC_2 new file mode 100644 index 0000000000000..cc68b6fb49deb --- /dev/null +++ b/tests/ref/fate/cbs-hevc-ipcm_E_NEC_2 @@ -0,0 +1 @@ +2e1f9c95364cfac2aa6e6ee3a52c43c4 diff --git a/tests/ref/fate/cbs-mpeg2-hhi_burst_422_short b/tests/ref/fate/cbs-mpeg2-hhi_burst_422_short new file mode 100644 index 0000000000000..c319fba7b3b09 --- /dev/null +++ b/tests/ref/fate/cbs-mpeg2-hhi_burst_422_short @@ -0,0 +1 @@ +e0c2fdd9baeba0c5ba5839a8cd7a72d3 diff --git a/tests/ref/fate/cbs-mpeg2-sony-ct3 b/tests/ref/fate/cbs-mpeg2-sony-ct3 new file mode 100644 index 0000000000000..b5b4b12f0737b --- /dev/null +++ b/tests/ref/fate/cbs-mpeg2-sony-ct3 @@ -0,0 +1 @@ +b1e15a09cfffbad801810af0928736ab diff --git a/tests/ref/fate/cbs-mpeg2-tcela-6 b/tests/ref/fate/cbs-mpeg2-tcela-6 new file mode 100644 index 0000000000000..530369d6728ac --- /dev/null +++ b/tests/ref/fate/cbs-mpeg2-tcela-6 @@ -0,0 +1 @@ +771b6756a63793e05b74e645794908a2 diff --git a/tests/ref/fate/cfhd-1 b/tests/ref/fate/cfhd-1 new file mode 100644 index 0000000000000..0280d66df1d48 --- /dev/null +++ b/tests/ref/fate/cfhd-1 @@ -0,0 +1,15 @@ +#tb 0: 1001/30000 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 720x480 +#sar 0: 0/1 +0, 0, 0, 1, 1382400, 0xa3e49817 +0, 1, 1, 1, 1382400, 0x544fdfac +0, 2, 2, 1, 1382400, 0x84964e11 +0, 3, 3, 1, 1382400, 0xc608c8d1 +0, 4, 4, 1, 1382400, 0xf2f1404f +0, 5, 5, 1, 1382400, 0x5a3100ba +0, 6, 6, 1, 1382400, 0x3727baa9 +0, 7, 7, 1, 1382400, 0x894f07db +0, 8, 8, 1, 1382400, 0x3ef27d46 +0, 9, 9, 1, 1382400, 0x1f90880d diff --git a/tests/ref/fate/cfhd-2 b/tests/ref/fate/cfhd-2 new file mode 100644 index 0000000000000..77db54c2657ff --- /dev/null +++ b/tests/ref/fate/cfhd-2 @@ -0,0 +1,15 @@ +#tb 0: 1001/30000 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 720x480 +#sar 0: 0/1 +0, 0, 0, 1, 2073600, 0x53fab433 +0, 1, 1, 1, 2073600, 0x0d2b3f64 +0, 2, 2, 1, 2073600, 0x857d1d48 +0, 3, 3, 1, 2073600, 0xe1a7df32 +0, 4, 4, 1, 2073600, 0x615861c1 +0, 5, 5, 1, 2073600, 0xf6cdb0a9 +0, 6, 6, 1, 2073600, 0x55dd9f16 +0, 7, 7, 1, 2073600, 0x7c126a32 +0, 8, 8, 1, 2073600, 0x53fdd4c5 +0, 9, 9, 1, 2073600, 0x6062a4b3 diff --git a/tests/ref/fate/cfhd-3 b/tests/ref/fate/cfhd-3 new file mode 100644 index 0000000000000..59fdc9226090d --- /dev/null +++ b/tests/ref/fate/cfhd-3 @@ -0,0 +1,15 @@ +#tb 0: 1000/14587 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 496x241 +#sar 0: 0/1 +0, 0, 0, 1, 478144, 0x48a01dbb +0, 1, 1, 1, 478144, 0x48a01dbb +0, 2, 2, 1, 478144, 0x48a01dbb +0, 3, 3, 1, 478144, 0xb978a72f +0, 4, 4, 1, 478144, 0x7bbb4679 +0, 5, 5, 1, 478144, 0xc3fd3f59 +0, 6, 6, 1, 478144, 0xfd2a4816 +0, 7, 7, 1, 478144, 0x207f65d3 +0, 8, 8, 1, 478144, 0x207f65d3 +0, 9, 9, 1, 478144, 0x207f65d3 diff --git a/tests/ref/fate/copy-trac2211-avi b/tests/ref/fate/copy-trac2211-avi index 007349e572752..06d81e537d983 100644 --- a/tests/ref/fate/copy-trac2211-avi +++ b/tests/ref/fate/copy-trac2211-avi @@ -1,5 +1,5 @@ -6f6b211cbc8de9871e8e09e64048e2f9 *tests/data/fate/copy-trac2211-avi.avi -1777924 tests/data/fate/copy-trac2211-avi.avi +0920978f3f8196413c43f0033b55a5b6 *tests/data/fate/copy-trac2211-avi.avi +1777956 tests/data/fate/copy-trac2211-avi.avi #tb 0: 1/14 #media_type 0: video #codec_id 0: rawvideo diff --git a/tests/ref/fate/copy-trac4914 b/tests/ref/fate/copy-trac4914 index e0864a0035ca9..a8f287fafae17 100644 --- a/tests/ref/fate/copy-trac4914 +++ b/tests/ref/fate/copy-trac4914 @@ -1,4 +1,4 @@ -d51f6bcc96885a2ce8517ae8c774f610 *tests/data/fate/copy-trac4914.mxf +05fdc4a6e28abb2c26e96224682d2684 *tests/data/fate/copy-trac4914.mxf 560697 tests/data/fate/copy-trac4914.mxf #tb 0: 1001/30000 #media_type 0: video diff --git a/tests/ref/fate/crc b/tests/ref/fate/crc index 8aa0dd24481d3..7b59a3cc07ae3 100644 --- a/tests/ref/fate/crc +++ b/tests/ref/fate/crc @@ -4,3 +4,4 @@ crc 00864CFB = 326039 crc 0000A001 = BFD8 crc 00008005 = BB1F crc 00000007 = E3 +crc 0000001D = D6 diff --git a/tests/ref/fate/exif-image-embedded b/tests/ref/fate/exif-image-embedded index 306ae0854b1a8..392c145efb9e7 100644 --- a/tests/ref/fate/exif-image-embedded +++ b/tests/ref/fate/exif-image-embedded @@ -29,6 +29,12 @@ color_transfer=unknown chroma_location=center TAG:UserComment=AppleMark +[SIDE_DATA] +side_data_type=QP table data +[/SIDE_DATA] +[SIDE_DATA] +side_data_type=QP table properties +[/SIDE_DATA] [/FRAME] [FRAME] media_type=audio @@ -44,7 +50,7 @@ pkt_duration=15040 pkt_duration_time=0.001066 pkt_pos=16292 pkt_size=417 -sample_fmt=s16p +sample_fmt=fltp nb_samples=47 channels=2 channel_layout=stereo @@ -63,7 +69,7 @@ pkt_duration=368640 pkt_duration_time=0.026122 pkt_pos=16709 pkt_size=418 -sample_fmt=s16p +sample_fmt=fltp nb_samples=1152 channels=2 channel_layout=stereo @@ -82,7 +88,7 @@ pkt_duration=368640 pkt_duration_time=0.026122 pkt_pos=17127 pkt_size=418 -sample_fmt=s16p +sample_fmt=fltp nb_samples=1152 channels=2 channel_layout=stereo @@ -101,7 +107,7 @@ pkt_duration=368640 pkt_duration_time=0.026122 pkt_pos=17545 pkt_size=418 -sample_fmt=s16p +sample_fmt=fltp nb_samples=1152 channels=2 channel_layout=stereo @@ -120,7 +126,7 @@ pkt_duration=368640 pkt_duration_time=0.026122 pkt_pos=17963 pkt_size=418 -sample_fmt=s16p +sample_fmt=fltp nb_samples=1152 channels=2 channel_layout=stereo @@ -139,7 +145,7 @@ pkt_duration=368640 pkt_duration_time=0.026122 pkt_pos=18381 pkt_size=418 -sample_fmt=s16p +sample_fmt=fltp nb_samples=1152 channels=2 channel_layout=stereo @@ -158,7 +164,7 @@ pkt_duration=368640 pkt_duration_time=0.026122 pkt_pos=18799 pkt_size=418 -sample_fmt=s16p +sample_fmt=fltp nb_samples=1152 channels=2 channel_layout=stereo @@ -177,7 +183,7 @@ pkt_duration=368640 pkt_duration_time=0.026122 pkt_pos=19217 pkt_size=418 -sample_fmt=s16p +sample_fmt=fltp nb_samples=1152 channels=2 channel_layout=stereo @@ -196,7 +202,7 @@ pkt_duration=368640 pkt_duration_time=0.026122 pkt_pos=19635 pkt_size=418 -sample_fmt=s16p +sample_fmt=fltp nb_samples=1152 channels=2 channel_layout=stereo @@ -215,7 +221,7 @@ pkt_duration=368640 pkt_duration_time=0.026122 pkt_pos=20053 pkt_size=418 -sample_fmt=s16p +sample_fmt=fltp nb_samples=1152 channels=2 channel_layout=stereo @@ -234,7 +240,7 @@ pkt_duration=368640 pkt_duration_time=0.026122 pkt_pos=20471 pkt_size=418 -sample_fmt=s16p +sample_fmt=fltp nb_samples=1152 channels=2 channel_layout=stereo @@ -253,7 +259,7 @@ pkt_duration=368640 pkt_duration_time=0.026122 pkt_pos=20889 pkt_size=418 -sample_fmt=s16p +sample_fmt=fltp nb_samples=1152 channels=2 channel_layout=stereo @@ -272,7 +278,7 @@ pkt_duration=368640 pkt_duration_time=0.026122 pkt_pos=21307 pkt_size=418 -sample_fmt=s16p +sample_fmt=fltp nb_samples=1152 channels=2 channel_layout=stereo @@ -291,7 +297,7 @@ pkt_duration=368640 pkt_duration_time=0.026122 pkt_pos=21725 pkt_size=418 -sample_fmt=s16p +sample_fmt=fltp nb_samples=1152 channels=2 channel_layout=stereo @@ -310,7 +316,7 @@ pkt_duration=368640 pkt_duration_time=0.026122 pkt_pos=22143 pkt_size=418 -sample_fmt=s16p +sample_fmt=fltp nb_samples=1152 channels=2 channel_layout=stereo @@ -329,7 +335,7 @@ pkt_duration=368640 pkt_duration_time=0.026122 pkt_pos=22561 pkt_size=418 -sample_fmt=s16p +sample_fmt=fltp nb_samples=1152 channels=2 channel_layout=stereo @@ -348,7 +354,7 @@ pkt_duration=368640 pkt_duration_time=0.026122 pkt_pos=22979 pkt_size=418 -sample_fmt=s16p +sample_fmt=fltp nb_samples=1152 channels=2 channel_layout=stereo @@ -367,7 +373,7 @@ pkt_duration=368640 pkt_duration_time=0.026122 pkt_pos=23397 pkt_size=418 -sample_fmt=s16p +sample_fmt=fltp nb_samples=1152 channels=2 channel_layout=stereo @@ -386,7 +392,7 @@ pkt_duration=368640 pkt_duration_time=0.026122 pkt_pos=23815 pkt_size=418 -sample_fmt=s16p +sample_fmt=fltp nb_samples=1152 channels=2 channel_layout=stereo @@ -405,7 +411,7 @@ pkt_duration=368640 pkt_duration_time=0.026122 pkt_pos=24233 pkt_size=418 -sample_fmt=s16p +sample_fmt=fltp nb_samples=1152 channels=2 channel_layout=stereo @@ -424,7 +430,7 @@ pkt_duration=368640 pkt_duration_time=0.026122 pkt_pos=24651 pkt_size=418 -sample_fmt=s16p +sample_fmt=fltp nb_samples=1152 channels=2 channel_layout=stereo diff --git a/tests/ref/fate/exif-image-jpg b/tests/ref/fate/exif-image-jpg index b266501191bed..eb18dede21925 100644 --- a/tests/ref/fate/exif-image-jpg +++ b/tests/ref/fate/exif-image-jpg @@ -229,4 +229,10 @@ TAG:ExposureMode= 0 TAG:WhiteBalance= 0 TAG:DigitalZoomRatio= 4000:4000 TAG:SceneCaptureType= 0 +[SIDE_DATA] +side_data_type=QP table data +[/SIDE_DATA] +[SIDE_DATA] +side_data_type=QP table properties +[/SIDE_DATA] [/FRAME] diff --git a/tests/ref/fate/exr-rgba-zip16-16x32-flag4 b/tests/ref/fate/exr-rgba-zip16-16x32-flag4 new file mode 100644 index 0000000000000..e34aa711eab7f --- /dev/null +++ b/tests/ref/fate/exr-rgba-zip16-16x32-flag4 @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 16x32 +#sar 0: 1/1 +0, 0, 0, 1, 4096, 0xf90ab1e9 diff --git a/tests/ref/fate/ffmpeg-attached_pics b/tests/ref/fate/ffmpeg-attached_pics new file mode 100644 index 0000000000000..ee2f20638e6f8 --- /dev/null +++ b/tests/ref/fate/ffmpeg-attached_pics @@ -0,0 +1,140 @@ +#tb 0: 1/90000 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 200x200 +#sar 0: 2834/2834 +#tb 1: 1/44100 +#media_type 1: audio +#codec_id 1: pcm_s16le +#sample_rate 1: 44100 +#channel_layout 1: 3 +#channel_layout_name 1: stereo +0, 0, 0, 0, 120000, 0x748cc771 +1, 0, 0, 4096, 16384, 0x00000000 +1, 4096, 4096, 4096, 16384, 0x29cd639d +1, 8192, 8192, 4096, 16384, 0xd52066e5 +1, 12288, 12288, 4096, 16384, 0x0c933408 +1, 16384, 16384, 4096, 16384, 0xb3b97675 +1, 20480, 20480, 4096, 16384, 0x1cb4a26b +1, 24576, 24576, 4096, 16384, 0x6bf693b9 +1, 28672, 28672, 4096, 16384, 0x12896c95 +1, 32768, 32768, 4096, 16384, 0x48b7167a +1, 36864, 36864, 4096, 16384, 0x5a9c06ad +1, 40960, 40960, 4096, 16384, 0x42fa8e65 +1, 45056, 45056, 4096, 16384, 0x175e6a61 +1, 49152, 49152, 4096, 16384, 0x3cd0e606 +1, 53248, 53248, 4096, 16384, 0x5ceff67d +1, 57344, 57344, 4096, 16384, 0xa24ba733 +1, 61440, 61440, 4096, 16384, 0xafe61a2d +1, 65536, 65536, 4096, 16384, 0xef8355f1 +1, 69632, 69632, 4096, 16384, 0x8e53cb7c +1, 73728, 73728, 4096, 16384, 0x461bb940 +1, 77824, 77824, 4096, 16384, 0x96bb6ebd +1, 81920, 81920, 4096, 16384, 0xb99977dc +1, 86016, 86016, 4096, 16384, 0xa6b6a178 +1, 90112, 90112, 4096, 16384, 0x7bdc3e50 +1, 94208, 94208, 4096, 16384, 0x44cda519 +1, 98304, 98304, 4096, 16384, 0xbdfd2e72 +1, 102400, 102400, 4096, 16384, 0x5c09dc3c +1, 106496, 106496, 4096, 16384, 0xe5aabb75 +1, 110592, 110592, 4096, 16384, 0x5db83fb2 +1, 114688, 114688, 4096, 16384, 0x69a6e3c0 +1, 118784, 118784, 4096, 16384, 0x0c09a90d +1, 122880, 122880, 4096, 16384, 0x978d2b50 +1, 126976, 126976, 4096, 16384, 0x9707fbaa +1, 131072, 131072, 4096, 16384, 0x8003f93b +1, 135168, 135168, 4096, 16384, 0xaa12ab0c +1, 139264, 139264, 4096, 16384, 0x49980501 +1, 143360, 143360, 4096, 16384, 0xdcb891db +1, 147456, 147456, 4096, 16384, 0x52b76938 +1, 151552, 151552, 4096, 16384, 0x7cb55457 +1, 155648, 155648, 4096, 16384, 0x6b08b7d2 +1, 159744, 159744, 4096, 16384, 0xb56bb312 +1, 163840, 163840, 4096, 16384, 0xcbf9d3e0 +1, 167936, 167936, 4096, 16384, 0xe8958c07 +1, 172032, 172032, 4096, 16384, 0x054ac021 +1, 176128, 176128, 4096, 16384, 0x36811603 +1, 180224, 180224, 4096, 16384, 0x3354f6e1 +1, 184320, 184320, 4096, 16384, 0xa6c11686 +1, 188416, 188416, 4096, 16384, 0xed353877 +1, 192512, 192512, 4096, 16384, 0xef21373e +1, 196608, 196608, 4096, 16384, 0x31c806d9 +1, 200704, 200704, 4096, 16384, 0x3c1c79d4 +1, 204800, 204800, 4096, 16384, 0x1b7b3d9a +1, 208896, 208896, 4096, 16384, 0x08977239 +1, 212992, 212992, 4096, 16384, 0x07f9d169 +1, 217088, 217088, 4096, 16384, 0xa66ae19a +1, 221184, 221184, 4096, 16384, 0x42f51169 +1, 225280, 225280, 4096, 16384, 0x98ff59b6 +1, 229376, 229376, 4096, 16384, 0x855216b9 +1, 233472, 233472, 4096, 16384, 0x0986573d +1, 237568, 237568, 4096, 16384, 0x060aeffe +1, 241664, 241664, 4096, 16384, 0x391c19bc +1, 245760, 245760, 4096, 16384, 0x9939c472 +1, 249856, 249856, 4096, 16384, 0x4e0d31c5 +1, 253952, 253952, 4096, 16384, 0xed2678a6 +1, 258048, 258048, 4096, 16384, 0xfd899fc3 +1, 262144, 262144, 4096, 16384, 0x35cf5263 +1, 266240, 266240, 4096, 16384, 0xa2e35dad +1, 270336, 270336, 4096, 16384, 0xf9ed08a0 +1, 274432, 274432, 4096, 16384, 0x022d9356 +1, 278528, 278528, 4096, 16384, 0x508042f7 +1, 282624, 282624, 4096, 16384, 0xe2e7e70b +1, 286720, 286720, 4096, 16384, 0x30812bfd +1, 290816, 290816, 4096, 16384, 0x5590ea7d +1, 294912, 294912, 4096, 16384, 0xebaa4fc4 +1, 299008, 299008, 4096, 16384, 0x731cee53 +1, 303104, 303104, 4096, 16384, 0x1127b480 +1, 307200, 307200, 4096, 16384, 0x0809f7c8 +1, 311296, 311296, 4096, 16384, 0xc0d4256f +1, 315392, 315392, 4096, 16384, 0xe868795c +1, 319488, 319488, 4096, 16384, 0x801a77d1 +1, 323584, 323584, 4096, 16384, 0x1d44bed5 +1, 327680, 327680, 4096, 16384, 0x7619f16b +1, 331776, 331776, 4096, 16384, 0x301064b6 +1, 335872, 335872, 4096, 16384, 0x42f3e0fb +1, 339968, 339968, 4096, 16384, 0xfe186dc6 +1, 344064, 344064, 4096, 16384, 0x1a9bbbab +1, 348160, 348160, 4096, 16384, 0x3c4e00a8 +1, 352256, 352256, 4096, 16384, 0x3101c84e +1, 356352, 356352, 4096, 16384, 0x11a6c764 +1, 360448, 360448, 4096, 16384, 0xb75e82a1 +1, 364544, 364544, 4096, 16384, 0x81e3b3dd +1, 368640, 368640, 4096, 16384, 0x2656fc8e +1, 372736, 372736, 4096, 16384, 0x6c655f40 +1, 376832, 376832, 4096, 16384, 0xba0432f9 +1, 380928, 380928, 4096, 16384, 0x7028ee57 +1, 385024, 385024, 4096, 16384, 0x16baf6ed +1, 389120, 389120, 4096, 16384, 0x863bcff5 +1, 393216, 393216, 4096, 16384, 0x4dbce87e +1, 397312, 397312, 4096, 16384, 0x825e268c +1, 401408, 401408, 4096, 16384, 0xfe269f0a +1, 405504, 405504, 4096, 16384, 0x47b9c0ef +1, 409600, 409600, 4096, 16384, 0xbbe55aac +1, 413696, 413696, 4096, 16384, 0xeb0674a7 +1, 417792, 417792, 4096, 16384, 0x01afba1b +1, 421888, 421888, 4096, 16384, 0x5ec18306 +1, 425984, 425984, 4096, 16384, 0x6d0b844f +1, 430080, 430080, 4096, 16384, 0x6cd1bea2 +1, 434176, 434176, 4096, 16384, 0x97e47cbb +1, 438272, 438272, 4096, 16384, 0xbb6bf554 +1, 442368, 442368, 4096, 16384, 0x33ea7961 +1, 446464, 446464, 4096, 16384, 0x83ce2f2a +1, 450560, 450560, 4096, 16384, 0x3bed9e0d +1, 454656, 454656, 4096, 16384, 0xd3a9570a +1, 458752, 458752, 4096, 16384, 0x4d5e1aca +1, 462848, 462848, 4096, 16384, 0x874a9b11 +1, 466944, 466944, 4096, 16384, 0xe51061d8 +1, 471040, 471040, 4096, 16384, 0x3582fac4 +1, 475136, 475136, 4096, 16384, 0x35df558e +1, 479232, 479232, 4096, 16384, 0xe2485fed +1, 483328, 483328, 4096, 16384, 0x31f9c6a7 +1, 487424, 487424, 4096, 16384, 0x0a82b244 +1, 491520, 491520, 4096, 16384, 0xfbb428f4 +1, 495616, 495616, 4096, 16384, 0x57b90bb6 +1, 499712, 499712, 4096, 16384, 0x5c6daa1a +1, 503808, 503808, 4096, 16384, 0xe02ac113 +1, 507904, 507904, 4096, 16384, 0x47ed59b6 +1, 512000, 512000, 4096, 16384, 0x220e4bd3 +1, 516096, 516096, 4096, 16384, 0x65de48b1 +1, 520192, 520192, 4085, 16340, 0x326fa751 diff --git a/tests/ref/fate/ffmpeg-filter_complex_audio b/tests/ref/fate/ffmpeg-filter_complex_audio new file mode 100644 index 0000000000000..c4246750610d0 --- /dev/null +++ b/tests/ref/fate/ffmpeg-filter_complex_audio @@ -0,0 +1,10 @@ +#tb 0: 1/44100 +#media_type 0: audio +#codec_id 0: ac3 +#sample_rate 0: 44100 +#channel_layout 0: 4 +#channel_layout_name 0: mono +0, -256, -256, 1536, 416, 0x3001fb2d +0, 1280, 1280, 1536, 418, 0xba72fc16 +0, 2816, 2816, 1536, 418, 0xba72fc16 +0, 4352, 4352, 1536, 418, 0xba72fc16 diff --git a/tests/ref/fate/fifo-muxer-tst b/tests/ref/fate/fifo-muxer-tst index ca7e294860eac..e1139ee0a81c0 100644 --- a/tests/ref/fate/fifo-muxer-tst +++ b/tests/ref/fate/fifo-muxer-tst @@ -2,7 +2,6 @@ flush count: 1 pts seen nr: 15 pts seen: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14 nonfail test: ok -write header error test: ok recovery test: ok flush count: 1 pts seen nr: 15 diff --git a/tests/ref/fate/filter-acrossfade b/tests/ref/fate/filter-acrossfade index 0567b022e873c..8d524c4d2e8e4 100644 --- a/tests/ref/fate/filter-acrossfade +++ b/tests/ref/fate/filter-acrossfade @@ -178,7 +178,8 @@ 0, 174968, 174968, 1024, 4096, 0x74ffeeae 0, 175992, 175992, 408, 1632, 0x28353dae 0, 176400, 176400, 88200, 352800, 0x4fb492af -0, 264600, 264600, 1912, 7648, 0xf0c93a5a +0, 264600, 264600, 888, 3552, 0xa5a41b07 +0, 265488, 265488, 1024, 4096, 0xc1c61f53 0, 266512, 266512, 1024, 4096, 0x35b6d595 0, 267536, 267536, 1024, 4096, 0xc4481118 0, 268560, 268560, 1024, 4096, 0x5dc0b58d diff --git a/tests/ref/fate/filter-formats b/tests/ref/fate/filter-formats index ea85eed23d3f9..17ff5b222f12f 100644 --- a/tests/ref/fate/filter-formats +++ b/tests/ref/fate/filter-formats @@ -75,7 +75,7 @@ quad(side) 0 = ff_parse_channel_layout(0000000000000004, 1, 1c); 0 = ff_parse_channel_layout(0000000000000003, 2, 2c); -1 = ff_parse_channel_layout(FFFFFFFFFFFFFFFF, -1, -1c); -0 = ff_parse_channel_layout(0000000000000000, 60, 60c); +-1 = ff_parse_channel_layout(FFFFFFFFFFFFFFFF, -1, 60c); -1 = ff_parse_channel_layout(FFFFFFFFFFFFFFFF, -1, 65c); 0 = ff_parse_channel_layout(0000000000000000, 2, 2C); 0 = ff_parse_channel_layout(0000000000000000, 60, 60C); diff --git a/tests/ref/fate/filter-fps-down b/tests/ref/fate/filter-fps-down new file mode 100644 index 0000000000000..eb8b36898548b --- /dev/null +++ b/tests/ref/fate/filter-fps-down @@ -0,0 +1,15 @@ +#tb 0: 1/3 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x240 +#sar 0: 1/1 +0, 0, 0, 1, 115200, 0x0c1062d6 +0, 1, 1, 1, 115200, 0x278d887e +0, 2, 2, 1, 115200, 0x75e1a17b +0, 3, 3, 1, 115200, 0x686b77e7 +0, 4, 4, 1, 115200, 0x1fc2d693 +0, 5, 5, 1, 115200, 0x2d0ba5a4 +0, 6, 6, 1, 115200, 0x40426f99 +0, 7, 7, 1, 115200, 0xc705ccd9 +0, 8, 8, 1, 115200, 0x5635daa5 +0, 9, 9, 1, 115200, 0x7161ef8f diff --git a/tests/ref/fate/filter-fps-down-eof-pass b/tests/ref/fate/filter-fps-down-eof-pass new file mode 100644 index 0000000000000..0b6725f0376e4 --- /dev/null +++ b/tests/ref/fate/filter-fps-down-eof-pass @@ -0,0 +1,16 @@ +#tb 0: 1/3 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x240 +#sar 0: 1/1 +0, 0, 0, 1, 115200, 0x0c1062d6 +0, 1, 1, 1, 115200, 0x278d887e +0, 2, 2, 1, 115200, 0x75e1a17b +0, 3, 3, 1, 115200, 0x686b77e7 +0, 4, 4, 1, 115200, 0x1fc2d693 +0, 5, 5, 1, 115200, 0x2d0ba5a4 +0, 6, 6, 1, 115200, 0x40426f99 +0, 7, 7, 1, 115200, 0xc705ccd9 +0, 8, 8, 1, 115200, 0x5635daa5 +0, 9, 9, 1, 115200, 0x7161ef8f +0, 10, 10, 1, 115200, 0xccf02fed diff --git a/tests/ref/fate/filter-fps-down-round-down b/tests/ref/fate/filter-fps-down-round-down new file mode 100644 index 0000000000000..4440539b6fddb --- /dev/null +++ b/tests/ref/fate/filter-fps-down-round-down @@ -0,0 +1,15 @@ +#tb 0: 1/3 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x240 +#sar 0: 1/1 +0, 0, 0, 1, 115200, 0x201b9db1 +0, 1, 1, 1, 115200, 0x309b9c06 +0, 2, 2, 1, 115200, 0xa14e9aca +0, 3, 3, 1, 115200, 0x02b6ab21 +0, 4, 4, 1, 115200, 0x296dd4a5 +0, 5, 5, 1, 115200, 0x59e85f83 +0, 6, 6, 1, 115200, 0xf040bf35 +0, 7, 7, 1, 115200, 0xa76dcd9d +0, 8, 8, 1, 115200, 0x3af5d306 +0, 9, 9, 1, 115200, 0xc8ce7fb1 diff --git a/tests/ref/fate/filter-fps-down-round-up b/tests/ref/fate/filter-fps-down-round-up new file mode 100644 index 0000000000000..c3cf02fd24fae --- /dev/null +++ b/tests/ref/fate/filter-fps-down-round-up @@ -0,0 +1,16 @@ +#tb 0: 1/3 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x240 +#sar 0: 1/1 +0, 0, 0, 1, 115200, 0x3744b3ed +0, 1, 1, 1, 115200, 0x201b9db1 +0, 2, 2, 1, 115200, 0x309b9c06 +0, 3, 3, 1, 115200, 0xb73857e2 +0, 4, 4, 1, 115200, 0x02b6ab21 +0, 5, 5, 1, 115200, 0x296dd4a5 +0, 6, 6, 1, 115200, 0xc95a675e +0, 7, 7, 1, 115200, 0xf040bf35 +0, 8, 8, 1, 115200, 0xa76dcd9d +0, 9, 9, 1, 115200, 0x0caf7172 +0, 10, 10, 1, 115200, 0xc8ce7fb1 diff --git a/tests/ref/fate/filter-fps-start-drop b/tests/ref/fate/filter-fps-start-drop new file mode 100644 index 0000000000000..cfa1c40997bbc --- /dev/null +++ b/tests/ref/fate/filter-fps-start-drop @@ -0,0 +1,11 @@ +#tb 0: 1/3 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x240 +#sar 0: 1/1 +0, 5, 5, 1, 115200, 0x2d0ba5a4 +0, 6, 6, 1, 115200, 0xc95a675e +0, 7, 7, 1, 115200, 0xf040bf35 +0, 8, 8, 1, 115200, 0x5635daa5 +0, 9, 9, 1, 115200, 0x0caf7172 +0, 10, 10, 1, 115200, 0xc8ce7fb1 diff --git a/tests/ref/fate/filter-fps-start-fill b/tests/ref/fate/filter-fps-start-fill new file mode 100644 index 0000000000000..c5efb42a8f7b3 --- /dev/null +++ b/tests/ref/fate/filter-fps-start-fill @@ -0,0 +1,11 @@ +#tb 0: 1/3 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x240 +#sar 0: 1/1 +0, 5, 5, 1, 115200, 0x3744b3ed +0, 6, 6, 1, 115200, 0x3744b3ed +0, 7, 7, 1, 115200, 0x201b9db1 +0, 8, 8, 1, 115200, 0x75e1a17b +0, 9, 9, 1, 115200, 0xb73857e2 +0, 10, 10, 1, 115200, 0x02b6ab21 diff --git a/tests/ref/fate/filter-fps-up b/tests/ref/fate/filter-fps-up new file mode 100644 index 0000000000000..f1a847864fab3 --- /dev/null +++ b/tests/ref/fate/filter-fps-up @@ -0,0 +1,17 @@ +#tb 0: 1/7 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x240 +#sar 0: 1/1 +0, 0, 0, 1, 115200, 0x3744b3ed +0, 1, 1, 1, 115200, 0x3744b3ed +0, 2, 2, 1, 115200, 0x60a58f35 +0, 3, 3, 1, 115200, 0x60a58f35 +0, 4, 4, 1, 115200, 0x60a58f35 +0, 5, 5, 1, 115200, 0x09ffa4e1 +0, 6, 6, 1, 115200, 0x09ffa4e1 +0, 7, 7, 1, 115200, 0x33f15918 +0, 8, 8, 1, 115200, 0x33f15918 +0, 9, 9, 1, 115200, 0xb0dfacf8 +0, 10, 10, 1, 115200, 0xb0dfacf8 +0, 11, 11, 1, 115200, 0xb0dfacf8 diff --git a/tests/ref/fate/filter-fps-up-round-down b/tests/ref/fate/filter-fps-up-round-down new file mode 100644 index 0000000000000..daecb125e3d00 --- /dev/null +++ b/tests/ref/fate/filter-fps-up-round-down @@ -0,0 +1,16 @@ +#tb 0: 1/7 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x240 +#sar 0: 1/1 +0, 0, 0, 1, 115200, 0x3744b3ed +0, 1, 1, 1, 115200, 0x3744b3ed +0, 2, 2, 1, 115200, 0x60a58f35 +0, 3, 3, 1, 115200, 0x60a58f35 +0, 4, 4, 1, 115200, 0x09ffa4e1 +0, 5, 5, 1, 115200, 0x09ffa4e1 +0, 6, 6, 1, 115200, 0x09ffa4e1 +0, 7, 7, 1, 115200, 0x33f15918 +0, 8, 8, 1, 115200, 0x33f15918 +0, 9, 9, 1, 115200, 0xb0dfacf8 +0, 10, 10, 1, 115200, 0xb0dfacf8 diff --git a/tests/ref/fate/filter-fps-up-round-up b/tests/ref/fate/filter-fps-up-round-up new file mode 100644 index 0000000000000..d69dbf67ffd04 --- /dev/null +++ b/tests/ref/fate/filter-fps-up-round-up @@ -0,0 +1,17 @@ +#tb 0: 1/7 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x240 +#sar 0: 1/1 +0, 0, 0, 1, 115200, 0x3744b3ed +0, 1, 1, 1, 115200, 0x3744b3ed +0, 2, 2, 1, 115200, 0x3744b3ed +0, 3, 3, 1, 115200, 0x60a58f35 +0, 4, 4, 1, 115200, 0x60a58f35 +0, 5, 5, 1, 115200, 0x09ffa4e1 +0, 6, 6, 1, 115200, 0x09ffa4e1 +0, 7, 7, 1, 115200, 0x33f15918 +0, 8, 8, 1, 115200, 0x33f15918 +0, 9, 9, 1, 115200, 0x33f15918 +0, 10, 10, 1, 115200, 0xb0dfacf8 +0, 11, 11, 1, 115200, 0xb0dfacf8 diff --git a/tests/ref/fate/filter-framerate-12bit-down b/tests/ref/fate/filter-framerate-12bit-down new file mode 100644 index 0000000000000..25a3c0a53a7af --- /dev/null +++ b/tests/ref/fate/filter-framerate-12bit-down @@ -0,0 +1,55 @@ +#tb 0: 1/50 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x240 +#sar 0: 1/1 +0, 0, 0, 1, 307200, 0xb49cf016 +0, 1, 1, 1, 307200, 0xbccf696d +0, 2, 2, 1, 307200, 0x709c8dd1 +0, 3, 3, 1, 307200, 0xb948d907 +0, 4, 4, 1, 307200, 0x850f849a +0, 5, 5, 1, 307200, 0xaf71e7fc +0, 6, 6, 1, 307200, 0x0a1ba486 +0, 7, 7, 1, 307200, 0x0601f62a +0, 8, 8, 1, 307200, 0x2c6d3a59 +0, 9, 9, 1, 307200, 0xed03597b +0, 10, 10, 1, 307200, 0x9f84df5d +0, 11, 11, 1, 307200, 0x9fbe8c84 +0, 12, 12, 1, 307200, 0x8f7bc394 +0, 13, 13, 1, 307200, 0x5113c787 +0, 14, 14, 1, 307200, 0x41e8002f +0, 15, 15, 1, 307200, 0xab2162fc +0, 16, 16, 1, 307200, 0xbf8f847c +0, 17, 17, 1, 307200, 0x832d9ef7 +0, 18, 18, 1, 307200, 0xd2f5e043 +0, 19, 19, 1, 307200, 0xceeaddb8 +0, 20, 20, 1, 307200, 0xf2b12fe5 +0, 21, 21, 1, 307200, 0xf3477e11 +0, 22, 22, 1, 307200, 0xdf387773 +0, 23, 23, 1, 307200, 0x273be7e2 +0, 24, 24, 1, 307200, 0x68cd0360 +0, 25, 25, 1, 307200, 0x4693ab03 +0, 26, 26, 1, 307200, 0xe2baef73 +0, 27, 27, 1, 307200, 0x0c9fa60a +0, 28, 28, 1, 307200, 0x6e4ddbc5 +0, 29, 29, 1, 307200, 0xd1b2353c +0, 30, 30, 1, 307200, 0x8a512668 +0, 31, 31, 1, 307200, 0x7224b439 +0, 32, 32, 1, 307200, 0x7a9243e2 +0, 33, 33, 1, 307200, 0x9a7e4553 +0, 34, 34, 1, 307200, 0x4d795626 +0, 35, 35, 1, 307200, 0x4e24d659 +0, 36, 36, 1, 307200, 0xa230b54b +0, 37, 37, 1, 307200, 0x14598ea5 +0, 38, 38, 1, 307200, 0x21619cf3 +0, 39, 39, 1, 307200, 0x5220a167 +0, 40, 40, 1, 307200, 0xb6505ff0 +0, 41, 41, 1, 307200, 0x0a482a3d +0, 42, 42, 1, 307200, 0x6bdce40c +0, 43, 43, 1, 307200, 0x3c6074f3 +0, 44, 44, 1, 307200, 0x369c71c8 +0, 45, 45, 1, 307200, 0x4fda2634 +0, 46, 46, 1, 307200, 0x4df2d619 +0, 47, 47, 1, 307200, 0x21205aab +0, 48, 48, 1, 307200, 0xe00f48c2 +0, 49, 49, 1, 307200, 0xe3b11798 diff --git a/tests/ref/fate/filter-framerate-12bit-up b/tests/ref/fate/filter-framerate-12bit-up new file mode 100644 index 0000000000000..15bf9be6f6403 --- /dev/null +++ b/tests/ref/fate/filter-framerate-12bit-up @@ -0,0 +1,65 @@ +#tb 0: 1/60 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x240 +#sar 0: 1/1 +0, 0, 0, 1, 307200, 0xb49cf016 +0, 1, 1, 1, 307200, 0x95d191b2 +0, 2, 2, 1, 307200, 0x20e5173b +0, 3, 3, 1, 307200, 0x5378b13c +0, 4, 4, 1, 307200, 0x3e304543 +0, 5, 5, 1, 307200, 0x2f131cdb +0, 6, 6, 1, 307200, 0x83dbe321 +0, 7, 7, 1, 307200, 0xb81fc682 +0, 8, 8, 1, 307200, 0xb32a8644 +0, 9, 9, 1, 307200, 0xc5c8b0f8 +0, 10, 10, 1, 307200, 0x27945d0a +0, 11, 11, 1, 307200, 0x444c7640 +0, 12, 12, 1, 307200, 0xcba4c6bb +0, 13, 13, 1, 307200, 0xf923c7a3 +0, 14, 14, 1, 307200, 0x88149757 +0, 15, 15, 1, 307200, 0x4bdfd3ca +0, 16, 16, 1, 307200, 0x1c279695 +0, 17, 17, 1, 307200, 0x634cc809 +0, 18, 18, 1, 307200, 0xda8c6c41 +0, 19, 19, 1, 307200, 0x2136c986 +0, 20, 20, 1, 307200, 0x457576a8 +0, 21, 21, 1, 307200, 0xe2337c57 +0, 22, 22, 1, 307200, 0x8ed517c9 +0, 23, 23, 1, 307200, 0x4fd35f99 +0, 24, 24, 1, 307200, 0x4237e892 +0, 25, 25, 1, 307200, 0x1383a9d8 +0, 26, 26, 1, 307200, 0xc7195735 +0, 27, 27, 1, 307200, 0x0e058165 +0, 28, 28, 1, 307200, 0x0b81f345 +0, 29, 29, 1, 307200, 0x2ddf2f0a +0, 30, 30, 1, 307200, 0x0b58bcf7 +0, 31, 31, 1, 307200, 0x1b684a1d +0, 32, 32, 1, 307200, 0x1e44f1cf +0, 33, 33, 1, 307200, 0x3ed6b5d8 +0, 34, 34, 1, 307200, 0x00881a40 +0, 35, 35, 1, 307200, 0x2c3d1406 +0, 36, 36, 1, 307200, 0xbd67248a +0, 37, 37, 1, 307200, 0x46261913 +0, 38, 38, 1, 307200, 0xe5b2bbaa +0, 39, 39, 1, 307200, 0x0e4455cd +0, 40, 40, 1, 307200, 0xb4943212 +0, 41, 41, 1, 307200, 0xf96b6808 +0, 42, 42, 1, 307200, 0x58adad3f +0, 43, 43, 1, 307200, 0x978413f0 +0, 44, 44, 1, 307200, 0x0037320a +0, 45, 45, 1, 307200, 0xaac8e1ca +0, 46, 46, 1, 307200, 0xc3578407 +0, 47, 47, 1, 307200, 0xfc29c675 +0, 48, 48, 1, 307200, 0x22ed5b5a +0, 49, 49, 1, 307200, 0x6d58e21e +0, 50, 50, 1, 307200, 0xbf62b4c3 +0, 51, 51, 1, 307200, 0xbd5edb2d +0, 52, 52, 1, 307200, 0x55528432 +0, 53, 53, 1, 307200, 0xa3f1e514 +0, 54, 54, 1, 307200, 0xba073e6f +0, 55, 55, 1, 307200, 0x29b8df00 +0, 56, 56, 1, 307200, 0x1517512b +0, 57, 57, 1, 307200, 0x4e740b42 +0, 58, 58, 1, 307200, 0xbd6b7053 +0, 59, 59, 1, 307200, 0xe73f29ef diff --git a/tests/ref/fate/filter-framerate-up b/tests/ref/fate/filter-framerate-up index b2af9cb879df5..a276bf660dce6 100644 --- a/tests/ref/fate/filter-framerate-up +++ b/tests/ref/fate/filter-framerate-up @@ -4,12 +4,12 @@ #dimensions 0: 320x240 #sar 0: 1/1 0, 0, 0, 1, 115200, 0x3744b3ed -0, 1, 1, 1, 115200, 0xc44bdc65 +0, 1, 1, 1, 115200, 0xec1fdfa0 0, 2, 2, 1, 115200, 0xa17f0d74 -0, 3, 3, 1, 115200, 0xb0c83274 -0, 4, 4, 1, 115200, 0x232d6368 +0, 3, 3, 1, 115200, 0xd72532a9 +0, 4, 4, 1, 115200, 0x032e60f8 0, 5, 5, 1, 115200, 0x6e318ba0 -0, 6, 6, 1, 115200, 0x247e846e +0, 6, 6, 1, 115200, 0x76018292 0, 7, 7, 1, 115200, 0x89e27599 -0, 8, 8, 1, 115200, 0x31c5704e -0, 9, 9, 1, 115200, 0x97e45fec +0, 8, 8, 1, 115200, 0x68536eac +0, 9, 9, 1, 115200, 0xc3ac62a8 diff --git a/tests/ref/fate/filter-mcdeint-fast b/tests/ref/fate/filter-mcdeint-fast index 228be5e17d23e..e4c2f8a337895 100644 --- a/tests/ref/fate/filter-mcdeint-fast +++ b/tests/ref/fate/filter-mcdeint-fast @@ -3,33 +3,33 @@ #codec_id 0: rawvideo #dimensions 0: 720x576 #sar 0: 16/15 -0, 9, 9, 1, 622080, 0xb3b66c5c -0, 10, 10, 1, 622080, 0xc6568bd7 -0, 11, 11, 1, 622080, 0xa5b543c3 -0, 12, 12, 1, 622080, 0x4095ac51 -0, 13, 13, 1, 622080, 0xccd8c1d9 -0, 14, 14, 1, 622080, 0x84a88f22 -0, 15, 15, 1, 622080, 0x7273c26b -0, 16, 16, 1, 622080, 0xac188c41 -0, 17, 17, 1, 622080, 0xf32f6fb4 -0, 18, 18, 1, 622080, 0xd696ccce -0, 19, 19, 1, 622080, 0x9778a418 -0, 20, 20, 1, 622080, 0xf2b5be2e -0, 21, 21, 1, 622080, 0x653ee12a -0, 22, 22, 1, 622080, 0xe7fce188 -0, 23, 23, 1, 622080, 0x6e9f1deb -0, 24, 24, 1, 622080, 0x33090aac -0, 25, 25, 1, 622080, 0x840a57f1 -0, 26, 26, 1, 622080, 0x635e430a -0, 27, 27, 1, 622080, 0x52f98809 -0, 28, 28, 1, 622080, 0xc567b6a5 -0, 29, 29, 1, 622080, 0x4134f583 -0, 30, 30, 1, 622080, 0xd02a73bc -0, 31, 31, 1, 622080, 0x763085d6 -0, 32, 32, 1, 622080, 0x77fdc7a6 -0, 33, 33, 1, 622080, 0x77f71b9f -0, 34, 34, 1, 622080, 0x71c91244 -0, 35, 35, 1, 622080, 0xc7b86da5 -0, 36, 36, 1, 622080, 0x1edf8890 -0, 37, 37, 1, 622080, 0x03c82bec -0, 38, 38, 1, 622080, 0x148b6a04 +0, 9, 9, 1, 622080, 0xff496bf5 +0, 10, 10, 1, 622080, 0x513c8bd9 +0, 11, 11, 1, 622080, 0x4e474368 +0, 12, 12, 1, 622080, 0x1248abe9 +0, 13, 13, 1, 622080, 0xa705c158 +0, 14, 14, 1, 622080, 0xf9048e95 +0, 15, 15, 1, 622080, 0x78b5c1a2 +0, 16, 16, 1, 622080, 0x0efa8be8 +0, 17, 17, 1, 622080, 0xd3396eac +0, 18, 18, 1, 622080, 0x5870cbdd +0, 19, 19, 1, 622080, 0x086fa311 +0, 20, 20, 1, 622080, 0x7ce9bced +0, 21, 21, 1, 622080, 0xe7e0e0e1 +0, 22, 22, 1, 622080, 0x5af3e14b +0, 23, 23, 1, 622080, 0xbf221d96 +0, 24, 24, 1, 622080, 0x43d90a62 +0, 25, 25, 1, 622080, 0x267a57b6 +0, 26, 26, 1, 622080, 0x88d942eb +0, 27, 27, 1, 622080, 0x34ff87bf +0, 28, 28, 1, 622080, 0xa849b5ec +0, 29, 29, 1, 622080, 0x8302f51f +0, 30, 30, 1, 622080, 0xac9e7315 +0, 31, 31, 1, 622080, 0x38b284fc +0, 32, 32, 1, 622080, 0x1ff0c6c4 +0, 33, 33, 1, 622080, 0x50bf1ba5 +0, 34, 34, 1, 622080, 0xe9bd1240 +0, 35, 35, 1, 622080, 0x22116da3 +0, 36, 36, 1, 622080, 0x6f3e887a +0, 37, 37, 1, 622080, 0x46b82bc5 +0, 38, 38, 1, 622080, 0xeaaf69ee diff --git a/tests/ref/fate/filter-mcdeint-medium b/tests/ref/fate/filter-mcdeint-medium index 05d1d722f8778..1b0261960e466 100644 --- a/tests/ref/fate/filter-mcdeint-medium +++ b/tests/ref/fate/filter-mcdeint-medium @@ -3,33 +3,33 @@ #codec_id 0: rawvideo #dimensions 0: 720x576 #sar 0: 16/15 -0, 9, 9, 1, 622080, 0xb3b66c5c -0, 10, 10, 1, 622080, 0x26a29152 -0, 11, 11, 1, 622080, 0x787adddc -0, 12, 12, 1, 622080, 0xcc52df08 -0, 13, 13, 1, 622080, 0x53dad126 -0, 14, 14, 1, 622080, 0xe1448652 -0, 15, 15, 1, 622080, 0x159fd353 -0, 16, 16, 1, 622080, 0xcbe893a0 -0, 17, 17, 1, 622080, 0x43a67c6b -0, 18, 18, 1, 622080, 0xef30caf9 -0, 19, 19, 1, 622080, 0xa9cea62b -0, 20, 20, 1, 622080, 0x4c4cada1 -0, 21, 21, 1, 622080, 0x8e91f6de -0, 22, 22, 1, 622080, 0xb03ef044 -0, 23, 23, 1, 622080, 0x6b54262b -0, 24, 24, 1, 622080, 0x911e0cea -0, 25, 25, 1, 622080, 0x8320632c -0, 26, 26, 1, 622080, 0x2bde42b2 -0, 27, 27, 1, 622080, 0xe9d988c3 -0, 28, 28, 1, 622080, 0xa9f0b1db -0, 29, 29, 1, 622080, 0xb5bcf186 -0, 30, 30, 1, 622080, 0x469c6717 -0, 31, 31, 1, 622080, 0x2ca883e6 -0, 32, 32, 1, 622080, 0x4f5fba72 -0, 33, 33, 1, 622080, 0xa2e423ca -0, 34, 34, 1, 622080, 0xc1fb0aaf -0, 35, 35, 1, 622080, 0x96a879b8 -0, 36, 36, 1, 622080, 0x212e92e6 -0, 37, 37, 1, 622080, 0x9f26378a -0, 38, 38, 1, 622080, 0xdeaf77ab +0, 9, 9, 1, 622080, 0xff496bf5 +0, 10, 10, 1, 622080, 0xc0e4912c +0, 11, 11, 1, 622080, 0xa8aedd7e +0, 12, 12, 1, 622080, 0x2054deb9 +0, 13, 13, 1, 622080, 0x1005d0ca +0, 14, 14, 1, 622080, 0x60f085dc +0, 15, 15, 1, 622080, 0x4da0d261 +0, 16, 16, 1, 622080, 0x968e940e +0, 17, 17, 1, 622080, 0x86687b04 +0, 18, 18, 1, 622080, 0xd63bc93d +0, 19, 19, 1, 622080, 0x7ab0a6e6 +0, 20, 20, 1, 622080, 0x883dab85 +0, 21, 21, 1, 622080, 0x9f6ef6b5 +0, 22, 22, 1, 622080, 0xceccee25 +0, 23, 23, 1, 622080, 0x2aa823a5 +0, 24, 24, 1, 622080, 0xb20d0f48 +0, 25, 25, 1, 622080, 0x571560b9 +0, 26, 26, 1, 622080, 0xc0904764 +0, 27, 27, 1, 622080, 0xdb5b89c3 +0, 28, 28, 1, 622080, 0x707aadc5 +0, 29, 29, 1, 622080, 0x6383ef1b +0, 30, 30, 1, 622080, 0xf9e56040 +0, 31, 31, 1, 622080, 0x86ce7ff0 +0, 32, 32, 1, 622080, 0x0c76bd84 +0, 33, 33, 1, 622080, 0xd7192781 +0, 34, 34, 1, 622080, 0x83b70cdc +0, 35, 35, 1, 622080, 0xaae87453 +0, 36, 36, 1, 622080, 0xfafa92e2 +0, 37, 37, 1, 622080, 0x28323354 +0, 38, 38, 1, 622080, 0x34d47484 diff --git a/tests/ref/fate/filter-metadata-silencedetect b/tests/ref/fate/filter-metadata-silencedetect index 4161287e6c05f..16a9d07692514 100644 --- a/tests/ref/fate/filter-metadata-silencedetect +++ b/tests/ref/fate/filter-metadata-silencedetect @@ -1,512 +1,12 @@ -pkt_pts=0 -pkt_pts=320 -pkt_pts=640 -pkt_pts=960 -pkt_pts=1280 -pkt_pts=1600 -pkt_pts=1920|tag:lavfi.silence_start=0.02 -pkt_pts=2240 -pkt_pts=2560|tag:lavfi.silence_end=0.16|tag:lavfi.silence_duration=0.14 -pkt_pts=2880 -pkt_pts=3200 -pkt_pts=3520 -pkt_pts=3840 -pkt_pts=4160 -pkt_pts=4480 -pkt_pts=4800 -pkt_pts=5120 -pkt_pts=5440 -pkt_pts=5760|tag:lavfi.silence_start=0.26|tag:lavfi.silence_end=0.36|tag:lavfi.silence_duration=0.1 -pkt_pts=6080 -pkt_pts=6400 -pkt_pts=6720 -pkt_pts=7040 -pkt_pts=7360 -pkt_pts=7680 -pkt_pts=8000 -pkt_pts=8320 -pkt_pts=8640 -pkt_pts=8960 -pkt_pts=9280 -pkt_pts=9600 -pkt_pts=9920 -pkt_pts=10240 -pkt_pts=10560 -pkt_pts=10880 -pkt_pts=11200 -pkt_pts=11520 -pkt_pts=11840 -pkt_pts=12160 -pkt_pts=12480 -pkt_pts=12800 -pkt_pts=13120 -pkt_pts=13440 -pkt_pts=13760 -pkt_pts=14080 -pkt_pts=14400 -pkt_pts=14720 -pkt_pts=15040 -pkt_pts=15360 -pkt_pts=15680 -pkt_pts=16000 -pkt_pts=16320 -pkt_pts=16640 -pkt_pts=16960 -pkt_pts=17280 -pkt_pts=17600 -pkt_pts=17920 -pkt_pts=18240 -pkt_pts=18560 -pkt_pts=18880 -pkt_pts=19200 -pkt_pts=19520 -pkt_pts=19840 -pkt_pts=20160 -pkt_pts=20480 -pkt_pts=20800 -pkt_pts=21120 -pkt_pts=21440 -pkt_pts=21760 -pkt_pts=22080|tag:lavfi.silence_start=1.28 -pkt_pts=22400 -pkt_pts=22720 -pkt_pts=23040 -pkt_pts=23360 -pkt_pts=23680 -pkt_pts=24000 -pkt_pts=24320 -pkt_pts=24640 -pkt_pts=24960 -pkt_pts=25280 -pkt_pts=25600 -pkt_pts=25920 -pkt_pts=26240 -pkt_pts=26560 -pkt_pts=26880 -pkt_pts=27200 -pkt_pts=27520 -pkt_pts=27840 -pkt_pts=28160 -pkt_pts=28480 -pkt_pts=28800 -pkt_pts=29120 -pkt_pts=29440 -pkt_pts=29760 -pkt_pts=30080 -pkt_pts=30400 -pkt_pts=30720 -pkt_pts=31040 -pkt_pts=31360 -pkt_pts=31680|tag:lavfi.silence_end=1.98|tag:lavfi.silence_duration=0.7 -pkt_pts=32000 -pkt_pts=32320 -pkt_pts=32640 -pkt_pts=32960 -pkt_pts=33280 -pkt_pts=33600 -pkt_pts=33920 -pkt_pts=34240 -pkt_pts=34560 -pkt_pts=34880 -pkt_pts=35200 -pkt_pts=35520 -pkt_pts=35840 -pkt_pts=36160 -pkt_pts=36480 -pkt_pts=36800 -pkt_pts=37120 -pkt_pts=37440 -pkt_pts=37760 -pkt_pts=38080 -pkt_pts=38400 -pkt_pts=38720 -pkt_pts=39040 -pkt_pts=39360 -pkt_pts=39680 -pkt_pts=40000 -pkt_pts=40320 -pkt_pts=40640 -pkt_pts=40960 -pkt_pts=41280 -pkt_pts=41600 -pkt_pts=41920 -pkt_pts=42240 -pkt_pts=42560 -pkt_pts=42880 -pkt_pts=43200 -pkt_pts=43520 -pkt_pts=43840 -pkt_pts=44160 -pkt_pts=44480 -pkt_pts=44800 -pkt_pts=45120 -pkt_pts=45440 -pkt_pts=45760 -pkt_pts=46080 -pkt_pts=46400 -pkt_pts=46720 -pkt_pts=47040 -pkt_pts=47360 -pkt_pts=47680 -pkt_pts=48000 -pkt_pts=48320 -pkt_pts=48640 -pkt_pts=48960 -pkt_pts=49280 -pkt_pts=49600 -pkt_pts=49920 -pkt_pts=50240 -pkt_pts=50560 -pkt_pts=50880 -pkt_pts=51200 -pkt_pts=51520 -pkt_pts=51840 -pkt_pts=52160 -pkt_pts=52480 -pkt_pts=52800|tag:lavfi.silence_start=3.2 -pkt_pts=53120 -pkt_pts=53440 -pkt_pts=53760 -pkt_pts=54080 -pkt_pts=54400 -pkt_pts=54720 -pkt_pts=55040 -pkt_pts=55360 -pkt_pts=55680 -pkt_pts=56000 -pkt_pts=56320 -pkt_pts=56640 -pkt_pts=56960 -pkt_pts=57280 -pkt_pts=57600 -pkt_pts=57920 -pkt_pts=58240 -pkt_pts=58560 -pkt_pts=58880 -pkt_pts=59200 -pkt_pts=59520 -pkt_pts=59840 -pkt_pts=60160 -pkt_pts=60480 -pkt_pts=60800 -pkt_pts=61120 -pkt_pts=61440 -pkt_pts=61760 -pkt_pts=62080 -pkt_pts=62400|tag:lavfi.silence_end=3.9|tag:lavfi.silence_duration=0.7 -pkt_pts=62720 -pkt_pts=63040 -pkt_pts=63360 -pkt_pts=63680 -pkt_pts=64000 -pkt_pts=64320 -pkt_pts=64640 -pkt_pts=64960 -pkt_pts=65280 -pkt_pts=65600 -pkt_pts=65920 -pkt_pts=66240 -pkt_pts=66560 -pkt_pts=66880 -pkt_pts=67200 -pkt_pts=67520 -pkt_pts=67840 -pkt_pts=68160 -pkt_pts=68480 -pkt_pts=68800 -pkt_pts=69120 -pkt_pts=69440 -pkt_pts=69760 -pkt_pts=70080 -pkt_pts=70400 -pkt_pts=70720 -pkt_pts=71040 -pkt_pts=71360 -pkt_pts=71680 -pkt_pts=72000 -pkt_pts=72320 -pkt_pts=72640 -pkt_pts=72960 -pkt_pts=73280 -pkt_pts=73600 -pkt_pts=73920 -pkt_pts=74240 -pkt_pts=74560 -pkt_pts=74880 -pkt_pts=75200 -pkt_pts=75520 -pkt_pts=75840 -pkt_pts=76160 -pkt_pts=76480 -pkt_pts=76800 -pkt_pts=77120 -pkt_pts=77440 -pkt_pts=77760 -pkt_pts=78080 -pkt_pts=78400 -pkt_pts=78720 -pkt_pts=79040 -pkt_pts=79360 -pkt_pts=79680 -pkt_pts=80000|tag:lavfi.silence_start=4.9 -pkt_pts=80320 -pkt_pts=80640 -pkt_pts=80960 -pkt_pts=81280 -pkt_pts=81600 -pkt_pts=81920 -pkt_pts=82240 -pkt_pts=82560 -pkt_pts=82880 -pkt_pts=83200 -pkt_pts=83520 -pkt_pts=83840 -pkt_pts=84160 -pkt_pts=84480 -pkt_pts=84800 -pkt_pts=85120 -pkt_pts=85440 -pkt_pts=85760 -pkt_pts=86080 -pkt_pts=86400 -pkt_pts=86720 -pkt_pts=87040|tag:lavfi.silence_end=5.44|tag:lavfi.silence_duration=0.54 -pkt_pts=87360 -pkt_pts=87680 -pkt_pts=88000 -pkt_pts=88320 -pkt_pts=88640 -pkt_pts=88960 -pkt_pts=89280 -pkt_pts=89600 -pkt_pts=89920 -pkt_pts=90240 -pkt_pts=90560 -pkt_pts=90880 -pkt_pts=91200 -pkt_pts=91520 -pkt_pts=91840 +pkt_pts=0|tag:lavfi.silence_duration=0.523107|tag:lavfi.silence_end=0.690023|tag:lavfi.silence_start=0.736417 +pkt_pts=46080|tag:lavfi.silence_start=1.27626|tag:lavfi.silence_end=1.80751|tag:lavfi.silence_duration=0.531247 pkt_pts=92160 -pkt_pts=92480 -pkt_pts=92800 -pkt_pts=93120 -pkt_pts=93440 -pkt_pts=93760 -pkt_pts=94080 -pkt_pts=94400 -pkt_pts=94720 -pkt_pts=95040 -pkt_pts=95360 -pkt_pts=95680 -pkt_pts=96000 -pkt_pts=96320 -pkt_pts=96640 -pkt_pts=96960 -pkt_pts=97280 -pkt_pts=97600 -pkt_pts=97920 -pkt_pts=98240 -pkt_pts=98560 -pkt_pts=98880 -pkt_pts=99200 -pkt_pts=99520 -pkt_pts=99840 -pkt_pts=100160 -pkt_pts=100480 -pkt_pts=100800 -pkt_pts=101120 -pkt_pts=101440 -pkt_pts=101760 -pkt_pts=102080 -pkt_pts=102400 -pkt_pts=102720 -pkt_pts=103040 -pkt_pts=103360 -pkt_pts=103680 -pkt_pts=104000 -pkt_pts=104320 -pkt_pts=104640|tag:lavfi.silence_start=6.44 -pkt_pts=104960 -pkt_pts=105280 -pkt_pts=105600 -pkt_pts=105920 -pkt_pts=106240 -pkt_pts=106560 -pkt_pts=106880 -pkt_pts=107200 -pkt_pts=107520 -pkt_pts=107840 -pkt_pts=108160 -pkt_pts=108480 -pkt_pts=108800 -pkt_pts=109120 -pkt_pts=109440 -pkt_pts=109760 -pkt_pts=110080 -pkt_pts=110400 -pkt_pts=110720 -pkt_pts=111040 -pkt_pts=111360 -pkt_pts=111680 -pkt_pts=112000 -pkt_pts=112320 -pkt_pts=112640 -pkt_pts=112960 -pkt_pts=113280 -pkt_pts=113600 -pkt_pts=113920 -pkt_pts=114240 -pkt_pts=114560 -pkt_pts=114880 -pkt_pts=115200 -pkt_pts=115520 -pkt_pts=115840 -pkt_pts=116160|tag:lavfi.silence_end=7.26|tag:lavfi.silence_duration=0.82 -pkt_pts=116480 -pkt_pts=116800 -pkt_pts=117120 -pkt_pts=117440 -pkt_pts=117760 -pkt_pts=118080 -pkt_pts=118400 -pkt_pts=118720 -pkt_pts=119040 -pkt_pts=119360 -pkt_pts=119680 -pkt_pts=120000 -pkt_pts=120320 -pkt_pts=120640 -pkt_pts=120960 -pkt_pts=121280 -pkt_pts=121600 -pkt_pts=121920 -pkt_pts=122240 -pkt_pts=122560 -pkt_pts=122880 -pkt_pts=123200 -pkt_pts=123520 -pkt_pts=123840 -pkt_pts=124160 -pkt_pts=124480 -pkt_pts=124800 -pkt_pts=125120 -pkt_pts=125440 -pkt_pts=125760 -pkt_pts=126080 -pkt_pts=126400 -pkt_pts=126720 -pkt_pts=127040 -pkt_pts=127360 -pkt_pts=127680 -pkt_pts=128000 -pkt_pts=128320 -pkt_pts=128640 -pkt_pts=128960 -pkt_pts=129280 -pkt_pts=129600 -pkt_pts=129920 -pkt_pts=130240 -pkt_pts=130560 -pkt_pts=130880 -pkt_pts=131200 -pkt_pts=131520 -pkt_pts=131840 -pkt_pts=132160 -pkt_pts=132480 -pkt_pts=132800 -pkt_pts=133120 -pkt_pts=133440 -pkt_pts=133760 -pkt_pts=134080 -pkt_pts=134400 -pkt_pts=134720 -pkt_pts=135040 -pkt_pts=135360 -pkt_pts=135680 -pkt_pts=136000 -pkt_pts=136320 -pkt_pts=136640 -pkt_pts=136960 -pkt_pts=137280 -pkt_pts=137600|tag:lavfi.silence_start=8.5 -pkt_pts=137920 pkt_pts=138240 -pkt_pts=138560 -pkt_pts=138880|tag:lavfi.silence_end=8.68|tag:lavfi.silence_duration=0.18 -pkt_pts=139200 -pkt_pts=139520 -pkt_pts=139840 -pkt_pts=140160 -pkt_pts=140480|tag:lavfi.silence_start=8.68 -pkt_pts=140800 -pkt_pts=141120 -pkt_pts=141440 -pkt_pts=141760 -pkt_pts=142080 -pkt_pts=142400 -pkt_pts=142720 -pkt_pts=143040 -pkt_pts=143360 -pkt_pts=143680|tag:lavfi.silence_end=8.98|tag:lavfi.silence_duration=0.3 -pkt_pts=144000 -pkt_pts=144320 -pkt_pts=144640 -pkt_pts=144960 -pkt_pts=145280 -pkt_pts=145600 -pkt_pts=145920 -pkt_pts=146240 -pkt_pts=146560 -pkt_pts=146880 -pkt_pts=147200 -pkt_pts=147520 -pkt_pts=147840 -pkt_pts=148160 -pkt_pts=148480 -pkt_pts=148800 -pkt_pts=149120 -pkt_pts=149440 -pkt_pts=149760 -pkt_pts=150080 -pkt_pts=150400 -pkt_pts=150720 -pkt_pts=151040 -pkt_pts=151360 -pkt_pts=151680 -pkt_pts=152000 -pkt_pts=152320 -pkt_pts=152640 -pkt_pts=152960 -pkt_pts=153280 -pkt_pts=153600 -pkt_pts=153920 -pkt_pts=154240 -pkt_pts=154560 -pkt_pts=154880 -pkt_pts=155200 -pkt_pts=155520 -pkt_pts=155840 -pkt_pts=156160 -pkt_pts=156480 -pkt_pts=156800 -pkt_pts=157120 -pkt_pts=157440 -pkt_pts=157760 -pkt_pts=158080 -pkt_pts=158400 -pkt_pts=158720 -pkt_pts=159040 -pkt_pts=159360 -pkt_pts=159680 -pkt_pts=160000 -pkt_pts=160320 -pkt_pts=160640 -pkt_pts=160960 -pkt_pts=161280 -pkt_pts=161600|tag:lavfi.silence_start=10 -pkt_pts=161920 -pkt_pts=162240 -pkt_pts=162560 -pkt_pts=162880 -pkt_pts=163200 -pkt_pts=163520 +pkt_pts=184320 +pkt_pts=230400 +pkt_pts=276480 +pkt_pts=322560 +pkt_pts=368640 +pkt_pts=414720 +pkt_pts=460800 +pkt_pts=506880 diff --git a/tests/ref/fate/filter-pan-mono1 b/tests/ref/fate/filter-pan-mono1 new file mode 100644 index 0000000000000..3bd7c25bc1f3c --- /dev/null +++ b/tests/ref/fate/filter-pan-mono1 @@ -0,0 +1,26 @@ +#tb 0: 1/44100 +#media_type 0: audio +#codec_id 0: pcm_s16le +#sample_rate 0: 44100 +#channel_layout 0: 4 +#channel_layout_name 0: mono +0, 0, 0, 1024, 2048, 0x750f0a66 +0, 1024, 1024, 1024, 2048, 0x155cf063 +0, 2048, 2048, 1024, 2048, 0x1e43fc32 +0, 3072, 3072, 1024, 2048, 0x282ffc28 +0, 4096, 4096, 1024, 2048, 0x6d7bf000 +0, 5120, 5120, 1024, 2048, 0xc0b2f411 +0, 6144, 6144, 1024, 2048, 0xd711fb03 +0, 7168, 7168, 1024, 2048, 0x3164189c +0, 8192, 8192, 1024, 2048, 0x8c69e827 +0, 9216, 9216, 1024, 2048, 0x562d0518 +0, 10240, 10240, 1024, 2048, 0x380aee27 +0, 11264, 11264, 1024, 2048, 0x990a03e4 +0, 12288, 12288, 1024, 2048, 0x68d7ef60 +0, 13312, 13312, 1024, 2048, 0xd13fef9e +0, 14336, 14336, 1024, 2048, 0x009306e4 +0, 15360, 15360, 1024, 2048, 0x51850390 +0, 16384, 16384, 1024, 2048, 0xcd3ceeae +0, 17408, 17408, 1024, 2048, 0x189ff277 +0, 18432, 18432, 1024, 2048, 0x4b98f68c +0, 19456, 19456, 1024, 2048, 0x34eaf544 diff --git a/tests/ref/fate/filter-pan-mono2 b/tests/ref/fate/filter-pan-mono2 new file mode 100644 index 0000000000000..0867ca9a1342f --- /dev/null +++ b/tests/ref/fate/filter-pan-mono2 @@ -0,0 +1,26 @@ +#tb 0: 1/44100 +#media_type 0: audio +#codec_id 0: pcm_s16le +#sample_rate 0: 44100 +#channel_layout 0: 0 +#channel_layout_name 0: 1 channels +0, 0, 0, 1024, 2048, 0x6130fb80 +0, 1024, 1024, 1024, 2048, 0xd5ef0930 +0, 2048, 2048, 1024, 2048, 0x40bce3f6 +0, 3072, 3072, 1024, 2048, 0x72e5d193 +0, 4096, 4096, 1024, 2048, 0xb005073f +0, 5120, 5120, 1024, 2048, 0xa323fdbe +0, 6144, 6144, 1024, 2048, 0xe5cbfe1e +0, 7168, 7168, 1024, 2048, 0x4b42fe79 +0, 8192, 8192, 1024, 2048, 0x384eedea +0, 9216, 9216, 1024, 2048, 0xe5cdf825 +0, 10240, 10240, 1024, 2048, 0xc2970ec0 +0, 11264, 11264, 1024, 2048, 0xa85fe5e0 +0, 12288, 12288, 1024, 2048, 0xfd51f2de +0, 13312, 13312, 1024, 2048, 0xa1aafe30 +0, 14336, 14336, 1024, 2048, 0x8770fea2 +0, 15360, 15360, 1024, 2048, 0x67c50d76 +0, 16384, 16384, 1024, 2048, 0x7772fbc8 +0, 17408, 17408, 1024, 2048, 0xc48eff54 +0, 18432, 18432, 1024, 2048, 0x2e14f359 +0, 19456, 19456, 1024, 2048, 0x2df70a60 diff --git a/tests/ref/fate/filter-pan-stereo1 b/tests/ref/fate/filter-pan-stereo1 new file mode 100644 index 0000000000000..3125d4e570a57 --- /dev/null +++ b/tests/ref/fate/filter-pan-stereo1 @@ -0,0 +1,26 @@ +#tb 0: 1/44100 +#media_type 0: audio +#codec_id 0: pcm_s16le +#sample_rate 0: 44100 +#channel_layout 0: 3 +#channel_layout_name 0: stereo +0, 0, 0, 682, 2728, 0xaf365458 +0, 682, 682, 682, 2728, 0xcd684898 +0, 1364, 1364, 682, 2728, 0x5d514ae5 +0, 2046, 2046, 682, 2728, 0x48cb4605 +0, 2728, 2728, 682, 2728, 0x76ac43ee +0, 3410, 3410, 682, 2728, 0x088355fa +0, 4092, 4092, 682, 2728, 0xf66f4efa +0, 4774, 4774, 682, 2728, 0x7efc3b1a +0, 5456, 5456, 682, 2728, 0x1c1745f3 +0, 6138, 6138, 682, 2728, 0x824d50fe +0, 6820, 6820, 682, 2728, 0xb26c5b94 +0, 7502, 7502, 682, 2728, 0x02d5636d +0, 8184, 8184, 682, 2728, 0x65e647de +0, 8866, 8866, 682, 2728, 0x93374812 +0, 9548, 9548, 682, 2728, 0xa0d55153 +0, 10230, 10230, 682, 2728, 0x56cf392c +0, 10912, 10912, 682, 2728, 0x554051c3 +0, 11594, 11594, 682, 2728, 0xbc3655ce +0, 12276, 12276, 682, 2728, 0xb432529f +0, 12958, 12958, 682, 2728, 0x64df52a7 diff --git a/tests/ref/fate/filter-pan-stereo2 b/tests/ref/fate/filter-pan-stereo2 new file mode 100644 index 0000000000000..7f96799e2c1a5 --- /dev/null +++ b/tests/ref/fate/filter-pan-stereo2 @@ -0,0 +1,26 @@ +#tb 0: 1/44100 +#media_type 0: audio +#codec_id 0: pcm_s16le +#sample_rate 0: 44100 +#channel_layout 0: 3 +#channel_layout_name 0: stereo +0, 0, 0, 682, 2728, 0x35c15e81 +0, 682, 682, 682, 2728, 0x770f2e2d +0, 1364, 1364, 682, 2728, 0x6f8d6d9f +0, 2046, 2046, 682, 2728, 0x5b9e46f3 +0, 2728, 2728, 682, 2728, 0xda7e5fdc +0, 3410, 3410, 682, 2728, 0x55e446f8 +0, 4092, 4092, 682, 2728, 0x4fcf4f8e +0, 4774, 4774, 682, 2728, 0x86e757b2 +0, 5456, 5456, 682, 2728, 0x8d4256e9 +0, 6138, 6138, 682, 2728, 0xa28d4e58 +0, 6820, 6820, 682, 2728, 0xacaa5738 +0, 7502, 7502, 682, 2728, 0xd1fe580f +0, 8184, 8184, 682, 2728, 0x09a05c0a +0, 8866, 8866, 682, 2728, 0xcaf2555d +0, 9548, 9548, 682, 2728, 0xcee159fc +0, 10230, 10230, 682, 2728, 0xaa3444a5 +0, 10912, 10912, 682, 2728, 0x23b76512 +0, 11594, 11594, 682, 2728, 0xef2243dd +0, 12276, 12276, 682, 2728, 0x36486118 +0, 12958, 12958, 682, 2728, 0xfd59626c diff --git a/tests/ref/fate/filter-pan-stereo3 b/tests/ref/fate/filter-pan-stereo3 new file mode 100644 index 0000000000000..effe11c785d49 --- /dev/null +++ b/tests/ref/fate/filter-pan-stereo3 @@ -0,0 +1,26 @@ +#tb 0: 1/44100 +#media_type 0: audio +#codec_id 0: pcm_s16le +#sample_rate 0: 44100 +#channel_layout 0: 3 +#channel_layout_name 0: stereo +0, 0, 0, 1024, 4096, 0xa0d1fbb3 +0, 1024, 1024, 1024, 4096, 0x598a056c +0, 2048, 2048, 1024, 4096, 0x741ded28 +0, 3072, 3072, 1024, 4096, 0xc651b0ec +0, 4096, 4096, 1024, 4096, 0x1082057c +0, 5120, 5120, 1024, 4096, 0x70f7f00d +0, 6144, 6144, 1024, 4096, 0xaed7fc53 +0, 7168, 7168, 1024, 4096, 0x4250faae +0, 8192, 8192, 1024, 4096, 0xf7fcf61a +0, 9216, 9216, 1024, 4096, 0xb1350562 +0, 10240, 10240, 1024, 4096, 0x16adea0b +0, 11264, 11264, 1024, 4096, 0x706fd834 +0, 12288, 12288, 1024, 4096, 0x5431dd24 +0, 13312, 13312, 1024, 4096, 0xfaedfb73 +0, 14336, 14336, 1024, 4096, 0xee3d07e2 +0, 15360, 15360, 1024, 4096, 0x2561eeb8 +0, 16384, 16384, 1024, 4096, 0x8f76fc05 +0, 17408, 17408, 1024, 4096, 0xef05f0a1 +0, 18432, 18432, 1024, 4096, 0x4e92f19a +0, 19456, 19456, 1024, 4096, 0x81b6e0bc diff --git a/tests/ref/fate/filter-pan-stereo4 b/tests/ref/fate/filter-pan-stereo4 new file mode 100644 index 0000000000000..87c70a7f1fccf --- /dev/null +++ b/tests/ref/fate/filter-pan-stereo4 @@ -0,0 +1,26 @@ +#tb 0: 1/44100 +#media_type 0: audio +#codec_id 0: pcm_s16le +#sample_rate 0: 44100 +#channel_layout 0: 0 +#channel_layout_name 0: 4 channels +0, 0, 0, 1024, 8192, 0xdaadfc44 +0, 1024, 1024, 1024, 8192, 0xe6d9ec37 +0, 2048, 2048, 1024, 8192, 0x5edfea64 +0, 3072, 3072, 1024, 8192, 0x7f7be38c +0, 4096, 4096, 1024, 8192, 0x3f60f5c9 +0, 5120, 5120, 1024, 8192, 0xcee4fe06 +0, 6144, 6144, 1024, 8192, 0xdb98fa3e +0, 7168, 7168, 1024, 8192, 0x4cb30687 +0, 8192, 8192, 1024, 8192, 0x00f6ecab +0, 9216, 9216, 1024, 8192, 0xa7b0e0db +0, 10240, 10240, 1024, 8192, 0xc2dcf89c +0, 11264, 11264, 1024, 8192, 0x30d6f2fe +0, 12288, 12288, 1024, 8192, 0xf83ae182 +0, 13312, 13312, 1024, 8192, 0xeecd05d1 +0, 14336, 14336, 1024, 8192, 0xfd3b0559 +0, 15360, 15360, 1024, 8192, 0xcd69e3e6 +0, 16384, 16384, 1024, 8192, 0xdf80fc29 +0, 17408, 17408, 1024, 8192, 0x7e8bf52b +0, 18432, 18432, 1024, 8192, 0xee07e5f7 +0, 19456, 19456, 1024, 8192, 0xc874f294 diff --git a/tests/ref/fate/filter-pixdesc-p016be b/tests/ref/fate/filter-pixdesc-p016be new file mode 100644 index 0000000000000..7c934079c8b36 --- /dev/null +++ b/tests/ref/fate/filter-pixdesc-p016be @@ -0,0 +1 @@ +pixdesc-p016be 784a49bf554861da9d0809a615bcf813 diff --git a/tests/ref/fate/filter-pixdesc-p016le b/tests/ref/fate/filter-pixdesc-p016le new file mode 100644 index 0000000000000..c723a0f1fd021 --- /dev/null +++ b/tests/ref/fate/filter-pixdesc-p016le @@ -0,0 +1 @@ +pixdesc-p016le ed04897de0a6788bb3458e7365f10d36 diff --git a/tests/ref/fate/filter-pixfmts-copy b/tests/ref/fate/filter-pixfmts-copy index 124dddeacbe6e..c45ce937b3777 100644 --- a/tests/ref/fate/filter-pixfmts-copy +++ b/tests/ref/fate/filter-pixfmts-copy @@ -51,6 +51,8 @@ nv12 8e24feb2c544dc26a20047a71e4c27aa nv21 335d85c9af6110f26ae9e187a82ed2cf p010be 7f9842d6015026136bad60d03c035cc3 p010le c453421b9f726bdaf2bacf59a492c43b +p016be 7f9842d6015026136bad60d03c035cc3 +p016le c453421b9f726bdaf2bacf59a492c43b pal8 ff5929f5b42075793b2c34cb441bede5 rgb0 0de71e5a1f97f81fb51397a0435bfa72 rgb24 f4438057d046e6d98ade4e45294b21be diff --git a/tests/ref/fate/filter-pixfmts-crop b/tests/ref/fate/filter-pixfmts-crop index e21479ceb0086..c5bb8a4135599 100644 --- a/tests/ref/fate/filter-pixfmts-crop +++ b/tests/ref/fate/filter-pixfmts-crop @@ -49,6 +49,8 @@ nv12 92cda427f794374731ec0321ee00caac nv21 1bcfc197f4fb95de85ba58182d8d2f69 p010be 8b2de2eb6b099bbf355bfc55a0694ddc p010le 373b50c766dfd0a8e79c9a73246d803a +p016be 8b2de2eb6b099bbf355bfc55a0694ddc +p016le 373b50c766dfd0a8e79c9a73246d803a pal8 1f2cdc8e718f95c875dbc1034a688bfb rgb0 736646b70dd9a0be22b8da8041e35035 rgb24 c5fbbf816bb2000f4d2914e335698ef5 diff --git a/tests/ref/fate/filter-pixfmts-field b/tests/ref/fate/filter-pixfmts-field index ba2af6e76fc44..df43ce693127b 100644 --- a/tests/ref/fate/filter-pixfmts-field +++ b/tests/ref/fate/filter-pixfmts-field @@ -51,6 +51,8 @@ nv12 16f7a46708ef25ebd0b72e47920cc11e nv21 7294574037cc7f9373ef5695d8ebe809 p010be a0311a09bba7383553267d2b3b9c075e p010le ee09a18aefa3ebe97715b3a7312cb8ff +p016be a0311a09bba7383553267d2b3b9c075e +p016le ee09a18aefa3ebe97715b3a7312cb8ff pal8 0658c18dcd8d052d59dfbe23f5b368d9 rgb0 ca3fa6e865b91b3511c7f2bf62830059 rgb24 25ab271e26a5785be169578d99da5dd0 diff --git a/tests/ref/fate/filter-pixfmts-hflip b/tests/ref/fate/filter-pixfmts-hflip index 875980d8928dd..a98314b0b3568 100644 --- a/tests/ref/fate/filter-pixfmts-hflip +++ b/tests/ref/fate/filter-pixfmts-hflip @@ -49,6 +49,8 @@ nv12 801e58f1be5fd0b5bc4bf007c604b0b4 nv21 9f10dfff8963dc327d3395af21f0554f p010be 744b13e44d39e1ff7588983fa03e0101 p010le a50b160346ab94f55a425065b57006f0 +p016be 744b13e44d39e1ff7588983fa03e0101 +p016le a50b160346ab94f55a425065b57006f0 pal8 5b7c77d99817b4f52339742a47de7797 rgb0 0092452f37d73da20193265ace0b7d57 rgb24 21571104e6091a689feabb7867e513dd diff --git a/tests/ref/fate/filter-pixfmts-il b/tests/ref/fate/filter-pixfmts-il index c6885b970ef42..3ed6c462266d9 100644 --- a/tests/ref/fate/filter-pixfmts-il +++ b/tests/ref/fate/filter-pixfmts-il @@ -51,6 +51,8 @@ nv12 3c3ba9b1b4c4dfff09c26f71b51dd146 nv21 ab586d8781246b5a32d8760a61db9797 p010be 3df51286ef66b53e3e283dbbab582263 p010le eadcd8241e97e35b2b47d5eb2eaea6cd +p016be 3df51286ef66b53e3e283dbbab582263 +p016le eadcd8241e97e35b2b47d5eb2eaea6cd rgb0 cfaf68671e43248267d8cd50cae8c13f rgb24 88894f608cf33ba310f21996748d77a7 rgb444be 99d36d814988fb388aacdef575dacfcf diff --git a/tests/ref/fate/filter-pixfmts-lut b/tests/ref/fate/filter-pixfmts-lut index db3fd417b7d69..6cf798ad77f95 100644 --- a/tests/ref/fate/filter-pixfmts-lut +++ b/tests/ref/fate/filter-pixfmts-lut @@ -12,6 +12,11 @@ gbrp12le c5a4b89571f7095eb737ad9fd6b1ee08 gbrp14le bdfdfd6f36c60497d1cdae791f3cc117 gbrp16le df095ef3a20995935cfcaf144afc68b6 gbrp9le a8c4e29f4cb627db81ba053e0853e702 +gray 20b14b5e26cd11300ed1249e04082170 +gray10le 8f4140b55e847cc423002b89666db5ea +gray12le ea89c02f6b3af49ddaf13364ed33d86d +gray16le aa10599924fb2440fa12b76e90f57dcb +gray9le 7d9cc9ad6118674c547a54281d10cf05 rgb24 a356171207723a580e7d277078072005 rgb48le 5c7dd8575836d18c91e09f1915cf9aa9 rgba 7bc854c2698b78af3e9159a19c2d9d21 diff --git a/tests/ref/fate/filter-pixfmts-null b/tests/ref/fate/filter-pixfmts-null index 124dddeacbe6e..c45ce937b3777 100644 --- a/tests/ref/fate/filter-pixfmts-null +++ b/tests/ref/fate/filter-pixfmts-null @@ -51,6 +51,8 @@ nv12 8e24feb2c544dc26a20047a71e4c27aa nv21 335d85c9af6110f26ae9e187a82ed2cf p010be 7f9842d6015026136bad60d03c035cc3 p010le c453421b9f726bdaf2bacf59a492c43b +p016be 7f9842d6015026136bad60d03c035cc3 +p016le c453421b9f726bdaf2bacf59a492c43b pal8 ff5929f5b42075793b2c34cb441bede5 rgb0 0de71e5a1f97f81fb51397a0435bfa72 rgb24 f4438057d046e6d98ade4e45294b21be diff --git a/tests/ref/fate/filter-pixfmts-scale b/tests/ref/fate/filter-pixfmts-scale index f43c5194286b0..1611c60ea7cbb 100644 --- a/tests/ref/fate/filter-pixfmts-scale +++ b/tests/ref/fate/filter-pixfmts-scale @@ -51,6 +51,8 @@ nv12 b118d24a3653fe66e5d9e079033aef79 nv21 c74bb1c10dbbdee8a1f682b194486c4d p010be 1d6726d94bf1385996a9a9840dd0e878 p010le 4b316f2b9e18972299beb73511278fa8 +p016be 31e204018cbb53f8988c4e1174ea8ce9 +p016le d5afe557f492a09317e525d7cb782f5b pal8 29e10892009b2cfe431815ec3052ed3b rgb0 fbd27e98154efb7535826afed41e9bb0 rgb24 e022e741451e81f2ecce1c7240b93e87 diff --git a/tests/ref/fate/filter-pixfmts-transpose b/tests/ref/fate/filter-pixfmts-transpose new file mode 100644 index 0000000000000..49069d6e06df8 --- /dev/null +++ b/tests/ref/fate/filter-pixfmts-transpose @@ -0,0 +1,110 @@ +0bgr 6929c1e308d2f4f941d002627047d262 +0rgb cf1bedd0784a3efd3ab00c4e44005c37 +abgr 6d6f896f853a6c6f93ee70dba9af3d17 +argb 87bbd23debb94d486ac3a6b6c0b005f9 +ayuv64le e4c07e0d5b333b3bc9eb4f3ce6af3a2c +bgr0 df3a6eedd4939ce09a357b655ac2962a +bgr24 f9a08135e5d58c0b2a5509c369a88414 +bgr444be dd9e990a327649ec0b2b81a8ee4d8f49 +bgr444le bee1d9fae8733d0c0669bca2ac4dfaf6 +bgr48be 39f48f6353dfc772af36cbb41e6126a4 +bgr48le 9a61d9531b1f6de44b27f6bb9b4dfc79 +bgr4_byte ddff9da461afce90e3122a41d79b287d +bgr555be 24e5c6502a6d927f8ba88f3320ebf619 +bgr555le 5201d098979ea86a66d8df1ef41c79ad +bgr565be 59afe17b455e921daf428ba05a40bab9 +bgr565le b2709790684abbd2133906b637f2b4b8 +bgr8 b6ee15f70989d2f52f184e32b3af2c18 +bgra f2fe61e08446900ad209f2c586997e15 +bgra64be 8d01994c8c32e628fcf9749851f1ffe8 +bgra64le faaef6d280f92e7e8abdd9fa4a61f7b5 +gbrap 0899b3af50d35a63bfecb419a5b29968 +gbrap10be 3e3be2d8f9aa5f449a1df404e27d0054 +gbrap10le db4e4861010cbbf726492fad282d5813 +gbrap12be 1518c9a565d1ba1a45dd369acc1aa75e +gbrap12le 714fe318af81a46f83655c6e7e13351e +gbrap16be 39d488528aacff466aac7539c9b948a8 +gbrap16le 5426ac9457289927bfe2ec03038a8780 +gbrp 7b4b6a2f1cdc51455b25515c3ecea944 +gbrp10be d7401725699b2ddf954caa16a0878a1e +gbrp10le 6036711969eae1979be6358f688bd9c8 +gbrp12be ec7d6e69fc579619b53d57a76c20480d +gbrp12le bf7478185274486c3f7dd4db1da8f7d0 +gbrp14be 9b66f22e4315aaa878a430ae3f44ab57 +gbrp14le 16f30349b42dca007b37b8522d3018df +gbrp16be 0d003b88d4f446ae9ba12cab1cbb359a +gbrp16le a1c09038fa4636c9843ab8dd2b7601ea +gbrp9be df381b4b27be25d172fa556434478807 +gbrp9le a5301e978f68b29bfc613b2462ec4888 +gray c5f8bc6636fd15dbc57deb4bba1e7379 +gray10be 48b421da79c195fd91dffb8fca79a8a2 +gray10le 7774e3296916b896afa46f626334a280 +gray12be 89f1c4b7821b771f6d967f9db871f8ef +gray12le 43d392c3dcbd79b47cce31f2006c5050 +gray16be 4aef307021a91b1de67f1d4381a39132 +gray16le 76f2afe156edca7ae05cfa4e5867126e +gray9be 2c425fa532c940d226822da8b3592310 +gray9le bcc575942910b3c72eaa72e8794f3acd +nv12 1965e3826144686748f2f6b516fca5ba +nv21 292adaf5271c5c8516b71640458c01f4 +p010be ad0de2cc9bff81688b182a870fcf7000 +p010le e7ff5143595021246733ce6bd0a769e8 +p016be ad0de2cc9bff81688b182a870fcf7000 +p016le e7ff5143595021246733ce6bd0a769e8 +rgb0 31ea5da7fe779c6ea0a33f1d28aad918 +rgb24 47654cabaaad79170b90afd5a02161dd +rgb444be 3cac1f0c43a74d2a95eb02e187070845 +rgb444le 46d602468bd9e5a430622e3d4b7c8f40 +rgb48be 400932419bbb780614254253ef5591c3 +rgb48le 6a99c40f21629cb0655e8772d7190374 +rgb4_byte d3990da196266305a3f2e5b1d72401a5 +rgb555be 79e4503ff0d5cf52d3a7901397499a28 +rgb555le c65f2594c0b3107a322f7aeb81aa8a16 +rgb565be 0c746b5063d02d6cb98e9e9a59ad3b99 +rgb565le 63b02db11c3d20be54d218c7c44f8ddb +rgb8 c90feb30c3c9391ef5f470209d7b7a15 +rgba 4d76a9542143752a4ac30f82f88f68f1 +rgba64be a60041217f4c0cd796d19d3940a12a41 +rgba64le ad47197774858858ae7b0c177dffa459 +xyz12be 68e5cba640f6e4ef72dff950e88b5342 +xyz12le 8b6b6a6db4d7561e80db88ccaecce7a9 +ya8 d4b7a62f80681fa44c977ff3a64f4ce4 +yuv410p 4c0143429edd30aa01493447c90132ea +yuv420p 2fa5b2201c75034206cc20e2c6134aed +yuv420p10be 0931660f930d9be8aea9d0c76b406055 +yuv420p10le 9ce12b168c49db871836c979b526c1f1 +yuv420p12be 73d6be4230b6f4e4e269977afab56323 +yuv420p12le 6938815c8acd690138506cbb5f005fb8 +yuv420p14be bf76a805b9c2f9808c73492d3b8da268 +yuv420p14le 5df47483b89ffe6ef4bbf14058d7d3b3 +yuv420p16be 3a64132681656be6db635f4e6a282dc9 +yuv420p16le c77a81e47d1690a338693ec6f323ef1e +yuv420p9be 2307cb7f324df299c4829b11cb0e6bc7 +yuv420p9le c735c3c8424c70d822ab4a1fe1f504e2 +yuv444p eb755977ca464baac5f03771858080ae +yuv444p10be 866b59a23dff3dc1cb6bf7bd7da26da4 +yuv444p10le 417d62f15abf4777c4ec5e0d00796a9e +yuv444p12be c1da110f0ee898fbcd4b45afb5aed58b +yuv444p12le dc18bddd7b6bb9fdb2e0c7e7476375fa +yuv444p14be 2f181fa3403e7911b233d3d976abea73 +yuv444p14le ac718343878786a25b9a50924f9aabca +yuv444p16be 128214efef6fffe3293db513ae700d4a +yuv444p16le a8b6613094b8d2b275e2e4bc4512c9e4 +yuv444p9be eae529dd1cdb7f512ae2674334c1ef08 +yuv444p9le 06ffcacdd03f6457614c352a4ccb7642 +yuva420p 058d00d9564be827e5db6ce2b8b2dbb5 +yuva420p10be 333209d11916161a65c6453d2bf435c2 +yuva420p10le 4b7ea5b59a712f1f59cd394b3b40ff69 +yuva420p16be 5984c7f4d14e4cf0e511cb0aa6c53089 +yuva420p16le 34e29fc4a22a0ab1ea01641d0df2ac86 +yuva420p9be 45ea80889575b31cccc83a4d16555497 +yuva420p9le 6e5cb3e761a9c45e26370307c49f8831 +yuva444p 4f9e649fbc2c0c91178d1576e462bb31 +yuva444p10be 9450fbac30b5f9da7414c895695591a9 +yuva444p10le 84a93637bf2c7e498380beff9b1fc503 +yuva444p16be 9fd2f00ea9bef8e488228bc0b47b28cb +yuva444p16le ae9fd8d1baea0f8626b963816d667d2d +yuva444p9be 4ce11ae57780f74c78cdd5c06be4bded +yuva444p9le 1b9cc85fd6ab0c7e240915a99e98d1c1 +yuvj420p 9603b8dd64daec41f0514197989c2b19 +yuvj444p 66ec9b3219df9eb2c1315d293602ab42 diff --git a/tests/ref/fate/filter-pixfmts-vflip b/tests/ref/fate/filter-pixfmts-vflip index 84b9d56858ab5..d49e50196e33e 100644 --- a/tests/ref/fate/filter-pixfmts-vflip +++ b/tests/ref/fate/filter-pixfmts-vflip @@ -51,6 +51,8 @@ nv12 261ebe585ae2aa4e70d39a10c1679294 nv21 2909feacd27bebb080c8e0fa41795269 p010be 06e9354b6e0e38ba41736352cedc0bd5 p010le fd18d322bffbf5816902c13102872e22 +p016be 06e9354b6e0e38ba41736352cedc0bd5 +p016le fd18d322bffbf5816902c13102872e22 pal8 450b0155d0f2d5628bf95a442db5f817 rgb0 56a7ea69541bcd27bef6a5615784722b rgb24 195e6dae1c3a488b9d3ceb7560d25d85 diff --git a/tests/ref/fate/filter-w3fdif-complex b/tests/ref/fate/filter-w3fdif-complex index 4b334daec16d5..cbd8f06faee92 100644 --- a/tests/ref/fate/filter-w3fdif-complex +++ b/tests/ref/fate/filter-w3fdif-complex @@ -3,33 +3,33 @@ #codec_id 0: rawvideo #dimensions 0: 720x576 #sar 0: 16/15 -0, 18, 18, 1, 622080, 0x21d21485 -0, 19, 19, 1, 622080, 0x600a5468 -0, 20, 20, 1, 622080, 0x9526f7b8 -0, 21, 21, 1, 622080, 0x8b3e661f -0, 22, 22, 1, 622080, 0xff5cb5a9 -0, 23, 23, 1, 622080, 0x7e5e730c -0, 24, 24, 1, 622080, 0x85219ac6 -0, 25, 25, 1, 622080, 0x2f3465a0 -0, 26, 26, 1, 622080, 0xddbf4da0 -0, 27, 27, 1, 622080, 0xc115d4ee -0, 28, 28, 1, 622080, 0x7a8a8d72 -0, 29, 29, 1, 622080, 0xbafcd973 -0, 30, 30, 1, 622080, 0xd2c15603 -0, 31, 31, 1, 622080, 0xd7217855 -0, 32, 32, 1, 622080, 0x9a584eca -0, 33, 33, 1, 622080, 0x9f3e1c40 -0, 34, 34, 1, 622080, 0x6d01efb7 -0, 35, 35, 1, 622080, 0x9ecfcce0 -0, 36, 36, 1, 622080, 0xb355fd7e -0, 37, 37, 1, 622080, 0xc7784021 -0, 38, 38, 1, 622080, 0x13fe4187 -0, 39, 39, 1, 622080, 0xfa03b613 -0, 40, 40, 1, 622080, 0x2c9ccfcd -0, 41, 41, 1, 622080, 0xcae6e6c6 -0, 42, 42, 1, 622080, 0x177968f9 -0, 43, 43, 1, 622080, 0xf708de36 -0, 44, 44, 1, 622080, 0x4491870a -0, 45, 45, 1, 622080, 0x37709f98 -0, 46, 46, 1, 622080, 0x23e8d22f -0, 47, 47, 1, 622080, 0x25cba876 +0, 18, 18, 1, 622080, 0xe1b21462 +0, 19, 19, 1, 622080, 0x1362538d +0, 20, 20, 1, 622080, 0x0f55f79b +0, 21, 21, 1, 622080, 0xfdb265f6 +0, 22, 22, 1, 622080, 0x2f8eb534 +0, 23, 23, 1, 622080, 0x0de472b1 +0, 24, 24, 1, 622080, 0x3e699a78 +0, 25, 25, 1, 622080, 0x66396524 +0, 26, 26, 1, 622080, 0x17244d40 +0, 27, 27, 1, 622080, 0x04a5d554 +0, 28, 28, 1, 622080, 0x0e278cd9 +0, 29, 29, 1, 622080, 0x7b53d8de +0, 30, 30, 1, 622080, 0xe51a558e +0, 31, 31, 1, 622080, 0xd58177e4 +0, 32, 32, 1, 622080, 0x270b4e1f +0, 33, 33, 1, 622080, 0x3fbf1bdf +0, 34, 34, 1, 622080, 0xbfebee9d +0, 35, 35, 1, 622080, 0x2c6fcccf +0, 36, 36, 1, 622080, 0x4a57fcc2 +0, 37, 37, 1, 622080, 0x33b53f5d +0, 38, 38, 1, 622080, 0x93ba405d +0, 39, 39, 1, 622080, 0xf4dbb54b +0, 40, 40, 1, 622080, 0xf205ce68 +0, 41, 41, 1, 622080, 0x383fe5bc +0, 42, 42, 1, 622080, 0x4dd06905 +0, 43, 43, 1, 622080, 0xc925de57 +0, 44, 44, 1, 622080, 0x7c8786e8 +0, 45, 45, 1, 622080, 0x550b9f60 +0, 46, 46, 1, 622080, 0x4162d1e9 +0, 47, 47, 1, 622080, 0xf609a847 diff --git a/tests/ref/fate/filter-w3fdif-simple b/tests/ref/fate/filter-w3fdif-simple index 62efaae929e68..09c0d7ce55f88 100644 --- a/tests/ref/fate/filter-w3fdif-simple +++ b/tests/ref/fate/filter-w3fdif-simple @@ -3,33 +3,33 @@ #codec_id 0: rawvideo #dimensions 0: 720x576 #sar 0: 16/15 -0, 18, 18, 1, 622080, 0xc73774f5 -0, 19, 19, 1, 622080, 0x4ea3a400 -0, 20, 20, 1, 622080, 0x95153cda -0, 21, 21, 1, 622080, 0xec39bf0b -0, 22, 22, 1, 622080, 0x94b6f836 -0, 23, 23, 1, 622080, 0xc145c3ee -0, 24, 24, 1, 622080, 0x4d4cdee2 -0, 25, 25, 1, 622080, 0x193ebc7c -0, 26, 26, 1, 622080, 0xbd728fd8 -0, 27, 27, 1, 622080, 0xf0f3252f -0, 28, 28, 1, 622080, 0xc012d20a -0, 29, 29, 1, 622080, 0x7b5831b2 -0, 30, 30, 1, 622080, 0x464e9622 -0, 31, 31, 1, 622080, 0x46e3c6c0 -0, 32, 32, 1, 622080, 0xa6ec908b -0, 33, 33, 1, 622080, 0x6a257595 -0, 34, 34, 1, 622080, 0xa6552ecc -0, 35, 35, 1, 622080, 0xdecd1a91 -0, 36, 36, 1, 622080, 0xfaa53e71 -0, 37, 37, 1, 622080, 0xc94a9707 -0, 38, 38, 1, 622080, 0xb5727fd4 -0, 39, 39, 1, 622080, 0x143c018c -0, 40, 40, 1, 622080, 0x92d110c9 -0, 41, 41, 1, 622080, 0x4f762fc0 -0, 42, 42, 1, 622080, 0x3dd2a7d2 -0, 43, 43, 1, 622080, 0xa5d02dc0 -0, 44, 44, 1, 622080, 0x2223ce3d -0, 45, 45, 1, 622080, 0xe4a5fc36 -0, 46, 46, 1, 622080, 0x8384159e -0, 47, 47, 1, 622080, 0x995efa57 +0, 18, 18, 1, 622080, 0x338874e8 +0, 19, 19, 1, 622080, 0x1a9da32b +0, 20, 20, 1, 622080, 0x2ecc3cd9 +0, 21, 21, 1, 622080, 0x0441beec +0, 22, 22, 1, 622080, 0x4de3f7ba +0, 23, 23, 1, 622080, 0x59a4c388 +0, 24, 24, 1, 622080, 0x833ade92 +0, 25, 25, 1, 622080, 0x4c79bbf3 +0, 26, 26, 1, 622080, 0xe1998f77 +0, 27, 27, 1, 622080, 0xd00e2586 +0, 28, 28, 1, 622080, 0xe716d185 +0, 29, 29, 1, 622080, 0x24763136 +0, 30, 30, 1, 622080, 0xaeaa95a2 +0, 31, 31, 1, 622080, 0x92eec65a +0, 32, 32, 1, 622080, 0x7cde9000 +0, 33, 33, 1, 622080, 0x98e2752c +0, 34, 34, 1, 622080, 0x5ffe2db6 +0, 35, 35, 1, 622080, 0x1e911a65 +0, 36, 36, 1, 622080, 0x302d3dc2 +0, 37, 37, 1, 622080, 0xc1399647 +0, 38, 38, 1, 622080, 0xc4477ebf +0, 39, 39, 1, 622080, 0x50e900ca +0, 40, 40, 1, 622080, 0x867e0f7a +0, 41, 41, 1, 622080, 0xa2412ebe +0, 42, 42, 1, 622080, 0xc7a5a7e6 +0, 43, 43, 1, 622080, 0xaa5d2de7 +0, 44, 44, 1, 622080, 0x9bf0ce31 +0, 45, 45, 1, 622080, 0xfb88fbf9 +0, 46, 46, 1, 622080, 0xe6321572 +0, 47, 47, 1, 622080, 0x5541fa37 diff --git a/tests/ref/fate/filter-yadif-mode0 b/tests/ref/fate/filter-yadif-mode0 index 2c6346bd4349d..be807f9de5432 100644 --- a/tests/ref/fate/filter-yadif-mode0 +++ b/tests/ref/fate/filter-yadif-mode0 @@ -3,33 +3,33 @@ #codec_id 0: rawvideo #dimensions 0: 720x576 #sar 0: 16/15 -0, 9, 9, 1, 622080, 0x6331caee -0, 10, 10, 1, 622080, 0xa459e690 -0, 11, 11, 1, 622080, 0x6429c648 -0, 12, 12, 1, 622080, 0xa49891ca -0, 13, 13, 1, 622080, 0x2a887404 -0, 14, 14, 1, 622080, 0xe8d49705 -0, 15, 15, 1, 622080, 0x1b627835 -0, 16, 16, 1, 622080, 0x686858fd -0, 17, 17, 1, 622080, 0x2675174f -0, 18, 18, 1, 622080, 0x78470e7f -0, 19, 19, 1, 622080, 0xffb366ec -0, 20, 20, 1, 622080, 0xd575da72 -0, 21, 21, 1, 622080, 0x5fb297f7 -0, 22, 22, 1, 622080, 0xbac77ca0 -0, 23, 23, 1, 622080, 0x3276ed72 -0, 24, 24, 1, 622080, 0x264092b2 -0, 25, 25, 1, 622080, 0x20ba1094 -0, 26, 26, 1, 622080, 0x76cc3139 -0, 27, 27, 1, 622080, 0x469a4902 -0, 28, 28, 1, 622080, 0x0ed7b8f5 -0, 29, 29, 1, 622080, 0xdc51aeac -0, 30, 30, 1, 622080, 0xee06aa36 -0, 31, 31, 1, 622080, 0x7372405f -0, 32, 32, 1, 622080, 0x9e0ee776 -0, 33, 33, 1, 622080, 0x39e6d8c9 -0, 34, 34, 1, 622080, 0x51d9ac9a -0, 35, 35, 1, 622080, 0x2b63441d -0, 36, 36, 1, 622080, 0x58afbd5e -0, 37, 37, 1, 622080, 0xb972f716 -0, 38, 38, 1, 622080, 0x6a6df129 +0, 9, 9, 1, 622080, 0x77c0ca92 +0, 10, 10, 1, 622080, 0xbe7fe646 +0, 11, 11, 1, 622080, 0x4384c5da +0, 12, 12, 1, 622080, 0x296b9168 +0, 13, 13, 1, 622080, 0x96d5738e +0, 14, 14, 1, 622080, 0x769b9681 +0, 15, 15, 1, 622080, 0x461d778d +0, 16, 16, 1, 622080, 0xb88c584b +0, 17, 17, 1, 622080, 0x7d7b1635 +0, 18, 18, 1, 622080, 0x49c60dc0 +0, 19, 19, 1, 622080, 0x498765a4 +0, 20, 20, 1, 622080, 0x0caed8f9 +0, 21, 21, 1, 622080, 0x41d897d3 +0, 22, 22, 1, 622080, 0x7aeb7c93 +0, 23, 23, 1, 622080, 0xa8bced40 +0, 24, 24, 1, 622080, 0x11de928c +0, 25, 25, 1, 622080, 0x64741075 +0, 26, 26, 1, 622080, 0x160f310e +0, 27, 27, 1, 622080, 0x702d489c +0, 28, 28, 1, 622080, 0xaf2fb8aa +0, 29, 29, 1, 622080, 0x575bae0f +0, 30, 30, 1, 622080, 0xfd68a990 +0, 31, 31, 1, 622080, 0x8b513f66 +0, 32, 32, 1, 622080, 0x0e6ae6c3 +0, 33, 33, 1, 622080, 0x3d12d8ab +0, 34, 34, 1, 622080, 0x45d0ac80 +0, 35, 35, 1, 622080, 0xb18d4421 +0, 36, 36, 1, 622080, 0x2e81bd32 +0, 37, 37, 1, 622080, 0x852cf6cf +0, 38, 38, 1, 622080, 0xb055f0e5 diff --git a/tests/ref/fate/filter-yadif-mode1 b/tests/ref/fate/filter-yadif-mode1 index e2d14d5605131..53741b0ae7f5a 100644 --- a/tests/ref/fate/filter-yadif-mode1 +++ b/tests/ref/fate/filter-yadif-mode1 @@ -3,62 +3,62 @@ #codec_id 0: rawvideo #dimensions 0: 720x576 #sar 0: 16/15 -0, 18, 18, 1, 622080, 0x6331caee -0, 19, 19, 1, 622080, 0x625da883 -0, 20, 20, 1, 622080, 0xa459e690 -0, 21, 21, 1, 622080, 0xce5d891e -0, 22, 22, 1, 622080, 0x6429c648 -0, 23, 23, 1, 622080, 0x608cc0ba -0, 24, 24, 1, 622080, 0xa49891ca -0, 25, 25, 1, 622080, 0x9721987f -0, 26, 26, 1, 622080, 0x2a887404 -0, 27, 27, 1, 622080, 0x60d71d47 -0, 28, 28, 1, 622080, 0xe8d49705 -0, 29, 29, 1, 622080, 0x821e13cb -0, 30, 30, 1, 622080, 0x1b627835 -0, 31, 31, 1, 622080, 0x1806c5f4 -0, 32, 32, 1, 622080, 0x686858fd -0, 33, 33, 1, 622080, 0xab865773 -0, 34, 34, 1, 622080, 0x2675174f -0, 35, 35, 1, 622080, 0x43a61a14 -0, 36, 36, 1, 622080, 0x78470e7f -0, 37, 37, 1, 622080, 0xeb877bc6 -0, 38, 38, 1, 622080, 0xffb366ec -0, 39, 39, 1, 622080, 0xda0906e7 -0, 40, 40, 1, 622080, 0xd575da72 -0, 41, 41, 1, 622080, 0x23ae25a4 -0, 42, 42, 1, 622080, 0x5fb297f7 -0, 43, 43, 1, 622080, 0x99b32978 -0, 44, 44, 1, 622080, 0xbac77ca0 -0, 45, 45, 1, 622080, 0xc1cdcbf9 -0, 46, 46, 1, 622080, 0x3276ed72 -0, 47, 47, 1, 622080, 0x4061f5ab -0, 48, 48, 1, 622080, 0x264092b2 -0, 49, 49, 1, 622080, 0xa4e2039e -0, 50, 50, 1, 622080, 0x20ba1094 -0, 51, 51, 1, 622080, 0x984e906e -0, 52, 52, 1, 622080, 0x76cc3139 -0, 53, 53, 1, 622080, 0xf70e2cf6 -0, 54, 54, 1, 622080, 0x469a4902 -0, 55, 55, 1, 622080, 0x235312e6 -0, 56, 56, 1, 622080, 0x0ed7b8f5 -0, 57, 57, 1, 622080, 0xd0269cc3 -0, 58, 58, 1, 622080, 0xdc51aeac -0, 59, 59, 1, 622080, 0x1aa5f76e -0, 60, 60, 1, 622080, 0xee06aa36 -0, 61, 61, 1, 622080, 0xa7103230 -0, 62, 62, 1, 622080, 0x7372405f -0, 63, 63, 1, 622080, 0x8d7a44b5 -0, 64, 64, 1, 622080, 0x9e0ee776 -0, 65, 65, 1, 622080, 0xd41e8560 -0, 66, 66, 1, 622080, 0x39e6d8c9 -0, 67, 67, 1, 622080, 0x7a23d70c -0, 68, 68, 1, 622080, 0x51d9ac9a -0, 69, 69, 1, 622080, 0x8eacf7f2 -0, 70, 70, 1, 622080, 0x2b63441d -0, 71, 71, 1, 622080, 0x9f71b742 -0, 72, 72, 1, 622080, 0x58afbd5e -0, 73, 73, 1, 622080, 0x4d645292 -0, 74, 74, 1, 622080, 0xb972f716 -0, 75, 75, 1, 622080, 0xbb5d01a2 -0, 76, 76, 1, 622080, 0x6a6df129 +0, 18, 18, 1, 622080, 0x77c0ca92 +0, 19, 19, 1, 622080, 0x06d3a822 +0, 20, 20, 1, 622080, 0xbe7fe646 +0, 21, 21, 1, 622080, 0x542e891a +0, 22, 22, 1, 622080, 0x4384c5da +0, 23, 23, 1, 622080, 0xddd4c056 +0, 24, 24, 1, 622080, 0x296b9168 +0, 25, 25, 1, 622080, 0xf8e09812 +0, 26, 26, 1, 622080, 0x96d5738e +0, 27, 27, 1, 622080, 0xac341d9b +0, 28, 28, 1, 622080, 0x769b9681 +0, 29, 29, 1, 622080, 0xb5da1354 +0, 30, 30, 1, 622080, 0x461d778d +0, 31, 31, 1, 622080, 0xd9dcc5a8 +0, 32, 32, 1, 622080, 0xb88c584b +0, 33, 33, 1, 622080, 0x581b5727 +0, 34, 34, 1, 622080, 0x7d7b1635 +0, 35, 35, 1, 622080, 0xfc1b1a12 +0, 36, 36, 1, 622080, 0x49c60dc0 +0, 37, 37, 1, 622080, 0x1d537b22 +0, 38, 38, 1, 622080, 0x498765a4 +0, 39, 39, 1, 622080, 0xdd2e063a +0, 40, 40, 1, 622080, 0x0caed8f9 +0, 41, 41, 1, 622080, 0xfb4a24aa +0, 42, 42, 1, 622080, 0x41d897d3 +0, 43, 43, 1, 622080, 0xdd3f29ae +0, 44, 44, 1, 622080, 0x7aeb7c93 +0, 45, 45, 1, 622080, 0x2410cbe2 +0, 46, 46, 1, 622080, 0xa8bced40 +0, 47, 47, 1, 622080, 0x5534f5ca +0, 48, 48, 1, 622080, 0x11de928c +0, 49, 49, 1, 622080, 0x82180322 +0, 50, 50, 1, 622080, 0x64741075 +0, 51, 51, 1, 622080, 0x5e048fc8 +0, 52, 52, 1, 622080, 0x160f310e +0, 53, 53, 1, 622080, 0x4f6d2ce7 +0, 54, 54, 1, 622080, 0x702d489c +0, 55, 55, 1, 622080, 0xa4b41315 +0, 56, 56, 1, 622080, 0xaf2fb8aa +0, 57, 57, 1, 622080, 0x5ec09c25 +0, 58, 58, 1, 622080, 0x575bae0f +0, 59, 59, 1, 622080, 0x94ecf775 +0, 60, 60, 1, 622080, 0xfd68a990 +0, 61, 61, 1, 622080, 0x15a7315c +0, 62, 62, 1, 622080, 0x8b513f66 +0, 63, 63, 1, 622080, 0xeba9440a +0, 64, 64, 1, 622080, 0x0e6ae6c3 +0, 65, 65, 1, 622080, 0x751484a6 +0, 66, 66, 1, 622080, 0x3d12d8ab +0, 67, 67, 1, 622080, 0xdff3d681 +0, 68, 68, 1, 622080, 0x45d0ac80 +0, 69, 69, 1, 622080, 0xbe2df7f7 +0, 70, 70, 1, 622080, 0xb18d4421 +0, 71, 71, 1, 622080, 0xa49cb6de +0, 72, 72, 1, 622080, 0x2e81bd32 +0, 73, 73, 1, 622080, 0xa47a5272 +0, 74, 74, 1, 622080, 0x852cf6cf +0, 75, 75, 1, 622080, 0x892a014e +0, 76, 76, 1, 622080, 0xb055f0e5 diff --git a/tests/ref/fate/filter-yadif10 b/tests/ref/fate/filter-yadif10 index 09ab7458bb15c..28e799fc1f01a 100644 --- a/tests/ref/fate/filter-yadif10 +++ b/tests/ref/fate/filter-yadif10 @@ -3,33 +3,33 @@ #codec_id 0: rawvideo #dimensions 0: 720x576 #sar 0: 16/15 -0, 9, 9, 1, 1244160, 0x5b49e0c0 -0, 10, 10, 1, 1244160, 0x76ba6bab -0, 11, 11, 1, 1244160, 0x0298cb8d -0, 12, 12, 1, 1244160, 0x9c81759a -0, 13, 13, 1, 1244160, 0xa239d1ae -0, 14, 14, 1, 1244160, 0x3e95ada9 -0, 15, 15, 1, 1244160, 0x8b87e8f8 -0, 16, 16, 1, 1244160, 0x64f89653 -0, 17, 17, 1, 1244160, 0x58e5d12e -0, 18, 18, 1, 1244160, 0x38b4003a -0, 19, 19, 1, 1244160, 0xc005c29c -0, 20, 20, 1, 1244160, 0x10c0c60d -0, 21, 21, 1, 1244160, 0x1b550998 -0, 22, 22, 1, 1244160, 0x7aacf6ab -0, 23, 23, 1, 1244160, 0xeb205d98 -0, 24, 24, 1, 1244160, 0x6ad2134c -0, 25, 25, 1, 1244160, 0x8aea4e56 -0, 26, 26, 1, 1244160, 0x0d910a6b -0, 27, 27, 1, 1244160, 0x749ae307 -0, 28, 28, 1, 1244160, 0x8ff7af3c -0, 29, 29, 1, 1244160, 0x9ba51b91 -0, 30, 30, 1, 1244160, 0xad476514 -0, 31, 31, 1, 1244160, 0x674481d6 -0, 32, 32, 1, 1244160, 0x0937e677 -0, 33, 33, 1, 1244160, 0x6c2c53ee -0, 34, 34, 1, 1244160, 0x524a164e -0, 35, 35, 1, 1244160, 0x77a405ab -0, 36, 36, 1, 1244160, 0xaa6b47c4 -0, 37, 37, 1, 1244160, 0x0b5ab556 -0, 38, 38, 1, 1244160, 0xbe1edab9 +0, 9, 9, 1, 1244160, 0xe0c2231b +0, 10, 10, 1, 1244160, 0xdc7caa43 +0, 11, 11, 1, 1244160, 0x52c4dfbf +0, 12, 12, 1, 1244160, 0x7c577f07 +0, 13, 13, 1, 1244160, 0x5b6ad7ce +0, 14, 14, 1, 1244160, 0x6f15ce76 +0, 15, 15, 1, 1244160, 0xf120034a +0, 16, 16, 1, 1244160, 0x9c65ba64 +0, 17, 17, 1, 1244160, 0x883b237e +0, 18, 18, 1, 1244160, 0xb8292e0d +0, 19, 19, 1, 1244160, 0xbc392721 +0, 20, 20, 1, 1244160, 0x7cd82ec9 +0, 21, 21, 1, 1244160, 0x167325eb +0, 22, 22, 1, 1244160, 0x49bafa73 +0, 23, 23, 1, 1244160, 0xe1ff6dbf +0, 24, 24, 1, 1244160, 0x85f710b6 +0, 25, 25, 1, 1244160, 0xd1fd4cdb +0, 26, 26, 1, 1244160, 0xafee03c5 +0, 27, 27, 1, 1244160, 0x566be070 +0, 28, 28, 1, 1244160, 0xb6abbd01 +0, 29, 29, 1, 1244160, 0xa98f38fd +0, 30, 30, 1, 1244160, 0x00f4736b +0, 31, 31, 1, 1244160, 0x6b0f9dd2 +0, 32, 32, 1, 1244160, 0x15810b92 +0, 33, 33, 1, 1244160, 0x0b516465 +0, 34, 34, 1, 1244160, 0x927d15e6 +0, 35, 35, 1, 1244160, 0xd102f2bf +0, 36, 36, 1, 1244160, 0xdd8b3b20 +0, 37, 37, 1, 1244160, 0x229ac529 +0, 38, 38, 1, 1244160, 0xf844e0a2 diff --git a/tests/ref/fate/filter-yadif16 b/tests/ref/fate/filter-yadif16 index 3386b026c9a48..0c856ab37a8d2 100644 --- a/tests/ref/fate/filter-yadif16 +++ b/tests/ref/fate/filter-yadif16 @@ -3,33 +3,33 @@ #codec_id 0: rawvideo #dimensions 0: 720x576 #sar 0: 16/15 -0, 9, 9, 1, 1244160, 0xfb65caee -0, 10, 10, 1, 1244160, 0x6222e690 -0, 11, 11, 1, 1244160, 0x020ac648 -0, 12, 12, 1, 1244160, 0xb76691ca -0, 13, 13, 1, 1244160, 0xe0fd7404 -0, 14, 14, 1, 1244160, 0x3ab29705 -0, 15, 15, 1, 1244160, 0xbe807835 -0, 16, 16, 1, 1244160, 0x77d358fd -0, 17, 17, 1, 1244160, 0x359b174f -0, 18, 18, 1, 1244160, 0xe20f0e7f -0, 19, 19, 1, 1244160, 0x988966ec -0, 20, 20, 1, 1244160, 0xd078da72 -0, 21, 21, 1, 1244160, 0x276d97f7 -0, 22, 22, 1, 1244160, 0xf8ee7ca0 -0, 23, 23, 1, 1244160, 0x776bed72 -0, 24, 24, 1, 1244160, 0xb9bf92b2 -0, 25, 25, 1, 1244160, 0x30e01094 -0, 26, 26, 1, 1244160, 0xbc5f3139 -0, 27, 27, 1, 1244160, 0x44324902 -0, 28, 28, 1, 1244160, 0x64aab8f5 -0, 29, 29, 1, 1244160, 0x0a05aeac -0, 30, 30, 1, 1244160, 0x31e5aa36 -0, 31, 31, 1, 1244160, 0xa685405f -0, 32, 32, 1, 1244160, 0x54a6e776 -0, 33, 33, 1, 1244160, 0x9af4d8c9 -0, 34, 34, 1, 1244160, 0xf709ac9a -0, 35, 35, 1, 1244160, 0x12a9441d -0, 36, 36, 1, 1244160, 0xf3f1bd5e -0, 37, 37, 1, 1244160, 0x7bcef716 -0, 38, 38, 1, 1244160, 0xe3a2f129 +0, 9, 9, 1, 1244160, 0x24eeca92 +0, 10, 10, 1, 1244160, 0x96b8e646 +0, 11, 11, 1, 1244160, 0xc11fc5da +0, 12, 12, 1, 1244160, 0xc15f9168 +0, 13, 13, 1, 1244160, 0xba1c738e +0, 14, 14, 1, 1244160, 0x56b59681 +0, 15, 15, 1, 1244160, 0x14ad778d +0, 16, 16, 1, 1244160, 0x18dc584b +0, 17, 17, 1, 1244160, 0xe4c11635 +0, 18, 18, 1, 1244160, 0x85cc0dc0 +0, 19, 19, 1, 1244160, 0x2d6a65a4 +0, 20, 20, 1, 1244160, 0x4054d8f9 +0, 21, 21, 1, 1244160, 0xebce97d3 +0, 22, 22, 1, 1244160, 0x79437c93 +0, 23, 23, 1, 1244160, 0x6438ed40 +0, 24, 24, 1, 1244160, 0x9121928c +0, 25, 25, 1, 1244160, 0xb8731075 +0, 26, 26, 1, 1244160, 0xfb01310e +0, 27, 27, 1, 1244160, 0x97be489c +0, 28, 28, 1, 1244160, 0xa5b4b8aa +0, 29, 29, 1, 1244160, 0x00a7ae0f +0, 30, 30, 1, 1244160, 0x514fa990 +0, 31, 31, 1, 1244160, 0xd73c3f66 +0, 32, 32, 1, 1244160, 0x3602e6c3 +0, 33, 33, 1, 1244160, 0xa16ad8ab +0, 34, 34, 1, 1244160, 0xdf11ac80 +0, 35, 35, 1, 1244160, 0x1f084421 +0, 36, 36, 1, 1244160, 0x9fc1bd32 +0, 37, 37, 1, 1244160, 0x1389f6cf +0, 38, 38, 1, 1244160, 0x6fc5f0e5 diff --git a/tests/ref/fate/fitsdec-gbrap16 b/tests/ref/fate/fitsdec-gbrap16le similarity index 100% rename from tests/ref/fate/fitsdec-gbrap16 rename to tests/ref/fate/fitsdec-gbrap16le diff --git a/tests/ref/fate/fmvc-type1 b/tests/ref/fate/fmvc-type1 new file mode 100644 index 0000000000000..d59de047e7109 --- /dev/null +++ b/tests/ref/fate/fmvc-type1 @@ -0,0 +1,11 @@ +#tb 0: 1/15 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 664x382 +#sar 0: 0/1 +0, 0, 0, 1, 760944, 0x2feb1453 +0, 1, 1, 1, 760944, 0x9677ebf8 +0, 2, 2, 1, 760944, 0x83d2ed49 +0, 3, 3, 1, 760944, 0x9ab6c63d +0, 4, 4, 1, 760944, 0x1820189c +0, 5, 5, 1, 760944, 0x4b94f521 diff --git a/tests/ref/fate/fmvc-type2 b/tests/ref/fate/fmvc-type2 new file mode 100644 index 0000000000000..60c630803a42b --- /dev/null +++ b/tests/ref/fate/fmvc-type2 @@ -0,0 +1,33 @@ +#tb 0: 1/10 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 768x576 +#sar 0: 0/1 +0, 0, 0, 1, 1327104, 0xa73c232d +0, 1, 1, 1, 1327104, 0xa73c232d +0, 2, 2, 1, 1327104, 0xa73c232d +0, 3, 3, 1, 1327104, 0xf14e05be +0, 4, 4, 1, 1327104, 0xd8c03726 +0, 5, 5, 1, 1327104, 0x16e8447a +0, 6, 6, 1, 1327104, 0x8dfd94d2 +0, 7, 7, 1, 1327104, 0x3550833b +0, 8, 8, 1, 1327104, 0x74bd2959 +0, 9, 9, 1, 1327104, 0xc2b4505c +0, 10, 10, 1, 1327104, 0x7c6999cd +0, 11, 11, 1, 1327104, 0xb6562711 +0, 12, 12, 1, 1327104, 0x50993565 +0, 13, 13, 1, 1327104, 0x579549d2 +0, 14, 14, 1, 1327104, 0xb17170f6 +0, 15, 15, 1, 1327104, 0xc7d87708 +0, 16, 16, 1, 1327104, 0xdb3879da +0, 17, 17, 1, 1327104, 0xdb3879da +0, 18, 18, 1, 1327104, 0xdb3879da +0, 19, 19, 1, 1327104, 0x6f1c5c01 +0, 20, 20, 1, 1327104, 0xd9d15c01 +0, 21, 21, 1, 1327104, 0x826f0bab +0, 22, 22, 1, 1327104, 0xf25b041d +0, 23, 23, 1, 1327104, 0xc85a041d +0, 24, 24, 1, 1327104, 0xc85a041d +0, 25, 25, 1, 1327104, 0xc85a041d +0, 26, 26, 1, 1327104, 0xc85a041d +0, 27, 27, 1, 1327104, 0xc54cc6ae diff --git a/tests/ref/fate/h264-bsf-mp4toannexb b/tests/ref/fate/h264-bsf-mp4toannexb index 2049f39701e32..7cd086a268cd1 100644 --- a/tests/ref/fate/h264-bsf-mp4toannexb +++ b/tests/ref/fate/h264-bsf-mp4toannexb @@ -1 +1 @@ -5f04c27cc6ee8625fe2405fb0f7da9a3 +f340e7ca9a46d437af4e96f6c8de221c diff --git a/tests/ref/fate/h264-ref-pic-mod-overflow b/tests/ref/fate/h264-ref-pic-mod-overflow new file mode 100644 index 0000000000000..d4386c026431e --- /dev/null +++ b/tests/ref/fate/h264-ref-pic-mod-overflow @@ -0,0 +1,25 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 1920x1080 +#sar 0: 1/1 +0, 0, 0, 1, 3110400, 0x5cd0bee9 +0, 1, 1, 1, 3110400, 0x19d0155c +0, 2, 2, 1, 3110400, 0x3519be4b +0, 3, 3, 1, 3110400, 0x87dc6708 +0, 4, 4, 1, 3110400, 0xef3c1056 +0, 5, 5, 1, 3110400, 0x5064aad2 +0, 6, 6, 1, 3110400, 0xbfb35057 +0, 7, 7, 1, 3110400, 0x6089eb95 +0, 8, 8, 1, 3110400, 0x85de8dea +0, 9, 9, 1, 3110400, 0x216b1e5a +0, 10, 10, 1, 3110400, 0xba73bdc4 +0, 11, 11, 1, 3110400, 0x536e437a +0, 12, 12, 1, 3110400, 0x4be0cdbd +0, 13, 13, 1, 3110400, 0x7316462d +0, 14, 14, 1, 3110400, 0x80eb8622 +0, 15, 15, 1, 3110400, 0xa612a70b +0, 16, 16, 1, 3110400, 0x9ff65345 +0, 17, 17, 1, 3110400, 0x57003dfa +0, 18, 18, 1, 3110400, 0xf29e036e +0, 19, 19, 1, 3110400, 0x70285363 diff --git a/tests/ref/fate/h264_mp4toannexb_ticket2991 b/tests/ref/fate/h264_mp4toannexb_ticket2991 index 76bdf3cae79c7..3245ef442c62e 100644 --- a/tests/ref/fate/h264_mp4toannexb_ticket2991 +++ b/tests/ref/fate/h264_mp4toannexb_ticket2991 @@ -1,12 +1,12 @@ -05d66e60ab22ee004720e0051af0fe74 *tests/data/fate/h264_mp4toannexb_ticket2991.h264 -1985815 tests/data/fate/h264_mp4toannexb_ticket2991.h264 -#extradata 0: 47, 0x3a590d55 +dba672c154b41414cf26aae967c27eef *tests/data/fate/h264_mp4toannexb_ticket2991.h264 +1985823 tests/data/fate/h264_mp4toannexb_ticket2991.h264 +#extradata 0: 48, 0x47ae0d55 #tb 0: 1/1200000 #media_type 0: video #codec_id 0: h264 #dimensions 0: 1280x720 #sar 0: 3/4 -0, 0, 0, 48000, 37126, 0xb020184c +0, 0, 0, 48000, 37127, 0xc125184c 0, 48000, 48000, 40040, 6920, 0x8512361a, F=0x0 0, 88040, 88040, 40040, 7550, 0x1bc56ed4, F=0x0 0, 128081, 128081, 40040, 8752, 0xb8c6f0a1, F=0x0 @@ -21,7 +21,7 @@ 0, 488444, 488444, 40040, 11234, 0x83cbd9fd, F=0x0 0, 528485, 528485, 40040, 17616, 0xfdf95104, F=0x0 0, 568525, 568525, 40040, 10689, 0x9633d32b, F=0x0 -0, 608566, 608566, 40040, 45291, 0x543c2cf6 +0, 608566, 608566, 40040, 45292, 0x66dd2cf6 0, 648606, 648606, 40040, 20837, 0x051abfab, F=0x0 0, 688646, 688646, 40040, 21418, 0xe2a59d70, F=0x0 0, 728687, 728687, 40040, 15643, 0x15cf2cec, F=0x0 @@ -36,7 +36,7 @@ 0, 1089050, 1089050, 40040, 13130, 0xcbb6bb8e, F=0x0 0, 1129091, 1129091, 40040, 16180, 0x5d188a7a, F=0x0 0, 1169131, 1169131, 40040, 14961, 0x9ff2f463, F=0x0 -0, 1209172, 1209172, 40040, 54296, 0xe6ec30ed +0, 1209172, 1209172, 40040, 54297, 0xf98d30ed 0, 1249212, 1249212, 40040, 11500, 0x8c4852c9, F=0x0 0, 1289252, 1289252, 40040, 12065, 0xfb7954c3, F=0x0 0, 1329293, 1329293, 40040, 12532, 0xf0a935d3, F=0x0 @@ -51,7 +51,7 @@ 0, 1689656, 1689656, 40040, 13250, 0xfed0deb8, F=0x0 0, 1729697, 1729697, 40040, 13360, 0xbf92d476, F=0x0 0, 1769737, 1769737, 40040, 11749, 0x3041eaf1, F=0x0 -0, 1809778, 1809778, 40040, 23997, 0xdbe6d5c4 +0, 1809778, 1809778, 40040, 23998, 0xee87d5c4 0, 1849818, 1849818, 40040, 16065, 0xe8f715b7, F=0x0 0, 1889858, 1889858, 40040, 16441, 0x0a4e060f, F=0x0 0, 1929899, 1929899, 40040, 17395, 0xa8edecc2, F=0x0 @@ -66,7 +66,7 @@ 0, 2290262, 2290262, 40040, 13748, 0xed26aeb4, F=0x0 0, 2330303, 2330303, 40040, 15092, 0x3c983538, F=0x0 0, 2370343, 2370343, 40040, 14636, 0x9b278a6c, F=0x0 -0, 2410384, 2410384, 40040, 29134, 0xf784be18 +0, 2410384, 2410384, 40040, 29135, 0x0a34be18 0, 2450424, 2450424, 40040, 10232, 0x5408e15b, F=0x0 0, 2490464, 2490464, 40040, 9769, 0xc93cb7f9, F=0x0 0, 2530505, 2530505, 40040, 14454, 0x45230dbe, F=0x0 @@ -81,7 +81,7 @@ 0, 2890868, 2890868, 40040, 14801, 0x40bae016, F=0x0 0, 2930909, 2930909, 40040, 17303, 0x9ce1fd31, F=0x0 0, 2970949, 2970949, 40040, 17678, 0x9bd66141, F=0x0 -0, 3010990, 3010990, 40040, 48672, 0x3215ce46 +0, 3010990, 3010990, 40040, 48673, 0x44b6ce46 0, 3051030, 3051030, 40040, 11894, 0x12e1fece, F=0x0 0, 3091070, 3091070, 40040, 16514, 0xc57aed05, F=0x0 0, 3131111, 3131111, 40040, 13044, 0x61914fa0, F=0x0 @@ -96,7 +96,7 @@ 0, 3491474, 3491474, 40040, 12208, 0x81a587c0, F=0x0 0, 3531515, 3531515, 40040, 14709, 0x5dffbe04, F=0x0 0, 3571555, 3571555, 40040, 14390, 0xbfd1e041, F=0x0 -0, 3611596, 3611596, 40040, 37236, 0xe7f924b1 +0, 3611596, 3611596, 40040, 37237, 0xfa9a24b1 0, 3651636, 3651636, 40040, 14056, 0x24714c7c, F=0x0 0, 3691676, 3691676, 40040, 19438, 0x0c50dcd5, F=0x0 0, 3731717, 3731717, 40040, 21728, 0x7eea4a11, F=0x0 @@ -111,7 +111,7 @@ 0, 4092080, 4092080, 40040, 16878, 0x98efbae2, F=0x0 0, 4132121, 4132121, 40040, 14685, 0x1bf78d65, F=0x0 0, 4172161, 4172161, 40040, 13127, 0x0b91881d, F=0x0 -0, 4212202, 4212202, 40040, 29390, 0xf6a5ed6b +0, 4212202, 4212202, 40040, 29391, 0x0955ed6b 0, 4252242, 4252242, 40040, 12576, 0xe9845ded, F=0x0 0, 4292282, 4292282, 40040, 12599, 0x96a79ab8, F=0x0 0, 4332323, 4332323, 40040, 16134, 0xb4c36d3f, F=0x0 diff --git a/tests/ref/fate/h264_mp4toannexb_ticket5927 b/tests/ref/fate/h264_mp4toannexb_ticket5927 index 95e35c4d802f2..006ea398fd6e0 100644 --- a/tests/ref/fate/h264_mp4toannexb_ticket5927 +++ b/tests/ref/fate/h264_mp4toannexb_ticket5927 @@ -1,12 +1,12 @@ -a3b02fd09392e01619cebc959d4d9ff2 *tests/data/fate/h264_mp4toannexb_ticket5927.h264 -595583 tests/data/fate/h264_mp4toannexb_ticket5927.h264 -#extradata 0: 33, 0x84fe08f8 +562487bfea635cdadbc23d390322b589 *tests/data/fate/h264_mp4toannexb_ticket5927.h264 +595585 tests/data/fate/h264_mp4toannexb_ticket5927.h264 +#extradata 0: 34, 0x8df608f8 #tb 0: 1/1200000 #media_type 0: video #codec_id 0: h264 #dimensions 0: 1920x1080 #sar 0: 0/1 -0, -48000, -9223372036854775808, 48000, 247993, 0x1ce821ea +0, -48000, -9223372036854775808, 48000, 247994, 0x2e1e21ea 0, 0, -9223372036854775808, 48000, 43354, 0xa05dca6f, F=0x0 0, 48000, -9223372036854775808, 48000, 11423, 0x5e8086dd, F=0x0 0, 96000, -9223372036854775808, 48000, 50798, 0x145fbe4f, F=0x0 @@ -18,4 +18,4 @@ a3b02fd09392e01619cebc959d4d9ff2 *tests/data/fate/h264_mp4toannexb_ticket5927.h2 0, 384000, -9223372036854775808, 48000, 54483, 0xefead99f, F=0x0 0, 432000, -9223372036854775808, 48000, 13705, 0x23cd27e8, F=0x0 0, 480000, -9223372036854775808, 48000, 22308, 0x4093b5af, F=0x0 -0, 528000, -9223372036854775808, 48000, 6369, 0x858b2aa1 +0, 528000, -9223372036854775808, 48000, 6370, 0x96c12aa1 diff --git a/tests/ref/fate/h264_mp4toannexb_ticket5927_2 b/tests/ref/fate/h264_mp4toannexb_ticket5927_2 index 8db6a7e54a7d7..51432b153533f 100644 --- a/tests/ref/fate/h264_mp4toannexb_ticket5927_2 +++ b/tests/ref/fate/h264_mp4toannexb_ticket5927_2 @@ -1,12 +1,12 @@ -a3b02fd09392e01619cebc959d4d9ff2 *tests/data/fate/h264_mp4toannexb_ticket5927_2.h264 -595583 tests/data/fate/h264_mp4toannexb_ticket5927_2.h264 -#extradata 0: 33, 0x84fe08f8 +562487bfea635cdadbc23d390322b589 *tests/data/fate/h264_mp4toannexb_ticket5927_2.h264 +595585 tests/data/fate/h264_mp4toannexb_ticket5927_2.h264 +#extradata 0: 34, 0x8df608f8 #tb 0: 1/1200000 #media_type 0: video #codec_id 0: h264 #dimensions 0: 1920x1080 #sar 0: 0/1 -0, -48000, -9223372036854775808, 48000, 247993, 0x1ce821ea +0, -48000, -9223372036854775808, 48000, 247994, 0x2e1e21ea 0, 0, -9223372036854775808, 48000, 43354, 0xa05dca6f, F=0x0 0, 48000, -9223372036854775808, 48000, 11423, 0x5e8086dd, F=0x0 0, 96000, -9223372036854775808, 48000, 50798, 0x145fbe4f, F=0x0 @@ -18,4 +18,4 @@ a3b02fd09392e01619cebc959d4d9ff2 *tests/data/fate/h264_mp4toannexb_ticket5927_2. 0, 384000, -9223372036854775808, 48000, 54483, 0xefead99f, F=0x0 0, 432000, -9223372036854775808, 48000, 13705, 0x23cd27e8, F=0x0 0, 480000, -9223372036854775808, 48000, 22308, 0x4093b5af, F=0x0 -0, 528000, -9223372036854775808, 48000, 6369, 0x858b2aa1 +0, 528000, -9223372036854775808, 48000, 6370, 0x96c12aa1 diff --git a/tests/ref/fate/hap-alpha-only-nosnappy-128x72 b/tests/ref/fate/hap-alpha-only-nosnappy-128x72 new file mode 100644 index 0000000000000..d9b1b56147f69 --- /dev/null +++ b/tests/ref/fate/hap-alpha-only-nosnappy-128x72 @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 128x72 +#sar 0: 1/1 +0, 0, 0, 1, 9216, 0x5967036f diff --git a/tests/ref/fate/hap-alpha-only-snappy-127x71 b/tests/ref/fate/hap-alpha-only-snappy-127x71 new file mode 100644 index 0000000000000..1559204ca229c --- /dev/null +++ b/tests/ref/fate/hap-alpha-only-snappy-127x71 @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 127x71 +#sar 0: 1/1 +0, 0, 0, 1, 9017, 0xc390c38c diff --git a/tests/ref/fate/hapenc-hap-none b/tests/ref/fate/hapenc-hap-none new file mode 100644 index 0000000000000..22c8b2c75163e --- /dev/null +++ b/tests/ref/fate/hapenc-hap-none @@ -0,0 +1,14 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: hap +#dimensions 0: 352x288 +#sar 0: 0/1 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 50696, 7fd5bc08f7b96326953ba6926cb06109 +0, 1, 1, 1, 50696, 24d172f2ea03994add2596a48151fca8 +0, 2, 2, 1, 50696, e5f2bac02ad850eb769007694a2f7acc +0, 3, 3, 1, 50696, 26042fbce3868ad012b0b4557fd95d8a +0, 4, 4, 1, 50696, 80902dd47d1211f1cd388652d5e0a797 diff --git a/tests/ref/fate/hapenc-hapa-none b/tests/ref/fate/hapenc-hapa-none new file mode 100644 index 0000000000000..9aa80ae83d05f --- /dev/null +++ b/tests/ref/fate/hapenc-hapa-none @@ -0,0 +1,14 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: hap +#dimensions 0: 352x288 +#sar 0: 0/1 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 101384, 7bd1e603a54fb468242c9e00b0a90359 +0, 1, 1, 1, 101384, 09bf0e48db9bf465f3d89a192ddfda2d +0, 2, 2, 1, 101384, 4993a96ed5f5d2bc0f0ff2080622eed2 +0, 3, 3, 1, 101384, 5cdbd0f763ba40366816588160ec73c2 +0, 4, 4, 1, 101384, 9202fe8358efde2c92c75210ed93c118 diff --git a/tests/ref/fate/hapenc-hapq-none b/tests/ref/fate/hapenc-hapq-none new file mode 100644 index 0000000000000..ee467b6753f65 --- /dev/null +++ b/tests/ref/fate/hapenc-hapq-none @@ -0,0 +1,14 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: hap +#dimensions 0: 352x288 +#sar 0: 0/1 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 101384, cb6ef787ae7adff965ba4904a57c2188 +0, 1, 1, 1, 101384, 7cd50676c256354c06f728a265556efd +0, 2, 2, 1, 101384, 454b14f7770a1f57830a678ea6e24b86 +0, 3, 3, 1, 101384, 6e6c088ed068d05870976fe78a75bb30 +0, 4, 4, 1, 101384, ba79bd8e7fc5d8919b174f0c8ea82753 diff --git a/tests/ref/fate/hapqa-extract-nosnappy-to-hapalphaonly-mov b/tests/ref/fate/hapqa-extract-nosnappy-to-hapalphaonly-mov new file mode 100644 index 0000000000000..f5ecdd4311411 --- /dev/null +++ b/tests/ref/fate/hapqa-extract-nosnappy-to-hapalphaonly-mov @@ -0,0 +1,73 @@ +[PACKET] +codec_type=video +stream_index=0 +pts=0 +pts_time=0.000000 +dts=0 +dts_time=0.000000 +duration=512 +duration_time=0.040000 +convergence_duration=N/A +convergence_duration_time=N/A +size=4612 +pos=36 +flags=K_ +data_hash=adler32:ed83c166 +[/PACKET] +[STREAM] +index=0 +codec_name=hap +codec_long_name=Vidvox Hap +profile=unknown +codec_type=video +codec_time_base=1/25 +codec_tag_string=HapA +codec_tag=0x41706148 +width=127 +height=71 +coded_width=128 +coded_height=72 +has_b_frames=0 +sample_aspect_ratio=1:1 +display_aspect_ratio=127:71 +pix_fmt=gray +level=-99 +color_range=unknown +color_space=unknown +color_transfer=unknown +color_primaries=unknown +chroma_location=unspecified +field_order=unknown +timecode=N/A +refs=1 +id=N/A +r_frame_rate=25/1 +avg_frame_rate=25/1 +time_base=1/12800 +start_pts=0 +start_time=0.000000 +duration_ts=512 +duration=0.040000 +bit_rate=922400 +max_bit_rate=N/A +bits_per_raw_sample=N/A +nb_frames=1 +nb_read_frames=N/A +nb_read_packets=1 +extradata_hash=adler32:00000001 +DISPOSITION:default=1 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +TAG:language=eng +TAG:handler_name=DataHandler +TAG:encoder=HAPAlpha Only +[/STREAM] diff --git a/tests/ref/fate/hapqa-extract-nosnappy-to-hapq-mov b/tests/ref/fate/hapqa-extract-nosnappy-to-hapq-mov new file mode 100644 index 0000000000000..c3a0a599fd401 --- /dev/null +++ b/tests/ref/fate/hapqa-extract-nosnappy-to-hapq-mov @@ -0,0 +1,73 @@ +[PACKET] +codec_type=video +stream_index=0 +pts=0 +pts_time=0.000000 +dts=0 +dts_time=0.000000 +duration=512 +duration_time=0.040000 +convergence_duration=N/A +convergence_duration_time=N/A +size=9220 +pos=36 +flags=K_ +data_hash=adler32:b3ccc147 +[/PACKET] +[STREAM] +index=0 +codec_name=hap +codec_long_name=Vidvox Hap +profile=unknown +codec_type=video +codec_time_base=1/25 +codec_tag_string=HapY +codec_tag=0x59706148 +width=127 +height=71 +coded_width=128 +coded_height=72 +has_b_frames=0 +sample_aspect_ratio=1:1 +display_aspect_ratio=127:71 +pix_fmt=rgb0 +level=-99 +color_range=unknown +color_space=unknown +color_transfer=unknown +color_primaries=unknown +chroma_location=unspecified +field_order=unknown +timecode=N/A +refs=1 +id=N/A +r_frame_rate=25/1 +avg_frame_rate=25/1 +time_base=1/12800 +start_pts=0 +start_time=0.000000 +duration_ts=512 +duration=0.040000 +bit_rate=1844000 +max_bit_rate=N/A +bits_per_raw_sample=N/A +nb_frames=1 +nb_read_frames=N/A +nb_read_packets=1 +extradata_hash=adler32:00000001 +DISPOSITION:default=1 +DISPOSITION:dub=0 +DISPOSITION:original=0 +DISPOSITION:comment=0 +DISPOSITION:lyrics=0 +DISPOSITION:karaoke=0 +DISPOSITION:forced=0 +DISPOSITION:hearing_impaired=0 +DISPOSITION:visual_impaired=0 +DISPOSITION:clean_effects=0 +DISPOSITION:attached_pic=0 +DISPOSITION:timed_thumbnails=0 +TAG:language=eng +TAG:handler_name=DataHandler +TAG:encoder=HAPQ +[/STREAM] diff --git a/tests/ref/fate/hapqa-extract-snappy1-to-hapalphaonly b/tests/ref/fate/hapqa-extract-snappy1-to-hapalphaonly new file mode 100644 index 0000000000000..9ab123f09d1d8 --- /dev/null +++ b/tests/ref/fate/hapqa-extract-snappy1-to-hapalphaonly @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: hap +#dimensions 0: 127x71 +#sar 0: 1/1 +0, 0, 0, 1, 3044, 0xcaf6ddd0 diff --git a/tests/ref/fate/hapqa-extract-snappy1-to-hapq b/tests/ref/fate/hapqa-extract-snappy1-to-hapq new file mode 100644 index 0000000000000..f658b1c0b4908 --- /dev/null +++ b/tests/ref/fate/hapqa-extract-snappy1-to-hapq @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: hap +#dimensions 0: 127x71 +#sar 0: 1/1 +0, 0, 0, 1, 8217, 0x04271f0f diff --git a/tests/ref/fate/hapqa-extract-snappy16-to-hapalphaonly b/tests/ref/fate/hapqa-extract-snappy16-to-hapalphaonly new file mode 100644 index 0000000000000..1bd920699ae2f --- /dev/null +++ b/tests/ref/fate/hapqa-extract-snappy16-to-hapalphaonly @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: hap +#dimensions 0: 127x71 +#sar 0: 1/1 +0, 0, 0, 1, 3513, 0x69c7014f diff --git a/tests/ref/fate/hapqa-extract-snappy16-to-hapq b/tests/ref/fate/hapqa-extract-snappy16-to-hapq new file mode 100644 index 0000000000000..8334d53d616ec --- /dev/null +++ b/tests/ref/fate/hapqa-extract-snappy16-to-hapq @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: hap +#dimensions 0: 127x71 +#sar 0: 1/1 +0, 0, 0, 1, 8726, 0xf889691c diff --git a/tests/ref/fate/hapqa-nosnappy-127x71 b/tests/ref/fate/hapqa-nosnappy-127x71 new file mode 100644 index 0000000000000..36069b4849f7b --- /dev/null +++ b/tests/ref/fate/hapqa-nosnappy-127x71 @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 127x71 +#sar 0: 1/1 +0, 0, 0, 1, 36068, 0x16c0a011 diff --git a/tests/ref/fate/hapqa-snappy1-127x71 b/tests/ref/fate/hapqa-snappy1-127x71 new file mode 100644 index 0000000000000..36069b4849f7b --- /dev/null +++ b/tests/ref/fate/hapqa-snappy1-127x71 @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 127x71 +#sar 0: 1/1 +0, 0, 0, 1, 36068, 0x16c0a011 diff --git a/tests/ref/fate/hapqa-snappy16-127x71 b/tests/ref/fate/hapqa-snappy16-127x71 new file mode 100644 index 0000000000000..36069b4849f7b --- /dev/null +++ b/tests/ref/fate/hapqa-snappy16-127x71 @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 127x71 +#sar 0: 1/1 +0, 0, 0, 1, 36068, 0x16c0a011 diff --git a/tests/ref/fate/hevc-conformance-PERSIST_RPARAM_A_RExt_Sony_3 b/tests/ref/fate/hevc-conformance-PERSIST_RPARAM_A_RExt_Sony_3 new file mode 100644 index 0000000000000..54f4db8c5f184 --- /dev/null +++ b/tests/ref/fate/hevc-conformance-PERSIST_RPARAM_A_RExt_Sony_3 @@ -0,0 +1,7 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 400x384 +#sar 0: 0/1 +0, 0, 0, 1, 921600, 0x702f0d67 +0, 1, 1, 1, 921600, 0x99822b52 diff --git a/tests/ref/fate/hevc-skiploopfilter b/tests/ref/fate/hevc-skiploopfilter new file mode 100644 index 0000000000000..9c29909c51735 --- /dev/null +++ b/tests/ref/fate/hevc-skiploopfilter @@ -0,0 +1,14 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 1920x1080 +#sar 0: 0/1 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 3110400, 076c9288843ef1197a8cbef7f9a13fee +0, 1, 1, 1, 3110400, 6190eeea952805ebde69d22961aaeb45 +0, 2, 2, 1, 3110400, 9aaa5111d5e6b25dcf5ddd19c58f17f7 +0, 3, 3, 1, 3110400, 52a487e5f71b314e33e6632b4496f0a6 +0, 4, 4, 1, 3110400, 13abb1c78313705b57a8298dc1e6c0e2 diff --git a/tests/ref/fate/id3v2-priv b/tests/ref/fate/id3v2-priv new file mode 100644 index 0000000000000..965c8695e8852 --- /dev/null +++ b/tests/ref/fate/id3v2-priv @@ -0,0 +1,5 @@ +[FORMAT] +TAG:title=id3v2-test +TAG:id3v2_priv.testowner=testdata +TAG:id3v2_priv.testowner2=\x00\x01\x02 +[/FORMAT] diff --git a/tests/ref/fate/mov-440hz-10ms b/tests/ref/fate/mov-440hz-10ms new file mode 100644 index 0000000000000..498879e52db52 --- /dev/null +++ b/tests/ref/fate/mov-440hz-10ms @@ -0,0 +1,11 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1/44100 +#media_type 0: audio +#codec_id 0: pcm_s16le +#sample_rate 0: 44100 +#channel_layout 0: 4 +#channel_layout_name 0: mono +#stream#, dts, pts, duration, size, hash +0, 0, 0, 960, 1920, 44e7e48ff08835ce30e93c7971dae7df diff --git a/tests/ref/fate/mov-bbi-elst-starts-b b/tests/ref/fate/mov-bbi-elst-starts-b new file mode 100644 index 0000000000000..3ba28b5e755d0 --- /dev/null +++ b/tests/ref/fate/mov-bbi-elst-starts-b @@ -0,0 +1,391 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1001/30000 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 1920x1080 +#sar 0: 1/1 +#tb 1: 1/48000 +#media_type 1: audio +#codec_id 1: pcm_s16le +#sample_rate 1: 48000 +#channel_layout 1: 3 +#channel_layout_name 1: stereo +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 3110400, e9454409af76038dbe56e834921d2fa8 +1, 0, 0, 1024, 4096, 620f0b67a91f7f74151bc5be745b7110 +1, 1024, 1024, 1024, 4096, 4963ab641585142fbac06502873fb6d3 +0, 1, 1, 1, 3110400, 37aa620e494d22ba248feea9a5a869a0 +1, 2048, 2048, 1024, 4096, 80649ae10d2587264fcb43c7dc25e61b +1, 3072, 3072, 1024, 4096, 01ec94c18060be08988e8b9b1c9de822 +0, 2, 2, 1, 3110400, 7b8be9619e4e1d618ab1ed85aff3957b +1, 4096, 4096, 1024, 4096, 3f8342da3124e22b89211c2f233eb5b2 +0, 3, 3, 1, 3110400, 756a4551420853bc3ae444e6b86169f3 +1, 5120, 5120, 1024, 4096, 4832d1a3f7d8aaceb0489c1ca0706d31 +1, 6144, 6144, 1024, 4096, 7e89f1e8318ed54d81e4efe3c679515f +0, 4, 4, 1, 3110400, 94a93c1669a96ebf41a7258177849396 +1, 7168, 7168, 1024, 4096, d73468c68e92c9e2939eb30d66a45bc2 +0, 5, 5, 1, 3110400, 5d1c49d3f43cd472683e4a039e376af5 +1, 8192, 8192, 1024, 4096, 72e1020c1bb961cb1c177f97e427edb9 +1, 9216, 9216, 1024, 4096, 1a4773af7080bd904a3b14c12a8028fa +0, 6, 6, 1, 3110400, e0e88cc34b0a9d7963cddf554a3909f0 +1, 10240, 10240, 1024, 4096, d39ae1809032c4807efe41520302bd37 +0, 7, 7, 1, 3110400, 1f464f2427aa3842224803b6d67154f8 +1, 11264, 11264, 1024, 4096, e26af86998d1a9579127a97dbe45890b +1, 12288, 12288, 1024, 4096, 148e1ab102c1c62d9018095c7e934eea +0, 8, 8, 1, 3110400, e5d610b8e53203b5ccb01877acb3ac56 +1, 13312, 13312, 1024, 4096, 96582c941184ad967e9e91198775e61f +1, 14336, 14336, 1024, 4096, 8d2371bb1524d9d007ae44519b55a055 +0, 9, 9, 1, 3110400, d1363fbdffbb85a0affe660bfd09b98c +1, 15360, 15360, 1024, 4096, 6034c9e409d8dcdfd032b44f631e2362 +0, 10, 10, 1, 3110400, 130bb4c17e963b092a717325498c06c3 +1, 16384, 16384, 1024, 4096, 3649e9edc65a042c4c913c06c3f3bff7 +1, 17408, 17408, 1024, 4096, a4cdb0c4bed48d1f7c4918e5590a542d +0, 11, 11, 1, 3110400, a3cb7a37fef5d8a49815dd15970c1f3d +1, 18432, 18432, 1024, 4096, a130e8ba9a47df0c76edf5c3ece5762f +0, 12, 12, 1, 3110400, 7dc4a4334fa9bb61f2ad56b3d059b3f7 +1, 19456, 19456, 1024, 4096, cf76a132c205c29a0b7042599973fda4 +1, 20480, 20480, 1024, 4096, b9b7d819599bb6d7cd53cc1bc0810ca7 +0, 13, 13, 1, 3110400, ccda106ec5899787c3bc8679ee052854 +1, 21504, 21504, 1024, 4096, 3d0d6ef8318a94416a56108248e6cad3 +0, 14, 14, 1, 3110400, 4254c7b01a67a0810bf234ba7b1f59d0 +1, 22528, 22528, 1024, 4096, a8a082b4c521d2e7fc990f54e3580a9e +1, 23552, 23552, 1024, 4096, 60b36c268bc98093f35a7c90c64b507c +0, 15, 15, 1, 3110400, 6c0acd9781cfecaf9a10fe91f8d6ec41 +1, 24576, 24576, 1024, 4096, c5211b49eb51cea4c16079eb54df3d12 +1, 25600, 25600, 1024, 4096, dddd55a31e8a65110a89de1af67861b0 +0, 16, 16, 1, 3110400, 2a9d5db0bc2f54e2c66834db64386bb7 +1, 26624, 26624, 1024, 4096, 0c220f1d405bb463469b54fa126a2c41 +0, 17, 17, 1, 3110400, 0140f515be87da399061764050d15b16 +1, 27648, 27648, 1024, 4096, 11d740234a9a4dd28e3191e258fc8e3b +1, 28672, 28672, 1024, 4096, e456943c722a9807669f57776dcb8c5d +0, 18, 18, 1, 3110400, cad554fe221fbd8ee848facebd7b24d2 +1, 29696, 29696, 1024, 4096, 3c13165d648f46c3e3e699b874da372a +0, 19, 19, 1, 3110400, 1e8474911cb1bd831808dc2beba540c0 +1, 30720, 30720, 1024, 4096, 7e7a46e3360f884507c95f640cd6f532 +1, 31744, 31744, 1024, 4096, 420d047ee4d55b7af2d97c5116e25d37 +0, 20, 20, 1, 3110400, f39c483fbf3c598c38cf543abad2c03c +1, 32768, 32768, 1024, 4096, b3334bcd2ed3b2ab32ac13c24a8d1322 +0, 21, 21, 1, 3110400, 3b21171a003827a203c0c5853c36893e +1, 33792, 33792, 1024, 4096, 1472898e0d4fafd52fc0adb789e06987 +1, 34816, 34816, 1024, 4096, f3e7c33d92578fa5eb90933491106c37 +0, 22, 22, 1, 3110400, 40e8733f93c468cb58c3921c80f81c68 +1, 35840, 35840, 1024, 4096, 7d7f8e8f542be9291b7895472f8cf0a7 +0, 23, 23, 1, 3110400, a2d716f215af7d778bd605decae201dd +1, 36864, 36864, 1024, 4096, 66e2e35d40beb6e1df30d4d180661d4b +1, 37888, 37888, 1024, 4096, 8fc0c16fc3ec5db47e437263b429406b +0, 24, 24, 1, 3110400, e6fb8d3f1c9747f185b50eded67ff0ab +1, 38912, 38912, 1024, 4096, dd6331f430abf41dade4e4a85784745f +1, 39936, 39936, 1024, 4096, 5c693b37419fe43fb83b715d4f7083ec +0, 25, 25, 1, 3110400, fe4e0cf566674672ad043f24eae02e63 +1, 40960, 40960, 1024, 4096, 9e13b054c07feac0fad601ed4823996e +0, 26, 26, 1, 3110400, f57d4d32012dfcb14a270bdc90812e5e +1, 41984, 41984, 1024, 4096, dbffea22781b35088859868189e270aa +1, 43008, 43008, 1024, 4096, 59f1a985d7a96273bf48be9dc8a7d4d2 +0, 27, 27, 1, 3110400, fe7aa8c1754b9590fe75b783d4e126ed +1, 44032, 44032, 1024, 4096, b07e02d0bfecbde9b48e6e83952aa3c7 +0, 28, 28, 1, 3110400, 29ae6e541021bf481c8937c37ac34570 +1, 45056, 45056, 1024, 4096, d0dfca31885ac1d21fe42bb26e3b11ec +1, 46080, 46080, 1024, 4096, 5479670aea3a4d07a61b9edcc2113c7b +0, 29, 29, 1, 3110400, 211e0803b5a704c7ef1c36fc5c182710 +1, 47104, 47104, 1024, 4096, 0118d7fc0d0f8462647f37aa6d82c8fc +0, 30, 30, 1, 3110400, a4ea3a4686d214ad54fcdce63f8c2dc0 +1, 48128, 48128, 1024, 4096, cc2b22d4c7497accb6b194968b407e10 +1, 49152, 49152, 1024, 4096, fe8d30c082a3608b8ccf5e3d6f4b0ddb +0, 31, 31, 1, 3110400, 8af971cf637609534ec59b6f29a3666e +1, 50176, 50176, 1024, 4096, ed15a6aa2d87395b47888f744f41df30 +1, 51200, 51200, 1024, 4096, 8d4971ee25d274822cceaa00cc8df1a1 +0, 32, 32, 1, 3110400, 8cfe93dfd76e4f97cc04a145bb559af5 +1, 52224, 52224, 1024, 4096, 799f1c9cac6c3cedaac80cc6b26df827 +0, 33, 33, 1, 3110400, 691fe61398016f767ea7ba781ef72953 +1, 53248, 53248, 1024, 4096, 40cbefbb455231c0f21af129e2504395 +1, 54272, 54272, 1024, 4096, 05eb1731cb93ff68815e92f0a528d4d7 +0, 34, 34, 1, 3110400, 7eaf5bc5e942f8218f46c9c505d7b58c +1, 55296, 55296, 1024, 4096, de96fa062c59b6b3b88731e60e02d040 +0, 35, 35, 1, 3110400, feacc8282186935e310ec2dccbb79239 +1, 56320, 56320, 1024, 4096, 14d38d89079c1b7801987c5315477d11 +1, 57344, 57344, 1024, 4096, 9a0029ae7fc7e029402ec29536288cff +0, 36, 36, 1, 3110400, a5dfb5c4c23e647e2c77dd117e4ed714 +1, 58368, 58368, 1024, 4096, 83925a6ebf953e6b711d3042c95ffe51 +0, 37, 37, 1, 3110400, da9306c2872788ba2a587eab7f597f13 +1, 59392, 59392, 1024, 4096, 5b332b22a2a8ae72cbf8154d2cfd9b5d +1, 60416, 60416, 1024, 4096, 8dcd5041b49036e43f74819439a6db63 +0, 38, 38, 1, 3110400, 19d14a655aa02cc2767afd9ed9bc2ff4 +1, 61440, 61440, 1024, 4096, 90ea3ac56003b4f1c0242a611746b76a +0, 39, 39, 1, 3110400, 4d9e6455fb71d5cd511dddf894b4f7d8 +1, 62464, 62464, 1024, 4096, 6ed9f815739e6e3b8ed125688f693d5f +1, 63488, 63488, 1024, 4096, e056b91f4875029af3c29a26e37380a1 +0, 40, 40, 1, 3110400, 052c32c00bc1b40d5270f4b5c4d34d6b +1, 64512, 64512, 1024, 4096, 36ff82cb34ffc9ea60b1fbc8d3edd9f1 +1, 65536, 65536, 1024, 4096, 975c2d6080532645be510241d52b788c +0, 41, 41, 1, 3110400, 645e0c3eb8599c2cc712a97cbae9d1d3 +1, 66560, 66560, 1024, 4096, 9a53c620f19d5bb733c8bd068137ba3a +0, 42, 42, 1, 3110400, d0b3fe092511fed0e384ffad85f6ae3c +1, 67584, 67584, 1024, 4096, 482365611c86663b70a13511d8194282 +1, 68608, 68608, 1024, 4096, 4f9002718a7103a4b15b96e9e08a2cfd +0, 43, 43, 1, 3110400, 131c090f806658ffbb4949b3310a6348 +1, 69632, 69632, 1024, 4096, 2301e3336164fe298b85006b0e7dc0b8 +0, 44, 44, 1, 3110400, 71e8042ed01a1bbe971417d87685dda1 +1, 70656, 70656, 1024, 4096, d8b4c47bb3f58a70109d70edaea9916b +1, 71680, 71680, 1024, 4096, ff87ca54ad112c083b1cc25043429410 +0, 45, 45, 1, 3110400, 948cc8d7eceb2e512c8660063143557b +1, 72704, 72704, 1024, 4096, eee9c7fd3c78681fcfcdf40ed7ee2c6b +0, 46, 46, 1, 3110400, 8b580d4f620af52ac0a5702197f5e9d6 +1, 73728, 73728, 1024, 4096, d05a2d810e2c201cff9e115c48cff977 +1, 74752, 74752, 1024, 4096, 5ef14640b86062c99427e0177b33657c +0, 47, 47, 1, 3110400, a30bfc0727c6abb477751969c1b1450c +1, 75776, 75776, 1024, 4096, 92398dd17af6362aa81fe8a9aad0af01 +1, 76800, 76800, 1024, 4096, 131b910e0af30e5250726b3d4a5f4f10 +0, 48, 48, 1, 3110400, 28381142e60e9011d0cd75e7881c1956 +1, 77824, 77824, 1024, 4096, 50157f3541acd42d2c460e125a9f2393 +0, 49, 49, 1, 3110400, 1b4bdae40d76ed7625f85da7c5289360 +1, 78848, 78848, 1024, 4096, 266fd18529d95b7347e9a019271056fc +1, 79872, 79872, 1024, 4096, 2f9a347ce750501f2e4d0a36c95bc8b0 +0, 50, 50, 1, 3110400, 354fb545adf6082dc57b8077ba1466ad +1, 80896, 80896, 1024, 4096, 0f8b0626ef01d0e941914d7810945aa1 +0, 51, 51, 1, 3110400, c969f21be0dcbef6b232d3f0a9e3f189 +1, 81920, 81920, 1024, 4096, 51da6b0c3d5daddb8f4635d692b0e8ba +1, 82944, 82944, 1024, 4096, aac8a7152103243dabd94e2a37caf53f +0, 52, 52, 1, 3110400, 4ff19ab89ebe466e8ce3df0ba25b6b0a +1, 83968, 83968, 1024, 4096, 50c8d5b0a373c07ecb66ca33e087a299 +0, 53, 53, 1, 3110400, 49f601932c19ae8d405771e9cfd4f9e8 +1, 84992, 84992, 1024, 4096, 2abd975868c9805fa456a08f1ab16c91 +1, 86016, 86016, 1024, 4096, 56309326bc80a6216b048934713db907 +0, 54, 54, 1, 3110400, c75d2221327d5953b013fdc9d36dbcd3 +1, 87040, 87040, 1024, 4096, 470fd4997793f53ad2b21b47c6b98bb1 +1, 88064, 88064, 1024, 4096, 1aed57e8ba33350711e1ff668c906953 +0, 55, 55, 1, 3110400, 6c8b8c6012b6ac36c4c2a3ab5629ec61 +1, 89088, 89088, 1024, 4096, 9e910446a3b8d30f270c05aca011704d +0, 56, 56, 1, 3110400, 44a05705ad5cb730e7244c36b4f94771 +1, 90112, 90112, 1024, 4096, af6c036d66dd5bb5c250f16207173180 +1, 91136, 91136, 1024, 4096, de76d587f349fe597e65cb1f51bdcc34 +0, 57, 57, 1, 3110400, 0ee53224814c84224525181aacbd9a39 +1, 92160, 92160, 1024, 4096, 7abab5bffebfcc801a11f6b7905a13c9 +0, 58, 58, 1, 3110400, cd7797aa75c96a2a71e939ea6b677310 +1, 93184, 93184, 1024, 4096, 3567caaaea75b1cda5920fd6dbf2a016 +1, 94208, 94208, 1024, 4096, 2a6848418d829a273b85620e5b59cabe +0, 59, 59, 1, 3110400, ac2207156da29fd33ca1c66224445bbc +1, 95232, 95232, 1024, 4096, 79d0c213acefa2bc00de4fd455b34df9 +0, 60, 60, 1, 3110400, 1669c959bd2b6f245cc83ea00d0de83f +1, 96256, 96256, 1024, 4096, 267414473e0e7c75c7c1dde7be001762 +1, 97280, 97280, 1024, 4096, 893107ddb969cbc25a5aa8c564559836 +0, 61, 61, 1, 3110400, a74e6586842a4c877fa9a123e7b8ef94 +1, 98304, 98304, 1024, 4096, 1555a7117d5254afef3e36b1d0a9edd2 +0, 62, 62, 1, 3110400, 5af4edbf8a77ead17f4891cbac6d72be +1, 99328, 99328, 1024, 4096, dd92c3241e45d54cc072fc0307d1850c +1, 100352, 100352, 1024, 4096, 95c55b1767ddea9af80edbb32e2b4dbc +0, 63, 63, 1, 3110400, 52598cb5f3cb75bc401370118bcb2c49 +1, 101376, 101376, 1024, 4096, 1d133e7a83f0cf96a6e9cee90d17975a +1, 102400, 102400, 1024, 4096, b71b82a4abcde640a46fcc3bd6930d51 +0, 64, 64, 1, 3110400, d44aa05de89e71b3af23de9afbb2a3b1 +1, 103424, 103424, 1024, 4096, 57697c6f8e32dda304b77b2881b5011d +0, 65, 65, 1, 3110400, 161fd1ff8b477a137e113ce7e6ac26f7 +1, 104448, 104448, 1024, 4096, 592725ee5ee2adfc02e8c189f402a3d9 +1, 105472, 105472, 1024, 4096, 2b1073734ea08c0cfeeaab15ad04aa60 +0, 66, 66, 1, 3110400, b9b5efaf5f74954897882b0f09a5c088 +1, 106496, 106496, 1024, 4096, 18f2a5daef2293e690fe0915127cb795 +0, 67, 67, 1, 3110400, 1405f3d5e75c2ffd390b46f7def70478 +1, 107520, 107520, 1024, 4096, 4fa75ff788019d99f6ab0ad2ee5cc3d4 +1, 108544, 108544, 1024, 4096, d40f1172149821d84130990d5acd9395 +0, 68, 68, 1, 3110400, 3bf19eda056d5fc609662bf5ca8e3b33 +1, 109568, 109568, 1024, 4096, edae14a39d1034cfce5655337df2206e +0, 69, 69, 1, 3110400, 8ba1925dc6b38a340e51aa234b5ff4df +1, 110592, 110592, 1024, 4096, 574a6a3b427314c2eb48226d2d7ce67d +1, 111616, 111616, 1024, 4096, ebf13ab2795c091f15b9086d5bf2e11e +0, 70, 70, 1, 3110400, 301aecbe3f8bf3831d6de540a568abbc +1, 112640, 112640, 1024, 4096, 074c63c81345804c7437de33cb5e355f +1, 113664, 113664, 1024, 4096, 58da9edb5e278e292cebebf6b26435b0 +0, 71, 71, 1, 3110400, 388565f088710aeb0f50ecdf8ef0ee86 +1, 114688, 114688, 1024, 4096, ce75fd079a21e0637900ac491c4fbc36 +0, 72, 72, 1, 3110400, df27196ff8da5085c58979deeae9c4a1 +1, 115712, 115712, 1024, 4096, 92153c14aeabfb4b4546c340201202b0 +1, 116736, 116736, 1024, 4096, f02e8d23ee0ca80713b4458873ce724f +0, 73, 73, 1, 3110400, 750226c84aae270449e0a20751218217 +1, 117760, 117760, 1024, 4096, 0adec04349d269f7dde27c59c7077954 +0, 74, 74, 1, 3110400, 076d4246e5494e6d5cf8ffb09be3a751 +1, 118784, 118784, 1024, 4096, 4408d6824ca6c2080fd76c1ab840382c +1, 119808, 119808, 1024, 4096, c3603730a05cff479148d9b69b7ed2e8 +0, 75, 75, 1, 3110400, 9f626289f18a3482628b511840deaa10 +1, 120832, 120832, 1024, 4096, 25a6af5ef98aae3c40610e58ca65b8a9 +0, 76, 76, 1, 3110400, f925e3ff4bda9962a313b6ac21a201f1 +1, 121856, 121856, 1024, 4096, 5ad875e4437059157f0f3a5ec911e741 +1, 122880, 122880, 1024, 4096, cfc06fdc755579be7440fca797d81191 +0, 77, 77, 1, 3110400, 1d893861545e804944c519e580204988 +1, 123904, 123904, 1024, 4096, 7c783d7b973bb8048eeaa568297cfa35 +0, 78, 78, 1, 3110400, 4d42fca73082fde38020a8fec0b27db2 +1, 124928, 124928, 1024, 4096, cae22b99b2c6fea527fb5c038d3765f8 +1, 125952, 125952, 1024, 4096, fc4b5ef5a5a28102bf782b8732fc2993 +0, 79, 79, 1, 3110400, ed88335480ef00aedcf73c3a8712705c +1, 126976, 126976, 1024, 4096, e278968277ccc64992ba6bb73ad9909d +1, 128000, 128000, 1024, 4096, e2eb81d30fe7fa901eaf295fca8bc8b8 +0, 80, 80, 1, 3110400, 968ba4c93f80cb8c6fbfaccb765c3d70 +1, 129024, 129024, 1024, 4096, 5a9b99c0639bd80ef7f20971590e23c7 +0, 81, 81, 1, 3110400, 01ef52b0a18f46556ba9e00d1b0c77af +1, 130048, 130048, 1024, 4096, 2765d109f09efa2f2661dfd2e666f25c +1, 131072, 131072, 1024, 4096, 1ff52d5870cd667388fe69f48e228fc6 +0, 82, 82, 1, 3110400, 54582f2ae6878b37cbd1b5c576fd09c7 +1, 132096, 132096, 1024, 4096, 3612470a58bb5eab26239fbd3d097866 +0, 83, 83, 1, 3110400, fec6585d244257b52c90cfa19b22fd7c +1, 133120, 133120, 1024, 4096, be170a1e3eba4c53b0e2fc8b795c7767 +1, 134144, 134144, 1024, 4096, abb85ab4987c50e05ecab0e831d53fd6 +0, 84, 84, 1, 3110400, be1e0237c5d8bab98aa75a91e0d4bd9b +1, 135168, 135168, 1024, 4096, 2e9b5c17dcaf77f171544c0eee6cf191 +0, 85, 85, 1, 3110400, 1138a9f316d1a2a9ae3c42d777561595 +1, 136192, 136192, 1024, 4096, 54c1c5d9c706e1999b2243828736c98d +1, 137216, 137216, 1024, 4096, 7b482f85e123981e8eb37c364b2f4bbe +0, 86, 86, 1, 3110400, 62da42e9e8643ec9b1299bbeaffa4be5 +1, 138240, 138240, 1024, 4096, 0be223967283ac3a0029fad458176155 +1, 139264, 139264, 1024, 4096, 8ec0c4054d484ebf8d68e32c3ffb5924 +0, 87, 87, 1, 3110400, 55fc4dcfb7f8bab37518884fc6747416 +1, 140288, 140288, 1024, 4096, 0308762a4362acbf1c9e1e62e5055880 +0, 88, 88, 1, 3110400, 51be69793bfae3fe078d04e8dee3a48b +1, 141312, 141312, 1024, 4096, 56a18f795b25ef93d27a53a9f6a87ec9 +1, 142336, 142336, 1024, 4096, ad46ed8c3ac23b79bbd066e43b77f4e6 +0, 89, 89, 1, 3110400, 363b794880a2cc06e5be4626c6847c19 +1, 143360, 143360, 1024, 4096, 62719a7d4521ac82957ce3f52ba21854 +0, 90, 90, 1, 3110400, cd1d585cf9cb68f72f7d6a0ec9ab96ab +1, 144384, 144384, 1024, 4096, 8854128aa8377ad5e52af990d4642ef5 +1, 145408, 145408, 1024, 4096, 38827bf7a129f92062b90fcf03ba80c1 +0, 91, 91, 1, 3110400, 138f8686ee7294bf4af072cee7043f52 +1, 146432, 146432, 1024, 4096, 24d4e112b275116dcb512e6b283487e3 +0, 92, 92, 1, 3110400, 137c1bdc2bb6fa1e181f84b09c14e0b6 +1, 147456, 147456, 1024, 4096, 03c374d9d72df87f99427fe1045be8da +1, 148480, 148480, 1024, 4096, c0c5a8fd24d5a9f535118ec266468976 +0, 93, 93, 1, 3110400, e7bc46739c46ec886fc5059af72f772a +1, 149504, 149504, 1024, 4096, 3381472e14c42a06cdcf35774a0b3a9a +1, 150528, 150528, 1024, 4096, 4c07a7a02831675a686c6f31e2809e4a +0, 94, 94, 1, 3110400, db4c2aa67c76573e4880b029bef59c8d +1, 151552, 151552, 1024, 4096, adde928f734ffe6c07446c9d70214f74 +0, 95, 95, 1, 3110400, 3a287113ad2196420a0474243bd1813d +1, 152576, 152576, 1024, 4096, f1ff82fec1ef096090acbf60212b2b69 +1, 153600, 153600, 1024, 4096, e3b271991cc2cd4fdb56616443c9f3e8 +0, 96, 96, 1, 3110400, d3ed803ca1984f021802e6c7364cb57f +1, 154624, 154624, 1024, 4096, 025c3272bfb9f24ab687bc818d57d853 +0, 97, 97, 1, 3110400, 776d99c2973261c12e978fe9fe5c5794 +1, 155648, 155648, 1024, 4096, 8bb2de059194408962be4dfdd88775fc +1, 156672, 156672, 1024, 4096, eb61bcbcc9897d01f5645a0662dfbd6d +0, 98, 98, 1, 3110400, 62ee2ec1261db8544ded9db8c4442f15 +1, 157696, 157696, 1024, 4096, 48a3c897183538de9920e94417f54733 +0, 99, 99, 1, 3110400, 1bfabc7ab3701e112e76955a449431d7 +1, 158720, 158720, 1024, 4096, ffe159d137e51d8fd4d5b3639df563a3 +1, 159744, 159744, 1024, 4096, 7702e58e4ae075b6e12e863f8c5d908e +0, 100, 100, 1, 3110400, e03dfc70c25b77fc47ea42ddb8d5da5c +1, 160768, 160768, 1024, 4096, 2e2b497643e1b6bf13dd5e585ecd9092 +0, 101, 101, 1, 3110400, b0f0c308b49cb82fad3b4995cb60b6a1 +1, 161792, 161792, 1024, 4096, fcce76ebba5166966db792dfc77fda3d +1, 162816, 162816, 1024, 4096, ccf5a819e00ce8c5197ae5b2b827f3e5 +0, 102, 102, 1, 3110400, 627c888ea94dabff2aaf96c800a85f7a +1, 163840, 163840, 1024, 4096, 2385c9e205cfdd5e0b2ac54e9ef0f525 +1, 164864, 164864, 1024, 4096, 40214ba3f9bdc1bbb7d59e1fdb9def2f +0, 103, 103, 1, 3110400, f2231eac6e5885f61f470a5c6b65ceea +1, 165888, 165888, 1024, 4096, 52516e860beca0af0d80f79266c761cc +0, 104, 104, 1, 3110400, ec873def59cde7c114fe27ba1b2c25a6 +1, 166912, 166912, 1024, 4096, a25848945235fd70d1021b9a92dafd8d +1, 167936, 167936, 1024, 4096, 38c7a26c7a545df5fa1721ee3e820309 +0, 105, 105, 1, 3110400, 7a5e98b10b1f984b624bc6399a45dde2 +1, 168960, 168960, 1024, 4096, 506d3c3b34f060a0516011ca237cb6a5 +0, 106, 106, 1, 3110400, 180d7b9ef69a8ee32e5fcc3b9579c11f +1, 169984, 169984, 1024, 4096, 2ef3cd56dfc870a251bb97f4d474be84 +1, 171008, 171008, 1024, 4096, 383c82e600ebadddd0467cc3a9575f3e +0, 107, 107, 1, 3110400, 8c0107e3bda4c993131b361d598b4b4d +1, 172032, 172032, 1024, 4096, b99763cdc1d5412f89e7d1fcb3bd1c35 +0, 108, 108, 1, 3110400, 31e1ea32c3200a41814b5890b81c5211 +1, 173056, 173056, 1024, 4096, 7b3ecb91c63f7f86d6e96f305b3bd507 +1, 174080, 174080, 1024, 4096, 6945621a1ee0fbc68e7db786bc837f53 +0, 109, 109, 1, 3110400, f6223221be5136d03c87333c7f2113c5 +1, 175104, 175104, 1024, 4096, fb1de71ab0d840699834d583fbd3468e +1, 176128, 176128, 1024, 4096, 2a3b2d299d87f5b982156ae740fb7b46 +0, 110, 110, 1, 3110400, 325d0fb65e35826aebb0f80fc34f426f +1, 177152, 177152, 1024, 4096, 6462952e8555172110c37c579d45f63c +0, 111, 111, 1, 3110400, 1328e8c69419fe1c44fc6cfa1f648839 +1, 178176, 178176, 1024, 4096, 279537a0668d254a6710c935f2a7b8d7 +1, 179200, 179200, 1024, 4096, 286a27fee95bf8773ee8ea03621e9502 +0, 112, 112, 1, 3110400, b234f9aab6965e136bb283a2ad0fbb68 +1, 180224, 180224, 1024, 4096, 343413b110fe48674dddeba071440707 +0, 113, 113, 1, 3110400, 3961ef43173c69a28d2196f4fa11d37a +1, 181248, 181248, 1024, 4096, 66265d80629369fc9fffddbbe6ef104d +1, 182272, 182272, 1024, 4096, 3ff193da4d2168f97f17841f9669d33e +0, 114, 114, 1, 3110400, 943c6dd42254d346d81fd55bfad60573 +1, 183296, 183296, 1024, 4096, dd4074398b101502c29009687686e78d +0, 115, 115, 1, 3110400, 0028c32eacb6f4d77cb98cf856d266e4 +1, 184320, 184320, 1024, 4096, 562be444896543f259527081c7795597 +1, 185344, 185344, 1024, 4096, 145b4b260f2393ec1e3464d79c87fe8e +0, 116, 116, 1, 3110400, f478fe49fed80b92eaa182aa8e794077 +1, 186368, 186368, 1024, 4096, 6884ebc820bb41e61dc54a87bd55011e +0, 117, 117, 1, 3110400, 9a52c061c135bd75ee317fe48a2cddf8 +1, 187392, 187392, 1024, 4096, d2d8b2fd7a140a3f32d5649f8e507637 +1, 188416, 188416, 1024, 4096, 767071a409e0b07bd2cdb250c3c89607 +0, 118, 118, 1, 3110400, c327b95c8afa716f7719603d2b65679b +1, 189440, 189440, 1024, 4096, 64c4eed5e1b85e0728b1b0e3de30ffa1 +1, 190464, 190464, 1024, 4096, 11ffef7e85d9925a4032b3bcd9740e20 +0, 119, 119, 1, 3110400, edd3b4c4fa157940b9c252a7d94e6f55 +1, 191488, 191488, 1024, 4096, 99893421a493664be17085567e160280 +0, 120, 120, 1, 3110400, 5ccdffe7356a73d2d11eb7767ddfa396 +1, 192512, 192512, 1024, 4096, ea422077bc582aef4af5bf3ca3aa062a +1, 193536, 193536, 1024, 4096, a9e7ab9c45faf39f3cd1eee69c95d647 +0, 121, 121, 1, 3110400, 7c4d8083656581ccc666597da5559a46 +1, 194560, 194560, 1024, 4096, fc19b6642df3b85c7ebe684e705bf29d +0, 122, 122, 1, 3110400, 28cae533418f9a5d62869cbed0be384c +1, 195584, 195584, 1024, 4096, 39420620aea9d61b240691dada0f3063 +1, 196608, 196608, 1024, 4096, 5ad516a55655cdc2a3348badc2c7e5a1 +0, 123, 123, 1, 3110400, e9cf527a059c80461fd507bab4817069 +1, 197632, 197632, 1024, 4096, fa4f3d45c1cfc88088b4cd6f2924184d +0, 124, 124, 1, 3110400, a2f2518b8a25932afbb78523e8da289e +1, 198656, 198656, 1024, 4096, 689be1d6f84b136537df11b8ed22b540 +1, 199680, 199680, 1024, 4096, 9612dad6c93c75b6911f21997f2f7aee +0, 125, 125, 1, 3110400, 8fcbddce7f2a6c3bc380ad4cec17e51c +1, 200704, 200704, 1024, 4096, defe4b66e5dd9c6a527aeb9ebec04cdf +1, 201728, 201728, 1024, 4096, 0c39b71be01611d6be02b796aec2c6de +0, 126, 126, 1, 3110400, 32ff7b550d09821b2b1eb64c288559ba +1, 202752, 202752, 1024, 4096, 2150a3d6fdec61cd587b83217f9bbb2c +0, 127, 127, 1, 3110400, 1eb4e9050a6657ab9290ac58ed3aa93f +1, 203776, 203776, 1024, 4096, 4be35b36d46ca56b778ae0afdd1e4200 +1, 204800, 204800, 1024, 4096, fb79d3d9d0e4d590882cbd023bbcd00d +0, 128, 128, 1, 3110400, e45fd52e9ec3ad2d42740dd7cb5e971b +1, 205824, 205824, 1024, 4096, d4295a4a32d647a04ec0eab639c0d9fc +0, 129, 129, 1, 3110400, d625b970a797e37e465d9319471d40c3 +1, 206848, 206848, 1024, 4096, f03478b7689af9bdf6e67d271a4b3114 +1, 207872, 207872, 1024, 4096, 9fd97010278dc9147d8b73be9aacfb35 +0, 130, 130, 1, 3110400, b98e4a8fd994915a3dde3def26a9b171 +1, 208896, 208896, 1024, 4096, 2b9670707ad661b2125620d2156f11f6 +0, 131, 131, 1, 3110400, a99b759bdfcf7f7cee8f1ee84ca2d66d +1, 209920, 209920, 1024, 4096, e1b2afbfcb5edb8e4b88ae9c08848c30 +1, 210944, 210944, 1024, 4096, 58c8914fd4ec12bfe13f388050b251e8 +0, 132, 132, 1, 3110400, 5439cd9643a76d21e5f1deb0aa4000a2 +1, 211968, 211968, 1024, 4096, 4d8e0b0d4cd31f98eb4ca9922bba1497 +1, 212992, 212992, 1024, 4096, 02b1c362c2f1939fa41a4cc8d4b25d6a +0, 133, 133, 1, 3110400, 383640e375fa6b46bba21acd556f0efd +1, 214016, 214016, 1024, 4096, 10d3b076171713e9978c67515fdd4304 +0, 134, 134, 1, 3110400, e91ba9ef2595fbee20fb0f1d5e0b92ba +1, 215040, 215040, 1024, 4096, 726450c85dbd838bc00c6866d4c10786 +1, 216064, 216064, 1024, 4096, 3479045f30a97faaed2f241478ea0447 +0, 135, 135, 1, 3110400, 9c8ce07f22215b8450b01e82fc085b3d +1, 217088, 217088, 1024, 4096, 63d5ca0f8d7e086dfae54e86a75f8971 +0, 136, 136, 1, 3110400, 4f11b553eaaa1feb682842a1123e1b43 +1, 218112, 218112, 1024, 4096, 41953b97d8f2d3e5c05827c670e3c562 +1, 219136, 219136, 1024, 4096, 50709f01bf8dbe8e40f5b414211e7dbe +0, 137, 137, 1, 3110400, 32e8823643ce4cb0154482611f4de51d +1, 220160, 220160, 1024, 4096, 03d813116d70fed14987e17ebcaeed3e +0, 138, 138, 1, 3110400, 207ee505f0cfb54a3fd1fd5256ba906a +1, 221184, 221184, 1024, 4096, d695e2905aac1dee39a8f35e3a4b7fed +1, 222208, 222208, 1024, 4096, 35c5c7a9cfe5cfb08d3dd269aec9b901 +0, 139, 139, 1, 3110400, f95de0e1f3cd2559b6a81a6dbe53ed5c +1, 223232, 223232, 1024, 4096, 2a4f3699775e0d67651c4c40913c9059 +0, 140, 140, 1, 3110400, 3c47b1ea481bdae7b7730084407fd22a +1, 224256, 224256, 1024, 4096, bb561814ffb5b76a1faf7df4375c233e +1, 225280, 225280, 1024, 4096, a3c632a0d54e07e3928aec8ef169fd11 +0, 141, 141, 1, 3110400, fbec533f0cb4d79185e09c9917329473 +1, 226304, 226304, 1024, 4096, a805c35e91615f17669130ec58191b75 +1, 227328, 227328, 1024, 4096, 0858806663f6430219b68df7ff83a932 +0, 142, 142, 1, 3110400, 5b9f1cf510bc72d42772a78d400d9831 +1, 228352, 228352, 1024, 4096, 59339810dea47a705ab9e0913f7a88d5 +0, 143, 143, 1, 3110400, 6b031f180439e753b6b0e36de46dc1a5 +1, 229376, 229376, 1024, 4096, 6d9cdd81e0ba85ad4e00c34e2a096611 +1, 230400, 230400, 1024, 4096, cd6dd8dd0dc5198b7bf0b45d4ecc2608 +0, 144, 144, 1, 3110400, c09870b1e13efa8b685d89ebd781e835 +1, 231424, 231424, 1024, 4096, c2dd972eb34af27a210bcfa3e5f8da93 +0, 145, 145, 1, 3110400, 439c6cc6f7157eaf046e06d9e55ddf69 +1, 232448, 232448, 1024, 4096, 0993bc45c9582048d6982beeaec6b72e +1, 233472, 233472, 1024, 4096, ae93c593fd775ae997c43eef40fe8d0e +0, 146, 146, 1, 3110400, 7d5520c184c7bf3f175eea3526deb7a8 diff --git a/tests/ref/fate/mov-elst-ends-betn-b-and-i b/tests/ref/fate/mov-elst-ends-betn-b-and-i new file mode 100644 index 0000000000000..d6f325bba29ad --- /dev/null +++ b/tests/ref/fate/mov-elst-ends-betn-b-and-i @@ -0,0 +1,33 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x240 +#sar 0: 1/1 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 115200, e10741e5457e9326d5e992e6c05c3e32 +0, 1, 1, 1, 115200, 7e20f8729b6b53dc11791927bf4a5aec +0, 2, 2, 1, 115200, 4e5dc2b806e394cd666c968f736fecd0 +0, 3, 3, 1, 115200, 7a3c7473d44c5f60c07655f6fc0c2ac3 +0, 4, 4, 1, 115200, 038254422a603a3270c09cdcd149707b +0, 5, 5, 1, 115200, 7553b6b4547cb23ef8f0392ed5a5d4b0 +0, 6, 6, 1, 115200, 6d017ede7f446124af7308667cb0dc41 +0, 7, 7, 1, 115200, 77752f0288ae64f857732b8e62e47457 +0, 8, 8, 1, 115200, d656833951af99330625f7c6de7685c4 +0, 9, 9, 1, 115200, 14338b833e431e566ac98da841600bfe +0, 10, 10, 1, 115200, 07ea95d1659f3c4424a470a546d0df6e +0, 11, 11, 1, 115200, fd05b8cc83072f813e89d394d1f6efc6 +0, 12, 12, 1, 115200, 750b82ca5c7e901545e7b1aa69692426 +0, 13, 13, 1, 115200, 7347679ab09bc936047368b8caebcaff +0, 14, 14, 1, 115200, 63a23fdd57ac8462b9ffbcb12ab717b3 +0, 15, 15, 1, 115200, 705257a1c99693db233e2a3ee027adcf +0, 16, 16, 1, 115200, df861a2ec7a4ef70e82b1c28025e5a48 +0, 17, 17, 1, 115200, 2a8b403c077b6b43aa71eaf7d1537713 +0, 18, 18, 1, 115200, 973b5cd3ce473e3970dfa96045553172 +0, 19, 19, 1, 115200, fc612c0afeae3b6576b5ee2f3f119832 +0, 20, 20, 1, 115200, 97074fe5a0b6e7e8470729654092e56c +0, 21, 21, 1, 115200, 8cf9337201065335b3aa4da21dc9b37a +0, 22, 22, 1, 115200, 93ff3589294cc0673af3daee1e7fe42a +0, 23, 23, 1, 115200, c0b6fd870a022f374f9d6c697e8e293d diff --git a/tests/ref/fate/mov-frag-overlap b/tests/ref/fate/mov-frag-overlap new file mode 100644 index 0000000000000..265a93d7e6df5 --- /dev/null +++ b/tests/ref/fate/mov-frag-overlap @@ -0,0 +1,105 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1001/24000 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 640x360 +#sar 0: 1/1 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 345600, bb5e1ec37e1cb5a4ef2399c7b1c0ed08 +0, 1, 1, 1, 345600, 40455fa94b1f3b1cd199f127401fe187 +0, 2, 2, 1, 345600, 9147b59915250de3508f062b45dda499 +0, 3, 3, 1, 345600, bb9b9109ea61622f491c1e2aa21c503e +0, 4, 4, 1, 345600, eaceff4d694212b2eb6abf5e090d7b4c +0, 5, 5, 1, 345600, eaceff4d694212b2eb6abf5e090d7b4c +0, 6, 6, 1, 345600, f04ca4f64e7e990874c7ac9264ebbe65 +0, 7, 7, 1, 345600, f195d115e0ad6d5c240b08226d312cef +0, 8, 8, 1, 345600, 7585f3f325cc82028701fcd2360610e0 +0, 9, 9, 1, 345600, 7585f3f325cc82028701fcd2360610e0 +0, 10, 10, 1, 345600, 4e4a2d2d47881b238c4f423917c29182 +0, 11, 11, 1, 345600, 72609b459bde5644fe5815bb88fa537e +0, 12, 12, 1, 345600, 67569df185a64ec08498d71e94ab0197 +0, 13, 13, 1, 345600, 352e1d41fd8d5fb0a92b722782591066 +0, 14, 14, 1, 345600, f50f96f0ff0ee58ef8577cb9ce218be4 +0, 15, 15, 1, 345600, 9681c998992d20055388ae6c0d4f40e6 +0, 16, 16, 1, 345600, 4cd9c3056c0d1b2d6ed666d2fbabef45 +0, 17, 17, 1, 345600, 88d0c13cff5acb1746e7bb227e7ec81a +0, 18, 18, 1, 345600, 37a15a2d1d055a9c157a82d77cf48328 +0, 19, 19, 1, 345600, f30e43818a41242ca75caec4be7f366d +0, 20, 20, 1, 345600, e0441ca5e4137910ed94ea2d67f506ad +0, 21, 21, 1, 345600, 61cae30cdb5512610ba1ffb7b372be51 +0, 22, 22, 1, 345600, 28832e6ec917fece50ab94f8d6883d4b +0, 23, 23, 1, 345600, 07cfd60c53a4ede0de4f5eba749abae0 +0, 24, 24, 1, 345600, 254b072e2fe7017933738b8d43cd3f2e +0, 25, 25, 1, 345600, aa2ceef866576011653fc9e4add8c852 +0, 26, 26, 1, 345600, d5507e992763f69ef7da06bca2e5e0e4 +0, 27, 27, 1, 345600, 3d7fd83fab12dc9ca1bb5c0d09104174 +0, 28, 28, 1, 345600, 1fdc34d30f94bfa2acd5ab4791b3b6be +0, 29, 29, 1, 345600, a993a348279f71db20e48a879c718096 +0, 30, 30, 1, 345600, b999b6a51b3bdeb99df80aa88f2c43ff +0, 31, 31, 1, 345600, 2c851f444aaf1dd6f149ee8e6e1bdfa4 +0, 32, 32, 1, 345600, a50301d48d283e9881d142cd87128d86 +0, 33, 33, 1, 345600, 0ddffa560c6310a2ad1cb534336472ac +0, 34, 34, 1, 345600, 5f5565daeb737f3543a5d07ff9115d4a +0, 35, 35, 1, 345600, 91640f9887d074221e4e08f9a97a938b +0, 36, 36, 1, 345600, bc01f13d5c73a92895ca2ad13209628a +0, 37, 37, 1, 345600, 9750f282817c6df143565e2f57f9f85f +0, 38, 38, 1, 345600, a1803a3ce342d25b45f913cc8b9fe961 +0, 39, 39, 1, 345600, 4a0ae00d4e9df52c7df5bfb08236ae96 +0, 40, 40, 1, 345600, 819b12f2f7356b296bffd39e85c9b6be +0, 41, 41, 1, 345600, 40a5af89bff4b10a10d0a51ab5eeb4e0 +0, 42, 42, 1, 345600, 454a9b71be88d3c026cb7239988f3e37 +0, 43, 43, 1, 345600, c653e9c9d64c9495b764b0a6eb3bfbc9 +0, 44, 44, 1, 345600, 6a4facbf8e14ff6177fd4b0f6f659180 +0, 45, 45, 1, 345600, 843d5b77042e347c3d21d113ba2993fb +0, 46, 46, 1, 345600, 284785e924efba8ab17e6e1f75329287 +0, 47, 47, 1, 345600, 4f2b2d0f3dc4ad165e0bc56560930d49 +0, 48, 48, 1, 345600, 71154e17c2f5c316272e8904ef61c0bc +0, 49, 49, 1, 345600, 6b10588be4540b5dbbd765db406b8723 +0, 50, 50, 1, 345600, aaf62a95b621c8de2dca22f78594b8c7 +0, 51, 51, 1, 345600, bb508b634416287baf4406f70ca3693d +0, 52, 52, 1, 345600, 0551149846fca1ae1d164a7a7c64439f +0, 53, 53, 1, 345600, c3fad13ac1643744c4ea194763ae6cf7 +0, 54, 54, 1, 345600, 4c487adf3ec204c041a50cbf82abd8e8 +0, 55, 55, 1, 345600, dc48539225f4dc05588995d4288c71d0 +0, 56, 56, 1, 345600, be005c4f81422a775fc909dcee84094d +0, 57, 57, 1, 345600, a374c2ed0e644f03cbb8cd5456877cbb +0, 58, 58, 1, 345600, 9b7d5fac577cf0d82e11551cd9b280db +0, 59, 59, 1, 345600, c1d0551bc5cd1f53133e30ed811d8032 +0, 60, 60, 1, 345600, 6ab563cf2df92a2e9e1b8b90c0e0ec07 +0, 61, 61, 1, 345600, 19dadbe3c3638578fe8a3ed3f730858e +0, 62, 62, 1, 345600, e9810a12f7c14c4b8305a418e4bc3055 +0, 63, 63, 1, 345600, d45d74535cd471949238716bdc12c16f +0, 64, 64, 1, 345600, d1c2c19d0aba4170fe1a03f9c10b6863 +0, 65, 65, 1, 345600, 047c7fbfcce41fcaec6f1e1686db0429 +0, 66, 66, 1, 345600, 4adc1aa1017880f6baf4786ecd2c8ddb +0, 67, 67, 1, 345600, 90bad80d9e6c75784423f74984e40dd2 +0, 68, 68, 1, 345600, feb378d740e1e5f9312bf68c047040c3 +0, 69, 69, 1, 345600, 28b1de125fd6f6a9d42eb42300be7a3f +0, 70, 70, 1, 345600, 495043e65515c790c1fe026c9d2c0a49 +0, 71, 71, 1, 345600, fa6d5062932e7fc11fbfe31349ecbbfd +0, 72, 72, 1, 345600, 897952d332218f2dab7d760b2d2076eb +0, 73, 73, 1, 345600, 79dfce7ac29b96ef23c7f648e87a3e0b +0, 74, 74, 1, 345600, 94d11a85dc32b4693048a39a6227919b +0, 75, 75, 1, 345600, f9c149dbdc71c60f146cf68a673102d5 +0, 76, 76, 1, 345600, febddbb90b3f37cb29b07102575d844f +0, 77, 77, 1, 345600, b9e5cdfa63c2637f2204dcb885608bb9 +0, 78, 78, 1, 345600, 051773f40a3749b54c5a802f8a97128f +0, 79, 79, 1, 345600, 5fed52a298b8eef94ebe21c03313a5d7 +0, 80, 80, 1, 345600, f8a447cd738ec587fbacde061db51be5 +0, 81, 81, 1, 345600, 474cfd0529c0a5daffdcaed5183ee583 +0, 82, 82, 1, 345600, b0dd2ddd7037e70e774a7b3baad0b094 +0, 83, 83, 1, 345600, 86622696017283d3ce98e71d10f89f75 +0, 84, 84, 1, 345600, 20d6ae8b4dcf75ab31cc1f00002298ca +0, 85, 85, 1, 345600, a882528cd387fb3a55d6e184a33fe2c9 +0, 86, 86, 1, 345600, 6bfcb539ce16f3db0d7f24dab6166913 +0, 87, 87, 1, 345600, 6bfcb539ce16f3db0d7f24dab6166913 +0, 88, 88, 1, 345600, 3bde52ee85883e4f353d4736a47b3874 +0, 89, 89, 1, 345600, 6f20835eb29f824d6a3e1be0ce772f08 +0, 90, 90, 1, 345600, 7b99b15c1b8fbe0e643b75fda7b17b04 +0, 91, 91, 1, 345600, f0139cd28a0030d611d60e9d28837af0 +0, 92, 92, 1, 345600, f0139cd28a0030d611d60e9d28837af0 +0, 93, 93, 1, 345600, adf0a37ad23c38b54c7394871c876468 +0, 94, 94, 1, 345600, f0bd37bcb8299e90efd05a0e01c84029 +0, 95, 95, 1, 345600, 8a9d76bc611731eabc29bbf231e21528 diff --git a/tests/ref/fate/mov-guess-delay-1 b/tests/ref/fate/mov-guess-delay-1 new file mode 100644 index 0000000000000..96cb67be0c9f0 --- /dev/null +++ b/tests/ref/fate/mov-guess-delay-1 @@ -0,0 +1,3 @@ +[STREAM] +has_b_frames=1 +[/STREAM] diff --git a/tests/ref/fate/mov-guess-delay-2 b/tests/ref/fate/mov-guess-delay-2 new file mode 100644 index 0000000000000..248de1c3ea718 --- /dev/null +++ b/tests/ref/fate/mov-guess-delay-2 @@ -0,0 +1,3 @@ +[STREAM] +has_b_frames=2 +[/STREAM] diff --git a/tests/ref/fate/mov-guess-delay-3 b/tests/ref/fate/mov-guess-delay-3 new file mode 100644 index 0000000000000..248de1c3ea718 --- /dev/null +++ b/tests/ref/fate/mov-guess-delay-3 @@ -0,0 +1,3 @@ +[STREAM] +has_b_frames=2 +[/STREAM] diff --git a/tests/ref/fate/mov-ibi-elst-starts-b b/tests/ref/fate/mov-ibi-elst-starts-b new file mode 100644 index 0000000000000..1ab9c2a51db1a --- /dev/null +++ b/tests/ref/fate/mov-ibi-elst-starts-b @@ -0,0 +1,33 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x240 +#sar 0: 1/1 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 115200, 7e20f8729b6b53dc11791927bf4a5aec +0, 1, 1, 1, 115200, 4e5dc2b806e394cd666c968f736fecd0 +0, 2, 2, 1, 115200, 7a3c7473d44c5f60c07655f6fc0c2ac3 +0, 3, 3, 1, 115200, 038254422a603a3270c09cdcd149707b +0, 4, 4, 1, 115200, 7553b6b4547cb23ef8f0392ed5a5d4b0 +0, 5, 5, 1, 115200, 6d017ede7f446124af7308667cb0dc41 +0, 6, 6, 1, 115200, 77752f0288ae64f857732b8e62e47457 +0, 7, 7, 1, 115200, d656833951af99330625f7c6de7685c4 +0, 8, 8, 1, 115200, 14338b833e431e566ac98da841600bfe +0, 9, 9, 1, 115200, 07ea95d1659f3c4424a470a546d0df6e +0, 10, 10, 1, 115200, fd05b8cc83072f813e89d394d1f6efc6 +0, 11, 11, 1, 115200, 750b82ca5c7e901545e7b1aa69692426 +0, 12, 12, 1, 115200, 7347679ab09bc936047368b8caebcaff +0, 13, 13, 1, 115200, 63a23fdd57ac8462b9ffbcb12ab717b3 +0, 14, 14, 1, 115200, 705257a1c99693db233e2a3ee027adcf +0, 15, 15, 1, 115200, df861a2ec7a4ef70e82b1c28025e5a48 +0, 16, 16, 1, 115200, 2a8b403c077b6b43aa71eaf7d1537713 +0, 17, 17, 1, 115200, 973b5cd3ce473e3970dfa96045553172 +0, 18, 18, 1, 115200, fc612c0afeae3b6576b5ee2f3f119832 +0, 19, 19, 1, 115200, 97074fe5a0b6e7e8470729654092e56c +0, 20, 20, 1, 115200, 8cf9337201065335b3aa4da21dc9b37a +0, 21, 21, 1, 115200, 93ff3589294cc0673af3daee1e7fe42a +0, 22, 22, 1, 115200, c0b6fd870a022f374f9d6c697e8e293d +0, 23, 23, 1, 115200, bc4638ff7036b323c39a948a6407695d diff --git a/tests/ref/fate/mov-invalid-elst-entry-count b/tests/ref/fate/mov-invalid-elst-entry-count new file mode 100644 index 0000000000000..ac1e02ea0406e --- /dev/null +++ b/tests/ref/fate/mov-invalid-elst-entry-count @@ -0,0 +1,57 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1/24 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 640x480 +#sar 0: 1/1 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 460800, 549730883a0b56e6accaf021903daecf +0, 1, 1, 1, 460800, d5fc844d512a1decb0814b8692914d60 +0, 2, 2, 1, 460800, 69753185911f99aa38bd9d9ee0ff24f7 +0, 3, 3, 1, 460800, 2a985178c8b24e97708c6d33142f18a9 +0, 4, 4, 1, 460800, a23818e43bdf4ee77291e0f74051d0bf +0, 5, 5, 1, 460800, f2c927b11350b9822065bec5f06b65d9 +0, 6, 6, 1, 460800, 0c553fb530cf042eb84f5b13817a96a6 +0, 7, 7, 1, 460800, a2be429b570ce30a7471b901f2ea5bcc +0, 8, 8, 1, 460800, b4f4a3b1988404b35c57688755beb8b9 +0, 9, 9, 1, 460800, 2778b931d5e1570e1b809a87b1c45491 +0, 10, 10, 1, 460800, 4eb341ebf32006d8bce13f1d132d84b2 +0, 11, 11, 1, 460800, c39a34287300ee52547752198a2222fc +0, 12, 12, 1, 460800, f3ec59e6fc4e3c2e75f42bef34ca73b5 +0, 13, 13, 1, 460800, 3f0e6116a94fefe890b79d1e94c156c6 +0, 14, 14, 1, 460800, 0a8a597c0806818112bf8351f53d350a +0, 15, 15, 1, 460800, ab5c10023712ea21d595f5f856f53c66 +0, 16, 16, 1, 460800, d4e218051ef32e68e3df58c8c3d6a1ab +0, 17, 17, 1, 460800, 24082fa9a277123a65398a36cb1b06af +0, 18, 18, 1, 460800, 4c6da38c984496fb514d5e4d8ebb13f8 +0, 19, 19, 1, 460800, 5354435f662e80a47e1460d3ba020133 +0, 20, 20, 1, 460800, 6854beaaf90ad9f055af80fc75e802ae +0, 21, 21, 1, 460800, cb40c57f9b61788fb4abe674b585142f +0, 22, 22, 1, 460800, 8f42c6553c33dc049f6fb5e71f631125 +0, 23, 23, 1, 460800, d393b3efa7921caab3504044551bf6c3 +0, 24, 24, 1, 460800, 60a099be31244b2f69ca6107cdbd7e06 +0, 25, 25, 1, 460800, 05e542c105dc3f6f810d815fbf022afe +0, 26, 26, 1, 460800, bf478f55694eda43942a343e0b70eb19 +0, 27, 27, 1, 460800, b1012ea5ff7232da20d2c7f242540bda +0, 28, 28, 1, 460800, 936cdd0fd147f9c3ad4e82bed77a6d2c +0, 29, 29, 1, 460800, 20baafde1ab281444d8cbf58995344c2 +0, 30, 30, 1, 460800, b0bb3647ec88d1a862e2e92c32d95b65 +0, 31, 31, 1, 460800, c86d78b06c281a8c3b63b4d7beeb3ddd +0, 32, 32, 1, 460800, 4d699157c55ec3439390c6ff400655b4 +0, 33, 33, 1, 460800, 3327b0e09944dc13f0f2124cdfad86e9 +0, 34, 34, 1, 460800, 5db56bb14cd478f70bb5244781f1382d +0, 35, 35, 1, 460800, cb8564d7a763444cc85512df3f7f10db +0, 36, 36, 1, 460800, 1256eac030985c04c4501ad5a72e9d66 +0, 37, 37, 1, 460800, 20efdff9919faac5528cb576a21d6c2a +0, 38, 38, 1, 460800, 28420714ad1008772ce8100d917e2226 +0, 39, 39, 1, 460800, 6c18dad0a470e8c0d62413b549e0ae2c +0, 40, 40, 1, 460800, 3d8b9352e5d21697733e5fb5fdd55d58 +0, 41, 41, 1, 460800, 025e32ced915530eb814d399a8b28a20 +0, 42, 42, 1, 460800, cc880a64b66f158595521182a1db8a36 +0, 43, 43, 1, 460800, 322a2349a08e3b3cd18562050287c133 +0, 44, 44, 1, 460800, c19c16a382449594f1dec7a77a4e264e +0, 45, 45, 1, 460800, 0d424b26031fa1db52fbd80c100e27a4 +0, 46, 46, 1, 460800, cef6158cd43beee0aea777982613e493 +0, 47, 47, 1, 460800, eb64a091a54ebb1077c667e1b33add2a diff --git a/tests/ref/fate/mov-neg-firstpts-discard b/tests/ref/fate/mov-neg-firstpts-discard new file mode 100644 index 0000000000000..7c982d3ffebb0 --- /dev/null +++ b/tests/ref/fate/mov-neg-firstpts-discard @@ -0,0 +1,3 @@ +[STREAM] +start_time=N/A +[/STREAM] diff --git a/tests/ref/fate/mov-neg-firstpts-discard-frames b/tests/ref/fate/mov-neg-firstpts-discard-frames new file mode 100644 index 0000000000000..81b59b384b8a0 --- /dev/null +++ b/tests/ref/fate/mov-neg-firstpts-discard-frames @@ -0,0 +1,24 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#tb 0: 1/30 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 320x240 +#sar 0: 1/1 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 115200, 1e55263b359b4c99c3463655a1120f11 +0, 1, 1, 1, 115200, ce33efea81064e7c23deb57dc4c21995 +0, 2, 2, 1, 115200, 42234f25d6191ab13c3676a7937c921b +0, 3, 3, 1, 115200, eab2ccb227c66cba4c9feb8cdbf28ef8 +0, 4, 4, 1, 115200, c8816e0b151b2c892163e35086918520 +0, 5, 5, 1, 115200, c633f5604c8651165d551ee88fb4cd92 +0, 6, 6, 1, 115200, 5f3f8530d720fef3ac4c937e7f488ea7 +0, 7, 7, 1, 115200, be24a583909ca92008b642f39be02685 +0, 8, 8, 1, 115200, 83872a6e5c3369fe76f684de31bd9a36 +0, 9, 9, 1, 115200, 4629d6eb656883b337e8e0b381f2db8d +0, 10, 10, 1, 115200, f6bec55bc026440d23a44b948900e785 +0, 11, 11, 1, 115200, 7e12e8113916305c79e5d08354acc9ae +0, 12, 12, 1, 115200, d315c0093536642d340ea50de3b2bfbb +0, 13, 13, 1, 115200, 3d12b24aaed72bfada4a1a3e5e02945a +0, 14, 14, 1, 115200, 070d6b8935c11304d8f9520c4401a130 diff --git a/tests/ref/fate/mov-zombie b/tests/ref/fate/mov-zombie index e89abb1167682..fef2adc35436f 100644 --- a/tests/ref/fate/mov-zombie +++ b/tests/ref/fate/mov-zombie @@ -1,6 +1,6 @@ packet|codec_type=video|stream_index=0|pts=0|pts_time=0.000000|dts=-3004|dts_time=-0.033378|duration=3003|duration_time=0.033367|convergence_duration=N/A|convergence_duration_time=N/A|size=4133|pos=11309|flags=K_ -frame|media_type=video|stream_index=0|key_frame=1|pkt_pts=0|pkt_pts_time=0.000000|pkt_dts=-3004|pkt_dts_time=-0.033378|best_effort_timestamp=0|best_effort_timestamp_time=0.000000|pkt_duration=3003|pkt_duration_time=0.033367|pkt_pos=11309|pkt_size=4133|width=160|height=240|pix_fmt=yuv420p|sample_aspect_ratio=2:1|pict_type=I|coded_picture_number=0|display_picture_number=0|interlaced_frame=0|top_field_first=0|repeat_pict=0|color_range=tv|color_space=smpte170m|color_primaries=smpte170m|color_transfer=bt709|chroma_location=topleft packet|codec_type=video|stream_index=0|pts=5440|pts_time=0.060444|dts=-567|dts_time=-0.006300|duration=3003|duration_time=0.033367|convergence_duration=N/A|convergence_duration_time=N/A|size=1077|pos=15442|flags=__ +frame|media_type=video|stream_index=0|key_frame=1|pkt_pts=0|pkt_pts_time=0.000000|pkt_dts=-567|pkt_dts_time=-0.006300|best_effort_timestamp=0|best_effort_timestamp_time=0.000000|pkt_duration=3003|pkt_duration_time=0.033367|pkt_pos=11309|pkt_size=4133|width=160|height=240|pix_fmt=yuv420p|sample_aspect_ratio=2:1|pict_type=I|coded_picture_number=0|display_picture_number=0|interlaced_frame=0|top_field_first=0|repeat_pict=0|color_range=tv|color_space=smpte170m|color_primaries=smpte170m|color_transfer=bt709|chroma_location=topleft packet|codec_type=video|stream_index=0|pts=2437|pts_time=0.027078|dts=2436|dts_time=0.027067|duration=3003|duration_time=0.033367|convergence_duration=N/A|convergence_duration_time=N/A|size=355|pos=16519|flags=__ frame|media_type=video|stream_index=0|key_frame=0|pkt_pts=2437|pkt_pts_time=0.027078|pkt_dts=2436|pkt_dts_time=0.027067|best_effort_timestamp=2437|best_effort_timestamp_time=0.027078|pkt_duration=3003|pkt_duration_time=0.033367|pkt_pos=16519|pkt_size=355|width=160|height=240|pix_fmt=yuv420p|sample_aspect_ratio=2:1|pict_type=B|coded_picture_number=2|display_picture_number=0|interlaced_frame=0|top_field_first=0|repeat_pict=0|color_range=tv|color_space=smpte170m|color_primaries=smpte170m|color_transfer=bt709|chroma_location=topleft packet|codec_type=video|stream_index=0|pts=11446|pts_time=0.127178|dts=5439|dts_time=0.060433|duration=3003|duration_time=0.033367|convergence_duration=N/A|convergence_duration_time=N/A|size=1110|pos=16874|flags=__ @@ -129,5 +129,5 @@ packet|codec_type=video|stream_index=0|pts=188623|pts_time=2.095811|dts=188622|d frame|media_type=video|stream_index=0|key_frame=0|pkt_pts=188623|pkt_pts_time=2.095811|pkt_dts=188622|pkt_dts_time=2.095800|best_effort_timestamp=188623|best_effort_timestamp_time=2.095811|pkt_duration=3003|pkt_duration_time=0.033367|pkt_pos=100846|pkt_size=974|width=160|height=240|pix_fmt=yuv420p|sample_aspect_ratio=2:1|pict_type=B|coded_picture_number=64|display_picture_number=0|interlaced_frame=0|top_field_first=0|repeat_pict=0|color_range=tv|color_space=smpte170m|color_primaries=smpte170m|color_transfer=bt709|chroma_location=topleft packet|codec_type=video|stream_index=0|pts=197632|pts_time=2.195911|dts=191625|dts_time=2.129167|duration=3003|duration_time=0.033367|convergence_duration=N/A|convergence_duration_time=N/A|size=580|pos=101820|flags=__ frame|media_type=video|stream_index=0|key_frame=0|pkt_pts=191626|pkt_pts_time=2.129178|pkt_dts=N/A|pkt_dts_time=N/A|best_effort_timestamp=191626|best_effort_timestamp_time=2.129178|pkt_duration=3003|pkt_duration_time=0.033367|pkt_pos=99180|pkt_size=1666|width=160|height=240|pix_fmt=yuv420p|sample_aspect_ratio=2:1|pict_type=P|coded_picture_number=63|display_picture_number=0|interlaced_frame=0|top_field_first=0|repeat_pict=0|color_range=tv|color_space=smpte170m|color_primaries=smpte170m|color_transfer=bt709|chroma_location=topleft -stream|index=0|codec_name=h264|profile=77|codec_type=video|codec_time_base=212521/12744000|codec_tag_string=avc1|codec_tag=0x31637661|width=160|height=240|coded_width=160|coded_height=240|has_b_frames=0|sample_aspect_ratio=2:1|display_aspect_ratio=4:3|pix_fmt=yuv420p|level=12|color_range=tv|color_space=smpte170m|color_transfer=bt709|color_primaries=smpte170m|chroma_location=topleft|field_order=unknown|timecode=N/A|refs=2|is_avc=true|nal_length_size=4|id=N/A|r_frame_rate=30000/1001|avg_frame_rate=6372000/212521|time_base=1/90000|start_pts=0|start_time=0.000000|duration_ts=2125200|duration=23.613333|bit_rate=333874|max_bit_rate=N/A|bits_per_raw_sample=8|nb_frames=708|nb_read_frames=65|nb_read_packets=66|disposition:default=1|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|tag:rotate=0|tag:creation_time=2008-05-12T20:59:27.000000Z|tag:language=eng|tag:handler_name=Apple Alias Data Handler|tag:encoder=H.264 +stream|index=0|codec_name=h264|profile=77|codec_type=video|codec_time_base=212521/12744000|codec_tag_string=avc1|codec_tag=0x31637661|width=160|height=240|coded_width=160|coded_height=240|has_b_frames=1|sample_aspect_ratio=2:1|display_aspect_ratio=4:3|pix_fmt=yuv420p|level=12|color_range=tv|color_space=smpte170m|color_transfer=bt709|color_primaries=smpte170m|chroma_location=topleft|field_order=unknown|timecode=N/A|refs=2|is_avc=true|nal_length_size=4|id=N/A|r_frame_rate=30000/1001|avg_frame_rate=6372000/212521|time_base=1/90000|start_pts=0|start_time=0.000000|duration_ts=2125200|duration=23.613333|bit_rate=333874|max_bit_rate=N/A|bits_per_raw_sample=8|nb_frames=708|nb_read_frames=65|nb_read_packets=66|disposition:default=1|disposition:dub=0|disposition:original=0|disposition:comment=0|disposition:lyrics=0|disposition:karaoke=0|disposition:forced=0|disposition:hearing_impaired=0|disposition:visual_impaired=0|disposition:clean_effects=0|disposition:attached_pic=0|disposition:timed_thumbnails=0|tag:rotate=0|tag:creation_time=2008-05-12T20:59:27.000000Z|tag:language=eng|tag:handler_name=Apple Alias Data Handler|tag:encoder=H.264 side_data|side_data_type=Display Matrix|displaymatrix=\n00000000: 131072 0 0\n00000001: 0 65536 0\n00000002: 0 0 1073741824\n|rotation=0 diff --git a/tests/ref/fate/mpeg2-field-enc b/tests/ref/fate/mpeg2-field-enc index 4c288a83efc01..8062b824832e7 100644 --- a/tests/ref/fate/mpeg2-field-enc +++ b/tests/ref/fate/mpeg2-field-enc @@ -3,33 +3,33 @@ #codec_id 0: rawvideo #dimensions 0: 720x576 #sar 0: 16/15 -0, 9, 9, 1, 622080, 0xb3b66c5c -0, 10, 10, 1, 622080, 0x088ec02b -0, 11, 11, 1, 622080, 0x7a36db21 -0, 12, 12, 1, 622080, 0x541b286f -0, 13, 13, 1, 622080, 0xb6c3e590 -0, 14, 14, 1, 622080, 0x39dbed51 -0, 15, 15, 1, 622080, 0x973dc728 -0, 16, 16, 1, 622080, 0xd7a4f804 -0, 17, 17, 1, 622080, 0xa2484762 -0, 18, 18, 1, 622080, 0x0cd268d1 -0, 19, 19, 1, 622080, 0x72eb663d -0, 20, 20, 1, 622080, 0x8fdbac59 -0, 21, 21, 1, 622080, 0xa6f4feb9 -0, 22, 22, 1, 622080, 0xadb828c6 -0, 23, 23, 1, 622080, 0xea630a63 -0, 24, 24, 1, 622080, 0xa901d925 -0, 25, 25, 1, 622080, 0xac5e7087 -0, 26, 26, 1, 622080, 0x10274a2b -0, 27, 27, 1, 622080, 0x143d541c -0, 28, 28, 1, 622080, 0xee94c93a -0, 29, 29, 1, 622080, 0xca030208 -0, 30, 30, 1, 622080, 0x26f30ead -0, 31, 31, 1, 622080, 0xfc22f32c -0, 32, 32, 1, 622080, 0x940a5ff8 -0, 33, 33, 1, 622080, 0x2164f805 -0, 34, 34, 1, 622080, 0xa76f5aba -0, 35, 35, 1, 622080, 0x8c311471 -0, 36, 36, 1, 622080, 0xa45e1d95 -0, 37, 37, 1, 622080, 0x6cc61d6c -0, 38, 38, 1, 622080, 0x6983b417 +0, 9, 9, 1, 622080, 0xff496bf5 +0, 10, 10, 1, 622080, 0x9bf6c014 +0, 11, 11, 1, 622080, 0x870edac7 +0, 12, 12, 1, 622080, 0x9dec280c +0, 13, 13, 1, 622080, 0x0f02e57a +0, 14, 14, 1, 622080, 0x161beccb +0, 15, 15, 1, 622080, 0x2234c6b0 +0, 16, 16, 1, 622080, 0x143ef78a +0, 17, 17, 1, 622080, 0x0d6e46cf +0, 18, 18, 1, 622080, 0xb41667fd +0, 19, 19, 1, 622080, 0xcc476539 +0, 20, 20, 1, 622080, 0x85d8ab16 +0, 21, 21, 1, 622080, 0xcd6afec1 +0, 22, 22, 1, 622080, 0x187a28ac +0, 23, 23, 1, 622080, 0x06100a4b +0, 24, 24, 1, 622080, 0x1b4ed8e9 +0, 25, 25, 1, 622080, 0xde33702c +0, 26, 26, 1, 622080, 0x11974a0c +0, 27, 27, 1, 622080, 0x1a0553e8 +0, 28, 28, 1, 622080, 0x98e1c8da +0, 29, 29, 1, 622080, 0x003801ce +0, 30, 30, 1, 622080, 0x6f300e00 +0, 31, 31, 1, 622080, 0xb232f27d +0, 32, 32, 1, 622080, 0x07c65f57 +0, 33, 33, 1, 622080, 0x6363f7ce +0, 34, 34, 1, 622080, 0x69ba5ac3 +0, 35, 35, 1, 622080, 0x8561143e +0, 36, 36, 1, 622080, 0xf45e1d76 +0, 37, 37, 1, 622080, 0x69f81d2f +0, 38, 38, 1, 622080, 0x8653b3ed diff --git a/tests/ref/fate/mpeg2-ticket186 b/tests/ref/fate/mpeg2-ticket186 index b716ca56110c1..31afda15e8c47 100644 --- a/tests/ref/fate/mpeg2-ticket186 +++ b/tests/ref/fate/mpeg2-ticket186 @@ -3,354 +3,354 @@ #codec_id 0: rawvideo #dimensions 0: 352x288 #sar 0: 12/11 -0, 0, 0, 1, 152064, 0xd23ffc59 +0, 0, 0, 1, 152064, 0x8f9d00c1 0, 1, 1, 1, 152064, 0x899fb8b1 -0, 2, 2, 1, 152064, 0x5958d070 +0, 2, 2, 1, 152064, 0x7225cb39 0, 3, 3, 1, 152064, 0xf2becd8f -0, 4, 4, 1, 152064, 0xb47bbed7 +0, 4, 4, 1, 152064, 0xd56bc556 0, 5, 5, 1, 152064, 0x7ca54f36 -0, 6, 6, 1, 152064, 0x02389610 +0, 6, 6, 1, 152064, 0x06d7805c 0, 7, 7, 1, 152064, 0x469f3f87 -0, 8, 8, 1, 152064, 0x935a780e +0, 8, 8, 1, 152064, 0xdb2f57d5 0, 9, 9, 1, 152064, 0x3876c20c -0, 10, 10, 1, 152064, 0x49df265f +0, 10, 10, 1, 152064, 0x5b670e79 0, 11, 11, 1, 152064, 0xdfe420e0 -0, 12, 12, 1, 152064, 0x6e34a0c4 +0, 12, 12, 1, 152064, 0x17578222 0, 13, 13, 1, 152064, 0x47e1cb26 -0, 14, 14, 1, 152064, 0x68e74188 +0, 14, 14, 1, 152064, 0x168e35d6 0, 15, 15, 1, 152064, 0xe9d34b4e -0, 16, 16, 1, 152064, 0xa8665e1a +0, 16, 16, 1, 152064, 0x5e395308 0, 17, 17, 1, 152064, 0x88e3b39f -0, 18, 18, 1, 152064, 0x1c1ab2c3 +0, 18, 18, 1, 152064, 0x6b099c51 0, 19, 19, 1, 152064, 0xb1a24ddf -0, 20, 20, 1, 152064, 0x030d5afc +0, 20, 20, 1, 152064, 0xcea840fc 0, 21, 21, 1, 152064, 0x98306d64 -0, 22, 22, 1, 152064, 0x5ce0548d +0, 22, 22, 1, 152064, 0xb05354d3 0, 23, 23, 1, 152064, 0xacac26f3 -0, 24, 24, 1, 152064, 0xf167f698 +0, 24, 24, 1, 152064, 0xbccdf14b 0, 25, 25, 1, 152064, 0xd9398539 -0, 26, 26, 1, 152064, 0xd7aec2c4 +0, 26, 26, 1, 152064, 0x07aec13a 0, 27, 27, 1, 152064, 0xa6ef9440 -0, 28, 28, 1, 152064, 0xc289b278 +0, 28, 28, 1, 152064, 0x0e7ab64e 0, 29, 29, 1, 152064, 0x3796939d -0, 30, 30, 1, 152064, 0x48c09366 +0, 30, 30, 1, 152064, 0xcc219365 0, 31, 31, 1, 152064, 0xf4cc815a -0, 32, 32, 1, 152064, 0x1c63cdc2 +0, 32, 32, 1, 152064, 0x8b91c622 0, 33, 33, 1, 152064, 0xd3a8ad8e -0, 34, 34, 1, 152064, 0x70f94bc0 +0, 34, 34, 1, 152064, 0x658e498f 0, 35, 35, 1, 152064, 0xf9c115ea -0, 36, 36, 1, 152064, 0x44a2f607 +0, 36, 36, 1, 152064, 0xb639f8d2 0, 37, 37, 1, 152064, 0x7e9eaa64 -0, 38, 38, 1, 152064, 0x37b86b68 +0, 38, 38, 1, 152064, 0x8a546bcf 0, 39, 39, 1, 152064, 0x59d22dd4 -0, 40, 40, 1, 152064, 0x5d0d0e8d +0, 40, 40, 1, 152064, 0x80a10edc 0, 41, 41, 1, 152064, 0x5c97d4a1 -0, 42, 42, 1, 152064, 0xd44ef54d +0, 42, 42, 1, 152064, 0x4f1bf025 0, 43, 43, 1, 152064, 0x42721789 -0, 44, 44, 1, 152064, 0x27597277 +0, 44, 44, 1, 152064, 0x39e6700d 0, 45, 45, 1, 152064, 0xdf4af8b4 -0, 46, 46, 1, 152064, 0x5df7390c +0, 46, 46, 1, 152064, 0xacf839bb 0, 47, 47, 1, 152064, 0xbebfbf7c -0, 48, 48, 1, 152064, 0x753959bb +0, 48, 48, 1, 152064, 0x09c7630d 0, 49, 49, 1, 152064, 0x3331ab18 -0, 50, 50, 1, 152064, 0xec4a0f33 +0, 50, 50, 1, 152064, 0xae0f0f28 0, 51, 51, 1, 152064, 0xbb085737 -0, 52, 52, 1, 152064, 0x3938abf4 +0, 52, 52, 1, 152064, 0x1e23ad39 0, 53, 53, 1, 152064, 0x18d46683 -0, 54, 54, 1, 152064, 0xb12ace0c +0, 54, 54, 1, 152064, 0x4eadd0a0 0, 55, 55, 1, 152064, 0x09b13430 -0, 56, 56, 1, 152064, 0x85bd5e88 +0, 56, 56, 1, 152064, 0x240a607b 0, 57, 57, 1, 152064, 0xec0f8a67 -0, 58, 58, 1, 152064, 0x51a4fc74 +0, 58, 58, 1, 152064, 0x6c37fc08 0, 59, 59, 1, 152064, 0xded4cda7 -0, 60, 60, 1, 152064, 0xb69412a9 +0, 60, 60, 1, 152064, 0xc5df1477 0, 61, 61, 1, 152064, 0x3c9de6f9 -0, 62, 62, 1, 152064, 0x223fcc41 +0, 62, 62, 1, 152064, 0xefd1cdbd 0, 63, 63, 1, 152064, 0x5df7b89c -0, 64, 64, 1, 152064, 0x1e58b37a +0, 64, 64, 1, 152064, 0x1b04af5f 0, 65, 65, 1, 152064, 0xbbff2c09 -0, 66, 66, 1, 152064, 0x4e0f4d4a +0, 66, 66, 1, 152064, 0x23b04553 0, 67, 67, 1, 152064, 0x3d99caa3 -0, 68, 68, 1, 152064, 0xcc329c2f +0, 68, 68, 1, 152064, 0x35139bf8 0, 69, 69, 1, 152064, 0x49207c0a -0, 70, 70, 1, 152064, 0x489f2d50 +0, 70, 70, 1, 152064, 0xa78e2efa 0, 71, 71, 1, 152064, 0x5a50b0df -0, 72, 72, 1, 152064, 0x509eb79e +0, 72, 72, 1, 152064, 0x3255b306 0, 73, 73, 1, 152064, 0x60622c61 0, 74, 74, 1, 152064, 0x8c8cde9f 0, 75, 75, 1, 152064, 0xe8c0bb6c -0, 76, 76, 1, 152064, 0xb03581b6 +0, 76, 76, 1, 152064, 0xbc698473 0, 77, 77, 1, 152064, 0x398525c2 0, 78, 78, 1, 152064, 0x87983ab0 0, 79, 79, 1, 152064, 0x032af6b5 -0, 80, 80, 1, 152064, 0x7434baa4 +0, 80, 80, 1, 152064, 0x4878bb11 0, 81, 81, 1, 152064, 0xff5dd044 -0, 82, 82, 1, 152064, 0x45b2bb36 +0, 82, 82, 1, 152064, 0xe675bfe0 0, 83, 83, 1, 152064, 0x1af29008 0, 84, 84, 1, 152064, 0x07aa8975 0, 85, 85, 1, 152064, 0x17957756 0, 86, 86, 1, 152064, 0x48b5825e 0, 87, 87, 1, 152064, 0x169d70bc -0, 88, 88, 1, 152064, 0x803b30c6 +0, 88, 88, 1, 152064, 0x326730c8 0, 89, 89, 1, 152064, 0x6158c971 -0, 90, 90, 1, 152064, 0xb126e53e +0, 90, 90, 1, 152064, 0x1035e3ee 0, 91, 91, 1, 152064, 0xef49ba53 -0, 92, 92, 1, 152064, 0xfcfd7f17 +0, 92, 92, 1, 152064, 0x261081fa 0, 93, 93, 1, 152064, 0x5280779e -0, 94, 94, 1, 152064, 0x638d6f48 +0, 94, 94, 1, 152064, 0x8a6d6df3 0, 95, 95, 1, 152064, 0xdb0f1ed5 -0, 96, 96, 1, 152064, 0x2cb959b0 +0, 96, 96, 1, 152064, 0x5162570a 0, 97, 97, 1, 152064, 0x0841547c -0, 98, 98, 1, 152064, 0x412a555b +0, 98, 98, 1, 152064, 0xf0694fcd 0, 99, 99, 1, 152064, 0xfe525057 -0, 100, 100, 1, 152064, 0xa8cf0cbc +0, 100, 100, 1, 152064, 0xb4ec0c96 0, 101, 101, 1, 152064, 0xbf2dcaee -0, 102, 102, 1, 152064, 0x636cc494 +0, 102, 102, 1, 152064, 0x7860c418 0, 103, 103, 1, 152064, 0xc9e288bc -0, 104, 104, 1, 152064, 0xe77f4d03 +0, 104, 104, 1, 152064, 0xb0514dc3 0, 105, 105, 1, 152064, 0x722a4bd0 -0, 106, 106, 1, 152064, 0x5271f5ef +0, 106, 106, 1, 152064, 0x5277f52d 0, 107, 107, 1, 152064, 0x05208e75 -0, 108, 108, 1, 152064, 0xb8845f88 +0, 108, 108, 1, 152064, 0x0b596089 0, 109, 109, 1, 152064, 0x47aa117c -0, 110, 110, 1, 152064, 0xe695fe27 +0, 110, 110, 1, 152064, 0x12edfe8b 0, 111, 111, 1, 152064, 0x2e50f864 -0, 112, 112, 1, 152064, 0x52d2b719 +0, 112, 112, 1, 152064, 0x4cedb882 0, 113, 113, 1, 152064, 0xdbf48285 -0, 114, 114, 1, 152064, 0xe0b2ba93 +0, 114, 114, 1, 152064, 0x9071b0e6 0, 115, 115, 1, 152064, 0x1c85a5ce 0, 116, 116, 1, 152064, 0x8ef9a8e8 0, 117, 117, 1, 152064, 0x41e8ae26 0, 118, 118, 1, 152064, 0x3328d571 0, 119, 119, 1, 152064, 0xce7d4da2 -0, 120, 120, 1, 152064, 0x7a6f7416 +0, 120, 120, 1, 152064, 0x032d7575 0, 121, 121, 1, 152064, 0xb3fc65a6 -0, 122, 122, 1, 152064, 0xc5a261e9 +0, 122, 122, 1, 152064, 0xe5a266b4 0, 123, 123, 1, 152064, 0x943c5925 -0, 124, 124, 1, 152064, 0x259180b2 +0, 124, 124, 1, 152064, 0xe6138024 0, 125, 125, 1, 152064, 0x3acd4e1b -0, 126, 126, 1, 152064, 0x692090b4 +0, 126, 126, 1, 152064, 0x9de7903e 0, 127, 127, 1, 152064, 0xea1184d0 -0, 128, 128, 1, 152064, 0x3e0038d5 +0, 128, 128, 1, 152064, 0x9e323818 0, 129, 129, 1, 152064, 0xf77872a2 -0, 130, 130, 1, 152064, 0xe4cb7bb5 +0, 130, 130, 1, 152064, 0x8f7c75c7 0, 131, 131, 1, 152064, 0x9d6d2623 -0, 132, 132, 1, 152064, 0xb9056247 +0, 132, 132, 1, 152064, 0x3d8e62ab 0, 133, 133, 1, 152064, 0xcd8b3dc5 -0, 134, 134, 1, 152064, 0x13ea1b6d +0, 134, 134, 1, 152064, 0x57681ebc 0, 135, 135, 1, 152064, 0x764f3233 -0, 136, 136, 1, 152064, 0x54c00ba8 +0, 136, 136, 1, 152064, 0x8c8b0a4b 0, 137, 137, 1, 152064, 0x2d9aedac -0, 138, 138, 1, 152064, 0x1af00532 +0, 138, 138, 1, 152064, 0x0afe03ae 0, 139, 139, 1, 152064, 0xcecae31b 0, 140, 140, 1, 152064, 0x0e6ea17f 0, 141, 141, 1, 152064, 0x66b0b8c4 -0, 142, 142, 1, 152064, 0x0ee879bb +0, 142, 142, 1, 152064, 0xd44f7976 0, 143, 143, 1, 152064, 0xf7f029cc -0, 144, 144, 1, 152064, 0xdd5d08d6 +0, 144, 144, 1, 152064, 0xada307a9 0, 145, 145, 1, 152064, 0x936ae367 -0, 146, 146, 1, 152064, 0xf0f4aba0 +0, 146, 146, 1, 152064, 0xa019ad8a 0, 147, 147, 1, 152064, 0x5233a9e7 -0, 148, 148, 1, 152064, 0x02af732b +0, 148, 148, 1, 152064, 0x6fd5737f 0, 149, 149, 1, 152064, 0xb2eb2476 -0, 150, 150, 1, 152064, 0x998732b4 +0, 150, 150, 1, 152064, 0x36a53280 0, 151, 151, 1, 152064, 0xf025230f -0, 152, 152, 1, 152064, 0x474f3b12 +0, 152, 152, 1, 152064, 0x48373a3e 0, 153, 153, 1, 152064, 0xe4e950e2 -0, 154, 154, 1, 152064, 0xa3f87fb3 +0, 154, 154, 1, 152064, 0x63d37fc4 0, 155, 155, 1, 152064, 0x1e465fda -0, 156, 156, 1, 152064, 0x9e8caab2 +0, 156, 156, 1, 152064, 0xc47ea97e 0, 157, 157, 1, 152064, 0x0224aca7 -0, 158, 158, 1, 152064, 0x24fcec49 +0, 158, 158, 1, 152064, 0x909dedcc 0, 159, 159, 1, 152064, 0x1c1df7ea -0, 160, 160, 1, 152064, 0xc466f68f +0, 160, 160, 1, 152064, 0x5e43f7f1 0, 161, 161, 1, 152064, 0xdb11d8fa -0, 162, 162, 1, 152064, 0xa0f61157 +0, 162, 162, 1, 152064, 0xa66710f5 0, 163, 163, 1, 152064, 0x352013b0 -0, 164, 164, 1, 152064, 0xc14243c7 +0, 164, 164, 1, 152064, 0xc8e745f1 0, 165, 165, 1, 152064, 0xb18b6810 -0, 166, 166, 1, 152064, 0x040942e6 +0, 166, 166, 1, 152064, 0xb1c243e2 0, 167, 167, 1, 152064, 0x6fe129f9 -0, 168, 168, 1, 152064, 0xc3d64c5f +0, 168, 168, 1, 152064, 0x92814bde 0, 169, 169, 1, 152064, 0x50954752 -0, 170, 170, 1, 152064, 0xa4d24c64 +0, 170, 170, 1, 152064, 0x48634df3 0, 171, 171, 1, 152064, 0x3af254c0 0, 172, 172, 1, 152064, 0x6fde4801 0, 173, 173, 1, 152064, 0xf8fe19b4 -0, 174, 174, 1, 152064, 0x97b34958 +0, 174, 174, 1, 152064, 0x57004906 0, 175, 175, 1, 152064, 0x916e2ff4 -0, 176, 176, 1, 152064, 0x60c528e2 +0, 176, 176, 1, 152064, 0xbc0d28f0 0, 177, 177, 1, 152064, 0x4522435e 0, 178, 178, 1, 152064, 0x861f5d1b 0, 179, 179, 1, 152064, 0x42c3bf28 -0, 180, 180, 1, 152064, 0x9772db11 +0, 180, 180, 1, 152064, 0xbd6adb19 0, 181, 181, 1, 152064, 0x0692f5b8 -0, 182, 182, 1, 152064, 0xb06b4aed +0, 182, 182, 1, 152064, 0x1e1e4bfb 0, 183, 183, 1, 152064, 0xdc852986 -0, 184, 184, 1, 152064, 0xa7a025fb +0, 184, 184, 1, 152064, 0x61c5259e 0, 185, 185, 1, 152064, 0xe28f365a -0, 186, 186, 1, 152064, 0xcbf3830e +0, 186, 186, 1, 152064, 0x19388308 0, 187, 187, 1, 152064, 0x043bace9 -0, 188, 188, 1, 152064, 0x5dd0b5df +0, 188, 188, 1, 152064, 0x4bebb678 0, 189, 189, 1, 152064, 0x6bd6d112 -0, 190, 190, 1, 152064, 0xa585ceb6 +0, 190, 190, 1, 152064, 0x3c9dc401 0, 191, 191, 1, 152064, 0x91e7556a -0, 192, 192, 1, 152064, 0x8f2a0404 +0, 192, 192, 1, 152064, 0xae60f7e7 0, 193, 193, 1, 152064, 0x14066893 -0, 194, 194, 1, 152064, 0x8f715862 +0, 194, 194, 1, 152064, 0x7f5a5f0a 0, 195, 195, 1, 152064, 0xb1063958 -0, 196, 196, 1, 152064, 0x014c40f0 +0, 196, 196, 1, 152064, 0xadf13b9f 0, 197, 197, 1, 152064, 0x7ddcf94d -0, 198, 198, 1, 152064, 0x25473a22 +0, 198, 198, 1, 152064, 0x91393730 0, 199, 199, 1, 152064, 0xcd150536 -0, 200, 200, 1, 152064, 0x2d24d974 +0, 200, 200, 1, 152064, 0x52e0d7bd 0, 201, 201, 1, 152064, 0x9130b2ce -0, 202, 202, 1, 152064, 0x9450a62a +0, 202, 202, 1, 152064, 0xa07fa62a 0, 203, 203, 1, 152064, 0x7da258cd -0, 204, 204, 1, 152064, 0x6c2770de +0, 204, 204, 1, 152064, 0x984071a6 0, 205, 205, 1, 152064, 0xd5fa731a -0, 206, 206, 1, 152064, 0x93757c14 +0, 206, 206, 1, 152064, 0x593d7910 0, 207, 207, 1, 152064, 0x4b754c71 0, 208, 208, 1, 152064, 0x51544841 0, 209, 209, 1, 152064, 0xf466910e -0, 210, 210, 1, 152064, 0xe818c675 +0, 210, 210, 1, 152064, 0x6535c9c4 0, 211, 211, 1, 152064, 0x6d45b6d8 -0, 212, 212, 1, 152064, 0xa3de9aec +0, 212, 212, 1, 152064, 0xe77998a2 0, 213, 213, 1, 152064, 0x56023275 -0, 214, 214, 1, 152064, 0xa1af21cb +0, 214, 214, 1, 152064, 0x779b20cc 0, 215, 215, 1, 152064, 0x1ff1b05e -0, 216, 216, 1, 152064, 0x142ecbdb +0, 216, 216, 1, 152064, 0xb9e2c3f0 0, 217, 217, 1, 152064, 0xdfc6d541 -0, 218, 218, 1, 152064, 0x8d8f7a4c +0, 218, 218, 1, 152064, 0x301a7948 0, 219, 219, 1, 152064, 0x03d611ca -0, 220, 220, 1, 152064, 0x999e6d3f +0, 220, 220, 1, 152064, 0xe9426f2a 0, 221, 221, 1, 152064, 0x304c95df -0, 222, 222, 1, 152064, 0xbdcff306 +0, 222, 222, 1, 152064, 0x60e7f924 0, 223, 223, 1, 152064, 0x6408670c -0, 224, 224, 1, 152064, 0xa6d4d038 +0, 224, 224, 1, 152064, 0xbf09ca74 0, 225, 225, 1, 152064, 0xf2d13572 -0, 226, 226, 1, 152064, 0x2fa8b357 +0, 226, 226, 1, 152064, 0x90ccb47d 0, 227, 227, 1, 152064, 0x24bbd269 -0, 228, 228, 1, 152064, 0x23dd31f2 +0, 228, 228, 1, 152064, 0x7ae333dd 0, 229, 229, 1, 152064, 0x90913fe2 -0, 230, 230, 1, 152064, 0x855efbca +0, 230, 230, 1, 152064, 0xc994007c 0, 231, 231, 1, 152064, 0x45a123c0 -0, 232, 232, 1, 152064, 0xec465cb2 +0, 232, 232, 1, 152064, 0xa0335bbf 0, 233, 233, 1, 152064, 0x3e79c4e9 -0, 234, 234, 1, 152064, 0xaeac4476 +0, 234, 234, 1, 152064, 0x05cf4479 0, 235, 235, 1, 152064, 0x2146392c -0, 236, 236, 1, 152064, 0x7a186239 +0, 236, 236, 1, 152064, 0x68ac5d0a 0, 237, 237, 1, 152064, 0x9d26fed8 -0, 238, 238, 1, 152064, 0x88f090ba +0, 238, 238, 1, 152064, 0x047c9082 0, 239, 239, 1, 152064, 0x518bd9f8 -0, 240, 240, 1, 152064, 0x70013bdd +0, 240, 240, 1, 152064, 0xfbd03b16 0, 241, 241, 1, 152064, 0x5317601a -0, 242, 242, 1, 152064, 0x97e91795 +0, 242, 242, 1, 152064, 0x450118c5 0, 243, 243, 1, 152064, 0x1058915b -0, 244, 244, 1, 152064, 0x3549ffeb +0, 244, 244, 1, 152064, 0x0a4a000a 0, 245, 245, 1, 152064, 0xa277707d -0, 246, 246, 1, 152064, 0xdcb6287d +0, 246, 246, 1, 152064, 0xc7cb29b2 0, 247, 247, 1, 152064, 0x371344fc -0, 248, 248, 1, 152064, 0xb7ea75c7 +0, 248, 248, 1, 152064, 0xbc9375a9 0, 249, 249, 1, 152064, 0x70c2fa2f -0, 250, 250, 1, 152064, 0x8dbec050 +0, 250, 250, 1, 152064, 0x41fbc057 0, 251, 251, 1, 152064, 0xc21a77fe -0, 252, 252, 1, 152064, 0xf7c7678e +0, 252, 252, 1, 152064, 0x51e06384 0, 253, 253, 1, 152064, 0xbee83fcb -0, 254, 254, 1, 152064, 0x6627efd7 +0, 254, 254, 1, 152064, 0xce2befdf 0, 255, 255, 1, 152064, 0x4f139865 -0, 256, 256, 1, 152064, 0x76fa5435 +0, 256, 256, 1, 152064, 0x4e0f5372 0, 257, 257, 1, 152064, 0xf0701fd6 -0, 258, 258, 1, 152064, 0x153e3763 +0, 258, 258, 1, 152064, 0x746c35f4 0, 259, 259, 1, 152064, 0xf5211469 -0, 260, 260, 1, 152064, 0xc19d24b8 +0, 260, 260, 1, 152064, 0xae8f1c2f 0, 261, 261, 1, 152064, 0xc2483a75 -0, 262, 262, 1, 152064, 0x67a149ee +0, 262, 262, 1, 152064, 0x2da24ae6 0, 263, 263, 1, 152064, 0x86f70e3a -0, 264, 264, 1, 152064, 0x281b166b +0, 264, 264, 1, 152064, 0x52b8172a 0, 265, 265, 1, 152064, 0xca810f3b -0, 266, 266, 1, 152064, 0x91c90741 +0, 266, 266, 1, 152064, 0x6d9504c4 0, 267, 267, 1, 152064, 0x4edcfbfa -0, 268, 268, 1, 152064, 0x0ca40c66 +0, 268, 268, 1, 152064, 0x292c0bfd 0, 269, 269, 1, 152064, 0xee998e3d 0, 270, 270, 1, 152064, 0xe4b6c1b2 0, 271, 271, 1, 152064, 0xbbe0a4cc -0, 272, 272, 1, 152064, 0xd080bcfd +0, 272, 272, 1, 152064, 0xcd88bcf2 0, 273, 273, 1, 152064, 0x365df7c5 -0, 274, 274, 1, 152064, 0x934f071f +0, 274, 274, 1, 152064, 0x01cd06a4 0, 275, 275, 1, 152064, 0xcfaefeef -0, 276, 276, 1, 152064, 0xedd8263e +0, 276, 276, 1, 152064, 0xe615289d 0, 277, 277, 1, 152064, 0x1d5243de -0, 278, 278, 1, 152064, 0xc0d87e50 +0, 278, 278, 1, 152064, 0x7c397dfe 0, 279, 279, 1, 152064, 0xe25845b1 -0, 280, 280, 1, 152064, 0x47006123 +0, 280, 280, 1, 152064, 0x2d6a60a8 0, 281, 281, 1, 152064, 0xf1926203 -0, 282, 282, 1, 152064, 0x494b8b9c +0, 282, 282, 1, 152064, 0x634a88c9 0, 283, 283, 1, 152064, 0xc50aa1b7 -0, 284, 284, 1, 152064, 0xb82da5e2 +0, 284, 284, 1, 152064, 0x972fa713 0, 285, 285, 1, 152064, 0xa11cd0f6 -0, 286, 286, 1, 152064, 0x7ebff98d +0, 286, 286, 1, 152064, 0xbff8f90e 0, 287, 287, 1, 152064, 0x00902e76 -0, 288, 288, 1, 152064, 0xdee41ea2 +0, 288, 288, 1, 152064, 0x5cf31cb1 0, 289, 289, 1, 152064, 0x2b026058 -0, 290, 290, 1, 152064, 0xce81051f +0, 290, 290, 1, 152064, 0x258002cc 0, 291, 291, 1, 152064, 0x0d708815 -0, 292, 292, 1, 152064, 0xd7719e35 +0, 292, 292, 1, 152064, 0xe3809ce0 0, 293, 293, 1, 152064, 0xf0239467 -0, 294, 294, 1, 152064, 0x466d98b4 +0, 294, 294, 1, 152064, 0x6e71916a 0, 295, 295, 1, 152064, 0xc1fb36e1 -0, 296, 296, 1, 152064, 0x26bc139e +0, 296, 296, 1, 152064, 0xd47f07c9 0, 297, 297, 1, 152064, 0x7fd111ea -0, 298, 298, 1, 152064, 0xa39737cb +0, 298, 298, 1, 152064, 0xc4023a80 0, 299, 299, 1, 152064, 0x8f5851ba -0, 300, 300, 1, 152064, 0xa971f6e2 +0, 300, 300, 1, 152064, 0x9982f47b 0, 301, 301, 1, 152064, 0x0e5f6f80 -0, 302, 302, 1, 152064, 0xdb8b5e06 +0, 302, 302, 1, 152064, 0x49925e53 0, 303, 303, 1, 152064, 0xf6006bcc -0, 304, 304, 1, 152064, 0x060cd1a6 +0, 304, 304, 1, 152064, 0xd4b5d0f7 0, 305, 305, 1, 152064, 0x419ef0a4 -0, 306, 306, 1, 152064, 0xe79f0b93 +0, 306, 306, 1, 152064, 0x4e610934 0, 307, 307, 1, 152064, 0x1919e999 -0, 308, 308, 1, 152064, 0xacb715bc +0, 308, 308, 1, 152064, 0x3a750d80 0, 309, 309, 1, 152064, 0x16616075 -0, 310, 310, 1, 152064, 0x09aa4f10 +0, 310, 310, 1, 152064, 0x3284519f 0, 311, 311, 1, 152064, 0x976cdd70 -0, 312, 312, 1, 152064, 0x4811dc21 +0, 312, 312, 1, 152064, 0x4ec5d1e3 0, 313, 313, 1, 152064, 0x30d31172 -0, 314, 314, 1, 152064, 0x2db60b70 +0, 314, 314, 1, 152064, 0xe33609b5 0, 315, 315, 1, 152064, 0x5377bb89 -0, 316, 316, 1, 152064, 0x6c20cab3 +0, 316, 316, 1, 152064, 0x5479cd3d 0, 317, 317, 1, 152064, 0x964dad60 -0, 318, 318, 1, 152064, 0x514df2c3 +0, 318, 318, 1, 152064, 0x3a7deaf4 0, 319, 319, 1, 152064, 0xced22332 -0, 320, 320, 1, 152064, 0x1c64bc82 +0, 320, 320, 1, 152064, 0x3b36b53f 0, 321, 321, 1, 152064, 0x10c38662 -0, 322, 322, 1, 152064, 0xe6c7ff46 +0, 322, 322, 1, 152064, 0x45d4fceb 0, 323, 323, 1, 152064, 0x359da948 -0, 324, 324, 1, 152064, 0x5a9458ee +0, 324, 324, 1, 152064, 0x60625190 0, 325, 325, 1, 152064, 0x1cda9888 -0, 326, 326, 1, 152064, 0xbd081682 +0, 326, 326, 1, 152064, 0x77ad1d8c 0, 327, 327, 1, 152064, 0x20f1510f -0, 328, 328, 1, 152064, 0x6bc261a9 +0, 328, 328, 1, 152064, 0xd11d52c6 0, 329, 329, 1, 152064, 0x9f0e5797 -0, 330, 330, 1, 152064, 0xd14ca712 +0, 330, 330, 1, 152064, 0x174ca55b 0, 331, 331, 1, 152064, 0x8df79054 -0, 332, 332, 1, 152064, 0x34efa950 +0, 332, 332, 1, 152064, 0x3844a495 0, 333, 333, 1, 152064, 0x268d9d12 -0, 334, 334, 1, 152064, 0xad91b2ed +0, 334, 334, 1, 152064, 0xf672b44f 0, 335, 335, 1, 152064, 0xe0ac87cf -0, 336, 336, 1, 152064, 0xba4cfd8e +0, 336, 336, 1, 152064, 0xbc99fd7d 0, 337, 337, 1, 152064, 0x876ef9e3 -0, 338, 338, 1, 152064, 0x45ab6684 +0, 338, 338, 1, 152064, 0xef8066f7 0, 339, 339, 1, 152064, 0x72a99564 -0, 340, 340, 1, 152064, 0xdfc8be01 +0, 340, 340, 1, 152064, 0x5921c088 0, 341, 341, 1, 152064, 0x3a6b9e74 -0, 342, 342, 1, 152064, 0xca1be9c6 +0, 342, 342, 1, 152064, 0xfb03e9b5 0, 343, 343, 1, 152064, 0xc351bfc6 -0, 344, 344, 1, 152064, 0xef30c978 +0, 344, 344, 1, 152064, 0x2faec717 0, 345, 345, 1, 152064, 0x062fc6f3 -0, 346, 346, 1, 152064, 0x8731a9ec +0, 346, 346, 1, 152064, 0xede7a97f 0, 347, 347, 1, 152064, 0x19874144 0, 348, 348, 1, 152064, 0x929650eb 0, 349, 349, 1, 152064, 0x082557a1 -0, 350, 350, 1, 152064, 0xb80510ae +0, 350, 350, 1, 152064, 0x2b25104b diff --git a/tests/ref/fate/mpeg2-ticket6677 b/tests/ref/fate/mpeg2-ticket6677 new file mode 100644 index 0000000000000..e963e32f2dfbc --- /dev/null +++ b/tests/ref/fate/mpeg2-ticket6677 @@ -0,0 +1,12 @@ +#tb 0: 1/30 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 720x480 +#sar 0: 8/9 +0, 0, 0, 1, 518400, 0xc1866f5f +0, 1, 1, 1, 518400, 0x9ba32764 +0, 2, 2, 1, 518400, 0xa9031bb8 +0, 3, 3, 1, 518400, 0x5e2c3502 +0, 4, 4, 1, 518400, 0xe860027a +0, 5, 5, 1, 518400, 0xa9152430 +0, 6, 6, 1, 518400, 0xb98dd9f7 diff --git a/tests/ref/fate/mpegps-remuxed-pcm-demux b/tests/ref/fate/mpegps-remuxed-pcm-demux new file mode 100644 index 0000000000000..b5b277868ff50 --- /dev/null +++ b/tests/ref/fate/mpegps-remuxed-pcm-demux @@ -0,0 +1,50 @@ +#tb 0: 1/90000 +#media_type 0: audio +#codec_id 0: pcm_dvd +#sample_rate 0: 44100 +#channel_layout 0: 4 +#channel_layout_name 0: mono +0, 0, 0, 2040, 2005, 0x8e98e563 +0, 2090, 2090, 2069, 2033, 0xd6f2f455 +0, 4180, 4180, 2057, 2021, 0x77a6e6c9 +0, 6269, 6269, 2057, 2021, 0x8dbcf6be +0, 8359, 8359, 2057, 2021, 0xc629eaa0 +0, 10449, 10449, 2057, 2021, 0xa951ebe5 +0, 12539, 12539, 2057, 2021, 0x1324f29b +0, 14629, 14629, 2057, 2021, 0x55f1e968 +0, 16718, 16718, 2057, 2021, 0x98a7f994 +0, 18808, 18808, 2057, 2021, 0xba42f42f +0, 20898, 20898, 2057, 2021, 0xcf5cefe6 +0, 22988, 22988, 2057, 2021, 0xeef8f2b5 +0, 25078, 25078, 2057, 2021, 0x71faf42f +0, 27167, 27167, 2057, 2021, 0x0346f019 +0, 29257, 29257, 2057, 2021, 0xbca0f4a3 +0, 31347, 31347, 2057, 2021, 0x3b6ced4f +0, 33437, 33437, 2057, 2021, 0xc8b9ea0a +0, 35527, 35527, 2057, 2021, 0x18e5f385 +0, 37616, 37616, 2057, 2021, 0x74f6e9d6 +0, 39706, 39706, 2057, 2021, 0x35d8f2b5 +0, 41796, 41796, 2057, 2021, 0x9d2aec53 +0, 43886, 43886, 2057, 2021, 0xf0acf1a0 +0, 45976, 45976, 2057, 2021, 0xa724ebe9 +0, 48065, 48065, 2057, 2021, 0xd4f8f534 +0, 50155, 50155, 2057, 2021, 0xdf62efc6 +0, 52245, 52245, 2057, 2021, 0x9865f504 +0, 54335, 54335, 2057, 2021, 0x8670efb7 +0, 56424, 56424, 2057, 2021, 0xe51af219 +0, 58514, 58514, 2057, 2021, 0x0210f27f +0, 60604, 60604, 2057, 2021, 0x4b08f406 +0, 62694, 62694, 2057, 2021, 0x2b02eed4 +0, 64784, 64784, 2057, 2021, 0x0445ed00 +0, 66873, 66873, 2057, 2021, 0xfae9f21f +0, 68963, 68963, 2057, 2021, 0x3d6beabc +0, 71053, 71053, 2057, 2021, 0xc50af39c +0, 73143, 73143, 2057, 2021, 0xf9eceb82 +0, 75233, 75233, 2057, 2021, 0x7b89eb9b +0, 77322, 77322, 2057, 2021, 0x7c07ef4b +0, 79412, 79412, 2057, 2021, 0xbfacf1eb +0, 81502, 81502, 2057, 2021, 0xccb2f27b +0, 83592, 83592, 2057, 2021, 0xc035f557 +0, 85682, 85682, 2057, 2021, 0xbdf1edea +0, 87771, 87771, 2057, 2021, 0x3644f424 +0, 89861, 89861, 1457, 1433, 0xdd17d51f diff --git a/tests/ref/fate/mpegts-probe-program b/tests/ref/fate/mpegts-probe-program new file mode 100644 index 0000000000000..bb1012c8c7d04 --- /dev/null +++ b/tests/ref/fate/mpegts-probe-program @@ -0,0 +1,8 @@ +[PROGRAM] +[STREAM] +codec_name=hevc +[/STREAM] +[/PROGRAM] +[STREAM] +codec_name=hevc +[/STREAM] diff --git a/tests/ref/fate/mxf-reel_name b/tests/ref/fate/mxf-reel_name new file mode 100644 index 0000000000000..fb9586097a16d --- /dev/null +++ b/tests/ref/fate/mxf-reel_name @@ -0,0 +1 @@ +dda6c54b642b8794a87d809fdb361f95 diff --git a/tests/ref/fate/opt b/tests/ref/fate/opt index 7b47d429c55e7..6a7dbfa797026 100644 --- a/tests/ref/fate/opt +++ b/tests/ref/fate/opt @@ -18,31 +18,31 @@ num64=1 flt=0.333333 dbl=0.333333 TestContext AVOptions: - -num E....... set num (from 0 to 100) (default 0) - -toggle E....... set toggle (from 0 to 1) (default 1) - -rational E....... set rational (from 0 to 10) (default 1/1) - -string E....... set string (default "default") - -escape E....... set escape str (default "\=,") - -flags E....... set flags (default cool) - cool E....... set cool flag - lame E....... set lame flag - mu E....... set mu flag - -size E....... set size (default "200x300") - -pix_fmt E....... set pixfmt (default 0bgr) - -sample_fmt E....... set samplefmt (default s16) - -video_rate E....... set videorate (default "25") - -duration E....... set duration (default 0.001) - -color E....... set color (default "pink") - -cl E....... set channel layout (default 0x137) - -bin E....... set binary value - -bin1 E....... set binary value - -bin2 E....... set binary value - -num64 E....... set num 64bit (from 0 to 100) (default 1) - -flt E....... set float (from 0 to 100) (default 0.333333) - -dbl E....... set double (from 0 to 100) (default 0.333333) - -bool1 E....... set boolean value (default auto) - -bool2 E....... set boolean value (default true) - -bool3 E....... set boolean value (default false) + -num E........ set num (from 0 to 100) (default 0) + -toggle E........ set toggle (from 0 to 1) (default 1) + -rational E........ set rational (from 0 to 10) (default 1/1) + -string E........ set string (default "default") + -escape E........ set escape str (default "\=,") + -flags E........ set flags (default cool) + cool E........ set cool flag + lame E........ set lame flag + mu E........ set mu flag + -size E........ set size (default "200x300") + -pix_fmt E........ set pixfmt (default 0bgr) + -sample_fmt E........ set samplefmt (default s16) + -video_rate E........ set videorate (default "25") + -duration E........ set duration (default 0.001) + -color E........ set color (default "pink") + -cl E........ set channel layout (default 0x137) + -bin E........ set binary value + -bin1 E........ set binary value + -bin2 E........ set binary value + -num64 E........ set num 64bit (from 0 to 100) (default 1) + -flt E........ set float (from 0 to 100) (default 0.333333) + -dbl E........ set double (from 0 to 100) (default 0.333333) + -bool1 E........ set boolean value (default auto) + -bool2 E........ set boolean value (default true) + -bool3 E........ set boolean value (default false) Testing av_opt_is_set_to_default() name: num default:1 error: diff --git a/tests/ref/fate/rgb24-mkv b/tests/ref/fate/rgb24-mkv index 4c357accaf2b7..439b2bc5e91e8 100644 --- a/tests/ref/fate/rgb24-mkv +++ b/tests/ref/fate/rgb24-mkv @@ -1,5 +1,5 @@ -55270be3b5d393d770a1dfcb19b68271 *tests/data/fate/rgb24-mkv.matroska -58345 tests/data/fate/rgb24-mkv.matroska +09ee413b2d92a6be5e3b18e9e20a1f74 *tests/data/fate/rgb24-mkv.matroska +58342 tests/data/fate/rgb24-mkv.matroska #tb 0: 1/10 #media_type 0: video #codec_id 0: rawvideo diff --git a/tests/ref/fate/segment-mp4-to-ts b/tests/ref/fate/segment-mp4-to-ts index 847c1a297db90..b5accb60f7268 100644 --- a/tests/ref/fate/segment-mp4-to-ts +++ b/tests/ref/fate/segment-mp4-to-ts @@ -1,10 +1,10 @@ -#extradata 0: 50, 0x4f1b0df9 +#extradata 0: 51, 0x5d140df9 #tb 0: 1/90000 #media_type 0: video #codec_id 0: h264 #dimensions 0: 640x360 #sar 0: 1/1 -0, -7200, 0, 0, 22630, 0x9b109541, S=1, 1, 0x00e000e0 +0, -7200, 0, 0, 22631, 0x9cec9541, S=1, 1, 0x00e000e0 0, -3600, 14400, 0, 4021, 0xbf7cdb02, F=0x0, S=1, 1, 0x00e000e0 0, 0, 7200, 0, 1096, 0x4f162690, F=0x0, S=1, 1, 0x00e000e0 0, 3600, 3600, 0, 687, 0x00394b95, F=0x0, S=1, 1, 0x00e000e0 diff --git a/tests/ref/fate/source b/tests/ref/fate/source index 2def03495beec..809c4632d4ffd 100644 --- a/tests/ref/fate/source +++ b/tests/ref/fate/source @@ -23,12 +23,8 @@ compat/avisynth/avs/types.h compat/avisynth/avxsynth_c.h compat/avisynth/windowsPorts/basicDataTypeConversions.h compat/avisynth/windowsPorts/windows2linux.h -compat/cuda/dynlink_cuda.h -compat/cuda/dynlink_cuviddec.h compat/cuda/dynlink_loader.h -compat/cuda/dynlink_nvcuvid.h compat/float/float.h compat/float/limits.h -compat/nvenc/nvEncodeAPI.h Use of av_clip() where av_clip_uintp2() could be used: Use of av_clip() where av_clip_intp2() could be used: diff --git a/tests/ref/fate/sub-cc-scte20 b/tests/ref/fate/sub-cc-scte20 new file mode 100644 index 0000000000000..71fc92bfc5da5 --- /dev/null +++ b/tests/ref/fate/sub-cc-scte20 @@ -0,0 +1,15 @@ +[Script Info] +; Script generated by FFmpeg/Lavc +ScriptType: v4.00+ +PlayResX: 384 +PlayResY: 288 + +[V4+ Styles] +Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding +Style: Default,Monospace,16,&Hffffff,&Hffffff,&H0,&H0,0,0,0,0,100,100,0,0,3,1,0,2,10,10,10,0 + +[Events] +Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text +Dialogue: 0,0:00:00.00,0:00:01.44,Default,,0,0,0,,{\an7}{\pos(48,182)}BESIDES THE +Dialogue: 0,0:00:01.43,0:00:03.93,Default,,0,0,0,,{\an7}{\pos(38,166)}\hBESIDES THE \N{\an7}{\pos(38,197)}SPENDING AND THIS, IS THAT CAR +Dialogue: 0,0:00:03.94,0:00:06.31,Default,,0,0,0,,{\an7}{\pos(38,182)}SPENDING AND THIS, IS THAT CAR \N{\an7}{\pos(38,197)}MANUFACTURERS ARE ABOUT AS diff --git a/tests/ref/fate/time_base b/tests/ref/fate/time_base index 7923556b351a9..4dd14084d370a 100644 --- a/tests/ref/fate/time_base +++ b/tests/ref/fate/time_base @@ -1 +1 @@ -d26a35b141551b36c5b8bd716451cfcb +f97551f884df5ab709c5869c66c7b9bc diff --git a/tests/ref/fate/ts-demux b/tests/ref/fate/ts-demux index e2931af427326..eb13ecc6840f9 100644 --- a/tests/ref/fate/ts-demux +++ b/tests/ref/fate/ts-demux @@ -13,7 +13,7 @@ 1, 0, 0, 2880, 1536, 0x773ffeea, S=1, 1, 0x00bd00bd 1, 2880, 2880, 2880, 1536, 0x6dc10748 1, 5760, 5760, 2880, 1536, 0xbab5129c -1, 8640, 8640, 2880, 1536, 0x602f034b +1, 8640, 8640, 2880, 1536, 0x602f034b, S=1, 1, 0x00bd00bd 1, 11520, 11520, 2880, 906, 0x69cdcbcd 0, 32037, 36541, 1501, 114336, 0x37a215a8, S=1, 1, 0x00e000e0 0, 33538, 33538, 1501, 12560, 0xb559a3d4, F=0x0, S=1, 1, 0x00e000e0 diff --git a/tests/ref/fate/utvideo_rgb_int_gradient b/tests/ref/fate/utvideo_rgb_int_gradient new file mode 100644 index 0000000000000..a4e6986622ec9 --- /dev/null +++ b/tests/ref/fate/utvideo_rgb_int_gradient @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x48 +#sar 0: 0/1 +0, 0, 0, 1, 9216, 0xd00fdd8c diff --git a/tests/ref/fate/utvideo_rgb_int_median b/tests/ref/fate/utvideo_rgb_int_median new file mode 100644 index 0000000000000..a4e6986622ec9 --- /dev/null +++ b/tests/ref/fate/utvideo_rgb_int_median @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x48 +#sar 0: 0/1 +0, 0, 0, 1, 9216, 0xd00fdd8c diff --git a/tests/ref/fate/utvideo_rgba_gradient b/tests/ref/fate/utvideo_rgba_gradient new file mode 100644 index 0000000000000..f52f46b23e519 --- /dev/null +++ b/tests/ref/fate/utvideo_rgba_gradient @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 37x37 +#sar 0: 0/1 +0, 0, 0, 1, 5476, 0x20f860ad diff --git a/tests/ref/fate/utvideo_yuv420_gradient b/tests/ref/fate/utvideo_yuv420_gradient new file mode 100644 index 0000000000000..5e2b7ee1be283 --- /dev/null +++ b/tests/ref/fate/utvideo_yuv420_gradient @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x48 +#sar 0: 0/1 +0, 0, 0, 1, 4608, 0xc441dd90 diff --git a/tests/ref/fate/utvideo_yuv420_int_gradient b/tests/ref/fate/utvideo_yuv420_int_gradient new file mode 100644 index 0000000000000..08e45d79e6abd --- /dev/null +++ b/tests/ref/fate/utvideo_yuv420_int_gradient @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x48 +#sar 0: 0/1 +0, 0, 0, 1, 4608, 0x8cecddae diff --git a/tests/ref/fate/utvideo_yuv420_int_median b/tests/ref/fate/utvideo_yuv420_int_median new file mode 100644 index 0000000000000..08e45d79e6abd --- /dev/null +++ b/tests/ref/fate/utvideo_yuv420_int_median @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x48 +#sar 0: 0/1 +0, 0, 0, 1, 4608, 0x8cecddae diff --git a/tests/ref/fate/utvideo_yuv422_gradient b/tests/ref/fate/utvideo_yuv422_gradient new file mode 100644 index 0000000000000..f4949b23413bd --- /dev/null +++ b/tests/ref/fate/utvideo_yuv422_gradient @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x48 +#sar 0: 0/1 +0, 0, 0, 1, 6144, 0xd33add91 diff --git a/tests/ref/fate/utvideo_yuv422_int_gradient b/tests/ref/fate/utvideo_yuv422_int_gradient new file mode 100644 index 0000000000000..f4949b23413bd --- /dev/null +++ b/tests/ref/fate/utvideo_yuv422_int_gradient @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x48 +#sar 0: 0/1 +0, 0, 0, 1, 6144, 0xd33add91 diff --git a/tests/ref/fate/utvideo_yuv422_int_median b/tests/ref/fate/utvideo_yuv422_int_median new file mode 100644 index 0000000000000..f4949b23413bd --- /dev/null +++ b/tests/ref/fate/utvideo_yuv422_int_median @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x48 +#sar 0: 0/1 +0, 0, 0, 1, 6144, 0xd33add91 diff --git a/tests/ref/fate/utvideo_yuv444_709_gradient b/tests/ref/fate/utvideo_yuv444_709_gradient new file mode 100644 index 0000000000000..0870c87d3bf76 --- /dev/null +++ b/tests/ref/fate/utvideo_yuv444_709_gradient @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 38x38 +#sar 0: 0/1 +0, 0, 0, 1, 4332, 0xa9de65ba diff --git a/tests/ref/fate/utvideo_yuv444_709_int_gradient b/tests/ref/fate/utvideo_yuv444_709_int_gradient new file mode 100644 index 0000000000000..af9337cd6a82c --- /dev/null +++ b/tests/ref/fate/utvideo_yuv444_709_int_gradient @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x48 +#sar 0: 0/1 +0, 0, 0, 1, 9216, 0xbcb2dd78 diff --git a/tests/ref/fate/utvideo_yuv444_709_int_median b/tests/ref/fate/utvideo_yuv444_709_int_median new file mode 100644 index 0000000000000..af9337cd6a82c --- /dev/null +++ b/tests/ref/fate/utvideo_yuv444_709_int_median @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x48 +#sar 0: 0/1 +0, 0, 0, 1, 9216, 0xbcb2dd78 diff --git a/tests/ref/fate/utvideo_yuv444_709_median b/tests/ref/fate/utvideo_yuv444_709_median new file mode 100644 index 0000000000000..af9337cd6a82c --- /dev/null +++ b/tests/ref/fate/utvideo_yuv444_709_median @@ -0,0 +1,6 @@ +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: rawvideo +#dimensions 0: 64x48 +#sar 0: 0/1 +0, 0, 0, 1, 9216, 0xbcb2dd78 diff --git a/tests/ref/fate/utvideoenc_rgb_left b/tests/ref/fate/utvideoenc_rgb_left index a1d200096a641..1ee7c5856433d 100644 --- a/tests/ref/fate/utvideoenc_rgb_left +++ b/tests/ref/fate/utvideoenc_rgb_left @@ -8,53 +8,53 @@ #dimensions 0: 352x288 #sar 0: 0/1 #stream#, dts, pts, duration, size, hash -0, 0, 0, 1, 182328, cd084b244939d7e0008d8e5ab3429dc1 -0, 1, 1, 1, 182336, c9c40672750f372134185901147fb776 -0, 2, 2, 1, 182956, c728911ca73225f2dc7453533c9be95e -0, 3, 3, 1, 182384, 54521f709b461a25198db755bce582fa -0, 4, 4, 1, 181704, 5e03ab58b4480a6613f54857f10c39e5 -0, 5, 5, 1, 182136, c623fb06b90fdd7a5ba0b4f217b6a388 -0, 6, 6, 1, 181552, 5d03be9dfc01ad99364fc3cc8378af72 -0, 7, 7, 1, 182292, fc90878278c82b2f835151dc6d43dd47 -0, 8, 8, 1, 181424, 9b6339a0d3af2d3034162183cd4d79e4 -0, 9, 9, 1, 182316, 7e45bb5ffe57f98a433420abaffe78cc -0, 10, 10, 1, 182064, d9525605a7d7d75a8e33502f61733af1 -0, 11, 11, 1, 182596, 62e87fa5c33a8d208deaa8719682b9a5 -0, 12, 12, 1, 180900, 149059d3d56c55358c7044c7d569730f -0, 13, 13, 1, 181920, 0d20f588c27471a038e159a131e9c8ea -0, 14, 14, 1, 182824, a301a411ff11042ecb583e1e3b12dbda -0, 15, 15, 1, 182452, 0ee2a9ed39fb8569a8d6c2b3afb8f80a -0, 16, 16, 1, 182312, 68dd3b820adf2cbc6686a7d48fa22c6e -0, 17, 17, 1, 181856, 1897926cfe9b7acaf9c21714c449ce41 -0, 18, 18, 1, 181108, 15d2af460733fdd896078632cdfef9fd -0, 19, 19, 1, 181388, 8b8e7a4b7d355f41f7e836120c4792ac -0, 20, 20, 1, 180936, e18e27aa027f2470bfa95c536a0a89af -0, 21, 21, 1, 180900, eb663ae3c5ffa8e751280e0dbb260e02 -0, 22, 22, 1, 181936, 7514bbe06cee027f54710dc900297863 -0, 23, 23, 1, 182304, 8cb2dcdbd4c919b4c977f45bee46c54c -0, 24, 24, 1, 182580, 9185ed53b7e8339b61d3abe230bbab71 -0, 25, 25, 1, 182572, 81f8bdd3255b91d6621e9ebd3c9d7679 -0, 26, 26, 1, 182356, 1f9ff40700881054c62e33acde06910d -0, 27, 27, 1, 181532, 10d2477aa1e319a61e517d25fd6c95d0 -0, 28, 28, 1, 179580, 3012480c43d15866ccc4a81d56650ee2 -0, 29, 29, 1, 179528, 5e0fbd62a164dc72cf511023da792175 -0, 30, 30, 1, 180760, 679f430c86dca203456f532e978dffc2 -0, 31, 31, 1, 181564, 64d31faf01cb7b52d7d7e20280e6652b -0, 32, 32, 1, 181428, 04961d71aa3c81b33d28b39ead20ee1d -0, 33, 33, 1, 182980, 51361c802005721002f5f4924f081708 -0, 34, 34, 1, 182624, 67c5582c45e3ee7e6aca49fdc0a980b8 -0, 35, 35, 1, 182352, 4fade9db12f2d6ce633556fdb8914971 -0, 36, 36, 1, 181336, ac8fbab67b36d58c4e8374bfb07458e7 -0, 37, 37, 1, 181528, f798157b6d4d04c767ecb76346922ddc -0, 38, 38, 1, 179776, 01d407ed0b86eeb2c3ee3c24dd452d8d -0, 39, 39, 1, 180100, 062e4af150100d7accf86a907a4b99b5 -0, 40, 40, 1, 180228, 23c617b76ef8f274bd089016fb8516c7 -0, 41, 41, 1, 180592, 5cd3d93597325196079dc019556f6933 -0, 42, 42, 1, 181188, d39d52f5b690661434b1abd8717b3e30 -0, 43, 43, 1, 181300, 9e202444287234bafd103fab83b1a974 -0, 44, 44, 1, 180812, 602165271de71594132cce98af56a7b2 -0, 45, 45, 1, 178816, c427d67196f43ece6bf3855e1256d7bb -0, 46, 46, 1, 178196, 0d05902e2870a85333a216c723077e98 -0, 47, 47, 1, 178772, 57f528eb984b5b7181c89b48b58271f3 -0, 48, 48, 1, 178652, 5cd1031b0ada3ba9c2d4c2f2b7c8e277 -0, 49, 49, 1, 178512, d3c0c84fc63f1e32a4a026e2cd39b161 +0, 0, 0, 1, 197832, 11da778d3d904fcd2ad6daf84b227e6b +0, 1, 1, 1, 197840, e89c967c27d7cd9963c9f12f9df2c268 +0, 2, 2, 1, 198632, b2c59f9834024d1e4b829e540a91814e +0, 3, 3, 1, 197100, b21b344d42da10ef6730fed553fb3f2f +0, 4, 4, 1, 196236, e61de0e4ff879b6630ae8eb63d063b7f +0, 5, 5, 1, 197352, efd21105f5f98cbd5953e85a10091531 +0, 6, 6, 1, 197252, 0e2444a9185f68294c16f034dd522666 +0, 7, 7, 1, 197204, 0254750d85c474c13fe3c0e4e3c272cf +0, 8, 8, 1, 197084, 4c89a99df233575978d9bcd8936e4588 +0, 9, 9, 1, 197692, 681a76f67892f9d05be72abaa403bc32 +0, 10, 10, 1, 197456, bba96b8520eaa5b6612b5c48d6409938 +0, 11, 11, 1, 197024, b9ea3dcc0cb8cf552e536765c5bb31f6 +0, 12, 12, 1, 195132, 2664b79397af76081b7ddd5c3507d579 +0, 13, 13, 1, 196796, d6128308c1fc3493ebc2cece7ed785cb +0, 14, 14, 1, 198708, 6b3e50d5d47f29dfb38e178ffb9036c5 +0, 15, 15, 1, 198000, a3d6be893edb02e44f65f7a06aa8eeed +0, 16, 16, 1, 197568, 1ed7a01f810770d62aed3d12d10cd12c +0, 17, 17, 1, 197396, 515e13befb9eebf92f77574d6cd9fec4 +0, 18, 18, 1, 196680, ac1835b9a426927855e3e5dbab28c177 +0, 19, 19, 1, 196784, 56fa26a339c69df17d003fb00b335baa +0, 20, 20, 1, 195980, 853744fb2a2de76858d32f35f8b3d836 +0, 21, 21, 1, 196120, e9c50124d92e261f7a98599cb9a20e36 +0, 22, 22, 1, 196620, e750eaed752d09874d823ee40a8904c4 +0, 23, 23, 1, 197528, 6671598014db402b70e2753efda028d1 +0, 24, 24, 1, 198204, 6e471eb9c354d6be4e0d8a691313e23e +0, 25, 25, 1, 197512, 7e415738fb7889dee478f63900f47e7c +0, 26, 26, 1, 196832, 0e30afab6de602d099d88edd6276f1de +0, 27, 27, 1, 196396, 13880ad888c9cf3504e2eb087767602e +0, 28, 28, 1, 194220, aa9007687cade8c9a872de063bed0755 +0, 29, 29, 1, 194428, 78ab57958ef8914095477e58ee4461c2 +0, 30, 30, 1, 195676, a7d0779dcda7f93da5601482bb68625b +0, 31, 31, 1, 196352, 668c525c910000aab7d9285be6ac7ed1 +0, 32, 32, 1, 196468, 9c124995d63f2a548e640811e9391951 +0, 33, 33, 1, 198188, 1cb600005e68d1ef1418b1b42e463f0a +0, 34, 34, 1, 197556, 80f6223aba2d6cfab3cb596f372243f2 +0, 35, 35, 1, 197020, b1890bbb734c016103190a9c043e9fe2 +0, 36, 36, 1, 196208, 7adf4b08c90231eddec16aff65cc138f +0, 37, 37, 1, 196448, de69c81a605c9e173a7ac65077d0396d +0, 38, 38, 1, 194072, 8b3afb6897210f1660b4427df0d9cc51 +0, 39, 39, 1, 194036, 1827f1deef659426939ffd94b73575bc +0, 40, 40, 1, 194436, 46f3ad01e18a2a24d720e78f9bdb532d +0, 41, 41, 1, 195696, a160ff1e281959147fe11606754ecc7d +0, 42, 42, 1, 196044, 37f15771f5c04c13b02c0127bd977fed +0, 43, 43, 1, 196384, fc43c356e577555757e220bee7e8a232 +0, 44, 44, 1, 195424, 6820346735e390b86d9564298c934101 +0, 45, 45, 1, 193688, 5f346f622f8e0d33d7f662e9dfbcccb5 +0, 46, 46, 1, 193000, 15eb6569d9fd39a343d110b965a97277 +0, 47, 47, 1, 193592, d41d561eb927b8e0d608177af90d0e1d +0, 48, 48, 1, 193512, 35112e23e238beff03c769674db40399 +0, 49, 49, 1, 192528, 3a3ac1b24fb8fc72174970d668c30292 diff --git a/tests/ref/fate/utvideoenc_rgb_median b/tests/ref/fate/utvideoenc_rgb_median index b1558d7f53330..6c4d2f808a8ca 100644 --- a/tests/ref/fate/utvideoenc_rgb_median +++ b/tests/ref/fate/utvideoenc_rgb_median @@ -8,53 +8,53 @@ #dimensions 0: 352x288 #sar 0: 0/1 #stream#, dts, pts, duration, size, hash -0, 0, 0, 1, 182160, abcf4f477f74b696faca2fcff1f62aa9 -0, 1, 1, 1, 182104, 7cbcf339fa40c24522067295b39d637f -0, 2, 2, 1, 183108, dfc2c418f4379a89654c16b34ff19446 -0, 3, 3, 1, 182320, 62a4647b05709d86c51a18be16877e98 -0, 4, 4, 1, 181920, 61d63520703503f6e17fad67cbc08794 -0, 5, 5, 1, 182424, f467638396feabe613b3c851289452d8 -0, 6, 6, 1, 182248, 8a0cba950d6c5d63ba9603212ca95b0e -0, 7, 7, 1, 181876, 91432f472cf373d5d4036bd100950f3e -0, 8, 8, 1, 182104, 1c8852d82a48c1b01911ffbedf0ac1f4 -0, 9, 9, 1, 182540, f36b9d48123b55f2141ae10dd26e1ca0 -0, 10, 10, 1, 182120, e6ecdb9af6591916153ca9aeba76b9d0 -0, 11, 11, 1, 182136, 7dc7b828a5b7c652df612474fad66f6b -0, 12, 12, 1, 181296, 347eac6563435a62f75298cefe13d3a6 -0, 13, 13, 1, 182136, 3bbcd8afacdf9549da9ebd736df548a7 -0, 14, 14, 1, 182412, 17f8c6ef692b4085624ce1ef7efbc963 -0, 15, 15, 1, 182732, 9212760fa11fe4fa193ba1aa259e9765 -0, 16, 16, 1, 181944, 7dd6d6a7084f97a77ec09ec6c62f0ab8 -0, 17, 17, 1, 182232, 518552687d47ae93726679f0ed962ef4 -0, 18, 18, 1, 181512, 29a66924742add13a0cae65d93d38ea9 -0, 19, 19, 1, 181424, 67c965637248333f92da9d493bf7546e -0, 20, 20, 1, 180764, 298457c6c2b3f4ebcda87a12579f094d -0, 21, 21, 1, 181072, 493ea592b7d59eebf01c002e7e22fc43 -0, 22, 22, 1, 181160, e30195fcc16ecfbb9348943cff01623f -0, 23, 23, 1, 182156, d26cfac33e19b4ca11210c9e6cb91955 -0, 24, 24, 1, 182260, 963c157d3f0023b49d23099d53d60c8b -0, 25, 25, 1, 181976, 2494d481bf2be97692eaeda95f279b0d -0, 26, 26, 1, 181832, f1be95c840d4fcb0c8d4b7aed5b197c5 -0, 27, 27, 1, 181424, 03d92e89358a8b9b9e7cf302edde307e -0, 28, 28, 1, 180632, 09f9e162fdaf28342c442172179a75c9 -0, 29, 29, 1, 180624, 481e7f7730ab3ba67c06faa620a8bd5e -0, 30, 30, 1, 181024, 7a1d1b06b73d2bf41563eb749805780c -0, 31, 31, 1, 181844, 8a6ce6dd6f79e423a3bb6c2b163adc55 -0, 32, 32, 1, 181712, a68007bbdf0169c9ed2dffae3dc63221 -0, 33, 33, 1, 182008, f37dd0635de369761e2de979ee799c3a -0, 34, 34, 1, 181800, 14029ba1c364eca476559ce553919e99 -0, 35, 35, 1, 181840, ee227d15f15c3cd564dcad2160453fb7 -0, 36, 36, 1, 181848, 13b5d0892cc76a25b4914f2d706a0ad5 -0, 37, 37, 1, 181976, 1a0be9f2cefe0d867c5c03d6b3987ad8 -0, 38, 38, 1, 181216, 79795d735f9e0f92091203bf8b9eb9ed -0, 39, 39, 1, 181236, 2d006c8c4ba448ca7841df76e44ffa88 -0, 40, 40, 1, 180672, ed5210abdae49042fcae9bde2f65a057 -0, 41, 41, 1, 181324, fbbc7839c595cd0f0efc0917edfed2c3 -0, 42, 42, 1, 180980, c6120b5a9440f4a0d83731627eb96d98 -0, 43, 43, 1, 181204, ac4371912d16f657c90e8a00cfafdfd2 -0, 44, 44, 1, 180720, d392d95c67349296d922dbf53ec3f832 -0, 45, 45, 1, 180028, 37a2717fbd5aaeb128812298484f8267 -0, 46, 46, 1, 179704, e8716f4856e4ccdc541632a218894f62 -0, 47, 47, 1, 179648, e99cbe5d1bbd7bce241ae500b4de06c2 -0, 48, 48, 1, 179424, 6f8a5e356fb77b61d9dfcabdf97340b9 -0, 49, 49, 1, 178980, 75a7700b822236b0ecb169fd692910f1 +0, 0, 0, 1, 194232, 96431f57c15dfce7894563df186457c7 +0, 1, 1, 1, 194256, f7617d88a5bb862047dd62a3618eca2c +0, 2, 2, 1, 195048, 77aa5446e64733aa29bf5ba4ad92073d +0, 3, 3, 1, 194012, 4a73e8b156eebc15de299c57087639a5 +0, 4, 4, 1, 193268, a0afb35be4f9f91366d848b0600c949d +0, 5, 5, 1, 194168, b0580fbf05dc9a2abc053f2deb48b8c9 +0, 6, 6, 1, 194240, 5f5adb862a13843123e27f01d1870799 +0, 7, 7, 1, 193512, 71dca88d3fdf753858887006ac3cc13b +0, 8, 8, 1, 193952, 7efa7d138fa412343741ccbeb18acd18 +0, 9, 9, 1, 194700, ffddf410e5b8e49cf0462baf7bc9e179 +0, 10, 10, 1, 193984, c71b59a9699f2832e8c3d76e5d5e4f0c +0, 11, 11, 1, 193640, 598bdf3a814db44775ad703d674e9ab9 +0, 12, 12, 1, 192900, de83dd60e69a305ab0a79c4a859d444d +0, 13, 13, 1, 193780, 7858349baa970794b0353e011f751259 +0, 14, 14, 1, 194564, 9470359eb6f09d5a1db5dc199e910bcf +0, 15, 15, 1, 194856, c15823765a9d4d1583f2dd7b63534c95 +0, 16, 16, 1, 194056, 5f60ee32c9e06f080dcd0b4025576d5b +0, 17, 17, 1, 194124, a10815c6603e375ab0b21331e03651de +0, 18, 18, 1, 193508, 54a5762f2717ce1be3b9193b930d1b1f +0, 19, 19, 1, 193412, 782b07b8ac3bd1a86ad562ef7d7ebca5 +0, 20, 20, 1, 192472, 96f7f1983d6ac34c591e33045c5ba3dc +0, 21, 21, 1, 192844, b56bec01d69b3e073ac9823b2bf4c2f5 +0, 22, 22, 1, 192668, 3071c2d282672a597bee4682cef304ff +0, 23, 23, 1, 194108, 3484d2ca748c20d87280f5333054552d +0, 24, 24, 1, 194552, b05a90da02c18ee880234d620259361d +0, 25, 25, 1, 193860, 08617a493d2abe75b438a35315aef7a0 +0, 26, 26, 1, 193452, 958eaccd55d6a55832ec9cb6ce201fc4 +0, 27, 27, 1, 193364, 8cab6850866ce9c0ecf818cc4630bdb3 +0, 28, 28, 1, 192064, 03ce30fadf6b80d0b901c0f53f09e23b +0, 29, 29, 1, 192464, 7bf3364a095cbea2a032f6762d3433bf +0, 30, 30, 1, 192880, 6176bcbdf42f787aa4c21791fd3d73e2 +0, 31, 31, 1, 193672, 0760b04edf969c5b0914fcae82ee7ee3 +0, 32, 32, 1, 193636, a08c905e46e35d575001e570389a9b70 +0, 33, 33, 1, 193976, dff151dc2dfa5a86103bddc11484a38f +0, 34, 34, 1, 193456, 86f44e4a438ad150baee14facdebb701 +0, 35, 35, 1, 193768, 5645f55ed8154a0c913890a11b6f1261 +0, 36, 36, 1, 193584, 023ca364d9a88ccb2bae08008c6c3098 +0, 37, 37, 1, 193844, be83062bffff72ba0c442f502c41a187 +0, 38, 38, 1, 193008, 6e1dd8f2d18145ee199395d34c0e55ff +0, 39, 39, 1, 192680, 27256f3f1111554a75d7b7366b77457f +0, 40, 40, 1, 192188, d86ea5fafc41d57e320479f54fd1286a +0, 41, 41, 1, 193200, a37553416c0187b364ce2b64ece22975 +0, 42, 42, 1, 193052, 8e3c81d246b744c2aed9b735015ee93f +0, 43, 43, 1, 193032, dd8e2b350d8181c6a73832c868ea99f4 +0, 44, 44, 1, 192444, 6844e2dc435f417028644d3314b94c4f +0, 45, 45, 1, 191824, fc01e22ba45bca6eac69ba76043e1484 +0, 46, 46, 1, 191772, 5e2bedda3828d590d25caa14f96ba7b0 +0, 47, 47, 1, 191720, edaae522f8a975bbef0e909ef09e7fc7 +0, 48, 48, 1, 191528, f2d98179f5cf0752ecbd6d39c4457283 +0, 49, 49, 1, 190692, 74cd0f762371781712e2ff2e3f60ac57 diff --git a/tests/ref/fate/utvideoenc_rgb_none b/tests/ref/fate/utvideoenc_rgb_none index 403c807a4a7cf..27df8badca105 100644 --- a/tests/ref/fate/utvideoenc_rgb_none +++ b/tests/ref/fate/utvideoenc_rgb_none @@ -8,53 +8,53 @@ #dimensions 0: 352x288 #sar 0: 0/1 #stream#, dts, pts, duration, size, hash -0, 0, 0, 1, 301024, 44de62472f485410819707c44b53f276 -0, 1, 1, 1, 301036, ff3c28c23b15834a84c57b304610924f -0, 2, 2, 1, 300812, 72f02a697464f5fdd54ae2e054c131d1 -0, 3, 3, 1, 300876, 8879becf8b3d5001b196f45b7817ef6b -0, 4, 4, 1, 300880, 2edeed55c4d84dea1fc9386553d7503f -0, 5, 5, 1, 300904, f799f26eae30e1796bd62f9cdbcb2b17 -0, 6, 6, 1, 300908, bc606ee3ab284d3567a3fbd476d674f0 -0, 7, 7, 1, 301012, 404f55be9ec860a1ab3d15711965c9ba -0, 8, 8, 1, 301048, 112394db28656101b4e8ba3621b437ae -0, 9, 9, 1, 301008, 8945bb7668b4a529844e68e1f6b6522b -0, 10, 10, 1, 300908, a9097c5f0bd7ddea711a25aa74696f70 -0, 11, 11, 1, 300876, 579de317d166295088530c78f403611d -0, 12, 12, 1, 301012, d97e3627c494012d6167a30ec8192360 -0, 13, 13, 1, 300928, fd20066b7f31363751328aefedfae04c -0, 14, 14, 1, 300836, d9bdd5606f4426b503f19a674e8058a3 -0, 15, 15, 1, 300848, 6c8f2cbd75646592876f8138a017c1ce -0, 16, 16, 1, 300988, 54e19940011b3bfed809a0edc12c3dd7 -0, 17, 17, 1, 301040, b1d5f39215f305953a846fb01dbc2f24 -0, 18, 18, 1, 301164, 9dde74f0ee3626eeea41c538fd80e1fb -0, 19, 19, 1, 301196, fdf22d2c35c7ab72416a268bf6612650 -0, 20, 20, 1, 301148, 275261bc1c1dec0bf712dcf05213def2 -0, 21, 21, 1, 301144, 66ccea6fce9d6d7016dafb3b349fa163 -0, 22, 22, 1, 301080, d6dc6ce0708dfdf74e936271a98c19e9 -0, 23, 23, 1, 301028, 48e610b9d798e0642825919fab233524 -0, 24, 24, 1, 301100, aed8f8f0a9d96ab9906ea8175e18c9ff -0, 25, 25, 1, 301116, fe9e1eccb9ccc92b4041228ea2c56c8e -0, 26, 26, 1, 301052, 3ec2f76b41fd8a6eafaa6bb14b94c153 -0, 27, 27, 1, 301200, 60d608bbe0ca285a7d8a1a4822a84c4d -0, 28, 28, 1, 301120, 6d2cec50ee32e76eb6dff76a4976d221 -0, 29, 29, 1, 301188, 8faa69fd62e0646e4eb85c1601827364 -0, 30, 30, 1, 301192, eb1fa109c5e9b89f29be7cf363649acd -0, 31, 31, 1, 301128, 32ba1797f5dee6643712688621984326 -0, 32, 32, 1, 301088, a1bfa70314c40f60a0823beef74e233e -0, 33, 33, 1, 301064, b18d84efa0091199dd9167bbdb36b873 -0, 34, 34, 1, 300964, a2ae8d3dd655403bcfdace40aaa1d78b -0, 35, 35, 1, 301124, 8ece60df0f0ef4f3d887eac16c23cad6 -0, 36, 36, 1, 301200, 13eb4b5ec7471837aadce38848e48cb2 -0, 37, 37, 1, 301196, b5fdef211755134f8e7998793a0ab0c0 -0, 38, 38, 1, 301260, 2f7e2046bae9e664e74bc56a3596743c -0, 39, 39, 1, 301264, 2cfc013c9e66a5dd0229c6551febd658 -0, 40, 40, 1, 301272, 47e8ff02a8f054c66687e2b613e46cf5 -0, 41, 41, 1, 301236, f4d766155eeeb7b03687a3141840bf32 -0, 42, 42, 1, 301312, 8fe134aefc02b6910dc2054447fd9c37 -0, 43, 43, 1, 301272, 9ec57db275fca2b596734c48a50c28bc -0, 44, 44, 1, 301256, 17bae207d8d6f5b2b500885e3058185f -0, 45, 45, 1, 301308, 9f8e91f3fbbdd0ca17b2ad0ffe888d5a -0, 46, 46, 1, 301400, 8184e55eb5432516547df512175c15fc -0, 47, 47, 1, 301408, dd0c0aa1426427549e9cbb22ef82f930 -0, 48, 48, 1, 301424, c65025dc3fa21fad98118ab0386b910e -0, 49, 49, 1, 301408, 2982b49e94aa25b8ef30f81769650f15 +0, 0, 0, 1, 303768, c37d23b5bc1dcceacafcebd0a5054590 +0, 1, 1, 1, 303764, a6a8b445323c00ab56ad1077a90b34bf +0, 2, 2, 1, 303672, 029048769e006f2a2357f373cfc0b6bf +0, 3, 3, 1, 303672, e13433d7e8f75a26eeca86523d47d0cf +0, 4, 4, 1, 303724, 4c3d437c158255e398071bdd2e699d9e +0, 5, 5, 1, 303672, 11e335df4fdfcfb7563305a33740058e +0, 6, 6, 1, 303676, 594a7a6101fbf884bb3bc309479bdf18 +0, 7, 7, 1, 303764, 09f91a05f8f507f6338d15591df34002 +0, 8, 8, 1, 303772, 1e177889c188fdd783815103c1987e5e +0, 9, 9, 1, 303700, f6da8873c69fb6365764327305a36840 +0, 10, 10, 1, 303684, 6810c80719058078b7d40a787fabee70 +0, 11, 11, 1, 303696, f8dcad694c276074f5022276e4067694 +0, 12, 12, 1, 303720, d1f764aaf14e78b64b182503342df764 +0, 13, 13, 1, 303676, 43066ddba20726f57d76230891f76730 +0, 14, 14, 1, 303548, 6512bff050521cd6343e5b2f4b18be6c +0, 15, 15, 1, 303604, 76c91368e8db8c18591c7cb569774e12 +0, 16, 16, 1, 303748, 365805842ee3cefee8d5feb169075ecf +0, 17, 17, 1, 303740, e6bbc34d7057d812cd994473b93ccadb +0, 18, 18, 1, 303788, 48bcbbc3bf805586c34ff23ebeaa28ea +0, 19, 19, 1, 303808, 29f268867c4522551e6f73dd4afb36e1 +0, 20, 20, 1, 303808, effd1cf0a61501f427e47c76c469ff32 +0, 21, 21, 1, 303832, 0ea84576612a4b0b8f9e14b3ecf10861 +0, 22, 22, 1, 303800, 4b4d24ce4f176de4c34ec85656ea1e49 +0, 23, 23, 1, 303716, 58845ad1c9a07d62f83414662eaf1181 +0, 24, 24, 1, 303780, 8db647c5324b3c061aa2cdae7527ec8d +0, 25, 25, 1, 303824, 7a2ddbe9d1af3d34d7538ba10a0aae3c +0, 26, 26, 1, 303796, a8444e8ec7b64c3481766ebcafd2e7b7 +0, 27, 27, 1, 303816, bf78e04e04429aab3527baacd51da1b0 +0, 28, 28, 1, 303872, 02d9693cc78af1b9d4a17b5361daa325 +0, 29, 29, 1, 303900, 065cde35c0ac49675a9ee8e047bb1471 +0, 30, 30, 1, 303876, 0888dd5201864a9f34f784b7959563ba +0, 31, 31, 1, 303828, 6837a1a3f4ae04c9601fa9f4c27098b2 +0, 32, 32, 1, 303720, 8c90fc8481d745b020c325134bf0047d +0, 33, 33, 1, 303704, d37bd88a42e4b84a98f0e51208a3877d +0, 34, 34, 1, 303640, 2444c069427bf6a847113fd16e7a863f +0, 35, 35, 1, 303780, 7a9aa1d7d43bcb22a754fa5e7ee911a0 +0, 36, 36, 1, 303828, 4a0ab1bbea88697950bbafe566a03b52 +0, 37, 37, 1, 303860, 6d2073d28e226286e1e78df92bc27154 +0, 38, 38, 1, 303884, 74c43f24d636de3fd6afd1d0ab098e57 +0, 39, 39, 1, 303876, 329a1d1558ffc42b7cdb1f141e042431 +0, 40, 40, 1, 303912, 6b1f3c35f28ab1182354b33ea9e37331 +0, 41, 41, 1, 303856, ec00db5b019a3f72c3fc934d3811cad7 +0, 42, 42, 1, 303880, 6d291f829145c07f0002631b0e22a1f9 +0, 43, 43, 1, 303856, c438ae4db7f897c9e2a1bc6526bb43e1 +0, 44, 44, 1, 303828, d9e5870cf4598577e4ba0ac468ef25db +0, 45, 45, 1, 303936, 6c90dbca317295010024cc4ec70d3f87 +0, 46, 46, 1, 303940, 025d9173ff307f89c3edf43074a261e9 +0, 47, 47, 1, 303948, 48e7ab65fb9c7a35e4933a7658935726 +0, 48, 48, 1, 303944, 925eb3c42b865d0861ae0348136fc18c +0, 49, 49, 1, 303924, 83ae105d9d301ea900f004d274adf894 diff --git a/tests/ref/fate/utvideoenc_rgba_left b/tests/ref/fate/utvideoenc_rgba_left index eb3305d61a57f..11bde1e63f9c9 100644 --- a/tests/ref/fate/utvideoenc_rgba_left +++ b/tests/ref/fate/utvideoenc_rgba_left @@ -8,53 +8,53 @@ #dimensions 0: 352x288 #sar 0: 0/1 #stream#, dts, pts, duration, size, hash -0, 0, 0, 1, 195260, a8fdb226460f210542e7aca6c12b0874 -0, 1, 1, 1, 195268, 45f098764ccba85dc641b7e401461c0a -0, 2, 2, 1, 195888, e922261672c7de46a302abad3a3fe450 -0, 3, 3, 1, 195316, f8febd5af0fed000fab2943cc649975f -0, 4, 4, 1, 194636, d90985ad8afd2f969afa842510085852 -0, 5, 5, 1, 195068, 909adb44bd049186a959f2803e641520 -0, 6, 6, 1, 194484, 547772233e653daccc6610fcb6369da7 -0, 7, 7, 1, 195224, aa82b75f6230b2e948abdfe36bce1150 -0, 8, 8, 1, 194356, d67fb1208532137252701ddcbf7bfc2e -0, 9, 9, 1, 195248, 7b08698d2a911fba5231c0fef0ded4c2 -0, 10, 10, 1, 194996, 570e7d9caec52975dec1c2a5dbf7cdef -0, 11, 11, 1, 195528, 7309c0531b942902c691781f2a6da1a1 -0, 12, 12, 1, 193832, 40954ceb87370cac3db5c8c2d7c001d1 -0, 13, 13, 1, 194852, 538382c377f0c6e9070ec0b8c5fb3e39 -0, 14, 14, 1, 195756, d002a80346f3460380abb794f2d56a62 -0, 15, 15, 1, 195384, 1a4f58b3c710f2fedaf746c281556b4c -0, 16, 16, 1, 195244, 218832dab1251e1dc852e6839a48b3fc -0, 17, 17, 1, 194788, a035acf428bd9565a4c3fec25dfc6f4f -0, 18, 18, 1, 194040, 6dbfeb949bdeeb055a4f7ebf78af9a85 -0, 19, 19, 1, 194320, 8b4aa3f6f05aa684d9e4adfa4cdce814 -0, 20, 20, 1, 193868, 98cd8b150784f6695f8dea163cecf286 -0, 21, 21, 1, 193832, 27a8db33014c4bc6a8da356c4b1a3e4f -0, 22, 22, 1, 194868, f1e1460dca9127197c0a40e659924616 -0, 23, 23, 1, 195236, a012f8548e92243334edcd7c8f57aa52 -0, 24, 24, 1, 195512, bf3d4e968d126231baa6618d3344ef81 -0, 25, 25, 1, 195504, adf4b49d8721f1b323fa518f2f0d4750 -0, 26, 26, 1, 195288, aa16dd087a73a9cadc5abfc0a46ccdd4 -0, 27, 27, 1, 194464, 2e3f07244999cbe949495b57adcabe69 -0, 28, 28, 1, 192512, 2d6ce0d29a929e0208e1578e95c9d388 -0, 29, 29, 1, 192460, 081d18cd138eead0cd4b25f54a7c7540 -0, 30, 30, 1, 193692, 546b6ad28b612c2f601c7d87b265ba95 -0, 31, 31, 1, 194496, b2b2ae3b1d67e332295456e6c7bdd381 -0, 32, 32, 1, 194360, 0837b122d85abc4d704d40629266c58d -0, 33, 33, 1, 195912, b7a4bbe436d63394cee70d40e8a8a4cf -0, 34, 34, 1, 195556, 1b9a3eb6cda9bbd44bbdd0dc26a74252 -0, 35, 35, 1, 195284, f28d780d43fa6979379dd21fcb12e906 -0, 36, 36, 1, 194268, 5508989dad06fa05ee4054e759cdfd4b -0, 37, 37, 1, 194460, cb65a0e97c03b2fbe69caa6ac1660070 -0, 38, 38, 1, 192708, 4125ee86cf4b8ca6d891c176662e584f -0, 39, 39, 1, 193032, 096ee24b3e35049480e28171693fbd85 -0, 40, 40, 1, 193160, c01aef63b8bc792d08355ce6d68affee -0, 41, 41, 1, 193524, 57af47b7bfe132cf58eab2807996b3fe -0, 42, 42, 1, 194120, 9a4e2d72f4526815b253b3acce2dd49c -0, 43, 43, 1, 194232, e575508ffbd2a53871e817cd8947e2d2 -0, 44, 44, 1, 193744, 95d8eefbfbf5a7354ecbf35835243e44 -0, 45, 45, 1, 191748, de2eedebb28491e59700300635af1f90 -0, 46, 46, 1, 191128, 652670f6881419be5068f2de6ac2d91e -0, 47, 47, 1, 191704, 070f46dc278230528aa6b40256a6d891 -0, 48, 48, 1, 191584, e4b76fcf344e125729c339e360a14b15 -0, 49, 49, 1, 191444, 6a33b374a8b48549094a24543d81d999 +0, 0, 0, 1, 210764, 7c17cd8382580fcfd6dac1ddaa644c8d +0, 1, 1, 1, 210772, 4c6bcde52e58d800927620df9e0e03b8 +0, 2, 2, 1, 211564, c0754e5c821ae0c0ca0bae78ad8fe1aa +0, 3, 3, 1, 210032, 6ea988397d00f553c6e5ddbca7a08af9 +0, 4, 4, 1, 209168, c2d1fcee61bfdb5e3925aca342550ae5 +0, 5, 5, 1, 210284, dc92cc07ac1211e664a24c701c410e0e +0, 6, 6, 1, 210184, 0977e253355bff82f0efd330e94cec6c +0, 7, 7, 1, 210136, d81c28cfef7dd47abf2ac951b6a948e7 +0, 8, 8, 1, 210016, d378efd0efe103407afa8b8f45d17e24 +0, 9, 9, 1, 210624, 1a7e4a4c7b4ccbd10b9238b22dbc953b +0, 10, 10, 1, 210388, 607fdb29b0bf5846cbbb776459840401 +0, 11, 11, 1, 209956, c4c4c18b83db1983b1d9268024027025 +0, 12, 12, 1, 208064, f1a73d7fe1dfdeb33758c9d7c61fa81b +0, 13, 13, 1, 209728, ce7b81e19d940ebddeef93e281fed00d +0, 14, 14, 1, 211640, 0d6929d8d034f8accd00f58b887073f5 +0, 15, 15, 1, 210932, b895f81c00f959868e24944ee816e0df +0, 16, 16, 1, 210500, c43494420a45bb8fb0a907d3169d30b7 +0, 17, 17, 1, 210328, 5e4d72389e2733d8ce274f0c9a7cf7aa +0, 18, 18, 1, 209612, 59d368acc1ea2c0f28ed0787fe5bad4a +0, 19, 19, 1, 209716, 77a331effc0bb544ef1445fd5c42cfe2 +0, 20, 20, 1, 208912, 1de694210d8e781ce8ea29add190ad06 +0, 21, 21, 1, 209052, b48927d6e1658b5df335c34bf0fc0dc9 +0, 22, 22, 1, 209552, 1c00ad79bcf1efdb633baa040f5e1400 +0, 23, 23, 1, 210460, 755c6daf2681ba0aed4e4c962faa288c +0, 24, 24, 1, 211136, e6a5687e05a70fc7c741f2ef7afb93b9 +0, 25, 25, 1, 210444, 6fe3ec5657f092b009a7bcc4815fc5b3 +0, 26, 26, 1, 209764, 19bc9792b30711fb7276a9f74d423c3e +0, 27, 27, 1, 209328, 0144894411a4c5f14c66a393a46bb3b4 +0, 28, 28, 1, 207152, 61bbd2676caf8fbe6582274fe8add09d +0, 29, 29, 1, 207360, 9663a6d131b029c9ad7469d67a381823 +0, 30, 30, 1, 208608, a0908484dfeead74fb351bb1ba3b514a +0, 31, 31, 1, 209284, 00dda733e216eb968cfdf97f6138294d +0, 32, 32, 1, 209400, 7f7e4d3546ab89ba5eaed835a2fabf64 +0, 33, 33, 1, 211120, 3b281fadbc1eed3b4d0e6b14deb4a18f +0, 34, 34, 1, 210488, f3fb93f6504ffee9984574a7b6854d89 +0, 35, 35, 1, 209952, 1ccf5aa118c8cd51e099749289fdc374 +0, 36, 36, 1, 209140, 4e4c0f0a38608f1ff760a7ada9d44a6f +0, 37, 37, 1, 209380, dac76683c0ce9e1008fe1490dc1479bf +0, 38, 38, 1, 207004, e914b5454210fc6b4c39d22b7daf16da +0, 39, 39, 1, 206968, 0a9566c879a6897536ec094100f32fbf +0, 40, 40, 1, 207368, a644c2b3b8c89ec01b2b51576a5b09b5 +0, 41, 41, 1, 208628, 2ce6ca69d5f6e29641f5a907ffac9bb0 +0, 42, 42, 1, 208976, d3be7fe389e80df517eafd0c861947a2 +0, 43, 43, 1, 209316, c5148e0073cebd50d8f619d4875874dd +0, 44, 44, 1, 208356, 54e0082cdc1aa7fcbb8c655e94fbd410 +0, 45, 45, 1, 206620, 77ec6d3714a0dcbf0cdd5349df0951fc +0, 46, 46, 1, 205932, 7857acd2afd3169126a5428ddef97abd +0, 47, 47, 1, 206524, c903ec677106ec1f7f583bb813a1120a +0, 48, 48, 1, 206444, ea549da62a460b50811cb3f182fe5c19 +0, 49, 49, 1, 205460, 81d823633491b13a31dfdbc5f33d79f4 diff --git a/tests/ref/fate/utvideoenc_rgba_median b/tests/ref/fate/utvideoenc_rgba_median index 0cdab8d41af17..a2118c276f3d3 100644 --- a/tests/ref/fate/utvideoenc_rgba_median +++ b/tests/ref/fate/utvideoenc_rgba_median @@ -8,53 +8,53 @@ #dimensions 0: 352x288 #sar 0: 0/1 #stream#, dts, pts, duration, size, hash -0, 0, 0, 1, 195092, d32d5a3dc88b9aef0826b565ee5dfbc6 -0, 1, 1, 1, 195036, ea13e3522d1f3aeddd47117c91eccc55 -0, 2, 2, 1, 196040, 21c2c9abe791bed2a9bf02e539caa787 -0, 3, 3, 1, 195252, 58d5e081127f246f711f5b8ee1c760ff -0, 4, 4, 1, 194852, 8ceb3824ec628a73e1c08e498f369484 -0, 5, 5, 1, 195356, 30ea64094f29d670e2ff8f43b50578d6 -0, 6, 6, 1, 195180, 08b406b9f3063a54681d7195fb53e953 -0, 7, 7, 1, 194808, e28c43ef3aef174f0f9b9d7a702ca747 -0, 8, 8, 1, 195036, 66247b40b0def9373bf6fdda9ef832f7 -0, 9, 9, 1, 195472, efa8a624d6b0fa69e0c1c746baed0b33 -0, 10, 10, 1, 195052, fdfc784aed661cb76bc5b3ef1863bd89 -0, 11, 11, 1, 195068, 040ad503d18a36d4f1cdaec64998138a -0, 12, 12, 1, 194228, 1cd168427d022825a801b232cb23ca12 -0, 13, 13, 1, 195068, e4082f833d3bf75af24e1bb5f06d94fe -0, 14, 14, 1, 195344, 19638340e93d4f1f7099deda34d28e3f -0, 15, 15, 1, 195664, 001a801c5c5ceb197576c0f7b793850d -0, 16, 16, 1, 194876, 9550b3cf6133997bf7557483f346b036 -0, 17, 17, 1, 195164, eb7220caf48ab2605ec971ca1297a7ae -0, 18, 18, 1, 194444, a2ac812e6307a92ecd09d4282367a9d4 -0, 19, 19, 1, 194356, ee4d250226ab2a34cef0e3ed8920f7b2 -0, 20, 20, 1, 193696, 4bff0fc871969d17ad1f7391bbd543b2 -0, 21, 21, 1, 194004, 080e2a91fe768fd1725a8400bc6a1331 -0, 22, 22, 1, 194092, 5b9d65275695372e1f6b9c0a23f1ffa0 -0, 23, 23, 1, 195088, a4060bf595c877476a5952b335526d57 -0, 24, 24, 1, 195192, 17b55735834f291ecae399c317007d2c -0, 25, 25, 1, 194908, fc78d797bd5740f4fec8f3d34bc2ff1b -0, 26, 26, 1, 194764, d229a9e4d1c782504cad617d2b00802b -0, 27, 27, 1, 194356, f987a587cb9fdcd04e36d9382c4d9139 -0, 28, 28, 1, 193564, bdfa512e3a0a46aabf289c22dbaee0b9 -0, 29, 29, 1, 193556, 341708f3181ba4b37114d6dbffc65e63 -0, 30, 30, 1, 193956, f97693469ae6f49c3995794d00430c4a -0, 31, 31, 1, 194776, 970c96fe0f733683ce4f2b478af21b88 -0, 32, 32, 1, 194644, 8a96248e2821040e4d0d6d32d0a4f1a9 -0, 33, 33, 1, 194940, 70a462d8de0da8b5718bf8fb8034fa38 -0, 34, 34, 1, 194732, 2fb3437abbc0a85b6c46e1b1edd922c9 -0, 35, 35, 1, 194772, 0a0f54e266438e1a840247e1af2fb1f1 -0, 36, 36, 1, 194780, c4d516a459523b1c150d8aad1d5e3a6d -0, 37, 37, 1, 194908, e09db67196513400dd55397a525b73c2 -0, 38, 38, 1, 194148, f3cc9fc8597f8806fbc2a0c13af5b9ba -0, 39, 39, 1, 194168, 2bb82f80c239984fe7c1091ab6afb332 -0, 40, 40, 1, 193604, 6fd128240c540a0655e8f27ff6a50ee9 -0, 41, 41, 1, 194256, 9b49275154b4538abdebbddffe010105 -0, 42, 42, 1, 193912, 6acff798f9cca91347e36ee1ea86183c -0, 43, 43, 1, 194136, f24ca78d9b813ab8bfc720bad2682e7b -0, 44, 44, 1, 193652, d7d927faf59a3b82bd1cce418c13c430 -0, 45, 45, 1, 192960, 8a813fce1d21dd4ad474d06d890a3de5 -0, 46, 46, 1, 192636, 6bbe157ec4f799cfd47a69c5a5cbb0fc -0, 47, 47, 1, 192580, 1c17bf08a3928533a0036bda1fb08ecb -0, 48, 48, 1, 192356, a5b34ac48c82e79ff827f72dddbfc6b0 -0, 49, 49, 1, 191912, afceb467ddffd9697c9566c43f2576f9 +0, 0, 0, 1, 207164, 91bd0a04c522e4a449a2b2729cceb273 +0, 1, 1, 1, 207188, 8a9a23c32503fe30df47a598d319591e +0, 2, 2, 1, 207980, fac02289d860c485b09053119a259772 +0, 3, 3, 1, 206944, bc0251f0a3ad5881cb402d1d071cbfe8 +0, 4, 4, 1, 206200, e3b811ea58b790b171b75c9af46a3637 +0, 5, 5, 1, 207100, 076ca542190996d4ff4380bfff1b8707 +0, 6, 6, 1, 207172, 87d8540012df5c62ffcec97ac4255e44 +0, 7, 7, 1, 206444, 8a4a787dd73b93653ab69622b3fcaa6d +0, 8, 8, 1, 206884, e4ce5916ecee62387a44257f9f7e309f +0, 9, 9, 1, 207632, 67f343e24f47b1eddb47e59831752aab +0, 10, 10, 1, 206916, 6a1d003a2b3c10bd87d5b71a0ecb6fae +0, 11, 11, 1, 206572, 8939adde46e92bf02be301590de578ae +0, 12, 12, 1, 205832, ac36ce0cc201b89aa85aea9f8f85b654 +0, 13, 13, 1, 206712, 1d85faa22ef18e060354d2e2931f78f3 +0, 14, 14, 1, 207496, 2459b868050730ba3c3152443f119e59 +0, 15, 15, 1, 207788, 27616d7494e570814378a35fd72b3d4a +0, 16, 16, 1, 206988, 4f0daddba744ae0ebeea8b55ebc6778b +0, 17, 17, 1, 207056, e2340667064a25a75f67e261fe96baf7 +0, 18, 18, 1, 206440, d487795c5f4a3f338cebfd36b264a760 +0, 19, 19, 1, 206344, 0cd1a4c459402e82d7c89a131d6f75fe +0, 20, 20, 1, 205404, 52ea62992efacc4bf4234507752cd4ed +0, 21, 21, 1, 205776, 7712e82b94fd155c1e0dfec1db19a298 +0, 22, 22, 1, 205600, ec081ebb4e12f35aa47e673c5cd8c858 +0, 23, 23, 1, 207040, 637d7b20ab169db4671d76abc986c20d +0, 24, 24, 1, 207484, a776de1269ad564e1dc21ead94dcc71e +0, 25, 25, 1, 206792, 6aaa68388fb12b2e70eb542819902a97 +0, 26, 26, 1, 206384, b4c4d079d7c75b03e2d3915a8676a64d +0, 27, 27, 1, 206296, 521647a00535f63c241b54699b5d803a +0, 28, 28, 1, 204996, 892f0c216d04dfa120576c0cbbbdb0a2 +0, 29, 29, 1, 205396, fa1b2301c765bb1ca1c85828918462b9 +0, 30, 30, 1, 205812, e40d8da60a07f19b43ab27a13928b87d +0, 31, 31, 1, 206604, 2a06b115a3a400a73ad06b69c90a0768 +0, 32, 32, 1, 206568, e6d367cc3d7bd17a6c470fe86591e56d +0, 33, 33, 1, 206908, 8d53fe57b1043562c50a2fd63fa2ebfa +0, 34, 34, 1, 206388, 3a5544a0a814dbba171d0384c91ea566 +0, 35, 35, 1, 206700, bfe43124bcbbaef9884893c32396f316 +0, 36, 36, 1, 206516, a93e303f30a9269c6d6b59882b668630 +0, 37, 37, 1, 206776, 3044d9c98555d3415fc75b085f8aab0a +0, 38, 38, 1, 205940, 870403f6326de73750a57692a288bc2d +0, 39, 39, 1, 205612, f97b94da7b565f67cb476c73c2196bb1 +0, 40, 40, 1, 205120, 78341e169158f97791ec9a88ee936048 +0, 41, 41, 1, 206132, 83d31e0b40f2850b0767fbd162b4aabd +0, 42, 42, 1, 205984, ba029595b56087c55f324a54cb5e20a6 +0, 43, 43, 1, 205964, d067932b507acda9020837ed271eb09e +0, 44, 44, 1, 205376, 62b45f4949405875f947cd6d5133b76d +0, 45, 45, 1, 204756, ec45bcef0601faff97d89f89bfede4f3 +0, 46, 46, 1, 204704, 59c9d309aa381e39f3b236d332ae516a +0, 47, 47, 1, 204652, c44f8fba96dfb305cdc797ddfa033899 +0, 48, 48, 1, 204460, d0116d06128babcf8ec55205ce89d46a +0, 49, 49, 1, 203624, bbd3523ac263c622541aa67825601fd2 diff --git a/tests/ref/fate/utvideoenc_rgba_none b/tests/ref/fate/utvideoenc_rgba_none index 65f07289d117d..f388c9101d91a 100644 --- a/tests/ref/fate/utvideoenc_rgba_none +++ b/tests/ref/fate/utvideoenc_rgba_none @@ -8,53 +8,53 @@ #dimensions 0: 352x288 #sar 0: 0/1 #stream#, dts, pts, duration, size, hash -0, 0, 0, 1, 301284, 55e84c6e1f41e48f47dcefb63e3c1efd -0, 1, 1, 1, 301296, 12dab23dfd2c2d5b48bed2292b876688 -0, 2, 2, 1, 301072, cc2e2889403dcc5d8e36868f07918b9d -0, 3, 3, 1, 301136, 9813d60e613a3a14e639f9af0a5b1fe7 -0, 4, 4, 1, 301140, 58554bb6749e8bbd9476335ac1cb0076 -0, 5, 5, 1, 301164, 37a249286019761a4a3e498e977f9da1 -0, 6, 6, 1, 301168, f3aa11b419ec6f683ad906e7f7a36342 -0, 7, 7, 1, 301272, f489654640f0e42225815ea9c9681201 -0, 8, 8, 1, 301308, f10eb3c1d0324b59bd25c8bc6556aca0 -0, 9, 9, 1, 301268, 2163aa992afef5210d677953d81adb17 -0, 10, 10, 1, 301168, 684d19d14212615ebffa1748a9c552ed -0, 11, 11, 1, 301136, a5c47c30d12dbc679ce932a5988b32e5 -0, 12, 12, 1, 301272, 3a51dc37d7e5ecb4a8db948eade2e0fa -0, 13, 13, 1, 301188, f9f9ed41c233e791e6cd75a34e52edf8 -0, 14, 14, 1, 301096, 63bbfbee6f0fa6745e143dfae40ce7ff -0, 15, 15, 1, 301108, 1fb3340dd1804d27fb40aea6b073e9ce -0, 16, 16, 1, 301248, 476d27f29da8e74db696ff38e81743fc -0, 17, 17, 1, 301300, 84a7f5804a856b7ef640838320634568 -0, 18, 18, 1, 301424, f34006fb55745aac29e265e0362434bf -0, 19, 19, 1, 301456, d9207e54e261d184ddd02f3706e63103 -0, 20, 20, 1, 301408, 89b5a6804bad85025a6a3d23dc539426 -0, 21, 21, 1, 301404, 5987d22d6e3bf18cd2ebea98a1915f57 -0, 22, 22, 1, 301340, 43ff13bb237a7899ecb04fa7d27e94ab -0, 23, 23, 1, 301288, 01b3e148ed6b8a0d05ee628fb21fa4a5 -0, 24, 24, 1, 301360, aa7704007e3c437cfcad4fb83a69594a -0, 25, 25, 1, 301376, 4dea983f0b4a012ba6875aa857d02e91 -0, 26, 26, 1, 301312, e263f1cb0fb19b50751e9a214a4c9d81 -0, 27, 27, 1, 301460, 85ad441664c99c591d6dc427910faa19 -0, 28, 28, 1, 301380, 86ffe8273011763d800dbf6c89942a70 -0, 29, 29, 1, 301448, 500862ea62e1982325d653d4853dcbcd -0, 30, 30, 1, 301452, 91c4390a805e02d1924bd75946bc0b63 -0, 31, 31, 1, 301388, 4eb3040d65948355c4506ee8e8e041ca -0, 32, 32, 1, 301348, ece814a764470f1d80973743a7adaa4b -0, 33, 33, 1, 301324, 2ae0b9af5380c8f98087b90c646af813 -0, 34, 34, 1, 301224, d6a3ba0b543534bd7de9dd82107c468c -0, 35, 35, 1, 301384, 4f4919c1b2502c6e03ddaa83f4c03f15 -0, 36, 36, 1, 301460, b45189bc89e6583f4426c390622fa1fc -0, 37, 37, 1, 301456, db0c5e2bc705c825e554c2da54314746 -0, 38, 38, 1, 301520, 8d01037b2dcbba39d4746758fd53323c -0, 39, 39, 1, 301524, 0a78af44bf49520ae8830060e6011898 -0, 40, 40, 1, 301532, da9032ac97b76ec10f94d74ee878cf41 -0, 41, 41, 1, 301496, 9a22b2a9a3ad897406fc7c3137d41a3b -0, 42, 42, 1, 301572, a14a80ab416cf4a9a1ec24bfc72602a1 -0, 43, 43, 1, 301532, 71ea5a240540a2e08ced8ad78c1a0676 -0, 44, 44, 1, 301516, fffe101d036ed5afee9b6f86267c2a0c -0, 45, 45, 1, 301568, 58ea3a6edaee760d98eadb072fb30796 -0, 46, 46, 1, 301660, 9886e77f5df35d8bd164d598d0f87514 -0, 47, 47, 1, 301668, 1f326eb789974fc853e1db57115ef58b -0, 48, 48, 1, 301684, 08b2eb620b9a7be1bded4744cd4c88db -0, 49, 49, 1, 301668, bfcce1ce5f7c30230aae9a2d67fc8a70 +0, 0, 0, 1, 304028, e1687f63bd131ace3866b61881e8e9a1 +0, 1, 1, 1, 304024, 93067fdad1470b1c2f2fd4ae603a3afe +0, 2, 2, 1, 303932, 2fef08ce570f581373bd48b3a4773acb +0, 3, 3, 1, 303932, 8623d4635239deac16d56085edb8aec1 +0, 4, 4, 1, 303984, ef0a1be76f7c854e5f2724d7a6707f54 +0, 5, 5, 1, 303932, 0e57009f6e93c2e5ce80d6109d9a66f3 +0, 6, 6, 1, 303936, db988d8d6e9ee0383cfc69a201de62e2 +0, 7, 7, 1, 304024, 963e86c081fafed2f757c4aafc9186df +0, 8, 8, 1, 304032, e867c068706bff34a561a4b2c4622fd3 +0, 9, 9, 1, 303960, 0dd6d1cbe6a9fb07e3f3cb4a12c2821a +0, 10, 10, 1, 303944, 424612ce8850b378171ee8bfca5d91ce +0, 11, 11, 1, 303956, f26d5065818f98bbf97aae56fe07b057 +0, 12, 12, 1, 303980, dfd1a61b5a717805a06f19ee899c3917 +0, 13, 13, 1, 303936, 2223f98ac58078c49489811171c713e1 +0, 14, 14, 1, 303808, 6a63bd7cd4cafe5e64dc8dc46f9f3760 +0, 15, 15, 1, 303864, a355699c989795379d1ef2089c98e619 +0, 16, 16, 1, 304008, 07a0c41088846ed77fedc565cfeaeba7 +0, 17, 17, 1, 304000, dbb37a1af0bb534112aac9269b7d7c2c +0, 18, 18, 1, 304048, 3129997c9ba84a0c91ff9d1c48d12d7e +0, 19, 19, 1, 304068, 620b4c964daca105cd1b6bf8d55e86ae +0, 20, 20, 1, 304068, bafaf53530f76d525eafb75a3866b5e7 +0, 21, 21, 1, 304092, 678138b93f07ef8f30ad373499a9caa3 +0, 22, 22, 1, 304060, 4bf8174ff9ee62c13bde29ad5bba3fc9 +0, 23, 23, 1, 303976, e6e926057f49e69e2ea8e679871e449a +0, 24, 24, 1, 304040, f81ba4d36df7e8967a16e7de5c7a023b +0, 25, 25, 1, 304084, a5a63a22e6bc3a54bfbd60852ca9da60 +0, 26, 26, 1, 304056, df9bd50b9dd7437afb3671c99e2e1746 +0, 27, 27, 1, 304076, 785a2a7de44e83f1111e66165b3d0765 +0, 28, 28, 1, 304132, ab01bacd7aee91ab80b30a48f54ec4d7 +0, 29, 29, 1, 304160, 4893296140e7ee6f2d194bc279f928f3 +0, 30, 30, 1, 304136, 6046c7516a5e8db2f4dd3b1286ad46c0 +0, 31, 31, 1, 304088, e6dbc1ec86cb678bab6a1ca0e93888d0 +0, 32, 32, 1, 303980, 66db98674c107af297a3de01c047ebce +0, 33, 33, 1, 303964, e2ce0a2ee5ba8de50960873a8405c001 +0, 34, 34, 1, 303900, 7ae96a39e66e0abe63e298f45477c0ec +0, 35, 35, 1, 304040, d5fc8f7809470bc40935285d4ed69a80 +0, 36, 36, 1, 304088, efae0966a7e421c3107016df862b0429 +0, 37, 37, 1, 304120, c6a3bf8991bf2b559f27d5ea9ae76d08 +0, 38, 38, 1, 304144, 588ac89c403c5d3ca9289fbd339fdb74 +0, 39, 39, 1, 304136, a3824537484dd2fc25dde9ec2974068c +0, 40, 40, 1, 304172, e1a024aa9faba0ee0cb98e41cef254c9 +0, 41, 41, 1, 304116, c26c4c053d53b70c97cbf989cb51a15d +0, 42, 42, 1, 304140, 4d13ee2a3b32ba3f080fffa7ca2db6e6 +0, 43, 43, 1, 304116, fb02b57f9a9fafa7bc6d2a35a68548fc +0, 44, 44, 1, 304088, 6daa494c1ed11c9ea8da6c83eb473ce7 +0, 45, 45, 1, 304196, 8886953ff026efef28f4af12ce5239b6 +0, 46, 46, 1, 304200, 51ff2c8552b8b044a1a183330a188d62 +0, 47, 47, 1, 304208, 72fcd3dbf45284bb434ad3660f8a1ddf +0, 48, 48, 1, 304204, 1d5e2170963d70acea2ad01e1486d490 +0, 49, 49, 1, 304184, 6eec23c3d4402f7a0ab4de16fde86462 diff --git a/tests/ref/fate/utvideoenc_yuv444_left b/tests/ref/fate/utvideoenc_yuv444_left new file mode 100644 index 0000000000000..1b8d9257610be --- /dev/null +++ b/tests/ref/fate/utvideoenc_yuv444_left @@ -0,0 +1,60 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#extradata 0, 16, e46c7123194c0ebf19a23e5cefebaa63 +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: utvideo +#dimensions 0: 352x288 +#sar 0: 0/1 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 144080, 678b4a3ece35971c3e0f199fcab2b4a1 +0, 1, 1, 1, 144120, d0c326ed062b569a04ea84359e43cfde +0, 2, 2, 1, 144956, 32e2d8a1dc22b1d837e8f70509767d7d +0, 3, 3, 1, 143324, 6fff1691c498ccf1cf848147dcc1b62c +0, 4, 4, 1, 142464, df4caa8316ec987fe3cba4a76c0976f0 +0, 5, 5, 1, 144068, 2cc92f54850a45d76b8a959d62c28408 +0, 6, 6, 1, 143840, c80e0e9945a92869ca639b59118f24f3 +0, 7, 7, 1, 143536, 682a3148911f94daa333e12a505d689f +0, 8, 8, 1, 143736, af692d8d5fe2e23f9e16c7164ceaaeb5 +0, 9, 9, 1, 144076, 13412473483a727e8cced00d0d0fbb78 +0, 10, 10, 1, 144012, 4f1402c7d25ee222329cc007aa4df345 +0, 11, 11, 1, 143520, cc4b83f407d031cc4a166c3210583599 +0, 12, 12, 1, 141640, e4a4d1b88c7aabfcc40c51ff80305f70 +0, 13, 13, 1, 143096, b3de93652c190bc88dd6e17a27db4ebf +0, 14, 14, 1, 144704, 48ce5d6a84b965f38f5e4a46e8bfd0c3 +0, 15, 15, 1, 144520, 936970ae76c23e6a7880f2c875c1fb66 +0, 16, 16, 1, 143704, 32d9a3e4118e1134f3c0ead846805aaf +0, 17, 17, 1, 143648, 4214224b843fab53ae45921426de1892 +0, 18, 18, 1, 142920, 22b1c3a09f23fa262d7ffa2fb4347f3a +0, 19, 19, 1, 142604, d24c0ba247bb38bf7bdfc348d7c6fdf1 +0, 20, 20, 1, 141928, 8115cdd0fb51fa90821f93900c8cc980 +0, 21, 21, 1, 142072, f6d87afe383aa9a85b89832e422859e0 +0, 22, 22, 1, 142204, ced75258ae7001a8a4029423d61abf06 +0, 23, 23, 1, 143420, 686a5ded45cd70af9e699e9919da9cc7 +0, 24, 24, 1, 144552, 5a1e0f522e74a1284b86c5d0e185f16d +0, 25, 25, 1, 143328, f54e6787ac2f3ac0e925388b66c95b2a +0, 26, 26, 1, 142584, 652dda504ace9c4e1569319ef6cd333d +0, 27, 27, 1, 142084, 3eafb87f47844ce6d0572af051d2e25b +0, 28, 28, 1, 140196, 92b60cf33e5c430f3e92a39bb4389096 +0, 29, 29, 1, 140152, 658a331d3f5ee1bb50392f3835aed56d +0, 30, 30, 1, 141484, b54db7d5978d99f7192dd2008438ab41 +0, 31, 31, 1, 142360, ed84a9d2241ade4c36f95eaa1ae00b0e +0, 32, 32, 1, 142744, 7dbb99de3a4a81de5564bb577471128d +0, 33, 33, 1, 144360, bd26a71b0824a04badfffa0653f0ac00 +0, 34, 34, 1, 143464, 11fe56173423180d581bc52fe044657a +0, 35, 35, 1, 142856, 9f690fa8727669ba8640032933eb8235 +0, 36, 36, 1, 142108, b5c182f3f0e6d307f598dc55f51f9d51 +0, 37, 37, 1, 142492, ab7b6b446b4f5f5ec2b2eb52f934523c +0, 38, 38, 1, 140532, 3fda7e5443dcf59e52f523bcf863d5d2 +0, 39, 39, 1, 140288, 1426cb304a219876586ba5c161809fac +0, 40, 40, 1, 140540, 3a69f372875e2cd6ec5b49498e1f1a05 +0, 41, 41, 1, 141868, aca8f0bd1b29c4142b80e5e3e59aeb75 +0, 42, 42, 1, 141892, 91bf3847703041b4fbe87602e78fb577 +0, 43, 43, 1, 142080, f1b28c53e1068a6305ebb6d4862aebf1 +0, 44, 44, 1, 141220, 188ffeef2973b490364e8cf01fc2d8e6 +0, 45, 45, 1, 139908, 1eaa1194f719aa6da4c7ab4dddcee4ce +0, 46, 46, 1, 138868, 2243b5d473d6df2ea283752fe799c95b +0, 47, 47, 1, 139276, d74f2cbfac00177d848fb1b1e223e654 +0, 48, 48, 1, 139312, 27054be184a1028a86c5e3406418a92c +0, 49, 49, 1, 138132, feb653f902c92cfd1954b61b9d1149f2 diff --git a/tests/ref/fate/utvideoenc_yuv444_median b/tests/ref/fate/utvideoenc_yuv444_median new file mode 100644 index 0000000000000..f690a38089332 --- /dev/null +++ b/tests/ref/fate/utvideoenc_yuv444_median @@ -0,0 +1,60 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#extradata 0, 16, e46c7123194c0ebf19a23e5cefebaa63 +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: utvideo +#dimensions 0: 352x288 +#sar 0: 0/1 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 136492, 5e3cc78fe9e404b0eca7c2df98841eab +0, 1, 1, 1, 136336, cec7bad80feac6e16a3d84734ae473d8 +0, 2, 2, 1, 137296, cb43d766c513da815c5964f1f48c2e49 +0, 3, 3, 1, 136088, 4c8900602c580526057b52bb14161274 +0, 4, 4, 1, 135276, a9b134a0e49812ff929cdd57d8a00907 +0, 5, 5, 1, 136668, 0b9dc3cd51ce5c674315c06bd677fcea +0, 6, 6, 1, 136480, 16020ff181e477f1b01b86aa5070bf7c +0, 7, 7, 1, 135876, 557f1f43cdfc06603f3bd97bb9d44394 +0, 8, 8, 1, 136204, c03b7cd310961ef9fe8734f45a9276e2 +0, 9, 9, 1, 136796, b668c63bed0b2de4d182cf0281e71ecf +0, 10, 10, 1, 136252, 7758777682f6e3ea84010cbaf2645a6e +0, 11, 11, 1, 136284, 699e6ab66911cdd0fa357c069537e3ec +0, 12, 12, 1, 135096, 65d4d3b6e1bbf6d67baca1f346d06735 +0, 13, 13, 1, 136088, 7d69fb86f67b3fd3df4008cb03d9f1ef +0, 14, 14, 1, 136876, abca4a026bf93da58283d5ddd51cead4 +0, 15, 15, 1, 137096, f5bb254ede8a9ed4c07fb80fb1a301d7 +0, 16, 16, 1, 136232, cdbe70b4b7051b9c1092ea626e825658 +0, 17, 17, 1, 136308, acb31052249c48b729842938977172e8 +0, 18, 18, 1, 135444, bf38e56e2a152154b0401507550b5605 +0, 19, 19, 1, 135300, 1737341c361f656feffc86903da34647 +0, 20, 20, 1, 134548, c28e9c441544b7c51cf76afd4b5a2799 +0, 21, 21, 1, 134816, 5b8ba0d205863105d723afcc28274fb2 +0, 22, 22, 1, 134776, 90c5ac5ed83ed6a43b4fe14c0ee07dc5 +0, 23, 23, 1, 136332, 3ca065b60b4fbc5b04f68e6bb900d862 +0, 24, 24, 1, 136724, 283b23278ca40dc93a326e96e5c22629 +0, 25, 25, 1, 135948, 6568fb8593edce20f294a936ab11153b +0, 26, 26, 1, 135400, 22abaf0c3184a79cb90b4d7fe6cee897 +0, 27, 27, 1, 135056, abd6117e31af2d136c0df8ab1db64599 +0, 28, 28, 1, 133676, 67a65017fb2a232a726717628fbe1d95 +0, 29, 29, 1, 133700, 7dff3d958ecbedc691d3b188084d26d9 +0, 30, 30, 1, 134444, 192c98c1a7c2f4a15c7aa59607b7d1ff +0, 31, 31, 1, 135388, 32d1aba6d499162345fcb0ca858558d5 +0, 32, 32, 1, 135680, 77cd1f8ddf7ce977ba9ff074d595e033 +0, 33, 33, 1, 136404, 9eb0213f0d66d957f668f88d426f014f +0, 34, 34, 1, 135816, 337b4082181e8627f2fe9c852681688f +0, 35, 35, 1, 135616, c73c95e75669ce9dafd0ac253239430a +0, 36, 36, 1, 135136, e4e5515dbb05b855b4ce42fe1638d119 +0, 37, 37, 1, 135572, 987ffdc8d0c142e92dc02190f73afd70 +0, 38, 38, 1, 134748, 8a01538b863e51066f896f18ad8cc68b +0, 39, 39, 1, 134428, 3096e9435e5813d54013bf5c86e15c4f +0, 40, 40, 1, 133796, 78d3952c814172173b24881e110c861f +0, 41, 41, 1, 135052, b0c2bf0b1047dd71268d3c3114b655d8 +0, 42, 42, 1, 134768, 653862b7e519c299278186920217a303 +0, 43, 43, 1, 134692, 26fb91814efadd0120f247d6b5f22d81 +0, 44, 44, 1, 134164, e85390622cb7eb6618512ead58d578c6 +0, 45, 45, 1, 133380, 7c04e5015f89c24713227329aa1820fb +0, 46, 46, 1, 132872, 877db229c19c9719bd9b19d0dab1c169 +0, 47, 47, 1, 132864, c4a86326303f96d53cb267111ed199e5 +0, 48, 48, 1, 132644, 7dd3fe41c535d168eb0450d96171ec0f +0, 49, 49, 1, 131772, c430f15c1683207fbec250dc9d7a2b13 diff --git a/tests/ref/fate/utvideoenc_yuv444_none b/tests/ref/fate/utvideoenc_yuv444_none new file mode 100644 index 0000000000000..880b813769dfa --- /dev/null +++ b/tests/ref/fate/utvideoenc_yuv444_none @@ -0,0 +1,60 @@ +#format: frame checksums +#version: 2 +#hash: MD5 +#extradata 0, 16, e46c7123194c0ebf19a23e5cefebaa63 +#tb 0: 1/25 +#media_type 0: video +#codec_id 0: utvideo +#dimensions 0: 352x288 +#sar 0: 0/1 +#stream#, dts, pts, duration, size, hash +0, 0, 0, 1, 286288, f77b660b13f4ca2d906dbe620019224f +0, 1, 1, 1, 286388, 61c3e9c05be428c2adf312257580d528 +0, 2, 2, 1, 286148, cf2d8de31997ba6c9c87ca0203295ffd +0, 3, 3, 1, 286124, 981f9eeeed512af38eac7c5df0693b85 +0, 4, 4, 1, 286644, be9e95106ca59737b1154b865e917110 +0, 5, 5, 1, 286280, e70b66f13e4a08c10e1d014ac1be0cf9 +0, 6, 6, 1, 286176, b20a78e4bcd02d7fedc0f00af8276847 +0, 7, 7, 1, 286132, 80cc66c88ea015b62bbf46ae188eed95 +0, 8, 8, 1, 285968, 446ae00d0e1fc233b66ecb35c720464d +0, 9, 9, 1, 285888, 9d4b29bfd62e5cac2d77185e19706325 +0, 10, 10, 1, 285792, bc74548c1ed37dc1d6ca523e00b83ed7 +0, 11, 11, 1, 285412, f7234684c90e0dfcfd7ff9a7612b9cb9 +0, 12, 12, 1, 286080, 3873173b7da6113b058c0e50d1fb2ac9 +0, 13, 13, 1, 285524, 90654181491240e1883cfa8e9dcbc53a +0, 14, 14, 1, 285628, 5ae2de1a60c2586af4a27dca27e0d614 +0, 15, 15, 1, 285620, 9d78ee5f1390c05af2677bedf2b088e4 +0, 16, 16, 1, 285768, 7c47cbbba7af11ace3233c904e628242 +0, 17, 17, 1, 285880, 8292ea2eb80b860edf0747707eb99966 +0, 18, 18, 1, 285956, 17aef410ca3fec63ef83185401e005a3 +0, 19, 19, 1, 285992, 779819d6d090a67261ef3611f7b50ad6 +0, 20, 20, 1, 285920, 52fbe43f864350643cb4e8a57fcf8f63 +0, 21, 21, 1, 286040, c2e7919e6e20c7fcf78c0229e4d456d4 +0, 22, 22, 1, 285844, edc46036a229878d26a8df1f6dfbd661 +0, 23, 23, 1, 285868, 7e5a9af2d70dc57a7ca0a03f88a3a1a9 +0, 24, 24, 1, 286056, 174d2c8aca73cb5481e12a5a22516d02 +0, 25, 25, 1, 285836, cf1d28a88aa4fc2a5e16e03e2081919f +0, 26, 26, 1, 286004, 2ffd12c7501e4709939712a62945ec29 +0, 27, 27, 1, 286264, 61962127ef2a4612a9a352119b7444dd +0, 28, 28, 1, 286632, 9355ea7ef38424633b9e0b77ebb23d77 +0, 29, 29, 1, 286508, a741f67693b0154355966a1b07265939 +0, 30, 30, 1, 286124, 0fb2a3a0b6e525907b6d0c50ca8f7be1 +0, 31, 31, 1, 286308, 89fd53c38119426cdd63be714e857dac +0, 32, 32, 1, 286032, 674d9043981cce19c39e2c6d405d856a +0, 33, 33, 1, 285672, 7b9678e7772b71abf5a95fa967d319af +0, 34, 34, 1, 285520, 6e626d4c722ccafea6600a62c093a47a +0, 35, 35, 1, 285828, 49e9023d9c820798af6b445ec1d87b13 +0, 36, 36, 1, 286344, 6cf611f3ef47442659e3ce3807d3a480 +0, 37, 37, 1, 286360, a0eca88afed37e0747b1fa61c7e36713 +0, 38, 38, 1, 286264, 5b3e605f71b8bab3aa2cc3ed439c6f8a +0, 39, 39, 1, 286096, f9a1c5beca596e2b5eef2392b0adb01e +0, 40, 40, 1, 286284, eb2440f6539413efc86e5a0cd545ecd4 +0, 41, 41, 1, 285816, 520d3344f335b580bfb2fad58b1643b4 +0, 42, 42, 1, 285864, 48ed0d9ed707808298800c87f2d61d75 +0, 43, 43, 1, 286108, 9cb952285049f8354ab7e00c0ab2f7d5 +0, 44, 44, 1, 286308, 7ba07e4cc04cd42272ab75e1a65703ca +0, 45, 45, 1, 286552, 55722a7bc60c9eb68a94fd0e8ba3ba4f +0, 46, 46, 1, 286456, e3e54e031bcf3067360955817690a755 +0, 47, 47, 1, 286240, 96aa493b2b8d264ffb0d49c952594c11 +0, 48, 48, 1, 286128, 6e7e04eec86f257aa46c59f0e8b6b22c +0, 49, 49, 1, 286128, ab72c8a01a095040efb1d4cb1fddbd4a diff --git a/tests/ref/fate/vp8-alpha b/tests/ref/fate/vp8-alpha index 4922d527396dd..cc096c6d3a947 100644 --- a/tests/ref/fate/vp8-alpha +++ b/tests/ref/fate/vp8-alpha @@ -3,7 +3,7 @@ #codec_id 0: vp8 #dimensions 0: 320x213 #sar 0: 1/1 -0, 0, 0, 33, 2108, 0x59b92a34, S=2, 1900, 0x8fb3adc5, 8, 0x00000000 +0, 0, 0, 33, 2108, 0x59b92a34, S=2, 1900, 0x8fb3adc5, 12, 0x00000000 0, 32, 32, 33, 142, 0x2f2a3fed, F=0x0, S=1, 160, 0xa13346af 0, 65, 65, 33, 157, 0x17804767, F=0x0, S=1, 209, 0x64115f15 0, 99, 99, 33, 206, 0x537262ca, F=0x0, S=1, 317, 0x44a09dd0 diff --git a/tests/ref/lavf/ffm b/tests/ref/lavf/ffm deleted file mode 100644 index d9fa8d52cbcf5..0000000000000 --- a/tests/ref/lavf/ffm +++ /dev/null @@ -1,3 +0,0 @@ -ca2a450cd0d1e299514a345923b4c82a *./tests/data/lavf/lavf.ffm -376832 ./tests/data/lavf/lavf.ffm -./tests/data/lavf/lavf.ffm CRC=0x000e23ae diff --git a/tests/ref/lavf/mxf b/tests/ref/lavf/mxf index b9c37334a9735..7318447ecb793 100644 --- a/tests/ref/lavf/mxf +++ b/tests/ref/lavf/mxf @@ -1,9 +1,9 @@ -1c06a9d69b6e309579784db5ecb0b69f *./tests/data/lavf/lavf.mxf +d4140129463dec64bdb4a7d7ad1b0c82 *./tests/data/lavf/lavf.mxf 525369 ./tests/data/lavf/lavf.mxf ./tests/data/lavf/lavf.mxf CRC=0x8dddfaab -50b4f9ca0493e6d83f4c52dc3aa2b7a5 *./tests/data/lavf/lavf.mxf +a27bb8cd5e185ea13b0a8daa4eb221cd *./tests/data/lavf/lavf.mxf 560697 ./tests/data/lavf/lavf.mxf ./tests/data/lavf/lavf.mxf CRC=0xf21b1b48 -4b71b154ae37364c8028cb50850a54c5 *./tests/data/lavf/lavf.mxf +395bf0047c97ceca96935357166b94c7 *./tests/data/lavf/lavf.mxf 525369 ./tests/data/lavf/lavf.mxf ./tests/data/lavf/lavf.mxf CRC=0x8dddfaab diff --git a/tests/ref/lavf/mxf_d10 b/tests/ref/lavf/mxf_d10 index 134db876d5bc2..2384d427b024d 100644 --- a/tests/ref/lavf/mxf_d10 +++ b/tests/ref/lavf/mxf_d10 @@ -1,3 +1,3 @@ -73c0cb416548c33d0651c59519a8f7e2 *./tests/data/lavf/lavf.mxf_d10 +f4694941b0cd5b5e3c91064d84dbd345 *./tests/data/lavf/lavf.mxf_d10 5330989 ./tests/data/lavf/lavf.mxf_d10 ./tests/data/lavf/lavf.mxf_d10 CRC=0x6c74d488 diff --git a/tests/ref/lavf/mxf_dv25 b/tests/ref/lavf/mxf_dv25 index 85094828d15f7..e836b14240aef 100644 --- a/tests/ref/lavf/mxf_dv25 +++ b/tests/ref/lavf/mxf_dv25 @@ -1,3 +1,3 @@ -1871bd11947924116776201f24fd0adf *./tests/data/lavf/lavf.mxf_dv25 +1ca8143bf6cf322fd39f6e856959d502 *./tests/data/lavf/lavf.mxf_dv25 3833389 ./tests/data/lavf/lavf.mxf_dv25 ./tests/data/lavf/lavf.mxf_dv25 CRC=0xbdaf7f52 diff --git a/tests/ref/lavf/mxf_dvcpro50 b/tests/ref/lavf/mxf_dvcpro50 index 1d0cf79996196..bb3d6b928a812 100644 --- a/tests/ref/lavf/mxf_dvcpro50 +++ b/tests/ref/lavf/mxf_dvcpro50 @@ -1,3 +1,3 @@ -6c9cb62911ac16c3b55f0ad0b052c05b *./tests/data/lavf/lavf.mxf_dvcpro50 +987fd4b2abb36433fba0e35f4092efc6 *./tests/data/lavf/lavf.mxf_dvcpro50 7430189 ./tests/data/lavf/lavf.mxf_dvcpro50 ./tests/data/lavf/lavf.mxf_dvcpro50 CRC=0xe3bbe4b4 diff --git a/tests/ref/lavf/mxf_opatom b/tests/ref/lavf/mxf_opatom index ea1190c06ae51..1cc612e627517 100644 --- a/tests/ref/lavf/mxf_opatom +++ b/tests/ref/lavf/mxf_opatom @@ -1,3 +1,3 @@ -962c2cd582340f8961a8283636093abf *./tests/data/lavf/lavf.mxf_opatom +b8fe60f7457b83709f33357d04c8db0c *./tests/data/lavf/lavf.mxf_opatom 4717113 ./tests/data/lavf/lavf.mxf_opatom ./tests/data/lavf/lavf.mxf_opatom CRC=0xf55aa22a diff --git a/tests/ref/lavf/mxf_opatom_audio b/tests/ref/lavf/mxf_opatom_audio index 953df9094fd6d..deed55e52692d 100644 --- a/tests/ref/lavf/mxf_opatom_audio +++ b/tests/ref/lavf/mxf_opatom_audio @@ -1,3 +1,3 @@ -d4ad5a0faf410a9d9e99b3328143e89d *./tests/data/lavf/lavf.mxf_opatom_audio +e7da52bd591e6eddb4e1af381a4e5bd4 *./tests/data/lavf/lavf.mxf_opatom_audio 101945 ./tests/data/lavf/lavf.mxf_opatom_audio ./tests/data/lavf/lavf.mxf_opatom_audio CRC=0xd155c6ff diff --git a/tests/ref/lavf/wav_peak b/tests/ref/lavf/wav_peak index aa7e5fc49e93e..861b246d72aa1 100644 --- a/tests/ref/lavf/wav_peak +++ b/tests/ref/lavf/wav_peak @@ -1,3 +1,3 @@ -35148d1f6e66b0080893851d917ecbf4 *./tests/data/lavf/lavf.peak.wav +105805963fb767d00da056f42f32d9f3 *./tests/data/lavf/lavf.peak.wav 89094 ./tests/data/lavf/lavf.peak.wav ./tests/data/lavf/lavf.peak.wav CRC=0x3a1da17e diff --git a/tests/ref/lavf/wav_peak_only b/tests/ref/lavf/wav_peak_only index dccd0e72ff4f4..b203d0345bed0 100644 --- a/tests/ref/lavf/wav_peak_only +++ b/tests/ref/lavf/wav_peak_only @@ -1,2 +1,2 @@ -b609a363e6d490710ed52231a8d09d3c *./tests/data/lavf/lavf.peak_only.wav +f1a8aeeae8069f3992c4d780436c3d23 *./tests/data/lavf/lavf.peak_only.wav 832 ./tests/data/lavf/lavf.peak_only.wav diff --git a/tests/ref/seek/empty-edit-mp4 b/tests/ref/seek/empty-edit-mp4 new file mode 100644 index 0000000000000..f0a4ad30b000e --- /dev/null +++ b/tests/ref/seek/empty-edit-mp4 @@ -0,0 +1,134 @@ +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 5.000000 pos: 48 size: 2917 +ret: 0 st: 0 flags:0 dts: 5.100000 pts: 5.100000 pos: 2965 size: 672 +ret: 0 st: 0 flags:0 dts: 5.200000 pts: 5.200000 pos: 3637 size: 464 +ret: 0 st: 0 flags:0 dts: 5.300000 pts: 5.300000 pos: 4101 size: 454 +ret: 0 st:-1 flags:0 ts:-1.000000 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 5.000000 pos: 48 size: 2917 +ret: 0 st: 0 flags:0 dts: 5.100000 pts: 5.100000 pos: 2965 size: 672 +ret: 0 st: 0 flags:0 dts: 5.200000 pts: 5.200000 pos: 3637 size: 464 +ret: 0 st: 0 flags:0 dts: 5.300000 pts: 5.300000 pos: 4101 size: 454 +ret: 0 st:-1 flags:1 ts: 11.894167 +ret: 0 st: 0 flags:1 dts: 11.000000 pts: 11.000000 pos: 40515 size: 3214 +ret: 0 st: 0 flags:0 dts: 11.100000 pts: 11.100000 pos: 43729 size: 581 +ret: 0 st: 0 flags:0 dts: 11.200000 pts: 11.200000 pos: 44310 size: 432 +ret: 0 st: 0 flags:0 dts: 11.300000 pts: 11.300000 pos: 44742 size: 380 +ret: 0 st: 0 flags:0 ts: 9.788379 +ret: 0 st: 0 flags:1 dts: 10.000000 pts: 10.000000 pos: 33523 size: 3221 +ret: 0 st: 0 flags:0 dts: 10.100000 pts: 10.100000 pos: 36744 size: 575 +ret: 0 st: 0 flags:0 dts: 10.200000 pts: 10.200000 pos: 37319 size: 438 +ret: 0 st: 0 flags:0 dts: 10.300000 pts: 10.300000 pos: 37757 size: 449 +ret: 0 st: 0 flags:1 ts: 7.682520 +ret: 0 st: 0 flags:1 dts: 7.000000 pts: 7.000000 pos: 13643 size: 3234 +ret: 0 st: 0 flags:0 dts: 7.100000 pts: 7.100000 pos: 16877 size: 585 +ret: 0 st: 0 flags:0 dts: 7.200000 pts: 7.200000 pos: 17462 size: 442 +ret: 0 st: 0 flags:0 dts: 7.300000 pts: 7.300000 pos: 17904 size: 371 +ret: 0 st:-1 flags:0 ts: 5.576668 +ret: 0 st: 0 flags:1 dts: 6.000000 pts: 6.000000 pos: 6953 size: 3166 +ret: 0 st: 0 flags:0 dts: 6.100000 pts: 6.100000 pos: 10119 size: 599 +ret: 0 st: 0 flags:0 dts: 6.200000 pts: 6.200000 pos: 10718 size: 418 +ret: 0 st: 0 flags:0 dts: 6.300000 pts: 6.300000 pos: 11136 size: 354 +ret: 0 st:-1 flags:1 ts: 3.470835 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 5.000000 pos: 48 size: 2917 +ret: 0 st: 0 flags:0 dts: 5.100000 pts: 5.100000 pos: 2965 size: 672 +ret: 0 st: 0 flags:0 dts: 5.200000 pts: 5.200000 pos: 3637 size: 464 +ret: 0 st: 0 flags:0 dts: 5.300000 pts: 5.300000 pos: 4101 size: 454 +ret: 0 st: 0 flags:0 ts: 1.365039 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 5.000000 pos: 48 size: 2917 +ret: 0 st: 0 flags:0 dts: 5.100000 pts: 5.100000 pos: 2965 size: 672 +ret: 0 st: 0 flags:0 dts: 5.200000 pts: 5.200000 pos: 3637 size: 464 +ret: 0 st: 0 flags:0 dts: 5.300000 pts: 5.300000 pos: 4101 size: 454 +ret: 0 st: 0 flags:1 ts:-0.740820 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 5.000000 pos: 48 size: 2917 +ret: 0 st: 0 flags:0 dts: 5.100000 pts: 5.100000 pos: 2965 size: 672 +ret: 0 st: 0 flags:0 dts: 5.200000 pts: 5.200000 pos: 3637 size: 464 +ret: 0 st: 0 flags:0 dts: 5.300000 pts: 5.300000 pos: 4101 size: 454 +ret: 0 st:-1 flags:0 ts: 12.153336 +ret: 0 st: 0 flags:1 dts: 13.000000 pts: 13.000000 pos: 54444 size: 3310 +ret: 0 st: 0 flags:0 dts: 13.100000 pts: 13.100000 pos: 57754 size: 540 +ret: 0 st: 0 flags:0 dts: 13.200000 pts: 13.200000 pos: 58294 size: 419 +ret: 0 st: 0 flags:0 dts: 13.300000 pts: 13.300000 pos: 58713 size: 338 +ret: 0 st:-1 flags:1 ts: 10.047503 +ret: 0 st: 0 flags:1 dts: 10.000000 pts: 10.000000 pos: 33523 size: 3221 +ret: 0 st: 0 flags:0 dts: 10.100000 pts: 10.100000 pos: 36744 size: 575 +ret: 0 st: 0 flags:0 dts: 10.200000 pts: 10.200000 pos: 37319 size: 438 +ret: 0 st: 0 flags:0 dts: 10.300000 pts: 10.300000 pos: 37757 size: 449 +ret: 0 st: 0 flags:0 ts: 7.941699 +ret: 0 st: 0 flags:1 dts: 8.000000 pts: 8.000000 pos: 20396 size: 3281 +ret: 0 st: 0 flags:0 dts: 8.100000 pts: 8.100000 pos: 23677 size: 631 +ret: 0 st: 0 flags:0 dts: 8.200000 pts: 8.200000 pos: 24308 size: 349 +ret: 0 st: 0 flags:0 dts: 8.300000 pts: 8.300000 pos: 24657 size: 319 +ret: 0 st: 0 flags:1 ts: 5.835840 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 5.000000 pos: 48 size: 2917 +ret: 0 st: 0 flags:0 dts: 5.100000 pts: 5.100000 pos: 2965 size: 672 +ret: 0 st: 0 flags:0 dts: 5.200000 pts: 5.200000 pos: 3637 size: 464 +ret: 0 st: 0 flags:0 dts: 5.300000 pts: 5.300000 pos: 4101 size: 454 +ret: 0 st:-1 flags:0 ts: 3.730004 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 5.000000 pos: 48 size: 2917 +ret: 0 st: 0 flags:0 dts: 5.100000 pts: 5.100000 pos: 2965 size: 672 +ret: 0 st: 0 flags:0 dts: 5.200000 pts: 5.200000 pos: 3637 size: 464 +ret: 0 st: 0 flags:0 dts: 5.300000 pts: 5.300000 pos: 4101 size: 454 +ret: 0 st:-1 flags:1 ts: 1.624171 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 5.000000 pos: 48 size: 2917 +ret: 0 st: 0 flags:0 dts: 5.100000 pts: 5.100000 pos: 2965 size: 672 +ret: 0 st: 0 flags:0 dts: 5.200000 pts: 5.200000 pos: 3637 size: 464 +ret: 0 st: 0 flags:0 dts: 5.300000 pts: 5.300000 pos: 4101 size: 454 +ret: 0 st: 0 flags:0 ts:-0.481641 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 5.000000 pos: 48 size: 2917 +ret: 0 st: 0 flags:0 dts: 5.100000 pts: 5.100000 pos: 2965 size: 672 +ret: 0 st: 0 flags:0 dts: 5.200000 pts: 5.200000 pos: 3637 size: 464 +ret: 0 st: 0 flags:0 dts: 5.300000 pts: 5.300000 pos: 4101 size: 454 +ret: 0 st: 0 flags:1 ts: 12.412500 +ret: 0 st: 0 flags:1 dts: 12.000000 pts: 12.000000 pos: 47419 size: 3229 +ret: 0 st: 0 flags:0 dts: 12.100000 pts: 12.100000 pos: 50648 size: 588 +ret: 0 st: 0 flags:0 dts: 12.200000 pts: 12.200000 pos: 51236 size: 404 +ret: 0 st: 0 flags:0 dts: 12.300000 pts: 12.300000 pos: 51640 size: 415 +ret: 0 st:-1 flags:0 ts: 10.306672 +ret: 0 st: 0 flags:1 dts: 11.000000 pts: 11.000000 pos: 40515 size: 3214 +ret: 0 st: 0 flags:0 dts: 11.100000 pts: 11.100000 pos: 43729 size: 581 +ret: 0 st: 0 flags:0 dts: 11.200000 pts: 11.200000 pos: 44310 size: 432 +ret: 0 st: 0 flags:0 dts: 11.300000 pts: 11.300000 pos: 44742 size: 380 +ret: 0 st:-1 flags:1 ts: 8.200839 +ret: 0 st: 0 flags:1 dts: 8.000000 pts: 8.000000 pos: 20396 size: 3281 +ret: 0 st: 0 flags:0 dts: 8.100000 pts: 8.100000 pos: 23677 size: 631 +ret: 0 st: 0 flags:0 dts: 8.200000 pts: 8.200000 pos: 24308 size: 349 +ret: 0 st: 0 flags:0 dts: 8.300000 pts: 8.300000 pos: 24657 size: 319 +ret: 0 st: 0 flags:0 ts: 6.095020 +ret: 0 st: 0 flags:1 dts: 7.000000 pts: 7.000000 pos: 13643 size: 3234 +ret: 0 st: 0 flags:0 dts: 7.100000 pts: 7.100000 pos: 16877 size: 585 +ret: 0 st: 0 flags:0 dts: 7.200000 pts: 7.200000 pos: 17462 size: 442 +ret: 0 st: 0 flags:0 dts: 7.300000 pts: 7.300000 pos: 17904 size: 371 +ret: 0 st: 0 flags:1 ts: 3.989160 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 5.000000 pos: 48 size: 2917 +ret: 0 st: 0 flags:0 dts: 5.100000 pts: 5.100000 pos: 2965 size: 672 +ret: 0 st: 0 flags:0 dts: 5.200000 pts: 5.200000 pos: 3637 size: 464 +ret: 0 st: 0 flags:0 dts: 5.300000 pts: 5.300000 pos: 4101 size: 454 +ret: 0 st:-1 flags:0 ts: 1.883340 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 5.000000 pos: 48 size: 2917 +ret: 0 st: 0 flags:0 dts: 5.100000 pts: 5.100000 pos: 2965 size: 672 +ret: 0 st: 0 flags:0 dts: 5.200000 pts: 5.200000 pos: 3637 size: 464 +ret: 0 st: 0 flags:0 dts: 5.300000 pts: 5.300000 pos: 4101 size: 454 +ret: 0 st:-1 flags:1 ts:-0.222493 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 5.000000 pos: 48 size: 2917 +ret: 0 st: 0 flags:0 dts: 5.100000 pts: 5.100000 pos: 2965 size: 672 +ret: 0 st: 0 flags:0 dts: 5.200000 pts: 5.200000 pos: 3637 size: 464 +ret: 0 st: 0 flags:0 dts: 5.300000 pts: 5.300000 pos: 4101 size: 454 +ret: 0 st: 0 flags:0 ts: 12.671680 +ret: 0 st: 0 flags:1 dts: 13.000000 pts: 13.000000 pos: 54444 size: 3310 +ret: 0 st: 0 flags:0 dts: 13.100000 pts: 13.100000 pos: 57754 size: 540 +ret: 0 st: 0 flags:0 dts: 13.200000 pts: 13.200000 pos: 58294 size: 419 +ret: 0 st: 0 flags:0 dts: 13.300000 pts: 13.300000 pos: 58713 size: 338 +ret: 0 st: 0 flags:1 ts: 10.565820 +ret: 0 st: 0 flags:1 dts: 10.000000 pts: 10.000000 pos: 33523 size: 3221 +ret: 0 st: 0 flags:0 dts: 10.100000 pts: 10.100000 pos: 36744 size: 575 +ret: 0 st: 0 flags:0 dts: 10.200000 pts: 10.200000 pos: 37319 size: 438 +ret: 0 st: 0 flags:0 dts: 10.300000 pts: 10.300000 pos: 37757 size: 449 +ret: 0 st:-1 flags:0 ts: 8.460008 +ret: 0 st: 0 flags:1 dts: 9.000000 pts: 9.000000 pos: 27090 size: 3182 +ret: 0 st: 0 flags:0 dts: 9.100000 pts: 9.100000 pos: 30272 size: 481 +ret: 0 st: 0 flags:0 dts: 9.200000 pts: 9.200000 pos: 30753 size: 334 +ret: 0 st: 0 flags:0 dts: 9.300000 pts: 9.300000 pos: 31087 size: 328 +ret: 0 st:-1 flags:1 ts: 6.354175 +ret: 0 st: 0 flags:1 dts: 6.000000 pts: 6.000000 pos: 6953 size: 3166 +ret: 0 st: 0 flags:0 dts: 6.100000 pts: 6.100000 pos: 10119 size: 599 +ret: 0 st: 0 flags:0 dts: 6.200000 pts: 6.200000 pos: 10718 size: 418 +ret: 0 st: 0 flags:0 dts: 6.300000 pts: 6.300000 pos: 11136 size: 354 diff --git a/tests/ref/seek/extra-mp4 b/tests/ref/seek/extra-mp4 index c25544c0954b9..c17ce4003c68a 100644 --- a/tests/ref/seek/extra-mp4 +++ b/tests/ref/seek/extra-mp4 @@ -28,10 +28,10 @@ ret: 0 st: 0 flags:0 dts: 50.633333 pts: 50.733333 pos:5926157 size: 13 ret: 0 st: 0 flags:0 dts: 50.666667 pts: 50.666667 pos:5927464 size: 150 ret: 0 st: 0 flags:0 dts: 50.700000 pts: 50.700000 pos:5927614 size: 176 ret: 0 st:-1 flags:1 ts: 153.470835 -ret: 0 st: 0 flags:1 dts: 153.466667 pts: 153.500000 pos:15867700 size: 96169 -ret: 0 st: 0 flags:0 dts: 153.500000 pts: 153.533333 pos:15963869 size: 785 -ret: 0 st: 0 flags:0 dts: 153.533333 pts: 153.633333 pos:15964654 size: 3135 -ret: 0 st: 0 flags:0 dts: 153.566667 pts: 153.566667 pos:15967789 size: 859 +ret: 0 st: 0 flags:1 dts: 151.966667 pts: 152.000000 pos:15705355 size:146924 +ret: 0 st: 0 flags:0 dts: 152.000000 pts: 152.100000 pos:15852279 size: 1355 +ret: 0 st: 0 flags:0 dts: 152.033333 pts: 152.033333 pos:15853634 size: 211 +ret: 0 st: 0 flags:0 dts: 152.066667 pts: 152.066667 pos:15853845 size: 217 ret: 0 st: 0 flags:0 ts: 76.365000 ret: 0 st: 0 flags:1 dts: 77.833333 pts: 77.866667 pos:8659657 size: 41182 ret: 0 st: 0 flags:0 dts: 77.866667 pts: 77.966667 pos:8700839 size: 4197 @@ -83,10 +83,10 @@ ret: 0 st: 0 flags:0 dts: 101.333333 pts: 101.433333 pos:11049548 size: ret: 0 st: 0 flags:0 dts: 101.366667 pts: 101.366667 pos:11053072 size: 562 ret: 0 st: 0 flags:0 dts: 101.400000 pts: 101.400000 pos:11053634 size: 599 ret: 0 st:-1 flags:0 ts: 25.306672 -ret: 0 st: 0 flags:1 dts: 27.400000 pts: 27.433333 pos:2674605 size:127383 -ret: 0 st: 0 flags:0 dts: 27.433333 pts: 27.466667 pos:2801988 size: 68 -ret: 0 st: 0 flags:0 dts: 27.466667 pts: 27.500000 pos:2802268 size: 1754 -ret: 0 st: 0 flags:0 dts: 27.500000 pts: 27.533333 pos:2804022 size: 4071 +ret: 0 st: 0 flags:1 dts: 25.300000 pts: 25.333333 pos:2607246 size: 40273 +ret: 0 st: 0 flags:0 dts: 25.333333 pts: 25.433333 pos:2647519 size: 2959 +ret: 0 st: 0 flags:0 dts: 25.366667 pts: 25.366667 pos:2650478 size: 197 +ret: 0 st: 0 flags:0 dts: 25.400000 pts: 25.400000 pos:2650675 size: 230 ret: 0 st:-1 flags:1 ts: 128.200839 ret: 0 st: 0 flags:1 dts: 127.833333 pts: 127.866667 pos:13514072 size: 67382 ret: 0 st: 0 flags:0 dts: 127.866667 pts: 127.966667 pos:13581454 size: 2936 diff --git a/tests/ref/seek/lavf-alaw b/tests/ref/seek/lavf-alaw index 4b1f8fbc02e11..8d517fa2bbdcb 100644 --- a/tests/ref/seek/lavf-alaw +++ b/tests/ref/seek/lavf-alaw @@ -1,53 +1,53 @@ -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 ret: 0 st:-1 flags:0 ts:-1.000000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 ret: 0 st:-1 flags:1 ts: 1.894167 -ret: 0 st: 0 flags:1 dts: 1.894150 pts: 1.894150 pos: 41766 size: 1024 +ret: 0 st: 0 flags:1 dts: 1.894150 pts: 1.894150 pos: 41766 size: 882 ret: 0 st: 0 flags:0 ts: 0.788345 -ret: 0 st: 0 flags:1 dts: 0.788345 pts: 0.788345 pos: 17383 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.788345 pts: 0.788345 pos: 17383 size: 882 ret: 0 st: 0 flags:1 ts:-0.317506 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 ret: 0 st:-1 flags:0 ts: 2.576668 ret:-EOF ret: 0 st:-1 flags:1 ts: 1.470835 -ret: 0 st: 0 flags:1 dts: 1.470839 pts: 1.470839 pos: 32432 size: 1024 +ret: 0 st: 0 flags:1 dts: 1.470839 pts: 1.470839 pos: 32432 size: 882 ret: 0 st: 0 flags:0 ts: 0.364989 -ret: 0 st: 0 flags:1 dts: 0.364989 pts: 0.364989 pos: 8048 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.364989 pts: 0.364989 pos: 8048 size: 882 ret: 0 st: 0 flags:1 ts:-0.740816 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 ret: 0 st:-1 flags:0 ts: 2.153336 ret:-EOF ret: 0 st:-1 flags:1 ts: 1.047503 -ret: 0 st: 0 flags:1 dts: 1.047483 pts: 1.047483 pos: 23097 size: 1024 +ret: 0 st: 0 flags:1 dts: 1.047483 pts: 1.047483 pos: 23097 size: 882 ret: 0 st: 0 flags:0 ts:-0.058322 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 ret: 0 st: 0 flags:1 ts: 2.835828 ret:-EOF ret: 0 st:-1 flags:0 ts: 1.730004 -ret: 0 st: 0 flags:1 dts: 1.730023 pts: 1.730023 pos: 38147 size: 1024 +ret: 0 st: 0 flags:1 dts: 1.730023 pts: 1.730023 pos: 38147 size: 882 ret: 0 st:-1 flags:1 ts: 0.624171 -ret: 0 st: 0 flags:1 dts: 0.624172 pts: 0.624172 pos: 13763 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.624172 pts: 0.624172 pos: 13763 size: 882 ret: 0 st: 0 flags:0 ts:-0.481678 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 ret: 0 st: 0 flags:1 ts: 2.412517 ret:-EOF ret: 0 st:-1 flags:0 ts: 1.306672 -ret: 0 st: 0 flags:1 dts: 1.306667 pts: 1.306667 pos: 28812 size: 1024 +ret: 0 st: 0 flags:1 dts: 1.306667 pts: 1.306667 pos: 28812 size: 882 ret: 0 st:-1 flags:1 ts: 0.200839 -ret: 0 st: 0 flags:1 dts: 0.200816 pts: 0.200816 pos: 4428 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.200816 pts: 0.200816 pos: 4428 size: 882 ret: 0 st: 0 flags:0 ts:-0.904989 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 ret: 0 st: 0 flags:1 ts: 1.989161 ret: 0 st: 0 flags:1 dts: 1.989161 pts: 1.989161 pos: 43861 size: 239 ret: 0 st:-1 flags:0 ts: 0.883340 -ret: 0 st: 0 flags:1 dts: 0.883356 pts: 0.883356 pos: 19478 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.883356 pts: 0.883356 pos: 19478 size: 882 ret: 0 st:-1 flags:1 ts:-0.222493 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 ret: 0 st: 0 flags:0 ts: 2.671655 ret:-EOF ret: 0 st: 0 flags:1 ts: 1.565850 -ret: 0 st: 0 flags:1 dts: 1.565850 pts: 1.565850 pos: 34527 size: 1024 +ret: 0 st: 0 flags:1 dts: 1.565850 pts: 1.565850 pos: 34527 size: 882 ret: 0 st:-1 flags:0 ts: 0.460008 -ret: 0 st: 0 flags:1 dts: 0.460000 pts: 0.460000 pos: 10143 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.460000 pts: 0.460000 pos: 10143 size: 882 ret: 0 st:-1 flags:1 ts:-0.645825 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 diff --git a/tests/ref/seek/lavf-ffm b/tests/ref/seek/lavf-ffm deleted file mode 100644 index eceed1a2c2791..0000000000000 --- a/tests/ref/seek/lavf-ffm +++ /dev/null @@ -1,53 +0,0 @@ -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663 -ret: 0 st:-1 flags:0 ts:-1.000000 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663 -ret: 0 st:-1 flags:1 ts: 1.894167 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st: 0 flags:0 ts: 0.788334 -ret: 0 st: 1 flags:1 dts: 0.825011 pts: 0.825011 pos: 327680 size: 209 -ret: 0 st: 0 flags:1 ts:-0.317499 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663 -ret: 0 st: 1 flags:0 ts: 2.576668 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st: 1 flags:1 ts: 1.470835 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st:-1 flags:0 ts: 0.365002 -ret: 0 st: 1 flags:1 dts: 0.380930 pts: 0.380930 pos: 163840 size: 209 -ret: 0 st:-1 flags:1 ts:-0.740831 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663 -ret: 0 st: 0 flags:0 ts: 2.153336 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st: 0 flags:1 ts: 1.047503 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st: 1 flags:0 ts:-0.058330 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663 -ret: 0 st: 1 flags:1 ts: 2.835837 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st:-1 flags:0 ts: 1.730004 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st:-1 flags:1 ts: 0.624171 -ret: 0 st: 1 flags:1 dts: 0.642154 pts: 0.642154 pos: 274432 size: 209 -ret: 0 st: 0 flags:0 ts:-0.481662 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663 -ret: 0 st: 0 flags:1 ts: 2.412505 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st: 1 flags:0 ts: 1.306672 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st: 1 flags:1 ts: 0.200839 -ret: 0 st: 1 flags:1 dts: 0.224195 pts: 0.224195 pos: 114688 size: 209 -ret: 0 st:-1 flags:0 ts:-0.904994 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663 -ret: 0 st:-1 flags:1 ts: 1.989173 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st: 0 flags:0 ts: 0.883340 -ret: 0 st: 0 flags:0 dts: 0.880000 pts: 0.920000 pos: 339968 size: 12307 -ret: 0 st: 0 flags:1 ts:-0.222493 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663 -ret: 0 st: 1 flags:0 ts: 2.671674 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st: 1 flags:1 ts: 1.565841 -ret: 0 st: 1 flags:1 dts: 0.929501 pts: 0.929501 pos: 376832 size: 209 -ret: 0 st:-1 flags:0 ts: 0.460008 -ret: 0 st: 1 flags:1 dts: 0.485420 pts: 0.485420 pos: 221184 size: 209 -ret: 0 st:-1 flags:1 ts:-0.645825 -ret: 0 st: 0 flags:1 dts:-0.040000 pts: 0.000000 pos: 8192 size: 24663 diff --git a/tests/ref/seek/lavf-mulaw b/tests/ref/seek/lavf-mulaw index 4b1f8fbc02e11..8d517fa2bbdcb 100644 --- a/tests/ref/seek/lavf-mulaw +++ b/tests/ref/seek/lavf-mulaw @@ -1,53 +1,53 @@ -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 ret: 0 st:-1 flags:0 ts:-1.000000 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 ret: 0 st:-1 flags:1 ts: 1.894167 -ret: 0 st: 0 flags:1 dts: 1.894150 pts: 1.894150 pos: 41766 size: 1024 +ret: 0 st: 0 flags:1 dts: 1.894150 pts: 1.894150 pos: 41766 size: 882 ret: 0 st: 0 flags:0 ts: 0.788345 -ret: 0 st: 0 flags:1 dts: 0.788345 pts: 0.788345 pos: 17383 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.788345 pts: 0.788345 pos: 17383 size: 882 ret: 0 st: 0 flags:1 ts:-0.317506 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 ret: 0 st:-1 flags:0 ts: 2.576668 ret:-EOF ret: 0 st:-1 flags:1 ts: 1.470835 -ret: 0 st: 0 flags:1 dts: 1.470839 pts: 1.470839 pos: 32432 size: 1024 +ret: 0 st: 0 flags:1 dts: 1.470839 pts: 1.470839 pos: 32432 size: 882 ret: 0 st: 0 flags:0 ts: 0.364989 -ret: 0 st: 0 flags:1 dts: 0.364989 pts: 0.364989 pos: 8048 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.364989 pts: 0.364989 pos: 8048 size: 882 ret: 0 st: 0 flags:1 ts:-0.740816 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 ret: 0 st:-1 flags:0 ts: 2.153336 ret:-EOF ret: 0 st:-1 flags:1 ts: 1.047503 -ret: 0 st: 0 flags:1 dts: 1.047483 pts: 1.047483 pos: 23097 size: 1024 +ret: 0 st: 0 flags:1 dts: 1.047483 pts: 1.047483 pos: 23097 size: 882 ret: 0 st: 0 flags:0 ts:-0.058322 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 ret: 0 st: 0 flags:1 ts: 2.835828 ret:-EOF ret: 0 st:-1 flags:0 ts: 1.730004 -ret: 0 st: 0 flags:1 dts: 1.730023 pts: 1.730023 pos: 38147 size: 1024 +ret: 0 st: 0 flags:1 dts: 1.730023 pts: 1.730023 pos: 38147 size: 882 ret: 0 st:-1 flags:1 ts: 0.624171 -ret: 0 st: 0 flags:1 dts: 0.624172 pts: 0.624172 pos: 13763 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.624172 pts: 0.624172 pos: 13763 size: 882 ret: 0 st: 0 flags:0 ts:-0.481678 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 ret: 0 st: 0 flags:1 ts: 2.412517 ret:-EOF ret: 0 st:-1 flags:0 ts: 1.306672 -ret: 0 st: 0 flags:1 dts: 1.306667 pts: 1.306667 pos: 28812 size: 1024 +ret: 0 st: 0 flags:1 dts: 1.306667 pts: 1.306667 pos: 28812 size: 882 ret: 0 st:-1 flags:1 ts: 0.200839 -ret: 0 st: 0 flags:1 dts: 0.200816 pts: 0.200816 pos: 4428 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.200816 pts: 0.200816 pos: 4428 size: 882 ret: 0 st: 0 flags:0 ts:-0.904989 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 ret: 0 st: 0 flags:1 ts: 1.989161 ret: 0 st: 0 flags:1 dts: 1.989161 pts: 1.989161 pos: 43861 size: 239 ret: 0 st:-1 flags:0 ts: 0.883340 -ret: 0 st: 0 flags:1 dts: 0.883356 pts: 0.883356 pos: 19478 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.883356 pts: 0.883356 pos: 19478 size: 882 ret: 0 st:-1 flags:1 ts:-0.222493 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 ret: 0 st: 0 flags:0 ts: 2.671655 ret:-EOF ret: 0 st: 0 flags:1 ts: 1.565850 -ret: 0 st: 0 flags:1 dts: 1.565850 pts: 1.565850 pos: 34527 size: 1024 +ret: 0 st: 0 flags:1 dts: 1.565850 pts: 1.565850 pos: 34527 size: 882 ret: 0 st:-1 flags:0 ts: 0.460008 -ret: 0 st: 0 flags:1 dts: 0.460000 pts: 0.460000 pos: 10143 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.460000 pts: 0.460000 pos: 10143 size: 882 ret: 0 st:-1 flags:1 ts:-0.645825 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 1024 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 0 size: 882 diff --git a/tests/ref/seek/lavf-mxf_d10 b/tests/ref/seek/lavf-mxf_d10 index 17cca29c03be4..5a682f0927e2a 100644 --- a/tests/ref/seek/lavf-mxf_d10 +++ b/tests/ref/seek/lavf-mxf_d10 @@ -8,9 +8,9 @@ ret: 0 st: 0 flags:1 dts: 0.800000 pts: 0.800000 pos:4265984 size:150000 ret: 0 st: 0 flags:1 ts:-0.320000 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 ret: 0 st: 1 flags:0 ts: 2.576667 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st: 1 flags:1 ts: 1.470833 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st:-1 flags:0 ts: 0.365002 ret: 0 st: 0 flags:1 dts: 0.360000 pts: 0.360000 pos:1923072 size:150000 ret: 0 st:-1 flags:1 ts:-0.740831 @@ -22,7 +22,7 @@ ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st: 1 flags:0 ts:-0.058333 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 ret: 0 st: 1 flags:1 ts: 2.835833 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st:-1 flags:0 ts: 1.730004 ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st:-1 flags:1 ts: 0.624171 @@ -32,7 +32,7 @@ ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 ret: 0 st: 0 flags:1 ts: 2.400000 ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st: 1 flags:0 ts: 1.306667 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st: 1 flags:1 ts: 0.200833 ret: 0 st: 0 flags:1 dts: 0.200000 pts: 0.200000 pos:1071104 size:150000 ret: 0 st:-1 flags:0 ts:-0.904994 @@ -44,9 +44,9 @@ ret: 0 st: 0 flags:1 dts: 0.880000 pts: 0.880000 pos:4691968 size:150000 ret: 0 st: 0 flags:1 ts:-0.240000 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 6144 size:150000 ret: 0 st: 1 flags:0 ts: 2.671667 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st: 1 flags:1 ts: 1.565833 -ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos:5117952 size:150000 +ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos:5117952 size:150000 ret: 0 st:-1 flags:0 ts: 0.460008 ret: 0 st: 0 flags:1 dts: 0.480000 pts: 0.480000 pos:2562048 size:150000 ret: 0 st:-1 flags:1 ts:-0.645825 diff --git a/tests/ref/seek/lavf-rm b/tests/ref/seek/lavf-rm index 4b1917300e604..756e157fb3e5a 100644 --- a/tests/ref/seek/lavf-rm +++ b/tests/ref/seek/lavf-rm @@ -1,4 +1,4 @@ -ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 395 size: 278 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 696 size: 31082 ret: 0 st:-1 flags:0 ts:-1.000000 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 696 size: 31082 ret: 0 st:-1 flags:1 ts: 1.894167 @@ -20,7 +20,7 @@ ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 314992 size: 31143 ret: 0 st: 0 flags:1 ts: 1.048000 ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 314992 size: 31143 ret: 0 st: 1 flags:0 ts:-0.058000 -ret: 0 st: 1 flags:1 dts: 0.000000 pts: 0.000000 pos: 395 size: 278 +ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 696 size: 31082 ret: 0 st: 1 flags:1 ts: 2.836000 ret: 0 st: 1 flags:1 dts: 0.975000 pts: 0.975000 pos: 346138 size: 278 ret: 0 st:-1 flags:0 ts: 1.730004 @@ -34,7 +34,7 @@ ret: 0 st: 0 flags:1 dts: 0.960000 pts: 0.960000 pos: 314992 size: 31143 ret: 0 st: 1 flags:0 ts: 1.307000 ret: 0 st: 1 flags:1 dts: 0.975000 pts: 0.975000 pos: 346138 size: 278 ret: 0 st: 1 flags:1 ts: 0.201000 -ret: 0 st: 1 flags:1 dts: 0.174000 pts: 0.174000 pos: 78977 size: 278 +ret: 0 st: 0 flags:0 dts: 0.200000 pts: 0.200000 pos: 79274 size: 11400 ret: 0 st:-1 flags:0 ts:-0.904994 ret: 0 st: 0 flags:1 dts: 0.000000 pts: 0.000000 pos: 696 size: 31082 ret: 0 st:-1 flags:1 ts: 1.989173 diff --git a/tests/ref/seek/test-iibbibb-mp4 b/tests/ref/seek/test-iibbibb-mp4 new file mode 100644 index 0000000000000..5a8960021882f --- /dev/null +++ b/tests/ref/seek/test-iibbibb-mp4 @@ -0,0 +1,122 @@ +ret: 0 st: 0 flags:1 dts:-2.000000 pts: 0.000000 pos: 48 size: 7804 +ret: 0 st: 0 flags:1 dts:-1.000000 pts: 3.000000 pos: 7852 size: 7808 +ret: 0 st: 0 flags:0 dts: 0.000000 pts: 2.000000 pos: 15660 size: 1301 +ret: 0 st: 0 flags:0 dts: 1.000000 pts: 1.000000 pos: 16961 size: 1114 +ret: 0 st:-1 flags:0 ts:-1.000000 +ret: 0 st: 0 flags:1 dts:-2.000000 pts: 0.000000 pos: 48 size: 7804 +ret: 0 st: 0 flags:1 dts:-1.000000 pts: 3.000000 pos: 7852 size: 7808 +ret: 0 st: 0 flags:0 dts: 0.000000 pts: 2.000000 pos: 15660 size: 1301 +ret: 0 st: 0 flags:0 dts: 1.000000 pts: 1.000000 pos: 16961 size: 1114 +ret: 0 st:-1 flags:1 ts: 4.894167 +ret: 0 st: 0 flags:1 dts: 2.000000 pts: 6.000000 pos: 18075 size: 7730 +ret: 0 st: 0 flags:0 dts: 3.000000 pts: 5.000000 pos: 25805 size: 1247 +ret: 0 st: 0 flags:0 dts: 4.000000 pts: 4.000000 pos: 27052 size: 1110 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 9.000000 pos: 28162 size: 7595 +ret:-1 st: 0 flags:0 ts: 10.788330 +ret: 0 st: 0 flags:1 ts: 3.682495 +ret: 0 st: 0 flags:1 dts:-1.000000 pts: 3.000000 pos: 7852 size: 7808 +ret: 0 st: 0 flags:0 dts: 0.000000 pts: 2.000000 pos: 15660 size: 1301 +ret: 0 st: 0 flags:0 dts: 1.000000 pts: 1.000000 pos: 16961 size: 1114 +ret: 0 st: 0 flags:1 dts: 2.000000 pts: 6.000000 pos: 18075 size: 7730 +ret: 0 st:-1 flags:0 ts: 9.576668 +ret: 0 st: 0 flags:1 dts: 8.000000 pts: 12.000000 pos: 38160 size: 6734 +ret: 0 st: 0 flags:0 dts: 9.000000 pts: 11.000000 pos: 44894 size: 1437 +ret: 0 st: 0 flags:0 dts: 10.000000 pts: 10.000000 pos: 46331 size: 1186 +ret:-EOF +ret: 0 st:-1 flags:1 ts: 2.470835 +ret: 0 st: 0 flags:1 dts:-1.000000 pts: 3.000000 pos: 7852 size: 7808 +ret: 0 st: 0 flags:0 dts: 0.000000 pts: 2.000000 pos: 15660 size: 1301 +ret: 0 st: 0 flags:0 dts: 1.000000 pts: 1.000000 pos: 16961 size: 1114 +ret: 0 st: 0 flags:1 dts: 2.000000 pts: 6.000000 pos: 18075 size: 7730 +ret: 0 st: 0 flags:0 ts: 8.364990 +ret: 0 st: 0 flags:1 dts: 8.000000 pts: 12.000000 pos: 38160 size: 6734 +ret: 0 st: 0 flags:0 dts: 9.000000 pts: 11.000000 pos: 44894 size: 1437 +ret: 0 st: 0 flags:0 dts: 10.000000 pts: 10.000000 pos: 46331 size: 1186 +ret:-EOF +ret: 0 st: 0 flags:1 ts: 1.259155 +ret: 0 st: 0 flags:1 dts:-1.000000 pts: 3.000000 pos: 7852 size: 7808 +ret: 0 st: 0 flags:0 dts: 0.000000 pts: 2.000000 pos: 15660 size: 1301 +ret: 0 st: 0 flags:0 dts: 1.000000 pts: 1.000000 pos: 16961 size: 1114 +ret: 0 st: 0 flags:1 dts: 2.000000 pts: 6.000000 pos: 18075 size: 7730 +ret: 0 st:-1 flags:0 ts: 7.153336 +ret: 0 st: 0 flags:1 dts: 8.000000 pts: 12.000000 pos: 38160 size: 6734 +ret: 0 st: 0 flags:0 dts: 9.000000 pts: 11.000000 pos: 44894 size: 1437 +ret: 0 st: 0 flags:0 dts: 10.000000 pts: 10.000000 pos: 46331 size: 1186 +ret:-EOF +ret: 0 st:-1 flags:1 ts: 0.047503 +ret: 0 st: 0 flags:1 dts:-2.000000 pts: 0.000000 pos: 48 size: 7804 +ret: 0 st: 0 flags:1 dts:-1.000000 pts: 3.000000 pos: 7852 size: 7808 +ret: 0 st: 0 flags:0 dts: 0.000000 pts: 2.000000 pos: 15660 size: 1301 +ret: 0 st: 0 flags:0 dts: 1.000000 pts: 1.000000 pos: 16961 size: 1114 +ret: 0 st: 0 flags:0 ts: 5.941650 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 9.000000 pos: 28162 size: 7595 +ret: 0 st: 0 flags:0 dts: 6.000000 pts: 8.000000 pos: 35757 size: 1273 +ret: 0 st: 0 flags:0 dts: 7.000000 pts: 7.000000 pos: 37030 size: 1130 +ret: 0 st: 0 flags:1 dts: 8.000000 pts: 12.000000 pos: 38160 size: 6734 +ret: 0 st: 0 flags:1 ts: 11.835815 +ret: 0 st: 0 flags:1 dts: 8.000000 pts: 12.000000 pos: 38160 size: 6734 +ret: 0 st: 0 flags:0 dts: 9.000000 pts: 11.000000 pos: 44894 size: 1437 +ret: 0 st: 0 flags:0 dts: 10.000000 pts: 10.000000 pos: 46331 size: 1186 +ret:-EOF +ret: 0 st:-1 flags:0 ts: 4.730004 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 9.000000 pos: 28162 size: 7595 +ret: 0 st: 0 flags:0 dts: 6.000000 pts: 8.000000 pos: 35757 size: 1273 +ret: 0 st: 0 flags:0 dts: 7.000000 pts: 7.000000 pos: 37030 size: 1130 +ret: 0 st: 0 flags:1 dts: 8.000000 pts: 12.000000 pos: 38160 size: 6734 +ret: 0 st:-1 flags:1 ts: 10.624171 +ret: 0 st: 0 flags:1 dts: 8.000000 pts: 12.000000 pos: 38160 size: 6734 +ret: 0 st: 0 flags:0 dts: 9.000000 pts: 11.000000 pos: 44894 size: 1437 +ret: 0 st: 0 flags:0 dts: 10.000000 pts: 10.000000 pos: 46331 size: 1186 +ret:-EOF +ret: 0 st: 0 flags:0 ts: 3.518311 +ret: 0 st: 0 flags:1 dts: 2.000000 pts: 6.000000 pos: 18075 size: 7730 +ret: 0 st: 0 flags:0 dts: 3.000000 pts: 5.000000 pos: 25805 size: 1247 +ret: 0 st: 0 flags:0 dts: 4.000000 pts: 4.000000 pos: 27052 size: 1110 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 9.000000 pos: 28162 size: 7595 +ret: 0 st: 0 flags:1 ts: 9.412476 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 9.000000 pos: 28162 size: 7595 +ret: 0 st: 0 flags:0 dts: 6.000000 pts: 8.000000 pos: 35757 size: 1273 +ret: 0 st: 0 flags:0 dts: 7.000000 pts: 7.000000 pos: 37030 size: 1130 +ret: 0 st: 0 flags:1 dts: 8.000000 pts: 12.000000 pos: 38160 size: 6734 +ret: 0 st:-1 flags:0 ts: 2.306672 +ret: 0 st: 0 flags:1 dts: 2.000000 pts: 6.000000 pos: 18075 size: 7730 +ret: 0 st: 0 flags:0 dts: 3.000000 pts: 5.000000 pos: 25805 size: 1247 +ret: 0 st: 0 flags:0 dts: 4.000000 pts: 4.000000 pos: 27052 size: 1110 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 9.000000 pos: 28162 size: 7595 +ret: 0 st:-1 flags:1 ts: 8.200839 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 9.000000 pos: 28162 size: 7595 +ret: 0 st: 0 flags:0 dts: 6.000000 pts: 8.000000 pos: 35757 size: 1273 +ret: 0 st: 0 flags:0 dts: 7.000000 pts: 7.000000 pos: 37030 size: 1130 +ret: 0 st: 0 flags:1 dts: 8.000000 pts: 12.000000 pos: 38160 size: 6734 +ret: 0 st: 0 flags:0 ts: 1.095032 +ret: 0 st: 0 flags:1 dts: 2.000000 pts: 6.000000 pos: 18075 size: 7730 +ret: 0 st: 0 flags:0 dts: 3.000000 pts: 5.000000 pos: 25805 size: 1247 +ret: 0 st: 0 flags:0 dts: 4.000000 pts: 4.000000 pos: 27052 size: 1110 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 9.000000 pos: 28162 size: 7595 +ret: 0 st: 0 flags:1 ts: 6.989197 +ret: 0 st: 0 flags:1 dts: 2.000000 pts: 6.000000 pos: 18075 size: 7730 +ret: 0 st: 0 flags:0 dts: 3.000000 pts: 5.000000 pos: 25805 size: 1247 +ret: 0 st: 0 flags:0 dts: 4.000000 pts: 4.000000 pos: 27052 size: 1110 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 9.000000 pos: 28162 size: 7595 +ret: 0 st:-1 flags:0 ts:-0.116660 +ret: 0 st: 0 flags:1 dts:-2.000000 pts: 0.000000 pos: 48 size: 7804 +ret: 0 st: 0 flags:1 dts:-1.000000 pts: 3.000000 pos: 7852 size: 7808 +ret: 0 st: 0 flags:0 dts: 0.000000 pts: 2.000000 pos: 15660 size: 1301 +ret: 0 st: 0 flags:0 dts: 1.000000 pts: 1.000000 pos: 16961 size: 1114 +ret: 0 st:-1 flags:1 ts: 5.777507 +ret: 0 st: 0 flags:1 dts: 2.000000 pts: 6.000000 pos: 18075 size: 7730 +ret: 0 st: 0 flags:0 dts: 3.000000 pts: 5.000000 pos: 25805 size: 1247 +ret: 0 st: 0 flags:0 dts: 4.000000 pts: 4.000000 pos: 27052 size: 1110 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 9.000000 pos: 28162 size: 7595 +ret:-1 st: 0 flags:0 ts: 11.671692 +ret: 0 st: 0 flags:1 ts: 4.565857 +ret: 0 st: 0 flags:1 dts: 2.000000 pts: 6.000000 pos: 18075 size: 7730 +ret: 0 st: 0 flags:0 dts: 3.000000 pts: 5.000000 pos: 25805 size: 1247 +ret: 0 st: 0 flags:0 dts: 4.000000 pts: 4.000000 pos: 27052 size: 1110 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 9.000000 pos: 28162 size: 7595 +ret:-1 st:-1 flags:0 ts: 10.460008 +ret: 0 st:-1 flags:1 ts: 3.354175 +ret: 0 st: 0 flags:1 dts:-1.000000 pts: 3.000000 pos: 7852 size: 7808 +ret: 0 st: 0 flags:0 dts: 0.000000 pts: 2.000000 pos: 15660 size: 1301 +ret: 0 st: 0 flags:0 dts: 1.000000 pts: 1.000000 pos: 16961 size: 1114 +ret: 0 st: 0 flags:1 dts: 2.000000 pts: 6.000000 pos: 18075 size: 7730 diff --git a/tests/ref/seek/test-iibbibb-neg-ctts-mp4 b/tests/ref/seek/test-iibbibb-neg-ctts-mp4 new file mode 100644 index 0000000000000..5a8960021882f --- /dev/null +++ b/tests/ref/seek/test-iibbibb-neg-ctts-mp4 @@ -0,0 +1,122 @@ +ret: 0 st: 0 flags:1 dts:-2.000000 pts: 0.000000 pos: 48 size: 7804 +ret: 0 st: 0 flags:1 dts:-1.000000 pts: 3.000000 pos: 7852 size: 7808 +ret: 0 st: 0 flags:0 dts: 0.000000 pts: 2.000000 pos: 15660 size: 1301 +ret: 0 st: 0 flags:0 dts: 1.000000 pts: 1.000000 pos: 16961 size: 1114 +ret: 0 st:-1 flags:0 ts:-1.000000 +ret: 0 st: 0 flags:1 dts:-2.000000 pts: 0.000000 pos: 48 size: 7804 +ret: 0 st: 0 flags:1 dts:-1.000000 pts: 3.000000 pos: 7852 size: 7808 +ret: 0 st: 0 flags:0 dts: 0.000000 pts: 2.000000 pos: 15660 size: 1301 +ret: 0 st: 0 flags:0 dts: 1.000000 pts: 1.000000 pos: 16961 size: 1114 +ret: 0 st:-1 flags:1 ts: 4.894167 +ret: 0 st: 0 flags:1 dts: 2.000000 pts: 6.000000 pos: 18075 size: 7730 +ret: 0 st: 0 flags:0 dts: 3.000000 pts: 5.000000 pos: 25805 size: 1247 +ret: 0 st: 0 flags:0 dts: 4.000000 pts: 4.000000 pos: 27052 size: 1110 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 9.000000 pos: 28162 size: 7595 +ret:-1 st: 0 flags:0 ts: 10.788330 +ret: 0 st: 0 flags:1 ts: 3.682495 +ret: 0 st: 0 flags:1 dts:-1.000000 pts: 3.000000 pos: 7852 size: 7808 +ret: 0 st: 0 flags:0 dts: 0.000000 pts: 2.000000 pos: 15660 size: 1301 +ret: 0 st: 0 flags:0 dts: 1.000000 pts: 1.000000 pos: 16961 size: 1114 +ret: 0 st: 0 flags:1 dts: 2.000000 pts: 6.000000 pos: 18075 size: 7730 +ret: 0 st:-1 flags:0 ts: 9.576668 +ret: 0 st: 0 flags:1 dts: 8.000000 pts: 12.000000 pos: 38160 size: 6734 +ret: 0 st: 0 flags:0 dts: 9.000000 pts: 11.000000 pos: 44894 size: 1437 +ret: 0 st: 0 flags:0 dts: 10.000000 pts: 10.000000 pos: 46331 size: 1186 +ret:-EOF +ret: 0 st:-1 flags:1 ts: 2.470835 +ret: 0 st: 0 flags:1 dts:-1.000000 pts: 3.000000 pos: 7852 size: 7808 +ret: 0 st: 0 flags:0 dts: 0.000000 pts: 2.000000 pos: 15660 size: 1301 +ret: 0 st: 0 flags:0 dts: 1.000000 pts: 1.000000 pos: 16961 size: 1114 +ret: 0 st: 0 flags:1 dts: 2.000000 pts: 6.000000 pos: 18075 size: 7730 +ret: 0 st: 0 flags:0 ts: 8.364990 +ret: 0 st: 0 flags:1 dts: 8.000000 pts: 12.000000 pos: 38160 size: 6734 +ret: 0 st: 0 flags:0 dts: 9.000000 pts: 11.000000 pos: 44894 size: 1437 +ret: 0 st: 0 flags:0 dts: 10.000000 pts: 10.000000 pos: 46331 size: 1186 +ret:-EOF +ret: 0 st: 0 flags:1 ts: 1.259155 +ret: 0 st: 0 flags:1 dts:-1.000000 pts: 3.000000 pos: 7852 size: 7808 +ret: 0 st: 0 flags:0 dts: 0.000000 pts: 2.000000 pos: 15660 size: 1301 +ret: 0 st: 0 flags:0 dts: 1.000000 pts: 1.000000 pos: 16961 size: 1114 +ret: 0 st: 0 flags:1 dts: 2.000000 pts: 6.000000 pos: 18075 size: 7730 +ret: 0 st:-1 flags:0 ts: 7.153336 +ret: 0 st: 0 flags:1 dts: 8.000000 pts: 12.000000 pos: 38160 size: 6734 +ret: 0 st: 0 flags:0 dts: 9.000000 pts: 11.000000 pos: 44894 size: 1437 +ret: 0 st: 0 flags:0 dts: 10.000000 pts: 10.000000 pos: 46331 size: 1186 +ret:-EOF +ret: 0 st:-1 flags:1 ts: 0.047503 +ret: 0 st: 0 flags:1 dts:-2.000000 pts: 0.000000 pos: 48 size: 7804 +ret: 0 st: 0 flags:1 dts:-1.000000 pts: 3.000000 pos: 7852 size: 7808 +ret: 0 st: 0 flags:0 dts: 0.000000 pts: 2.000000 pos: 15660 size: 1301 +ret: 0 st: 0 flags:0 dts: 1.000000 pts: 1.000000 pos: 16961 size: 1114 +ret: 0 st: 0 flags:0 ts: 5.941650 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 9.000000 pos: 28162 size: 7595 +ret: 0 st: 0 flags:0 dts: 6.000000 pts: 8.000000 pos: 35757 size: 1273 +ret: 0 st: 0 flags:0 dts: 7.000000 pts: 7.000000 pos: 37030 size: 1130 +ret: 0 st: 0 flags:1 dts: 8.000000 pts: 12.000000 pos: 38160 size: 6734 +ret: 0 st: 0 flags:1 ts: 11.835815 +ret: 0 st: 0 flags:1 dts: 8.000000 pts: 12.000000 pos: 38160 size: 6734 +ret: 0 st: 0 flags:0 dts: 9.000000 pts: 11.000000 pos: 44894 size: 1437 +ret: 0 st: 0 flags:0 dts: 10.000000 pts: 10.000000 pos: 46331 size: 1186 +ret:-EOF +ret: 0 st:-1 flags:0 ts: 4.730004 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 9.000000 pos: 28162 size: 7595 +ret: 0 st: 0 flags:0 dts: 6.000000 pts: 8.000000 pos: 35757 size: 1273 +ret: 0 st: 0 flags:0 dts: 7.000000 pts: 7.000000 pos: 37030 size: 1130 +ret: 0 st: 0 flags:1 dts: 8.000000 pts: 12.000000 pos: 38160 size: 6734 +ret: 0 st:-1 flags:1 ts: 10.624171 +ret: 0 st: 0 flags:1 dts: 8.000000 pts: 12.000000 pos: 38160 size: 6734 +ret: 0 st: 0 flags:0 dts: 9.000000 pts: 11.000000 pos: 44894 size: 1437 +ret: 0 st: 0 flags:0 dts: 10.000000 pts: 10.000000 pos: 46331 size: 1186 +ret:-EOF +ret: 0 st: 0 flags:0 ts: 3.518311 +ret: 0 st: 0 flags:1 dts: 2.000000 pts: 6.000000 pos: 18075 size: 7730 +ret: 0 st: 0 flags:0 dts: 3.000000 pts: 5.000000 pos: 25805 size: 1247 +ret: 0 st: 0 flags:0 dts: 4.000000 pts: 4.000000 pos: 27052 size: 1110 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 9.000000 pos: 28162 size: 7595 +ret: 0 st: 0 flags:1 ts: 9.412476 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 9.000000 pos: 28162 size: 7595 +ret: 0 st: 0 flags:0 dts: 6.000000 pts: 8.000000 pos: 35757 size: 1273 +ret: 0 st: 0 flags:0 dts: 7.000000 pts: 7.000000 pos: 37030 size: 1130 +ret: 0 st: 0 flags:1 dts: 8.000000 pts: 12.000000 pos: 38160 size: 6734 +ret: 0 st:-1 flags:0 ts: 2.306672 +ret: 0 st: 0 flags:1 dts: 2.000000 pts: 6.000000 pos: 18075 size: 7730 +ret: 0 st: 0 flags:0 dts: 3.000000 pts: 5.000000 pos: 25805 size: 1247 +ret: 0 st: 0 flags:0 dts: 4.000000 pts: 4.000000 pos: 27052 size: 1110 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 9.000000 pos: 28162 size: 7595 +ret: 0 st:-1 flags:1 ts: 8.200839 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 9.000000 pos: 28162 size: 7595 +ret: 0 st: 0 flags:0 dts: 6.000000 pts: 8.000000 pos: 35757 size: 1273 +ret: 0 st: 0 flags:0 dts: 7.000000 pts: 7.000000 pos: 37030 size: 1130 +ret: 0 st: 0 flags:1 dts: 8.000000 pts: 12.000000 pos: 38160 size: 6734 +ret: 0 st: 0 flags:0 ts: 1.095032 +ret: 0 st: 0 flags:1 dts: 2.000000 pts: 6.000000 pos: 18075 size: 7730 +ret: 0 st: 0 flags:0 dts: 3.000000 pts: 5.000000 pos: 25805 size: 1247 +ret: 0 st: 0 flags:0 dts: 4.000000 pts: 4.000000 pos: 27052 size: 1110 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 9.000000 pos: 28162 size: 7595 +ret: 0 st: 0 flags:1 ts: 6.989197 +ret: 0 st: 0 flags:1 dts: 2.000000 pts: 6.000000 pos: 18075 size: 7730 +ret: 0 st: 0 flags:0 dts: 3.000000 pts: 5.000000 pos: 25805 size: 1247 +ret: 0 st: 0 flags:0 dts: 4.000000 pts: 4.000000 pos: 27052 size: 1110 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 9.000000 pos: 28162 size: 7595 +ret: 0 st:-1 flags:0 ts:-0.116660 +ret: 0 st: 0 flags:1 dts:-2.000000 pts: 0.000000 pos: 48 size: 7804 +ret: 0 st: 0 flags:1 dts:-1.000000 pts: 3.000000 pos: 7852 size: 7808 +ret: 0 st: 0 flags:0 dts: 0.000000 pts: 2.000000 pos: 15660 size: 1301 +ret: 0 st: 0 flags:0 dts: 1.000000 pts: 1.000000 pos: 16961 size: 1114 +ret: 0 st:-1 flags:1 ts: 5.777507 +ret: 0 st: 0 flags:1 dts: 2.000000 pts: 6.000000 pos: 18075 size: 7730 +ret: 0 st: 0 flags:0 dts: 3.000000 pts: 5.000000 pos: 25805 size: 1247 +ret: 0 st: 0 flags:0 dts: 4.000000 pts: 4.000000 pos: 27052 size: 1110 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 9.000000 pos: 28162 size: 7595 +ret:-1 st: 0 flags:0 ts: 11.671692 +ret: 0 st: 0 flags:1 ts: 4.565857 +ret: 0 st: 0 flags:1 dts: 2.000000 pts: 6.000000 pos: 18075 size: 7730 +ret: 0 st: 0 flags:0 dts: 3.000000 pts: 5.000000 pos: 25805 size: 1247 +ret: 0 st: 0 flags:0 dts: 4.000000 pts: 4.000000 pos: 27052 size: 1110 +ret: 0 st: 0 flags:1 dts: 5.000000 pts: 9.000000 pos: 28162 size: 7595 +ret:-1 st:-1 flags:0 ts: 10.460008 +ret: 0 st:-1 flags:1 ts: 3.354175 +ret: 0 st: 0 flags:1 dts:-1.000000 pts: 3.000000 pos: 7852 size: 7808 +ret: 0 st: 0 flags:0 dts: 0.000000 pts: 2.000000 pos: 15660 size: 1301 +ret: 0 st: 0 flags:0 dts: 1.000000 pts: 1.000000 pos: 16961 size: 1114 +ret: 0 st: 0 flags:1 dts: 2.000000 pts: 6.000000 pos: 18075 size: 7730 diff --git a/tests/ref/vsynth/vsynth1-cinepak b/tests/ref/vsynth/vsynth1-cinepak index f1dfcd81db6ad..e47ae26b6da8e 100644 --- a/tests/ref/vsynth/vsynth1-cinepak +++ b/tests/ref/vsynth/vsynth1-cinepak @@ -1,4 +1,4 @@ -546c7c1069f9e418aa787f469b693b94 *tests/data/fate/vsynth1-cinepak.mov -99465 tests/data/fate/vsynth1-cinepak.mov -bee091c200262be3427a233a2812388c *tests/data/fate/vsynth1-cinepak.out.rawvideo -stddev: 8.46 PSNR: 29.58 MAXDIFF: 105 bytes: 7603200/ 456192 +cd28e47a6ac396240a3fee69f15625d1 *tests/data/fate/vsynth1-cinepak.avi +408616 tests/data/fate/vsynth1-cinepak.avi +e74066a028c708f467272884ecd3f7d3 *tests/data/fate/vsynth1-cinepak.out.rawvideo +stddev: 61.38 PSNR: 12.37 MAXDIFF: 225 bytes: 7603200/ 921600 diff --git a/tests/ref/vsynth/vsynth1-ffvhuff420p12 b/tests/ref/vsynth/vsynth1-ffvhuff420p12 index 0d80bd6d6806f..d4b22f3b4be13 100644 --- a/tests/ref/vsynth/vsynth1-ffvhuff420p12 +++ b/tests/ref/vsynth/vsynth1-ffvhuff420p12 @@ -1,4 +1,4 @@ 866485c954242232878e40f0389790dd *tests/data/fate/vsynth1-ffvhuff420p12.avi 14205356 tests/data/fate/vsynth1-ffvhuff420p12.avi -b48f32c140712e8c7bf81cfdd66ae312 *tests/data/fate/vsynth1-ffvhuff420p12.out.rawvideo -stddev: 0.68 PSNR: 51.47 MAXDIFF: 1 bytes: 7603200/ 7603200 +c5ccac874dbf808e9088bc3107860042 *tests/data/fate/vsynth1-ffvhuff420p12.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth1-vc2-420p10 b/tests/ref/vsynth/vsynth1-vc2-420p10 index 037c77cacf02d..025a1cc779ee4 100644 --- a/tests/ref/vsynth/vsynth1-vc2-420p10 +++ b/tests/ref/vsynth/vsynth1-vc2-420p10 @@ -1,4 +1,4 @@ 1365742985b6315f6796c765aa17f39e *tests/data/fate/vsynth1-vc2-420p10.mov 1417047 tests/data/fate/vsynth1-vc2-420p10.mov -d3deedfa461a2696f82910890412fa2d *tests/data/fate/vsynth1-vc2-420p10.out.rawvideo -stddev: 0.60 PSNR: 52.47 MAXDIFF: 1 bytes: 7603200/ 760320 +387696707c79cf1a6c9aeff4024226b9 *tests/data/fate/vsynth1-vc2-420p10.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth1-vc2-420p12 b/tests/ref/vsynth/vsynth1-vc2-420p12 index b0c56afcd5625..719f0d5f37e64 100644 --- a/tests/ref/vsynth/vsynth1-vc2-420p12 +++ b/tests/ref/vsynth/vsynth1-vc2-420p12 @@ -1,4 +1,4 @@ 08a844d17940cd612da269fb08430628 *tests/data/fate/vsynth1-vc2-420p12.mov 1746007 tests/data/fate/vsynth1-vc2-420p12.mov -5a78509638a96b0fa17c1b7e9159fd24 *tests/data/fate/vsynth1-vc2-420p12.out.rawvideo -stddev: 0.67 PSNR: 51.48 MAXDIFF: 1 bytes: 7603200/ 760320 +387696707c79cf1a6c9aeff4024226b9 *tests/data/fate/vsynth1-vc2-420p12.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-cinepak b/tests/ref/vsynth/vsynth2-cinepak index 18eb1d59a84db..835de78d16135 100644 --- a/tests/ref/vsynth/vsynth2-cinepak +++ b/tests/ref/vsynth/vsynth2-cinepak @@ -1,4 +1,4 @@ -cc0879f1993cdd6231e2c3b9c2c015a0 *tests/data/fate/vsynth2-cinepak.mov -88400 tests/data/fate/vsynth2-cinepak.mov -12c480911ebb89762dc49af003b176c7 *tests/data/fate/vsynth2-cinepak.out.rawvideo -stddev: 5.07 PSNR: 34.02 MAXDIFF: 59 bytes: 7603200/ 456192 +663a2804f421709208c76f6e34e7bea5 *tests/data/fate/vsynth2-cinepak.avi +400402 tests/data/fate/vsynth2-cinepak.avi +2c761c3c8cda083eb8f54b2df72b257b *tests/data/fate/vsynth2-cinepak.out.rawvideo +stddev: 80.96 PSNR: 9.96 MAXDIFF: 227 bytes: 7603200/ 921600 diff --git a/tests/ref/vsynth/vsynth2-ffvhuff420p12 b/tests/ref/vsynth/vsynth2-ffvhuff420p12 index 82c467ac3ea5b..f97edfbf4e10f 100644 --- a/tests/ref/vsynth/vsynth2-ffvhuff420p12 +++ b/tests/ref/vsynth/vsynth2-ffvhuff420p12 @@ -1,4 +1,4 @@ 3ab9567895bf1ec31a82aadf16a5da0e *tests/data/fate/vsynth2-ffvhuff420p12.avi 10562808 tests/data/fate/vsynth2-ffvhuff420p12.avi -542327cb5ca7708085513ffc3d7c693c *tests/data/fate/vsynth2-ffvhuff420p12.out.rawvideo -stddev: 0.72 PSNR: 50.87 MAXDIFF: 1 bytes: 7603200/ 7603200 +36d7ca943916e1743cefa609eba0205c *tests/data/fate/vsynth2-ffvhuff420p12.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-vc2-420p10 b/tests/ref/vsynth/vsynth2-vc2-420p10 index 9de40d227598e..48d97d60e4274 100644 --- a/tests/ref/vsynth/vsynth2-vc2-420p10 +++ b/tests/ref/vsynth/vsynth2-vc2-420p10 @@ -1,4 +1,4 @@ 1197f8108683b9eb6b0777adb2db1aa8 *tests/data/fate/vsynth2-vc2-420p10.mov 1181271 tests/data/fate/vsynth2-vc2-420p10.mov -75174cb90e76c433f6d769531d573ac2 *tests/data/fate/vsynth2-vc2-420p10.out.rawvideo -stddev: 0.63 PSNR: 52.11 MAXDIFF: 1 bytes: 7603200/ 760320 +01389f7ae4f2a3dc0d7b8384d435fd83 *tests/data/fate/vsynth2-vc2-420p10.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth2-vc2-420p12 b/tests/ref/vsynth/vsynth2-vc2-420p12 index 660a1eeb5c38c..9b9ccb8ec1e43 100644 --- a/tests/ref/vsynth/vsynth2-vc2-420p12 +++ b/tests/ref/vsynth/vsynth2-vc2-420p12 @@ -1,4 +1,4 @@ 0e6b3aefd70fca45e67dc8cbc99640e8 *tests/data/fate/vsynth2-vc2-420p12.mov 1525079 tests/data/fate/vsynth2-vc2-420p12.mov -b4d45651e20faa7a0bb84a0738638c48 *tests/data/fate/vsynth2-vc2-420p12.out.rawvideo -stddev: 0.73 PSNR: 50.84 MAXDIFF: 1 bytes: 7603200/ 760320 +01389f7ae4f2a3dc0d7b8384d435fd83 *tests/data/fate/vsynth2-vc2-420p12.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth3-ffvhuff420p12 b/tests/ref/vsynth/vsynth3-ffvhuff420p12 index 72d412d644d0a..201ec7658b2d6 100644 --- a/tests/ref/vsynth/vsynth3-ffvhuff420p12 +++ b/tests/ref/vsynth/vsynth3-ffvhuff420p12 @@ -1,4 +1,4 @@ e5a178d75afeda6df1d4eb6f7cdfa3a0 *tests/data/fate/vsynth3-ffvhuff420p12.avi 175260 tests/data/fate/vsynth3-ffvhuff420p12.avi -ee95a44ccd612b5057860b43fe9775d6 *tests/data/fate/vsynth3-ffvhuff420p12.out.rawvideo -stddev: 0.69 PSNR: 51.35 MAXDIFF: 1 bytes: 86700/ 86700 +a038ad7c3c09f776304ef7accdea9c74 *tests/data/fate/vsynth3-ffvhuff420p12.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 86700/ 86700 diff --git a/tests/ref/vsynth/vsynth_lena-cinepak b/tests/ref/vsynth/vsynth_lena-cinepak index 39b1d68268b03..6b021673a03a6 100644 --- a/tests/ref/vsynth/vsynth_lena-cinepak +++ b/tests/ref/vsynth/vsynth_lena-cinepak @@ -1,4 +1,4 @@ -e3837018f84929f07019ae2eccd303e2 *tests/data/fate/vsynth_lena-cinepak.mov -88900 tests/data/fate/vsynth_lena-cinepak.mov -f54ffa70f335ac7b701d7ae34462e001 *tests/data/fate/vsynth_lena-cinepak.out.rawvideo -stddev: 4.09 PSNR: 35.88 MAXDIFF: 46 bytes: 7603200/ 456192 +a9ea19eb0d239a53af8630d5bc4167d0 *tests/data/fate/vsynth_lena-cinepak.avi +407574 tests/data/fate/vsynth_lena-cinepak.avi +e32d4103194665d2ea0f46d5cdd0cdf2 *tests/data/fate/vsynth_lena-cinepak.out.rawvideo +stddev: 58.10 PSNR: 12.85 MAXDIFF: 185 bytes: 7603200/ 921600 diff --git a/tests/ref/vsynth/vsynth_lena-ffvhuff420p12 b/tests/ref/vsynth/vsynth_lena-ffvhuff420p12 index e8ea4bcc85d68..e77698ba0c5e1 100644 --- a/tests/ref/vsynth/vsynth_lena-ffvhuff420p12 +++ b/tests/ref/vsynth/vsynth_lena-ffvhuff420p12 @@ -1,4 +1,4 @@ b2f3d04ca30c113b79877bb5518dd6ea *tests/data/fate/vsynth_lena-ffvhuff420p12.avi 10925580 tests/data/fate/vsynth_lena-ffvhuff420p12.avi -08b3c6c70eba608bae926608ff253f2a *tests/data/fate/vsynth_lena-ffvhuff420p12.out.rawvideo -stddev: 0.68 PSNR: 51.38 MAXDIFF: 1 bytes: 7603200/ 7603200 +dde5895817ad9d219f79a52d0bdfb001 *tests/data/fate/vsynth_lena-ffvhuff420p12.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth_lena-vc2-420p10 b/tests/ref/vsynth/vsynth_lena-vc2-420p10 index 6428dd17887c2..2558ef8e9b564 100644 --- a/tests/ref/vsynth/vsynth_lena-vc2-420p10 +++ b/tests/ref/vsynth/vsynth_lena-vc2-420p10 @@ -1,4 +1,4 @@ 5bccec653c330f03b90065a84fad9b4b *tests/data/fate/vsynth_lena-vc2-420p10.mov 1154775 tests/data/fate/vsynth_lena-vc2-420p10.mov -32265ec286c54104b3be8f11c519da1b *tests/data/fate/vsynth_lena-vc2-420p10.out.rawvideo -stddev: 0.61 PSNR: 52.34 MAXDIFF: 1 bytes: 7603200/ 760320 +b1c660113acab8eb4075f3d9fbb9cee9 *tests/data/fate/vsynth_lena-vc2-420p10.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 760320 diff --git a/tests/ref/vsynth/vsynth_lena-vc2-420p12 b/tests/ref/vsynth/vsynth_lena-vc2-420p12 index e62b2b6d38831..bc60116ffe829 100644 --- a/tests/ref/vsynth/vsynth_lena-vc2-420p12 +++ b/tests/ref/vsynth/vsynth_lena-vc2-420p12 @@ -1,4 +1,4 @@ d27a6d3517cc9a6d22e338f4b206545c *tests/data/fate/vsynth_lena-vc2-420p12.mov 1516759 tests/data/fate/vsynth_lena-vc2-420p12.mov -bc62f1c3bade7224c55219dba8a3c6af *tests/data/fate/vsynth_lena-vc2-420p12.out.rawvideo -stddev: 0.68 PSNR: 51.39 MAXDIFF: 1 bytes: 7603200/ 760320 +b1c660113acab8eb4075f3d9fbb9cee9 *tests/data/fate/vsynth_lena-vc2-420p12.out.rawvideo +stddev: 0.00 PSNR:999.99 MAXDIFF: 0 bytes: 7603200/ 760320 diff --git a/tools/aviocat.c b/tools/aviocat.c index 983108a64a791..2aa08b92ed988 100644 --- a/tools/aviocat.c +++ b/tools/aviocat.c @@ -42,7 +42,6 @@ int main(int argc, char **argv) AVDictionary *in_opts = NULL; AVDictionary *out_opts = NULL; - av_register_all(); avformat_network_init(); for (i = 1; i < argc; i++) { @@ -107,6 +106,11 @@ int main(int argc, char **argv) if (n <= 0) break; avio_write(output, buf, n); + if (output->error) { + av_strerror(output->error, errbuf, sizeof(errbuf)); + fprintf(stderr, "Unable to write %s: %s\n", output_url, errbuf); + break; + } stream_pos += n; if (bps) { avio_flush(output); diff --git a/tools/bisect-create b/tools/bisect-create index fc60e86669711..ee6ec3feb82f4 100755 --- a/tools/bisect-create +++ b/tools/bisect-create @@ -20,7 +20,7 @@ fi case "$1" in need) case $2 in - ffmpeg|ffplay|ffprobe|ffserver) + ffmpeg|ffplay|ffprobe) echo $2.c >> tools/bisect.need ;; esac diff --git a/tools/cl2c b/tools/cl2c new file mode 100755 index 0000000000000..e3f92bab1c6e9 --- /dev/null +++ b/tools/cl2c @@ -0,0 +1,36 @@ +#!/bin/sh +# Convert an OpenCL source file into a C source file containing the +# OpenCL source as a C string. Also adds a #line directive so that +# compiler messages are useful. + +# This file is part of FFmpeg. +# +# FFmpeg is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# FFmpeg is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with FFmpeg; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +input="$1" +output="$2" + +name=$(basename "$input" | sed 's/.cl$//') + +cat >$output <>$output + +echo ";" >>$output diff --git a/tools/enum_options.c b/tools/enum_options.c index c2a295cad62e4..77e1f9f799d98 100644 --- a/tools/enum_options.c +++ b/tools/enum_options.c @@ -130,8 +130,6 @@ int main(int argc, char **argv) if (argc < 2) print_usage(); - av_register_all(); - if (!strcmp(argv[1], "format")) show_format_opts(); else if (!strcmp(argv[1], "codec")) diff --git a/tools/graph2dot.c b/tools/graph2dot.c index 21d0795e88184..d5c1e4e3c7920 100644 --- a/tools/graph2dot.c +++ b/tools/graph2dot.c @@ -189,8 +189,6 @@ int main(int argc, char **argv) *p = '\0'; } - avfilter_register_all(); - if (avfilter_graph_parse(graph, graph_string, NULL, NULL, NULL) < 0) { fprintf(stderr, "Failed to parse the graph description\n"); return 1; diff --git a/tools/ismindex.c b/tools/ismindex.c index 0254a98ff71ec..7601f62e06ff5 100644 --- a/tools/ismindex.c +++ b/tools/ismindex.c @@ -791,8 +791,6 @@ int main(int argc, char **argv) int split = 0, ismf = 0, i; struct Tracks tracks = { 0, .video_track = -1, .audio_track = -1 }; - av_register_all(); - for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-n")) { basename = argv[i + 1]; diff --git a/tools/patcheck b/tools/patcheck index 26137d6b218b0..101a542ff3219 100755 --- a/tools/patcheck +++ b/tools/patcheck @@ -68,7 +68,7 @@ $EGREP $OPT '^\+ *(const *|)static' $*| $EGREP --color=always '[^=]= *(0|NULL)[^ cat $TMP hiegrep '# *ifdef * (HAVE|CONFIG)_' 'ifdefs that should be #if' $* -hiegrep '\b(awnser|cant|dont|wont|doesnt|usefull|successfull|occured|teh|alot|wether|skiped|skiping|heigth|informations|colums|loosy|loosing|ouput|seperate|preceed|upto|paket|posible|unkown|inpossible|dimention|acheive|funtions|overriden|outputing|seperation|initalize|compatibilty|bistream|knwon|unknwon|choosen|additonal|gurantee|availble|wich|begining|milisecond|missmatch)\b' 'common typos' $* +hiegrep '\b(awnser|cant|dont|wont|doesnt|usefull|successfull|occured|teh|alot|wether|skiped|skiping|heigth|informations|colums|loosy|loosing|ouput|seperate|preceed|upto|paket|posible|unkown|inpossible|dimention|acheive|funtions|overriden|outputing|seperation|initalize|compatibilty|bistream|knwon|unknwon|choosen|additonal|gurantee|availble|wich|begining|milisecond|missmatch|threshhold)\b' 'common typos' $* hiegrep 'av_log\( *NULL' 'Missing context in av_log' $* hiegrep '[^sn]printf' 'Please use av_log' $* diff --git a/tools/pktdumper.c b/tools/pktdumper.c index 6516ad3a225d5..16a965b75697b 100644 --- a/tools/pktdumper.c +++ b/tools/pktdumper.c @@ -89,9 +89,6 @@ int main(int argc, char **argv) strcat(fntemplate, PKTFILESUFF); printf("FNTEMPLATE: '%s'\n", fntemplate); - // register all file formats - av_register_all(); - err = avformat_open_input(&fctx, argv[1], NULL, NULL); if (err < 0) { fprintf(stderr, "cannot open input: error %d\n", err); diff --git a/tools/probetest.c b/tools/probetest.c index 74045eb4985e2..2c6c1de246393 100644 --- a/tools/probetest.c +++ b/tools/probetest.c @@ -124,9 +124,6 @@ int main(int argc, char **argv) return 1; } - avcodec_register_all(); - av_register_all(); - av_lfg_init(&state, 0xdeadbeef); pd.buf = NULL; diff --git a/tools/qt-faststart.c b/tools/qt-faststart.c index 728f80c39c731..97be019c585ef 100644 --- a/tools/qt-faststart.c +++ b/tools/qt-faststart.c @@ -29,10 +29,7 @@ #include #include -#ifdef __MINGW32CE__ -#define fseeko(x, y, z) fseek(x, y, z) -#define ftello(x) ftell(x) -#elif defined(__MINGW32__) +#ifdef __MINGW32__ #undef fseeko #define fseeko(x, y, z) fseeko64(x, y, z) #undef ftello diff --git a/tools/seek_print.c b/tools/seek_print.c index de876b487c581..9280421741de8 100644 --- a/tools/seek_print.c +++ b/tools/seek_print.c @@ -65,7 +65,6 @@ int main(int argc, char **argv) argv++; argc--; - av_register_all(); if ((ret = avformat_open_input(&avf, filename, NULL, NULL)) < 0) { fprintf(stderr, "%s: %s\n", filename, av_err2str(ret)); return 1; diff --git a/tools/sidxindex.c b/tools/sidxindex.c index be284610d563f..a4f95515e4f06 100644 --- a/tools/sidxindex.c +++ b/tools/sidxindex.c @@ -363,8 +363,6 @@ int main(int argc, char **argv) struct Tracks tracks = { 0 }; int i; - av_register_all(); - for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "-out")) { out = argv[i + 1]; diff --git a/tools/target_dec_fuzzer.c b/tools/target_dec_fuzzer.c index a8696f9fc7368..62d62a9de34f8 100644 --- a/tools/target_dec_fuzzer.c +++ b/tools/target_dec_fuzzer.c @@ -99,7 +99,7 @@ static void FDBCreate(FuzzDataBuffer *FDB) { static void FDBDesroy(FuzzDataBuffer *FDB) { av_free(FDB->data_); } static void FDBRealloc(FuzzDataBuffer *FDB, size_t size) { - size_t needed = size + FF_INPUT_BUFFER_PADDING_SIZE; + size_t needed = size + AV_INPUT_BUFFER_PADDING_SIZE; av_assert0(needed > size); if (needed > FDB->size_) { av_free(FDB->data_); @@ -116,8 +116,8 @@ static void FDBPrepare(FuzzDataBuffer *FDB, AVPacket *dst, const uint8_t *data, FDBRealloc(FDB, size); memcpy(FDB->data_, data, size); size_t padd = FDB->size_ - size; - if (padd > FF_INPUT_BUFFER_PADDING_SIZE) - padd = FF_INPUT_BUFFER_PADDING_SIZE; + if (padd > AV_INPUT_BUFFER_PADDING_SIZE) + padd = AV_INPUT_BUFFER_PADDING_SIZE; memset(FDB->data_ + size, 0, padd); av_init_packet(dst); dst->data = FDB->data_; @@ -154,10 +154,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { av_log_set_level(AV_LOG_PANIC); } - // Unsupported - if (c->capabilities & AV_CODEC_CAP_HWACCEL_VDPAU) - return 0; - switch (c->type) { case AVMEDIA_TYPE_AUDIO : decode_handler = avcodec_decode_audio4; break; case AVMEDIA_TYPE_VIDEO : decode_handler = avcodec_decode_video2; break; diff --git a/tools/uncoded_frame.c b/tools/uncoded_frame.c index 3ca2ba4bbef58..3f850d344d746 100644 --- a/tools/uncoded_frame.c +++ b/tools/uncoded_frame.c @@ -11,7 +11,6 @@ typedef struct { AVFormatContext *mux; AVStream *stream; AVFilterContext *sink; - AVFilterLink *link; } Stream; static int create_sink(Stream *st, AVFilterGraph *graph, @@ -36,7 +35,6 @@ static int create_sink(Stream *st, AVFilterGraph *graph, ret = avfilter_link(f, idx, st->sink, 0); if (ret < 0) return ret; - st->link = st->sink->inputs[0]; return 0; } @@ -64,9 +62,7 @@ int main(int argc, char **argv) out_dev_name = argv + 2; nb_out_dev = argc - 2; - av_register_all(); avdevice_register_all(); - avfilter_register_all(); /* Create input graph */ if (!(in_graph = avfilter_graph_alloc())) { @@ -143,7 +139,7 @@ int main(int argc, char **argv) goto fail; } if (!(st->mux->oformat->flags & AVFMT_NOFILE)) { - ret = avio_open2(&st->mux->pb, st->mux->filename, AVIO_FLAG_WRITE, + ret = avio_open2(&st->mux->pb, st->mux->url, AVIO_FLAG_WRITE, NULL, NULL); if (ret < 0) { av_log(st->mux, AV_LOG_ERROR, "Failed to init output: %s\n", @@ -163,26 +159,24 @@ int main(int argc, char **argv) av_log(NULL, AV_LOG_ERROR, "Failed to create output stream\n"); goto fail; } - st->stream->codec->codec_type = st->link->type; - st->stream->time_base = st->stream->codec->time_base = - st->link->time_base; - switch (st->link->type) { + st->stream->codecpar->codec_type = av_buffersink_get_type(st->sink); + st->stream->time_base = av_buffersink_get_time_base(st->sink); + switch (av_buffersink_get_type(st->sink)) { case AVMEDIA_TYPE_VIDEO: - st->stream->codec->codec_id = AV_CODEC_ID_RAWVIDEO; + st->stream->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO; st->stream->avg_frame_rate = st->stream-> r_frame_rate = av_buffersink_get_frame_rate(st->sink); - st->stream->codec->width = st->link->w; - st->stream->codec->height = st->link->h; - st->stream->codec->sample_aspect_ratio = st->link->sample_aspect_ratio; - st->stream->codec->pix_fmt = st->link->format; + st->stream->codecpar->width = av_buffersink_get_w(st->sink); + st->stream->codecpar->height = av_buffersink_get_h(st->sink); + st->stream->codecpar->sample_aspect_ratio = av_buffersink_get_sample_aspect_ratio(st->sink); + st->stream->codecpar->format = av_buffersink_get_format(st->sink); break; case AVMEDIA_TYPE_AUDIO: - st->stream->codec->channel_layout = st->link->channel_layout; - st->stream->codec->channels = avfilter_link_get_channels(st->link); - st->stream->codec->sample_rate = st->link->sample_rate; - st->stream->codec->sample_fmt = st->link->format; - st->stream->codec->codec_id = - av_get_pcm_codec(st->stream->codec->sample_fmt, -1); + st->stream->codecpar->channel_layout = av_buffersink_get_channel_layout(st->sink); + st->stream->codecpar->channels = av_buffersink_get_channels(st->sink); + st->stream->codecpar->sample_rate = av_buffersink_get_sample_rate(st->sink); + st->stream->codecpar->format = av_buffersink_get_format(st->sink); + st->stream->codecpar->codec_id = av_get_pcm_codec(st->stream->codecpar->format, -1); break; default: av_assert0(!"reached"); @@ -240,14 +234,14 @@ int main(int argc, char **argv) } if (frame->pts != AV_NOPTS_VALUE) frame->pts = av_rescale_q(frame->pts, - st->link ->time_base, + av_buffersink_get_time_base(st->sink), st->stream->time_base); ret = av_interleaved_write_uncoded_frame(st->mux, st->stream->index, frame); frame = NULL; if (ret < 0) { - av_log(st->stream->codec, AV_LOG_ERROR, + av_log(st->mux, AV_LOG_ERROR, "Error writing frame: %s\n", av_err2str(ret)); goto fail; }